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.
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.
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:
- Check with Sam to find out what's going on with the queues.
- Push my changes to GitHub (always done before pushing to production).
- Add the new redis configuration to the production environment.
- 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!
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
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.
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
shelf.hover-intent; because clearly no-one is working on it any more.
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
Please report bugs and feature requests to GitHub issues.