A Git Workflow for Agile Teams

March 2nd, 2009
by Rein Henrichs

An efficient workflow for developers in Agile teams that handles features and
bugs while keeping a clean and sane history.

At Hashrocket we use git both internally and in our
Agile mentoring and training. Git gives us the flexibility to design a version
control workflow that meets the needs of either a fully Agile team or a team
that is transitioning towards an Agile process.

There are many usable git workflows. Indeed, git is really “a tool for
designing VCS workflows” rather than a Version Control System itself. Or, as
Linus would say, git is just a stupid content tracker.

This is by no means a normative document or my attempt to define The One True
Workflow. I have found this workflow to be productive and relatively painless,
especially for teams that are still learning and transitioning towards a more
Agile process. I invite you to comment below and describe the git workflow that
works best for you.

Credits

Anyone interested in using git in an Agile environment should read Josh
Susser’s Agile Git and the Story Branch Pattern. This workflow
is based largely on his.

The process of squashing commits into more atomic and incremental units has
been described by Justin Reagor in A “Squash” WorkFlow in Git.
Justin’s post also references a git rebase -i walkthrough by MadCoder
that provides a good explanation the interactive rebase process.

First, and while in your master branch (git checkout master), pull in the
most recent changes:

git pull origin master

This should never create a merge commit because we are never working directly
in master.

NB: Whenever you perform a pull, merge or rebase, make sure that you
run tests directly afterwards. Git may not show any conflicts but that doesn’t
mean that two changes are compatible. Also run tests before you commit (of
course).

We begin with the topmost available story in Pivotal Tracker.
Let’s say that it’s #3275: User Can Add A
Comment To a Post. First, check out a feature branch named with the story id
and a short, descriptive title:

git checkout -b 3275-add-commenting

The id allows us to easily track this branch back to the story that spawned it.
The title is there to give us humans a little hint as to what’s in it. Do some
work on this branch, committing early and often (for instance, whenever your
tests pass). Rebase against the upstream frequently to prevent your branch from
diverging significantly:

git fetch origin master
git rebase origin/master

NB: This is often done by checking master out and pulling, but this method
requires extra steps:

Once work on the feature is complete, you will have a branch with a lot of
small commits like “adding a model and a migration”, “adding a controller and
some views”, “oh crap - adding tests” and so on. This is useful while
developing but larger, incremental commits are more easier to maintain. We will
use an interactive rebase to squash them together. Also, squashing
these commits together will allow us to pretend that we wrote the tests
first…

We want the rebase to affect only the commits we’ve made to this branch, not
the commits that exist on the upstream. To ensure that we only deal with the
“local” commits, use:

git rebase -i origin/master

Git will display an editor window with a list of the commits to be modified,
something like:

Save and close the file. This will squash these commits together into one
commit and present us with a new editor window where we can give the new commit
a message. We’ll use the story id and title for the subject and list the
original commit messages in the body:

This also follows Tim Pope’s git commit message best
practices. Now, save and close your editor.
This commit is now ready to be merged back into master. First rebase against
any recent changes in the upstream. Then merge your changes back into master:

git checkout master
git merge 3275-add-commenting

And finally, push your changes to the upstream:

git push origin master

Bug Fixes

Bugfixes will use the same workflow as feature work. Name your bugfix branch
after the bug id and give it a descriptive name. Prefix the branch name with
“bug” to help you keep track of them, for instance:
bug-3845-empty-comments-allowed.

Do work in your bugfix branch, committing early and often. Rebase frequently
against the upstream and again when you are finished. Then, use an interactive
rebase to squash all the commits together. Use the bug id and title for the
subject of the new commit. Include “BUG” or “BUGFIX” to make these commits
easier to identify. For instance:

[#3278] BUGFIX: Empty Comments Should Not Be Allowed

NB: With a bugfix, squash the commits down into one and exactly one commit
that completely represents that bugfix. Half of a bugfix is useless.

QA Branch Management

In a truly Agile process, as Josh Susser explained to me, you simply deploy
directly from your latest “green” build. While this may seem impossible, there
are real world examples of the viability of Continuous Deployment.

For most of the teams we train, this sort of extreme agility is a goal rather
than a way of life. They are transitioning towards a fully Agile process from a
more rigorous one and often have a significant investment in Quality Assurance.
For these teams, I recommend a compromise solution: Use a remote QA branch that
is fast-forward merged from the latest “green” (all CI tests pass) master build
for QA deployments.

If you don’t already have a QA branch, create one from the current master
(assuming it’s green) and then push it to your git host:

git checkout -b qa
git push origin qa:refs/heads/qa

To update an existing QA branch with the latest changes from master, do this:

git checkout qa
git merge master
git push origin qa

Ensure that the master branch is green when you merge. Also ensure that this
merge is always a Fast Forward merge. If it is not, it means that commits have
been made in the QA branch that are not in the master branch. QA should be
merged into from master only, never worked on directly.

Production Tagging

While an Agile team will be deploying continuously, most teams will require a
more rigorous vetting process before a build is deployed to production. Tags
provide a simple way for QA to vet a particular build.

Once QA has signed off on a build as ready for production, a tag should be made
and deployed. In git, a tag can be created with git tag <name>. It is
important that tag naming is consistent and it is useful if they sort in a
meaningful way (latest last, for instance). Two good options are a timestamp or
product version. Use whichever is more meaningful to your team.

The process of creating a timestamped production tag can be automated with a
simple script or a git alias like this one:

git config alias.datetag '!git tag `date "+%Y%m%d%H%M"`'

With this alias, git datetag will create a new tag from HEAD with the
current timestamp. You will want to be in the QA branch. If the QA branch has
moved beyond the last commit vetted by your QA team, be sure to checkout that
commit first.