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:

  1. What changed? (the diff shows this, but summarize)
  2. Why did it change? (this is the important part)
  3. 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 ~/.gitmessage

When 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 --amend

Need to clean up a branch before merge?

git rebase -i HEAD~5

Squash 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.

React to this post: