Git commit message format and Conventional Commits

Git commit message format and Conventional Commits

During a developer's daily work, it's very common to push commits to Git repos. How do we write Git commit messages? The basic rule is: if the team has an existing rule for commit messages, then stick to this rule. This is the same as code styles. There is no absolutely right or wrong formats for commit messages. The key point is about consistency.

If the team doesn't have a pre-defined rule, then below are some suggestions.

The Git commit message should have two parts, subject and body. These two parts are separated with a blank line. The subject is a brief description about the commit. The body should describes details of the commit and why this commit is required.

Conventional Commits is a popular specification about Git commits. Conventional Commits has conventions about Git commits, so they can be easily processed by tools.

Below is the format of a conventional commit.

<type>[optional scope]: <description>

[optional body]

[optional footer(s)]

There are three parts of a conventional commit:

  • type, scope, and description
  • body
  • footer

There are several types of commits, including fix, feat, build, chore, ci, docs, styles, refactor, perf, and test.

An optional scope can be added to specify the component of a commit. For example, fix(api) means a bug fix for api component.

The body can have multiple paragraphs separated with blank lines.

The footers use git trailer format.

Below is an example commit from Angular.

feat(docs-infra): add @developerPreview tag for APIs in developer p…
…review (#46050)

This commit adds a tag processor for `@developerPreview`. Adding this tag to
an exported symbol or to a decorator parameter causes an API status tag to
be shown for the API which links to the Developer Preview documentation.

PR Close #46050

For breaking changes, there are two ways to specify.

  • Appends a ! after the type/scope, e.g. feat(api)!.
  • Uses a footer BREAKING CHANGE:, e.g. BREAKING CHANGE: some changes.

Below is an example commit of adding BREAKING CHANGE.

fix(router): Remove deprecated initialNavigation option (#45729)
`initialNavigation: 'enabled'` was deprecated in v11 and is replaced by
`initialNavigation: 'enabledBlocking'`.

PR Close #45729

If you want to see what good commits look like, you can checkout the repository of Linux and Git itself.

Below is an example commit from Git.

sha1-file.c: don't freshen cruft packs
We don't bother to freshen objects stored in a cruft pack individually
by updating the `.mtimes` file. This is because we can't portably `mmap`
and write into the middle of a file (i.e., to update the mtime of just
one object). Instead, we would have to rewrite the entire `.mtimes` file
which may incur some wasted effort especially if there a lot of cruft
objects and they are freshened infrequently.

Instead, force the freshening code to avoid an optimizing write by
writing out the object loose and letting it pick up a current mtime.

This works because we prefer the mtime of the loose copy of an object
when both a loose and packed one exist (whether or not the packed copy
comes from a cruft pack or not).

This could certainly do with a test and/or be included earlier in this
series/PR, but I want to wait until after I have a chance to clean up
the overly-repetitive nature of the cruft pack tests in general.

Signed-off-by: Taylor Blau <>
Signed-off-by: Junio C Hamano <>
© 2022 VividCode