Document toolboxDocument toolbox

Git Workflow

Terminology

For the purposes of this tutorial I'll use some abbreviations short names to refer to particular git repositories.

local - your local repository that exists on your machine

origin - your forked version of the Sage Bionetworks repository (you did fork the repo on github right?)

upstream - the "official" repository that is owned by Sage Bionetworks on github.

Bringing in Upstream Changes

There are two basic paths for the git workflow:

  1. You have local changes committed to your local develop branch
  2. You have local changes committed to a local "feature" branch

Now, you see that the upstream repository has changes in it from one of your teammates checking in code (via code review!).  In order for your changes to make it into upstream with a minimum of fuss, you need to bring in those changes before you can submit a pull request.

Changes to local develop branch

This is probably basically what your branch history looks like in this scenario:

A---B---C develop
     \
      D---E upstream/develop

The problem here, is that if you simply do a git pull to merge in the upstream changes, you'll get an extra commit, and if git resolves merge conflicts the wrong way you could potentially end up committing changes that undo whatever work occurred upstream.  So instead what you want to do is this:

git fetch upstream # make sure you have all the latest info on your upstream repo
git checkout develop # be on your develop branch
git rebase upstream/develop

This should result in your history looking like this:

A---B---D---E upstream/develop
             \
              C' develop

Now move on to Sharing Your Changes

Changes to local "feature" branch

This is a little simpler. For it to work smoothly though, your local develop branch must be able to fast-forward to where upstream develop is.  Put another way, your local develop branch must point at a commit that is a direct or indirect parent of the commit that upstream develop is pointing at.

That is if we have commits:

           A---B---C---D---E---F 

and upstream/master points to F, then develop points to any of A through E.  Similarly, your feature branch can be based off of any commit on the develop branch (before or after your local develop).

Now you do

# You can skip this if you're already on the develop branch
git checkout develop
git pull upstream develop

Now assuming that you are done with the feature you're working on and want to bring your changes into the main develop branch so that you can issue a pull request.  Now:

git merge my-feature
git branch -d myfeature # remove the now useless branch

Git should ask you to enter a commit message. Now you're ready to Share Your Changes

Sharing Your Changes

Squash feature commits into one

Git allows you to rewrite your history and squash several commits into a single commit. While Git encourages (and often requires) many commits for a single feature, all these commits make the upstream repository's history confusing. To squash commits you do an interactive rebase:

  1. Make sure you don't have any uncommited changes
  2. Find the commit just before your work started
    1. An easy way to do this is using the command line git graph specified on our Git page
    2. In this example, if I wanted to squash feature 123's commits, I need to use commit 4a25eee for the rebase

      * 073c346        (develop) feature work 123 - all done (David Burdick)
      * 23e1f7b        feature work 123 - small commit (David Burdick)
      * f4f4f99        feature work 123 - initial feature code (David Burdick)
      *   4a25eee      Some commit from someone else prior to your work (Jay Hodgson)
      |\  
      | * 0437009      blah2 (David Burdick)
      | *   ee3fc4e    blah1 (David Burdick)
  3. git rebase -i <commit>

    1. For the example above, <commit> = 4a25eee
  4. Git will open a shell editor and show you the commits

    pick 073c346 feature work 123 - all done
    pick 23e1f7b feature work 123 - small commit
    pick f4f4f99 feature work 123 - initial feature code
    # Rebase 073c346..f4f4f99 onto 4a25eee
    #
    # Commands:
    #  p, pick = use commit
    #  r, reword = use commit, but edit the commit message
    #  e, edit = use commit, but stop for amending
    #  s, squash = use commit, but meld into previous commit
    #  f, fixup = like "squash", but discard this commit's log message
    #  x, exec = run command (the rest of the line) using shell
    #
    # If you remove a line here THAT COMMIT WILL BE LOST.
    # However, if you remove everything, the rebase will be aborted.
    #                                                                                                                                                                                                                                                                                                   
  5. change "pick" to "squash" (or just "s") to squash commits up into the previous commit. Don't worry about changing the comments, that comes later
    1. Example Feature squash

      pick 073c346 feature work 123 - all done
      s 23e1f7b feature work 123 - small commit
      s f4f4f99 feature work 123 - initial feature code
      
      
      # Rebase 073c346..f4f4f99 onto 4a25eee
      #
      # Commands:
      #  p, pick = use commit
      #  r, reword = use commit, but edit the commit message
      ...
  6. Save and exit the editor. 
  7. Git now brings up a comments editor. 
  8. Delete all non commented lines and write a message like "Feature PLFM-123 work", which will be the commit message for the single commit
  9. Save and exit
    1. The git graph history will now look like this

      * b0f5732        Feature PLFM-123 work (David Burdick)
      *   4a25eee      Some commit from someone else prior to your work (Jay Hodgson)
      |\  
      | * 0437009      blah2 (David Burdick)
      | *   ee3fc4e    blah1 (David Burdick)
  10. Two things to remember
    1. If something goes wrong or you chose the wrong range, you can delete everything in the editors to abort the rebase
    2. As with any rebase, DO NOT rebase commits that have been pushed to public repositories (i.e. GitHub). This will mess up anyone who has forked the public repository. However, it is okay to push this type of rebase change up to your own GitHub fork as no one should be forking your forked origin repo. 

Send changes to GitHub and Pull Request

Now to share your changes with the rest of the team (starting from your local develop branch)

git push origin develop

Now go to your GitHub repository page and click the "Pull Request" button, mark the changeset as

Sage-Bionetworks/<repo-name>@develop to <your-name>/<repo-name>@develop

Then send someone an email, and schedule your code review!