top | item 13889155

How to Write a Git Commit Message (2014)

341 points| deyton | 9 years ago |chris.beams.io

118 comments

order
[+] jph|9 years ago|reply
My team uses a git commit message convention that helps us read fast and also is parsable by toolchains.

We agree on a short list of leading active verbs:

Add = Create a capability e.g. feature, test, dependency.

Cut = Remove a capability e.g. feature, test, dependency.

Fix = Fix an issue e.g. bug, typo, accident, misstatement.

Bump = Increase the version of something e.g. dependency.

Make = Change the build process, or tooling, or infra.

Start = Begin doing something; e.g. create a feature flag.

Stop = End doing something; e.g. remove a feature flag.

Refactor = A code change that MUST be just a refactoring.

Reformat = Refactor of formatting, e.g. omit whitespace.

Optimize = Refactor of performance, e.g. speed up code.

Document = Refactor of documentation, e.g. help files.

[+] jwdunne|9 years ago|reply
This is a great idea. Interestingly, Google has a tool that will analyse your git history and identify "hotspots" i.e code that is regularly associated with commit messages with words like "fix".

I'm wondering if the same general idea is applicable to other types of commits given your list. For example, if you are regularly adding features and a certain part of the code base is touched, perhaps with a lower ratio of "refactor" commits, that code could be a solid candidate for refactoring.

Here's the tool i mentioned anyway https://google-engtools.blogspot.co.uk/2011/12/bug-predictio...

[+] stinos|9 years ago|reply
Not a bad idea actually. It's like the PowerShell 'approved verbs'. At first I was like 'meh' but after a while it makes sense as it greatly improves discoverability. Looking at a couple of repositories I contribute to this also looks close to what 'good' committers tend to use automatically.
[+] eriknstr|9 years ago|reply
I like all of these but am wondering what the following two mean.

Start = Begin doing something; e.g. create a feature flag.

Stop = End doing something; e.g. remove a feature flag.

Could someone explain these and give a few examples?

[+] milesrout|9 years ago|reply
I particularly like this because it doesn't interfere with the flow of the commit message's first line in explaining what it does. There are too many commits out there that waste half the first line with the ticket number, area of code, etc.

Instead of 'JAT-1241: app/index.js(opt): Optimised the index', 'Optimised the index' should be fine. Tools can understand that, and can already work out which files changed.

[+] component|9 years ago|reply
This is great

