My Git history is a lie

Posted by : on

Category : Guide

I spend a lot of time fussing over the “correct-ness” of my code. Is it well formed? Is it clear and easy to follow? Does it adhere to SOLID design principles?

I like to think I write code much like a master-woodworker finishes a wood carving. Spending hours sanding down that grain with 8000-grit sandpaper to make sure it’s a perfect finish. In software parlance, this is endless re-factoring, code-commenting and formatting-niceties. The structure and layout of the code is just as important to me as the resilience, robustness and reliability of the executable that it will become.

So then why do my git commit messages look like random postings from someone with a shallow grasp of the written language?

Commit early, commit often leads to meaningless commit messages

The biggest contributor to my problem is a well-known best-practise of “Commit Early, Commit Often”. Which I do. Problem is, I find it really hard to apply this other best-practise of the “Meaningful Commit Message” when I’m committing early and often.

Why is that?

In my flow state churning out new code, or hammering on a GitHub actions workflow, I have a particular mindset or focus. That mindset does not lend itself well to crafting informative paragraphs of prose for every single commit message.

So stuck between a rock and a hard place. Which “best practise” do I give up, in the light that my flow-state makes them mutually exclusive?

The good news is I don’t have to give up either one. I can figuratively have my cake and eat it too.

Enter the “interactive rebase”.

This is perhaps my most beloved feature of Git; the ability to re-write my commit history.

> git rebase -i HEAD~20

This little command then lets me edit my past commits, with neat features like picking, squashing, re-wording or just plain discarding.

Interactive rebase output in notepad

Each line in the history represents a commit, and the first word of each line is an instruction on what to do with that commit. By default, it will pick every commit, but that would just leave me with the same history I started with.

Instead, I want to group some of these related changes into the same bucket. That is, I want to squash many commits into one commit.

Pick and squash commits

In this example, I am keeping three commits (by picking them), and then squashing subsequent commits into the ones I pick. When I am done with grouping them, the next part of the rebase allows me to write a new git commit message.

This is the part that allows me to write up my meaningful commit message!

Meaningful commit message

Once I have finished picking, squashing & re-writing messages, git will replace those 20 messy commits with three neat commits.

Three neat git commits

Gone are the half-scribbled notes in my git history; replaced now with something that I’m not ashamed of others reading in my git history.

This single feature allows me to keep my flow state while barfing out seemingly obscure remarks into my commit messages. The secret is that these are not obscure remarks to me. I use these as mementos to keep track of what the change was at the time I committed early and often.

Once I’m done with my flow state, I then gather up these related commits and start to finesse the messages into meaningful summaries. I squash many related-commits into a few “bucket commits”. These commits are usually related to a broader change. As a guide, I group these by the notion of “the revert”. That is, if I had to revert a particular change, how can I do that with the least number of revert-commits?

Not only does this technique allow me to keep all the “best practise” notions mentioned earlier, but it also means I afford my git history the same care and attention to detail that the rest of my codebase receives.

After all, my git commit history IS a part of my deliverable, so it makes sense that it too receives the same level of artisanship.


About Aaron White

I'm a Developer Advocate. I aim to make software development more accessible for everyone.

Useful Links