When working on a project many people don't have the time to write meaningful commit messages. For me, I have to work with many other developers which involve reviewing their commits, reviewing merge requests, creating and fixing stuff, etc. And all that simultaneously for multiple projects. Often their commit message does not describe what changes did they did in that current commit, and I have to dig through their code to understand that, and it can be a nightmare sometimes.
Even if they write a good message, many people have their own style or convention of writing their commit messages. To solve this particular problem I started using commitlint along with commitizen so that my team adheres to a commit convention.
Sneak peek to the end result π

Step 1: Setup husky and commitlint
Firstly, you will need husky, which is used for writing git hooks. See More
Install husky to your project.
npx husky-init && npm install
or, if you prefer yarn like me
npx husky-init && yarn
Next, we are going to install commitlint and commitlint-config-gitmoji
yarn add -D @commitlint/cli commitlint-config-gitmoji
or,
npm install --save-dev @commitlint/cli commitlint-config-gitmoji
The @commitlint/cli will be used to check if our commit message follows the convention we configured for the project and the commitlint-config-gitmoji is the commit convention preset we will be using. There are other conventions as well which you can use.
The commitlint-config-gitmoji follows the below convention.
You need to provide a emoji (or gitmoji) then a type, following a scope (not mandatory), and then the subject, which is your actual commit message. You can add a body and footer too if you like.
:gitmoji: type(scope?): subject
body?
footer?
Example,
β¨ feat(api): add middleware for user authentication
Now, we need to define the commitlint config for our project. Create a file named commitlint.config.js and define your config given below.
module.exports = {
extends: ['gitmoji'],
rules: {
'header-max-length': [0, 'always', 100],
},
};
You can customize the rules of your commit message per you like similarly to eslint. See here
Step 2: Add commitlint checking as a git hook
Next, we need to add commitlint as a git hook using husky to check our commit message before every commit. To do this run the below command.
yarn husky add .husky/commit-msg 'yarn commitlint --edit "$1"'
OR
npx husky add .husky/commit-msg 'npx --no-install commitlint --edit "$1"'
This will create a file named commit-msg inside your project inside .husky folder.
Note: husky by default creates a pre-commit file, which runs npm test. If you don't have a test script defined in your package.json it will throw an error. You can remove the npm test line from the pre-commit file or add a valid test script.
Now try to do a commit π
Well now my fellow teammates cannot commit unless they write a proper commit message π.
commitlint prevents us from doing a commit if the commit message does not adhere to the structure provided by commitlint-config-gitmoji.
Step 3: Adding commitizen cli for composing commit messages
Coming to the last part, now we will create a CLI helper to generate the commit message using commitizen. Also we are using cz-customizable to customize the CLI helper.
yarn add -D commitizen cz-customizable
OR
npm install --save-dev commitizen cz-customizable
Next, add a commitizen config in your package.json like below
{
....
"devDependencies": {
...,
},
"config": {
"commitizen": {
"path": "cz-customizable"
}
}
}
Now create a file in your root folder named .cz-config.js to customize the options of the CLI helper, and paste the below config.
module.exports = {
types: [
{ value: ':sparkles: feat', name: 'β¨ feat:\tAdding a new feature' },
{ value: ':bug: fix', name: 'π fix:\tFixing a bug' },
{ value: ':memo: docs', name: 'π docs:\tAdd or update documentation' },
{
value: ':lipstick: style',
name: 'π style:\tAdd or update styles, ui or ux',
},
{
value: ':recycle: refactor',
name: 'β»οΈ refactor:\tCode change that neither fixes a bug nor adds a feature',
},
{
value: ':zap: perf',
name: 'β‘οΈ perf:\tCode change that improves performance',
},
{
value: ':white_check_mark: test',
name: 'β
test:\tAdding tests cases',
},
{
value: ':truck: chore',
name: 'π chore:\tChanges to the build process or auxiliary tools\n\t\tand libraries such as documentation generation',
},
{ value: ':rewind: revert', name: 'βͺοΈ revert:\tRevert to a commit' },
{ value: ':construction: wip', name: 'π§ wip:\tWork in progress' },
{
value: ':construction_worker: build',
name: 'π· build:\tAdd or update regards to build process',
},
{
value: ':green_heart: ci',
name: 'π ci:\tAdd or update regards to build process',
},
],
scopes: [
{ name: 'ui' },
{ name: 'android' },
{ name: 'ios' },
{ name: 'home' },
{ name: 'planner' },
{ name: 'settings' },
],
scopeOverrides: {
fix: [{ name: 'merge' }, { name: 'style' }, { name: 'test' }, { name: 'hotfix' }],
},
allowCustomScopes: true,
allowBreakingChanges: ['feat', 'fix'],
// skip any questions you want
skipQuestions: ['body'],
subjectLimit: 100,
};
Also, add a npm script to run the commitizen cli.
{
"scripts": {
...,
"cm": "cz"
},
"dependencies": {
...
}
}
You can modify the config as per your choice. See here
Now run the script to see commitizen in action.
yarn cm
OR
npm run cm
Ta-da, now you and everyone in your team can easily write beautiful conventional commit messages.


Top comments (4)
Thanks a lot :)
Liked your articled.
I standardized around cz-customizable which I found is a better alternative especially in standalone mode.
sorry.. I meant to say : that standalone mode for cz-customizable is great
Awesome.