Commit Messages
Commit Messages as Documentation
Commit messages serve as the primary narrative documentation of repository evolution. Well-crafted messages enable efficient debugging, code archaeology, and team coordination, while poor messages create friction in every subsequent interaction with repository history.
The Newsfeed Mental Model
Think of your commit log as a newsfeed for your project, where each commit
message is a headline. Just as you can skim newspaper headlines and understand
what’s happening in the world, developers should be able to scan
git log --oneline and understand project evolution without reading code.
Good Headlines:
- Tell you enough to know what the story is about
- Don’t have to tell the whole story
- Fit in limited display space
Practical Reality: Commits that are perfect, single units of work, wrapped up in perfectly worded messages, are the exception rather than the rule. Don’t beat yourself up for a messy commit with a vague label like “fixed the header”—just know that better is possible and aim for it when you can.
The Cost of Poor Commit Messages
Common Anti-Patterns:
git log --oneline
abc1234 fix
def5678 updates
ghi9012 stuff
jkl3456 wip
mno7890 final
pqr1111 final finalConsequences:
git bisectsessions require code inspection instead of message scanninggit blameprovides no context for why changes were made- Code review becomes archaeological expedition rather than focused examination
- Team members duplicate investigation effort
Contrast: Professional Message Quality:
abc1234 Fix authentication timeout on slow networks
def5678 Refactor user model to support OAuth integration
ghi9012 Add rate limiting to API endpoints (fixes #243)
jkl3456 Optimize database queries in dashboard (30% improvement)Value: Clear messages enable rapid understanding without code examination.
The Conventional Commits Standard
Structure Template
<type>(<scope>): <subject>
<body>
<footer>Component Breakdown:
Type (required): Categorizes change intent
feat: New featurefix: Bug fixdocs: Documentation onlystyle: Code style (formatting, no logic change)refactor: Code restructuring (no behavior change)perf: Performance improvementtest: Test addition or correctionchore: Build process, tooling, dependencies
Scope (optional): Component or module affected
(auth): Authentication system(api): API layer(ui): User interface(db): Database layer
Subject (required): Imperative mood, concise summary (≤50 chars)
Body (optional): Detailed explanation (wrapped at 72 chars)
Footer (optional): Breaking changes, issue references
Example: Well-Structured Commit
feat(auth): implement JWT token refresh mechanism
Add automatic token refresh 5 minutes before expiration to prevent
session interruptions during active usage. Previous implementation
required users to re-authenticate when tokens expired mid-session.
Implementation:
- Background refresh timer in auth service
- Token expiration monitoring
- Graceful fallback to re-auth if refresh fails
Closes #156
BREAKING CHANGE: Auth configuration requires new `refreshWindow` parameterSubject Line Crafting
The 50-Character Constraint
Rationale: Git tooling truncates at 50 characters in various displays:
git log --onelineoutput- GitHub/GitLab commit lists
- Email subject lines (git send-email)
Pattern: <type>(<scope>): <imperative-verb> <what>
Effective Subject Lines:
✅ feat(api): add pagination to user list endpoint
✅ fix(auth): resolve race condition in token validation
✅ refactor(db): extract query builder to separate module
✅ perf(render): optimize component re-render logicIneffective Subject Lines:
❌ updated files
❌ fix bug
❌ changes
❌ WIP
❌ final versionImperative Mood Usage
Rule: Write as if completing sentence “If applied, this commit will _”
Correct:
- “Add user authentication”
- “Fix memory leak in cache module”
- “Refactor payment processing pipeline”
Incorrect:
- “Added user authentication”
- “Fixing memory leak”
- “Refactored code”
Technical Justification: Matches Git’s own message style and creates consistent imperative instruction set.
Body Composition
When to Include Body
Include Body When:
- Change isn’t self-explanatory from subject
- Implementation requires specific approach explanation
- Alternative approaches were considered
- Breaking changes introduced
- Complex business logic implemented
- Performance characteristics changed
Omit Body When:
- Change is trivial (typo fix, whitespace)
- Subject line fully explains change
- Commit follows obvious implementation
Body Content Structure
Effective Body Pattern:
1. What: Describe the change
2. Why: Explain motivation and context
3. How: Detail implementation approach (if non-obvious)
4. Consequences: Note any side effects or considerationsExample:
refactor(cache): migrate from Redis to Memcached
Previous Redis implementation experienced memory pressure under high load,
leading to eviction of actively-used keys. Profiling revealed our usage
pattern (high read/write ratio, simple key-value storage, no persistence
requirements) better suited to Memcached's LRU algorithm.
Implementation:
- Updated cache interface to abstract storage backend
- Migrated connection pooling logic
- Adjusted TTL settings to match Memcached behavior
Performance impact:
- 40% reduction in memory usage
- 15% improvement in cache hit rate
- Simplified deployment (removed Redis persistence configuration)
Testing notes:
- Backward compatibility maintained through cache interface
- Load testing conducted with production traffic profile
- Gradual rollout planned with canary deployment
Refs: PERF-234Footer Section: Metadata and References
Issue Tracking Integration
GitHub/GitLab Syntax:
# Close single issue
Closes #123
# Close multiple issues
Closes #123, #456
# Reference without closing
Refs #789
See #456
# Fix issue
Fixes #123
Resolves #456Jira Integration:
JIRA-1234
PROJ-5678Breaking Changes Declaration
Format:
BREAKING CHANGE: <description of breaking change>
# Or deprecated syntax
BREAKING CHANGE: API endpoint /users now requires authentication tokenExample in Full Commit:
feat(api): add authentication to user endpoints
All user-related endpoints now require JWT authentication. This prevents
unauthorized access to user data and aligns with security requirements
from audit.
Migration guide:
1. Update API clients to include Authorization header
2. Refresh tokens implement 15-minute expiration
3. Update integration tests with authentication fixtures
BREAKING CHANGE: /api/users endpoints now return 401 for unauthenticated requestsWriting Commit Messages in Your Editor
Editor Integration for Better Messages
While the -m flag is convenient, Git integrates with text editors for
composing multi-line commit messages with greater ease.
Configure Your Editor:
# VS Code
git config --global core.editor "code --wait"
# Sublime Text
git config --global core.editor "subl --wait"
# Vim
git config --global core.editor "vim"
# Emacs
git config --global core.editor "emacs"
# Nano
git config --global core.editor "nano"Usage:
# Omit -m to use editor
git commit
# Git opens configured editor with template
# Write message, save, close
# Git automatically captures the messageBenefits:
- Multi-line composition with proper formatting
- Spell-checking and syntax highlighting
- Access to commit message templates
- Visual confirmation of line length constraints
Pro Tip: Editors like VS Code display column indicators, making it easy to respect the 50/72 character guidelines.
Commit Message Templates
Creating Template File
# Create template file
cat > ~/.gitmessage << 'EOF'
<type>(<scope>): <subject>
# Why (motivation and context):
#
# How (implementation approach):
#
# Consequences (side effects):
#
# Issue references:
# Closes #
# ────────────────────────────────────────────────────────────
# Types: feat, fix, docs, style, refactor, perf, test, chore
# Subject: Imperative mood, ≤50 chars, no period
# Body: Wrap at 72 chars, explain what and why vs. how
# Footer: Issue references, breaking changes
# ────────────────────────────────────────────────────────────
EOF
# Configure Git to use template
git config --global commit.template ~/.gitmessageUsage: Running git commit (without -m) opens editor with template.
Template for Different Commit Types
Feature Addition Template:
feat(<scope>): <brief feature description>
# New feature details:
# - What: Feature implemented
# - Why: Business/user need addressed
# - How: Implementation approach
# - Testing: How feature was validated
Closes #Bug Fix Template:
fix(<scope>): <brief fix description>
# Bug details:
# - Symptom: Observable behavior
# - Root cause: Technical cause
# - Solution: Fix approach
# - Prevention: How to avoid recurrence
Fixes #Configuration for Team Consistency
Commit Message Linting
Install commitlint:
npm install --save-dev @commitlint/cli @commitlint/config-conventional
# Configure
echo "module.exports = {extends: ['@commitlint/config-conventional']}" > commitlint.config.js
# Add to Git hooks
npm install --save-dev husky
npx husky add .husky/commit-msg 'npx --no -- commitlint --edit "$1"'Enforcement: Invalid commit messages rejected at commit time.
Pre-Commit Hook for Message Validation
#!/bin/sh
# .git/hooks/commit-msg
commit_msg=$(cat "$1")
commit_regex='^(feat|fix|docs|style|refactor|perf|test|chore)(\(.+\))?: .{1,50}'
if ! echo "$commit_msg" | grep -qE "$commit_regex"; then
echo "ERROR: Commit message does not follow Conventional Commits format"
echo "Format: <type>(<scope>): <subject>"
echo "Example: feat(auth): add JWT token refresh"
exit 1
fiHistorical Analysis with Well-Structured Messages
Leveraging Message Quality
Search by Type:
# Find all features added
git log --grep="^feat"
# Find all bug fixes
git log --grep="^fix"
# Find database-related changes
git log --grep="(db)"Generate Changelog:
# Features and fixes between versions
git log v1.0.0..v2.0.0 --grep="^feat\|^fix" --onelineIdentify Breaking Changes:
git log --grep="BREAKING CHANGE"Advanced Message Techniques
Co-Author Attribution
Format:
feat(api): implement GraphQL endpoint
Co-authored-by: Jane Developer <[email protected]>
Co-authored-by: John Smith <[email protected]>GitHub Recognition: Properly formatted co-author lines credit contributors in GitHub UI.
Anti-Pattern: Combining Unrelated Changes
❌ git commit -m "fix login bug and refactor database queries and update docs"Correction: Separate commits
✅ git commit -m "fix(auth): resolve login failure on password reset"
✅ git commit -m "refactor(db): optimize user query performance"
✅ git commit -m "docs: update authentication flow documentation"Integration with Development Workflow
Commit Message in Pull Requests
Strategy: PR description synthesizes commit messages
Example PR Description:
## Summary
Implements JWT-based authentication system
## Changes
- feat(auth): add JWT token generation
- feat(auth): implement token validation middleware
- test(auth): add authentication flow tests
- docs(auth): update API authentication documentation
## Breaking Changes
- API clients must now include Authorization header
- Legacy session-based auth deprecated
## Testing
- Unit tests: 45 new tests
- Integration tests: Authentication flow validated
- Load testing: 10K concurrent authenticated requests
Closes #123, #145Amending Commit Messages
Scenario: Committed with poor message, want to improve before pushing.
# Amend most recent commit message
git commit --amend
# Amend without changing staged content
git commit --amend --onlyInteractive Rebase for Older Commits:
git rebase -i HEAD~3
# In editor, change 'pick' to 'reword' for commits to modify
reword abc1234
pick def5678
pick ghi9012
# Git will prompt for new message for each rewordFurther Reading
For deeper exploration of commit message philosophy and additional best practices, the Git community has produced excellent resources:
- Tim Pope’s “A Note About Git Commit Messages”: Widely-cited guidelines that influenced modern commit message standards
- Chris Beams’s “How To Write A Git Commit Message”: Comprehensive guide with the famous “Seven Rules”
These resources complement the Conventional Commits standard and provide historical context for commit message best practices.
Summary: Message Excellence as Force Multiplier
Core Principles:
- Clarity: Messages should explain what and why without code inspection
- Consistency: Follow team conventions (Conventional Commits recommended)
- Conciseness: Subject ≤50 chars, body wrapped at 72 chars
- Context: Include issue references, breaking changes, rationale
Practical Implementation:
- Use commit templates for consistency
- Configure editor integration for multi-line messages
- Enforce with pre-commit hooks and linting
- Review commit history quality during code review
- Treat commit messages as documentation, not afterthought
Strategic Value: High-quality commit messages compound over time—each good message saves future debugging time, improves code archaeology, and enables automated changelog generation.
Technical Excellence: Commit message discipline transforms repository history from opaque sequence of changes into navigable, searchable project narrative.
Next Steps: Create Custom Git Commands with Aliases