Some of the active verbs are also commands that automatically close/reference issues right out of the box on GitHub & BitBucket (& I'm sure on GitLab too)

[+] npolet|9 years ago|reply
This is a really nice way doing commits. It's the kind of simplicity that can be made into a simple document and shared easily, or printed out and put somewhere everyone can see.

Might try and get my team into using this.

At the moment our teams commit messages are a mangled mess of everyone's own 'commit language'. It can be really tricky to quickly scan over commit logs and get a feel of where development has been heading over the last x weeks.

[+] tmsldd|9 years ago|reply
I use similar strategy with my team. In addition I ask them to summarize in one line the job they are going to do before starting the job... which is related to the task description in the task board. That is normally the commit message. Works (most of the time...).
[+] wst_|9 years ago|reply
How do you enforce such commits messages? People makes mistakes, or forget stuff. But when you have a pull request, all intermediate commits are already pushed to central repository. They already are public. You can't change them anymore. Pre-commit hook?
[+] amcrouch|9 years ago|reply
Great idea, I'm gonna steal this.
[+] bluetwo|9 years ago|reply
That's a nice way to standardize. I like it.
[+] _pmf_|9 years ago|reply
Useful; never actually thought about using ubiquitous language here, but it makes absolute sense.
[+] trjordan|9 years ago|reply
There are so many articles like this, and all of them focus so much on prescriptive rules for commit messages. There's a similar set of articles on how to deal with branching and merging. Somehow, everybody comes to slightly different conclusions.

The discussion that needs to happen before this is to understand what tools you want to make available to your developers in the future. Using git's history as a first class debugging tool is powerful, but it's by no means mandatory to provide. There's also a real cost to providing each of the tools.

- Do you want bisect to be available? Well, then you should have most commits represent a fully-functional version of the software. Consider squashing branches when you merge them.

- Do you want narrative documentation around strange choices? Fine-grained commits are a great place to put those thoughts, but they may discourage devs from writing those thoughts in inline comments.

- Do you want ownership via git blame? Line-by-line changes may help you identify who wrote the code, but that might prevent your developers from ever fully transferring ownership, which could create bottlenecks in startups that have a few long-tenure devs and a lot of recently hired devs.

I really like to think of git history as a context tool, like monitoring or unit testing or documentation. It's worthwhile to sit down with your team, define what you want them to be able to do with commit history, and build your commit style from there.

[+] data_hope|9 years ago|reply
My personal, subjective impression: Commits are getting smaller and smaller nowadays. As in: In the subversion days, many people commited only few times a day, sometimes not for several days. SVN commits of course involved a sync with the server (a "push" in git lingo), and thus usually represented a much larger increment with a substantial change to the code base [X]

With git, it became very common to structure changes to a code base in many, very small commits. Rename a variable? Commit. Write some docs? Commit. Of course, the overall changes when developing a feature did not become smaller, they are now just distributed over many more commits. So I'd argue that a SVN commit was often conceptionally closer to what we now have with a git pull-request.

Why does this matter? Because It is kind of hard and not helping anyone if you describe your renaming of a local variable with an extensive docstring.

What I do miss however, is a good description of the overall change. I.e. now often the description in the merge commit is just the autogenerated message, but this is where I would like people to really take the time and describe the change extensively. This is why I like `--squash` merges, because they let people focus on the relevant parts in their description. I know, rewriting history is bad, but overall, I favour reading a history book than 18th century newspapers.

[X] not saying that there weren't small one-line-change commits, but overall they were rarer.

[+] projectileboy|9 years ago|reply
Changing _public_ history is bad. I don't see any problem with rewriting your _personal_ history before merging it in.
[+] wst_|9 years ago|reply
I find tons of small commits a clutter and waste of time. I don't see any reason for doing so. On the contrary I can see disadvantage - reading and understanding a history later may become difficult task. After all what counts is your full chunk of work, reviewed via pull request, and merged to master. It should be treated as a whole.

Has it really become so common with git? I don't see such trend around me.

[+] greenhouse_gas|9 years ago|reply
Would be interesting if there was a way to annotate a set of commits, like "commit ???? - ????: refactored A,B, and C" so you'd get the advantage of small commits and clearer messages.
[+] robbyking|9 years ago|reply
Unfortunately, I'm guilty of the opposite: I rarely, rarely commit. Maybe one commit per point. I have to consciously remind myself to commit more often.
[+] flukus|9 years ago|reply
> As in: In the subversion days, many people commited only few times a day, sometimes not for several days.

This was often the source of merge hell. Half of what makes git merges easier is the smaller commits that it encourages.

[+] emodendroket|9 years ago|reply
I mean, aren't pull requests basically the solution to that problem?
[+] stared|9 years ago|reply
I really recommend angular-style commit messages: https://github.com/angular/angular.js/blob/master/CONTRIBUTI...

type(scope) message

e.g.

feat(button) added play button

Types are:

- feat: A new feature

- fix: A bug fix

- docs: Documentation only changes

- style: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)

- refactor: A code change that neither fixes a bug nor adds a feature

- perf: A code change that improves performance

- test: Adding missing or correcting existing tests

- chore: Changes to the build process or auxiliary tools and libraries such as documentation generation

[+] jph|9 years ago|reply
If you like this format, then you may want to try a similar format that uses the same purpose, plus uses words that easier to read and that make more sense to people in more cultures.

We use Add, Fix, Refactor, Reformat, Optimize, etc.

See my comment on this thread or https://github.com/joelparkerhenderson/git_commit_message

[+] tazjin|9 years ago|reply
Agreed. I started using these on private & professional projects a year ago (and mostly got the team to use them, too) and it's a pleasure to browse the git log!

In the beginning the definition of "scope" is a bit wonky per project. However, once it solidifies you can easily start going through your log looking for "feat(endpoint)" to find new routes that have been added to an API for example.

