Writing better commits
I think we can all agree to have made commits where we just want to push the feature out without writing a detailed commit message
While we can fix this by doing an interactive rebase, it's not what we will be focusing on. Instead I want to talk about why and how we can make our commits more useful in general.
But first, let's discuss a little background
Communicating Intent
The primary goal of a software developer should be to communicate their intent to future developers - Louise Crow
And as such there are various ways of achieving that
-
readable and maintainable code1
-
code comments
-
Technical / Design documentations
-
Tests
Yes, tests can be considered documentation too. They are some of the best ways to document edge cases and to explain behaviours for how any user of an application/library would go about using it.
All of these things are about communicating intent. To explain to any future developers (that may also be you) how and why you wrote something the way it is.
Where does Git fit in?
Developing features is hard, and that is when you know what you are working with. More often than not this will not be the case.
Say, none of the above listed things helped you, maybe because of a lack of proper documentation or because they are simply outdated. So, when you find yourself in times of trouble, Mother Mary may not come to you2. Instead, you will have to go and ask someone else on the team about it. Now it may be the case that,
- The person who worked on the feature left the team.
- They are still with the team but can no longer remember why they wrote it that way.
Well, that's just bad luck, or is it?
That's where having a good reference history helps us. Git is a living, ever-changing, searchable record that tells the story of how and why the project came to be what it is today.
Your commits, if you do them well, offer unique benefits over other ways of explaining your code:
- They never change
- They live alongside your code
- They're searchable with commands like
git grep
orgit log
- They allow you to document your changes at the time that you made them
Every line of code is always documented - Mislav Marohniฤ
This allows you to debug things quicker because your project will have a searchable history. You'll have access to why this particular code change was added which will prevent you from re-introducing bugs.
Git on the train
Here are some principles to guide you on your journey abord the Git train ๐
1. Make atomic commits
Atomic messages are all about making your commits about a single isolated change.
Large commits are difficult to read, especially when they contain changes that are unrelated. It might be difficult to reason about what constitutes as unrelated when you are making the commit, so there's a simple rule of thumb. Avoid using and in your commit messages.
Similar to how you split a feature into multiple smaller tasks, split your big commit into small atomic ones that achieve one task, make sense in isolation, and when grouped together tell a larger story.
Sometimes it's not possible to make commits along the way, especially when you are still figuring out how to implement the feature. And that's all right, you do can do all the changes in one go and still make atomic commits. We know that we can stage some files but did you know that you can also stage only portions of a file?
When you have some lines in your file that you want to commit but some that you
don't - use git add --patch
. It will ask you which bits of a file you want to
add. It calls these bits hunks. If that's too much for you (like it's for me),
a lot of modern code editors like VS code make this process a lot easier and
that too out of the box without the need of any extensions.
So you will just be making a lot of atomic commits after you are done ๐
2. Write good commit messages
That's a pretty vague statement, so here's a template that might be a good place to start. However, keep in mind that each commit is different.
short one line title
longer description of *what* the change does (if the title isn't enough)
An explanation of *why* the change is needed
Perhaps a discussion of context and alternatives that were considered.
You at the time of writing this commit have the most knowledge about this piece of code. Only you know the alternative approaches that you have may thought of but ultimately ruled out. Keeping them in provides much needed context to future developers in understanding why the code is the way it is.
Along that line, it helps to look at the commit from the perspective of another developer. What questions might they ask looking at your code? What might not be immediately obvious to them?
PSA: If you are linking to tickets that's great, but don't rely on it for context. You never know when your ticketing hosting might change. So always put all of the details in the commit message.
Further Reading
- A Branch in Time (a story about revision histories)
- Getting more from Git / Alice Bartlett / ffconf 2019
- Static types are also a great way to communicate intent that makes it clear and unambiguous what the code does.โฉ
- sorry about that ๐ , see Let it Be by The Beatlesโฉ