Validate commit messages against Conventional Commits and custom rules. Pure Python, no dependencies.
bash
# Lint last commit
python3 scripts/lint_commits.py
# Lint last 5 commits
python3 scripts/lint_commits.py --range HEAD~5..HEAD
# Lint a branch
python3 scripts/lint_commits.py --range main..feature-branch
# Lint a single message
python3 scripts/lint_commits.py --message "feat: add login"
# Read from stdin (git commit-msg hook)
python3 scripts/lint_commits.py --stdin < .git/COMMIT_MSG
# Read from file
python3 scripts/lint_commits.py --file .git/COMMIT_MSG
bash
python3 scripts/lint_commits.py --format text # human-readable (default)
python3 scripts/lint_commits.py --format json # CI/tooling
python3 scripts/lint_commits.py --format markdown # reports
Generate default config:
bash
python3 scripts/lint_commits.py init
Creates .commitlintrc.json. Also auto-discovers .commitlintrc or commitlint.config.json.
Key config options:
header_max_length (72) — max header charsrequire_conventional (true) — enforce <type>[scope]: <desc> formattypes — allowed types (feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert)scopes — allowed scopes (empty = any)require_scope (false) — mandate scoperequire_body (false) — mandate bodyheader_case — description start case: lower/upper/sentence/anyno_trailing_period (true) — reject trailing period on headerforbidden_patterns — regex patterns that reject commitsrequired_patterns — regex patterns that must match--strict flag treats warnings as errorsRuleLevelDescriptionheader-emptyerrorEmpty headerheader-max-lengtherrorHeader exceeds max lengthheader-min-lengthwarningHeader below min lengthconventional-formaterrorNot Conventional Commits formattype-enumerrorType not in allowed listscope-requirederrorMissing required scopescope-enumerrorScope not in allowed listdescription-emptyerrorEmpty descriptiondescription-casewarningWrong description caseheader-no-periodwarningTrailing periodheader-leading-whitespaceerrorLeading whitespaceheader-trailing-whitespacewarningTrailing whitespacebody-separatorerrorNo blank line before bodybody-requiredwarningMissing required bodybody-line-lengthwarningBody line too longbody-max-lineswarningToo many body linesbreaking-change-descriptionwarningBreaking ! without BREAKING CHANGE: in bodyforbidden-patternerrorMatches forbidden regexrequired-patternwarningDoesn't match required regex
0 — all commits pass (warnings OK unless --strict)1 — errors found (or warnings with --strict)2 — git/system errorAs commit-msg hook ( .git/hooks/commit-msg):
bash
#!/bin/sh
python3 path/to/lint_commits.py --file "$1" --strict
Auto-ignored: merge commits, reverts, version tags, "Initial commit".