aaron maxwell

Three Things I Love About Git

git-commit --amend

One of the benefits of using version control is organization. When you commit a set of changes, you are implicitly marking that set as defining a certain feature set, or otherwise having something in common.

Have you ever committed something, then realized you forgot to include something with it? Maybe it's a new file, or maybe it's an extra small change you forgot to make.

Enter git-commit --amend. The amend option adds to the tip of the current branch, and actually replaces the last commit with the combined change! It even seeds the message editor with the last commit's description, so you don't have to type it in again.

git-checkout -b

I often like to work in branches, even if what I'm implementing is not large enough to make a branch-commits-merge cycle really necessary. I find that making frequent small commits, without needing to think about whether the product is fully stable each commit, helps me focus and develop more quickly and cleanly.

In most VCSs, branching is something that takes a bit of effort, and for maximum ease, you want to plan it ahead of time. Sometimes I start developing, and suddenly decide what I'm working on is going to be big enough that I want to use a branch. I'm now forced to decide whether I want to make the effort to "backport" the work done so far.

With git-checkout -b, it becomes a very easy decision. This command says "create a new branch, based off the last commit, and transfer my working copy to this branch in-place, so I can commit to the branch as I please." I just execute git-checkout -b new_branch_name and keep going, with no interruption to my train of thought or work flow.

(Bonus: merging is relatively painless in git, especially compared to most centralized version control systems. Which just makes the ease of branching even more valuable.)

Fine-grained commits

Like I mentioned, one valuable benefit of using version control is organization: by making intelligent commits, code content diffs are automatically organized by feature set.

Sometimes, when I'm ready to commit, I have changes I want to include mixed in with some I do not. Or, I decide it would make more sense to split the current set of changes across several commits.

An example from this week: I was editing a Makefile, and realized it contained three sets of changes that really had nothing to do with each other.Had the make file been split up into several physical files, perhaps it would have been trivial to put into separate commits, but it in reality it was just one physical file.

Most VC tools I know of can resolve commit changes only down to the individual file level - they don't get fine grained enough that you can tell them, "commit this part of this file, and that part of that file, but not these other parts". You can always hack around it, by manually editing and reverting, etc. But that's often not easy nor quick.

But lo! I have a friend in git-commit --interactive. This starts up a shell that allows you to selectively add individual changes, what git calls "hunks", to the staging area for committing. In this case, the Makefile had three of these hunks. You can split up any hunk into smaller hunks, if you want to control what you're committing with even finer granularity. You can review the change set as you build it, adding, deleting or refining changes as you like. When satisfied, I exit, and the change set is automatically committed.

That's for the simple case of one file. It can be an even more powerful tool with a larger change set.

(By the way, if you don't want the automatic commit, just use git-add --interactive instead. It otherwise works the same way.)