writing better commit messages

2020-02-05

 | 

~6 min read

 | 

1045 words

In a recent sprint retrospective, a teammate mentioned that we could help ourselves by adding more context to our pull requests. This got me thinking and I started reading about how other teams handled this problem. This search led me to three five resources which are changing the way I’m thinking about commits:

  1. “Telling stories through your commits” by Joel Chippindale | Mocoso.co.uk - A conference talk from The Lead Developer UK 2016
  2. “A Branch In Time” by Tekin Süleyman | tekin.co.uk - A conference talk recorded at RubyConf AU 2019
  3. “My favourite Git commit” by David Thompson | Fatbusinessman.com - A blog post which breaks down one particularly noteworthy commit
  4. “How To Write a Git Commit Message” by Chris Beams | chris.beams.io - A blog post by Chris Beam’s that summarizes many of the best practices for writing quality commit messages.
  5. “How to Make Your Code Reviewer Fall in Love with You” by Michael Lynch | mtlynch.io - A blog post by Michael Lynch rich with suggestions on how to improve code review, beginning with the golden rule: “respect your code reviewers time.”

Each of these blog posts and talks are worth investigating on their own and I highly encourage reading/watching them all! The purpose of this post is to call out a few of the lessons I took from them, but focusing primarily (at least for now) on Joel’s talk. Joel presented a three pronged framework for writing effective commits:

  1. Atomic commits
  2. Meaningful commit messages
  3. Revise history before sharing

What do they mean?

Atomic commits are the “minimum viable commit.” It’s the smallest chunk of code that together means something. Here, the --patch flag (also -p) of git add is particularly useful. A heuristic to use: If you need to use “and” to describe the commit, it may be too big.

Meaningful commit messages are described in four parts:

  1. Short one line title,1 e.g., “Fix Widget Bug.” Fewer than 50 characters is preferred. Imperative mood (i.e., written as if giving a command / instruction).
  2. (As necessary) a longer description of what the change does. This can include a reference to the project management software, though as Tekin pointed out in his talk, this can backfire when the tracking software changes (e.g., move from Trello to Jira to RoadmapAllstar2)
  3. Why the change was made
  4. (Optional) Discussion of alternative approaches evaluated

Chris Beams’ article includes a sample commit that demonstrates all of this quite well

Summarize changes in around 50 characters or less

More detailed explanatory text, if necessary. Wrap it to about 72
characters or so. In some contexts, the first line is treated as the
subject of the commit and the rest of the text as the body. The
blank line separating the summary from the body is critical (unless
you omit the body entirely); various tools like `log`, `shortlog`
and `rebase` can get confused if you run the two together.

Explain the problem that this commit is solving. Focus on why you
are making this change as opposed to how (the code explains that).
Are there side effects or other unintuitive consequences of this
change? Here's the place to explain them.

Further paragraphs come after blank lines.

 - Bullet points are okay, too

 - Typically a hyphen or asterisk is used for the bullet, preceded
   by a single space, with blank lines in between, but conventions
   vary here

If you use an issue tracker, put references to them at the bottom,
like this:

Resolves: #123
See also: #456, #789

I’ve ultimately settled on an approach similar to Chris’ with one significant departure: where to reference issues. Instead of placing them at the bottom, I like using some of the real-estate in the first line to note the issue. For example,

Summarize changes in around 50 characters or less [PROJ-123]

This is largely a product of the fact that I begin my investigation of git history by reading one-line summaries - and seeing the ticket number is useful.3

Ultimately, though, there are two side-effects to this approach that I find beneficial:

  1. It encourages that all work is also tied to issues/tickets that can lead to additional conversation with the team. This is because it becomes pretty noticeable if you’re committing messages that don’t have a ticket reference.
  2. The consistency makes it really helpful when you want to start digging into git histories, what I call git archeology, because you can reliably search for ticket numbers.

Revising history before sharing was probably the most eye opening for me. It was an argument for using git rebase --interactive in a way to help organize commits to tell a story. If the point of the commit is to communicate to a future developer what happened and why, then eliminating noise of commits like fix typo and linting makes that easier.

While these are trivial examples, Joel provided really interesting ones - like reorganizing the order of commits and merging them to be more complete units (e.g., combining a change with the test case written to cover it rather than leaving those as two separate commits).

Summary

Before seeing these talks and reading these articles, I thought I was doing alright with my commits, but what David, Tekin, Chris, Michael, and Joel showed me was that there’s so much more I can do - not just to help myself, but to help my team.

It’s a little extra effort, but it seems to be appreciated. I get comments from my teammates that they find my commit messages helpful, which is really all I could hope for.

Footnotes

  • 1 While he didn’t reference it explicitly, the examples Joel provided reminded me of Google’s Engineering Practices Documentation.
  • 2 Okay, I made that one up, but admit it, you weren’t sure for a moment!
  • 3 I alias my git log to gl which creates a concise picture using the following formatting. For more on the alias, see my post, Git: Pretty One Line Logs.

Hi there and thanks for reading! My name's Stephen. I live in Chicago with my wife, Kate, and dog, Finn. Want more? See about and get in touch!