Git commit message guideline


By browsing the log of many Git repositories, you will probably find messy commit messages - while well-crafted messages are the best way to communicate about a change to other contributors. Generally, the git diff will tell you what changed, but only the commit message can properly tell you why it was changed. Understanding why something happened is important not just months or years later but every day: reviewing others' commits could be done independently and efficient way with the help of meaningful and well-crafted messages.

There are many different commit message conventions where one could be a better convention to one team than the other. However, selecting one and stick to it is far better than does not apply any of them. There are four important things in commit message conventions:

  1. Structure: helps to find information easier if you know where to look for
  2. Content: determines which information is expected and which is not
  3. Style: writing in plain English helps to read more quickly and easily
  4. Metadata: provides references to issue tracking systems

In this post, I am addressing some well-tried conventions that I found useful in many projects. Our goal is to provide both human- and machine-readable meaning to commit messages, therefore, we are applying the Conventional Commits proposal, which complements and strongly correlates with SemVer specification.

Note: See Git commit message template page for the template. The Git repository template project is created to help composing (with using preformatted templates, syntax highlights within nano and Sublime, and commit message convention checking with Git::Hooks). Detailed installation instruction could be found in the project README.md.

Message guideline

Our guideline aims at providing an easy set of rules for creating an explicit commit history which makes it easier to write automated tools on top of it. As an overview, each commit message follows the next structure (please note, there are blank lines between the elements):

<type>[optional scope][!]: <issue-key> <description>
 
[optional body]
 
[optional footer(s)]

The expected structure of the commit messages are detailed in the next table:

ElementMandatoryMulti paragraphDescription
HeaderYesNoFor detailed specification read Header structure section below.
BodyNoYesFor detailed specification read Body structure section below.
FooterYesYesFor detailed specification read Footer structure section below.

Header structure

The header is the title of a commit. It has a strict structure. The header has a special format that includes a type (MANDATORY), a scope (OPTIONAL), a breaking change marker (i.e. *!*) (OPTIONAL), an issue-key (MANDATORY) and a description (MANDATORY). The whole header should be written in lower case letters (except names such as CHANGELOG.md).

Type parameter

The type parameter describes the nature of the change, that could be one of the the following list (this list could be extended with short nouns):

TypeDescriptionComment
buildthe commit changes that affect the build system or external dependencies (example scopes: gulp, maven, npm)
cithe commit changes to the continuous integration configuration files and scripts
docsthe commit changes the documentation only
featthe commit introduces a new feature to the codebasethis correlates with MINOR in semantic versioning (i.e. SemVer)
fixthe commit patches a bug in your codebasethis correlates with PATCH in semantic versioning (i.e. SemVer)
perfthe commit includes code change that improves performance
refactorthe commit contains only refactoring, so the code changes are neither fixes a bug nor adds a feature
stylethe commit changes those parts that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc.)
testthe commit includes missing tests or correcting existing tests

Scope parameter

The scope parameters should be one of the Git project components (see page Git repo README.md section "Component list") list if applicable. The scope should be put into parenthesis.

Subject parameter

The subject contains the concise description of the change using:

  • imperative, present tense: "change" not "changed" nor "changes"
  • don't capitalize the first letter
  • don't do dot (.) at the end of the line

Example

Commit message without body
docs(model-server): NET-1234 correct spelling of CHANGELOG.md

Body structure

The body should include the motivation for the change and contrast this with previous behaviour: what changes we have made and why we made them. The major goal is to give additional contextual information about the code changes.

The body follows the same style as in the section subject parameter. A commit body is free-form and MAY consist of any number of newline-separated paragraphs. The body MUST begin one blank line after the header.

Example

Commit message: with a body and a footer
feat(model-server): NET-133 add onUrlChange event (popstate/hashchange/polling)
 
Added new event to Editor:
- forward popstate event if available
- forward hashchange event if popstate not available
- do polling when neither popstate nor hashchange available
 
Reviewed-by: aszoke

Footer structure

A commit body is controlled-form and MAY consist of any number of newline-separated paragraphs of the following types (e.g. BREAKING CHANGES: <description>):

  1. Describing the breaking changes (OPTIONAL item) in detail (see Breaking changes section):

    BREAKING CHANGES: <details>

  2. Giving the person who reviewed the code:

    Reviewed-by: <git username>

  3. Listing which documents should be amended due to the changes:

    Doc-impact: <description>

  4. Listing who should be informed about the changes:

    CC: $PERSON <$MAIL>

The footer MUST begin one blank line after the body if exists or header if body does not exist. (This is inspired by the git trailer convention and looks similar to the RFC 822 email headers and the Git development.)

Breaking changes

A breaking change is a type of change when the commit leads to incompatibility comparing with the previous version. In SemVer terminology, it is called MAJOR change. A BREAKING CHANGE can be part of commits of many type parameter (cf. above).

Every breaking change MUST be denoted with the following:

  1. In the header, after the type structural element, an exclamation mark ('!') must be appended.
  2. In the footer, in (several) paragraphs the changes should be detailed and this description should start with the 'BREAKING CHANGE:' expression (capitalized!). The BREAKING CHANGE section should be the last section in the footer, because it could contain many paragraphs.

Examples

Commit message: breaking change without body
feat(build)!: NET-1234 allow provided config object to extend other configs
 
BREAKING CHANGE: `extends` key in config file is now used for extending other config files
Commit message: breaking change with multiple bodies - the most broader footer with detailed breaking change
feat($compile)!: NET-123 simplify isolate scope bindings
 
Changed the isolate scope binding options to:
  - @attr - attribute binding (including interpolation)
  - =model - by-directional model binding
  - &expr - expression execution binding
 
This change simplifies the terminology as well as
number of choices available to the developer. It
also supports local name aliasing from the parent.
 
CC: kapasd, zalkag
Doc-impact: Scope binding document
Reviewed-by: aszoke
BREAKING CHANGE: isolate scope bindings definition has changed and
the inject option for the directive controller injection was removed.
 
To migrate the code follow the example below:
 
Before:
 
scope: {
  myAttr: 'attribute',
  myBind: 'bind',
  myExpression: 'expression',
  myEval: 'evaluate',
  myAccessor: 'accessor'
}
 
After:
 
scope: {
  myAttr: '@',
  myBind: '@',
  myExpression: '&',
  // myEval - usually not useful, but in cases where the expression is assignable, you can use '='
  myAccessor: '=' // in directive's template change myAccessor() to myAccessor
}
 
The removed `inject` wasn't generally useful for directives so there should be no code using it.

FAQ

  • What do I do if the commit conforms to more than one of the commit types?

    Go back and make multiple commits whenever possible. Part of the benefit of the convention is its ability to drive us to make more organized commits.

  • What do I do if I accidentally use the wrong commit type?

    Please fix it as possible since the commit will be missed by tools that are based on the spec.

  • What language should use to write commit messages?

    We follow the general advice to write code, log messages and commit messages as well in English. IT-related expressions are full of easily-not-translateable words so we stick to the English language. Although, we do not necessarily translate all business-related Hungarian expressions to English.

  • What is the proposed commit message length?

    Any line of the commit message (the header, the body and the footer) cannot be longer than 72 characters. This allows the message to be easier to read in various git tools.