Git history is documentation, and inconsistent commit messages make it useless - "fix stuff," "wip," "更新," and "asdf" tell future-you nothing. commitlint enforces a convention. It checks each commit message against a ruleset (commonly Conventional Commits, like feat:, fix:, docs:) and rejects messages that don't conform, so your history stays structured, scannable, and - because the format is machine-readable - able to drive automated changelogs and version bumps.
A Convention, Enforced at Commit
Wired into a commit-msg hook, it validates the message as you commit:
# A message it accepts:
feat(bulk-add): auto-schedule posts one per day
# A message it rejects:
fixed the thing
# (no type, doesn't follow the convention)
Structured History, Automatable Releases
Because Conventional Commits encode intent - a feature, a fix, a breaking change - tools can read your history to generate a changelog and pick the next version number automatically. commitlint is the gate that keeps the history clean enough for that to work, and it pairs with the hook managers that run it.
Rough Edges and Limitations
- Discipline, with a learning curve. The team has to learn the format; the hook helps but the habit takes time.
- Node dependency. It's a JavaScript tool, an extra requirement for non-JS projects.
- Convention, not quality. It checks the message format, not whether the commit is good.
For any project where you want a history you can actually read - and maybe generate releases from - commitlint keeps everyone honest at the commit boundary.
Internal link suggestion: link "pairs with the hook managers" to the lefthook or pre-commit post that runs it.