Skip to content

Instantly share code, notes, and snippets.

@janderssonse
Last active February 26, 2025 17:33
Git Commit Message Guidelines

EDIT: have a look at conventional commits standard instead, they are saying much of what i'm saying here, but in a formalized way.

Commit Message Guidelines

This document gathers wisdom from different sources to provide a sensible guide for writing commit messages.

Sources:
The AngularJS contributing guides
Open Source Review Toolkit's contribute guide
Git 50/72: the rule of well formed Git commit messages
Tim Pope's classic git message post

Why?

Structured and clear project information

First, consider the following commit messages:

  • fix comment stripping
  • closes resource
  • fixing broken links
  • Bit of refactoring
  • Check whether links do exist and throw exception
  • Added support for properties in documentation
  • docs - various doc fixes
  • replaced double line break with single when text is fetched from Google only, a special case fix!

Ask yourself:

  • Which part of the code has changed? Some of the commits are trying to tell a story. Can you guess in what scope where the commit was done - docs? the compiler? or somewhere else?

  • What tense is used? Notice the different tense used: fix - fixing?

  • Which commits are more or less interesting when browsing the history? For example, would commits introducing formatting changes (adding/removing spaces/empty lines, indentation), missing semi colons, comments, etc be interesting in a changelog or when debugging?

  • How do you think the line length will affect readability, especially when wrapped in a terminal?

By adhering to this guide, the above issues will be handled, and your git log will be clean, predictable and comprehensible.


Commit Message Format

A commit message consists of a header, a body and a footer. The header has a special format that includes a type, an optional scope and a subject:

<type>(<scope>): <subject>
<BLANK LINE>
<body>
<BLANK LINE>
<footer>

The header is mandatory and the scope of the header is optional.

The footer should contain a closing reference to an issue if any.

Many projects sticks to the 50/72 rule by convention

  • maximum 50 characters long first line (excluding type and scope)
  • description maximum 72 lines long

This allows the message to be easier to read on GitHub as well as in various git tools.

In general:¨

  • Make separate commits for logically separate changes.
  • Describe your changes well.

<type>

Project defined, examples could be:

  • build: Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm)
  • ci: Changes to our CI configuration files and scripts (example scopes: Circle, BrowserStack, SauceLabs)
  • docs: Documentation only changes
  • feat: A new feature
  • license: Licensing compliance and changes
  • fix: A bug fix
  • perf: A code change that improves performance
  • refactor: A code change that neither fixes a bug nor adds a feature
  • style: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)
  • test: Adding missing tests or correcting existing tests
  • revert: If the commit reverts a previous commit, it should begin with revert: , followed by the header of the reverted commit. In the body it should say: This reverts commit <hash>., where the hash is the SHA of the commit being reverted.

Optional <scope>

If applicable, the scope should be the name of the package affected (as perceived by the person reading the changelog generated from commit messages).

The following is a list of example scopes:

  • common
  • compiler
  • compiler-cli
  • core
  • http
  • router

<subject>

The subject contains a succinct description of the change:

  • use the imperative, present tense: "change" not "changed" nor "changes". Read your commit message as "This commit will .."
  • don't capitalize the first letter
  • no dot (.) at the end

<body>

Just as in the subject, use the imperative, present tense: "change" not "changed" nor "changes". The body should include the motivation for the change and contrast this with previous behavior.

<footer>

The footer should contain any information about Breaking Changes and is also the place to reference GitHub issues that this commit Closes.

Breaking Changes

start with the word BREAKING CHANGE: with a space or two newlines. The rest of the commit message is then used for this..

Referencing issues

Closed bugs should be listed on a separate line in the footer prefixed with "Closes" keyword like this:

Closes #234

or in case of multiple issues:

Closes #123, #245, #992

Generate a CHANGELOG

Use these three sections in a changelog: new features, bug fixes, breaking changes. This list could be generated by a script when doing a release, along with links to related commits.

List of all subjects (first lines in commit message) since last release:

git log <last tag> HEAD --pretty=format:%s

New features in this release

git log <last release> HEAD --grep feature

Ignore non-important commits

You might want to ignore certain commits, like formatting changes

For example, when bisecting, you can ignore these by:

git bisect skip $(git rev-list --grep irrelevant <good place> HEAD)

Examples

Look at commits from the Git project
and samples from the angular project

Various:

docs: update changelog to beta
feat(directive): add directives disabled/checked/multiple/readonly

New directives for proper binding these attributes in older browsers.
Added coresponding description, live examples and e2e tests.

Closes #351
feat(compile): simplify isolate scope bindings

Change 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.

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 generaly useful for directives so there should be no 
code using it.

Pull Requests

  • To resolve conflicts, rebase pull request branches onto their target branch instead of merging the target branch into the pull request branch. This again results in a cleaner history without "criss-cross" merges.

  • When addressing review comments in a pull request, please fix the issue in the commit where it appears, not in a new commit on top of the pull request's history. While this requires force-pushing of the new iteration of your pull request's branch, it has several advantages:

    • Reviewers that go through (larger) pull requests commit by commit are always up-to-date with latest fixes, instead of coming across a commit that addresses their remarks only at the end.

    • It maintains a cleaner history without distracting commits like "Address review comments".

    • As a result, tools like git-bisect can operate in a more meaningful way.

    • Fixing up commits allows for making fixes to commit messages, which is not possible by only adding new commits.

      If you are unfamiliar with fixing up existing commits, please read about rewriting history and git rebase --interactive in particular.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment