Accepted (at acb9c62)
The commit-msg hook receives the proposed commit message, may reject it
(non-zero exit) or rewrite it (edit the message in place), after which the
commit proceeds with the possibly-modified message.
Canonical git implements this by writing the message to a file
(.git/COMMIT_EDITMSG), invoking the hook with that file's path as its single
argument, and then re-reading the file. In tsgit the commit message arrives as
CommitOptions.message — there is no editor and no message file yet.
Three ways to hand the message to the hook were considered:
- File round-trip (
.git/COMMIT_EDITMSG) — git's own mechanism; the hook edits the file, tsgit re-reads it. - stdin — pipe the message in. But a
commit-msghook expects a path argument ($1), so existing hooks would break; and stdin gives the hook no way to write a rewrite back. - environment variable — same rewrite-back problem; env is read-only to the caller after spawn.
commit round-trips the message through .git/COMMIT_EDITMSG, exactly as git:
- After the message is resolved (and after the tree-equality
nothingToCommitguard — no point validating a message for a commit that will not happen), write it to${gitDir}/COMMIT_EDITMSG. - Run the
commit-msghook with the absoluteCOMMIT_EDITMSGpath asargv[1]. The absolute form is used (rather than a.git/…-relative path) so it is correct for customgitDirs and worktrees. - Re-read the file and re-run
sanitizeMessage. A hook that empties the message re-triggersEMPTY_COMMIT_MESSAGEunlessallowEmptyMessageis set. - The hook-rewritten message feeds both the commit object and the reflog subject line.
The round-trip is skipped entirely when noVerify is set or no HookRunner is
wired. The COMMIT_EDITMSG file is left on disk afterwards (git leaves it too —
it doubles as the editor template for the next commit).
- Git-faithful: an existing
commit-msghook (e.g. Conventional-Commits linters,commitlint, ticket-number injectors) works unchanged — they all read and write$1. - A hook can both reject and rewrite, the full
commit-msgcontract.
- Every verified commit on Node performs one extra small file write + read,
even when no
commit-msghook exists. Negligible (sub-millisecond) and itself git-faithful — git always writesCOMMIT_EDITMSG. .git/COMMIT_EDITMSGis created/overwritten as a side effect ofcommit; callers inspecting the git dir will see it.
- The re-sanitised, hook-modified message — not the caller's original — is what lands in the commit object and the reflog.
pre-commitneeds no file round-trip (it takes no arguments and no message); onlycommit-msgusesCOMMIT_EDITMSG.