Skip to content

Instantly share code, notes, and snippets.

@qoomon
Last active September 24, 2024 18:55
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(api): handle empty message in request body
    
  • 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


@ujjwalstha
Copy link

ujjwalstha commented Aug 6, 2021

Thank you for the share.
But I have one question. What would be a suitable conventional commit message for deleted files?

@qoomon
Copy link
Author

qoomon commented Aug 6, 2021

@ujjwalstha depends on the file :-) In general I would say you should think of the behaviour that change by deleting your file, if it changes ops behaviour ex. ops: ${new behaviour} if it removes a feature ex. feature: remove ${feature} and so on. If it does not change behaviour it should be refactor: .... If non of that really fits as a last resort take chore: ...

@dmutoni
Copy link

dmutoni commented Nov 22, 2021

thanks for sharing

Copy link

ghost commented Mar 26, 2022

Thanks for sharing! :)

@marcothz
Copy link

marcothz commented Apr 6, 2022

Hey @qoomon,

I've just made a tiny fix and made it available here conventional_commit_messages.md.

💙

@qoomon
Copy link
Author

qoomon commented Apr 7, 2022

@marcothz thanks a lot I'll merge it

@juliomrafael
Copy link

Wonderfull 😁👏

@gutisalex
Copy link

using gitlab, the MR always puts its own commit message smth like Merge branch 'feature xyz' into 'develop'. I found where I can change the template under general - settings... but I wonder what would be the type of merge and squas commit messages?

@qoomon
Copy link
Author

qoomon commented Jun 30, 2022

In my opinion there are 2 two way to handle merge messages

  • #1 allow default merge messages e.g. https://github.com/qoomon/git-conventional-commits will treat them as a merge commit
  • #2 decide whether it is a fix, a feat or something else and try to sum up what has happened on the branch and create a new commit message.

I highly recommend the first way if your merge contains more than one type of commits

@andreygio
Copy link

Hi @qoomon, I am getting this error: No names found, cannot describe anything when I executed version command in a new repository what should I do to get my first changelog file when the repository is new and have no tags?

@qoomon
Copy link
Author

qoomon commented Aug 16, 2022

@andreygio for now you need to tag the initial commit with v0.0.0 or whatever your version pattern looks like. I'll consider to fix that in the cli by having a default version of 0.0.0 in that case.

@qoomon
Copy link
Author

qoomon commented Aug 17, 2022

@greeneley
Copy link

Great, thanks a lot

@howsmyanimeprofilepicture

Thank you for the nice resource !! It is really helpful to me ... 💕💕💕💕💕

@qoomon
Copy link
Author

qoomon commented Sep 17, 2022

@howsmyanimeprofilepicture glad to hear that.

@BoboTheBarbar
Copy link

Thanks a lot, that is really helpful 👍
One question though: is there a reason we prefer the imperative, present tense in subject and body?

@qoomon
Copy link
Author

qoomon commented Oct 26, 2022

@BoboTheBarbar this is caused by the idea that a commit message should always complete the sentence This commit will... or This commit will <subject>.

@BoboTheBarbar
Copy link

@qoomon this, sir, just made writing my commit messages much more meaningful and rewarding for me. Thanks for that :)

@0xProtocol
Copy link

How to commit new comments? Is this "style:"?

@qoomon
Copy link
Author

qoomon commented Nov 22, 2022

I would say docs

@marchingon12
Copy link

How about commuting translations and updating strings? Which type would be most suitable for this kind of commit? feat(il8n): added/updated fr, de languages perhaps?

@qoomon
Copy link
Author

qoomon commented Feb 20, 2023

@marchingon12 I probably would go for chore(i18n): yada yada yada if it is just an extension of i18n. I would not choose feat because it does not add or change behaviour.

If you introduce i18n the first time or if you add totally new languages I would go for feat(i18n): yada yada yada

@marchingon12
Copy link

@qoomon thnx a bunch! This helped a lot because I was struggling with which type to use, especially when I have an action that auto generated changelogs based on conventional commits. Thank you again! :D

@qoomon
Copy link
Author

qoomon commented Feb 20, 2023

You're welcome 🤗

@wbuck
Copy link

wbuck commented Mar 2, 2023

One thing I'm unsure about with conventional commits is how many commits should a PR have? Should I be squashing all of my commits in to a single commit before submitting a PR? Or can a PR have multiple commits with all commit messages following conventional commits?

@qoomon
Copy link
Author

qoomon commented Mar 2, 2023

IMHO it depends :-) Just think about whether it helps you to understand the history or not.

@dd84ai
Copy link

dd84ai commented Mar 14, 2023

Heyaaa! I liked that tool very much, but discovered it had some bugs that were not solvable due to tool using too many dependencies on other tools.
I remade this tool in golang, making it CI friendly one binary file, which is having zero dependencies from Operational System. Even Git is not needed to its functionality (because it uses inbuilt git-go!). Can be just more comfortable to use because it is not requiring Node.js or anything else installed at system :)
Fixed some stuff, augmented with new one.

https://github.com/darklab8/darklab_autogit
Tool uses also minimal amount of dependencies on other libraries, so hopefully should be more fixable and maintanable.

@qoomon
Copy link
Author

qoomon commented Mar 14, 2023

@dd84ai could you open some issues for the bugs you found at https://github.com/qoomon/git-conventional-commits/issues that would be very helpful. And what do you mean with to many dependencies?

@dd84ai
Copy link

dd84ai commented Mar 16, 2023

@qoomon

@dd84ai could you open some issues for the bugs you found at https://github.com/qoomon/git-conventional-commits/issues that would be very helpful. And what do you mean with to many dependencies?

And what do you mean with to many dependencies?

Node.js is one fragile and big dependency, programs often need certain Node.js version to run a program
Git is another dependency, user needs to have it available in path? for its working. Some people install it to work only git bash

As for other dependencies... strange, not seeing them at the moment. I thought i saw dependency on some semantic versioning library, which caused unresolvable bug. Ergh, probably i got mistaken with another library, which implements a similar functionality. Not really remembering where to seek now since it happened to me 4 moths ago back, when was traversing through different similar tools.
https://www.conventionalcommits.org/en/about/
https://github.com/c4urself/bump2version/blob/master/RELATED.md
Checking dependencies now, there is only dependency on yargs which is pretty much good :) Great job ;) I am sorry for saying disinformation. Your tool and work are certainly great in discovering all interface and rules to make it happen, interacting with users for many years and maintaining the product, my work is merely refactoring your accumulated years of results into a new language view

Well node.js and git are still very big dependencies though. So my remake of the tool still helps to eliminate them and making tool more usable in CI and in a long run when people having different node.js versions already installed. (at least if people don't know how to work with nvm)
Plus golang static typing and error resolving strategy should help to add easier more features and increasing its maintainability in a long run.
Due to golang having features even embedding any template / additional files into same binary, it makes quite smooth end result which will remain being one file always.
+added some new small features, like having ability to request next alpha, beta, prerelease semantic version of a product with setting build tag of semver, and other small things like that

@qoomon
Copy link
Author

qoomon commented Mar 16, 2023

@dd84ai thanks for the details answer

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