Files
gh-jeanluciano-quaestor-src…/skills/reviewing-and-shipping/COMMITS.md
2025-11-29 18:50:24 +08:00

24 KiB

Intelligent Commit Generation

This file describes strategies for analyzing changes and generating high-quality, atomic commits.

Commit Generation Overview

Commit Generation Process:
  1. Change Analysis: Understand what changed and why
  2. Change Grouping: Group related changes logically
  3. Commit Classification: Determine commit type
  4. Scope Extraction: Extract scope from context
  5. Message Generation: Create clear, conventional messages
  6. Specification Integration: Link to specifications
  7. Commit Creation: Create atomic commits

Goals:
  - Atomic: One logical change per commit
  - Clear: Easy to understand what changed
  - Conventional: Follow conventional commit format
  - Traceable: Link to specifications and context

Change Analysis

Understanding Changes

Discovery Phase:

# Get all changed files
git status --short
git diff --stat

# Analyze uncommitted changes
git diff
git diff --cached  # Staged changes

# Compare with main branch
git diff main...HEAD

# Get file-level changes
git diff --name-only
git diff --name-status  # Include status (A/M/D)

Change Classification:

Change Types:
  Added (A): New files created
  Modified (M): Existing files changed
  Deleted (D): Files removed
  Renamed (R): Files renamed/moved
  Copied (C): Files copied

Example Output:
  A  src/auth/jwt.py           # New JWT module
  M  src/auth/service.py       # Modified auth service
  A  tests/test_jwt.py         # New tests
  M  docs/api.md               # Updated docs
  M  README.md                 # Updated readme

Change Grouping Strategy

Group by Module:

Module-Based Grouping:
  Group 1 - Auth Module:
    - src/auth/jwt.py (new)
    - src/auth/service.py (modified)
    - tests/test_jwt.py (new)

  Group 2 - Documentation:
    - docs/api.md (modified)
    - README.md (modified)

Result: 2 commits (module, docs)

Group by Feature:

Feature-Based Grouping:
  Group 1 - JWT Implementation:
    - src/auth/jwt.py (new)
    - src/auth/service.py (modified - added JWT calls)

  Group 2 - JWT Tests:
    - tests/test_jwt.py (new)

  Group 3 - JWT Documentation:
    - docs/api.md (modified - JWT endpoints)
    - README.md (modified - JWT setup)

Result: 3 commits (impl, test, docs)

Group by Type:

Type-Based Grouping:
  Group 1 - Feature Changes:
    - src/auth/jwt.py (new feature)
    - src/auth/service.py (feature addition)

  Group 2 - Test Changes:
    - tests/test_jwt.py (tests for feature)

  Group 3 - Documentation Changes:
    - docs/api.md (document feature)
    - README.md (document feature)

Result: 3 commits (feat, test, docs)

Hybrid Strategy (Recommended):

Strategy: Feature-based with Test Inclusion

Rule: Include tests with implementation
  - Implementation + its tests = one commit
  - Documentation = separate commit
  - Refactoring = separate commit

Example:
  Commit 1: feat(auth): implement JWT generation
    - src/auth/jwt.py (JWT generation code)
    - tests/test_jwt.py (JWT generation tests)

  Commit 2: feat(auth): implement JWT validation
    - src/auth/jwt.py (JWT validation code)
    - tests/test_jwt.py (JWT validation tests)

  Commit 3: docs(auth): document JWT implementation
    - docs/api.md (JWT API documentation)
    - README.md (JWT setup instructions)

Benefits:
  - Atomic: Each commit is a complete logical change
  - Testable: Tests included with implementation
  - Clear: Easy to understand what each commit does
  - Revertable: Can revert entire feature cleanly

Commit Classification

Conventional Commit Types

Type Definitions:

feat: New feature for the user
  When:
    - Adding new functionality
    - New API endpoints
    - New user-facing features
    - New capabilities

  Examples:
    - "feat(auth): implement JWT authentication"
    - "feat(api): add user profile endpoint"
    - "feat(payments): integrate Stripe checkout"
    - "feat(search): add full-text search"

