Skip to content

Git Notes Getting Started

gforney edited this page Sep 13, 2016 · 15 revisions

Introduction

There are several ways to contribute to a project with Git. Since most of the current collaborators on this project are "newbies" to Git, the purpose of this Wiki is to prevent "wild west" code slinging by setting some guidelines for workflow. These are guidelines, not laws. But following this workflow will help ensure a reasonably smooth transition from Subversion to Git. Notes describing how to perform specific tasks using Git are given here.

The Git guru is Scott Chacon. Here is a link to his Pro Git book. Chapter 2 on Git basics and chapter 3 on branching are especially useful. And here is a link to his long YouTube video Introduction to Git. There is a ton of information here. The step-by-step instructions below are meant to distill most of this down to a workflow we can all follow. Let us know if something does not work right.

Getting Started

Install Git on your local machine

Mac and Linux users will likely already have Git installed. To confirm this, open a terminal and type

$ git --version
git version 2.4.0

To install Git for Windows go here.

Create a GitHub account

If you do not already have one, create a GitHub account.

Do some local configuration

You will need to set your Git configuration so that the remote server knows who you are when you are pushing.

$ git config --global user.name = "John Doe"              # need not be GitHub username
$ git config --global user.email = "john.doe@example.com" # same as GitHub account
$ git config --global color.ui true

Fork repos from Fire Models

IMPORTANT: If you are setting up fresh repositories after the reorganization, see the Reorg Notes.

Go to the Fire Models organization GitHub page. For each project you want to work with, fork the corresponding repo(s) over to your GitHub account by clicking the fork icon on the upper right. Note that for FDS you will need three repos: fds, exp, and out. For Smokeview, you need both fds and smv. You will now have copies of the repos in <username>/<repo> on GitHub.

Clone the forked repos

The repo you will work from is now in your space on GitHub. To get this repo to your computer you need to clone it. There are a few ways to do this. For example, see the "Clone to Desktop" and "Download Zip" buttons to the right side of your project page. Here I will use the command line SSH clone. Note that you need to have an SSH key enabled for your computer. Under the personal profile tab on the GitHub page, go to Settings >> SSH keys and follow the instructions. On a Windows-based computer you can use the instructions found on the Two Factor Authentication Wiki.

Note that if you decide to clone using HTTPS, you will need to create a personal access token. Go to your Settings >> Personal access tokens. You will use this as your password when making your first push.

IMPORTANT: Repo names cannot be changed because many relative paths are hardwired into the scripts in the project.

Therefore, we recommend you create a directory to put all your forked repositories. Below I will assume you have created a folder called "FireModels_fork" to hold all the Fire Models repos.

To clone the repo, open a terminal and cd to FireModels_fork. Copy the line above the "Clone to Desktop" button in the SSH window to your clipboard. Then in the command window type the following:

$ git clone git@github.com:<username>/fds.git
...
$ git clone git@github.com:<username>/smv.git
...
# exp uses macfp-db as a submodule
$ git clone --recursive git@github.com:<username>/exp.git
...
$ git clone git@github.com:<username>/out.git
...

The option --recursive tells Git to initialize any Submodule repositories used by the "super project". Here, the exp repo uses the macfp-db repo as a submodule.

Now, let's see what you've got. Change directories into your repository directory and list your local branches.

$ cd fds/
$ git branch
* master

What this tells you is that your local fds repo has one branch "master" and that this is the branch you are currently on (*).

Now let's look at what branches exist in your remote repo.

$ git branch -a
* master
  remotes/origin/HEAD -> origin/master
  remotes/origin/master

