Commitizen: Writing Better Git Commits with Conventional Commits
Good commit messages are the foundation of maintainable codebases. They help you understand what changed, why it changed, and how it impacts your project. But writing consistent, meaningful commit messages can be challenging. That's where Commitizen comes in.
What is Commitizen?
Commitizen is a command-line tool that helps you write standardized commit messages following the Conventional Commits specification. Instead of struggling to remember commit message formats, Commitizen guides you through an interactive prompt to create well-structured commits.
Why Use Conventional Commits?
Conventional Commits provide a standardized format for commit messages that:
- Improves readability - Clear structure makes commits easier to scan
- Enables automation - Tools can automatically generate changelogs and determine semantic versioning
- Better collaboration - Team members understand changes at a glance
- Easier debugging - Find specific types of changes quickly
The format looks like this:
<type>[optional scope]: <description>
[optional body]
[optional footer(s)]
Installing Commitizen
Global Installation
# Install globally with npm
npm install -g commitizen
# Install globally with yarn
yarn global add commitizen
# Install globally with pnpm
pnpm add -g commitizen
Project Installation
# Install as dev dependency
npm install --save-dev commitizen
# Add "commit": "cz" to the scripts section of package.json
Installing the Conventional Changelog Adapter
Commitizen needs an adapter to define the commit format. The most popular is
cz-conventional-changelog:
# Install the adapter
npm install --save-dev cz-conventional-changelog
# Configure it in package.json
npx commitizen init cz-conventional-changelog --save-dev --save-exact
Or add this configuration manually to your package.json:
{
"config": {
"commitizen": {
"path": "./node_modules/cz-conventional-changelog"
}
}
}
Using Commitizen
Once installed, replace git commit with git cz or npm run commit:
# Instead of this
git add .
git commit -m "fix something"
# Do this
git add .
git cz
Commitizen will then prompt you through an interactive questionnaire:
? Select the type of change that you're committing: (Use arrow keys)
❯ feat: A new feature
fix: A bug fix
docs: Documentation only changes
style: Changes that do not affect the meaning of the code
refactor: A code change that neither fixes a bug nor adds a feature
perf: A code change that improves performance
test: Adding missing tests or correcting existing tests
Commit Types Explained
Here are the standard commit types and when to use them:
feat - New Features
feat: add user authentication system
feat(auth): implement OAuth2 login
feat(api): add user profile endpoints
fix - Bug Fixes
fix: resolve login redirect issue
fix(auth): handle expired token correctly
fix(ui): correct button alignment on mobile
docs - Documentation
docs: update README installation steps
docs(api): add endpoint documentation
docs: fix typos in contributing guide
style - Code Style
style: fix eslint warnings
style: format code with prettier
style: remove trailing whitespace
refactor - Code Refactoring
refactor: simplify user validation logic
refactor(auth): extract token helper functions
refactor: migrate to TypeScript
perf - Performance Improvements
perf: optimise database queries
perf(images): implement lazy loading
perf: reduce bundle size by 20%
test - Tests
test: add unit tests for auth service
test(e2e): add login flow tests
test: improve test coverage to 90%
chore - Maintenance
chore: update dependencies
chore(deps): bump lodash to 4.17.21
chore: configure CI/CD pipeline
ci - Continuous Integration
ci: add GitHub Actions workflow
ci: fix Docker build process
ci: update deployment script
build - Build System
build: update webpack configuration
build: add production optimisation
build(deps): upgrade to Node 18
Advanced Features
Scopes
Scopes provide additional context about what part of the codebase was affected:
feat(auth): add login functionality
fix(ui): resolve mobile navigation bug
docs(api): update endpoint documentation
Breaking Changes
For changes that break backward compatibility, add ! after the type/scope or
include BREAKING CHANGE: in the footer:
feat!: remove deprecated API endpoints
BREAKING CHANGE: The /v1/users endpoint has been removed. Use /v2/users instead.
Multiple Line Commits
For complex changes, provide a detailed body and footer:
feat(auth): implement OAuth2 authentication
Add support for Google and GitHub OAuth2 providers.
Users can now sign in using their existing accounts
from these platforms.
Closes #123
Reviewed-by: @teammate
Setting Up Git Aliases
Make it even easier by setting up Git aliases:
# Add to your .gitconfig
git config --global alias.cz '!npx cz'
# Or add this alias to your shell
alias gcz='git cz'
Team Configuration
For consistent team usage, add these scripts to your package.json:
{
"scripts": {
"commit": "cz",
"commit:signed": "cz --signoff"
},
"scripts": {
"prepare": "husky"
}
}
Custom Adapters
You can create custom adapters for specific project needs. Popular alternatives include:
cz-emoji
Adds emoji to commit messages:
npm install --save-dev cz-emoji
Example output: ✨ feat: add new feature
cz-customizable
Highly customizable adapter:
npm install --save-dev cz-customizable
Create a .cz-config.js file to define custom prompts and types.
Integration with Tools
Husky + Commitlint
Enforce conventional commits with validation:
# Install commitlint
npm install --save-dev @commitlint/cli @commitlint/config-conventional
# Install husky
npm install --save-dev husky
# Setup husky
npx husky init
echo 'npx --no -- commitlint --edit ${1}' > .husky/commit-msg
Create commitlint.config.js:
module.exports = {
extends: ['@commitlint/config-conventional'],
rules: {
'type-enum': [
2,
'always',
[
'feat',
'fix',
'docs',
'style',
'refactor',
'perf',
'test',
'chore',
'ci',
'build',
],
],
},
};
Semantic Release
Automatically generate releases and changelogs:
npm install --save-dev semantic-release
Add to package.json:
{
"release": {
"branches": ["main"],
"plugins": [
"@semantic-release/commit-analyzer",
"@semantic-release/release-notes-generator",
"@semantic-release/changelog",
"@semantic-release/npm",
"@semantic-release/github"
]
}
}
Best Practices
- Be specific - Use clear, descriptive commit messages
- Use present tense - "add feature" not "added feature"
- Limit subject line - Keep it under 50 characters
- Use body for context - Explain why, not what
- Reference issues - Include ticket numbers when applicable
- Review before committing - Double-check your message
Common Patterns
Feature Development
feat(user): add user profile page
feat(user): implement profile editing
feat(user): add profile picture upload
test(user): add profile component tests
docs(user): document profile API endpoints
Bug Fixes
fix(auth): resolve token expiration issue
test(auth): add test for token refresh
docs(auth): update authentication guide
Refactoring
refactor(api): extract validation middleware
refactor(api): simplify error handling
test(api): update tests for refactored code
Troubleshooting
Commitizen not working
# Check if commitizen is installed
npx cz --version
# Verify adapter configuration
cat package.json | grep -A 5 commitizen
Custom adapter not loading
# Check adapter installation
npm list cz-conventional-changelog
# Verify path in package.json
Prompts not showing
# Try running with explicit adapter
npx cz --adapter=cz-conventional-changelog
Migration Strategy
For Existing Projects
- Start gradually - Begin using commitizen for new commits
- Train the team - Share this guide and best practices
- Set up automation - Add linting and release automation
- Review and iterate - Adjust rules based on team feedback
Example Migration Script
#!/bin/bash
# setup-commitizen.sh
echo "Setting up Commitizen..."
# Install dependencies
npm install --save-dev commitizen cz-conventional-changelog
# Configure commitizen
npx commitizen init cz-conventional-changelog --save-dev --save-exact
# Add "commit": "cz" to the scripts section of package.json
# Setup git alias
git config alias.cz '!npx cz'
echo "✅ Commitizen setup complete!"
echo "Use 'npm run commit' or 'git cz' for your next commit"
Conclusion
Commitizen transforms the way you write commit messages by providing structure, consistency, and automation capabilities. While it might feel like extra overhead initially, the long-term benefits of readable history, automated releases, and better collaboration make it invaluable for any serious development project.
Start small, be consistent, and watch your Git history become a valuable documentation resource for your project's evolution.
Next steps:
- Install Commitizen in your current project
- Try it for a few commits to get comfortable
- Set up team guidelines and automation
- Explore semantic release for automated versioning
Happy committing! 🚀