Git Commit Conventions
Writing commit messages that are actually useful six months later — subject line rules, body conventions, and the trailers that link commits to issue trackers.
The seven rules
From Tim Pope’s “A Note About Git Commit Messages”, still the reference everyone eventually converges on:
- Separate subject from body with a blank line
- Limit the subject line to 50 characters
- Capitalize the subject line
- No period at the end of the subject line
- Use the imperative mood in the subject line
- Wrap the body at 72 characters
- Use the body to explain what and why, not how
The imperative-mood test: a properly formed subject line should complete the sentence “If applied, this commit will ____.”
Refactor user authentication middleware # ✓ "If applied, this commit will refactor..."
Fixed bug in login flow # ✗ past tense
Fixes bug in login flow # ✗ third-person present
Subject vs. body
The subject is a summary; the body is the explanation. Git tooling depends on the blank-line separator — git log --oneline, git shortlog, and GitHub’s PR list all just show the subject line, so it needs to stand alone.
Short summary of changes (50 chars or less)
More detailed explanatory text, if necessary. Wrap it to about 72
characters. The blank line separating the summary from the body is
critical (unless you omit the body entirely).
Explain the problem this commit solves and why you're solving it
this way, not how the code works — the diff already shows that.
Focus on what motivated the change and what contrasts with the
previous behavior.
- Bullet points are fine here
- Use a hyphen or asterisk, followed by a space
git commit with no -m opens $EDITOR with exactly this shape in mind — worth using for anything beyond a trivial change, since composing multi-line messages on the command line with -m is awkward.
Why not -m
git commit -m "message" only writes a subject line. For a real body:
git commit # opens $EDITOR, write subject + blank line + body
git commit -m "Subject" -m "Body paragraph one" -m "Body paragraph two"
The second form works but the editor is easier for anything longer than one paragraph.
Amending and fixing up
git commit --amend # edit the last commit's message
git commit --amend --no-edit # add staged changes to last commit, keep message
git commit --fixup <sha> # mark a commit as a fixup for an earlier one
git rebase -i --autosquash <base> # auto-reorders and squashes fixup! commits
Only amend or rebase commits that haven’t been pushed to a shared branch — it rewrites SHAs.
Linking commits to tickets
GitHub closing keywords
A trailer or inline phrase referencing an issue, using one of GitHub’s closing keywords, closes that issue automatically when the commit lands on the default branch (via a merged PR):
Closes #123
Fixes #123
Resolves #123
Plain References #123 or See #123 links without closing.
Sourcehut ticket trailers
Sourcehut’s hub uses the same idea via standard git trailers (a Key: value line at the end of the body), where the value is the full ticket URL rather than a bare #number:
foo: add support for yaml config files
Implements: https://todo.sr.ht/~arkanoid/foobar/1337
Signed-off-by: John Doe <john@doe.io>
| Trailer | Effect |
|---|---|
References: |
links, no status change |
Implements: |
marks ticket IMPLEMENTED |
Fixes: |
marks ticket FIXED |
Closes: |
closes the ticket |
Status updates happen automatically on push — no web UI interaction needed. The same trailers work in patches submitted to Sourcehut mailing lists (git send-email), not just direct pushes.
Conventional Commits, if you’re using it
A stricter, machine-parseable format layered on top of the same subject/body split — see the “Conventional commit format” section on the main Git note for the <type>[scope]: <description> grammar. The two aren’t mutually exclusive: a Conventional Commits subject line can still follow the 50-char/imperative-mood/no-period rules above.