A commit message is simply a message that you add before staging your code changes, and that you can see on the history of your git repository; sounds very simple, but then, why everyone has such strong feelings about them.
As far as I can tell, there are two types of commit messages, ones that are informative and well written, and “some changes here…” kind of message.
In my view, and the many others, having clear commit messages is something we should aim for as it provides transparency of all the changes that happened on our project. It is, in a way, a simple form of documenting and can even make you a better developer.
On the importance of clear and informative commit messages
Before moving on to how to write good commit messages and even sharing with you my commit messages method, let me explain why it is crucial to have clear commit descriptions in your project history.
I’ll focus on explaining the importance of commit messages from different points of view:
I worked for a few years as a technical lead, and part of my work was to perform code reviews from multiple remote teams, which were sitting more than 10000km away and with 10 hours difference. Some days I’d get to the office to find a quite long PR, the work for a few developers for a few days, with hundreds of lines of code affected, where each commit would say something like “fixes.”, “more fixes”, “changes here.”, “committing”.
Besides the obvious factor here which I’m not going to get into of why PRs were so big, when I try to work on them I had many, many questions, which I couldn’t ask right away as I the team was already sleeping home (due to the time difference). So I would sit there trying to understand what was happening and trying to figure out from their commit history how changes evolved, to get a more clear picture of what was happening.
With commits like the ones I mentioned earlier, it was impossible, I had no chance, I’d review the code in the best way I could, and leave comments for the team to pick up the next day and provide the clarifications. It was inefficient.
However, believe it or not, after making some changes in the way we committed and by utilizing the system I’d detail next in the article, we made the code review process many times more efficient.
Due to the nature of the team set-up, we had some high rotation among members of the remote team; again, I won’t bother with the details on why it was just something we had to live with. Our codebase was quite huge for the team size and was quite intimidating for a new joiner, especially for those who had less experience as developers. We always had someone helping them integrate into the team, someone in their timezone, but it wasn’t an easy task.
Having access to the git history can help any developer understand how a particular page, service, file, or method evolved, or it can help understand why something got added, or when something got removed. But navigating through a world of “fixes”, “some text here”, “no message” can be very hard.
It may not sound like a lot, but for all those like me, who open the git history of a project when they first start working on it, it helps a lot!
Yes, having good commit messages can help even you out! Sometimes we are faced with questions like why is this button not here anymore, or when was that thing removed or added? And we often look for user stories that talk about that. But it’s not always there, sometimes we deleted something by accident, or we added something hard to find in a tool like Jira or Azure DevOps. However, it can be super easy to look at in the code and the commit history. So safe yourself some time, and create amazing commits!
I’m sure there are more scenarios where commit messages can be helpful, if you know any, please let me know on the comments section.
3 different workflows for commit messages
In teams I worked on over the years, I found three approaches for dealing with commit messages, and interestingly enough, they can be steps from which you can take your team from one category to another until your code history looks like an Allan Edgar Poe novel.
The first step is teams who don’t really care much, or they are unaware of the importance of commit messages, and they just put in there whatever they want.
Commit what you want, we squash commits when we merge
Some teams understand the importance of commit messages. Still, developers don’t want to be bothered with writing good commit messages, so they commit anything they want, but they provide a descriptive comment on the PRs. Those teams usually squash commits so that when you see the history, you only see the clear messages written on the PRs. The advantage is that you have a clean commit history; the disadvantage is that any commit that happened on the feature branch is gone.
This is not a bad approach, and I like it a lot, it’s definitely better than stage one, however, who’s reviewing the PR won’t have the value-added of clear commit message and valuable information can get missed from the project history.
Every commit message counts
At this point, every developer in your team writes clear and informative commit messages, which can be helpful during the code review process, and you don’t have to squash commits, and so you can access your full project history.
It can be a bit dangerous, though, as your history may grow substantially depending on how often developers commit.
My formula for great commit messages
Commit Message Format
Each commit message consists of a header, a body, and a footer. The header has a special format that includes a type, a scope, and a subject:
<type>(<scope>): <subject> <BLANK LINE> <body> <BLANK LINE> <footer>
The header is mandatory, and the scope of the header is optional.
If the commit reverts a previous commit, it should begin with “revert:” followed by the header of the reverted commit. In the body, it should say, “It reverts commit .”, where the hash is the SHA of the reverted commit.
Must be one of the following:
- build: Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm)
- ci: Changes to our CI configuration files and scripts (example scopes: Circle, BrowserStack, SauceLabs)
- docs: Documentation only changes
- feat: A new feature
- fix: A bug fix
- perf: A code change that improves performance
- refactor: A code change that neither fixes a bug nor adds a feature
- style: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc.)
- test: Adding missing tests or correcting existing tests
The scope should be the name of the npm package affected or the name of a module or component.
The subject contains a short description of the change:
- use the imperative, present tense: “change” not “changed” nor “changes”
- don’t capitalize the first letter
- no dot (.) at the end
Just as in the subject, use the imperative, present tense: “change” not “changed” nor “changes”. The body should include the motivation for the change and contrast this with previous behavior.
The footer should contain any information about Breaking Changes and is also the place to reference issues that this commit with Closes or References.
Breaking Changes should start with the word BREAKING CHANGE: with space or two newlines.
feat(Subscriptions): Support permission-based subscriptions Update the audience object to support permission-based References: #XXXXXX
Git histories are an incredibly valuable tool. However, it’s sometimes not clear what delimits a “good” commit message from a “bad” one. Also, the solution I provide may not be the best for your team. It is the solution I propose and try to implement wherever I go, and there’s nothing already in place. Be flexible; the important point is that a clear history matters, whichever way you make it happen.
Thanks so much for reading!