Skip to content

Git Commit Conventions

How to write commit messages that are clear, searchable, and team-friendly. Commands: Git Command Set; local checks: Gitignore & Hooks.

See also: Git Command Set · Gitignore & Hooks · Collaboration


How to read this page

  1. Concepts — parts of a message and why conventions help
  2. Overview — common formats, type table, related commands
  3. Scenarios — real patterns with good/bad examples
  4. Symptom lookup — at the bottom

What a commit message is

Every git commit stores a message: a subject (usually line 1), optional body, and optional footers (trailers).

In plain terms: “Label this change so future-you and teammates know what changed and why.”

Effect: Messages live in history forever—git log, PRs, changelogs, and release tools all read them. Quality directly affects review and debugging.


Overview

Common format patterns

Style Best for Example subject Scenario
Imperative one-liner Solo repos, tiny changes Fix login redirect loop Minimal bar
Conventional Commits OSS, teams, automated changelog feat(auth): add OAuth callback Conventional
Subject + body Complex changes, explain why subject + blank line + paragraphs Multiline
Breaking change Incompatible API changes feat!: drop Node 16 or footer Breaking
Trailers Credit, co-authors, issues Closes #42 Trailers

Conventional Commits is widely used (Angular, Semantic Release, etc.). Teams may subset it (e.g. type: without scope)—clarity beats rigid compliance.

Conventional Commits: type cheat sheet

type Meaning Example subject
feat New feature feat: add export to CSV
fix Bug fix fix: handle null user id
docs Documentation only docs: update install steps
style Formatting, no logic change style: format with prettier
refactor Refactor, not feat/fix refactor: extract auth middleware
perf Performance perf: cache config parse result
test Tests test: add login API cases
build Build / dependencies build: bump webpack to 5.94
ci CI config ci: add matrix for Node 20/22
chore Maintenance chore: update gitignore
revert Revert a commit revert: feat(auth): add OAuth

Optional scope: feat(api): ..., fix(ui): ....
Breaking changes: ! after type (feat(api)!: ...) or BREAKING CHANGE: in footer.

Git commands used in this doc

Command Job Scenario Command set
git commit -m '...' One-line message Minimal git commit
git commit (no -m) Editor for multiline Multiline git commit
git commit --amend Edit last message Amend git commit
git commit --amend --no-edit Add files, keep message Amend git commit
git revert <hash> Undo via new commit After push git revert
git log --oneline Scan subjects Finding hash for revert git log
git commit --no-verify Skip commit hooks Hooks doc git commit

Subject-line principles (language-agnostic)

Principle Guideline
Mood Imperative (Add feature not Added feature)
Length ~50 characters on subject (soft limit; use body for detail)
Focus What changed; why in the body
Punctuation Usually no trailing period on subject
Scope One logical change per commit; avoid WIP on main

Scenario: minimal bar when there is no team standard

Typical uses: Personal repos, teams without CONTRIBUTING yet.

In plain terms: “Subject should explain the change in five seconds.”

# Good: specific verb + context
git commit -m "Fix crash when profile avatar is missing"

# Bad: too vague
git commit -m "update"
git commit -m "fix bug"
git commit -m "WIP"

# Bad: issue number alone
git commit -m "#123"

Scenario: Conventional Commits

Typical uses: Open source, automated changelogs, PR titles aligned with history.

git commit -m "feat(billing): support annual subscription"
git commit -m "fix: prevent double submit on checkout"
git commit -m "docs: add API rate limit section"
git commit -m "build: upgrade eslint to 9.x"

Effect: Tools can classify feat vs fix for releases; reviewers filter git log by type.

Note

Before contributing, read that repo’s CONTRIBUTING.md, PR template, or git log --oneline -20—match existing style first.


Scenario: multiline subject + body

Typical uses: Refactors, behavior changes—explain why, not a file list.

git commit -m "$(cat <<'EOF'
fix(auth): reject expired refresh tokens

Previously expired tokens still passed middleware when
clock skew was under 30s. Align with OAuth spec and
return 401 with clear error code.

Refs #8842
EOF
)"

Or use the editor:

git commit
# fix(auth): reject expired refresh tokens
#
# Previously expired tokens still passed...

