Validate commit messages using Conventional Commits format
2.4K
Validate commit messages locally, in CI, or from stdin using Conventional Commits rules.
ccval helps you:
Once ccval is installed, validate the last commit in the current repository:
ccval
Validate all commits on your branch:
ccval -- origin/main..HEAD
Use the built-in strict preset:
ccval -p strict
Validate a commit message from stdin:
printf 'feat: add validation\n' | ccval --stdin
Choose the option that fits your workflow.
cargo install ccval
brew install andrey-fomin/tap/ccval
Download prebuilt binaries for Linux, macOS, and Windows from GitHub Releases.
Run ccval without installing it locally:
printf 'feat: add validation\n' | docker run --rm -i andreyfomin/ccval:distroless --stdin
Available image tags (moving convenience tags):
andreyfomin/ccval:latest - Alpine-based, includes Git support, about 11 MB
andreyfomin/ccval:distroless - minimal image, no Git support, about 1 MB
Use :distroless when you only need stdin or file validation
Use :latest when you need to validate commits from a Git repository
The release workflow also publishes versioned tags, including :1, :1.2, :1.2.3, and matching -distroless variants such as :1.2.3-distroless.
For Git-based validation in a mounted repository, use --trust-repo only when you control the repository and Git fails with a detected dubious ownership warning:
docker run --rm -v "$(pwd)":/repo -w /repo andreyfomin/ccval --trust-repo
If macOS blocks a downloaded binary, remove the quarantine attribute:
xattr -d com.apple.quarantine /path/to/ccval
You can also right-click the binary, choose Open, and confirm the prompt.
ccval
ccval -- origin/main..HEAD
ccval -r /path/to/repo -- HEAD~10..HEAD
--repository changes where Git reads commits from. Config auto-discovery still happens in the current working directory, so use --config too when the target repository has its own config file:
ccval -r /path/to/repo -c /path/to/repo/conventional-commits.yaml -- HEAD~10..HEAD
ccval --file .git/COMMIT_EDITMSG
ccval -T
Or with an explicit repository path:
ccval -r /repo -T -- HEAD~5..HEAD
Use a commit-msg hook to validate each commit message before Git creates the commit.
Create .git/hooks/commit-msg with this content:
#!/bin/sh
set -eu
exec ccval --file "$1"
Then make it executable:
chmod +x .git/hooks/commit-msg
This hook expects ccval to be installed and available on your PATH.
By default, if no config file is found and no preset is specified, ccval only checks whether the commit message is parseable as a Conventional Commit.
When a config file is present or a preset is provided, ccval also applies the validation rules defined there so you can enforce team-specific rules.
To enforce team-specific rules, add a config file such as conventional-commits.yaml.
Minimal example:
preset: strict
type:
values:
- feat
- fix
- docs
scope:
required: true
The same idea in TOML:
preset = "strict"
[type]
values = ["feat", "fix", "docs"]
[scope]
required = true
With this config:
strict enables useful default formatting rulesfeat, fix, and docs are allowedfeat(api): add endpointWhen --config is not provided, ccval looks for these files in order:
conventional-commits.yamlconventional-commits.ymlconventional-commits.tomlconventional-commits.jsonUse a custom config path when needed:
ccval -c .github/conventional-commits.yaml -- origin/main..HEAD
ccval includes two built-in presets:
default - formatting rules for description spacing and newline handling in body and footer valuesstrict - default plus header length limits and common type and scope restrictionsWhen a config file and preset are both used:
-p/--preset takes precedence over preset: in the config fileregexes: [] clears preset regex rules for that fieldUse a preset from the command line without changing your config file:
ccval -p strict
Use ccval in GitHub Actions to validate pull request commit ranges or pushed commits.
on: pull_request
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- uses: andrey-fomin/ccval@v0
Common options:
Use a custom config:
- uses: andrey-fomin/ccval@v0
with:
config: .github/conventional-commits.yaml
Use a built-in preset:
- uses: andrey-fomin/ccval@v0
with:
preset: strict
Override git arguments:
- uses: andrey-fomin/ccval@v0
with:
git-args: origin/main..HEAD --no-merges
Note: git-args is parsed as a whitespace-separated list of arguments by the action; shell-style quoting/escaping is not supported, and arguments that contain spaces cannot be passed as a single argument. Auto-detected behavior such as adding --no-merges applies only when git-args is not set.
Limit checked commits:
- uses: andrey-fomin/ccval@v0
with:
max-commits: "250"
The action supports push and pull_request events, discovers conventional-commits.yaml or .github/conventional-commits.yaml, skips merge commits in its auto-detected ranges, skips deleted-ref and zero-commit pushes, and limits validation to 100 commits by default.
For push events, it prefers the exact pushed range from local history. If the pushed before commit is not available locally, it falls back to the default-branch merge-base when possible and otherwise fails with a clear error.
If either the push event itself or the selected commit range exceeds max-commits, the action skips validation, emits a warning, and exits successfully.
Make sure your workflow fetches enough history, for example with fetch-depth: 0, so the required commit range is available.
Use @v0 to track the latest compatible v0.x.y release, or pin a specific release tag such as @v0.3.1. For a fully immutable reference, pin a commit SHA.
ccval checks commit messages in two steps:
A message can be parseable and still fail validation.
For example, feat: add api may parse successfully but fail stricter formatting rules.
Read more:
PARSING.md for commit message structure and parse errorsVALIDATION.md for available fields, rules, and configuration examplesUsage: ccval [-c <path>] [-p <preset>] [-r <path>] [-T] [-- <git-log-args>...]
ccval [-c <path>] [-p <preset>] --stdin
ccval [-c <path>] [-p <preset>] -f <path>
ccval -h
Validates commit messages from stdin, a file, or Git.
Modes:
(default) Validate commit(s) from git log
Use -- <git-log-args>... to pass arguments to git log
Default: -1 (last commit)
--stdin Read commit message from stdin
-f, --file <path> Read commit message from a file
-h, --help Show this help message
Options:
-c, --config <path> Use a custom config file path
-p, --preset <name> Use a built-in preset (default or strict)
-r, --repository <path>
Path to Git repository working tree
Cannot be used with --stdin or --file
-T, --trust-repo Trust the repository despite ownership mismatch
Useful when running in containers or accessing
repositories owned by other users
Requires git mode (cannot use with --stdin or --file)
Examples:
ccval # validate last commit
ccval -- origin/main..HEAD # validate commits on branch
ccval -p strict # validate last commit with strict preset
ccval -r /path/to/repo # validate last commit in specific repo
ccval -T # validate last commit, trusting repo
ccval -r /repo -T # validate in container
printf 'feat: msg\n' | ccval --stdin
ccval --file .git/COMMIT_EDITMSG
ccval -c config.yaml --stdin
0 success64 usage error65 content invalid66 input unavailable70 internal error74 I/O error77 permission error78 config errorPARSING.md explains the supported commit message structureVALIDATION.md lists fields, rule types, presets, and examplesCHANGELOG.md tracks release historyRELEASING.md documents the release processContent type
Image
Digest
sha256:d691fe78d…
Size
10.2 MB
Last updated
6 months ago
docker pull andreyfomin/ccval