remotes/origin/HEAD is a pointer to the tip of your current branch (don't worry about that for now). remotes/origin/origin is the default branch. This was the branch that was cloned to your machine. A stable snapshot of the project can be found at the Releases download page. The latest project build status for the master branch can be found here.

After cloning the repo, you can checkout the source code for a specific commit. For example, you could do

$ git checkout e611aa1 Source/*.f90 Build/makefile

Here e611aa1 is the abbreviated commit hash I found on the Releases page corresponding to v6.5.2. In general, it may also be necessary to checkout the makefile if major changes have been made. To get back the original source you can checkout HEAD:

$ git checkout HEAD Source/*.f90 Build/makefile

NOTE: If you checkout commits prior to the reorg, the directory structure was different. See the fds-smv_deprecated repo for the old structure.

Now the confusing bit: how does your local master branch stay up-to-date with the firemodels/fds master branch? We have to do one more thing: add an upstream tracking branch to pull from.

Staying up-to-date with the central repo

First, check your remote state. You should see no "upstream" repositories. The only remote repo you should see is origin.

$ git remote -v
origin	git@github.com:username/fds.git (fetch)
origin	git@github.com:username/fds.git (push)

If you see "upstream" repos in addition to origin, then you need to remove them.

$ git remote rm <repo-name>

Add tracking for firemodels/fds. Here we will go ahead and name our "upstream" repo "firemodels".

$ git remote add firemodels git://github.com/firemodels/fds.git
$ git fetch firemodles
remote: Counting objects: 6, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 6 (delta 4), reused 5 (delta 3), pack-reused 0
Unpacking objects: 100% (6/6), done.
From git://github.com/firemodels/fds
 * [new branch]      master -> firemodels/master
$ git remote -v
firemodels	git://github.com/firemodels/fds-smv.git (fetch)
firemodels	git://github.com/firemodels/fds-smv.git (push)
origin	git@github.com:rmcdermo/fds-smv.git (fetch)
origin	git@github.com:rmcdermo/fds-smv.git (push)

Now look at your branches.

$ git branch -a
* master
  remotes/firemodels/master
  remotes/firemodels/nist-pages
  remotes/origin/HEAD -> origin/development
  remotes/origin/development

remotes/firemodels are the branches from the firemodels/fds repo. remotes/origin are the branches in your GitHub repo. We will see how to merge these later (via pull requests). master is your LOCAL branch.

Updating your repository

To get all the changes committed by other project members to the central repo, do the following:

$ git remote update
Fetching origin
Fetching firemodels
$ git checkout master              # make sure you are in your master branch
$ git diff firemodels/master       # see what is different in your development branch
$ git merge firemodels/master      # merge any changes from the central repo
From git://github.com/firemodels/fds
 * branch            master -> FETCH_HEAD
Already up-to-date.

Your LOCAL repo will now have changes made to firemodels/fds. However, your GitHub repo will still be behind. You need to push the changes up to GitHub.

$ git push origin master

Tracking multiple repositories

Central to the philosophy of Git is that no particular repo is special. Of course, when we release the code we need to have a traceable source tree, hence the firemodels repo. But there is no reason we cannot view and share code between each other without going through the firemodels hub. To do this we simply need to add other remote repositories for tracking.

If you are on the firemodels/fds GitHub page and click on contributors then Members you can see a list of other GitHub users who have forked the firemodels/fds repo.

Do another remote add:

$ git remote add <gituser> git://github.com/<gituser>/fds.git
$ git remote update
Fetching origin
Fetching firemodels
Fetching <gituser>
From git://github.com/<gituser>/fds
 * [new branch]      master -> <gituser>/master

Now have a look at your branches.

$ git branch -a
* master
  remotes/firemodels/master
  remotes/firemodels/nist-pages
  remotes/<gituser>/master
  remotes/origin/HEAD -> origin/master
  remotes/origin/master

You can now easily fetch and merge any changes made by <gituser>.

Making changes

What follows is only an example. Please do not submit a real pull request to the firemodels project based on this example.

We can now finally start talking about how to make changes to project files and how to get these changes incorporated into the central project repo. Suppose you make a modification to a source file.

$ cd Source/
$ vi main.f90
PROGRAM FDS

! example pull request

You can see that the file main.f90 is now different than the current state of your development branch.

$ git diff origin/master
diff --git a/Source/main.f90 b/Source/main.f90
index 3c43257..eee15ad 100644
--- a/Source/main.f90
+++ b/Source/main.f90
@@ -1,5 +1,7 @@
 PROGRAM FDS  
 
+! example pull request
+
 ! Fire Dynamics Simulator, Main Program, Multiple CPU version.
 
 USE PRECISION_PARAMETERS

But note that, at this stage, your local repo is still in an unchanged state because you have not committed anything yet.

$ git status
On branch development
Your branch is up-to-date with 'origin/master'.
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

	modified:   main.f90

no changes added to commit (use "git add" and/or "git commit -a")

The next step is to "stage" your changes for commit and then to "commit" the changes to your local repo. But wait! First, make sure your working branch is up-to-date by fetching and merging (pulling) any last-minute changes from the central repo.

$ git fetch firemodels
$ git diff firemodels/master # Are these the changes you expect to see?  If not, don't merge.
$ git merge firemodels/master

Alternatively, if you know you want to merge, you can do the (fetch + merge) in one step using pull:

$ git pull firemodels master

Now do your add and commit.

$ git add main.f90
$ git commit -m "username: example pull request"
[master 4887e84] username: example pull request
 1 file changed, 2 insertions(+)

You are now going to push your commit up to your GitHub repo. It is good to explicitly say which repo and which branch you are pushing to, else you can forget where you are (if you are, say, a topic branch instead) and get your repo in a state that you have to untangle.

$ git push origin master
Counting objects: 4, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (4/4), done.
Writing objects: 100% (4/4), 406 bytes | 0 bytes/s, done.
Total 4 (delta 3), reused 0 (delta 0)
To git@github.com:username/fds.git
   02a63b2..4887e84  master -> master

Now your changes are in your repo on GitHub. Time to submit a pull request.

Submit a pull request

This only an example. Please do not submit a real pull request to the firemodels repo based on this example.

Go to your account on GitHub. Make sure you are on your master branch. You should see a note saying something like "This branch is 1 commit ahead of firemodels:master" (of course, this will depend on the current state of each repo). Next, click the "Compare & pull request" button. Notice you are now on the firemodels/fds account page. Use the compare tool to double check the changes you are submitting are the ones you intend to submit. It is also possible to just see a list of the files you are touching. Note that the compare tool is equivalent to the following Git command:

$ git remote update
$ git diff firemodels/master...<username>/master # note the "..."

This command shows the diff between your branch and the last common ancestor with firemodels/master (this is why its critical to do your fetch + merge with firemodels/master before your local commit). To see the diff between the tips of the two branches you are merging leave out the "..."

$ git remote update
$ git diff firemodels/master <username>/master

[Project members should be sure to check this diff before a major pull request.]

Click the "Create pull request" button. This will create a message "username wants to merge 1 commit into firemodels:master from username:master".

Accept or reject the request

Pull requests are accepted or rejected by project members. You can accept your own pull request if you are a member of the firemodels organization.

This process has advantages. First, it is a layer of quality control. Second, the graphical diff feature in GitHub is quite nice. As a former SmartSVN user, I have actually preferred to work from the command line with Git and to use GitHub for the GUI. Lastly, it is hard to untangle the state of a repo that has gotten out of sync (at least until we get more Git savvy) and the pull request is a good way to prevent unintended consequences of commands like $ git push, which may push ALL commits accidentally.

Summary

Here is the gist of what you need to do:

  1. Fork the firemodels/fds repo
  2. Checkout the master branch
  3. Setup the remote upstream repo (firemodels)
  4. Make changes in your local repo
  5. Stage your changes (git add)
  6. Commit your changes
  7. Push your changes to your GitHub repo (origin)
  8. Submit a pull request to firemodels/fds
  9. Accept or cancel the pull request (if you are a project member).
Clone this wiki locally