[+] sleepychu|9 years ago|reply
I've been writing commit messages this way for a little under a year (I think this is the same guide I used when I was looking for a more consistent form to write them and to avoid the dreaded -m "Fixed some things").

One thing I noticed is that it's increased my confidence in my commits; at the moment that I go to write the commit message because I'm describing why I made the decisions I did it breaks logical inconsistencies between what I've actually done and what I think I've done. If I'm able to explain all the change I'm much more confident that it's correct.

Another is that bad commit messages have trained people not to read them. Often people will ask why I've made a change and then discover that the commit message contains the answer to their question!

[+] gregmac|9 years ago|reply
The only one that really drives me crazy is

> Wrap the body at 72 characters

Why? Because the git CLI doesn't wrap properly? To borrow a quote, that seems like a 'you' problem, not a me problem.

Maybe I'm just biased because these days I almost entirely interact with git through a GUI (either desktop client or web interface), and though I use the CLI occasionally (mostly for branch management, sometimes for quick commits) I can't think of the last time I used it for any type of history viewing -- pretty much any GUI is going to do a better job of that.

My team often uses markdown (mainly bulleted lists) and the output looks terrible when you insert manual line breaks (because markdown interprets that as meaning that you explicitly want a line break there) and you're viewing it on a screen/viewport that is either larger or smaller than 72 characters wide.

Unless you're explicitly using a publishing format (eg, LaTeX, PDF, postscript), the function of wrapping text should be a concern of the rendering of the output, not the origin.

Am I missing something here? Is there any other reason to manually wrap text besides the git CLI's handling of it as a viewer?

[+] pbh101|9 years ago|reply
Linus Torvalds answered exactly this question [0]. Not that that means you should unblinkingly take it on authority, but the original reasoning is: the renderer doesn't alway know when a line should be wrapped. Examples: a stack trace, or long log line, or essentially any other quoted artifact that has a specific pre-determined format.

The relevant quote from the link:

  Some things should not be word-wrapped. They may be some kind of
  quoted text - long compiler error messages, oops reports, whatever.
  Things that have a certain specific format.

  The tool displaying the thing can't know. The person writing the
  commit message can. End result: you'd better do word-wrapping at
  commit time, because that's the only time you know the difference.
[0] https://github.com/torvalds/linux/pull/17#issuecomment-56611...

EDIT: small clarification and formatting

[+] nitemice|9 years ago|reply
Sounds like your markdown interpreter has an issue, or you're leaving lots of white space at the end of your lines.

Generally, in markdown, if you insert a line break, it won't translate to an explicit line break unless you put two in a row, or if there is 2+ spaces at the end of the line.

See [1] for an illustration

