Files
gh-jezweb-claude-skills-ski…/references/commit-message-guide.md
2025-11-30 08:25:07 +08:00

11 KiB

Commit Message Guide

A comprehensive guide to writing clear, consistent, and maintainable commit messages using the Conventional Commits format.


Why Good Commit Messages Matter

  • Documentation: Git history becomes a changelog
  • Code Review: Easier to understand what changed and why
  • Debugging: Quickly find when bugs were introduced
  • Automation: Enables automatic changelog generation and versioning
  • Professionalism: Shows attention to detail and respect for maintainers

Conventional Commits Format

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

[optional body]

[optional footer(s)]

Components

Type (required): Category of change Scope (optional): What section of codebase is affected Subject (required): Brief description of change Body (optional): Detailed explanation Footer (optional): Issue references, breaking changes


Types

Primary Types

feat: New feature for the user

feat(auth): add OAuth2 support for Google and GitHub

fix: Bug fix for the user

fix(api): resolve memory leak in worker shutdown

docs: Documentation changes only

docs(readme): update installation instructions for v2.0

style: Code style changes (formatting, missing semicolons, etc.)

style(components): format code with Prettier

refactor: Code change that neither fixes bug nor adds feature

refactor(auth): extract middleware to separate module

perf: Performance improvement

perf(database): add index to user_id column

test: Adding or updating tests

test(auth): add OAuth flow integration tests

Supporting Types

build: Changes to build system or dependencies

build(deps): upgrade React to v18.2.0

ci: CI configuration changes

ci(github): add automated release workflow

chore: Other changes that don't modify src or test files

chore(deps): update dev dependencies

revert: Revert a previous commit

revert: feat(auth): add OAuth2 support

This reverts commit abc123def456.

Subject Line Rules

The 7 Rules

  1. Limit to 50 characters (hard limit: 72)
  2. Use imperative mood ("Add" not "Added" or "Adds")
  3. Capitalize first word after the colon
  4. Don't end with punctuation
  5. Focus on WHAT changed (body explains WHY)
  6. Be specific but concise
  7. Start with type (if using Conventional Commits)

Examples

Good:

feat(api): add user authentication endpoint
fix(ui): resolve button alignment on mobile
docs(contributing): clarify PR submission process
refactor(utils): simplify date formatting logic

Bad:

Fixed stuff                           # Too vague
Added new feature to the authentication system that allows users to login with OAuth  # Too long
updated code                          # Not specific, wrong tense
feat(api): add user authentication.   # Don't end with period
Feat(api): add auth                   # Don't capitalize type

Optional Scope

The scope provides context about what part of the codebase changed.

Common Scopes

feat(auth): ...         # Authentication
feat(api): ...          # API layer
feat(ui): ...           # User interface
feat(database): ...     # Database
feat(docs): ...         # Documentation
feat(tests): ...        # Tests
fix(deps): ...          # Dependencies
build(webpack): ...     # Build tooling

Project-Specific Scopes

Check the project's recent commits for conventions:

git log --oneline -20

When to Omit Scope

Scope is optional. Omit when:

  • Change affects multiple areas
  • Project doesn't use scopes
  • Scope would be too generic
feat: add dark mode support
docs: update README

Body (Optional)

The body provides detailed explanation of WHAT and WHY (code shows HOW).

Rules

  • Separate from subject with blank line
  • Wrap at 72 characters per line
  • Explain motivation and context
  • Contrast with previous behavior
  • Use bullet points for multiple points

Example

feat(api): add rate limiting to authentication endpoints

Users can now make up to 100 authentication attempts per hour
per IP address. This prevents brute force attacks while allowing
legitimate users to retry failed login attempts.

Implementation details:
- Uses Redis for distributed rate limiting
- Configurable via RATE_LIMIT_MAX environment variable
- Returns 429 status with Retry-After header when exceeded
- Resets hourly at top of the hour

Previous behavior allowed unlimited attempts, which was identified
as a security vulnerability in audit #456.

When to Include Body

Include a body when:

  • Change is complex or non-obvious
  • Design decisions need explanation
  • Previous behavior needs context
  • Multiple related changes in one commit
  • Security or performance implications

When to Skip Body

Skip the body when:

  • Change is self-explanatory
  • Subject line tells the complete story
  • Trivial changes (typos, formatting)

Footers provide metadata about the commit.

Breaking Changes

Use BREAKING CHANGE: footer for breaking changes:

feat(api)!: change authentication endpoint path

BREAKING CHANGE: The authentication endpoint has moved from
/api/auth to /api/v2/auth. Update your API calls accordingly.

Migration guide available at docs/migration/v2.md

Note the ! after the type indicates a breaking change.

Issue References

Link issues using keywords for automatic closing:

fix(ui): resolve mobile layout issues

