Writing Effective Commit Messages in English

A beginner's guide to writing clear, professional Git commit messages in English — with real examples, common mistakes, and the Conventional Commits standard.

A commit message is a small piece of writing with a big impact. It tells your teammates — and your future self — what changed, and why. A good commit message saves hours of archaeology later. A bad one leaves the team guessing. Learning to write clear, professional commit messages in English is one of the most practical writing skills a developer can build.


Why Commit Messages Matter

When you run git log, you see a history of decisions. Each commit message is a record of intent. When a bug appears six months from now, the team will search that history. They will read commit messages to understand why a change was made, not just what changed (the diff already shows that).

A well-written commit message answers three questions:

  1. What changed?
  2. Why did it change?
  3. Is there anything important to know about how it changed?

Key Vocabulary

  • Subject line — the first line of a commit message, typically 50 characters or fewer
  • Body — the optional longer explanation below the subject line
  • Imperative mood — a grammatical style using command form: “Fix bug” not “Fixed bug” or “Fixing bug”
  • Scope — the part of the codebase affected by the change
  • Breaking change — a change that is incompatible with the previous version
  • Conventional Commits — a widely used standard for structuring commit messages
  • Changelog — a log of changes, often generated from commit messages automatically

The Golden Rule: Use the Imperative Mood

The most important grammar rule for commit messages is to use the imperative mood in the subject line. This means writing as if you are giving a command.

Think of it this way: your subject line should complete the sentence “If applied, this commit will…”

Correct (imperative)Incorrect
Fix login redirect bugFixed login redirect bug
Add user avatar uploadAdding user avatar upload
Remove deprecated API endpointRemoves deprecated API endpoint
Update dependencies to latestUpdated dependencies to latest

This convention is used by Git itself. When Git auto-generates a merge commit, it writes “Merge branch ‘feature/login’ into main” — imperative mood.


The Conventional Commits Standard

Many professional teams use the Conventional Commits specification. It adds a structured prefix to the subject line that makes messages easier to read and enables tools to auto-generate changelogs.

The format is:

type(scope): short description

Common Types

  • feat — a new feature: feat(auth): add OAuth2 login support
  • fix — a bug fix: fix(cart): correct total calculation with discount codes
  • docs — documentation changes: docs(readme): update local setup instructions
  • refactor — code restructuring without behaviour change: refactor(api): simplify error handling middleware
  • test — adding or updating tests: test(payments): add unit tests for retry logic
  • chore — maintenance tasks: chore(deps): upgrade react to 18.3.0
  • perf — performance improvements: perf(images): lazy-load product thumbnails
  • ci — CI/CD changes: ci: add deploy step for staging environment

Real Examples

feat(notifications): add email digest for weekly activity summary

Users can now opt in to a weekly email summary of their account activity.
This addresses the feature request from issue #412.

Breaking change: The NotificationService constructor now requires a mailer
instance to be passed explicitly.
fix(search): prevent crash when query contains special characters

Certain characters such as & and ? were not being URL-encoded before
being sent to the search API, causing a 400 error. Added encoding in
the SearchService buildQuery method.

Closes #891

Writing a Good Commit Body

The subject line tells what happened. The body explains why. Not every commit needs a body — simple changes like fix(typo): correct spelling in welcome email are self-explanatory. But any commit that involves a non-obvious decision deserves an explanation.

Good Body Practices

Keep lines under 72 characters. Many tools display commit messages in narrow terminals. Wrapping at 72 characters ensures readability.

Explain the motivation, not the mechanics. The diff already shows what changed. The body should explain why this approach was chosen.

Reference issues and pull requests. Use phrases like “Closes #123”, “See also #456”, or “Related to #789” to link context.

Example of a Well-Structured Commit

refactor(database): replace raw SQL queries with ORM calls

Raw SQL in the UserRepository was becoming difficult to maintain and
test. Switching to the ORM layer allows us to:

- Use the built-in query builder with type safety
- Mock the data layer more easily in unit tests
- Benefit from automatic SQL injection protection

Performance tests show no regression. Query execution time is within
5ms of the original for all tested endpoints.

See also: ADR-012 (architecture decision record on ORM adoption)

Common Mistakes to Avoid

Vague messages like “fix stuff”, “wip”, or “update” are useless. They tell the reader nothing.

Past tense subject lines like “Fixed the bug” break the imperative convention and look inconsistent in git log output.

Mixing unrelated changes in one commit makes it impossible to revert selectively. Each commit should do one thing.

Explaining the obvious: “Changed line 42 from X to Y” is not useful. The diff shows that. Write why.


Quick Checklist Before You Commit

Before writing your commit message, ask yourself:

  • Does the subject line complete “If applied, this commit will…”?
  • Is it 50 characters or fewer?
  • Does it use imperative mood?
  • If the change is complex, is there a body explaining the reasoning?
  • Are relevant issue numbers referenced?

Writing good commit messages is a habit, not a talent. With practice, it becomes second nature — and your future teammates (including future you) will thank you for it.