Write joyous git commit messages
Tips (or a convention) for writing good commit messages in your source code version control.
I have been known to write very long git commit messages. What follows is a guide to writing good commit messages in a style that I like for my projects.
Why I have high expectations for git commit messages
There are two main reasons why I care about git commit messages in my projects:
- Some projects are very serious either because of web security issues or human safety, and serious projects require accountability. When something goes wrong in these projects, it is important to know the exact cause: what code change was incorrect, which end-users are affected by the problem, why the change was made, etc.
- Good work deserves to be joyously shared. After spending a week on a new feature, it would be a shame if the creativity, problem solving skills, and tenacity that went into it were forgotten. Not just for your ego, but because your whole team benefits from learning about how challenges were overcome.
There are of course many other reasons to write good commit messages. A long git commit message isn’t a replacement for code comments, unit tests, end-user documentation, and discussion in GitHub issues and pull requests, but in my projects, I have particularly high expectations for commit messages.
This guide work best for single commits that contain a complete logical change. When committing intermediate work, hold off on this guide until you’re ready to write your pull request message or when squashing commits.
Here’s my preferred way to write a good commit message:
Quick version: A template
(See below the template for a comprehensive guide.)
Explain how to write a joyous commit message with a good verb ----one blank line-----The subsequent paragraphs explain the commit from the perspective of a user, your manager, the code, and git --- in that order. Use Markdown formatting and assume familiarity with the purpose and general architecture of your project to the extent that a junior member of your team will understand it. See lower down in this post for more details about these questions.It's hard to write commit messages and my team members have asked for help. This guide explains how to write a good commit message. [Talk about what a user would see (a bug, a new feature) and what user goals weren't being met. If the commit fixes a bug, describe how the bug was discovered and steps to reproduce it.][If this is a bug fix, what was the mistake in the application logic? Be precise. Act like a detective and report your findings.]I decided to write a Medium article with examples. I thought about putting this post on GitHub but decided it was more important for it to be easy to read. [Why did you make the change this way? What other ways did you consider but reject? Explain how amazing your work is.][What risks are associated with making the changes in the commit? Will anything else break? Are the changes backwards-compatible? Is there any "tech debt"?][Explain the source code changes. Changes that are fully explained in code comments don't need to be repeated here. Use bullets.]* src/main.cpp: The function parameters are updated and all of the places the function was called were updated.
* src/driver.cpp, start() function: This function is removed because it is no longer needed.I ran this Medium article by some friends to make sure it was clear. [Give evidence that the commit works.]This bug was caused by commit 24efaa88b17 on May 15, 2019. At that time, we tried to fix a related problem. The fix was included in version 1.2 of the application and affects all users of that version (and later) if they run the application with Administrator privileges. This commit reverts part of that commit.Fixes #101. See also #102. ZenDesk ticket 1001.See a longer discussion at https://internal.company/discussion/1701.
Now onto the detailed guide. We’ll start with the basic structure of a commit message.
Every git commit message should have the same first three lines:
Describe the commit in a short sentence fragment
This is an example commit message. The first line is a short summary. The second line is blank. The third line (this line) is a longer paragraph explaining the changes in the commit.
The first line should…
The first line is the hardest. It should:
- Be a short but comprehensive description of all of the changes in the commit — the first line may be the only line someone reads.
- Be between 50 and 72 characters.
- Start with a capital letter and NOT end with a period (because it looks nicer).
- Complete the sentence “After this commit, the application will…”. Start with an infinitive verb that tells what the thing in the repository will do after the commit like “Show,” “Compute,” “Deallocate.” Try to avoid verbs that describe your action rather than the application’s behavior— more on that below.
- In big repositories, add context using a “[bracketed phrase]” at the start.
Here are some examples of first lines for commit messages:
Show help text when the mouse hovers over the itemCompile with optimizations turned on
[documentation] Explain command-line arguments better
A little more on the first word of your message: Some say to use the imperative tense, which is basically the same thing in English as an infinitive. Try to find a verb that describes program behavior like the examples above. If you’re modifying documentation, use a verb that describes the document by completing the sentence, “After this commit, the documentation will…”.
It’s sometimes hard to find a good verb that describes program behavior, so if you can’t find a verb like that, you can fall back to a verb that is about the action you are taking, like “Fix,” “Add,” “Revert,” “Make.” In this case, your first line completes the sentence, “In this commit, I will…”. Some examples of these not-as-good verbs in first lines are:
Fix the document to include more details
Revert the last commit which broke the buildAdd files related to analytics which I forgot in the previous commit
Note the difference between describing the application’s behavior (“Show the user”) and describing your coding behavior (“Add a file”)! Describing the application’s behavior is best. (Reminder: DON’T use “Fixed,” “Reverting,” “Addition” — those aren’t infinitive verbs.)
Then there should be a blank line.
After that, write a longer explanation of the changes.
- Use Markdown to format your text. Some tools like GitHub will render Markdown when showing commit messages.
- Use asterisks bullets when you need to explain a long list of changes.
- The commit message should be clear on its own. Although you can and should link to discussions that have already taken place elsewhere, like in GitHub issues, the commit message should explain everything. Duplicate comments from discussions elsewhere if necessary.
Here’s an example of a short commit message using Markdown:
Include more details in command-line help textMore information about the *command-line* (not the *clothes line*) was added:* src/main.c: Command-line arguments now have help text.
* docs/commandline.md: Documentation added for the command-line arguments.
Your audience is junior members of your team.
The way you describe your changes and the technical jargon you use should be appropriate for communicating to a junior member of your team. So:
- Use technical jargon and assume familiarity with the purpose and general architecture of your project, but only to the extent that a junior member of your team will understand it. (Jargon is good when it’s clear and concise to your audience!)
- Your commit message is an opportunity to explain this part of your project to team members who aren’t as familiar with it.
- But it’s not just for junior team members — it’s also to make your message future-proof. In a few years, you’ll forget how your code works, or someone else might have taken over this part of the project and is new to it. Write for future team members too.
What to say in a commit message after the first line
Good commit messages will explain the same changes four times:
- From the user’s perspective: A description of how a user would see incorrect program behavior, steps to reproduce a bug, user goals that the commit is addressing, what they can see, who is affected.
- From a manager’s perspective: Design choices, your creativity, why you made the changes.
- From the code’s perspective: A line-by-line, function-by-function, or file-by-file summary.
- From git’s perspective: Any related commits in this or another repository, especially if you are reverting earlier changes; related GitHub issues.
Your message will generally answer the following questions in the order they are below. Answer each question in a separate paragraph separated by blank lines. If you’re writing a commit message right now, go down this list to write your message.
Questions from the user’s perspective
Start the body of your commit message by answering these questions that users of your application would care about:
What problem is being solved by the commit?
That might be a bug, a new feature, or an improvement to an existing part of the project. At this point, don’t talk about particular code changes — talk about it from a user’s point of view. Write about what a user would see in your application and whether their goals were being met. Use the past tense for bugs and the present tense for new features. Examples:
The program crashed when ____.
Users were not able to install the application.
The application can now output verbose information.Pages were loading too slowly (>150ms).
In this and the next few questions, you’re describing WHY you made the changes, not what the changes are. Use the commit message to record your thoughts from before you solved the problem while you still remember what you were thinking back then.
If the commit is fixing a bug, write how the bug was discovered.
What steps did a user take to encounter the bug? What are the pre-conditions for the bug to appear? Use the past or present tense. Examples:
When a user selects File -> New, the application crashes before the old document could be saved.
If application is installed in a read-only directory, then some menus do not appear.
If the commit is adding a new feature, explain what sort of end user is going to benefit from the feature and why.
Users who have MacOS computers need to be able to run the application too.
These questions could also be considered stakeholder impact.
Questions from your manager’s perspective
In the next few questions, you’ll answer questions that relate to the work you did but at a level of detail that your manager would care about.
What was the mistake in the application logic?
If the commit is fixing a bug, say what the application was doing wrong. Be precise about logic errors. Act like a detective and report your findings. Example:
The program assumed that all users would be using the same operating system --- that's wrong. We have seen at least three operating systems used by our users. As a result, hard-coded Microsoft Windows commands were failing on macOS computers.
Sometimes it’s difficult to drill down to the root cause of an issue. Try answering “Why?” five times building off of each answer in the next one:
The program computed the wrong value. [Why #1:] The formula was wrong. [Why #2:] There was a typo. [Why #3:] It looks like the code was copy/pasted from StackOverflow incorrectly. [Why #4:] I had gone to StackOverflow because I didn't know the formula. [Why #5:] We may need to train our team better so we know the formulas.
Why did you make the change this way? What other ways did you consider but reject?
Explain the architecture of the change. There may be multiple ways you could have fixed the bug or designed the new feature. Why did you do it your way? Discuss alternatives. This is your chance to show how amazing your work was. Write as much as you can. Don’t talk about code yet though. Example:
A permissions check solves the bug. A check could have been added at program startup or in the File -> New menu handler. I added the check in the File -> New menu handler so that the program would start.This was a hard problem to solve because there's no documentation in the component for how to write permissions checks, so I had to read the source code, learn some Typescript, buy the author a coffee, drive 100 miles to the nearest public library, and devise a new strategy for creating menu handlers.
What risks are associated with making the changes in the commit?
- Is some other part of the application now at risk of breaking because of the new changes?
- Are the changes backwards-compatible? Will any user lose a feature they rely on?
- Do the changes come with any TODOs? Have you made anything worse? Is there any “tech debt”?
Questions from the code’s perspective
The last few questions get down to the little details.
Explain every unexplained code change.
Provide an explanation for every code change you made that might not be clear from reading the source files. You can explain every line you modified, or every function you modified, or every source file you modified — as much as you need to ensure the reason for every change is clear.
If your code comments within the source files are really good, you can skip the parts that are clear from reading the commit’s changes.
Bullets are good here. Use the present tense. Example:
* src/main.cpp: The function parameters are updated and all of the places the function was called were updated.
* src/driver.cpp, start() function: This function is removed because it is no longer needed.
* src/driver.cpp, end() function: This function is added performs cleanup on program exit. It is used in main.cpp.
Give evidence that the changes are correct.
Every change we make to source code has a good chance of introducing a new bug, so it’s important to not only test our code but also to demonstrate that our code is tested. Include in your commit message how you know your change was right, such as creating a unit test, performing a user test, trying test data, etc.:
A new unit test was added to test this functionality.
I verified the software using input file 001-A which contains random data.
Pat tried out the change and said the application was easier to use.
From git’s perspective
The last part of your commit message creates breadcrumbs to other relevant information on GitHub or elsewhere.
If the commit is fixing a bug, find the commit that caused the bug and explain its impact:
- What commit caused the bug? Paste the SHA1 hash of the bad commit into your commit message. If the bug was caused by something not in the same repository, paste a link to a commit in another repository or issue tracker if possible.
- What versions of the application are affected by the bug? Which end users are affected by the error? Make it easy for users to know if they are affected or not.
This bug was caused by commit 24efaa88b17a754367585d6dab601fcdf19edcbf on May 15, 2019. At that time, we tried to fix a related problem. The fix was included in version 1.2 of the application and affects all users of that version (and later) if they run the application with Administrator privileges. This commit reverts part of that commit.
Mention any GitHub issues and external discussions related to the commit.
GitHub will look for any #1234 tokens and add cross-reference links to your issues for you. If you have another issue tracking system, add ticket numbers without #-signs so that GitHub doesn’t think you’re mentioning an issue on GitHub. Include links to any other relevant discussion. Examples:
ZenDesk ticket 1001.
Longer discussion at https://internal.company/discussion/1701.