Writing a meaningful commit message

November 16, 2018

When working in a team of developers, it’s important to share what you attended to achieve with your code and why you did it that way. It can be done using clear variable names, comments, … but also via Git commit messages.

Commit messages are useful for:

  • Code review: it helps the reviewer to follow your chain of thoughts, understand what you solved in your PR.
  • git blame: it brings context to the line/block of code.
  • git log, git rebase, git revert or git bisect: it helps you to grasp what the changes are about without having to dig into each line of code contained in the commit.

The structure of a commit message

I follow the rules detailed in the famous article from Chris Beams. They are the most common I encountered at work or in open source projects.

  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 like to follow his methodology to write the subject line. When writing the message, I think about the following sentence:

If applied, this commit will [your subject line]

I strongly recommend you to read the full article How to Write a Git Commit Message, it has a lot of great insights and guidance.

When things don’t go according to plan

git commit -am “Bunch of stuff”

It’s a good practice to commit as often as possible, since it simplifies the work when writing the commit message, hence a cleaner Git history. But, sometimes things don’t go as planned and we do too many changes without committing. Hopefully, it is possible to stage and commit code lines separately using git add --path. You can read more about it in The Git Add Patch Command article in which the author describes how to achieve it using the command line or in VSCode. I prefer to use a GUI to do that since I have a better overview at what I want to stage instead of going chunk by chunk using the CLI. It’s actually the only reason I open a GUI for Git.

git commit -am “Oops forgot a semicolon.”

For some reason*, an error passed through the linter and had been committed. We realise later when the CI is failing, and the PR rejected that we’ve forgotten a semicolon. Bummer. Committing that alone won’t be any value to the reviewer, and we might have to redo the fix if we need to revert to a previous state. Luckily the PR is still open so that we can add the missing semicolon in the right commit.

If the error occurred in the last commit, we could write the fix, stage and commit using the --amend flag. That way the change is part of the previous commit, incognito.

git add -A
git commit --amend --no-edit
# Push the fix to the PR branch
git push origin --force-with-lease

You can read more about why you should use --force-with-lease instead of --force.

Otherwise, if the issue happened earlier in Git history, we need to go back in time using the powerful git rebase. First, we need to find where it happened and we have several options:

  • Check the history of the given line where the issue is, using git blame.
  • Check the log to read through the changes, using git log --oneline or git log -p (or using your favourite GUI).
  • And if none of it worked, we can use git bisect.

In my experience, since it’s related to one of my commits, I can find it using the log.

We have now found the commit, we can use its SHA hash and rebase on it:

git rebase -i e39a40e39bc325cde31b71402a79afb7be7e31ef^
  • e38a... is the SHA hash
  • The ^ at the end of the SHA hash is to specify that we want to start the rebase from this commit. Without it, it will begin at the next commit.

Git opens a new window** where we specify the commands to run for each commit. Here, we replace pick with edit (or e for short) on the first line:

edit e39a40e The commit we want to update
pick 84da00a Another commit message

# Rebase e39a40e..84da00a onto e39a40e (2 commands)
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# d, drop <commit> = remove commit

Save the file, and Git brings us back at the commit.

Now, all we have to do is to add the missing semicolon, stage the change, continue the rebase and finally push the change to the remote branch.

git add -A
git rebase --continue
git push origin --force-with-lease

* I heard you like to commit using -n? 👀

** it’s possible to configure Git to use your favourite editor.

Feel free to send feedback or ask questions on Twitter.

Written by Antoine Lehurt (a.k.a kewah). Front-end developer living in Stockholm and currently working at Acast.