[1](https://johnmacfarlane.net/babelmark2/?text=This+line%0Ashou...)

[+] ajross|9 years ago|reply
> Why? Because the git CLI doesn't wrap properly?

First off, the commit message is plain text (by design) and can't be "wrapped" automatically, and any tool that tried would be insane.

The reason for 72 characters is that the CLI, like lots of other presentation mechanisms (including quoting in other commits or in code), wants to indent your message for readability. And the uniform standard width for terminals has been 80 characters for like four decades now.

Must it be? I dunno. I can imagine a uniform agreement among a broad team that everyone will assume a 100 character line and all tools should enforce that. Maybe a little more, but not that much because even on a modern screen you want to have two full terminals of text readable at a time.

But that's just a number. You'd still be told by your commit message style guide (or checkpatch.pl, or whatever) to wrap your lines manually at 92 characters. Is 25% more bytes on a line really worth yelling about?

[+] jupp0r|9 years ago|reply
I really like that Gerrit code reviews allow reviewers to comment on the commit message in the same way as on the code. The way to ensure useful commit message practices is the review process, if you ask me.
[+] ibgib|9 years ago|reply
1. Git commit templates. 2. Emoji. 3. Bullets in body.

1. Any article on structured git commit messages should mention git commit templates! https://robots.thoughtbot.com/better-commit-messages-with-a-...

I use a commit template for structure, as well as reducing boilerplate for expressive messages. Here is my default template on ibgib: https://github.com/ibgib/ibgib/blob/master/git-commit-templa...

2. I also use emoji (with a key there in the git commit template for reference) to communicate concepts like implemented, bug fix, etc., in a single emoji character. Note though that it is inappropriate when you start to do a pull request, as not all git message viewers will display the emoji. But I find it very useful FTMP.

3. Bullets are a simple way to enable both terse and structured comments within a commit.

[+] ratherbefuddled|9 years ago|reply
Does nobody else require there to be at least one issue tracker reference in the commit message these days? It makes automating stuff like release notes much easier.
[+] emodendroket|9 years ago|reply
So then you have like fifty hashes attached to the ticket?
[+] bjourne|9 years ago|reply
It doesn't matter that much. Some things in programming mater a lot, like consistent indentation and casing. Some things doesn't, like perfectly formatted commit messages. whether the verbs in commit messages should be in imperative or present tense is just too much.

I can tell you that I have been programming for a very long time. So if someone asks me "Why does it MATTER if lines are longer than 80 characters?" then I can answer "Because it means that the distribution of line-lengths will be more uniform, meaning that you will be able to fit more code on the screen, meaning that the amount of scrolling you'll have to do when trying to understand the code is greatly reduced." And scrolling interrupts your focus, which is bad. But if I ask someone, "Why does it MATTER if verbs are in present or imperative tense?" no one can answer.

[+] phailhaus|9 years ago|reply
Git has zero opinion on when you commit or what the messages are. Commits are made in private. Commits are also immutable. This is a losing battle.

If you use a code management tool like BitBucket or GitHub, it seems like the unit of work is less a commit and more a PR. A PR's description can always be edited and refined for future engineers, and a PR (almost) always represents a block of work that can be reverted. Instead of creating a hundred different approaches to writing commits that engineers essentially have to get right the first time, why not just focus on documentation in the form of PR's? It seems like if you could trivially tie a commit back to the PR and ticket it came from, most of these problems would be solved.

[+] CydeWeys|9 years ago|reply
Private commits aren't immutable at all. You can change anything about them up until you push them to a remote repository that other people are syncing from. I routinely squash a bunch of private commits together before issuing a public PR, for example.
[+] achr2|9 years ago|reply
The main issue with commits is that they end up representing more than a single logical change.

Are there any tools that allow you to initiate a commit as an 'intention stack' for work I am about to do, rather than work I have already done?

I'd love to be able to write an intent message "refactor XYZ.." before starting in on that activity, then when I have to go down another rabbit hole in the middle I push another intent message to the stack, then pop back out afterward and continue with XYZ. The final overall commit message could be auto generated from the initial intention and all tangents.

[+] pbosko|9 years ago|reply
My team uses task number and title as a commit message. We just can't fit all the description from task into one line of comment. So, when we look at git blame - we get a reference to a task in project management tool where we can find all the reasons behind a given change.

If there are more commits for the same task, all of them bare the same commit message. After each review, we add a comment to project management tool. That way we focus only on newer commits when performing another round of reviews.

Every other attempt to describe changes and intentions in one line seems doomed to me.

[+] kevinmannix|9 years ago|reply
I've really welcomed the recent GitHub features such as "squash & merge" and "rebase & merge". Instead of parsing through 200 commits of "typo", "lint", "spacing", a feature is placed in a compact diff with the feature title & related task id as the commit message.

A commit should be a unit of work. Tests should pass before and after. The commit message should describe the change. Ensuring that you have a good commit message then influences what content you contain in a commit.

[+] jdiez17|9 years ago|reply
I've found that writing commit messages by stating the problem in the subject, and an explanation of the solution in the body makes them very clear and descriptive.

For example:

    Problem: Windows build script requires edit of VS version

    Solution: Use CMD.EXE environment variable to extract
    DevStudio version number and build using it.
I got the idea from ZeroMQ's/hintjens' various repos.
[+] nighthawk454|9 years ago|reply
We've used this style in our commit messages for a few years, and it's been great. We also only allow fast-forward merges of squashed commits for our branching strategy.

  [ISSUE-ID]: Title

  [Problem]
  State problem and customer impact

  [Solution]
  Describe and justify solution

  [Test]
  Describe automated/manual testing