commitlint: Commit Message Linter Guide
npm install --save-dev @commitlint/cli @commitlint/config-conventional npx commitlint --from HEAD~1 --to HEAD
commitlint validates commit messages against a rule set. Paired with @commitlint/config-conventional it enforces the Conventional Commits spec: valid type, optional scope format, no trailing period, correct breaking-change syntax. Anything invalid blocks the commit: in a pre-commit hook locally, or in CI for anything that slips through.
The real value is upstream automation: a history that always passes commitlint guarantees semantic-release and changelog generators work, because their inputs are structurally predictable. It is the cheapest CI step you can add to an open source project.
Setup
npm install --save-dev @commitlint/cli @commitlint/config-conventional
# commitlint.config.js:
module.exports = { extends: ["@commitlint/config-conventional"] }Rules
# Most recent commit: npx commitlint --from HEAD~1 --to HEAD # Last 5 commits: npx commitlint --from HEAD~5 # A single message (also how CI bots validate): echo "feat: add search" | npx commitlint
module.exports = {
extends: ["@commitlint/config-conventional"],
rules: {
"type-enum": [2, "always", ["feat", "fix", "docs", "style", "refactor", "perf", "test", "build", "ci", "chore", "revert", "release"]],
"scope-enum": [2, "always", ["api", "cli", "web", "deps"]],
"header-max-length": [2, "always", 72]
}
}Git Hooks
npx husky init # .husky/prepare-commit-msg: npx --no -- commitlint --edit "$1" # Optional: also lint the message before it is finalized npx husky add .husky/commit-msg "npx --no -- commitlint --edit $1"
CI Integration
# GitHub Actions step:
match: \"--from:${{ github.event.pull_request.base.sha }}--"
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- run: npm ci
- run: npx commitlint --from ${{ github.event.pull_request.base.sha }} --to ${{ github.event.pull_request.head.sha }}