Commit Check (aka cchk) is the most comprehensive open-source tool for enforcing Git commit standards — including commit messages, branch naming, author identity, commit signoff, and more — helping teams maintain consistency and compliance across every repository.
As a lightweight, free alternative to GitHub Enterprise Metadata restrictions and Bitbucket's paid Yet Another Commit Checker plugin, Commit Check integrates DevOps principles and Infrastructure as Code (IaC) practices for a modern workflow.
Why Commit Check?
The table below compares common approaches to commit policy enforcement.
commitlint is a specialized commit-message linter. Custom Git hooks and
the pre-commit framework are integration mechanisms, so the last column
reflects a DIY approach rather than built-in product features.
| Feature | Commit Check ✅ | commitlint | Custom hooks |
|---|---|---|---|
| Conventional Commits enforcement | ✅ | ✅ | DIY |
| Branch naming validation | ✅ | ❌ | DIY |
| Author name / email validation | ✅ | ❌ | DIY |
| Signed-off-by trailer enforcement | ✅ | ✅ | DIY |
| Co-author ignore list | ✅ | ❌ | DIY |
| Organization-level shared config | ✅ | ✅ | DIY |
| Zero-config defaults | ✅ | ❌ | ❌ |
| Works without Node.js | ✅ | ❌ | Depends |
| Native TOML configuration | ✅ | ❌ | Depends |
| Git hook / pre-commit integration | ✅ | Partial | ✅ |
| CI/CD-friendly configuration | ✅ | Partial | DIY |
For commitlint, organization-level shared config is typically delivered via
shareable config packages or local files. DIY means you can implement a
capability with custom Git hooks or pre-commit scripts, but it is not
provided as a turnkey policy layer.
To install Commit Check, you can use pip:
pip install commit-checkOr install directly from the GitHub repository:
pip install git+https://github.com/commit-check/commit-check.git@mainThen, run commit-check --help or cchk --help (alias for commit-check) from the command line.
For more information, see the docs.
1. Install and run with zero configuration:
pip install commit-check
commit-check --message --branch2. Add to your pre-commit hooks (.pre-commit-config.yaml):
repos:
- repo: https://github.com/commit-check/commit-check
rev: v2.5.0
hooks:
- id: check-message
- id: check-branch3. Add a badge to your repository:
[](https://github.com/commit-check/commit-check)
Commit Check can be configured in three ways (in order of priority):
- Command-line arguments — Override settings for specific runs
- Environment variables — Configure via
CCHK_*environment variables - Configuration files — Use
cchk.tomlorcommit-check.toml
- Commit Check uses a default configuration if you do not provide a
cchk.tomlorcommit-check.tomlfile. - The default configuration is lenient — it only checks whether commit messages follow the Conventional Commits specification and branch names follow the Conventional Branch convention.
To customize the behavior, create a configuration file named cchk.toml or commit-check.toml in your repository's root directory or in the .github folder, e.g., cchk.toml or .github/cchk.toml.
[commit]
# https://www.conventionalcommits.org
conventional_commits = true
subject_imperative = true
subject_max_length = 80
allow_commit_types = ["feat", "fix", "docs", "style", "refactor", "test", "chore", "ci"]
allow_merge_commits = true
allow_wip_commits = false
require_signed_off_by = false
# Bypass checks for bot/automation authors and co-authors:
ignore_authors = ["dependabot[bot]", "renovate[bot]", "copilot[bot]"]
[branch]
# https://conventional-branch.github.io/
conventional_branch = true
allow_branch_types = ["feature", "bugfix", "hotfix", "release", "chore", "feat", "fix"]Share a base configuration across all repositories in your organization using inherit_from:
# .github/cchk.toml — inherits from org-level config, then overrides locally
inherit_from = "github:my-org/.github:cchk.toml"
[commit]
subject_max_length = 72 # Local overrideThe inherit_from field accepts:
- A GitHub shorthand (recommended):
inherit_from = "github:owner/repo:path/to/cchk.toml" - A GitHub shorthand with ref:
inherit_from = "github:owner/repo@main:path/to/cchk.toml" - A local file path (relative or absolute):
inherit_from = "../shared/cchk.toml" - An HTTPS URL:
inherit_from = "https://example.com/cchk.toml"
The github: shorthand fetches from raw.githubusercontent.com. HTTP (non-TLS) URLs are rejected for security.
Local settings always override the inherited base configuration.
For one-off checks or CI/CD pipelines, you can configure via CLI arguments or environment variables:
# Using CLI arguments
commit-check --message --subject-imperative=true --subject-max-length=72
# Using environment variables
export CCHK_SUBJECT_IMPERATIVE=true
export CCHK_SUBJECT_MAX_LENGTH=72
commit-check --message
# In pre-commit hooks (.pre-commit-config.yaml)
repos:
- repo: https://github.com/commit-check/commit-check
rev: v2.5.0
hooks:
- id: check-message
args:
- --subject-imperative=false
- --subject-max-length=100See the Configuration documentation for all available options.
For detailed usage instructions including pre-commit hooks, CLI commands, and STDIN examples, see the Usage Examples documentation.
Check Commit Message Failed
Commit rejected by Commit-Check.
(c).-.(c) (c).-.(c) (c).-.(c) (c).-.(c) (c).-.(c)
/ ._. \ / ._. \ / ._. \ / ._. \ / ._. \
__\( C )/__ __\( H )/__ __\( E )/__ __\( C )/__ __\( K )/__
(_.-/'-'\-._)(_.-/'-'\-._)(_.-/'-'\-._)(_.-/'-'\-._)(_.-/'-'\-._)
|| E || || R || || R || || O || || R ||
_.' '-' '._ _.' '-' '._ _.' '-' '._ _.' '-' '._ _.' '-' '._
(.-./`-´\.-.)(.-./`-´\.-.)(.-./`-´\.-.)(.-./`-´\.-.)(.-./`-´\.-.)
`-´ `-´ `-´ `-´ `-´ `-´ `-´ `-´ `-´ `-´
Commit rejected.
Type message check failed ==> test commit message check
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, style, refactor, test, chore, ci
Check Branch Naming Failed
Commit rejected by Commit-Check.
(c).-.(c) (c).-.(c) (c).-.(c) (c).-.(c) (c).-.(c)
/ ._. \ / ._. \ / ._. \ / ._. \ / ._. \
__\( C )/__ __\( H )/__ __\( E )/__ __\( C )/__ __\( K )/__
(_.-/'-'\-._)(_.-/'-'\-._)(_.-/'-'\-._)(_.-/'-'\-._)(_.-/'-'\-._)
|| E || || R || || R || || O || || R ||
_.' '-' '._ _.' '-' '._ _.' '-' '._ _.' '-' '._ _.' '-' '._
(.-./`-´\.-.)(.-./`-´\.-.)(.-./`-´\.-.)(.-./`-´\.-.)(.-./`-´\.-.)
`-´ `-´ `-´ `-´ `-´ `-´ `-´ `-´ `-´ `-´
Commit rejected.
Type branch check failed ==> test-branch
The branch should follow Conventional Branch. See https://conventional-branch.github.io/
Suggest: Use <type>/<description> with allowed types or add branch name to allow_branch_names in config, or use ignore_authors in config branch section to bypass
More examples see example documentation.
You can add a badge to your repository to show that you use commit-check!
Markdown
[](https://github.com/commit-check/commit-check)
reStructuredText
.. image:: https://img.shields.io/badge/commit--check-enabled-brightgreen?logo=Git&logoColor=white&color=%232c9ccd
:target: https://github.com/commit-check/commit-check
:alt: commit-check
Versioning follows Semantic Versioning.
Please post to issues for feedback, feature requests, or bug reports.
This project is released under the MIT License
