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
| Type | Use when | Example |
|---|---|---|
feat | Adding a new feature | feat(search): add full-text search to products |
fix | Fixing a bug | fix(api): handle null response from payment gateway |
docs | Documentation only | docs(readme): update local setup instructions |
style | Formatting, no logic change | style(button): apply consistent border-radius |
refactor | Code restructure, no feature or fix | refactor(user): extract validation into separate module |
test | Adding or updating tests | test(cart): add edge case for empty cart checkout |
chore | Maintenance tasks | chore(deps): upgrade eslint to v9 |
perf | Performance improvement | perf(query): add index to reduce user lookup latency |
ci | CI/CD configuration | ci(github): add step to run integration tests |
revert | Reverting a previous commit | revert: 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:
| Wrong | Right |
|---|---|
| ”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
| Mistake | Why it’s a problem | Fix |
|---|---|---|
| ”fix” | Tells you nothing | ”fix(api): return 404 when user not found" |
| "WIP” | Not a complete thought | Squash 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 subject | Hard to read in git log | Keep 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.
Navigating Nuances: Precision in Professional Descriptions
Writing effective Git commit messages isn’t just about stating what you changed; it’s about communicating why and how. For non-native English speakers, this can feel particularly challenging because technical language often has subtle nuances that aren’t immediately obvious. Let’s consider some common scenarios and how to approach them with greater precision.
One frequent issue arises during code reviews. Imagine receiving a comment like, “This commit doesn’t really explain the change.” While technically accurate, this is vague and unhelpful. A better response would be, “Could you elaborate on the reasoning behind this refactoring? Specifically, I’d appreciate understanding how it addresses the potential performance bottleneck we discussed in our last meeting.” Notice the shift – it requests clarification rather than simply criticizing a lack of explanation. Using phrases like “elaboration,” “reasoning,” and “addressing” demonstrates a more sophisticated grasp of the conversation’s purpose. It’s about showing you understand the broader context, not just the immediate code change.
Another situation might involve crafting a pull request description. Let’s say you’re adding a new feature – you could write something like, “Added new functionality.” This is incredibly brief and provides no value to reviewers. Instead, aim for something more descriptive: “Implemented user authentication using OAuth 2.0, adhering to the security guidelines outlined in document [link]. This enhancement allows users to register via their existing Google accounts, streamlining the onboarding process.” The key here is to incorporate specific terminology – “OAuth 2.0,” “security guidelines” - and clearly state the impact of the change (“streamlining the onboarding process”). Using active voice (“Implemented…”) also improves clarity compared to passive constructions.
Finally, consider Slack conversations around commit messages. A colleague might say, “Just made a quick fix.” This is often used informally but can be misleading in a professional setting. It’s better to communicate: “Resolved issue #123 – the intermittent error causing data corruption was traced and corrected using a rollback strategy. I’ve added detailed comments within the commit explaining the debugging process.” Again, being specific – referencing an issue number, detailing the ‘rollback strategy’, and explaining the ‘debugging process’ - significantly improves understanding and facilitates collaboration. Remember, concise doesn’t always equal effective; precision and context are paramount.