Skip to content

Instantly share code, notes, and snippets.

@qoomon
Last active July 20, 2026 03:07
Show Gist options
  • Select an option

  • Save qoomon/5dfcdf8eec66a051ecd85625518cfd13 to your computer and use it in GitHub Desktop.

Select an option

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 feature to/of/from 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, ...
  • ops Commits that affect operational aspects like infrastructure (IaC), deployment scripts, CI/CD pipelines, backups, monitoring, or recovery procedures, ...
  • chore Commits that represent tasks like initial commit, 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 (.)
  • In 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


@sarvsav

sarvsav commented Jul 2, 2024

Copy link
Copy Markdown

Thank you for sharing this. It is super helpful. 🙏

@qoomon

qoomon commented Jul 2, 2024

Copy link
Copy Markdown
Author

@sarvsav glad you like it :-)

@julian-alarcon

Copy link
Copy Markdown

What about adding ci ?
As recommended here: https://www.conventionalcommits.org/en/v1.0.0/ to describe changes related with CI/CD pipelines?

@qoomon

qoomon commented Aug 8, 2024

Copy link
Copy Markdown
Author

@julian-alarcon IMHO ci commit are typically changes to something related to build the software/artifact or something related to test the software or something related to changes in the behaviour of the process of the deployment (operational task) therefore ops

That's why you actually don't need a ci type.

What kind of ci related task you are thinking of?

@Asphaltrr

Copy link
Copy Markdown

Helpful

@doni404

doni404 commented Sep 25, 2024

Copy link
Copy Markdown

Should the first commit of the project be considered as 'build'? @andre-alck

I believe it should be categorized as a chore since labeling it that way for an initial commit makes sense.

@asacxyz

asacxyz commented Sep 25, 2024

Copy link
Copy Markdown

Should the first commit of the project be considered as 'build'? @andre-alck

I believe it should be categorized as a chore since labeling it that way for an initial commit makes sense.

Why do you think that makes sense?

@doni404

doni404 commented Sep 25, 2024

Copy link
Copy Markdown

Should the first commit of the project be considered as 'build'? @andre-alck

I believe it should be categorized as a chore since labeling it that way for an initial commit makes sense.

Why do you think that makes sense?

The build type is usually reserved for changes that affect the build system, such as updating dependencies, configuration files for build tools, or scripts that are essential for the build process. Since the initial commit is more about setting up the project structure and doesn't specifically involve modifying or adding build-related configurations, using chore is more fitting for this purpose. @andre-alck

@qoomon

qoomon commented Sep 25, 2024

Copy link
Copy Markdown
Author

@doni404 In the end it depends on what your first commit contains. If it is just a README it is probably docs if you have a hello world program with build process build make sense, if it already contains a real feature it might be an feat commit. If you just commit an .gitignore file or even create an empty commit chore: init would be appropriate.

If you are in doubt I would go for chore: init by default.

But to be honest it really does not matter for the first commit.

@nik-rev

nik-rev commented Sep 28, 2024

Copy link
Copy Markdown

What about commits in repositories that aren't even code? For example text-only .md repos. I usually do something like this myself:

  • fix when fixing spelling issues
  • style e.g. changing a bullet point list of 1. 2. 3. to 1. 1. 1., adding removing insignificant whitespace
  • feat for adding new content
  • docs for modifying which is not the primary source of purpose for the repo (e.g. repo contains javascript learning material, but we are modifying the README or other files which are only used for people working on the repo, not the end user)

or is it even worth using conventional commits on these types of repositories?

@qoomon

qoomon commented Sep 28, 2024

Copy link
Copy Markdown
Author

@nikitarevenco I think it make sense in your scenario as well.
In you use-case adding new content is a new feature because it will add a new feature to the primariy interface in this case the interface is a document. However I guess docs commits will be quite rare, because docs commit basically will add description on how to iteract with the project interface in your case a document, but maybe there will be some cases.

@ammar-codeable

Copy link
Copy Markdown

What would changing a variable name go under?

@qoomon

qoomon commented Sep 29, 2024

Copy link
Copy Markdown
Author

@ammar-codeable most likely refactor or feat if it has an impact on the interface

@yaroslavgorshkov

Copy link
Copy Markdown

powerful

@duggi

duggi commented Oct 6, 2024

Copy link
Copy Markdown

If you fix a bug in the build system
For example a ci config file
Is it A, B, C … or something else?

A: fix: update syntax error in ci config
B: build: fix syntax error in ci config
C: fix(ci): update syntax error in ci config

@qoomon

qoomon commented Oct 6, 2024

Copy link
Copy Markdown
Author

Definitely B, because fix as well as feat are only for interface/API related changes.

@marss72

marss72 commented Oct 12, 2024

Copy link
Copy Markdown

Hey. What type would I use, if I had some method, and I would only change some value in it, that would change the behavior of the program, but would not add or remove any feature.

A great example can be a method validate_registration(person), that would check for person age for example. In this example, how could I name the commit changing the minimum age from 18 to 15 years?

@qoomon

qoomon commented Oct 12, 2024

Copy link
Copy Markdown
Author

Should be feat because it will effect the API. Take feature as a synonym of behavior. When ever a behavior is changed by purpose it is most likely a feat commit if you repair an exit behavior it is most likely a fix commit.

@marss72

marss72 commented Oct 12, 2024

Copy link
Copy Markdown

Should be feat because it will effect the API. Take feature as a synonym of behavior. Wen ever a behavior is changed by purpose it is most likely a feat commit if you repair an exit behavior it is most likely a fix commit.

