Skip to content

docs: standardize commit message format - #226

Open
gregggreg wants to merge 2 commits into
marcus:mainfrom
gregggreg:nightshift/commit-normalize-standard
Open

docs: standardize commit message format#226
gregggreg wants to merge 2 commits into
marcus:mainfrom
gregggreg:nightshift/commit-normalize-standard

Conversation

@gregggreg

Copy link
Copy Markdown

Codifies the commit format the repo already mostly follows — Conventional Commits — as a documented, enforced standard.

About 129 of 171 commits on main (~75%) already conform. This makes that explicit for new work.

History is not rewritten

No filter-branch, no rebase of published commits. Merged PRs and released tags keep their SHAs. Enforcement applies to new commits only:

  • the commit-msg hook checks what you write locally (opt-in via make install-hooks)
  • the commit-lint CI job checks only the commits unique to a PR, computed from git merge-base against the base ref — historical drift on main is left alone

What's here

File Purpose
docs/guides/commit-messages.md The canonical convention: format, types table, rules, good/bad examples drawn from real history
.gitmessage.txt Commit template, so git commit opens with the format inline
scripts/commit-msg.sh POSIX-sh validator used as the commit-msg hook
scripts/check-commit-range.sh Same validation over a commit range, for CI and make lint-commits
scripts/commit-msg_test.sh 40 table tests for the validator

Plus: make install-hooks now installs both hooks and sets the template; new make test-scripts and make lint-commits targets; a commit-lint CI job; cross-references from AGENTS.md (and CODEX.md, which symlinks to it) and README.md; a CHANGELOG.md entry.

Format

<type>(<optional scope>): <lowercase imperative subject>

Subject ≤72 chars, no trailing period, imperative mood. Types: feat fix docs refactor test chore build ci perf style revert.

The validator deliberately passes through subjects git authors itself (Merge …, Revert …, fixup!, squash!) and accepts acronym-initial subjects (fix: JSONL parsing …), trailers, and long URLs in the body. --no-verify bypasses the hook locally.

Agent-authored commits

internal/orchestrator/orchestrator.go now states the subject format in both the plan and implement prompts, keeping the existing Nightshift-Task / Nightshift-Ref trailers intact. orchestrator_test.go locks that contract down.

Verification

  • gofmt -l . — clean
  • go build ./..., go vet ./... — pass
  • go test ./... — all packages pass
  • make test-scripts — 40/40 pass
  • Hook exercised live: it rejected Standardize commit messages, then accepted this PR's own commit
  • check-commit-range.sh verified in both directions (flags a known-drifted historical range, passes this branch)

Note on overlap

There is an earlier open PR #186 from a previous run of this task, based on docs-backfill rather than main. It takes a rewrite-in-place approach (scripts/normalize-commit-message.sh); this PR validates and rejects instead, which keeps authorship of the message with the committer. Only one of the two should land — closing #186 in favor of this one is the suggested path.

Nightshift-Task: commit-normalize
Nightshift-Ref: https://github.com/marcus/nightshift

Codify Conventional Commits as the repository standard: a convention guide,
a commit template, a commit-msg hook validator, a range validator reused by
a commit-lint CI job, and shell tests for the validator.

Enforcement covers new commits only. Existing history is not rewritten, so
merged pull requests and released tags keep their current SHAs.

Agent prompts now request a conforming subject while preserving the
Nightshift-Task and Nightshift-Ref trailers.

Nightshift-Task: commit-normalize
Nightshift-Ref: https://github.com/marcus/nightshift
The commit-msg hook sized subjects with `wc -c` and body lines with awk's
length(), both of which count bytes. A 71-character subject containing
accents, an em-dash, smart quotes, or emoji was rejected as over-long, so
the effective limit for non-ASCII text was well under 72. False rejections
in a hook that blocks every commit push people toward --no-verify, which
erodes the convention this hook exists to enforce.

Measure with `wc -m` under a UTF-8 locale instead, probing for a locale the
machine actually has. macOS awk reports length() in bytes even in a UTF-8
locale, so awk cannot be used for this.

Body-length errors also reported awk's line number from the internally
stripped message. git does not strip the comment block before running
commit-msg, and `make install-hooks` installs an 18-line comment template,
so "body line 3" pointed at line 21 of the author's editor buffer. Tag each
line with its original number while stripping and report that.

Nightshift-Task: commit-normalize
Nightshift-Ref: https://github.com/marcus/nightshift
@gregggreg

Copy link
Copy Markdown
Author

Addressed the two review findings in `scripts/commit-msg.sh` (fa7b592):

  • Subject length was measured in bytes. wc -c/awk length() counted bytes, so a 71-character subject with accents, an em-dash, smart quotes, or emoji was rejected as over-long. Now measured with wc -m under a UTF-8 locale, probed for one the machine actually has. Note macOS awk reports length() in bytes even in a UTF-8 locale, so awk could not be used here.
  • Body-length errors reported the post-strip line number. Since git does not strip the comment block before running commit-msg, and make install-hooks installs an 18-line comment template, "body line 3" pointed at line 21 of the editor buffer. Each line is now tagged with its original number while stripping.

Also documented that limits are character counts and that the body hard limit is 100 (wrap at 72), with trailers and single-token URLs exempt.

Regression tests added — the suite is now 45 checks, all passing. One test uses a body line that is 100 characters but 191 bytes, so it fails if byte counting ever returns. scripts/check-commit-range.sh --base origin/main HEAD passes on both commits, and go build, go vet, go test ./internal/orchestrator/ are green.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant