How We Write Commit Messages
By Tony Dewan and Jason Gladish
Why Commit Messages Matter
If you’ve worked on a codebase of any age or with many collaborators, you’ve surely had the question: “why is this code this way?”
Maybe it’s an unexpected function name or a seemingly unused class. Maybe it’s a line you wrote years ago or a file someone else added yesterday. A quick git blame
should give you the answer, right? Well, that depends entirely on the relevant commit message(s).
Check out this gem:
commit 123416953e66f1361f382c26b254d76670f5bbfc
Author: [REDACTED]
Date: Mon Jun 3 11:50:45 2015 -0400
No description necessary
Or this beauty:
commit 123416953e66f1361f382c26b254d76670f5ffff
Author: [REDACTED]
Date: Wed Jul 3 8:22:12 2009 -0400
moving this file
These do little to help you understand what happened and why. You’re left to infer what you can from the diff and maybe, if you’re lucky, knowledge gleaned from who wrote the commit and the commit date.
What Makes a Good Commit Message?
Much has been written about what a good commit message should look like. While we don’t necessarily have much to add, we like the 7 rules:
1. Separate subject from body with a blank line
2.Limit the subject line to 50 characters
3.Capitalize the subject line
4. Do not end the subject line with a period
5. Use the imperative mood in the subject line
6. Wrap the body at 72 characters
7.Use the body to explain what and why vs. how
Even though we often feel the pain of bad commit messages, and even though we all agree on what good commit messages look like, we still don’t always remember to write the best messages. We’ve found that pair programming helps, but we’ve also adopted a much simpler tool: git commit templates.
Git Commit Templates
A git commit template is just what it sounds like: a default starting point when writing a commit message. They are a great way to give yourself guardrails and reminders when writing commit messages.
Adding one is simply a matter of updating your ~/.gitconfig
with a new section:
[commit]
template = ~/.gittemplate
That example references a file ~/.gittemplate
, which is just a plaintext file of whatever you want in your template. Just like in a commit message, #
are comments.
Here’s one to get you started:
# If applied, this commit will…# Explain why this change is being made# Provide links to any relevant tickets, articles or other resources# Was this co-authored? Uncomment the correct following line(s), and
make sure you use their official github email address# Co-authored-by: Name <github account email address>
This explicitly nudges you to follow rules 1, 5, and 7. We find that 3 and 4 are easy enough to remember without being nudged.
Line Length?
You may have noticed that rules 2 and 6 (line lengths) aren’t referenced or enforced by our template. You could add that to the template itself:
# If applied, this commit will…
# ------------------------------------------------ #
However, we prefer to configure our text editors to display custom rulers for commit messages.
For Sublime Text, the easiest way to do this is to click Preferences > Settings — Syntax Specific
in the Sublime Text menu while writing a commit message. This will open a file called Git Commit.sublime-settings
. Add this:
{
"rulers": [50,72]
}
For Atom, edit ~/.atom/config.cson
to have this:
".git-commit.text":
editor:
preferredLineLength: 72
'wrap-guide':
'columns': [50, 72]
Links!
Our template includes a section for links. We often find it useful to include links to documentation, to-do items in our project management tool, or reference other commit hashes. In particular, it’s often helpful to reference links in one of the earlier sections as a footnote. Here’s a commit message from our Instrumental AWS Integration that shows what we mean:
commit 123416953e66f1361f382c26b254d76670f5abcd
Author: [REDACTED]
Date: Mon Jun 3 14:35:30 2019 -0400
Add ApiGateway metricsWe already support Lambda, and many people who will want lambda metrics will probably also want ApiGateway metrics.We needed to add SampleCount as an allowed statistic because that’s the only stat that returns anything useful for that metric (per the docs[1] and manual testing.)[1] — https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-metrics-and-dimensions.html
[2] — https://basecamp.com/xxxx/xxxx
Co-Authorship
Our sample template also includes some lines about co-authorship. Some of our teams pair nearly full-time, and it’s always been annoying that the work generated by these teams was only attributed to the driver. Now we’ve got attribution baked into our templates! Even better, GitHub supports this format, so co-authorship shows up in its interface!
Tip: pre-populate your template with the correct name and email for your teammates so that it’s simply a matter of uncommenting a line.
Bonus: Diffs!
If you aren’t already doing so, we highly recommend passing the -v
flag when running git commit
. This includes the full diff in the buffer when composing a commit message. The diff itself won’t actually be in the commit message, but it’s incredibly useful to be able to scroll down to see what you’re committing.
You should definitely automate this into a default, too. You can make aliases in your .gitconfig
, or add a plain old bash alias to your environment (you maintain your own dotfiles, right?).
Also, if you aren’t already using diff-so-fancy, go do it right now! You’ll thank us!
Hopefully this helps you write better commit messages, which will help future you and future collaborators better understand what just happened in your codebase (which is the distant and confusing past for them).