How to write commit messages (deprecated)
A proposal for a standardized structure of commit messages
Updated on Nov/2020: I reviewed this guideline and published a new, improved version of what I think about commit messages. Feel free to agree with my old self, but my new self opinion is this: https://writingfordevelopers.substack.com/p/how-to-write-a-commit-message
A good commit message is one that your team agrees that is good. That said, I have the impression that most teams don't take the time to make this agreement and define a standard. So this is a proposal for a standardized structure of commit messages for teams that don't have it.
A commit message is formed by a header and a body. The focus of this proposal is the header, as it is the most critical part and the one that most needs a standard. As it is just one sentence, a proper structure is essential to help people understand it correctly. It is where most of your thought should go. Finally, relying on one line only to explain your commit will nudge you to shorter commits, a beneficial side-effect.
I won't propose a structure for the body of the message, but at the end, I make a few comments about its role.
The Header - Formatting
The formatting guidelines are only about keeping it short. A good rule of thumb is to keep it shorter than 72 characters. To help with that, I agree with two common pieces of advice for commit messages: never use a period in the end and always start with a capitalized verb in the root form - which is the one used for imperative or simple future.
The root form is the shortest form of the verb, and there is no need to transmit any meaning added by verb tenses. So use “Fix bug that…”, not “Fixed…” or “Fixing…”
The Header - Content
Some types of commits are suitable to be almost completely explained in a single verb. So the first step is to see if your commit can make use of one of these highly specific verbs with inherent meaning.
Stronger verbs for bigger changes
Use when fixing bugs and serious issues.
Don't use fix for minor changes like typos on variables, indentation or line breaks. You want the first verb to convey the most information possible. Train the reader to understand that, when they are reading a commit, fix is about something big. If you are fixing the indentation, use more generic and weaker verbs like edit.
Fix also brings its own proper structure:
Example: Fix bug that prevents the user from logging out
Merge and Revert
These are two strong verbs used by Github on some automated commits. If you are manually doing those things, you can follow Github's structure for it.
<Pull Request/commit header>
The Intervention + Effect structure
If you are not doing a fix, merge or revert, then you have to go for a more embracing verb that will convey meaning only in conjunction with the rest of the message. So you are not only looking for standardized verbs but a standardized structure. My proposal for this structure is:
Intervention (verb + object) + Effect ("to" + verb + object)
You change the code, and the code does something. You first explain what you changed, then you complement with what this change does to the software. This respects the principle of growing familiarity. First, you give the reader context, by telling where the change happens; then you present the new information of what the expected effect is.
The intervention = a verb + object contextualizing with what you did
The intervention Verb
The first verb is the most important to be standardized. This set of verbs will cover most, if not all, of your daily commits, but if you keep facing cases where a different verb is necessary, add it to your project's standardized set. The verbs are ordered by strength and specificity.
Use whenever it is a code refactoring.
It will signal that you are improving nonfunctional attributes of the software. It has prevalence over the other verbs below, even in the case that your refactoring is made by creating, adding or editing something.
Just like fix, refactor is also a strong verb. Use it when you are significantly improving the code design, not when you are changing indentation or other minor things.
Use when you create some new entity.
You might notice that this is a verb with a similar meaning of add, the next one on the list. This apparent redundancy is useful for differentiating between major additions, with a big impact on your code base and minor ones, with a local impact to that specific scope. A good proxy for that is always to use create when you are committing a new file to the code base.
Use when you add some incremental code to an existing feature.
Save it for when you are mostly adding new lines in this commit, not substituting some for others. This will differentiate it from edit. By reserving create for bigger changes, when you use add it is easy for the reader to grasp that these commit changes are more local.
Use when you delete code.
Likewise, save it for when you are mostly deleting lines in the commit. It should be clear from the first verb that this commit is about removing some feature with no side-effects or cleaning the code base from obsolete code - strictly speaking, this would be a refactoring, so consider delete to be an exception to the rule that refactor prevails against all others. If a refactoring is just deletion, use delete.
Use when you are making additions and deletions at the same commit.
It is to be used when you have an existing feature or code block, and you are just changing its behavior. Edit is the catch-all of the verbs. The last, more generic option, when no stronger verbs apply.
The intervention Object
Here you inform what piece of code you are refactoring, creating, adding, deleting or editing.
It might be a specific entity like a table, column, object, constructor, class, method, variable, etc. If not applicable, or if you are touching in different blocks in the same commit, you might use a more encompassing term like logic or feature.
Make the core of the change clear when choosing the object. If you are editing the name of a variable that happens to be inside a method, don't start your commit message with "Edit method...", because it will lead the reader to think you are changing the method's functionality. Use "Edit variable’s name..." instead.
If you are changing a named entity (a method, a table, a component, etc.), use its name. The more specific and comprehensible for the reader to know exactly where you are intervening, the better. Just don't repeat any information that is already covered by the file you are editing. Git already does the job of including the file(s) you are editing in the context of your commit.
The effect - a verb + object informing the consequences of your code
Once the reader knows the kind of change and piece of code you are changing, they have enough context to be informed of the effect that your code changes provide.
The effect Verb
This verb is chosen according to its effect in the real world. It may be business effects, particularly when you are creating a new feature; or it may be software development and management effects, like when you are doing a code refactoring or paying technical debts.
Some examples of this verb are: improve, avoid, change, allow, facilitate, etc.
The effect Object
Here you complete the information of what is the effect you are creating with your code. Naturally, it is highly dependent on the verb you chose. The creation of a new feature will probably allow the user to do something they couldn't do before. A refactoring will likely improve readability, maintainability or some quality of your code base.
It is your choice to go for a more literal description of the effect or to inform the second-order effect of what you are doing. Example: "Edit code styling in the tests to separate setup, action, and assertions" or just "Edit code styling tests to improve readability."
The body of the commit message
The header is the one that needs a standardized structure, but there are few guidelines for the body that will help the reader correctly understand the reasons for your commit.
You should use the body to answer why that commit is being made. Not what, not where, just why. You explain what your thoughts on creating that code were and why it is needed. It's mostly documentation for non-obvious modifications and future reference.
As for formatting, also try to keep each line shorter than 72 characters and pay attention to proper use of word-wrapping and paragraphs.
If your team makes the use of Pull Requests, its description might make the body unnecessary. The benefit is that you save some work, creating one encompassing description for several commits. The risk of doing that is that all that context information is locked to whatever tool you used to push the code, where the commit's body message is saved by Git.
This proposed standard tries to create an intuitive structure that is easy for the writer to remember and easy for the reader to understand. A standard is important because repetition leads to familiarity and instinctive comprehension. When there is a standard, the exceptions stand out for exceptional commits. If there is no agreed standard among your team, this might be a good initial proposal.
If you are reading this on the web, please notice that this is actually a newsletter with writing advice for software developers. If you want to continue getting tips on how to improve your written communication skills, please go subscribe below.
Thanks to Renato Zannon for reading a draft of this.