Step-by-step
-
1
Keep the subject line under 50 characters
The first line of a commit message is the subject. GitHub truncates it at 72 characters; many terminals at 80. Aim for 50 so it fits cleanly in
git log --oneline, GitHub's list view, and email notifications. If you can't summarise in 50 chars, the commit is probably too large.bash# Too long — hard to scan Fix the issue where authenticated users were being redirected to the login page after session expiry instead of refreshing the token # Good Fix token refresh redirect for authenticated users -
2
Use the imperative mood in the subject
Write the subject as if completing the sentence \"If applied, this commit will…\". That means: Fix, Add, Remove, Update, Refactor — not "Fixed", "Adding", or "Various changes".
bash# Wrong Fixed broken login Adding dark mode support I changed the timeout value # Correct Fix broken login redirect Add dark mode support Change timeout from 3s to 5s -
3
Leave a blank line before the body
Git treats the first paragraph as the subject and everything after a blank line as the body. Without that blank line, tools like
git log --oneline, GitHub, and many email clients cannot distinguish subject from body. The blank line is not optional.bashFix token refresh redirect for authenticated users The session middleware was checking token expiry before the refresh handler ran, causing a redirect to /login even when a valid refresh token existed. Reorder the middleware chain to fix this. Fixes #218 -
4
Explain why, not what, in the body
The diff already shows what changed. Use the body to explain the reason, the trade-off chosen, or the alternative you rejected. Wrap lines at 72 characters so the body renders cleanly in terminals.
bash# Unhelpful body — just describes the diff Changed timeout from 3000 to 5000 in config/app.js # Helpful body — explains the reasoning Increase API timeout from 3s to 5s The third-party payment gateway occasionally takes 4–4.5s on the first request after a cold start. Users were seeing spurious payment errors. The gateway's SLA guarantees responses within 5s. -
5
Adopt Conventional Commits for automation
Conventional Commits is a lightweight standard that prefixes the subject with a type:
feat:,fix:,chore:,docs:,refactor:,test:. Tools like semantic-release and standard-version read these prefixes to auto-generate changelogs and version bumps — no manual release notes.bashfeat: add OAuth2 login with Google fix: correct cart total when discount code applied chore: upgrade Laravel from 11 to 12 docs: document the deployment workflow in CLAUDE.md refactor: extract payment logic into PaymentService test: add unit tests for CartController # Breaking change — add ! and a footer: feat!: rename /api/v1 to /api/v2 BREAKING CHANGE: All clients must update their base URL. -
6
Reference issues and pull requests
Link commits to the issue tracker so future readers can jump straight to the full discussion. GitHub closes issues automatically when a commit with
Fixes #Nlands on the default branch.bashfix: prevent double-submit on payment form Disable the submit button immediately on click and re-enable it only if the API returns an error. Previously, slow connections allowed users to click twice, creating duplicate charges. Fixes #312 See also: #298 -
7
Configure your editor for commit messages
Writing multi-line commit messages in the terminal is painful. Set your preferred editor so Git opens a real file when you run
git commit(without-m). VS Code's--waitflag tells it to block until the file is closed.bash# VS Code git config --global core.editor "code --wait" # Vim git config --global core.editor "vim" # Nano git config --global core.editor "nano" # Then just run: git commit # Git opens the editor; save & close to finalise.
Tips & gotchas
- "wip", "minor fix", "updates", and "asdf" are not commit messages. Your future self at 2 AM debugging production will not thank you.
- If you need the word "and" to describe a commit, it should probably be two commits.
- The <code>git log --oneline --graph</code> view rewards good subject lines — bad ones make the log unreadable.
- For teams, add a <code>.gitmessage</code> template file and set <code>git config commit.template .gitmessage</code> to nudge everyone toward the standard.
Wrapping up
A good commit message takes 90 extra seconds to write and saves hours of investigation six months later. The habit compounds: once your whole team writes clear messages, git log becomes a searchable decision journal rather than a list of timestamps and SHA hashes. Start with imperative mood and a 50-char subject line — everything else follows naturally.