Effect: git log shows subject; git show reveals body and footers.


Scenario: fix the last message (not pushed yet)

Typical uses: Typo in subject, forgot git add a file.

git commit --amend
git commit --amend -m "feat: add password reset email"

git add forgotten.ts
git commit --amend --no-edit

In plain terms: “Last commit still local—you may rewrite it.”

Effect: Commit hash changes—only safe if not pushed to a shared branch.

Warning

Do not amend commits already on shared remote branches unless the team explicitly allows it and coordinates force push. See After push.


Scenario: already pushed to the remote

Typical uses: Wrong message or need to undo, but commit is on origin/main.

Situation Prefer Example
Message wrong, code OK New commit or team-approved process Avoid empty “fix message” commits unless policy allows
Undo the whole change git revert (history preserved) git revert abc1234
Solo feature branch, no dependents rebase/amend + push --force-with-lease See Collaboration
git revert HEAD

# Avoid on shared main:
# git reset --hard HEAD~1 && git push --force

In plain terms: “Published history gets new commits, not erased rewrites.”


Scenario: breaking changes

Typical uses: Remove API, change defaults, major version bumps.

git commit -m "$(cat <<'EOF'
feat(api)!: remove legacy /v1 users endpoint

BREAKING CHANGE: clients must use /v2/users. v1 removed
after deprecation period noted in 2025-Q4 changelog.
EOF
)"

git commit -m "feat: switch default TLS to 1.3

BREAKING CHANGE: TLS 1.0/1.1 no longer supported."

Effect: Release tools may bump major version; users search logs for BREAKING CHANGE.


Scenario: trailers and issue links

Trailers are structured footer lines (Key: Value), common in OSS and GitHub/GitLab.

Trailer Purpose Example
Closes #123 / Fixes #123 Close issue on merge GitHub automation
Refs #123 Link only Partial work
Co-authored-by: Name <email> Co-author credit Pair programming, squash
Signed-off-by: Name <email> DCO sign-off Many foundation projects
Reviewed-by: Name <email> Record review Some enterprise policies
git commit -m "$(cat <<'EOF'
fix: validate upload MIME type

Co-authored-by: Alex Chen <alex@example.com>
Closes #456
EOF
)"

Typical uses:

  • Squash merge combining multiple authors’ trailers
  • IDE / AI tools auto-inserting footers—review before commit and drop lines the project forbids

Note

Allowed trailers depend on the target repo’s CONTRIBUTING / DCO—this page teaches common patterns, not project policy.


Scenario: what lands after a PR merge

Typical uses: GitHub/GitLab merge produces merge or squash commits.

Merge style Typical log Message tip
Merge commit Merge pull request #99 ... Branch commits preserved
Squash merge Single feat: ... (#99) PR title often becomes final subject—write it well upfront
Rebase merge Linear commits from branch Each commit should stay atomic

In plain terms: “On squash merge, PR title ≈ future commit subject.”


Scenario: working with commit-msg hooks

Teams validate format in a commit-msg hook (required prefix, non-empty subject). Examples: Gitignore & Hooks — commit-msg.

Effect: Bad messages fail locally before push.

Warning

Do not habitually use git commit --no-verify; fix the message or follow team exceptions.


Scenario: good vs bad examples

Bad Good Why
update code fix(ui): prevent modal focus trap Specific, searchable
fix bug and add feature Split into two commits One intent per commit
Fixed the thing. fix: handle timeout in payment webhook Imperative, no period
Body is 200 lines of diff Body explains why and trade-offs Diff is in git show
feat: mixed with unrelated deps bump Separate build: commit Easier revert / bisect

Quick lookup: symptom → suggestion

Symptom Suggestion
Blank on what to write Subject: what + where; body: why
Change spans many modules Split commits or pick primary scope
Forgot a file after commit Not pushed → git add + commit --amend --no-edit
Typo on pushed main No amend on main; revert or follow-up
Project has CONTRIBUTING Follow project docs; this page is general reference
Hook rejects commit Read error, fix format; see hooks doc
Co-authors needed Use Co-authored-by; align with platform merge docs

More commands: Git Command Set — git commit.