The other day, we were having a meeting about documentation. There was a conversation about where we currently stand and what to change: what to document, how and where to do that and how to make sure the writing stays current. We all know developers are notoriously bad at documentation — we just want to write code and be done, right? Well, almost. We also know it’s important not to skip out on writing some things down every so often. But we’d rather not.
There are many forms of documentation and they are intended for different audiences. For instance, the readme file of a repository is the perfect place to explain how to set up a development environment. A wiki can be used to gather information about the design of an application, or to list the concepts used in its development, or to explain the features to non-developers who need a reference to look things up in.
Closer to the code itself, there’s obviously the possibility to write comments, but as you might know, having to write comments often means you should rather rethink the structure and naming of your code. After all, good code often doesn’t need comments and even necessary comments run the risk of not getting updated when the code does, and becoming obsolete. Uncle Bob taught us that.
A more useful way of documenting code is writing commit messages. A good commit message can be a really powerful tool; it’s directly coupled to an exact code change and will remain in version control for as long as the repository exists. When the code associated with the commit message is changed, it’s simply committed again, with another message. And again, and again, building a history that, when the messages are written well, tells a story to anyone trying to understand the code and the intent of the developers who have worked on it.
Have you ever worked on a piece of code which you wanted to change, but were unsure about? Chances are that piece of code wasn’t your doing to begin with, or it was something you’ve written a very long time ago. You might have only wanted to change just a couple of lines, but there was just this one structure to it that was odd. It seemed to be there for some very specific reason. Can you change it without breaking something? When you can’t find a comment explaining the choice that was made and the unit tests offer no additional insight, how would you know what to do?
Well, in my case, if I want to know the story behind a line, method or class, I just look up the commit history. It tells me how this file started and which steps were taken to get to the current version. And the commit messages should be able to tell me why. Why was this if-statement nested the way it was? Why is this method here? Why is this variable passed by reference? Why was the check for Variable X deleted?
Unfortunately, not all commit messages are created equal; some are written quickly and without thought, resulting in loss of information, context and therefore clarity. I’d like to walk you through some things I think are useful to keep in mind when you’re committing your code. If you keep these things in mind, you’ll help yourself and others in the future. You’ll prevent mistakes, duplicate code, loss of time investigating a problem and more, just by committing the right pieces of code along with useful messages.
Split up your commits
Before I talk about the messages, I’d like to emphasize the mistake I see most often: committing too much code at once. Sometimes, when I investigate a change, I look up the diff for one commit and I get twenty (or more) files committed at once, with a one-liner describing the change. Now, sometimes, this is perfectly fine: if you add a new language to your set of language files, it’s no problem to commit a whole set at once. Everyone will understand that your commit represents the addition of a translation. But if you’re building a feature, carefully writing file after file and making changes in existing files, it might not be so useful to do a
git add . followed by a
git commit -m "You can now also ride rollercoasters."
Wondering why that’s wrong? As a set of changes, it might make perfect sense to unite them. But there may be a lot of design choices involved in introducing a new feature into your application. Sometimes, to make room for a new feature, you have to make changes to existing code that, when left unchanged, would prevent this feature from being functional. So you change it. But in the context of the original intent of this code, it could be less clear to another reader. And that’s where splitting your commits becomes useful; if this one change were to be investigated by someone looking at the history and they would only see “you can now also ride rollercoasters”, it would be confusing. ‘Yes, rollercoasters, fine, but why did this variable change from A to B?’ or ‘What the hell does this change have to do with that?’ Those questions could be answered by looking at the code or asking the developer who wrote it, but the former can be time consuming (and error prone, because of assumptions) and the latter depends on the developer still working at the company and still remembering what they did in the first place.
Split up your commits. If you do that, you can write a separate message for the change in the existing code. ‘Changed A to B to support variations in X.’ Include a reference to your issue tracker for context, if you want, but at least write a clear message. And use those extra lines. A Git commit message can be a one-liner, but it can also be a subject line, followed by a blank line, followed by a longer explanation. And because you’ve split up your commits, you can now be very specifically describe this one choice, this one change. And other changes.
And I don’t just mean that you should commit files separate from each other (after all; sometimes, you shouldn’t separate them, because they’re a unit). You can go even further. It’s okay to change three things in a file, and then do three small commits with different messages. Smaller often means ‘more accurate’.
Cover what you’ve changed
Don’t be lazy in your commit message. Don’t say ‘added Windows support’ and include a change that has absolutely nothing to do with supporting another operating system. That’s infuriating to Future You. Or me. Someone will look at the commit history, wonder why a change is there and see a commit message that doesn’t even closely begin to describe why the change was made. Yes, this is really a commit splitting issue; you might have made several changes that don’t belong together and then added the whole bunch to the Git index before committing. You probably didn’t inspect the diff for your changes before committing. A blind commit. That’s another crime altogether. But sometimes, the ‘whole bunch of changes’ does make sense to commit at once, but you just didn’t take the extra two minutes to accurately describe what you did, and now your future teammate is hating you for being so careless.
Cover the change. Write a commit message that serves as an explanation for roughly every line that was changed, which helps others make sense of why it was changed. If you can not cover the change in one message, you need multiple messages. Again, that’s the splitting again. Small commits are your friend.
Describe the change, not the problem
I’ve seen people copy paste the headline of the bug they were fixing into the commit message. “Submit button doesn’t work”, it will say. That’s just weird. Did you mean your commit deliberately results in a button not working anymore? Yeah, I didn’t think so. Don’t write that. Say “Added action attribute to form” or “Added type attribute to submit button” or whatever describes your change. Maybe add a commit message body indicating that “This makes the submit button work as intended” or something like that. If I read a commit message, I don’t (only) want to know what the problem was. I want to know what the change was. When you only describe the bug, you are not documenting how you’ve fixed it. My example above is simple, but what if you needed to rework a method completely to make it possible for a bug to be fixed? Just using the bug report title as the commit message won’t always explain why your change fixes that. Cover what you’ve changed.
A variation on this is “display bug fix” or something like that. It’s just briefly describing the area of the bug and mentioning that it’s fixed, but neither mentioning what the bug was or how you’ve solved it. Nobody can learn from that.
I recently saw a message along the lines of “elements will not show when empty”. That’s a clear and concrete message. It describes the change exactly. Or does it? Do these elements need to be shown regardless of emptiness? Or do they need to be hidden when empty? Oy. Does the commit message describe the problem or the solution? You can probably find out by reading the code, but you shouldn’t have to. Keep that in mind when writing your message. Mistakes could be built upon the wrong assumption made about your intent.
Don’t be funny
Ever seen someone write “fixed a whoops”? You probably don’t think much of that person, for two reasons: they didn’t just made a mistake (we all do, it’s no biggie), but apparently a stupid one, and then they weren’t even mature enough to admit what the mistake was, covering it up with baby language. Trying to make it seem as if screwing up is somehow amusing.
There are ‘random commit generators’ that supply you with a random message to use in your commit message. Oh my, aren’t we the rebellious rockstar developer with the sense of humor. Look how brazenly we’re just putting gibberish into these commit messages, defying The Man. Nobody reads this stuff, anyway! Wrong. Well, maybe nobody reads commit messages in your team, but if you’re serious about the quality of your work, you should be serious about describing it, too.
Write clear sentences
Encourage yourself to write a clear, full sentence, instead of just something in telegram style. I’ve seen “fixed requires” to describe a change in the paths used to require some files. That may be fine, but if you try to create a full sentence, with a subject, a verb and an object, you force yourself to think a bit longer about what you’re writing. Maybe you would have come up with “Require path A instead of path B” and then continue with the why of that change. And while you’re at it; start these sentences with a capital letter. I even end them with a period, but that’s a personal choice and some people deliberately don’t do that. That’s fine. Just write that sentence.
Don’t include unnecessary details
I haven’t seen this done in a while, but it might still occur in your team: including details that don’t help anyone and just clutter your history. Don’t start the message with your name, or a prefix like ‘changed’. Yes, it’s a change, that’s why you committed it. Duh. And I know you wrote it, your name is already attached to the commit (if it’s not, run
git config and fix it immediately). The commit is not about you, so leave your name out of it. Even if you're committing on your teammate's computer because you're pair programming.
So if you’re tempted to write “Bruce — changed: added category ‘messages’”, just write “Added category ‘messages’.” Don’t be a dick, Bruce.
Do include useful details
At SIM, we have the rule that commit messages start with a reference to our issue tracker. Our commit sniffer even checks for it; if we omit it, the commit will fail. But even if it’s not a requirement in your company, it might still be useful. The ticket in your issue tracker probably describes what was asked of you that lead to you making this change, right? It could help having a reference, so you can look it up for context. (For us, it’s also about having a reason for every commit: if you can’t name the issue number with the change, then why the hell are you apparently working on stuff that’s not in your sprint?)
Other details might also be useful, if not in the subject line, then at least in the message body. For instance, maybe you’re implementing a workaround because there’s a bug in your programming language you can’t fix right now. By all means, include a link to that programming language’s bug report in your commit. Or to Stack Overflow, GitHub or something else if you think that’s useful. It’s documentation, after all.
I’m paraphrasing an existing commit here: “added entries to filename.php so that a new module Something would show up in CMS > Menu-item > Sub-menu-item > Area on page. modified: filename.php”
I’ve only changed the filename, module name and the ‘crumbtrail path’ inside our CMS to make it more anonymous, but this is otherwise an actual message. It’s clearly too long. It doesn’t fit in the list view of my Git client. That’s because it tries to include too many details in the subject line. The actual change was just involved with activating a module, and yes, activating makes it show up in some place. But it was neither required nor necessary to mention the navigation path or the file that was changed (I can see in the diff which file was changed).
The commit did things right: it covered the commit. It was separated from other commits. It’s a clear sentence. It’s unambiguous. It included useful details, or so the developer thought. It would actually have been a great message, if not for the fact that “Activated module Something” would really have been sufficient.
All of the above comes down to one thing: your commit message is there to explain your commit. It’s meant to be helpful to anyone working on the code, including Future You. Think about that when you commit. What can you include or leave out when writing your commit? What describes the change most accurately? How can you help yourself when you come back to this after the summer break? How can you help me when I need to continue on your code while you’re on your summer break?
Documentation is important, but all forms of it are optional, except for one thing: the commit message. Don’t treat writing a commit message as an annoyance, an afterthought. It is a first class citizen of your workflow. Make it helpful.
So, what do you think? Is this all known territory to you, or did these tips inspire you to improve an area you didn’t know needed improving? Do you agree with the statements I made, or do you think they’re not as important as I made them out to be? Do you have additions to the list? I’d love to read your comments below!