fix: Bug fix for the user
  When:
    - Fixing broken functionality
    - Correcting errors
    - Resolving issues
    - Patching vulnerabilities

  Examples:
    - "fix(auth): prevent token expiry race condition"
    - "fix(api): handle null response in user endpoint"
    - "fix(validation): correct email regex pattern"
    - "fix(db): resolve connection timeout issue"

docs: Documentation changes only
  When:
    - Updating documentation
    - Adding code comments
    - README changes
    - API documentation
    - Examples and guides

  Examples:
    - "docs(api): update OpenAPI specifications"
    - "docs(readme): add installation instructions"
    - "docs(auth): document OAuth flow"
    - "docs: add contributing guidelines"

refactor: Code change that neither fixes nor adds feature
  When:
    - Restructuring code
    - Improving code quality
    - No behavior change
    - Performance optimization (internal)

  Examples:
    - "refactor(parser): simplify token extraction"
    - "refactor(utils): extract common validation logic"
    - "refactor(auth): improve session management structure"
    - "refactor: apply DRY principle to reducers"

test: Adding or updating tests
  When:
    - Adding missing tests
    - Improving test coverage
    - Fixing failing tests
    - Adding test utilities

  Examples:
    - "test(auth): add coverage for edge cases"
    - "test(api): add integration tests for user endpoints"
    - "test(utils): add unit tests for validators"
    - "test: increase coverage to 85%"

perf: Performance improvements
  When:
    - Optimizing performance
    - Reducing load times
    - Improving efficiency
    - User-visible performance gains

  Examples:
    - "perf(query): optimize database query for large datasets"
    - "perf(render): add memoization to reduce re-renders"
    - "perf(cache): implement Redis caching layer"
    - "perf(api): reduce response time by 40%"

style: Code style changes (formatting, naming)
  When:
    - Formatting changes
    - Whitespace fixes
    - Naming improvements
    - No code logic change

  Examples:
    - "style(auth): apply consistent naming conventions"
    - "style: format code with prettier"
    - "style(api): fix indentation"
    - "style: remove trailing whitespace"

chore: Maintenance tasks (dependencies, config)
  When:
    - Dependency updates
    - Configuration changes
    - Build script updates
    - Tool configuration

  Examples:
    - "chore(deps): update dependencies to latest versions"
    - "chore(config): update linting rules"
    - "chore: update CI/CD pipeline"
    - "chore(deps): bump axios from 0.21.0 to 0.21.1"

build: Build system or external dependency changes
  When:
    - Build configuration changes
    - Build tool updates
    - Compilation changes

  Examples:
    - "build: update webpack configuration"
    - "build(docker): optimize Docker image size"
    - "build: add source maps for production"

ci: CI/CD configuration changes
  When:
    - CI pipeline changes
    - GitHub Actions updates
    - Deployment config changes

  Examples:
    - "ci: add automated testing to PR workflow"
    - "ci: update deployment pipeline"
    - "ci(github): add code coverage reporting"

revert: Reverting a previous commit
  When:
    - Rolling back changes
    - Undoing a commit

  Examples:
    - "revert: revert 'feat(auth): implement JWT'"
    - "revert: undo performance optimization"

Type Selection Algorithm

Decision Tree:

Is this a new feature for users?
  Yes → feat

Does this fix a bug or error?
  Yes → fix

Does this change documentation only?
  Yes → docs

Does this add or improve tests only?
  Yes → test

Does this improve performance (user-visible)?
  Yes → perf

Does this restructure code without behavior change?
  Yes → refactor

Does this change only formatting/style?
  Yes → style

Does this update dependencies or config?
  Yes → chore

Does this change build system?
  Yes → build

Does this change CI/CD?
  Yes → ci

Scope Extraction

Determining Scope

From File Paths:

Path Analysis:
  src/auth/jwt.py → scope: auth
  src/api/users.py → scope: api
  src/api/posts.py → scope: api
  src/utils/validation.py → scope: utils
  src/database/migrations/ → scope: database
  tests/test_auth.py → scope: auth (test relates to auth)
  docs/api.md → scope: api (docs relate to api)
  README.md → scope: none (project-level)

Rules:
  - Use first directory after src/ as scope
  - For tests, use what they're testing
  - For docs, use what they're documenting
  - For project-level, omit scope

From Specification:

Specification-Based Scope:
  Spec ID: spec-feature-auth-001
    → scope: auth

  Spec ID: spec-refactor-api-endpoints
    → scope: api

  Spec Title: "User Profile Management"
    → scope: profile

  Spec Title: "Payment Integration"
    → scope: payments

From Change Context:

Context-Based Scope:
  User authentication changes → auth
  API endpoint changes → api
  Database changes → database or db
  UI component changes → ui or components
  Utility function changes → utils
  Configuration changes → config
  Testing changes → test (or omit)

Multiple Scopes

Handling Multiple Scopes:

Option 1: Separate Commits (Recommended)
  Changes in auth/ and api/
  → Commit 1: feat(auth): implement JWT
  → Commit 2: feat(api): add JWT middleware

Option 2: Multiple Scopes
  Changes in auth/ and api/
  → Commit: feat(auth,api): implement JWT authentication

Option 3: Broader Scope
  Changes in auth/ and api/ (tightly coupled)
  → Commit: feat: implement JWT authentication

Recommendation:
  - Prefer separate commits (Option 1) for clarity
  - Use multiple scopes if changes must be together
  - Use no scope for system-wide changes

Message Generation

Conventional Commit Format

Format Structure:

Format: type(scope): description

[optional body]

[optional footer]

Rules:
  - type: lowercase (feat, fix, docs, etc.)
  - scope: lowercase, optional, in parentheses
  - description: lowercase, imperative mood, no period
  - body: optional, explain "why" not "what"
  - footer: optional, breaking changes, references

Examples:
  feat(auth): implement JWT refresh tokens
  fix(api): handle null response in user endpoint
  docs(readme): add installation instructions
  refactor(parser): simplify token extraction logic

Description Guidelines

Good Descriptions:

Characteristics:
  - Imperative mood: "add" not "added" or "adds"
  - Lowercase: "implement feature" not "Implement Feature"
  - Concise: Under 72 characters
  - Clear: Describes what changed
  - No period: "add feature" not "add feature."

Examples:
  ✅ "implement JWT refresh tokens"
  ✅ "handle null response in user endpoint"
  ✅ "add coverage for edge cases"
  ✅ "update OpenAPI specifications"
  ✅ "simplify token extraction logic"

  ❌ "added JWT stuff"
  ❌ "Fixed a bug."
  ❌ "Update"
  ❌ "Implemented the JWT refresh token functionality for better security"
  ❌ "auth changes"

Body Content

When to Include Body:

Include Body When:
  - Need to explain "why" the change was made
  - Breaking changes need explanation
  - Complex changes need context
  - Alternatives were considered
  - Specification provides context

Omit Body When:
  - Description is self-explanatory
  - Simple, straightforward change
  - No additional context needed

Body Examples:

Example 1: With Context
  feat(auth): implement JWT refresh tokens

  Adds refresh token rotation for improved security.
  Access tokens expire after 15 minutes, refresh tokens after 7 days.

  This approach prevents token theft and improves security posture
  while maintaining good user experience.

  Implements spec-feature-auth-001 phase 2.

Example 2: Breaking Change
  feat(api): change user endpoint response format

  BREAKING CHANGE: User endpoint now returns nested profile object
  instead of flat structure.

  Old format: { id, name, email, bio }
  New format: { id, profile: { name, email, bio } }

  This improves consistency with other endpoints and supports
  future profile expansion.

Example 3: Bug Fix Context
  fix(auth): prevent token expiry race condition

  Users were occasionally logged out unexpectedly when token refresh
  happened simultaneously with API calls. Added mutex to ensure only
  one refresh happens at a time.

  Fixes issue reported in user feedback.

Footer Types:

Breaking Changes:
  BREAKING CHANGE: Description of breaking change

  Example:
    feat(api): redesign authentication endpoints

    BREAKING CHANGE: /auth/login endpoint now requires email instead of username

Issue References:
  Closes #123
  Fixes #456
  Resolves #789

  Example:
    fix(api): handle timeout in user fetch

    Fixes #123

Specification References:
  Spec: spec-feature-auth-001

  Example:
    feat(auth): implement JWT tokens

    Implements spec-feature-auth-001 phase 2

Multiple Footers:
  Example:
    feat(api): add rate limiting

    BREAKING CHANGE: API now returns 429 status when rate limit exceeded
    Closes #234
    Spec: spec-feature-api-ratelimit

Atomic Commit Strategy

Principles of Atomic Commits

Atomic Commit Principles:
  1. Single Logical Change: One commit = one complete change
  2. Independently Revertable: Can undo without breaking things
  3. Includes Tests: Tests for the change included
  4. Passes Tests: All tests pass after commit
  5. Clear Purpose: Easy to understand what and why

Benefits:
  - Easy to review: Focused, clear changes
  - Easy to revert: No tangled dependencies
  - Clear history: Understandable git log
  - Better debugging: git bisect works well
  - Selective cherry-pick: Can pick specific changes

Good Atomic Commits

Examples:

Example 1: Feature with Tests
  Commit: feat(auth): implement JWT generation
  Files:
    - src/auth/jwt.py (add generateToken function)
    - tests/test_jwt.py (add tests for generateToken)

  Why Atomic:
    - One logical change: JWT generation
    - Includes tests
    - Can be reverted cleanly
    - Tests pass

Example 2: Bug Fix with Test
  Commit: fix(api): handle null user in response
  Files:
    - src/api/users.py (add null check)
    - tests/test_users.py (add test for null case)

  Why Atomic:
    - One logical change: null handling
    - Includes regression test
    - Can be reverted
    - Tests pass

Example 3: Documentation Update
  Commit: docs(api): document authentication endpoints
  Files:
    - docs/api.md (add auth section)
    - README.md (add auth setup)

  Why Atomic:
    - One logical change: auth documentation
    - Related docs together
    - Can be reverted
    - No code changes to break

Example 4: Refactoring
  Commit: refactor(auth): extract UserValidator class
  Files:
    - src/auth/service.py (extract validation)
    - src/auth/validator.py (new validator class)
    - tests/test_validator.py (update tests)

  Why Atomic:
    - One logical change: extract validator
    - No behavior change
    - Tests updated
    - Tests pass

Bad Non-Atomic Commits

Anti-Patterns:

Example 1: Too Many Changes
  Commit: feat: add authentication and fix bugs and update docs
  Files:
    - src/auth/ (new auth system)
    - src/api/users.py (unrelated bug fix)
    - src/database/ (schema change)
    - docs/ (documentation)
    - tests/ (various tests)

  Why Bad:
    - Multiple unrelated changes
    - Can't revert one without affecting others
    - Hard to review
    - Unclear purpose

  Fix: Split into 4-5 commits:
    - feat(auth): implement authentication system
    - fix(api): correct user endpoint bug
    - feat(database): add user roles schema
    - test(auth): add authentication tests
    - docs(auth): document authentication

Example 2: Incomplete Change
  Commit: feat(auth): implement JWT (WIP)
  Files:
    - src/auth/jwt.py (incomplete implementation)
    - Tests don't pass

  Why Bad:
    - Not complete
    - Tests failing
    - Not in working state
    - "WIP" in commit message

  Fix: Complete implementation before committing

Example 3: Mixed Concerns
  Commit: update code
  Files:
    - src/auth/jwt.py (feature addition)
    - src/api/users.py (formatting)
    - README.md (typo fix)

  Why Bad:
    - Unrelated changes
    - Vague commit message
    - Hard to understand purpose

  Fix: Split into 3 commits:
    - feat(auth): add JWT token refresh
    - style(api): format users endpoint
    - docs(readme): fix typo in setup section

Specification Integration

Linking Commits to Specifications

Specification References:

In Commit Message Body:
  feat(auth): implement JWT refresh tokens

  Implements spec-feature-auth-001 phase 2: Token Management

In Commit Message Footer:
  feat(auth): implement JWT validation

  Spec: spec-feature-auth-001

In Both:
  feat(auth): implement session management

  Adds session storage with Redis for scalability.
  Users can maintain sessions across devices.

  Implements spec-feature-auth-001 phase 3
  Spec: spec-feature-auth-001

Tracking Implementation Progress

Update Specification File:

After Each Commit:
  1. Update specification file
  2. Mark completed phases/tasks
  3. Add commit reference
  4. Update completion evidence

Example Specification Update:
  ## Implementation Progress

  ### Phase 1: JWT Generation ✅
  - Status: Completed
  - Commit: abc123 "feat(auth): implement JWT generation"
  - Date: 2025-10-19

  ### Phase 2: JWT Validation ✅
  - Status: Completed
  - Commit: def456 "feat(auth): implement JWT validation"
  - Date: 2025-10-19

  ### Phase 3: Session Management 🚧
  - Status: In Progress
  - Commit: -
  - Date: -

Commit Hash References

In Specification:

Track Commits in Spec:
  ## Commits
  - abc123: feat(auth): implement JWT generation
  - def456: feat(auth): implement JWT validation
  - ghi789: test(auth): add comprehensive JWT tests
  - jkl012: docs(auth): document JWT implementation

Benefits:
  - Traceability: Link spec to implementation
  - Evidence: Show what was completed
  - Review: Easy to find relevant code
  - History: Track implementation timeline

Commit Generation Examples

Example 1: Authentication Feature

Changes:

Modified Files:
  - src/auth/jwt.py (new file - 120 lines)
  - src/auth/service.py (modified - added JWT integration)
  - tests/test_jwt.py (new file - 80 lines)
  - tests/test_auth_service.py (modified - added JWT tests)
  - docs/api.md (modified - documented JWT endpoints)
  - README.md (modified - added JWT setup)

Generated Commits:

Commit 1: feat(auth): implement JWT generation and signing
  Files:
    - src/auth/jwt.py (JWT generation, signing)
    - tests/test_jwt.py (generation tests)

  Message:
    feat(auth): implement JWT generation and signing

    Adds JWT token generation with HS256 signing algorithm.
    Tokens include user ID, expiry, and custom claims.

    Implements spec-feature-auth-001 phase 1

Commit 2: feat(auth): implement JWT validation and verification
  Files:
    - src/auth/jwt.py (JWT validation, verification)
    - tests/test_jwt.py (validation tests)

  Message:
    feat(auth): implement JWT validation and verification

    Adds JWT token validation including expiry check,
    signature verification, and claim extraction.

    Implements spec-feature-auth-001 phase 2

Commit 3: feat(auth): integrate JWT into authentication service
  Files:
    - src/auth/service.py (JWT integration)
    - tests/test_auth_service.py (integration tests)

  Message:
    feat(auth): integrate JWT into authentication service

    Updates authentication service to use JWT tokens
    for user sessions. Replaces session-based auth.

    Implements spec-feature-auth-001 phase 3

Commit 4: docs(auth): document JWT authentication
  Files:
    - docs/api.md (JWT API documentation)
    - README.md (JWT setup instructions)

  Message:
    docs(auth): document JWT authentication

    Adds documentation for JWT authentication including:
    - API endpoints for token generation
    - Token format and claims
    - Setup instructions

    Spec: spec-feature-auth-001

Example 2: Bug Fix

Changes:

Modified Files:
  - src/api/users.py (null check added)
  - tests/test_users.py (regression test added)

