A guide to write good commit messages in Git

Git Feb 1, 2020

The time you had an archive file on your disk called "version 1" should be far away. I bet you use some tool for version control like GitHub. So you must write commits everytime you want to add your code to a project. Have you ever wondered if your commits messages are good? Maybe you don't like writing them and wonder why you have to do it every time you want to push code. After all, isn't the change sufficient enough?

This article will help you to create a good commit message. It will give you a (for me) good pattern to see on the first look, what happened in this commit message.

Why commit messages are important?

So, is the change sufficient? In my (and I hope many other) opinion, the answer is no!

But why?

Commit messages have a lot of uses. This is the first way to communicate with your fellow developers on a project. The change defines how you achieve something but the commit message explains why you are doing it. It must give enough context to avoid a contributor to wonder why some code is written like that. With proper explanations you won't spend precious time asking yourself why a developer pushed this code. In some cases like open source projects, busy maintainers won't even read your code if you don't give them a minimum of information like a nicely written commit message.

Peter Hutterer wrote:

Any software project is a collaborative project. It has at least two developers, the original developer and the original developer a few weeks or months later when the train of thought has long left the station. Peter Hutterer(opens new window)

In summary he will tell us:

"Commit messages are not only for your coworkers but also for your future self as Peter Hutterer"

A project is designed to be maintained in the long term. Sometimes years after a piece of code was written, you may ask yourself why it has been written like that. It happened to me this week with a function I coded only 6 months ago. With a well written commit message, it is easier to get back in the state of mind at the time you wrote this change.

Taking care of your commit messages can also simplify your daily life. Some tools becomes more interesting with a meaningful commit history like a few git commands log, rebase, cherry-pick, ... When you come back from holidays a simple git log --pretty will give you a lot of information about what your coworkers did while you were away. Writing good commit messages forces you to split your change, making it easier to review with git log -p.

Speaking of review, did you ever struggle rebasing your code on some change a developer made? It becomes easier to know why a change was made if the commit message carries real meaning. It makes rebase result much more predictible. Another example is git blame command which, by the way, isn't there to make fun of your colleagues, but to give you context on a specific line of code. It can be pretty useful when you want to refactor a piece of code.

Last but not least, a well structured commit history allows changelog generation between two versions of your project to inform your users what changed.

This is a huge amount of reasons to start taking time to write good commit messages.

How to write a good commit message

Now that you are convinced commit messages are important, let's talk about how to write good ones.

For example these commit messages are not consistent, which makes them hard to read.

fixex bug #72 
did some perfomance stuff
Remove built files
Add tests #81
hope it work
forgot files
Style. Markup syntax, wrap margins, grammar, capitalization, punctuation. Spell these things out, remove the guesswork, and make it all as simple as possible. The end result will be a remarkably consistent log that’s not only a pleasure to read but that actually does get read on a regular basis. Content. What kind of information should the body of the commit message (if any) contain? What should it not contain? Metadata. How should issue tracking IDs, pull request numbers, etc. be referenced? Chris Beams - How to Write a Git Commit Message(opens new window)

In the example above, we se that some commits are confused, because the meaning was spread accross more than one commit. To prevent this Chris say that there mus exists a commit pattern that meet the 7 rules to write a good commit message

  1. Separate subject from body with a blank line
  2. Limit the subject line to 50 characters
  3. Capitalize the subject line
  4. Do not end the subject line with a period
  5. Use the imperative mood in the subject line
  6. Wrap the body at 72 characters
  7. Use the body to explain what and why vs. how

I personally apply a subset of these rules:

  1. Limit the subject line to 48 characters
  2. Capitalize the subject line
  3. Use the imperative mood in the subject line

Not only does the character limit force you to be concise, which is a great skill, but it fits well with a lot of tools.

I tend to think the perfect is the enemy of the good. That is why I omitted talking about commit messages body. I think we have enough work to do on the summary line. But I would add one rule too:

  1. Add a Ticket oder Task ID

Most of the time, we use tools to discuss during a code review process like GitHub, or Azure Devops. All pieces of information about the change will be at least described there. I added this rule about tracking ID so it becomes easy to find related pull/merge request. Writing a commit body is better than adding tracking IDs because if you change your repository manager solution, you will lose all this precious context information and your tracking IDs will be useless.

Here is an example commit history with these rule applied

Make core independent from the git client (#171)
Upgrade Docker image version (#167)
Add maven preset (#172)
Add a generic preset using configuration file (#160)
Improve error messages for preset system (#161)
Publish Canary version on master push (#141)

Having a consistent style makes it much more easier to read. You can figure out the context of the change, you see also the, if possible, the applied Ticket. The most important thing is to find common rules in your team to ensure having a well structured commit history. For this there are some conventions that can help you finding these but we will be back on this subject later.

If you have difficulties to find out what message you should write, maybe you should split your commit in smaller parts. Peter Hutterer listed in his article a few examples where it is difficult to find out a good commit message because your commit patch may not be logical.

Commit conventions

As written before, you should define a commit convention (maybe for your team or your entire development division). There exists a plenty of open source commit conventions that could be a good source of inspiration. They also come with a whole ecosystem that includes tools to help you write commit messages, generate changelog, create releases, and many more. A lot of things that can take a large amount of time. There are well documented so you don't have to write documentation about your own commit message convention.

We will talk about two of them Conventional Commits (opens new window)and gitmoji (opens new window).

Conventional Commits

It is a specification inspired from Angular commit message guidelines. It features a few interesting rules like:

  • Commit must be prefixed with a type (feat, fix)
  • A scope may be provided to point out a specific section of a the codebase (really interesting for monorepos)
  • Breaking changes must be included in a footer section

Here is how a commit message must be structured using this specification:

[optional scope]: <description>

[optional body]

[optional footer(s)]

For further information, you can look into their specifications(opens new window)

gitmoji

I love emojies, everyone loves it ❤, gitmoji lies on categorizing commits using emojies.I thing it fits well to visualize the commit reason, so I thing this convention is good for everyone.

I was not totally honest in my previous commit examples from gitmoji-changelog. There is a missing part as you should have guessed now.

:recycle: Make core independent from the git client (#171)
:whale: Upgrade Docker image version (#167)
:sparkles: Add maven preset (#172)
:sparkles: Add a generic preset using configuration file (#160)
:recycle: Improve error messages for preset system (#161)
:construction_worker: Publish Canary version on master push (#141)

These text aliases are widely used in tools like Slack, Discord, ... Most of the repository manager tools like GitHub or GitLab, AzureDevops interprets them and display it well in their UI:

♻️ Make core independent from the git client (#171)
🐳 Upgrade Docker image version (#167)
✨ Add maven preset (#172)
✨ Add a generic preset using configuration file (#160)
♻️ Improve error messages for preset system (#161)
👷‍♂️ Publish Canary version on master push (#141)

I like this convention because I know at first glance what kind of change do a commit. It comes with a cli called gitmoji-cli (opens new window)that helps you write your commit messages and I made a changelog generator for it.

There are more of them. Keep in mind that these are guidelines, you can mix them to get something that fills your need.

If you have any kind of suggestion, please leave it into the comment section below.

Tags