How To Guide

How to Write Good Git Commit Messages: A Practical Guide

Learn to write clear Git commit messages with Conventional Commits, the 50/72 rule, imperative mood, and how to fix bad messages with amend and rebase.

How to Write Good Git Commit Messages

A commit is the smallest unit of history in your repository, and its message is the only artifact that survives every rebase, cherry-pick, and blame investigation years from now. Yet most developers still ship wip, fix bug, or the infamous asdf. This guide walks through the conventions that turn a chaotic log into a searchable, changelog-ready history.

Why Commit Messages Matter

When a production incident hits at 2 a.m., the on-call engineer opens git log and git blame. If every line reads updates, the trail is dead. Good messages give you:

  • Faster debugging - git bisect pinpoints the offending commit; the message tells you why the change was made.
  • Automatic changelogs - tools like semantic-release and standard-version parse Conventional Commits to publish releases.
  • Better code review - reviewers understand intent before reading the diff.
  • Onboarding - new engineers learn a codebase by reading its history.

The Conventional Commits Standard

Conventional Commits is a lightweight convention layered on top of commit messages. The format is:

<type>(<optional scope>): <subject>

<optional body>

<optional footer>

Common types include feat (new feature), fix (bug fix), docs, style, refactor, perf, test, build, ci, and chore. A breaking change is signaled with ! after the type or a BREAKING CHANGE: footer, which triggers a major version bump.

Examples:

feat(billing): add annual plan discount
fix(auth): reject expired refresh tokens
refactor!: drop Node 16 support

BREAKING CHANGE: minimum runtime is now Node 18.

The 50/72 Rule

Tim Pope's classic guidance still holds up: keep the subject line under 50 characters, and wrap the body at 72 characters. The numbers are not arbitrary - GitHub truncates subjects around 50, and 72 keeps the body readable when git log indents by four spaces inside an 80-column terminal. Configure your editor to enforce these limits so you never have to count.

Use the Imperative Mood

Write the subject as if you were giving a command to the codebase: Add rate limiter, not Added rate limiter or Adds rate limiter. Git itself uses imperative in generated messages (Merge branch..., Revert...), so your custom commits blend in. The mnemonic test: the sentence If applied, this commit will ___ should read naturally.

What Belongs in the Body

The subject says what; the body explains why. A useful body typically covers:

  • The problem or user story that motivated the change.
  • The approach chosen and rejected alternatives.
  • Side effects, migration steps, or performance implications.
  • References to issue trackers - Refs #482 or Closes JIRA-1023.

Separate the subject from the body with a blank line, otherwise Git treats the whole message as one paragraph and tools that split subject from body will render it incorrectly.

Anti-Patterns to Avoid

These messages waste everyone's time:

  • wip, updates, changes, asdf
  • fix with no context
  • Merge branch main into feature from lazy merges - prefer rebase
  • Diff dumps - changed file X, then file Y - restating what git diff already shows

If you truly need a checkpoint commit while working, use git stash or push to a personal branch, then squash into a coherent commit before opening a pull request.

Fixing Bad Commit Messages

The last commit - amend it:

git commit --amend

Your editor opens with the previous message; rewrite it, save, and quit. If you have already pushed, you will need git push --force-with-lease, and only on branches you own.

Older commits - interactive rebase:

git rebase -i HEAD~5

Change pick to reword next to each commit you want to fix. Git will stop at each one and let you rewrite the message. Use squash or fixup to combine noisy commits into a single clean one.

Golden rule: never rewrite history on main, develop, or any branch other people have based work on. Rewriting shared history breaks their clones and forces painful resets.

Enforce It With Tooling

Install commitlint with a Husky commit-msg hook to reject non-conforming messages before they land. Pair it with commitizen so contributors get an interactive prompt, and configure CI to lint the pull-request title used as the merge commit subject. Once the pipeline enforces the rules, quality becomes automatic - and your git log starts reading like release notes.

Featured Tools

Try these free tools directly in your browser — no sign-up required.

git commit message conventional commits 50/72 rule imperative mood git rebase interactive git commit amend commit message style guide clean git history

Explore 300+ Free Tools

Utilko has tools for developers, writers, designers, students, and everyday users — all free, all browser-based.