Commit messages¶
Most of what a repository writes to its own history is machine-generated: sync-* and format-* jobs commit their output, the release lane commits the freeze and unfreeze, and dependency bots open their own pull requests. Those messages are read back by other machines, which makes the commit subject a small shared namespace rather than free text.
Square brackets are reserved¶
Important
A [bracketed] prefix in a commit subject is reserved for a load-bearing mechanism that parses it back. Never add one for decoration, categorization, or as a substitute for saying what changed.
The rule exists because a bracket prefix is not a label: it is an interface. Something downstream matches on it, and inventing a new one either collides with an existing matcher or trains readers to expect a meaning nothing enforces. The test to apply before writing one: name the code that reads it. If nothing does, write plain prose instead.
Two prefixes are load-bearing in a repomatic-managed repository, both emitted by prepare-release and both matched literally:
Prefix |
Emitted by |
Parsed by |
|---|---|---|
|
The release freeze commit |
The auto-tagging job, which locates the commit to tag by its message: a squash merge breaks it |
|
The unfreeze commit |
|
Everything else repomatic commits carries no prefix. Each sync-*, format-* and fix-* job takes its subject from its pull request template’s title: field, giving Sync action pins, Sync `uv.lock`, Format Markdown, Fix vulnerable dependencies: imperative, capitalized, no trailing period, identifiers backticked, no prefix.
Who else reads or writes commit messages¶
An inventory of what this project depends on, so you know which parts of the subject line are already claimed. Only GitHub Actions and git itself parse a commit message; the rest either write one you control or never look.
Tool or service |
Interaction |
Bracket convention |
|---|---|---|
Parses |
Skips the run when |
|
git |
Parses |
No brackets, but |
repomatic |
Writes and parses |
|
Writes |
No bracket default: it mimics the patterns it detects in the repository. A configured |
|
Writes |
No prefix by default ( |
|
|
Writes, when told to |
Free-form |
|
Writes |
Commits verbatim what the job supplies, so the convention is the caller’s |
Every |
Neither |
Formatters and linters ( |
Warning
The skip tokens are the reason this matters beyond style. They match anywhere in the message, not just at the start, and they are not limited to the subject: a token quoted in a commit body silently skips CI. Worse, a skipped required check sits in “Pending” forever and blocks the merge instead of failing loudly. Never paste one into a message, not even as an example.
Writing the subject¶
One line under 72 characters, imperative mood, capitalized, no trailing period, every identifier backticked. Name what changed, not the category it belongs to.
This is deliberately not Conventional Commits: no feat:, fix: or chore: prefixes. The verb already carries that information, and the repository’s automated operations follow the same verb-noun naming as their commits.
Avoid the bare one-word subject (Typo, Lint, Fix). It costs the next reader a git show to learn anything, and it reads identically to the fifty other commits that say the same word.
Writing the body¶
Omit it when the subject says everything. Add one short paragraph when the why is not evident from the diff, and especially when a public record of the decision exists: the upstream issue or pull request, a commit in another repository, the specification or documentation page that forced the behavior, the discussion thread. Point at the commit being reverted or followed up on.
Forges render commit messages as HTML, so a link is the cheapest path from git log to the full story. A body carrying one is where accountability and traceability actually live.