On this page

Skip to content

A Brief Introduction to Git Commit Conventions

Most Git commit conventions on the internet today originate from the Angular team's format, which has evolved into many versions over time. Although this information is widely available online, I decided to write an article to document it to prevent it from being lost—after all, the articles I read five years ago are nowhere to be found now. The current "[Angular Commit Format]" is as follows: (https://github.com/angular/angular/blob/main/CONTRIBUTING.md).

Commit Format

The Angular Commit Format is divided into three parts: header, body, and footer, separated by blank lines. The header is mandatory, the body depends on the header's type (mandatory if the type is docs), and the footer is optional.

xml
<header>
<BLANK LINE>
<body>
<BLANK LINE>
<footer>

The header format is as follows (excerpted from the Angular Commit Format content):

xml
<type>(<scope>): <short summary>
  │       │             │
  │       │             └─⫸ Summary in present tense. Not capitalized. No period at the end.
  │       │
  │       └─⫸ Commit Scope: animations|bazel|benchpress|common|compiler|compiler-cli|core|
  │                          elements|forms|http|language-service|localize|platform-browser|
  │                          platform-browser-dynamic|platform-server|router|service-worker|
  │                          upgrade|zone.js|packaging|changelog|docs-infra|migrations|
  │                          devtools

  └─⫸ Commit Type: build|ci|docs|feat|fix|perf|refactor|test

Type

The type is used to categorize commits. Categories have varied over time; the current table is summarized below. The main differences are that style and chore have been removed, and CI/CD has been separated from build:

TypeDescriptionNew Description
featNew featureNew feature
fixBug fixBug fix
docsDocumentation only changesDocumentation only changes
styleChanges that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc.)
refactorA code change that neither fixes a bug nor adds a featureA code change that neither fixes a bug nor adds a feature
testAdding missing tests or correcting existing testsAdding missing tests or correcting existing tests
perfA code change that improves performanceA code change that improves performance
buildChanges that affect the build system, CI configuration, or external dependencies (example scopes: gulp, broccoli, npm)Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm)
choreOther changes that don't modify src or test files
ciChanges to CI configuration files and scripts (example: CircleCI, SauceLabs)

Scope

The scope indicates the name of the affected npm package. This is defined specifically for Angular and may not apply to other programming languages. For me, in most cases, I choose to omit it or label it with the name of the project being changed.

Short Summary (Subject)

The Short Summary is a concise description of the change. The Angular specification is as follows:

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

However, since I write in Traditional Chinese, I simply omit the period at the end of the sentence.

Body

The original text from the Angular team is as follows:

Just as in the summary, use the imperative, present tense: "fix" not "fixed" nor "fixes".

Explain the motivation for the change in the commit message body. This commit message should explain why you are making the change. You can include a comparison of the previous behavior with the new behavior in order to illustrate the impact of the change.

Since I write in Chinese, there is no tense issue. In practice, unless the content is complex or requires a specific explanation of the reason for the change, I omit the Body. Recently, a friend mentioned using Visual Studio's Copilot to help generate commit messages (if you have a Copilot subscription), so I might start using the generated message as a base for the Body.

The footer can contain information about breaking changes and deprecations, and can also be used to reference GitHub issues, Jira tickets, and other PRs. For example:

text
BREAKING CHANGE: <breaking change summary>
<BLANK LINE>
<breaking change description + migration instructions>
<BLANK LINE>
<BLANK LINE>
Fixes #<issue number>

Or:

sql
DEPRECATED: <what is deprecated>
<BLANK LINE>
<deprecation description + recommended update path>
<BLANK LINE>
<BLANK LINE>
Closes #<pr number>

BREAKING CHANGE is used for major incompatible changes, and DEPRECATED is used to describe deprecated content.

In most cases, the Footer is only used to link to a requirement ticket number; the specific linking method depends on the Issue Tracker being used.

For example, in GitHub, you can use the following keywords to link and close an issue. See the GitHub documentation "Linking a pull request to an issue".

  • close
  • closes
  • closed
  • fix
  • fixes
  • fixed
  • resolve
  • resolves
  • resolved

In GitLab, you can link in the following ways, replacing 123 with the corresponding ID:

  • Link Issue: #123
  • Link MR: !123
  • Link Snippet: $123

GitLab also supports Closes #123 or Fixes #123 to close the corresponding issue when merging the branch. See the GitLab documentation "Tutorial: It's all connected in GitLab".

Personally, since PRs or MRs might not be linked to an Issue Tracker, or I might want to control the association manually, I use the prefix issue so that it is semantically clear that #123 is associated with an issue.

TIP

Keywords like close are case-insensitive. The examples in the documentation use uppercase at the start of the sentence; if you look closely, they are lowercase when appearing in the middle of a sentence.

Commit Template

The above is a brief introduction to the current mainstream commit conventions. However, in actual operation, you might forget some less frequently used content, such as the types I often forget. Git supports a default Commit Template, which can help us standardize the commit message format.

Configuration Method

First, create a file named .gitmessage.txt. The filename cannot be changed. The content is as follows and can be adjusted according to your needs:

git
<type>(<scope>): <subject>

# -- Type --
# Must be one of the following:
#
# feat: New feature
# fix:  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 tests or correcting existing tests
# build: Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm)
# chore: Other changes that don't modify src or test files
# ci: Changes to CI configuration files and scripts (example: CircleCI, SauceLabs)
#

