Writing Conventional Git Commit Messages

Updated Jan 18, 2022#git#misc#guides

When working on personal projects, you can commit with random messy short meaningless messages like wip, done, ok, working, still working on it, really done this time, or i don't care. You’re not the only one who has poorly named commits, weird branch merges, or one branch for everything. No one cares about git history of your private repositories!

But public and corporate projects often have very precise rules over how git commit messages should be formatted. This leads to more readable messages that are easy to follow when looking through the project history. Also, we can use the git commit messages to generate the changelog, determine a semantic version bump, or trigger publishing process.

The Conventional Commits

This specification is a lightweight convention on top of commit messages. It provides an easy set of rules for creating an explicit commit history; which makes it easier to write automated tools on top of. This convention dovetails with SemVer, by describing the features, fixes, and breaking changes made in commit messages.

<type>(<optional scope>): <subject>
<optional body>
<optional footer>

A full long commit message will look like this:

fix(middleware): ensure Range headers adhere more closely to RFC 2616

Add one new dependency, use `range-parser` (Express dependency) to compute
range. It is more well-tested in the wild.

Fixes #2310

Most tools only show the first line of the commit message, which is usually enough to know what it is about.

* 8decde6 - (1 months ago) docs(server): update file uploading api
* bee23f9 - (2 months ago) feat(client): add Apple login button
* a8ecd9d - (3 months ago) fix(client): broken header in safari
* 7a0f17e - (4 months ago) feat(server): add crud apis
* af61aec - (5 months ago) docs(changelog): update changelog


This spec suggests following types, you can always add more if that suits your projects.

  • feat: A new feature
  • fix: A bug fix
  • docs: Documentation only changes
  • build: Changes that affect the build system or external dependencies
  • ci: Changes to our CI configuration files and scripts
  • 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
  • test: Adding missing tests or correcting existing tests


The scope should be the name of the package/module affected (as perceived by the person reading the changelog generated from commit messages. It can be empty (e.g. if the change is a global or difficult to assign to a single component), in which case the parentheses are omitted.

Common scopes are client, server, mobile, core, worker, shared, etc.


The first line of the commit message should be a short description (50 characters is the soft limit), and should skip the full stop. Its first word is not capitalized unless there is a reason to capitalize it other than because it is the first word in the sentence.

Describe your changes in imperative mood, as if you are giving orders to the codebase to change its behavior (“change” not “changed” or “changes”). Try to make sure your explanation can be understood without external resources. Instead of giving a URL to a mailing list archive, summarize the relevant points of the discussion.

Rather than writing messages that say what you’ve done; consider these messages as the instructions for what applying the commit will do. It feels strange at first but it does make sense and eventually becomes natural.

If the subject starts to get too long, that’s a sign that you probably need to split up your commit to finer grained pieces.


The body should provide a meaningful commit message, which:

  • Explains the problem the change tries to solve, i.e. what is wrong with the current code without the change.
  • Justifies the way the change solves the problem, i.e. why the result with the change is better.
  • Alternate solutions considered but discarded, if any.


All breaking changes have to be mentioned in footer with the description of the change, justification and migration notes.


`port-runner` command line option has changed to `runner-port`, so that it is
consistent with the configuration file syntax.

To migrate your project, change all the commands, where you use `--port-runner`
to `--runner-port`.

Best Practices

If in doubt which identifier to use, run git log --no-merges on the files you are modifying to see the current conventions.

Don’t spoil the git history with multiple same message commits, better use git commit --amend --no-edit --date=now to append same work in progress.

This first line should be a concise summary of the changes introduced by the commit; if there are any technical details that cannot be expressed in these strict size constraints, put them in the body instead.

Remember the Conventional Commits spec is more like a guideline not a mandated rule or something. You are free to modify or adopt it in a way that makes you and your team happy.