Generated Commit:

Commit: fix(api): handle null user in response

  Files:
    - src/api/users.py (add null check)
    - tests/test_users.py (add regression test)

  Message:
    fix(api): handle null user in response

    API was returning 500 error when user not found.
    Now returns 404 with proper error message.

    Added regression test to prevent future occurrence.

    Fixes #234

Example 3: Refactoring

Changes:

Modified Files:
  - src/auth/service.py (extract validator)
  - src/auth/validator.py (new validator class)
  - tests/test_validator.py (validator tests)
  - tests/test_auth_service.py (update to use validator)

Generated Commits:

Commit 1: refactor(auth): extract UserValidator class
  Files:
    - src/auth/validator.py (new validator class)
    - tests/test_validator.py (validator tests)

  Message:
    refactor(auth): extract UserValidator class

    Extracts user validation logic into separate class
    for better separation of concerns and testability.

    No behavior change.

Commit 2: refactor(auth): use UserValidator in auth service
  Files:
    - src/auth/service.py (use new validator)
    - tests/test_auth_service.py (update tests)

  Message:
    refactor(auth): use UserValidator in auth service

    Updates auth service to use new UserValidator class.
    Removes duplicate validation logic.

    No behavior change.

Git Best Practices

Commit Workflow

# 1. Review changes
git status
git diff

# 2. Stage related changes
git add src/auth/jwt.py tests/test_jwt.py

# 3. Create commit with message
git commit -m "feat(auth): implement JWT generation" \
           -m "Adds JWT token generation with HS256 signing."

# 4. Repeat for next logical group
git add src/auth/service.py tests/test_auth_service.py
git commit -m "feat(auth): integrate JWT into auth service"

# 5. Push when ready
git push

Interactive Staging

# Stage specific hunks interactively
git add -p src/auth/service.py

# This allows selecting specific changes within a file
# Useful when file has multiple unrelated changes

Amending Commits

# Add forgotten file to last commit
git add tests/test_missing.py
git commit --amend --no-edit

# Change last commit message
git commit --amend -m "feat(auth): implement JWT tokens"

# WARNING: Only amend commits not yet pushed!

Commit Message Validation

# Use commitlint to validate messages
npm install -g @commitlint/cli @commitlint/config-conventional

# Validate commit message
echo "feat(auth): add JWT" | commitlint

# Set up git hook
# In .git/hooks/commit-msg
#!/bin/sh
npx commitlint --edit $1

Common Commit Scenarios

Scenario 1: Feature with Multiple Components

Situation: Authentication feature with JWT, session, and docs

Strategy: Separate by component
  Commit 1: feat(auth): implement JWT token management
  Commit 2: feat(auth): add session storage with Redis
  Commit 3: test(auth): add authentication test suite
  Commit 4: docs(auth): document authentication system

Why: Each component is independent and atomic

Scenario 2: Bug Fix Affecting Multiple Areas

Situation: Null handling bug in API and database layer

Strategy: Single commit if tightly coupled
  Commit: fix: handle null values in user data

  Files:
    - src/api/users.py (null check)
    - src/database/queries.py (null handling)
    - tests/test_users.py (regression tests)

Why: Changes are interdependent, must be together

Scenario 3: Large Refactoring

Situation: Refactor entire authentication module

Strategy: Multiple small commits
  Commit 1: refactor(auth): extract UserValidator
  Commit 2: refactor(auth): extract TokenManager
  Commit 3: refactor(auth): simplify AuthService
  Commit 4: refactor(auth): update tests for new structure

Why: Easier to review, revert if needed, understand changes

Scenario 4: Dependency Update

Situation: Update dependencies and fix breaking changes

Strategy: Separate commits
  Commit 1: chore(deps): update axios to v1.0
  Commit 2: fix(api): update API calls for axios v1.0

Why: Dependency update separate from code changes

Comprehensive guide to intelligent commit generation with conventional commits and atomic strategy