Skip to content

Instantly share code, notes, and snippets.

@qoomon
Last active July 18, 2025 15:51
Show Gist options
  • Save qoomon/5dfcdf8eec66a051ecd85625518cfd13 to your computer and use it in GitHub Desktop.
Save qoomon/5dfcdf8eec66a051ecd85625518cfd13 to your computer and use it in GitHub Desktop.
Conventional Commits Cheatsheet

Conventional Commit Messages starline

See how a minor change to your commit message style can make a difference.

git commit -m"<type>(<optional scope>): <description>" \
  -m"<optional body>" \
  -m"<optional footer>"

Note

This cheatsheet is opinionated, however it does not violate the specification of conventional commits

Tip

Take a look at git-conventional-commits ; a CLI util to ensure these conventions, determine version and generate changelogs.

Commit Message Formats

General Commit

<type>(<optional scope>): <description>
empty line as separator
<optional body>
empty line as separator
<optional footer>

Initial Commit

chore: init

Merge Commit

Merge branch '<branch name>'

Follows default git merge message

Revert Commit

Revert "<reverted commit subject line>"

Follows default git revert message

Types

  • Changes relevant to the API or UI:
    • feat Commits that add, adjust or remove a new feature to the API or UI
    • fix Commits that fix an API or UI bug of a preceded feat commit
  • refactor Commits that rewrite or restructure code without altering API or UI behavior
    • perf Commits are special type of refactor commits that specifically improve performance
  • style Commits that address code style (e.g., white-space, formatting, missing semi-colons) and do not affect application behavior
  • test Commits that add missing tests or correct existing ones
  • docs Commits that exclusively affect documentation
  • build Commits that affect build-related components such as build tools, dependencies, project version, CI/CD pipelines, ...
  • ops Commits that affect operational components like infrastructure, deployment, backup, recovery procedures, ...
  • chore Miscellaneous commits e.g. modifying .gitignore, ...

Scopes

The scope provides additional contextual information.

  • The scope is an optional part
  • Allowed scopes vary and are typically defined by the specific project
  • Do not use issue identifiers as scopes

Breaking Changes Indicator

  • A commit that introduce breaking changes must be indicated by an ! before the : in the subject line e.g. feat(api)!: remove status endpoint
  • Breaking changes should be described in the commit footer section, if the commit description isn't sufficiently informative

Description

The description contains a concise description of the change.

  • The description is a mandatory part
  • Use the imperative, present tense: "change" not "changed" nor "changes"
    • Think of This commit will... or This commit should...
  • Do not capitalize the first letter
  • Do not end the description with a period (.)
  • I case of breaking changes also see breaking changes indicator

Body

The body should include the motivation for the change and contrast this with previous behavior.

  • The body is an optional part
  • Use the imperative, present tense: "change" not "changed" nor "changes"

Footer