Thanks. I appreciate your gist and your quick response.

@Cyrille-18

Copy link
Copy Markdown

helpful , Thanks

@ierdss

ierdss commented Jan 19, 2025

Copy link
Copy Markdown

Does operational components include directories and assets under ops? Or are they under the feat category?

ops Commits, that affect operational components like infrastructure, deployment, backup, recovery, ...

Thanks for this. Your cheat sheet really helps!

Thanks again in advance!

@qoomon

qoomon commented Jan 19, 2025

Copy link
Copy Markdown
Author

Does operational components include directories and assets under ops?

I'm not sure what you mean by ops directory. However if you are referring to a directory where all your IAC or operation script are located then in most cases this will be an ops commit, unless it changes something that would result in change for the interface or api users. And you always have to define what are the users of your projekt (developers that are comiting to this project should not seen as users)

@ierdss

ierdss commented Jan 21, 2025

Copy link
Copy Markdown

I think I am lacking on my initial comment. I am going to mimic the comment from above to also give an example.

If I want to transfer a component, a folder, or an asset, into another folder, which category does it fall under?

A: docs(button): transfer story to foundations
B: ops(button): transfer story to foundations
C: chore(button): transfer story to foundations

@qoomon

qoomon commented Jan 22, 2025

Copy link
Copy Markdown
Author

It depends :-) on what kind of folder or assets you are moving.

  • If its related to documentation then it should be docs
  • If its related to operations like infrastructure as code then it should be ops
  • If you restructuring your application resources it should probably be refactor
  • chore should only be used if the commit really does not fit in any category e.g. editing the .gitignore file

@ierdss

ierdss commented Jan 22, 2025

Copy link
Copy Markdown

Omg thank you very much! This is the answer I am looking for!

I have been practicing conventional commits and I always find myself in situations similar to this. Thanks again!

@qoomon

qoomon commented Jan 22, 2025

Copy link
Copy Markdown
Author

Glad I could help

@wolfspyre

Copy link
Copy Markdown

this is super cool... Thanks for putting it together for people to reference.

Something I suspect might help others even more:
Indicate clearly which of the types/scopes aught corelate to major/minor/patch semver iteration.... I don't know if that's something you intended this to convey or not. or think is relevant to this doc or not... but .... figured I'd offer the opinion ;) Feel free to disregard if it's counter yours

Regardless; Thanks for sharing this and helping out fellow peeps.... <3

@cfgnunes

cfgnunes commented Feb 10, 2025

Copy link
Copy Markdown

I wanted to share my commit-msg Git hook script that enforces the Conventional Commits standard. This script ensures that all commit messages follow a consistent format, improving readability and maintainability of the project's commit history.

What it does:

  • Validates commit messages against the Conventional Commits format: <type>(<scope>): <subject>.
  • Provides detailed error messages if the commit message doesn't match the expected format.
  • Includes descriptions for each valid commit type to help users understand when to use them.

How to use it:

  1. Copy the script below into your repository's .git/hooks/commit-msg file.
  2. Make the script executable by running:
    chmod +x .git/hooks/commit-msg
  3. Start committing! The hook will automatically validate your commit messages.

Script:

#!/usr/bin/env bash

# Path to the commit message file (provided by Git).
COMMIT_MSG_FILE=$1

# Ignore automatic commit messages containing ' into ' or 'Merge'.
if grep --quiet --extended-regexp " into |^Merge " "$COMMIT_MSG_FILE"; then
    exit 0
fi

# Read the commit message from the file.
COMMIT_MSG=$(cat "$COMMIT_MSG_FILE")

CONVENTIONAL_COMMIT_REGEX='^(feat|fix|docs|style|refactor|test|chore|build|ci|perf|revert)(\([a-zA-Z0-9_.-]+\))?(!)?:\s.*$'

# Check if the commit message matches the regex.
if ! [[ $COMMIT_MSG =~ $CONVENTIONAL_COMMIT_REGEX ]]; then
    echo "ERROR: Commit message does not follow Conventional Commits format."
    echo
    echo "The commit message should be structured as follows:"
    echo "<type>(<optional scope>): <description>"
    echo "[optional body]"
    echo "[optional footer(s)]"
    echo
    echo "Valid types are:"
    echo "  feat:     A new feature."
    echo "  fix:      A bug fix."
    echo "  docs:     Documentation changes."
    echo "  style:    Code style changes (formatting, missing semicolons, etc.)."
    echo "  refactor: Code refactoring (neither fixes a bug nor adds a feature)."
    echo "  test:     Adding or updating tests."
    echo "  chore:    Routine tasks like updating dependencies or build tools."
    echo "  build:    Changes affecting the build system or external dependencies."
    echo "  ci:       Changes to CI configuration files or scripts."
    echo "  perf:     Performance improvements."
    echo "  revert:   Reverting a previous commit."
    echo
    echo "Examples:"
    echo "  feat(auth): add login functionality"
    echo "  fix(api)!: resolve timeout issue"
    echo "  docs(readme): update installation instructions"
    echo
    exit 1
fi

exit 0

@qoomon

qoomon commented Feb 10, 2025

Copy link
Copy Markdown
Author

@wolfspyre I've added a versioning section. Thanks for the idea.

@qoomon

qoomon commented Feb 10, 2025

Copy link
Copy Markdown
Author

@cfgnunes thanks for sharing, however I would recommend using git-conventional-commits

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