Conventional Commits Validator
Validate commit messages locally, in CI, or from stdin using Conventional Commits rules.
ccval helps you:
- catch invalid commit messages before merge or release
- enforce team rules for types, scopes, headers, and footers
- validate one commit, a branch range, or a message from stdin or a file
Quickstart
Once ccval is installed, validate the last commit in the current repository:
Validate all commits on your branch:
Use the built-in strict preset:
Validate a commit message from stdin:
|
Install
Choose the option that fits your workflow.
crates.io
Homebrew
GitHub Releases
Download prebuilt binaries for Linux, macOS, and Windows from GitHub Releases.
Docker
Run ccval without installing it locally:
|
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
:distrolesswhen you only need stdin or file validation -
Use
:latestwhen 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:
macOS note
If macOS blocks a downloaded binary, remove the quarantine attribute:
You can also right-click the binary, choose Open, and confirm the prompt.
Common Tasks
Validate the latest commit
Validate a commit range
Validate commits in another repository
--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:
Validate a message file
Validate in a container or ownership-mismatch environment
Or with an explicit repository path:
Git Hook
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
Then make it executable:
This hook expects ccval to be installed and available on your PATH.
Configuration in 30 Seconds
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:
= "strict"
[]
= ["feat", "fix", "docs"]
[]
= true
With this config:
strictenables useful default formatting rules- only
feat,fix, anddocsare allowed - every commit must include a scope such as
feat(api): add endpoint
When --config is not provided, ccval looks for these files in order:
conventional-commits.yamlconventional-commits.ymlconventional-commits.tomlconventional-commits.json
Use a custom config path when needed:
Presets
ccval includes two built-in presets:
default- formatting rules for description spacing and newline handling in body and footer valuesstrict-defaultplus header length limits and common type and scope restrictions
When a config file and preset are both used:
-p/--presettakes precedence overpreset:in the config file- rules omitted in your config inherit from the preset
regexes: []clears preset regex rules for that field
Use a preset from the command line without changing your config file:
GitHub Action
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.
Parsing vs Validation
ccval checks commit messages in two steps:
- Parse the message structure
- Apply validation rules from your config
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.mdfor commit message structure and parse errorsVALIDATION.mdfor available fields, rules, and configuration examples
Command Reference
Usage: 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
Exit Codes
0success64usage error65content invalid66input unavailable70internal error74I/O error77permission error78config error
Reference
PARSING.mdexplains the supported commit message structureVALIDATION.mdlists fields, rule types, presets, and examplesCHANGELOG.mdtracks release historyRELEASING.mddocuments the release process