The footer should contain issue references and informations about Breaking Changes

  • The footer is an optional part, except if the commit introduce breaking changes
  • Optionally reference issue identifiers (e.g., Closes #123, Fixes JIRA-456)
  • Breaking Changes must start with the word BREAKING CHANGE:
    • For a single line description just add a space after BREAKING CHANGE:
    • For a multi line description add two new lines after BREAKING CHANGE:

Versioning

  • If your next release contains commit with...
    • Breaking Changes incremented the major version
    • API relevant changes (feat or fix) incremented the minor version
  • Else increment the patch version

Examples

  • feat: add email notifications on new direct messages
    
  • feat(shopping cart): add the amazing button
    
  • feat!: remove ticket list endpoint
    
    refers to JIRA-1337
    
    BREAKING CHANGE: ticket endpoints no longer supports list all entities.
    
  • fix(shopping-cart): prevent order an empty shopping cart
    
  • fix(api): fix wrong calculation of request body checksum
    
  • fix: add missing parameter to service call
    
    The error occurred due to <reasons>.
    
  • perf: decrease memory footprint for determine unique visitors by using HyperLogLog
    
  • build: update dependencies
    
  • build(release): bump version to 1.0.0
    
  • refactor: implement fibonacci number calculation as recursion
    
  • style: remove empty line
    

Git Hook Scripts to ensure commit message header format

Click to expand

commit-msg Hook (local)

pre-receive Hook (server side)

  • create following file in your repository folder .git/hooks/pre-receive
    #!/usr/bin/env bash
    
    # Pre-receive hook that will block commits with messages that do not follow regex rule
    
    commit_msg_type_regex='feat|fix|refactor|style|test|docs|build'
    commit_msg_scope_regex='.{1,20}'
    commit_msg_description_regex='.{1,100}'
    commit_msg_regex="^(${commit_msg_type_regex})(\(${commit_msg_scope_regex}\))?: (${commit_msg_description_regex})\$"
    merge_msg_regex="^Merge branch '.+'\$"
    
    zero_commit="0000000000000000000000000000000000000000"
    
    # Do not traverse over commits that are already in the repository
    excludeExisting="--not --all"
    
    error=""
    while read oldrev newrev refname; do
      # branch or tag get deleted
      if [ "$newrev" = "$zero_commit" ]; then
        continue
      fi
    
      # Check for new branch or tag
      if [ "$oldrev" = "$zero_commit" ]; then
        rev_span=`git rev-list $newrev $excludeExisting`
      else
        rev_span=`git rev-list $oldrev..$newrev $excludeExisting`
      fi
    
      for commit in $rev_span; do
        commit_msg_header=$(git show -s --format=%s $commit)
        if ! [[ "$commit_msg_header" =~ (${commit_msg_regex})|(${merge_msg_regex}) ]]; then
          echo "$commit" >&2
          echo "ERROR: Invalid commit message format" >&2
          echo "$commit_msg_header" >&2
          error="true"
        fi
      done
    done
    
    if [ -n "$error" ]; then
      exit 1
    fi
  • ⚠ make .git/hooks/pre-receive executable (unix: chmod +x '.git/hooks/pre-receive')

References


@nafg
Copy link

nafg commented Jun 12, 2025

@qoomon now it says ops twice

@qoomon
Copy link
Author

qoomon commented Jun 12, 2025

Fixed, thanks @nafg

@qoomon
Copy link
Author

qoomon commented Jun 24, 2025

Thx for 3333 ⭐

@RobSmyth
Copy link

In the Breaking Changes Indicator section it says that breaking changes MUST be described in the commit footer section. Is this correct?

My understanding is that the footer entry is optional.

The Conventional Commits spec items 11 and 12 says (I have highlighted and capitalised a few words):

  1. Breaking changes MUST be indicated in the type/scope prefix of a commit, OR as an entry in the footer.
  2. IF INCLUDED AS A FOOTER, a breaking change MUST consist of the uppercase text BREAKING CHANGE, followed by a colon, space, and description, e.g., BREAKING CHANGE: environment variables now take precedence over config files.

Do I misunderstand?

@qoomon
Copy link
Author

qoomon commented Jun 25, 2025

@RobSmyth you are right I'll adjust the related section.

@qoomon
Copy link
Author

qoomon commented Jun 25, 2025

After some thinking about the breaking changes indicator I changed it to mandatory (must) and the footer is optional (should) if the commit description is sufficient tu understand the breaking change. I don't agree on the conventional commit specs in that case. Because if you scroll through your commit you probably only see the the first line of the commit message therefore you easily miss a breaking change. To avoid this it's best practice to always add the ! as breaking change indicator.

@RobSmyth
Copy link

Hi @qoomon,

I don't agree on the conventional commit specs in that case.

Sure, and helps clarify what the intent of this document is. I like it, it has some good ideas but it reads as a Conventional Commits cheatsheet. I think the intent is to describe a specific approach based on Conventional Commits (CC). Or, maybe it is a spec for the pre-commit hook (nice btw). A newbie reading this now will be confused or misled as to what the standard is.

e.g. While CC specs feat and fix, it does not spec the compliant build. These come from industry practices and complimentary standards (as I think you give a link to).

I think it would help the reader if variations to the Conventional Commits (CC) spec (like making an optional bit mandatory) are highlighted with reasoning. Deviations, if any, are important as if your using CC for automatic versioning (e.g. my Git2SemVer) or automated changelog generation you need to know what may not work with other tools.

But as for the breaking change visibility ... i get your reasoning but (for me) it is not so important as I use CC as a semantic versioning tool:

  • I expect the versioning tool to see a breaking change indication and bump the MAJOR version automatically. That is very visible and the objective.
  • I expect a changelog generator to pick and highlight the breaking change in the changelog automatically (the version bump already highlights it).
  • A breaking change is never the intent of a change but a side effect. Describing the change is most important.

BTW: Multiple version number incremtns without a realse might not be valid Semantic Versioning as you do not mention releases. See Version Incrementing.

Like what your doing. Let me know if I have anything not quite right.

@qoomon
Copy link
Author

qoomon commented Jun 26, 2025

I think the intent is to describe a specific approach based on Conventional Commits (CC). Or, maybe it is a spec for the pre-commit hook (nice btw). A newbie reading this now will be confused or misled as to what the standard is.

IMHO it is still a cheatsheet for best practice of how to use the conventional commits specs, because there is nothing described in this cheatsheet that conflicts with the specs. I case of breaking changes it just narrow down what is best practice.

e.g. While CC specs feat and fix, it does not spec the compliant build. These come from industry practices and complimentary standards (as I think you give a link to).

Same applies here, it does not violate the specs it extend them.

Multiple version number incremtns without a realse might

I don't think that this would violate semantic versioning specs.

Like what your doing. Let me know if I have anything not quite right.
🤍

@Luxcium
Copy link

Luxcium commented Jul 6, 2025

and, when we're removing something like remove pages, remove unused functions, replace a plugin with another one. We use feat for that right? I've been using chore this whole time. I interpret it as the wildcard type.

Copie d'écran_20250706_152517
when using vscode conventional-commits extension

@qoomon
Copy link
Author

qoomon commented Jul 6, 2025

chore should only be the last resort, most of the time there is a better type

@RobSmyth
Copy link

RobSmyth commented Jul 7, 2025

and, when we're removing something like remove pages, remove unused functions, replace a plugin with another one. We use feat for that right? I've been using chore this whole time. I interpret it as the wildcard type.

IMO

remove unused functions - refactor as no change in functionality but improves code structure. The purpose is to improve code maintainability. But ... if those functions are part of the puplic API it is a breaking change and not refactoring.

replace a plugin - chore (if that is a dependency) and no change in functionality to last release.

remove pages - If it is removing functionality, that a breaking change (even if few affected) that people ought to know about - e.g: 3.0.0?
"refactor" If the page is no longer accessible to anybody is refactor.

FYI - "refactor" is good to use as it flags to reviewers that the PR has NO functional changes. So the reviewer can focus on looking for any functional change and judge if the code structure is improved. Hint - as recommended by Conventional Commits never mix commit types in asingle commit it just makes life hard and has poor outcomes.

May help too, similar but may help: https://cheatsheets.zip/conventional-commits

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