Skip to content

Instantly share code, notes, and snippets.

@qoomon
Last active February 14, 2025 15:21
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.

Tip

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

Commit Message Formats

Default

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

Merge Commit

Merge branch '<branch name>'

Follows default git merge message

Revert Commit

Revert "<reverted commit subject line>"

Follows default git revert message

Inital Commit

chore: init

Types

  • API or UI relevant changes
    • feat Commits, that add or remove a new feature to the API or UI
    • fix Commits, that fix a API or UI bug of a preceded feat commit
  • refactor Commits, that rewrite/restructure your code, however do not change any API or UI behaviour
    • perf Commits are special refactor commits, that improve performance
  • style Commits, that do not affect the meaning (white-space, formatting, missing semi-colons, etc)
  • test Commits, that add missing tests or correcting existing tests
  • docs Commits, that affect documentation only
  • build Commits, that affect build components like build tool, ci pipeline, dependencies, project version, ...
  • ops Commits, that affect operational components like infrastructure, deployment, backup, recovery, ...
  • chore Miscellaneous commits e.g. modifying .gitignore

Scopes

The scope provides additional contextual information.

  • Is an optional part of the format
  • Allowed Scopes depends on the specific project
  • Don't use issue identifiers as scopes

Breaking Changes Indicator

Breaking changes should be indicated by an ! before the : in the subject line e.g. feat(api)!: remove status endpoint

  • Is an optional part of the format

Description

The description contains a concise description of the change.

  • Is a mandatory part of the format
  • Use the imperative, present tense: "change" not "changed" nor "changes"
    • Think of This commit will... or This commit should...
  • Don't capitalize the first letter
  • No dot (.) at the end

Body

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

  • Is an optional part of the format
  • Use the imperative, present tense: "change" not "changed" nor "changes"
  • This is the place to mention issue identifiers and their relations

Footer

The footer should contain any information about Breaking Changes and is also the place to reference Issues that this commit refers to.

  • Is an optional part of the format
  • optionally reference an issue by its id.
  • Breaking Changes should start with the word BREAKING CHANGES: followed by space or two newlines. The rest of the commit message is then used for this.

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 CHANGES: ticket enpoints no longer supports list all entites.
    
  • 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 because of <reasons>.
    
  • perf: decrease memory footprint for determine uniqe 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 messges 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


@yaroslavgorshkov
Copy link

powerful

@duggi
Copy link

duggi commented Oct 6, 2024

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
Copy link
Author

qoomon commented Oct 6, 2024

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

@marss72
Copy link

marss72 commented Oct 12, 2024

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
Copy link
Author

qoomon commented Oct 12, 2024

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
Copy link

marss72 commented Oct 12, 2024

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

helpful , Thanks

@andraxiusabyss
Copy link

andraxiusabyss commented Jan 19, 2025

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
Copy link
Author

qoomon commented Jan 19, 2025

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)

@andraxiusabyss
Copy link

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
Copy link
Author

qoomon commented Jan 22, 2025

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

@andraxiusabyss
Copy link

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
Copy link
Author

qoomon commented Jan 22, 2025

Glad I could help

@wolfspyre
Copy link

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
Copy link

cfgnunes commented Feb 10, 2025

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

# 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
Copy link
Author

qoomon commented Feb 10, 2025

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

@qoomon
Copy link
Author

qoomon commented Feb 10, 2025

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

@qoomon
Copy link
Author

qoomon commented Feb 10, 2025

@cfgnunes regarding

 echo "  feat:     A new feature."
 echo "  fix:      A bug fix."

I think it is important to emphasize that those type should only be used for API changes not for arbitrary commits that adding any new feature or fixing something within the project

@0x404
Copy link

0x404 commented Feb 11, 2025

Hi, we conducted a study and found that conventional commits are becoming increasingly popular among top open-source projects. Specifically, there is a stable uptrend in the adoption of conventional commits, with some projects mandating their use. By 2023, in repositories that do not require conventional commits, we found nearly 10% of commits were in line with the Conventional Commit format, indicating their popularity among developers.

During this process, we noticed that some commits, despite being conventional, clearly misused the commit message format, for example: feat: remove unnecessary lines from test file. This spurred our curiosity about the challenges developers face when categorizing commits using the conventional commits format. Therefore, we analyzed all the issues in this project, as well as the top 100 questions on Stack Overflow related to conventional commits. Our analysis identified four categories of challenges developers face, with the most common (around 57.7%) being confusion over which type to use. In the current CCS definition, categories other than 'feat' and 'fix' lack clear definitions, leading developers to rely on the categorizations used by Angular and other projects, which often overlap and lack clarity. For instance, in Angular's definition, 'refactor' is defined as "A code change that neither fixes a bug nor adds a feature," which could ambiguously include 'style', 'perf', 'test', among others.

We have proposed a clearer and less overlapping list of definitions based on our literature review and the documentation in repositories currently using conventional commits. Based on this, we have drafted an academic paper (you can find more detailed information about the above here), which has undergone peer review and been accepted by ICSE 2025, a premier software engineering conference.

We are happy to provide additional details or clarification about our methodology and findings. We look forward to any feedback you may have.

@qoomon
Copy link
Author

qoomon commented Feb 11, 2025

@0x404 so what's your point?

@cfgnunes
Copy link

@qoomon I didn't know about the project git-conventional-commits! It is really awesome! Thanks for this project and for sharing this helpful notes on Gist. 🚀

@qoomon
Copy link
Author

qoomon commented Feb 11, 2025

@cfgnunes git-conventional-commits is mentioned in the 3rd line of this gist in a green colored Tip box 😉

I'm glad that it's handy for you

@cfgnunes
Copy link

@qoomon The git-conventional-commits project is excellent. However, It requires quite a few dependencies to set up. I personally prefer using my simple shell script to validate commit messages with a simple regex (in my case, I don't need to install nothing to use it).

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