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:
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.
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.
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.
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.
Going back to me having written a shiny new password-reset dialog, I notice while I'm
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.
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.
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.
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:
Please report bugs and feature requests to GitHub issues.