Skip to content

Instantly share code, notes, and snippets.

@bkaney
Created November 24, 2009 16:49
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save bkaney/242008 to your computer and use it in GitHub Desktop.
Save bkaney/242008 to your computer and use it in GitHub Desktop.
Git Workflow with Backporting to origin/master

Git Workflow

Consider three remote branches origin/master, origin/staging and origin/production. The master is the shared developers' edge. Staging is what is tested before a push to production and production is the code that gets deployed.

New Development

Locally, I have a development branch that I rebase frequently from my local master which tracks the remote origin/master. The development branch is what I work in if I am not working on a topic branch for a certain feature.

$ git branch
 * development
   master
   staging
   production

I commit in very small increments with the feature tracking number from my project planning tool (i.e. jira ticket number, lighthouse number, pivotal tracker card id, etc.). I put the number as the first bit of information in my commit message.

$ git commit -m "[#1122] Test coverage on widget X"
$ git commit -m "[#1122] Slight regression, but nice refactoring on widget X"
$ git rebase master
$ git commit -m "[#1122] Feature for widget X is complete"
$ git rebase master

Note that I don't commit local changes directly to my local master.
This allows me to git pull my local master without rebasing.
(Admittedly for this example, I would have likely created a topic branch for the #1122 feature).

When I am finished and some commits I want to share, I rebase them to master interactively. This allows me to squish multiple commits down.

$ git rebase -i development master

Once satisfied, I can push my changes up to origin/master.

NOTE: The previous rebase command should have put you into your local master branch. Check with a quick git branch and git status; it's a good idea to get in the habit of checking the status, log (gitk, gitx, etc.) and what branch you are in throughout the process.

$ git push origin master

Cherry-picking

I recommend not cherry-picking across locally-tracked versions of remote branches. So avoid cherry-picking from staging to master (assuming these track origin/staging and origin/master respectively). There should be no issue cherry-picking across local non-shared branches.

Patching

We git-tag origin/production with release tags. A patch is a bug that needs to be deployed immediately -- it can't wait for the next release. The workflow is to create the patch that ends up in origin/staging, then deploy to the staging environment to test. After successful testing push origin/staging to origin/production, git-tag and then deploy to the production environment.

Here's an example, assume my local staging is tracking origin/staging:

$ git checkout staging
$ git pull origin staging
$ git checkout -b patch_for_1001

Test, code, commit, code, commit, etc.

$ git checkout staging
$ git rebase -i patch_for_1001

Here squish all commits into a single one for staging -- makes maintenance simpler, and ("Half of a bugfix is useless.")1.

At this point, we should test the patch on the staging environment. If successful, we can do the push to origin/production, create a new git-tag, and run our deploy scripts to the production environment.

Backporting Patches to origin/master

We would like to backport patches to origin/master. Since origin/staging is a branch of origin/master, there is some point of shared history. Rebasing either from our patch branch or from staging (after the patch has been applied to staging) should be analogous -- with the exception of squishing during an interactive rebase. Assume your patch_for_1001 has been rebased into origin/staging, you can now rebase master from staging.

Make sure we are up to date:

$ git checkout master
$ git pull origin master
$ git fetch origin staging:staging

Then rebase staging into master.

$ git rebase staging master

Observe the git history and make sure things look okay (gitx, gitk --all, etc). Now since we have re-wound the tip, we can't do a regular git push, as we will get an error like this:

$ git push
To git@git.git-server.com:project
 ! [rejected]        HEAD -> master (non-fast forward)
error: failed to push some refs to 'git@git.git-server.com:project'
To prevent you from losing history, non-fast-forward updates were rejected
Merge the remote changes before pushing again.  See the 'non-fast forward'
section of 'git push --help' for details.

So to avoid confusion with the people who fetch from the branch, we have a policy that we will regularly be rewinding the tip of the branch for patches. This should avoid confusion when seeing (forced update) when pulling down from origin/master.

Therefore we push as "non-forward", using the + modifier.

$ git push origin +master:master
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment