The Art of Git Commit Messages: Writing History That Future Developers Will Thank You For¶
Why I spend more time on commit messages than most people spend on comments, and how it pays dividends months later.
Reading My Own History Was Painful¶
I was debugging a production issue and ran git log to understand why a particular change was made six months ago. The commit message: "fix bug." That was it. No context, no reasoning, no reference to what bug. I checked blame on surrounding lines: "update code," "minor changes," "WIP." I had to read every diff, reconstruct the intent, and piece together what the developer was thinking. That developer was me. That was the day I decided to treat commit messages as a first-class communication channel.
The Anatomy of a Great Commit Message¶
After years of refining my approach, I follow a strict structure:
The subject line (max 50 characters) answers: "what does this commit do?" Written in imperative mood — "add feature," not "added feature" or "adds feature."
The body (wrapped at 72 characters) answers: "why was this change necessary? what approach was taken? what alternatives were considered?"
The footer contains references: issue numbers, breaking change notes, co-author credits.
Real Examples From My Work¶
Bad (my old style):
Good (my current style):
fix(auth): increase token refresh timeout to 30s
The default 5s timeout caused failures on high-latency
connections, particularly for users in Southeast Asia.
Monitoring showed 12% of refresh attempts timing out
since the v2.3 release.
30s matches the upstream OAuth2 provider's maximum
response time under load. Considered per-region timeouts
but deferred — the uniform increase resolves 98% of
failures with less complexity.
Fixes: PROJ-4521
Monitoring: https://grafana.internal/d/auth-timeouts
Six months from now, any developer can understand: what changed, why, what data supported the decision, and what alternatives were considered but rejected.
The Seven Rules I Follow¶
-
Separate subject from body with a blank line. Tools rely on this —
git log --onelineshows only the subject, email formatters use it as the email subject. -
Limit the subject to 50 characters. Forces precision. If you can't describe the commit in 50 characters, the commit is probably too large.
-
Capitalize the subject line. "Add user validation" not "add user validation."
-
No period at the end of the subject. Space is precious at 50 characters.
-
Use imperative mood in the subject. "Fix bug" not "Fixed bug." Think of it as completing the sentence: "If applied, this commit will fix bug."
-
Wrap body at 72 characters. Git doesn't wrap automatically. Terminal tools assume 72-character width for diffs and logs.
-
Explain what and why, not how. The diff shows how. The message explains why.
Conventional Commits: Structure That Scales¶
I use Conventional Commits format for the subject line:
feat(scope): add new capability
fix(scope): correct broken behavior
docs(scope): update documentation only
refactor(scope): restructure without behavior change
test(scope): add or fix tests
chore(scope): maintenance, dependencies, tooling
perf(scope): improve performance
ci(scope): CI/CD pipeline changes
This structure enables automation:
- Changelogs generated from commit history
- Semantic version bumping based on commit types
- Filtering history by type: git log --grep="^feat"
The Body: Where Real Value Lives¶
The subject line gets people to the commit. The body makes them understand it. I include:
Context: What situation prompted this change?
Users reported intermittent 403 errors during peak hours.
Investigation showed the session cache was evicting entries
under memory pressure, causing valid sessions to require
re-authentication.
Decision rationale: Why this approach over alternatives?
Considered three approaches:
1. Increase cache size (quick but doesn't solve the root cause)
2. Switch to Redis-backed sessions (correct but large scope)
3. Add cache-miss fallback to database (targeted, minimal risk)
Chose option 3 as it resolves the immediate issue while
option 2 is planned for Q3.
Impact: What should readers know about the effects?
This adds a database query on cache miss (~5ms p99).
Under normal load, cache hit rate is 99.7%, so impact
is negligible. Under the failure scenario, users get
a 5ms delay instead of a 403 error.
Commit Messages as Documentation¶
I treat commits as the most honest documentation. Unlike README files that go stale, commit messages are permanently tied to the exact code change they describe. They are:
- Discoverable via
git blame— click any line to understand its history - Permanent — unlike comments that get deleted during refactoring
- Contextual — they explain the transition, not just the current state
# Why was this line written this way?
git blame src/auth/session.py
# What was the developer thinking?
git log --format="%H %s" -- src/auth/session.py
# Full context for a specific change
git show <commit-sha>
Commit Messages for Reverts¶
When reverting, I explain why the original was wrong:
revert: "feat(cache): add LRU eviction policy"
This reverts commit a1b2c3d.
The LRU eviction was causing session loss under high load.
The eviction threshold (100MB) was too aggressive for our
workload pattern — users with long sessions (>30min) were
losing state.
Reverting while we implement size-based eviction with
session-duration weighting (PROJ-4890).
Teaching the Team¶
Commit message quality is cultural. I established it on my team through:
- commit-msg hook that enforces format (length, conventional prefix)
- PR template that asks "do your commit messages explain the why?"
- Leading by example — detailed messages on every commit, especially boring ones
- Code review feedback — I comment on unhelpful commit messages, not just code
Key Takeaway¶
A commit message is a letter to a future developer. It costs two minutes to write well and saves hours of archaeology later. The diff shows what changed. The message explains why it matters. Together, they form a complete historical record that no amount of documentation can replicate. Write as if the next reader has never seen this code before — because in six months, that reader is you.
Tags: git, commit-messages, documentation, conventions, communication