git aliae to make you more awesome (part 1)

Conrad Irwin — May 2012

One of the amazing advantages of git is that you can create commits locally on your own computer. I think this is one of the massively underestimated features of distributed version control systems as it enables (at least) three hugely wonderful things:

  1. You can make permanent check-points every time you get the code into a working state, and refer to them to when you break stuff.

  2. You can save what you're working on right now, and switch to work on something else for a while, and then just jump right back in where you left off.

  3. You can refactor the commits you make so that you end up with a string of neatly wrapped chunks of changes, one after the other. (aka. sausage making).

To be honest, point one is both the most obvious advantage and the least useful — most editors have undo features, so this is only game changing if your machine crashes a lot (maybe essential for Kernel developers, but not really for me).

The second point is pretty exciting however. It means you can have an infinite number of things going on at the same time, without having to keep them all in your head. To help me do this I've written two git-aliae that I use all of the time:

git-pause && git-resume

Let's say I'm sitting at my desk adding a password-reset dialog to the site, and suddenly the guy across from me says: "Hey, I just noticed we're broken on IE7 again, can you fix it?".

No problem, I just git pause on my current branch (wip.password-reset) and then git checkout master. I'm now ready to go and get a cup of tea and get stuck straight into the IE7 bug.

A few hours later, I've fixed the bug, deployed a new version of master, and am ready to get back to working on the password-reset dialog again. I go back to the branch I was working on with git checkout wip.password-reset, and then git resume, and all my work is back ready for me to get stuck back in.

sausage making

The third bullet point is the one I'm really wanting to rave about. If I can refactor commits as I go, then I can make the git history look awesome. This is vitally important to me because I'm very proud of my work as a programmer; if the guy reviewing my changes isn't thinking "wow, this stuff is awesome", I feel sad.

There are also sound "business" reasons to ensure your history is in working order: it makes code review easier, the git log output more useful for status tracking, and tracking down regressions much less painful. Finally of course, happy developers are productive developers, so letting me spend time being happy is good for everyone.

In order that all this refactoring of history doesn't take up too much of my time, I'd like to introduce you to two more git-aliae. This is really the tip of the iceberg in terms of what git can do, but these are definitely the commands I use most.

git-amend

Going back to me having written a shiny new password-reset dialog, I notice while I'm committing (with git commit -v so I can review my own diff) that I've just duplicated a lot of logic from the main sign-up form... This triggers my refactor alert, and so after I've finished committing the working (but lamely written) version of the password-reset dialog, I get stuck back into the code and refactor the sign-up form and the new password-reset dialog to share the same code.

Once the refactoring is done, I just git amend ., which takes all my new refactorings and shoves them straight into the previous commit. No-one else need know that I even considered duplicating the code, looking at the git history will make it appear as though the beautiful new version just sprang fully-formed into my mind.

git-uncommit

Unfortunately the commit that introduces the beautiful new version is quite chunky: it both refactors the main sign up form and adds a password reset dialog. To make this much nicer I really want to split it into two separate commits, first refactor the sign-up form into a reusable form; and then add a password reset dialog that uses the new reusable code.

Thankfully, git uncommit -p can be used to help with this. It walks me through a nice interactive process where I can choose which parts of the previous commit I want to keep, and which ones I want to pretend haven't yet happened.

Once that is done I need to do two more things: firstly change the message on the commit (which now contains only the sign-up form refactor), which I can do with git amend; and secondly commit all the password-reset dialog code that's now in my working tree, which I can do with git commit -av as normal.

installation

There's nothing quite as satisfying as the feeling of a job-well-done, and fixing up my commits like that gives me immense satisfaction. As I'm certain you'll also want to do this, I've made these aliae available on GitHub.

To install 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.