# -- Scope --
# The scope can be anything that specifies the location of the commit changes, e.g., init, runner, watcher, config, web-server, proxy, etc.
#

# -- Subject --
# The subject contains a concise description of the change:
# Use the imperative, present tense: "change" not "changed" nor "changes"
# Do not capitalize the first letter
# Do not use a period at the end
#

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

# -- Footer --
# The footer should contain information about Breaking Changes and is also a reference for closing GitHub issues.
# Breaking Changes should start with the word "BREAKING CHANGE": followed by a space or two newlines. Then use the rest of the commit message.
# Deprecated should start with the word "DEPRECATED": followed by a space or two newlines. Then use the rest of the commit message.

Next, open Git Bash and enter the following commands (where ~/ defaults to C:\Users\{Windows Username}, or replace ~/ with the full path where you want to place the file):

git
git config --global commit.template ~/.gitmessage.txt
git config --global commit.cleanup strip

Explanation:

  • git config: This is the Git configuration command used to view and set Git configuration options.
  • --global: This flag indicates that the setting will be applied globally, i.e., to all Git repositories. If this flag is not used, the setting will only take effect in the current Git repository.
  • commit.template: Used to specify the location of the template file for commit messages.
  • commit.cleanup: Used to specify how to handle commit messages during a commit. The default is whitespace, which does not ignore comment lines.
  • strip: This is the value for the commit.cleanup option, which means that comment lines and extra blank lines in the commit message are removed during the commit.

After execution, the following content will be added to the global .gitconfig. The global .gitconfig is stored by default in the user's account directory on Windows, for example: C:\Users\{Windows Username}.

text
[commit]
 cleanup = strip
 template = {Specified Path}/.gitmessage.txt

If the command is entered without --global, this content will be generated in the ./.git/config file of that repository.

TIP

If template is set to ./.gitmessage.txt, Git will use the .gitmessage.txt file in the root directory of the repository as the Commit Template.

Git has three levels of configuration:

  • System configuration:
    • Location: C:\Program Files\Git\etc\gitconfig.
    • Lowest priority. This setting affects all users and projects on the entire system. It is usually a global setting configured by the system administrator and is suitable for system-wide Git behavior conventions.
  • Global configuration:
    • C:\Users\{Windows Username}\.gitconfig:
    • Second highest priority. This setting applies to a single user but is overridden by Local settings. It is commonly used to set personal Git options and affects all repositories unless overridden by Local settings.
  • Local configuration:
    • .git\config
    • Highest priority. This setting is only valid for the current project and overrides Global and System settings. Since its scope is limited to a specific repository, it is particularly useful for cases where special settings are needed for a project.

TIP

The three filenames are all different XD

Practical Usage

When you enter git commit in Git Bash, the message hint: Waiting for your editor to close the file... will appear, and a text editor will open containing the content of .gitmessage.txt along with the following information:

git
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# On branch main
# Your branch is up to date with 'origin/main'.
#
# Changes to be committed:
# modified:   "{Modified Filename}"

The blank line added at the end of .gitmessage.txt is to separate it from this section of information. This section mainly explains that you should enter a commit message, that lines starting with # will be ignored, and provides a list of modified files.

Once you have modified the file and saved it, the content of the file will be used as the commit message.

If you use other Git version control software, it may not necessarily ignore lines starting with #, so you need to set commit.cleanup strip.

Currently, the version control software I know that supports Commit Templates is as follows:

  • GitKraken: In the repository tab, click File => Preferences... => Commit. The Commit Template setting will be displayed. If commit.cleanup strip is not set, remember to check "Removes comments from commit messages" to ignore lines starting with #.

  • Tortoisegit: When commit.cleanup is whitespace, commits do not ignore lines starting with #.

  • Git Extensions: When commit.cleanup is whitespace, commits still ignore lines starting with # (thanks to a colleague for testing).

  • Sourcetree:

    • Supported in Mac version 4.2.8 (thanks to a colleague for testing); supported in Windows version 3.4.20 and later.
    • When commit.cleanup is whitespace, commits still ignore lines starting with #.

TIP

Sourcetree version 3.4.18 did not yet support Git Template. However, I saw on 2024/6/27 that the official team closed many Jira tickets that people had been asking for for years, stating that Commit template message has been resolved, so it might be supported in a future version.

Sourcetree 3.4.20 has added support. See Sourcetree release notes.

SourceTree 3.4.20 [17 September 2024]

  • Changes: Supporting git commit template feature
  • Changes: Upgrade to Git 2.46.0 and Git LFS to 3.5.1
  • Fixed: 'Push changes immediately' checkbox is disabled in No Staging View
  • Fixed: Arbitrary code execution vulnerability
  • Fixed: Interactive rebase always aborting when a merge is necessary
  • Fixed: Silent crash when creating a hotfix
  • Fixed: Sourcetree diff treats large .sql files as binary
  • Fixed: Windows Line breaks are replaced with Unix breaks on "Discard Hunk" click

Reverting Settings

You can use the following command to remove the Git Template setting:

git
git config --unset --global commit.template

Use the following command to restore the setting to ignore comment lines:

git
git config --global commit.cleanup whitespace

Change Log

  • 2024-07-23 Initial document creation.
  • 2024-09-20
    • Updated to note that Windows Sourcetree 3.4.20 supports the Git Commit Template feature.
    • Corrected the explanation of the configuration file location.