# 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 ``` (): [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: ```bash 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) --- ## Footer (Optional) 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 Co-authored-by: John Smith ``` ### Other Footers ``` Reviewed-by: Name Signed-off-by: Name Acked-by: Name 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 ``` ### Example 6: Multiple Related Changes ``` 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 ❌ ``` --- ## Real-World Examples from Popular Projects ### 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: ```bash npm install -g commitizen git cz ``` ### Commitlint Lint commit messages: ```bash npm install --save-dev @commitlint/cli @commitlint/config-conventional ``` ### Husky Git hooks to enforce commit message format: ```bash npm install --save-dev husky npx husky add .husky/commit-msg 'npx --no -- commitlint --edit ${1}' ``` --- ## Resources **Specifications:** - Conventional Commits: https://www.conventionalcommits.org/ - Git Commit Guidelines: https://git-scm.com/book/en/v2/Distributed-Git-Contributing-to-a-Project **Tools:** - Commitizen: https://github.com/commitizen/cz-cli - Commitlint: https://commitlint.js.org/ **Further Reading:** - "How to Write a Git Commit Message": https://chris.beams.io/posts/git-commit/ - Angular Commit Guidelines: https://github.com/angular/angular/blob/main/CONTRIBUTING.md#commit