In Defense of the Commit Message

It’s time to acknowledge an inconvenient truth: For an industry full of perfectionists, our commit messages suck.

Open up your software’s source repository and issue a command that’ll output your most recent commit message. In git, our DVCS-of-choice here at Conductor, you can try:

$ git log -1 --author='<your_name>' --no-merges

Got it up on your screen? Now ask yourself this question: Which is likely to last longer, this commit message or the feature it describes?

Specs decay. Wikis age. Engineers move on. Our commit histories are the only information stores we have guaranteed to last as long as our applications. So what, then, do we do with commits like this?

* dc79620 - Working tests.
* 69fab05 - Changed default reference.
* 06acb41 - work in progress
* baa33ce - incremental commit
* 4f2e65d - whoops -- don't loop like that
* 1df06e6 - newest version

Everything but the kitchen sink

I call commits like these kitchen sink commits, as they tend to include whatever happened to be around when the developer issued a global git add. If the engineer follows something resembling a normal workflow, they’ll be logically chunked. Odds are they’ll include rogue whitespace changes. If the developer is inattentive, they might also include incidental files specific to the developer’s local environment.

It’s an easy habit to fall into. Kitchen sink commits happen when developers are rushed, because they’re saving work in progress, or because they’ve missed the point of commit history. Commits are not simply progressive states of the code, they’re tiny globules of context shot forward in time. They’re not for Today Us. They’re for Future Us, when the motivation for our code is long forgotten and yesterday’s decisions are lost in the haze of time.

We all owe a technical debt to our applications. Sometimes it’s rushed design – a holdover from a younger, more start-uppity age. For  web applications, it’s increasingly a debt of scale. The patterns and processes that worked at 1,000 users fail utterly at ten times that load. I don’t care about your test coverage today: Your code will break next year. Does your commit history have your back?

A better commit message

It’s easy to identify kitchen sink commits. It’s more difficult to settle on good commit design. Here’s what we aim for at Conductor, taken from the guidelines of git.git itself. We may not always hit this format, but like the rest of our engineering process, we view each commit as an opportunity to do better than we did last time:

commit 1df06e66668b4ae6befaa70321fb94b282b08a01
Author: Christopher Tiwald <myemail@conductor19.wpengine.com>
Date: Thu Aug 15 12:10:01 2013 -0400

subject_area: Use imperative language to order your app to do something

Write enough detail so that a reverse engineer could clone your application's
features and functions using nothing more than its commit messages. Highlight,
briefly, the problem you're trying to solve, your design's justification, and
any alternative solutions you considered but rejected.

First lines shouldn't exceed 80 characters. That's not just an antiquated
guideline: Exceeding 80 characters breaks the `git log` experience of command
line users and fills us with rage. Additionally, Git's developers preface most
messages with filenames, followed by a colon. Including some sort of preface, 
such as a filename, feature name, or issue number, is good practice. It makes 
history pagers easier to read.

Most messages end up being a couple of paragraphs. Single line commits aren't
anathema. Sometimes "Spell the name of our product correctly" is all you have
to say.

Writing a good commit message only takes five minutes. It’s easier than writing a unit test, and the payoff to Future You could be hours of saved opportunity cost. Over time, your version control system’s equivalent of git blame will become your first step in debugging. There will be no faster way to recall the Who, What, Where, and Why of old code.

About Chris Tiwald

Related Posts