We've all lived the XKCD about git commit messages at some point.
I am no exception. This is what the commit messages for my blog look like:
fixxxx stuff
post
post
post
post
posts
mmm
posts
front maddy
Add chris oliver
add syntax
article
add git patch article
fix video
video
arty art art
Fix links
oops
Because my blog's git history is only ever seen by me, that's okay. I've accepted that I'll never be able to take full-advantage of git in my blog, and I'm totally fine with that.
Unfortunately, some people treat real projects with multiple contributors a lot like I treat my blog. I've found that this practice is the result of ignorance rather than laziness. So I'm going to share some tips on how you should use commit messages in real projects.
Why should you care?
😤 I don't care, skip to the template! 🚀
Git is a powerful tool, even if you only use it for keeping a history of code changes and don't take advantage of its most powerful features.
However, you'll find that the deeper you dig, the more powerful git becomes. You'll also find that many of the most useful features of git work under the assumption that commit messages are helpful.
Think about the last time you used git blame
. Would it have been helpful if you found a commit message that read, fixed a bad bug
? Probably not, you were probably trying to find more context about code you were working on; you needed an explanation of what and why.
Git commit messages must include the what and why behind each change so that the brave git spelunkers of tomorrow can step into the headspace of a commit's author. If a commit message doesn't include that information, why write one at all? Commit messages are only useful if they are useful to someone trying to understand a change at some point in the future.
In order to create a template for a good commit message, I'll break commit messages down into several sections.
First, the subject line
In a commit message, the first line (sometimes called a subject line) should be isolated from the body. Ideally, this line summarizes the changes made in a commit.
When I write subject lines, I try to finish the sentence, "This commit will..."
For example, I might write a subject line that reads something like, Remove unused, commented code
. That would finish my sentence nicely: "This commit will remove unused, commented code."
When it comes to formatting your subject line, there are one or two rules to remember.
First, the first character in your subject line should be capitalized; this is just a common convention. In my experience, it also makes it easier to read long lists of one-line commits.
Second, your commit message shouldn't be longer than fifty characters. That is because tools like GitHub truncate the line at fifty characters. Therefore, to allow others to effectively scan and grok your subject line, you should try to summarize the entire change in fifty characters.
The first line of my commit message template looks like this:
Summarize the change in less than 50 characters
Next, the first body "paragraph"
In some commits, the subject line is enough to convey the entire idea. For example, if your commit will Add a comma to the README
, you probably don't have to explain yourself.
However, in most commits, your changes might benefit from some additional context. We don't want future developers to be missing context while trying to understand the reasoning behind a change.
This is where the message body comes into play. I divide the body into "paragraphs," which are just loosely defined strings of text separated by white space. They can be bullet points, sentences, or something else; it's just important that they are easy to read and understand from a cold start.
In the past, I usually used the first paragraph of a commit message body to explain what I had done. These days, I've moved away from what and started documenting why.
Ben Orenstein recently changed my mind on how I format commit messages:
So, in this case, we want to lead with why we are making the change.
Here is an example:
Refactor the coupon UI
Because:
- The old UI code is fairly slow
- There were a few unused dependencies
- The old UI has aged poorly
The great thing about these "paragraphs" is that there is only one formatting rule: Wrap at 72 characters. This is more of a legacy tradition than anything substantial. However, the primary reason is that this allows git some space to indent (assuming a max character limit of 80). I recommend following this rule even though it's not always strictly necessary.
Here is the commit message template so far:
Summarize the change in less than 50 characters
Because:
- Explain the reasons you made this change
- Make a new bullet for each reason
- Each line should be under 72 characters
Now the second body "paragraph"
Now that we've summarized the change and shared our reasons for making the change, it might be prudent to explain exactly what we did in a longer form.
I use the second "paragraph" to give a more detailed explanation of what I did in the change, for example:
Refactor the coupon UI
Because:
- The old UI code is fairly slow
- There were a few unused dependencies
- The old UI has aged poorly
I thought it was necessary to remove some of the old coupon UI code.
Unfortunately, it has aged pretty poorly, and I think this refactor makes
the code much easier to support in the long-run. Primarily, this commit
improves the performance of the coupon component. It also removes some
unused dependencies.
This section of the commit body should explain what was done with a little bit more depth than the 50 character summary. The formatting is up to you (as long as you're wrapping at 72 characters).
Here is the updated template:
Summarize the change in less than 50 characters
Because:
- Explain the reasons you made this change
- Make a new bullet for each reason
- Each line should be under 72 characters
Explain exactly what was done in this commit with more depth than the
50 character subject line. Remember to wrap at 72 characters!
The other sections: Additional notes and co-authors
At this point, we're writing effective and coherent commit messages. However, sometimes a commit message needs a few extra notes. That can be done in the last section.
For example:
Refactor the coupon UI
Because:
- The old UI code is fairly slow
- There were a few unused dependencies
- The old UI has aged poorly
I thought it was necessary to remove some of the old coupon UI code.
Unfortunately, it has aged pretty poorly, and I think this refactor makes
the code much easier to support in the long-run. Primarily, this commit
improves the performance of the coupon component. It also removes some
unused dependencies.
These changes should resolve issue #1337.
This commit removed the left-pad dependency, so please stop using it!
Co-authored-by: nspinazz89 <nick@example.com>
In this example I was able to:
- reference a related issue
- add a line to warn that I removed a dependency
- include a reference to a person that worked on the commit with me
At this point, anyone who looks at this commit message is going to know:
- What was done at a glance
- Why the change was necessary
- The details about what was done
- Any useful details concerning the change
This makes our commit message infinitely more useful to our future selves and any other developers who need to understand our code.
Even if you disagree with my methodology for writing commit messages, it's hard to deny that we must write commit messages that allow other developers to step into our headspace when they are reading our code.
I think most people agree that a hallmark of "good" code is maintainability, you can augment the maintainability of your code by writing commit messages that help others understand and even change your code in the future.
The final template
Summarize the change in less than 50 characters
Because:
- Explain the reasons you made this change
- Make a new bullet for each reason
- Each line should be under 72 characters
Explain exactly what was done in this commit with more depth than the
50 character subject line. Remember to wrap at 72 characters!
Include any additional notes, relevant links, or co-authors.
There's more...
I'm writing a lot of articles these days, I run a podcast, and I've started sending out a newsletter digest about all of the awesome stories I'm hearing.
You can also follow me on Twitter, where I make silly memes and talk about being a developer.
Top comments (45)
Nice guide, great points here.
I think commit-messages should be a lot like commenting code. Instead of re-stating the obvious in the commit message, having some meaning definitely gives more value. My general rule of thumb is to write a complete statement, not a question, sentence fragment, or a word. It should have a subject and a predicate in it. That is not to test people's English skills, but to ensure that it provides meaning.
I noticed some repositories have a policy on prefixing with "feat", "fix", "docs", etc. but I'm wondering if anyone finds those useful? To me, those seem like unnecessary clutter and are a crutch for not writing useful commit messages. Is "(feat) Add users" better than "Implement functionality to add users"? I suppose the argument could be they are easier to scan in a listing, but if it is an invitation to be brief then wouldn't that mean having to look deeper into it to really figure out what it is?
"I noticed some repositories have a policy on prefixing with "feat", "fix", "docs", etc. but I'm wondering if anyone finds those useful?"
There's an
npm
package named commitizen that does just the same, it enforces to select the type of modifications that were made and it appends it to the beginning of the commit's subject, I personally find it useful but not strictly necessaryThere are cases where prefixes like that can be useful - writing "fix" followed by an issue number can automatically resolve said issue on Github, and there are similar integrations with for example JIRA. Granted, it doesn't have to be a prefix, or even be in the subject line for that matter - but still.
Outside of automated stuff like that I suppose it comes down to personal preferences. In my case I have found prefixes like that to be useful sometimes when skimming through a log on projects with multiple people.
I like having a Jira (or whatever platform) issue number in it. Even if there is no automation set up to read that, usually the Jira issue title/description/comments give more history of it that might not be captured in the commit message.
As a maintainer, I see the benefit of having some of those prefixes, but I think you can lean on GitHub or GitLab labels for that kind of support.
Good thoughts!
One team I heard of uses a standardized set of emojis in this same way.
How would that work? Replace ✔ for "fixed", 🆕 for "feat", 📄 for "docs" in the commit messages or something?
I believe this was the article I read:
Semantic Commit Messages with Emojis
Jonathan Irvin ・ Aug 1 '18 ・ 5 min read
Those pefixes can be used for automatic versioning of a library with a tool like semantic-release
Tagging your commits with the associated ticket I think is the most essential part of a git commit.
I do understand that the author is focusing on just the content. So it's just me saying in addition to.
Depending on your size of the commit you may want to consider how verbose a git commit message should be.
I suppose if you squashing multiple commits to merge into a branch you could then be more verbose. I guess this going to depend on your workflow.
No opposition here, just some thoughts.
Absolutely. I'd say 50% of my commit messages are subject line only, you don't always need a commit message with this much context.
I also think tagging a related issue is critical, but of course, that is assuming your issues are kept up to date! 😉
I don't tend to squash commits when I have a choice. I tend to err on the side of too many commits. Atomic commits have always served me well and I would be afraid to lose some of the benefits by squashing too frequently. 🤷♀️
I used to work for a startup where one of the co-founders insisted you always have a hyphen between the commit message and the id eg.
Pull requests would be halted for this superficial format. A simple hook could have enforced that formating to satisfy the co-founder but they also refused to accept an automated solution.
Insanity!
There is enforcing reasonable processes and rituals, and then there is being picky. ;)
Great article! What are your thoughts on the Conventional Commits method?
My commits all have a type and a scope plus some info if necessary:
Should be "add" though, iirc. So I can read your commit like "this commit will
add pricing page
".But nevertheless, I'm using this method too and it's great. It looks nice and understandable in the commit log and I can even generate the changelog file without worrying about manual editing of changes.
I like this kinda commits. I'd add a scope and type like the Angular commit message
Something like
fix(User container): blabla...
Furthermore with this kinda commits you can generate a sweet changelog effortlessly.
Nice article, in my company we use the id of the jira task, for example:
"TEST-123: This is my beautiful explanatory commit".
This later shows up in Jira and we know that there is already a commit, PR for a certain task by using the Git plugin for Jira.
The last company I worked at did this with Clubhouse (sort of like Jira lite).
I love how people in 2019 still repeat the 72 characters limit mantra like they were developing kernel under Linus supervision using terminal from 1984.
He said 50 this time.. Our terminals are shrinking. 😱
72 is good for the subject line as a guideline. It shouldn't be enforced in any way. I prefer git clients that just give me a warning when I cross it.
How about the commit body? I've seen some people do manual word wrapping/line breaks there, and some git clients warn when I don't. Any reason to do manual word wrapping?
And markdown syntax in the commit message body, yay or nay?
Do whatever works and doesnt get in the way in your team.
Thats my recommendation. ;)
I prefer 50 for the subject line specifically because that's when GitHub starts to truncate.
I have my line wrapping done automatically, though.
Obviously, it's preference, I like it though.
I really like the template idea. I find quiet often that commit messages are not useful, or they were set the time. But as time went in, they became hard to understand or contain zero context. For which I am also very guilty of writing
I'm not always the best at following my own advice here, but having a template goes a long way towards remembering to follow a convention.
I can see how this would be useful, but I think Ben's point about why people look at commit messages is super important.
I don't use
git blame
to find out what was done nearly as often as why.Carrying a good message , but the template is not practical .
If even we force coders to write such a long commit messages the commit count will drop because they fear to commit, you need to get more familiar with the human nature. No matter what is the standards we do the easiest one
Interesting opinion. It doesn't affect me in that way. I also don't write every commit message like this: at least half are subject line only.
I dunno. I think the diffs speak for themselves. If I want to know what changed, I look at the diff. Isn't that what everybody does?
ETA: I don't really have time to write pretty commit messages knee deep in feature requests.
That's sort of the point of the article. A commit message should be about why not what. What is only useful as an afterthought to support the why.