Skip to content

Instantly share code, notes, and snippets.

@qoomon
Last active October 10, 2024 13:34
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

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 relevant changes
    • feat Commits, that adds or remove a new feature
    • fix Commits, that fixes a bug
  • refactor Commits, that rewrite/restructure your code, however does not change any API 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.

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


@alisenola
Copy link

Awesome!

@monish-khatri
Copy link

Helpful 😄

@123atif
Copy link

123atif commented Feb 5, 2024

Helpful

@andre-alck
Copy link

Should the first commit of the project be considered as 'build'?

@qoomon
Copy link
Author

qoomon commented Feb 12, 2024

The first commit is tricky, I think build is probably the best choice, however I'd tend to always use just init as the very first commit. Ill add this recommendation to this gist.

@Borodkov
Copy link

can you help me with server side script?
on my home Gitlab @ ubuntu 20.04 LTS create pre-commit hook in repository but got error on push from client:
pre-receive: 32: Syntax error: "(" unexpected (expecting "then")

Next, when comment lines 32 and 37 (if condition)
if ! [[ "$commit_msg_header" =~.....
...
fi
got 3 echo of my commit hash, "ERROR: Invalid commit message format", commit msg body

how rewrite if condition in line 32?

@qoomon
Copy link
Author

qoomon commented Feb 16, 2024

@Borodkov my bad. You need to change the first line of the script from #!/usr/bin/env sh to #!/usr/bin/env bash

@Borodkov
Copy link

how simple!
thanks @qoomon for fast answer

helpful gist

@Borodkov
Copy link

Borodkov commented Feb 16, 2024

can you help with some modifications of regexp for gitlab isuues links patterns (#1, #2, .... #999)?

  • #1 feat: add cool feature

what wrong with this one?:
^(#\d{1,3} )(feat|fix|refactor|style|test|docs|build): .+$

@qoomon
Copy link
Author

qoomon commented Feb 17, 2024

@Borodkov you can not use \d in bash regex use [[:digit:]] instead
e.g. (^(#[[:digit:]]{1,3} )(feat|fix|refactor|style|test|docs|build): .+$)

@dannyk0104
Copy link

Nice posting!
I have a question. What whould you put for changes for framework configuration files?
For springboot application (not sure you are familiar with springboot tho),
it has a application.yaml file that keeps some configurations like below.

spring:
  application:
    name: my-app
  profiles:
    active: local
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: http://mydb.com...

If I make a change in this configuration file, what would you put for the type? refactor?(since it is part of source code..?)

@qoomon
Copy link
Author

qoomon commented May 30, 2024

@dannyk0104 it depends

  • it is probably not a feat or fix commit, because you don't change the api
  • I would probably go for refactor, because you made a change to a source code file (I count application config files as source code as well)

@JohnnyWalkerDigital
Copy link

Finally! A clear, simple and concise explanation of the Conventional Commits format! So much better than the documentation on the actual website!

@qoomon
Copy link
Author

qoomon commented Jun 1, 2024

@JohnnyWalkerDigital thanks a lot.

@sarvsav
Copy link

sarvsav commented Jul 2, 2024

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

@qoomon
Copy link
Author

qoomon commented Jul 2, 2024

@sarvsav glad you like it :-)

@julian-alarcon
Copy link

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

@qoomon
Copy link
Author

qoomon commented Aug 8, 2024

@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

Helpful

@doni404
Copy link

doni404 commented Sep 25, 2024

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.

@andre-alck
Copy link

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

doni404 commented Sep 25, 2024

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

qoomon commented Sep 25, 2024

@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.

@nikitarevenco
Copy link

nikitarevenco commented Sep 28, 2024

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

qoomon commented Sep 28, 2024

@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

What would changing a variable name go under?

@qoomon
Copy link
Author

qoomon commented Sep 29, 2024

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

@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.

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