Fixes #123
Closes #456, #789
Relates to #234

Closing Keywords:

  • Closes #123
  • Fixes #123
  • Resolves #123
  • Also: close, fix, resolve (case insensitive)

Co-authored-by

Credit co-authors:

feat(api): add GraphQL support

Co-authored-by: Jane Doe <jane@example.com>
Co-authored-by: John Smith <john@example.com>

Other Footers

Reviewed-by: Name <email>
Signed-off-by: Name <email>
Acked-by: Name <email>
See-also: #123

Complete Examples

Example 1: Simple Feature

feat(ui): add dark mode toggle

Adds a toggle button in settings to switch between light and dark
themes. User preference is saved to localStorage and persists
across sessions.

Closes #234

Example 2: Bug Fix

fix(api): prevent race condition in cache invalidation

The cache invalidation logic wasn't thread-safe, causing occasional
race conditions when multiple workers tried to invalidate the same
key simultaneously.

Solution:
- Added mutex locks around the critical section
- Implemented timeout for lock acquisition (5s)
- Added retry logic with exponential backoff
- Updated tests to verify thread-safety

Fixes #456

Example 3: Breaking Change

feat(api)!: migrate to TypeScript and update endpoint contracts

BREAKING CHANGE: All API endpoints now return ISO 8601 date
strings instead of Unix timestamps. Update client code to parse
dates accordingly.

Additionally, authentication now requires JWT tokens in the
Authorization header instead of session cookies.

Migration guide: docs/migration/v3.md

Closes #567

Example 4: Refactoring

refactor(auth): extract middleware to separate module

No functional changes, but auth logic is now easier to test and
maintain. Consolidated duplicate code from 5 route handlers into
reusable middleware functions.

Files affected:
- New: middleware/authenticate.js
- Updated: routes/*.js (5 files)
- Tests: tests/middleware/auth.test.js

Relates to #301 (technical debt epic)

Example 5: Documentation

docs(api): add examples for authentication flows

Added code examples for:
- Basic authentication with username/password
- OAuth2 flow with Google
- API key authentication
- JWT token refresh

Examples include curl commands and JavaScript fetch() snippets.

Closes #678
fix(auth): resolve multiple OAuth edge cases

- Handle expired refresh tokens gracefully
- Prevent account linking when email doesn't match
- Add rate limiting to token refresh endpoint
- Log failed OAuth attempts for security monitoring

Each issue was related to OAuth implementation and fixing them
separately would have caused merge conflicts.

Fixes #123, #456, #789

Tips for Writing Good Commit Messages

Do:

Write in imperative mood ("Add" not "Added")

feat: add user profile page

Be specific about what changed

fix(api): resolve timeout in user search endpoint

Explain WHY in the body

refactor(db): switch to connection pooling

The previous approach created a new connection for each request,
which caused performance issues under load. Connection pooling
reduces overhead and improves response times by 40%.

Use the body for complex changes Reference issues and PRs Follow project conventions

Don't:

Use past tense

feat: added user profile page  ❌

Be vague

fix: bug fix  ❌
update: changes  ❌

Write novels in the subject line

feat(api): add new user authentication endpoint with OAuth2 support for Google and GitHub that also includes rate limiting  ❌

Skip the type (if project uses Conventional Commits)

Add user profile page  ❌

Use abbreviations or jargon unnecessarily

fix(db): rm dup recs via opt idx  ❌

Combine unrelated changes in one commit

feat: add dark mode, fix typo in README, update dependencies  ❌

React

feat(react-dom): Add support for CSS Layers

Implements support for @layer, enabling better CSS encapsulation.

Fixes #24556

Node.js

doc: add missing types to request and response

Added TypeScript type definitions for several Request and Response
methods that were previously missing from the declarations.

Fixes: #12345
Refs: #67890

Kubernetes

fix: prevent pod creation with invalid security context

Adds validation to reject pods with both `runAsUser: 0` and
`allowPrivilegeEscalation: false`, which is an invalid combination.

Closes #12345

Commit Message Checklist

Before committing, verify:

  • Type is correct (feat, fix, docs, etc.)
  • Subject line under 50 characters (max 72)
  • Imperative mood ("Add" not "Added")
  • First word capitalized
  • No period at end
  • Body explains WHY (if needed)
  • Body wrapped at 72 characters
  • Blank line between subject and body
  • Issues referenced in footer
  • Breaking changes noted with BREAKING CHANGE:
  • Follows project conventions

Tools & Automation

Commitizen

Interactive tool for writing commits:

npm install -g commitizen
git cz

Commitlint

Lint commit messages:

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

Husky

Git hooks to enforce commit message format:

npm install --save-dev husky
npx husky add .husky/commit-msg 'npx --no -- commitlint --edit ${1}'

Resources

Specifications:

Tools:

Further Reading: