How to Write Effective Git Commit Messages

A practical English guide to writing clear, professional Git commit messages — conventions, examples, and common mistakes to avoid.

Git commit messages are one of the most-written but least-thought-about forms of technical English. A well-written commit message tells the story of your codebase. A poorly written one — “fix stuff”, “WIP”, “asdfgh” — creates a history that is useless to your team and your future self.

This guide covers the conventions, vocabulary, and specific language choices that make commit messages genuinely useful.


The Conventional Commit Format

The most widely adopted standard is Conventional Commits, which uses a structured prefix:

<type>(<scope>): <short description>

[optional body]

[optional footer]

Example:

feat(auth): add JWT refresh token endpoint

Implements a /auth/refresh endpoint that accepts a valid refresh token
and returns a new access token. Refresh tokens expire after 7 days.

Closes #142

Commit Types and When to Use Them

TypeUse whenExample
featAdding a new featurefeat(search): add full-text search to products
fixFixing a bugfix(api): handle null response from payment gateway
docsDocumentation onlydocs(readme): update local setup instructions
styleFormatting, no logic changestyle(button): apply consistent border-radius
refactorCode restructure, no feature or fixrefactor(user): extract validation into separate module
testAdding or updating teststest(cart): add edge case for empty cart checkout
choreMaintenance taskschore(deps): upgrade eslint to v9
perfPerformance improvementperf(query): add index to reduce user lookup latency
ciCI/CD configurationci(github): add step to run integration tests
revertReverting a previous commitrevert: feat(auth): add JWT refresh token endpoint

Writing the Subject Line

The subject line (the first line) is the most important part. Rules:

  • Use the imperative mood: “Add feature” not “Added feature” or “Adding feature”
  • Keep it under 72 characters
  • Don’t end with a period
  • Capitalise the first word after the type prefix

Imperative mood examples:

WrongRight
”Fixed the login bug""fix(auth): resolve login failure on empty password"
"I added tests""test(user): add unit tests for email validation"
"Changes to config""chore(config): move timeout settings to env variables"
"Updated README""docs(readme): add Docker setup instructions”

The imperative mood feels like completing the sentence: “This commit will… [add a refresh token endpoint]”.


Writing the Body

The body is optional but valuable for non-obvious changes. Use it to explain:

  • Why the change was made (not just what changed — that’s visible in the diff)
  • The problem that existed before
  • Trade-offs or decisions made

Good body examples:

“Previously, all database connections were created per-request. This caused connection pool exhaustion under high load. This commit implements connection pooling via pg-pool, capping connections at 20 per instance.”

“The previous implementation used a synchronous file read, which blocked the event loop during large uploads. Switching to the async stream API resolves the performance issue reported in #234.”

What not to put in the body:

  • Repetition of what the diff already shows
  • Vague statements like “made some improvements”
  • Personal notes (“not sure if this is the right approach”)

Referencing Issues and Pull Requests

Most teams use keywords that automatically close issues when the commit is merged:

Closes #142 — closes the issue
Fixes #89 — closes the issue (also implies it was a bug)
Refs #201 — references without closing
See also #98 — additional context


Common Commit Message Mistakes

MistakeWhy it’s a problemFix
”fix”Tells you nothing”fix(api): return 404 when user not found"
"WIP”Not a complete thoughtSquash WIP commits before merging
”fixed a bug”Past tense, vague”fix(checkout): prevent duplicate order submission"
"Updating stuff”Completely meaningless”chore(deps): upgrade React to 18.3”
Very long subjectHard to read in git logKeep under 72 characters

Useful Verbs for Commit Messages

Technical commit writing uses a specific set of verbs consistently:

add, remove, update, fix, refactor, extract, move, rename, replace, implement, introduce, deprecate, revert, disable, enable, configure, document, optimise


A clear commit history is not cosmetic. It is what allows your team to git blame, git bisect, and understand the evolution of the codebase years later. Write messages for the engineer who will read them at 11pm during an incident — that engineer might be you.