adding context to a shared git repository

Conrad Irwin — June 2012

At Rapportive we use git extensively for its powerful branching and merging capabilities. The workflow we use is very similar to that used by GitHub: everything in master is deployed, everything else is in branches based off master. We're also using Heroku's git push deployment model, so git is the canonical source of information about which code is where.

In order to make this easier to work with we've adopted two simple conventions to add extra context to the information already stored in git. These help us understand what's going on in the repository quickly, which leads to fewer mistakes when deploying, and lessens the need to interrupt other people just to find out what they've been doing.

Commit prefixes

Not all commits are equal, and when we create one that makes a particularly scary change we add a short, loud marker to the commit message. For example:

  • [MIG] — This commit introduces a database migration.
  • [ENV] — This commit requires an environment variable to be set.
  • [GEM] — This commit adds or alters a gem dependency.
  • [TEMP] — This commit is a hot-fix that will only be needed for a short time.

Providing everyone does this when such a commit is created, it's easy to scan down the git log and spot which commits are likely to cause problems. This is useful both when deploying, to ensure that you don't break everything; and also when fetching changes from GitHub before starting to work on something new.

git-undeployed

The convention of prefixing works no-matter which tool you use to view git logs. Just before deploying however, I run git undeployed. It shows me all the commits that differ between production, GitHub, and my local master:


/0/rapportive[master] $ git undeployed

* 583adaf Sam (prod/master) [TEMP] No queueing
| * 7e7c8bc Conrad (master) Moar caching!
| * 88e2cf5 Conrad [ENV] Configure redis
|/
* 05a2e01 Martin (github/master) Use .present?

This (fictitious) output tells me quickly what I need to do in order to deploy, namely:

  1. Check with Sam to find out what's going on with the queues.
  2. Push my changes to GitHub (always done before pushing to production).
  3. Add the new redis configuration to the production environment.
  4. Push my changes to production.

We also have an internal deploy script that wraps git undeployed and git push, and which detects these prefixes. It then asks the user for confirmation before letting the push go through, which can be useful when deploying in a hurry!

Branch prefixes

The other convention alluded to in the introductory section is branch prefixes. In order that we can keep track of what state everything is in, we group our branches into meaningful categories:

  • wip. — A feature or bugfix that someone is working on right now.
  • review. — A feature or bugfix waiting on a second pair of eyes before it gets deployed.
  • experiment. — A cool hack being worked on, that probably won't go into production in the near future.
  • shelf. — All the old useful bits of code we didn't get round to finishing, but don't want to throw away.

After the prefix comes a short descriptive name, so we end up with branches called things like wip.cache-robots-txt, or shelf.debug-console. This means that it's really easy to see at a glance both what code branches contain, and also what state different branches are in. The shelf. prefix is particularly useful for automatically removing irrelevant branches from git's output.

git-happening

Just like commit prefixes, branch prefixes are useful no matter what tools you are using to interact with git as they give you extra context with no need to shell out to a different tool. That said they enable one very useful ability which is not present in vanilla git (though it is on GitHub), and that is seeing the current status of all your branches:


* Conrad (master)  28 hours ago

* Conrad (review.html-escape) 2 days ago
* Martin (wip.cache-expiry) 30 minutes ago
* Lee (wip.hi-res-photos) 4 hours ago
* Conrad (wip.hover-intent) 2 months ago

This very quickly shows you who is working on what, and when they last touched it. As it excludes shelf branches it doesn't matter that we keep a whole load of old stuff around, because it will never show up.

It also shows you other house-keeping data about the branches. In the given example, I need to delete the review.html-escape branch from GitHub, because it has been merged into master. I'll also consider renaming wip.hover-intent to shelf.hover-intent; because clearly no-one is working on it any more.

Installation

In order to use branch prefixes and commit prefixes, you don't have to install anything, just get into the habit. It takes very little extra time, and makes it much easier to see what's going on in your repository at a glance.

In order to get git happening and git undeployed, and a host of other useful git aliae:

git clone https://github.com/ConradIrwin/git-aliae
# Add the following line to your ~/.bashrc
export PATH=$PATH:/path/to/git-aliae/bin

Please report bugs and feature requests to GitHub issues.