Git Commit Messages

Write clearer Git commit messages using proven rules, Conventional Commits, and tools that support changelogs and releases.

Why Good Commit Messages Matter

A commit message is part of your project's long-term memory. It explains why a change exists and helps later readers understand what happened without opening every file diff first.

Good messages improve:

  • history review
  • git blame investigations
  • changelog generation
  • release notes
  • team communication

A weak message like fix stuff quickly becomes useless. A stronger message like fix(auth): handle expired refresh tokens gives useful context immediately.

Tip: Write commit messages for the person reading them months later, not just for the moment you type them.

The 7 Rules of a Great Commit Message

A widely used set of guidelines includes these rules:

  1. Separate subject from body with a blank line
  2. Keep the subject around 50 characters
  3. Capitalize the subject line
  4. Do not end the subject with a period
  5. Use the imperative mood
  6. Wrap the body near 72 characters
  7. Explain what and why in the body

Example:

Add validation for release tag names

Reject tag names that do not match the release policy. This prevents
invalid CI/CD releases from being published accidentally.

Imperative Mood

Subjects like Add, Fix, and Refactor read naturally after the phrase "If applied, this commit will...".

Good vs Bad Messages

Bad examples:

stuff
misc fixes
updated files

Better examples:

docs: clarify GitHub workflow steps
fix(ci): restore cache key for Node 22 builds
feat(api): add pagination to audit log endpoint

The better versions are specific and searchable.

Conventional Commits

Conventional Commits define a standard format that both people and tooling can understand.

Basic pattern:

type(scope): description

Common types include:

  • feat:
  • fix:
  • docs:
  • chore:
  • refactor:
  • test:
  • build:
  • ci:

Examples:

feat(auth): add SSO login flow
fix(ui): prevent navbar overlap on mobile
docs(git): add submodule troubleshooting section

Breaking Changes

A breaking change can be marked with ! or with a BREAKING CHANGE: note in the body.

feat(api)!: rename userId field to accountId

BREAKING CHANGE: Clients must send accountId instead of userId.

Note: Conventional Commits are most useful when the whole team follows the same format and a hook or CI job validates it.

Conventional Commits and Semantic Versioning

Conventional Commits connect well to semantic versioning:

  • MAJOR for breaking changes
  • MINOR for backward-compatible features
  • PATCH for backward-compatible fixes

A common mapping is:

  • feat: → minor bump
  • fix: → patch bump
  • BREAKING CHANGE: or ! → major bump

That makes commit history useful for release automation.

Helpful Tools

commitlint

commitlint checks whether commit messages follow your rules.

npm install --save-dev @commitlint/cli @commitlint/config-conventional

Example config:

cat > commitlint.config.js <<'EOF'
module.exports = { extends: ['@commitlint/config-conventional'] };
EOF

Test a message:

echo "fix: correct cache key" | npx commitlint

Teams often run this from a commit-msg hook.

semantic-release

semantic-release reads structured commit history and automates versioning and release notes.

npm install --save-dev semantic-release

A common pattern is:

  1. developers write Conventional Commits
  2. commitlint validates them
  3. CI runs semantic-release on main
  4. versioning and changelogs are generated automatically

What You Should Remember

Good commit messages make history easier to search, review, debug, and release. The seven classic rules improve clarity, while Conventional Commits provide a machine-readable format that works well with tools like commitlint and semantic-release. Better commit messages are a small habit with long-term payoff.

Test Your Understanding

Exercise

Exercise 1: Why commit messages matter

Which is the best reason strong commit messages improve long-term project maintenance?

Exercise

Exercise 2: Recognizing a Conventional Commit

Which option follows the Conventional Commits pattern from the lesson?

Exercise

Exercise 3: Linking commits to version bumps

According to the lesson, which type of change most directly signals a MAJOR semantic version bump?

Continue Learning

Explore Related Topics

Related Resources