Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions docs/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ below and to the page that documents the feature properly.

| Version | What changed | Documented in |
|---|---|---|
| [2.18.3](#v2183) | `--fix` corrects a message in place; `--branch` reads GitLab, Bitbucket, Azure and Jenkins variables | [Fixing a message in place](example.md#fixing-a-message-in-place) · [Other CI](guides/other-ci.md) |
| [2.18.0](#v2180) | AI disclosure policy: three rules, and the correction written for you | [Policy guides](guides/policies.md#asking-for-disclosure-instead) · [CC014](rules.md#cc014) |
| [2.17.0](#v2170) | Concrete corrections for mechanical slips; a `warn` level per rule | [Reading the JSON](example.md#reading-the-json) · [Report without enforcing](configuration.md#report-a-rule-without-enforcing-it) |
| [2.16.0](#v2160) | Tag name validation, and file size, path and pattern policies | [CC401](rules.md#cc401) · [CC302–CC304](rules.md#push-rules) |
Expand All @@ -29,6 +30,40 @@ below and to the page that documents the feature properly.
| [2.5.0](#v250) | Organization-wide config with `inherit_from` | [Across an organization](guides/organization.md) |
| [2.0.0](#v200) | Configuration moved from YAML to TOML — breaking | [Migrating from v1](migration.md) |

## v2.18.3 (2026-10-07) { #v2183 }

### Added

* **`--fix` corrects a commit message in place** — when every message check
the commit failed has a mechanical fix, the ones `--format json` reports in
`fix`, the message file is rewritten and the check passes, so
`Fix: add streaming support` is recorded as `fix: add streaming support`.
Anything that takes a judgment, such as a subject with no type at all,
leaves the file as it was and is rejected as before. It needs a message
file, so stdin and `--rev` are a usage error, and `--dry-run` rewrites
nothing. With pre-commit it is `args: [--fix]` on `check-message`.
See PR [#594](https://github.com/commit-check/commit-check/pull/594) and
[Fixing a message in place](example.md#fixing-a-message-in-place).

* **`--branch` reads the branch from GitLab, Bitbucket, Azure and Jenkins** —
on a detached checkout git names no branch, and only GitHub's variables
were read, so elsewhere the name became `HEAD`, which is always allowed, and
every branch passed. Each CI's own variables are now read, a merge or pull
request's source branch first, and Jenkins' only inside a Jenkins build that
is not a tag build. A pipeline that runs `--branch` on a long-lived branch
such as `develop` now has that name judged; `allow_branch_names` can allow
it.
See PR [#600](https://github.com/commit-check/commit-check/pull/600) and
[GitLab CI, Bitbucket and Azure Pipelines](guides/other-ci.md).

* **A setting nothing reads is named** — a misspelt key in `cchk.toml` was
ignored in silence, and its rule stayed at the default. Each one is now
reported on stderr with the closest real name, as in `⚠ unknown setting
[commit] subject_max_lenght is ignored; did you mean subject_max_length?`.
The exit code and the JSON do not change.
See PR [#593](https://github.com/commit-check/commit-check/pull/593) and
[Settings nothing reads](configuration.md#settings-nothing-reads).

## v2.18.2 (2026-09-28) { #v2182 }

### Fixed
Expand Down
24 changes: 23 additions & 1 deletion docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,28 @@ $ commit-check --config path/to/cchk.toml --message
PyCharm and IntelliJ offer completion, validation and inline documentation
for `cchk.toml` with nothing to configure.

### Settings nothing reads

A key that no check reads, usually a misspelling, leaves its rule at the
default. Commit Check names each one on stderr, with the closest real name:

```toml title="cchk.toml"
[commit]
subject_max_lenght = 50
```

```console
$ echo "feat: add streaming support" | commit-check -m
⚠ unknown setting [commit] subject_max_lenght is ignored; did you mean subject_max_length?
```

It is a warning, not an error: the exit code and the JSON on stdout do not
change. The top-level `warn` list and the GitHub App's
[`[jira]`](guides/github-app.md#jira-ticket-references) and
[`[pull_request]`](#pull-requests-every-commit-or-the-squash-message) sections
are read elsewhere and are not reported. The Python API and the MCP server
load the file themselves and do not report it either.

## Inheriting a shared config

An organization can keep one base policy and have every repository build on it.
Expand Down Expand Up @@ -239,7 +261,7 @@ Used from a hook definition, with no config file anywhere in the repository:
```yaml title=".pre-commit-config.yaml"
repos:
- repo: https://github.com/commit-check/commit-check
rev: v2.18.2
rev: v2.18.3
hooks:
- id: check-message
args:
Expand Down
33 changes: 31 additions & 2 deletions docs/example.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,27 @@ EOF
$ commit-check -m /tmp/msg.txt
```

### Fixing a message in place

`--fix` corrects the message instead of only rejecting it. When every check
the message failed has a mechanical fix, the corrections that
[`--format json` reports in `fix`](#reading-the-json), it rewrites the message
file and the check passes:

```console
$ printf 'Fix: add streaming support\n' > msg.txt
$ commit-check -m --fix msg.txt
✎ fixed the commit message: CC001 message
$ cat msg.txt
fix: add streaming support
```

A failure that takes a judgment, such as `updated the parser`, which has no
type at all, leaves the file as it was and fails as before. `--fix` needs a
message file to rewrite, so with stdin or `--rev` it is a usage error, and
`--dry-run` rewrites nothing. In the `commit-msg` hook it is one argument:
see [Fixing the message instead of rejecting it](guides/pre-commit.md#fixing-the-message-instead-of-rejecting-it).

## Checking the branch

```console
Expand All @@ -97,6 +118,13 @@ feature/role-caching
release/v1.2.0
```

On a detached HEAD, which is how most CI systems check out a commit, git has
no branch to report, so the name comes from the CI's own variables: GitHub
Actions, GitLab CI, Bitbucket Pipelines, Azure Pipelines, and Jenkins
multibranch inside a Jenkins build. A merge or pull request's source branch is
read first. With none of these set, the name is `HEAD`. The variables other
than GitHub's are read from 2.18.3 on.

## Checking the committer

```console
Expand Down Expand Up @@ -131,7 +159,7 @@ pushed:
```yaml title=".pre-commit-config.yaml"
repos:
- repo: https://github.com/commit-check/commit-check
rev: v2.18.2
rev: v2.18.3
hooks:
- id: check-no-force-push
stages: [pre-push]
Expand Down Expand Up @@ -302,7 +330,8 @@ $ echo "Fix: add streaming support" | commit-check -m --format json | jq '.check
`fix` is empty whenever the correction takes a judgment — a subject with no
type at all, one over the length limit, a verb that is not imperative — and
`suggest` then keeps the rule's general advice. A tool can apply a non-empty
`fix` as it stands; a person only ever needs `suggest`.
`fix` as it stands, and [`--fix`](#fixing-a-message-in-place) does that to a
message file; a person only ever needs `suggest`.

A rule listed under [`warn`](configuration.md#report-a-rule-without-enforcing-it)
reports with `"status": "warn"` instead of `"fail"`. The top-level `status` is
Expand Down
2 changes: 1 addition & 1 deletion docs/guides/github-app.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ way everywhere:

### Which rules

The App runs the commit message, author and branch rules — [CC001–CC013](../rules.md#commit-message-rules),
The App runs the commit message, author and branch rules — [CC001–CC016](../rules.md#commit-message-rules),
[CC101–CC102](../rules.md#author-rules) and [CC201–CC202](../rules.md#branch-rules) —
with the commit's own branch as the branch under test. One thing it does not
do: the push, file and tag rules ([CC301–CC304](../rules.md#push-rules),
Expand Down
34 changes: 23 additions & 11 deletions docs/guides/other-ci.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,10 @@ hook and the Action.
Two things are different from running it on your own machine, and each
example below handles both:

- **The checkout is a detached HEAD.** git has no branch to report, so
`commit-check --branch` would judge `HEAD`, which is always allowed, and
pass whatever the branch is called. Pipe the branch name in from the CI's
own variable instead: a value piped into `--branch` on its own is the name
it checks.
- **The checkout can be a detached HEAD**, as it is on GitLab and Azure, and
then git has no branch to report. `commit-check --branch` reads the name
from the CI's own variables instead, the merge or pull request's source
branch first, so the jobs call it as is.
- **A merge request has more than one commit.** `--rev` checks one commit, so
the job loops over the commits the merge request adds, as in
[Checking a range of commits](../example.md#checking-a-range-of-commits).
Expand All @@ -25,6 +24,19 @@ Each job runs on merge or pull requests only, because the variables it reads
exist only there. Add `--author-name --author-email` to the `commit-check`
call in the loop to check each commit's author as well.

!!! note "On 2.18.2 or older"

Releases before 2.18.3 read only GitHub's variables, so on a detached
checkout `--branch` judges `HEAD`, which is always allowed, and passes
whatever the branch is called. Pipe the name in instead: a value piped
into `--branch` on its own is the name it checks.

```console
$ echo "$CI_MERGE_REQUEST_SOURCE_BRANCH_NAME" | commit-check --branch # GitLab
$ echo "$BITBUCKET_BRANCH" | commit-check --branch # Bitbucket
$ echo "${SYSTEM_PULLREQUEST_SOURCEBRANCH#refs/heads/}" | commit-check --branch # Azure
```

## GitLab CI

```yaml title=".gitlab-ci.yml"
Expand All @@ -36,7 +48,7 @@ commit-check:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
script:
- pip install commit-check
- echo "$CI_MERGE_REQUEST_SOURCE_BRANCH_NAME" | commit-check --branch
- commit-check --branch
- |
head="${CI_MERGE_REQUEST_SOURCE_BRANCH_SHA:-$CI_COMMIT_SHA}"
shas=$(git rev-list "$CI_MERGE_REQUEST_DIFF_BASE_SHA..$head") || exit 1
Expand Down Expand Up @@ -69,7 +81,7 @@ pipelines:
depth: full
script:
- pip install commit-check
- echo "$BITBUCKET_BRANCH" | commit-check --branch
- commit-check --branch
- |
shas=$(git rev-list "$BITBUCKET_PR_DESTINATION_COMMIT..$BITBUCKET_COMMIT") || exit 1
status=0
Expand Down Expand Up @@ -104,7 +116,7 @@ steps:
versionSpec: "3.13"
- script: pip install commit-check
displayName: Install Commit Check
- script: echo "${SYSTEM_PULLREQUEST_SOURCEBRANCH#refs/heads/}" | commit-check --branch
- script: commit-check --branch
displayName: Check the branch name
- script: |
shas=$(git rev-list HEAD^1..HEAD^2) || exit 1
Expand All @@ -123,9 +135,9 @@ steps:
- A pull request build checks out a merge commit whose first parent is the
target branch and second the pull request, so `HEAD^1..HEAD^2` is exactly
the commits the pull request adds.
- `System.PullRequest.SourceBranch` is `refs/heads/feature/x` in Azure Repos
and `feature/x` for a GitHub repository; `#refs/heads/` strips the prefix
where there is one.
- The branch name comes from `System.PullRequest.SourceBranch`, which is
`refs/heads/feature/x` in Azure Repos and `feature/x` for a GitHub
repository. Commit Check drops the `refs/heads/` prefix itself.
- In Azure Repos the `pr:` section is ignored. Pull request builds come from a
[build validation branch policy](https://learn.microsoft.com/en-us/azure/devops/repos/git/branch-policies#set-build-validation)
on the target branch, and `System.PullRequest.SourceBranch` is only set for
Expand Down
34 changes: 30 additions & 4 deletions docs/guides/pre-commit.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Add Commit Check to `.pre-commit-config.yaml`:
```yaml title=".pre-commit-config.yaml"
repos:
- repo: https://github.com/commit-check/commit-check
rev: v2.18.2
rev: v2.18.3
hooks:
- id: check-message
- id: check-branch
Expand Down Expand Up @@ -36,26 +36,32 @@ That is it. The next malformed commit message is rejected before it exists.

| Hook ID | Stage | Rules |
|---|---|---|
| `check-message` | `commit-msg` | [CC001–CC013](../rules.md#commit-message-rules) |
| `check-message` | `commit-msg` | [CC001–CC016](../rules.md#commit-message-rules) |
| `check-branch` | `pre-commit` | [CC201–CC202](../rules.md#branch-rules) |
| `check-author-name` | `pre-commit` | [CC101](../rules.md#cc101) |
| `check-author-email` | `pre-commit` | [CC102](../rules.md#cc102) |
| `check-no-force-push` | `pre-push` | [CC301](../rules.md#cc301) |
| `check-files` | `pre-push` | [CC302–CC304](../rules.md#push-rules) |
| `check-tag` | `pre-push` | [CC401](../rules.md#cc401) |

`check-no-force-push` also needs its own install:
The three `pre-push` hooks need their own install too:

```console
$ pre-commit install --hook-type pre-push
```

pre-commit runs no hook for a push that creates a ref without carrying new
commits. So a new tag pushed on its own, when the commit it points at is
already on the remote, is never seen by `check-tag`.

## Configuring without a TOML file

Options can be passed as hook arguments, which keeps everything in one file:

```yaml title=".pre-commit-config.yaml"
repos:
- repo: https://github.com/commit-check/commit-check
rev: v2.18.2
rev: v2.18.3
hooks:
- id: check-message
args:
Expand All @@ -68,6 +74,26 @@ A `cchk.toml` is usually the better choice once you have more than a couple of
options, because CI and the CLI read it too. See
[Configuration](../configuration.md) for the precedence rules.

## Fixing the message instead of rejecting it

Give `check-message` the `--fix` argument and it corrects a message whose
every failure has a mechanical fix, such as a type written `Fix` or a missing
colon, and lets the commit through:

```yaml title=".pre-commit-config.yaml"
repos:
- repo: https://github.com/commit-check/commit-check
rev: v2.18.3
hooks:
- id: check-message
args: [--fix]
```

With that, `git commit -m "Fix: add streaming support"` records
`fix: add streaming support`. A message that needs a judgment, such as one
with no type at all, is rejected as before. More in
[Fixing a message in place](../example.md#fixing-a-message-in-place).

## Skipping a hook

Occasionally you need to get a commit through — a mid-rebase fixup, an
Expand Down