Skip to content

Commit 90bf806

Browse files
authored
docs: document --rev and the skip notice, and date v2.14.0 (#15)
Documentation for the engine changes merged in commit-check/commit-check#544, ahead of the v2.15.0 release, plus the release date for v2.14.0. ## Command-line recipes ([example.md](https://github.com/commit-check/commit-check.com/blob/docs/rev-and-skip-notice/docs/example.md)) - **A "From a revision" tab** under message checking: `--rev` takes anything `git rev-parse` understands, errors up front on a revision that does not resolve, and refuses to be combined with a message file or stdin. - **The author-check section now says whose identity is judged**: without `--rev` it is the local git config (right for a hook, wrong for CI); with `--rev` it is that commit's recorded author, and the config is never consulted. - **The range-checking recipe drops the stdin pipe** for `--rev`, which also lets it include the author checks meaningfully, and shows `git rev-list HEAD^1..HEAD^2` for covering exactly a PR's commits. - **A new "When a check is skipped" section**: which rules decline merge subjects and why only git's literal `Merge `/`fixup! ` prefixes qualify, the one-line stderr notice, the JSON `"status": "skip"`, and a warning box about the synthetic-merge-commit trap on `pull_request` checkouts. Both console examples are pasted from real runs of the current engine, not written by hand. ## Changelog - New v2.15.0 (unreleased) entry: `--rev`, the stdin-hang fix, skip visibility, and the tightened merge/fixup bypass. - v2.14.0 stamped with its release date (published 2026-08-12). - Highlights table row for 2.15.0. `mkdocs build -s` passes (social cards disabled locally — the build environment cannot reach fonts.google.com; nothing in this diff touches that path).
1 parent 9a3f758 commit 90bf806

5 files changed

Lines changed: 117 additions & 10 deletions

File tree

docs/changelog.md

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ below and to the page that documents the feature properly.
1111

1212
| Version | What changed | Documented in |
1313
|---|---|---|
14+
| [2.15.0](#v2150) | `--rev` names the commit under test; skipped checks are named on stderr | [Command-line recipes](example.md#checking-a-range-of-commits) |
1415
| [2.14.0](#v2140) | CC003 judges imperative mood by a word's form, not by a list of verbs | [CC003](rules.md#cc003) |
1516
| [2.13.1](#v2131) | JSON output reports the checked value for passing checks | [Output for scripts and CI](example.md#output-for-scripts-and-ci) |
1617
| [2.13.0](#v2130) | Stable rule IDs in terminal output and JSON | [Rules reference](rules.md) |
@@ -24,7 +25,49 @@ below and to the page that documents the feature properly.
2425
| [2.5.0](#v250) | Organization-wide config with `inherit_from` | [Integrations](guides/integrations.md#across-an-organization) |
2526
| [2.0.0](#v200) | Configuration moved from YAML to TOML — breaking | [Migrating from v1](migration.md) |
2627

27-
## v2.14.0 (unreleased) { #v2140 }
28+
## v2.15.0 (unreleased) { #v2150 }
29+
30+
### Added
31+
32+
* **`--rev REVISION` names the commit under test** — anything `git rev-parse`
33+
understands: a SHA, `HEAD~2`, `HEAD^2`. Message checks read that commit's
34+
message, and the author checks read **that commit's recorded author, never
35+
the local git config** — an existing commit's identity is a fact about the
36+
commit, not about whoever runs the check. Before `--rev`, CI could not
37+
iterate a pull request's commits without checking each one out, and a
38+
malformed author on any commit passed as long as the operator's own config
39+
was valid. A revision that does not resolve is a one-line error before any
40+
check runs; combining `--rev` with a message file or stdin is rejected,
41+
since each would name a second subject for the same checks. See
42+
[Checking a range of commits](example.md#checking-a-range-of-commits).
43+
44+
### Fixed
45+
46+
* **The CLI no longer hangs on an open, idle stdin** — stdin was read
47+
whenever it was not a terminal, for every check type. Under CI runners and
48+
process managers that hand the process a pipe nothing ever writes to or
49+
closes, `commit-check --author-name` blocked forever: a stuck step, not a
50+
failed one. The read is now gated on data actually being available, and
51+
genuinely piped input still works unchanged.
52+
53+
### Changed
54+
55+
* **Skipped checks are named on stderr instead of passing in silence** — a
56+
check that had nothing to judge (a merge subject under the subject rules,
57+
an absent message) reports a skip, and text mode prints one line naming
58+
every skipped check: `⊘ skipped (not validated): subject-max-length,
59+
subject-min-length`. Exit codes are unchanged and stdout is untouched. The
60+
case that motivated it: on a `pull_request` checkout `HEAD` is the
61+
synthetic merge commit, so a bare `commit-check -m` used to exit `0`
62+
having validated nothing it was asked about. See
63+
[When a check is skipped](example.md#when-a-check-is-skipped).
64+
65+
* **Only git's literal merge and fixup prefixes bypass the subject rules**
66+
the bypass matched any subject starting with the word "merge" in any case,
67+
so an author's own `merge the parser tables` escaped judgement. Now only
68+
the machine-written forms qualify: `Merge ` (and `fixup! ` for CC003).
69+
70+
## v2.14.0 (2026-08-12) { #v2140 }
2871

2972
### Changed
3073

docs/configuration.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ Used from a hook definition, with no config file anywhere in the repository:
167167
```yaml title=".pre-commit-config.yaml"
168168
repos:
169169
- repo: https://github.com/commit-check/commit-check
170-
rev: v2.13.4
170+
rev: v2.14.0
171171
hooks:
172172
- id: check-message
173173
args:

docs/example.md

Lines changed: 69 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ in [Configuration](configuration.md).
99

1010
## Checking a commit message
1111

12-
The message can come from the repository, a file, or standard input.
12+
The message can come from the repository, a file, standard input, or a named
13+
revision.
1314

1415
=== "From the repository"
1516

@@ -33,6 +34,21 @@ The message can come from the repository, a file, or standard input.
3334
$ echo "feat(auth): add OAuth2 login" | commit-check -m
3435
```
3536

37+
=== "From a revision"
38+
39+
`--rev` names the commit under test — anything `git rev-parse`
40+
understands. A revision that does not resolve is a one-line error before
41+
any check runs.
42+
43+
```console
44+
$ commit-check -m --rev HEAD~1
45+
$ commit-check -m --rev 1a2b3c4
46+
```
47+
48+
A revision and a message file would name two different subjects for the
49+
same checks, so passing both is rejected; stdin is likewise not consulted
50+
while `--rev` is set.
51+
3652
### Trying a message before you write it
3753

3854
```console
@@ -91,6 +107,17 @@ Either flag works alone. [CC101](rules.md#cc101) and
91107
[CC102](rules.md#cc102) describe what the built-in patterns accept and how to
92108
tighten them.
93109

110+
Without `--rev`, these validate the *local git config* — whoever is about to
111+
commit — falling back to `HEAD`'s author only when no identity is configured.
112+
That is the right subject for a hook and the wrong one for CI: an existing
113+
commit's identity is a fact about the commit, not about the operator running
114+
the check. Add `--rev` and both checks read that commit's recorded author, and
115+
the config is never consulted:
116+
117+
```console
118+
$ commit-check --author-name --author-email --rev HEAD
119+
```
120+
94121
## Blocking force pushes
95122

96123
```console
@@ -104,7 +131,7 @@ pushed:
104131
```yaml title=".pre-commit-config.yaml"
105132
repos:
106133
- repo: https://github.com/commit-check/commit-check
107-
rev: v2.13.4
134+
rev: v2.14.0
108135
hooks:
109136
- id: check-no-force-push
110137
stages: [pre-push]
@@ -165,11 +192,13 @@ and how CLI, environment and file settings override each other.
165192

166193
### Checking a range of commits
167194

168-
Nothing built in, but the exit code makes it a one-liner:
195+
`--rev` makes each commit addressable without checking it out or piping its
196+
message, and it is the only way the author checks apply to the commit rather
197+
than to the local config:
169198

170199
```bash title="check-recent.sh"
171200
#!/usr/bin/env bash
172-
# Check the last N commit messages; exits non-zero if any fail.
201+
# Check the last N commits; exits non-zero if any fail.
173202
174203
# Resolved before the loop rather than inside it: an unreadable range or a
175204
# directory that is not a repository would otherwise expand to nothing, and
@@ -178,14 +207,49 @@ shas=$(git rev-list -n "${1:-10}" HEAD) || exit 1
178207
179208
status=0
180209
for sha in $shas; do
181-
if ! git log -1 --format=%B "$sha" | commit-check -m --compact; then
210+
if ! commit-check -m --author-name --author-email --rev "$sha" --compact; then
182211
echo " ↑ $sha"
183212
status=1
184213
fi
185214
done
186215
exit $status
187216
```
188217

218+
On a `pull_request` checkout the same loop covers exactly the commits the PR
219+
adds — `HEAD` is GitHub's synthetic merge commit, whose first parent is the
220+
base branch and second the PR branch:
221+
222+
```console
223+
$ git rev-list HEAD^1..HEAD^2
224+
```
225+
226+
### When a check is skipped
227+
228+
A check that had nothing to judge reports a **skip**, not a pass. The common
229+
case is a merge subject: `Merge branch 'x'` is git's writing, so
230+
[CC002](rules.md#cc002), [CC003](rules.md#cc003), [CC004](rules.md#cc004) and
231+
[CC005](rules.md#cc005) decline it rather than grade prose the author never
232+
wrote. Only git's literal `Merge ` prefix qualifies (plus `fixup! ` for
233+
CC003); a subject that merely starts with the lowercase word is judged like
234+
any other.
235+
236+
Text mode names every skipped check in one line on stderr, leaving stdout and
237+
the exit code untouched — a skip is still not a failure:
238+
239+
```console
240+
$ echo "Merge branch 'main' into topic" | commit-check -m --no-banner
241+
⊘ skipped (not validated): subject-max-length, subject-min-length
242+
```
243+
244+
In JSON each skipped check carries `"status": "skip"`, distinct from `"pass"`.
245+
246+
!!! warning "A green run can still have validated nothing"
247+
248+
On a `pull_request` checkout, `HEAD` is the synthetic merge commit — so a
249+
bare `commit-check -m` exits `0` with every subject rule skipped. The
250+
notice makes that visible; the fix is to check what you actually mean:
251+
the PR title piped on stdin, or each branch commit via `--rev` as above.
252+
189253
### Reading the JSON
190254

191255
```console

docs/guides/integrations.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ Add Commit Check to `.pre-commit-config.yaml`:
2323
```yaml title=".pre-commit-config.yaml"
2424
repos:
2525
- repo: https://github.com/commit-check/commit-check
26-
rev: v2.13.4
26+
rev: v2.14.0
2727
hooks:
2828
- id: check-message
2929
- id: check-branch
@@ -70,7 +70,7 @@ Options can be passed as hook arguments, which keeps everything in one file:
7070
```yaml title=".pre-commit-config.yaml"
7171
repos:
7272
- repo: https://github.com/commit-check/commit-check
73-
rev: v2.13.4
73+
rev: v2.14.0
7474
hooks:
7575
- id: check-message
7676
args:

docs/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ whatever your AI agent is committing on your behalf.
3636
```yaml title=".pre-commit-config.yaml"
3737
repos:
3838
- repo: https://github.com/commit-check/commit-check
39-
rev: v2.13.4
39+
rev: v2.14.0
4040
hooks:
4141
- id: check-message
4242
- id: check-branch

0 commit comments

Comments
 (0)