Understanding Conventional Commits
Conventional Commits is a lightweight convention built on top of commit messages. It provides a set of rules for creating a clear commit history, which makes it easier to write automated tools on top of the codebase. By standardizing the format, teams can improve collaboration efficiency and codebase maintainability.
The standard structure generally looks like this:
<type>[optional scope]: <description>
[optional body]
[optional footer(s)]
Key components include:
- fix: Patches a bug in the codebase (correlates with
PATCHin Semantic Versioning). - feat: Introduces a new feature (correlates with
MINORin Semantic Versioning). - BREAKING CHANGE: Indicates a breaking API change. This can be noted by adding a
!after the type/scope or including aBREAKING CHANGE:footer. - Other types: Such as
build,chore,ci,docs,style,refactor,perf, andtest.
Common Examples
Basic feature addition:
feat(auth): implement JWT validation logic
Fix with a breaking change indicator:
fix!: remove deprecated legacy API endpoint
BREAKING CHANGE: The /api/v1/legacy endpoint is no longer supported.
Documentation update:
docs: update README with setup instructions
Summary of Commit Types
| Type | Purpose |
|---|---|
| feat | Introduction of a new capability |
| fix | Resolution of a software defect |
| docs | Changes to documentation only |
| style | Formatting changes that do not affect logic |
| refactor | Code restructuring without behavior change |
| perf | Performance improvements |
| test | Adding or correcting tests |
| build | Changes to build system or dependencies |
| ci | Updates to CI configuration files |
| chore | Routine tasks or tooling adjustments |
| revert | Reverting a previous commit |
Setting Up Commitizen
Commitizen is a command-line tool that prompts you to fill in required fields and generates a standardized commit message.
Install globally using pnpm:
pnpm add -g commitizen
pnpm add -g cz-conventional-changelog
Configure the adapter:
echo '{ "path": "cz-conventional-changelog" }' > ~/.czrc
Instead of git commit, use:
git cz
Customizing with cz-customizable
To personalize the prompts and add emojis, use cz-customizable.
Install the dependency:
npm install cz-customizable --save-dev
Update package.json:
{
"config": {
"commitizen": {
"path": "node_modules/cz-customizable"
}
}
}
Create a configuration file named .cz-config.js in the project root:
module.exports = {
types: [
{ value: '✨ feat', name: '✨ feat: New feature' },
{ value: '🐛 fix', name: '🐛 fix: Bug fix' },
{ value: '📝 docs', name: '📝 docs: Documentation changes' },
{ value: '💄 style', name: '💄 style: Formatting changes' },
{ value: '♻️ refactor', name: '♻️ refactor: Code refactoring' },
{ value: '⚡️ perf', name: '⚡️ perf: Performance boost' },
{ value: '✅ test', name: '✅ test: Adding tests' },
{ value: '🔧 chore', name: '🔧 chore: Tooling changes' },
{ value: '⏪ revert', name: '⏪ revert: Revert commit' }
],
messages: {
type: "Select the type of change:",
scope: "Specify the scope (optional):",
subject: "Write a short description:",
body: "Provide a detailed description (optional):",
footer: "Reference issues here (optional):",
confirmCommit: "Ready to commit?"
},
subjectLimit: 72
};
Enforcing Standards with Commitlint
To prevent non-compliant commits, integrate commitlint.
If using standard conventions:
npm install @commitlint/cli @commitlint/config-conventional -D
Create commitlint.config.js:
module.exports = {
extends: ['@commitlint/config-conventional']
};
If using the customizable adapter:
npm install commitlint-config-cz -D
module.exports = {
extends: ['cz']
};
Automating with Husky and Lint-Staged
husky manages Git hooks, and lint-staged runs linters on staged files.
Initialize Husky:
pnpm install husky --save-dev
npx husky install
Add a hook to validate the commit message:
npx husky add .husky/commit-msg 'npx --no -- commitlint --edit $1'
Install lint-staged:
npm install lint-staged --save-dev
Configure package.json to run checks before commits:
{
"scripts": {
"lint:js": "eslint --ext .js,.ts,.tsx",
"format": "prettier --write"
},
"lint-staged": {
"*.{js,ts,tsx}": ["npm run lint:js", "npm run format"],
"*.{json,md}": ["npm run format"]
}
}
Add the pre-commit hook:
npx husky add .husky/pre-commit 'npx lint-staged'