Commit Message Craft
Parent: Writing and Documentation · Published reference · snapshot 2026-09-08 · skill technical-writing-craft/references/commit-message-craft.md
↓ Facts as markdownall context files
Subject line: hard limit 50 characters. Body: wrap at 72.
These notes link each claim to its source. Some citations identify archived research reports that are no longer hosted on this site. A published reference means the content is available; it does not certify independent review or accuracy.Read the editorial policy and follow the sources before relying on a claim.
1. The 50/72 rule (Tim Pope, 2008)
- Subject line: hard limit 50 characters. Body: wrap at 72. [archived source: https://llms-explorer.com/sources/mdb-context-hub/commit-message-craft/#1-the-5072-rule-tim-pope-2008]
- Mechanical rules: [archived source: https://llms-explorer.com/sources/mdb-context-hub/commit-message-craft/#1-the-5072-rule-tim-pope-2008]
- Subject line ≤ 50 chars. Hard ceiling is 72, but cross 50 only when truly unavoidable. [archived source: https://llms-explorer.com/sources/mdb-context-hub/commit-message-craft/#1-the-5072-rule-tim-pope-2008]
- Blank line between subject and body - required. [archived source: https://llms-explorer.com/sources/mdb-context-hub/commit-message-craft/#1-the-5072-rule-tim-pope-2008]
- No trailing period on the subject. [archived source: https://llms-explorer.com/sources/mdb-context-hub/commit-message-craft/#1-the-5072-rule-tim-pope-2008]
2. Imperative mood for the subject
- Write the subject as a command the commit gives the codebase, not as a past-tense report. [archived source: https://llms-explorer.com/sources/mdb-context-hub/commit-message-craft/#2-imperative-mood-for-the-subject]
- Test: prepend "If applied, this commit will ___". The result must be a grammatical English sentence. [archived source: https://llms-explorer.com/sources/mdb-context-hub/commit-message-craft/#2-imperative-mood-for-the-subject]
- Add retry logic to S3 uploader - passes [archived source: https://llms-explorer.com/sources/mdb-context-hub/commit-message-craft/#2-imperative-mood-for-the-subject]
- Added retry logic to S3 uploader - fails [archived source: https://llms-explorer.com/sources/mdb-context-hub/commit-message-craft/#2-imperative-mood-for-the-subject]
3. Conventional Commits: structure beyond the basics
- Types: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert [archived source: https://llms-explorer.com/sources/mdb-context-hub/commit-message-craft/#3-conventional-commits-structure-beyond-the-basics]
4. Breaking changes: `!` and `BREAKING CHANGE:` footer
- Method 1 - exclamation mark in the header: [archived source: https://llms-explorer.com/sources/mdb-context-hub/commit-message-craft/#4-breaking-changes-and-breaking-change-footer]
- Method 2 - footer token: [archived source: https://llms-explorer.com/sources/mdb-context-hub/commit-message-craft/#4-breaking-changes-and-breaking-change-footer]
5. The "why not what" rule for the body
- The diff already shows what changed. The body must explain why. [archived source: https://llms-explorer.com/sources/mdb-context-hub/commit-message-craft/#5-the-why-not-what-rule-for-the-body]
- Body content checklist: [archived source: https://llms-explorer.com/sources/mdb-context-hub/commit-message-craft/#5-the-why-not-what-rule-for-the-body]
- What problem did this commit solve? [archived source: https://llms-explorer.com/sources/mdb-context-hub/commit-message-craft/#5-the-why-not-what-rule-for-the-body]
- Why this approach and not an alternative? [archived source: https://llms-explorer.com/sources/mdb-context-hub/commit-message-craft/#5-the-why-not-what-rule-for-the-body]
- Any non-obvious side effect or trade-off? [archived source: https://llms-explorer.com/sources/mdb-context-hub/commit-message-craft/#5-the-why-not-what-rule-for-the-body]
- Links to tickets, design docs, or incident reports. [archived source: https://llms-explorer.com/sources/mdb-context-hub/commit-message-craft/#5-the-why-not-what-rule-for-the-body]
- Body anti-content: [archived source: https://llms-explorer.com/sources/mdb-context-hub/commit-message-craft/#5-the-why-not-what-rule-for-the-body]
- Don't restate the subject line. [archived source: https://llms-explorer.com/sources/mdb-context-hub/commit-message-craft/#5-the-why-not-what-rule-for-the-body]
- Don't narrate the diff line by line. [archived source: https://llms-explorer.com/sources/mdb-context-hub/commit-message-craft/#5-the-why-not-what-rule-for-the-body]
6. Multi-commit storytelling for PR reviewers
- Prep commits first - refactors, renames, type-only changes with no behavior change. [archived source: https://llms-explorer.com/sources/mdb-context-hub/commit-message-craft/#6-multi-commit-storytelling-for-pr-reviewers]
- The substantive commit - the one that does the actual feature/fix. [archived source: https://llms-explorer.com/sources/mdb-context-hub/commit-message-craft/#6-multi-commit-storytelling-for-pr-reviewers]
- Test commit(s) - if tests are separated. [archived source: https://llms-explorer.com/sources/mdb-context-hub/commit-message-craft/#6-multi-commit-storytelling-for-pr-reviewers]
- Cleanup commits last - docs, changelog, version bumps. [archived source: https://llms-explorer.com/sources/mdb-context-hub/commit-message-craft/#6-multi-commit-storytelling-for-pr-reviewers]
7. Fixup / squash / autosquash discipline
- git commit --fixup=<sha> writes a commit message starting with fixup! <original-subject>. [archived source: https://llms-explorer.com/sources/mdb-context-hub/commit-message-craft/#7-fixup-squash-autosquash-discipline]
- --fixup discards the fixup's commit message; only the original is kept. Use for typo fixes. [archived source: https://llms-explorer.com/sources/mdb-context-hub/commit-message-craft/#7-fixup-squash-autosquash-discipline]
- --squash keeps both messages joined. Use when the "fix" adds meaningful nuance. [archived source: https://llms-explorer.com/sources/mdb-context-hub/commit-message-craft/#7-fixup-squash-autosquash-discipline]
- Never push fixup commits to a shared branch as-is. [archived source: https://llms-explorer.com/sources/mdb-context-hub/commit-message-craft/#7-fixup-squash-autosquash-discipline]
8. Signed-off-by and the Developer Certificate of Origin
- Use git commit -s (or --signoff) to add automatically. [archived source: https://llms-explorer.com/sources/mdb-context-hub/commit-message-craft/#8-signed-off-by-and-the-developer-certificate-of-origin]
9. Other trailers
- Co-authored-by: Name <email> - GitHub credits both authors [archived source: https://llms-explorer.com/sources/mdb-context-hub/commit-message-craft/#9-other-trailers]
- Closes #123, Fixes #123, Resolves #123 - GitHub auto-closes the issue [archived source: https://llms-explorer.com/sources/mdb-context-hub/commit-message-craft/#9-other-trailers]
Anti-Patterns
- "Fixed bug" / "Updates" / "WIP" - useless. [archived source: https://llms-explorer.com/sources/mdb-context-hub/commit-message-craft/#anti-patterns]
- Past-tense subjects - Added, Fixed, Refactored. [archived source: https://llms-explorer.com/sources/mdb-context-hub/commit-message-craft/#anti-patterns]
- Restating the diff in the body. [archived source: https://llms-explorer.com/sources/mdb-context-hub/commit-message-craft/#anti-patterns]
- Stacking unrelated changes in one commit. [archived source: https://llms-explorer.com/sources/mdb-context-hub/commit-message-craft/#anti-patterns]
- Burying breaking changes without ! or BREAKING CHANGE:. [archived source: https://llms-explorer.com/sources/mdb-context-hub/commit-message-craft/#anti-patterns]
References
- Conventional Commits v1.0.0 specification [archived source: https://llms-explorer.com/sources/mdb-context-hub/commit-message-craft/#references]
- Tim Pope - A Note About Git Commit Messages [archived source: https://llms-explorer.com/sources/mdb-context-hub/commit-message-craft/#references]
- Chris Beams - How to Write a Git Commit Message [archived source: https://llms-explorer.com/sources/mdb-context-hub/commit-message-craft/#references]
Where this helps
- Writing a commit subject line and needing a concrete, mechanical rule, a 50-character soft limit and a 72-character hard ceiling, instead of an arbitrary length guess. [source] — AI-suggested, synthesized from this pack's existing facts — not extracted from a source document.
- Deciding whether a fix belongs in the same commit as its context or as a separate prep commit for a PR reviewer to read in a deliberate order. [source] — AI-suggested, synthesized from this pack's existing facts — not extracted from a source document.
- Announcing a breaking change in a commit and needing both valid mechanisms: the ! shorthand in the header and the BREAKING CHANGE: footer token. [source] — AI-suggested, synthesized from this pack's existing facts — not extracted from a source document.
- Cleaning up a messy commit history before merge and needing to know the difference between --fixup, which discards the fixup's own message, and --squash, which keeps both messages, with autosquash. [source] — AI-suggested, synthesized from this pack's existing facts — not extracted from a source document.
How to apply this
- Write the subject as an imperative command to the codebase, such as “Add retry logic to S3 uploader,” and test it with the “If applied, this commit will ___” fill-in to confirm it reads as a grammatical sentence. [source] — AI-suggested, synthesized from this pack's existing facts — not extracted from a source document.
- Use the commit body to explain why, not what; the diff already shows what changed, so the body's job is the reasoning the diff can't carry. [source] — AI-suggested, synthesized from this pack's existing facts — not extracted from a source document.
- Structure a multi-commit PR for reviewer storytelling: prep commits, refactors, renames, type-only changes, first, then the substantive commit, then test commits if separated. [source] — AI-suggested, synthesized from this pack's existing facts — not extracted from a source document.
- Add the correct trailers for the situation: Co-authored-by for shared authorship, Closes or Fixes or Resolves for auto-closing linked issues, and -s or --signoff for the Developer Certificate of Origin. [source] — AI-suggested, synthesized from this pack's existing facts — not extracted from a source document.
Common mistakes
- Writing a useless subject line, such as “Fixed bug,” “Updates,” or “WIP,” that carries no information about what actually changed. [source] — AI-suggested, synthesized from this pack's existing facts — not extracted from a source document.
- Writing the subject in past tense, such as “Added,” “Fixed,” or “Refactored,” instead of the imperative mood the convention calls for. [source] — AI-suggested, synthesized from this pack's existing facts — not extracted from a source document.
- Restating the diff in the commit body instead of explaining the reasoning behind it, when the diff is already right there. [source] — AI-suggested, synthesized from this pack's existing facts — not extracted from a source document.
- Mixing a prep refactor and the substantive fix into one commit, which forces a PR reviewer to untangle mechanical changes from the actual behavior change in a single diff. [source] — AI-suggested, synthesized from this pack's existing facts — not extracted from a source document.
Known issues
- deprecate: is not an official Conventional Commits v1.0.0 type; teams using it are relying on a custom extension that spec-compliant tooling may not recognize. [source] — AI-suggested, synthesized from this pack's existing facts — not extracted from a source document.
- --fixup discards the fixup commit's own message entirely, keeping only the original, so a wrong choice between --fixup and --squash can silently lose the reasoning captured in the newer commit. [source] — AI-suggested, synthesized from this pack's existing facts — not extracted from a source document.
- The 50/72 rule is a convention, not something Git enforces; nothing stops a subject line from exceeding 50 or even 72 characters, so it depends entirely on author discipline or a lint hook. [source] — AI-suggested, synthesized from this pack's existing facts — not extracted from a source document.
- Signed-off-by, the Developer Certificate of Origin trailer, is a self-attestation, not a cryptographic guarantee; it records that the signer claims the right to submit the change, but doesn't verify identity the way commit signing does. [source] — AI-suggested, synthesized from this pack's existing facts — not extracted from a source document.
Children
- Conventional Commits (frontier)
- Tim Pope 50/72 rule (frontier)
- Imperative-mood subjects (frontier)
- BREAKING CHANGE footer (frontier)
- Why-not-what body discipline (frontier)
- Fixup/squash/autosquash workflow (frontier)
- Signed-off-by/DCO trailers (frontier)
- Co-authored-by trailer (frontier)
- Multi-commit storytelling (frontier)
- Commit splitting heuristics (frontier)
Frontier under this node: BREAKING CHANGE footer, Co-authored-by trailer, Commit splitting heuristics, Conventional Commits, Fixup/squash/autosquash workflow, Imperative-mood subjects, Multi-commit storytelling, Signed-off-by/DCO trailers, Tim Pope 50/72 rule, Why-not-what body discipline