Six months from now, you'll read this commit message. Will it help?
The Anatomy of a Good Message
feat: add rate limiting to API endpoints
Implement sliding window rate limiter to prevent abuse.
- 100 requests per minute per IP
- Returns 429 with Retry-After header when exceeded
- Configurable via RATE_LIMIT_RPM env var
Closes #234
Line 1: Type and short summary (50 chars max) Line 2: Blank Lines 3+: Body explaining what and why Last line: References (issues, PRs)
The Subject Line
Keep it short. Most tools truncate at 50-72 characters.
# Bad
fix: fixed the bug where users couldn't log in because the session token was being invalidated too early
# Good
fix: extend session token expiry to 24 hours
Use imperative mood—"add feature" not "added feature":
# Bad
Added user authentication
# Good
Add user authentication
Conventional Commits
A standard format that tools can parse:
feat: add something new
fix: repair something broken
docs: update documentation
style: formatting, no code change
refactor: restructure without behavior change
test: add or fix tests
chore: maintenance tasks
Pick a convention and stick to it. Consistency matters more than which convention you choose.
The Body
Answer these questions:
- What changed? (the diff shows this, but summarize)
- Why did it change? (this is the important part)
- How does it work? (if not obvious from the code)
fix: handle null user in payment flow
The payment processor was crashing when called with a guest checkout
(user=None). Now we generate a temporary ID for guest users.
This was causing ~50 failed checkouts per day in production.
The "why" saves future you hours of archaeology.
What Not to Write
Don't describe the diff:
# Bad
Change line 45 from foo to bar
# Good
Fix off-by-one error in pagination
Don't be vague:
# Bad
Fix bug
Update code
Changes
# Good
Fix duplicate email validation on signup
Don't include issue numbers only:
# Bad
Fixes #234
# Good
Fix rate limit bypass via header injection
Fixes #234
Commit Message Templates
Set up a template in ~/.gitmessage:
# <type>: <subject>
#
# <body>
#
# <footer>
#
# Types: feat, fix, docs, style, refactor, test, chore
# Subject: imperative, 50 chars, no period
# Body: wrap at 72 chars
# Footer: references, breaking changes
Configure git to use it:
git config --global commit.template ~/.gitmessageWhen to Commit
Commit when you have a coherent change:
- A test passes
- A function works
- A bug is fixed
- A feature is complete
Don't wait until end of day. Small, focused commits with clear messages beat giant commits with vague messages.
Amending and Rebasing
Made a typo? Amend instead of adding a "fix typo" commit:
git commit --amendNeed to clean up a branch before merge?
git rebase -i HEAD~5Squash WIP commits into meaningful ones. Your merge should tell a clear story.
The Test
Read your last 10 commit messages. Could someone understand what changed and why without reading the code?
If not, write better messages starting now. Your future self will thank you.
My Format
<type>: <what changed>
<why it changed>
<any relevant context: breaking changes, migration steps, related issues>
Simple. Consistent. Useful.