As software engineers who use git or other similar version control systems, we tend to write a lot of commits. Is investing in good commits a worthwhile investment?
Why should you write good commits?
As engineers, it’s easy to focus on just the code because, after all, that’s what we spend most of our time reading and changing. I’m going to argue that Git isn’t simply a smart diff merger to help us put all code in the same place nor is it just a simple version control system, it can be so much more.
Clearing your head whilst coding
One way I use git commits is to help myself understand what I was doing the day before when writing/changing a lot of code. It gives me a descriptive context that I can read in order to understand what I was doing the day/hours before quicker than just reading the code. This is also useful as a way to share with your colleagues some change you want some feedback on, what better place to write your intentions than in the commit message itself?
Example:
Documenting the codebase
If you use git to manage your codebase, then every single line of code is being documented by the commit messages. Along with each change, there’s a git commit message, and if we’re able to document each change with some text describing it in a way that’s not tied to any external services, why not leverage that as a way to document your whole codebase as you write it.
Easier debugging
Let’s pretend that you’re working in a codebase where each commit clearly explains the reason why it was added. You are now looking at a piece of code and you want to delete it, but you don’t know if you can. Using git blame
to check the commit itself lets you understand when and why that change happened. You can then know whether you can remove that code (if it’s not needed because it was added as part of an experiment that has finished, for example) or whether you should keep it (it’s really important because the specific version of your DB requires that for example).
Another git tool that can help us with debugging is git bisect
, which helps you find out which commit introduced a bug by helping you check commits using binary search. In this situation, it really helps having atomic commits that have one change only and that are well written so it’s easier for the person debugging to figure out which commit introduced the bug, but also why we made that specific change to answer questions such as: can we revert it?
And speaking of revert
, that’s another good example of how good commits can help you. If each change is isolated in a commit, then it’s easy to git revert
just that specific commit (or some) to fix a problem in production, when speed is crucial.
OK, then what is a “good commit”?
Let’s split the commit into two parts, the code change and the message.
The code change should be “atomic”, meaning it should not break tests and it should be contained in a particular change.
Good example:
- Implementing a new API endpoint including tests and documentation
Bad examples:
- Implementing a new API endpoint, tests and documentation in three separate commits
- Implementing a change to the code and another commit to “fix tests”
With atomic changes, it’s easier to run git bisect
for finding out problems since you know that every commit keeps the build green, so you won’t have noise with whatever command you’re running to find a particular commit when bisecting and it’s easy to git revert
it for the exact same reason.
As for the message, it should focus on explaining why the change is being added to the codebase rather than what it’s doing since that’s already described in the change itself, this way when you check a commit for a piece of code you’re curious about, you can use it to understand why that code was written and its purpose (when it’s unclear from the code itself).
What’s next?
OK, I managed to convince you and you want to write commit messages that explain the reasoning behind an atomic code change to the code, what can you do next?
- When writing a commit message, ask yourself whether the message explains well the reason for the change to be added to the codebase.
- When making a commit, consider if it can be amended with another commit or if it’s an independent change that doesn’t break the tests.
- Make reviewing merge requests commit by commit a part of the code review process so that you’re only merging good commits into your codebase.
- Share this article with your team and friends (who use git) :)
Resources
Because I’m standing on the shoulders of giants, here is a selection of talks/articles that helped me write this article and have helped me improve my own git commits during my career.
- Joel Chippindale | Simplify writing code with deliberate commits talk
- How atomic commits make you a better coder
- Pro git book | "Rewriting history"
- A good talk on git including a story of why git commit messages are useful
- The pro git book is free and a great resource to learn more about git: https://git-scm.com/book/en/v2
- Tom Stuart offers writing git commits as a solution to “Get off the tightrope”
Top comments (4)
I decided to write articles specifically because of this topic.
My bar for atomic can be a little lower. Separating code change from new tests can be clearer. Test changes can touch many files and risk hiding where the actual code changes are during review.
Being is QA, it can be nice to have test commits broken into many as well.
dev.to/jessekphillips/git-is-a-com...
For me, personally, it depends. If I introduce new test specifically because the change I made, I'd rather keep both within a single commit.
But, if during my work I spot some uncovered case for example, I create a separate commit with that specific test.
There's a really good npm package that enforces good commit message and other practices
It is commitizen...
While I do agree that commitizen is useful for enforcing good commit messages, I personally prefer to have human-first commit messages rather than something to be parsed by a program.
Commitizen is also helpful for building a changelog automatically, but one advantage of doing that manually is that you get a (potentially) more readable changelog/commit messages.
Disclaimer: I never used
commitizen
I only know what it's capable of.