Home / Blog / Commit message discipline: why it matters and how to enforce it

Commit message discipline: why it matters and how to enforce it

Commit messages aren't just dates, they're the memory of your codebase. How I install the discipline, and why it's worth it.

Open up git log and look at your last 100 commits. How many do you actually remember? Commits like “fix bug”, “update”, “wip”, “stuff” are lost history. Good commit messages are the memory of your codebase.

In 19 years as a developer, I’ve tried to install this discipline in plenty of teams. Here’s the practical approach I keep coming back to.

Why commit messages matter

1. Future debugging. Six months later, the answer to “why is this line like this?” lives in the commit message.

2. Code review context. A reviewer reads the diff, but also the commit message. It should answer “why did you make this change?”.

3. Release notes generation. Release notes can be auto-generated from commits.

4. Bisect debugging. When you’re using git bisect to find where a bug crept in, commit messages are the signposts.

5. Onboarding new developers. Git log is the evolution story of your codebase.

Bad commit messages throw away all five of these.

Conventional commits format

The most widespread standard: Conventional Commits.

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

<body>

<footer>

Types:
feat: new feature
fix: bug fix
docs: documentation change
style: code style (whitespace, formatting, no logic change)
refactor: code restructure, no behavior change
perf: performance improvement
test: adding or updating tests
chore: maintenance task (dependency update, config)

Example:

feat(checkout): add Apple Pay option

Implement Apple Pay as alternative payment method alongside
credit card. Uses Stripe's PKPaymentRequest API.

Closes #234

This format is machine-parseable. It unlocks changelog generation and semantic versioning automation.

Subject line rules

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

  1. Max 72 characters. Git tooling truncates beyond that.
  2. Imperative mood. “add feature”, not “added feature”.
  3. No period at the end.
  4. Lowercase after the type. Conventional commits prefers lowercase subjects.
  5. Concise but descriptive.

Good subjects:

feat(auth): add two-factor authentication
fix(api): prevent duplicate order creation on network retry
refactor(db): extract query builder into separate class
perf(list): memoize expensive filter computation

Bad subjects:

update  (update what?)
fix bug  (which bug?)
wip  (who cares)
misc changes  (vague)

Body: why, not what

Writing “what I changed” in the body is redundant. The diff already shows that. The body exists to explain “why”.

Bad body:

Changed line 45 in UserService.swift.
Updated the validation logic.
Added a new parameter.

Good body:

The existing validation allowed empty emails to pass through,
causing NULL values in the database. This led to the bug #412
where notification emails failed silently.

Now requires @ symbol and non-empty domain.

With “why” and “impact”, the reviewer gets the context they need.

Atomic commits

One commit equals one logical change. Mixed commits are sloppy.

Bad (mixed):

feat: add user profile, fix login bug, update deps

Three different things in one commit. Revert is painful (you can’t revert just the login fix). Review is painful.

Good (atomic):

commit 1: feat(profile): add user profile page
commit 2: fix(auth): prevent login loop after token expiry
commit 3: chore(deps): update lodash to 4.17.21

Three separate commits. Each one is self-contained, revertable, reviewable.

Branch naming

Commit discipline goes hand in hand with branch naming:

feature/checkout-apple-pay
bugfix/email-validation-nil-check
hotfix/payment-timeout
chore/update-firebase-sdk

Branch type as prefix, kebab-case descriptive name. For GitHub or GitLab issue integration, add the issue number:

feature/234-apple-pay-checkout

Amend and squash

git commit --amend fixes the most recent commit. Typo in the message, forgotten file.

git rebase -i HEAD~5 lets you interactively rewrite multiple commits:
– reword: change the commit message
– squash: combine multiple commits
– fixup: squash but drop the message
– drop: delete the commit

When to squash: during PR review you accumulate five commits like “fix typo”, “fix another typo”, “actually fix”. Before merge, squash:

git rebase -i main
# combine with the "squash" marker

Result: one clean commit at PR merge time.

Enforcing with git hooks

For team-wide discipline, use git hooks:

commit-msg hook: checks commit message format.

#!/bin/sh
# .git/hooks/commit-msg

commit_regex='^(feat|fix|docs|style|refactor|perf|test|chore)(([a-z-]+))?: .{1,72}'

if ! grep -qE "$commit_regex" "$1"; then
    echo "Commit message format invalid."
    echo "Format: type(scope): subject"
    exit 1
fi

Tools like Husky (Node.js projects) or pre-commit (Python) make hook management painless.

Team onboarding

How to explain commit discipline to a new developer:

  1. Commit convention in the README. Link to the Conventional Commits spec.
  2. PR template. The body asks “how should a reviewer judge this?”.
  3. Pair commit writing. For the first week, have a senior review commit messages.
  4. Reject PRs with bad commits. Leave feedback: “please squash into meaningful commits”.

Three or four weeks in, the pattern becomes second nature.

Multi-commit PR vs single-commit

Two PR approaches:

Option A: one commit per PR. Squash on merge. Clean final history.

Option B: multi-commit PR. Each commit is a logical unit. Merge commit or rebase merge.

I prefer Option B on large PRs. Five to ten commits with a logical breakdown is much easier to review. On small PRs (under 100 lines), Option A is fine.

Tools: git log visualization

Ways to read git log:

git log --oneline
git log --graph --oneline --all
git log --pretty=format:'%h %s (%an)' --abbrev-commit

Visual tools: GitLens (VS Code), Fork, Tower. They visualize commit history nicely.

Wrap-up

Commit discipline is core to long-term team productivity. At first it feels like over-discipline; six months later, when you’re doing code archaeology, you understand its value.

Conventional Commits plus atomic commits plus a meaningful subject and body. Enforce with hooks, enforce in PR review, teach during onboarding. After a month of discipline, it becomes natural for everyone.

Have a project on this topic?

Leave a brief summary — I’ll get back to you within 24 hours.

Get in touch