By the end of this page you will have Commit Check installed, rejecting a bad commit message on your machine, and wired into the two places it belongs.
It takes about five minutes and needs nothing but a Git repository.
=== "pip"
```console
$ pip install commit-check
```
=== "uv"
```console
$ uv tool install commit-check
```
=== "pipx"
```console
$ pipx install commit-check
```
Verify the install:
$ commit-check --versionThe CLI is also available as cchk, which is the same program under a shorter
name.
!!! tip "Supported Python versions"
Commit Check supports Python 3.10 through 3.14, on Linux, macOS and Windows.
Running it as a pre-commit hook or a GitHub Action needs no installation step at all — both fetch it for you.
Commit Check works with no configuration at all. Make a deliberately bad commit in a scratch repository:
$ git init demo && cd demo
$ git commit --allow-empty -m "updated the parser"Now check it:
$ commit-check --messageCC001 message check failed ==> updated the parser
The commit message should follow Conventional Commits. See https://www.conventionalcommits.org
Suggest: Use <type>(<scope>): <description>, where <type> is one of: feat, fix, docs, ...
Docs: https://commit-check.com/rules/#cc001
Four things are happening in that output, and each is deliberate:
| Part | What it gives you |
|---|---|
CC001 |
A stable rule ID. It will mean the same thing in five years. |
==> updated the parser |
The exact value that failed, not just "invalid message". |
Suggest: |
What to do about it. |
Docs: |
Why the rule exists, and how to configure or disable it. |
$ git commit --amend -m "fix(parser): handle empty input"
$ commit-check --messageNo output and an exit code of 0. Commit Check is quiet when it is happy.
$ git switch -c my-changes
$ commit-check --branchCC201 branch check failed ==> my-changes
The branch should follow Conventional Branch. See https://conventionalbranch.org
Suggest: Use <type>/<description> with allowed types
Docs: https://commit-check.com/rules/#cc201
Rename it to something structured and it passes:
$ git branch -m fix/empty-input
$ commit-check --branch!!! tip "Checks are opt-in per run"
`commit-check --message` never evaluates branch rules, and vice versa. Each
check is selected by its own flag, so you can run exactly what a given hook
or CI job needs. The [rules reference](rules.md) lists which flag activates
each rule.
So far you have been running the defaults. Create a cchk.toml in the
repository root — or in .github/ — to make the policy explicit:
[commit]
conventional_commits = true
subject_imperative = true # (1)!
subject_max_length = 72
allow_wip_commits = false # (2)!
[branch]
conventional_branch = true- Off by default. Turning it on rejects
fixed a bugin favour offix a bug. allow_*options describe what is permitted. Set tofalseto enforce.
Run it again and the new rules apply:
$ commit-check --message!!! warning "Defaults are not "nothing""
Even with no config file, Conventional Commits, Conventional Branch, subject
length limits of 5–80 characters, and author name/email patterns are
enforced. Check the *Default* column in the [rules reference](rules.md)
before assuming a rule is off.
Running the command by hand does not scale. Wire it into the two places it belongs:
-
:material-git:{ .lg .middle } Before the commit lands
A pre-commit hook rejects the message as you write it, so nothing bad reaches the branch in the first place.
-
:material-github:{ .lg .middle } On every pull request
A GitHub Action checks every commit in the PR and can comment on the PR with what needs fixing.
Releases are built with SLSA Level 3 provenance. To verify a release artifact came from this repository's build pipeline:
$ gh attestation verify commit_check-*.whl --repo commit-check/commit-check- Rules reference — every rule, what it does, why it matters, and how to configure it.
- Configuration — every option, its type and default, plus the environment variable and CLI flag that override it.
- Command-line recipes — checking a range, wiring up CI, reading the JSON output.
- Troubleshooting — a check failing that you did not turn on, nothing running at all, and how to get a commit through when you have to.