When it comes to writing documentation, nobody wants to do the job. And whatever documentation does get written is quickly outdated because nobody wants to update it, either.
The most accurate documentation of how a system works is the code itself, but even “self-documenting” code falls short of describing why it was written that way. The next best thing is that little bit of text that gets attached to every code change: the version control log message.
Very often when I’m refactoring or starting work on a new feature, I first want to understand why the system works as it does. If the original author is still around, I may be able to ask them directly. But even then, they may have forgotten many of the details.
Having some historical context may also help. Knowing what happened before can help you avoid trying a tactic that was previously found to be a dead-end. When I’m explaining part of a system to a new team member, I find myself starting with some background on how it used to be.
Finally, having good historical documentation is invaluable when tracking down the root cause of a regression or other bug. And since it’s already part of your workflow, there’s no reason not to write good commit messages.
Your workflow and branching strategy can guide you about how much detail to include in each commit message. My preference is to use feature branches for new development, keep commits small and focused (like a single-responsibility principle for commits), and rebase when necessary to put things in logical order before pushing.
When working closely with someone else on the same feature, you might use your version control system to stay in sync, ending up with many tiny commits and meaningless log messages. In this case, it might be useful to squash the branch when it’s reintegrated, providing a more detailed log message at that time.
A useful historical record depends on good documentation every step of the way. I try to keep the following in mind when writing a commit message:
- Focus on “why” – Your code already describes how something is done, so this is your chance to explain why this change was made, and perhaps why it was done this particular way.
- Discuss alternatives – Sometimes, before landing on a solution, you have to explore some alternative implementations. Other times, you just run out of time and have to go with something. Whether you found another solution that was simply different, or you had to back-track from a dead-end, this information will be useful later on.
- Link additional information – If your commit is related to an item in your bug tracker, include a reference to it (some source control systems add these automatically).
- Be self-contained – The purpose of the commit should be clear from the log message, and it should not rely on the reader’s knowledge of other things happening at the time. Links to work items or wiki pages are definitely helpful, but they shouldn’t be the entirety of the message.
- Be consistent – Even small changes need context. A message that amounts to “fixed stuff” doesn’t help anyone!
When I’m sifting through the history to determine why or when a particular change was made, log messages are vital to my understanding. I make heavy use of
git blame to find the most recent commit that affected a certain line. I can then use
git show <commit> to see the full commit, or
git blame <commit>~1 to see the state before that commit (the
~1 is Git syntax to select the parent of the commit).
I’ve also recently discovered the
-S switch to
git log. It’s like grepping for a string in diffs, but better since it will only match if the string was added or removed.
Log messages are the easiest form of documentation to write. When they’re done well, your teammates and future self will thank you!