alinaqi

commit-hygiene

457
37
# Install this skill:
npx skills add alinaqi/claude-bootstrap --skill "commit-hygiene"

Install specific skill from multi-skill repository

# Description

Atomic commits, PR size limits, commit thresholds, stacked PRs

# SKILL.md


name: commit-hygiene
description: Atomic commits, PR size limits, commit thresholds, stacked PRs


Commit Hygiene Skill

Load with: base.md

Purpose: Keep commits atomic, PRs reviewable, and git history clean. Advise when it's time to commit before changes become too large.


Core Philosophy

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  ATOMIC COMMITS                                                  β”‚
β”‚  ─────────────────────────────────────────────────────────────  β”‚
β”‚  One logical change per commit.                                  β”‚
β”‚  Each commit should be self-contained and deployable.            β”‚
β”‚  If you need "and" to describe it, split it.                     β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  SMALL PRS WIN                                                   β”‚
β”‚  ─────────────────────────────────────────────────────────────  β”‚
β”‚  < 400 lines changed = reviewed in < 1 hour                      β”‚
β”‚  > 1000 lines = likely rubber-stamped or abandoned               β”‚
β”‚  Smaller PRs = faster reviews, fewer bugs, easier reverts        β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  COMMIT EARLY, COMMIT OFTEN                                      β”‚
β”‚  ─────────────────────────────────────────────────────────────  β”‚
β”‚  Working code? Commit it.                                        β”‚
β”‚  Test passing? Commit it.                                        β”‚
β”‚  Don't wait for "done" - commit at every stable point.           β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Commit Size Thresholds

Warning Thresholds (Time to Commit!)

Metric Yellow Zone Red Zone Action
Files changed 5-10 files > 10 files Commit NOW
Lines added 150-300 lines > 300 lines Commit NOW
Lines deleted 100-200 lines > 200 lines Commit NOW
Total changes 250-400 lines > 400 lines Commit NOW
Time since last commit 30-60 min > 60 min Consider committing

Ideal Commit Size

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  IDEAL COMMIT                                                    β”‚
β”‚  ─────────────────────────────────────────────────────────────  β”‚
β”‚  Files: 1-5                                                      β”‚
β”‚  Lines: 50-200 total changes                                     β”‚
β”‚  Scope: Single logical unit of work                              β”‚
β”‚  Message: Describes ONE thing                                    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Check Current State (Run Frequently)

Quick Status Check

# See what's changed (staged + unstaged)
git status --short

# Count files and lines changed
git diff --stat
git diff --cached --stat  # Staged only

# Get totals
git diff --shortstat
# Example output: 8 files changed, 245 insertions(+), 32 deletions(-)

Detailed Change Analysis

# Full diff summary with file names
git diff --stat HEAD

# Just the numbers
git diff --numstat HEAD | awk '{add+=$1; del+=$2} END {print "+"add" -"del" total:"add+del}'

# Files changed count
git status --porcelain | wc -l

Pre-Commit Check Script

#!/bin/bash
# scripts/check-commit-size.sh

# Thresholds
MAX_FILES=10
MAX_LINES=400
WARN_FILES=5
WARN_LINES=200

# Get stats
FILES=$(git status --porcelain | wc -l | tr -d ' ')
STATS=$(git diff --shortstat HEAD 2>/dev/null)
INSERTIONS=$(echo "$STATS" | grep -oE '[0-9]+ insertion' | grep -oE '[0-9]+' || echo 0)
DELETIONS=$(echo "$STATS" | grep -oE '[0-9]+ deletion' | grep -oE '[0-9]+' || echo 0)
TOTAL=$((INSERTIONS + DELETIONS))

echo "πŸ“Š Current changes: $FILES files, +$INSERTIONS -$DELETIONS ($TOTAL total lines)"

# Check thresholds
if [ "$FILES" -gt "$MAX_FILES" ] || [ "$TOTAL" -gt "$MAX_LINES" ]; then
    echo "πŸ”΄ RED ZONE: Commit immediately! Changes are too large."
    echo "   Consider splitting into multiple commits."
    exit 1
elif [ "$FILES" -gt "$WARN_FILES" ] || [ "$TOTAL" -gt "$WARN_LINES" ]; then
    echo "🟑 WARNING: Changes getting large. Commit soon."
    exit 0
else
    echo "🟒 OK: Changes are within healthy limits."
    exit 0
fi

When to Commit

Commit Triggers (Any One = Commit)

Trigger Example
Test passes Just got a test green β†’ commit
Feature complete Finished a function β†’ commit
Refactor done Renamed variable across files β†’ commit
Bug fixed Fixed the issue β†’ commit
Before switching context About to work on something else β†’ commit
Clean compile Code compiles/lints clean β†’ commit
Threshold hit > 5 files or > 200 lines β†’ commit

Commit Immediately If

  • βœ… Tests are passing after being red
  • βœ… You're about to make a "big change"
  • βœ… You've been coding for 30+ minutes
  • βœ… You're about to try something risky
  • βœ… The current state is "working"

Don't Wait For

  • ❌ "Perfect" code
  • ❌ All features done
  • ❌ Full test coverage
  • ❌ Code review from yourself
  • ❌ Documentation complete

Atomic Commit Patterns

Good Atomic Commits

βœ… "Add email validation to signup form"
   - 3 files: validator.ts, signup.tsx, signup.test.ts
   - 120 lines changed
   - Single purpose: email validation

βœ… "Fix null pointer in user lookup"
   - 2 files: userService.ts, userService.test.ts
   - 25 lines changed
   - Single purpose: fix one bug

βœ… "Refactor: Extract PaymentProcessor class"
   - 4 files: payment.ts β†’ paymentProcessor.ts + types
   - 180 lines changed
   - Single purpose: refactoring

Bad Commits (Too Large)

❌ "Add authentication, fix bugs, update styles"
   - 25 files changed
   - 800 lines changed
   - Multiple purposes mixed

❌ "WIP"
   - Unknown scope
   - No clear purpose
   - Hard to review/revert

❌ "Updates"
   - 15 files changed
   - Mix of features, fixes, refactors
   - Impossible to review properly

Splitting Large Changes

Strategy 1: By Layer

Instead of one commit with:
  - API endpoint + database migration + frontend + tests

Split into:
  1. "Add users table migration"
  2. "Add User model and repository"
  3. "Add GET /users endpoint"
  4. "Add UserList component"
  5. "Add integration tests for user flow"

Strategy 2: By Feature Slice

Instead of one commit with:
  - All CRUD operations for users

Split into:
  1. "Add create user functionality"
  2. "Add read user functionality"
  3. "Add update user functionality"
  4. "Add delete user functionality"

Strategy 3: Refactor First

Instead of:
  - Feature + refactoring mixed

Split into:
  1. "Refactor: Extract validation helpers" (no behavior change)
  2. "Add email validation using new helpers" (new feature)

Strategy 4: By Risk Level

Instead of:
  - Safe changes + risky changes together

Split into:
  1. "Update dependencies" (safe, isolated)
  2. "Migrate to new API version" (risky, separate)

PR Size Guidelines

Optimal PR Size

Metric Optimal Acceptable Too Large
Files 1-10 10-20 > 20
Lines changed 50-200 200-400 > 400
Commits 1-5 5-10 > 10
Review time < 30 min 30-60 min > 60 min

PR Size vs Defect Rate

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  RESEARCH FINDINGS (Google, Microsoft studies)                  β”‚
β”‚  ─────────────────────────────────────────────────────────────  β”‚
β”‚  PRs < 200 lines: 15% defect rate                               β”‚
β”‚  PRs 200-400 lines: 23% defect rate                             β”‚
β”‚  PRs > 400 lines: 40%+ defect rate                              β”‚
β”‚                                                                 β”‚
β”‚  Review quality drops sharply after 200-400 lines.              β”‚
β”‚  Large PRs get "LGTM" rubber stamps, not real reviews.          β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

When PR is Too Large

# Check PR size before creating
git diff main --stat
git diff main --shortstat

# If too large, consider:
# 1. Split into multiple PRs (stacked PRs)
# 2. Create feature flag and merge incrementally
# 3. Use draft PR for early feedback

Commit Message Format

Structure

<type>: <description> (50 chars max)

[optional body - wrap at 72 chars]

[optional footer]

Types

Type Use For
feat New feature
fix Bug fix
refactor Code change that neither fixes nor adds
test Adding/updating tests
docs Documentation only
style Formatting, no code change
chore Build, config, dependencies

Examples

feat: Add email validation to signup form

fix: Prevent null pointer in user lookup

refactor: Extract PaymentProcessor class

test: Add integration tests for checkout flow

chore: Update dependencies to latest versions

Git Workflow Integration

Pre-Commit Hook for Size Check

#!/bin/bash
# .git/hooks/pre-commit

MAX_LINES=400
MAX_FILES=15

FILES=$(git diff --cached --name-only | wc -l | tr -d ' ')
STATS=$(git diff --cached --shortstat)
INSERTIONS=$(echo "$STATS" | grep -oE '[0-9]+ insertion' | grep -oE '[0-9]+' || echo 0)
DELETIONS=$(echo "$STATS" | grep -oE '[0-9]+ deletion' | grep -oE '[0-9]+' || echo 0)
TOTAL=$((INSERTIONS + DELETIONS))

if [ "$TOTAL" -gt "$MAX_LINES" ]; then
    echo "❌ Commit too large: $TOTAL lines (max: $MAX_LINES)"
    echo "   Consider splitting into smaller commits."
    echo "   Use 'git add -p' for partial staging."
    exit 1
fi

if [ "$FILES" -gt "$MAX_FILES" ]; then
    echo "❌ Too many files: $FILES (max: $MAX_FILES)"
    echo "   Consider splitting into smaller commits."
    exit 1
fi

echo "βœ… Commit size OK: $FILES files, $TOTAL lines"

Partial Staging (Split Large Changes)

# Stage specific hunks interactively
git add -p

# Stage specific files
git add path/to/specific/file.ts

# Stage with preview
git add -N file.ts  # Intent to add
git diff            # See what would be added
git add file.ts     # Actually add

Unstage If Too Large

# Unstage everything
git reset HEAD

# Unstage specific files
git reset HEAD path/to/file.ts

# Stage just what you need for THIS commit
git add -p

Claude Integration

Periodic Check During Development

Claude should run this check after every significant change:

# Quick status
git diff --shortstat HEAD

Thresholds for Claude to advise committing:

Condition Claude Action
> 5 files changed Suggest: "Consider committing current changes"
> 200 lines changed Suggest: "Changes are getting large, commit recommended"
> 10 files OR > 400 lines Warn: "⚠️ Commit now before changes become unmanageable"
Test just passed Suggest: "Good checkpoint - commit these passing tests"
Refactoring complete Suggest: "Refactoring done - commit before adding features"

Claude Commit Reminder Messages

πŸ“Š Status: 7 files changed, +180 -45 (225 total)
πŸ’‘ Approaching commit threshold. Consider committing current work.

---

πŸ“Š Status: 12 files changed, +320 -80 (400 total)
⚠️ Changes are large! Commit now to keep PRs reviewable.
   Suggested commit: "feat: Add user authentication flow"

---

πŸ“Š Status: 3 files changed, +85 -10 (95 total)
βœ… Tests passing. Good time to commit!
   Suggested commit: "fix: Validate email format on signup"

Stacked PRs (For Large Features)

When a feature is genuinely large, use stacked PRs:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  STACKED PR PATTERN                                             β”‚
β”‚  ─────────────────────────────────────────────────────────────  β”‚
β”‚                                                                 β”‚
β”‚  main ─────────────────────────────────────────────────────────│
β”‚    └── PR #1: Database schema (200 lines) ← Review first       β”‚
β”‚         └── PR #2: API endpoints (250 lines) ← Review second   β”‚
β”‚              └── PR #3: Frontend (300 lines) ← Review third    β”‚
β”‚                                                                 β”‚
β”‚  Each PR is reviewable independently.                           β”‚
β”‚  Merge in order: #1 β†’ #2 β†’ #3                                   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Creating Stacked PRs

# Create base branch
git checkout -b feature/auth-schema
# ... make changes ...
git commit -m "feat: Add users table schema"
git push -u origin feature/auth-schema
gh pr create --base main --title "feat: Add users table schema"

# Create next branch FROM the first
git checkout -b feature/auth-api
# ... make changes ...
git commit -m "feat: Add authentication API endpoints"
git push -u origin feature/auth-api
gh pr create --base feature/auth-schema --title "feat: Add auth API endpoints"

# And so on...

Checklist

Before Every Commit

  • [ ] Changes are for ONE logical purpose
  • [ ] Tests pass (if applicable)
  • [ ] Lint/typecheck pass
  • [ ] < 10 files changed
  • [ ] < 400 lines total
  • [ ] Commit message describes ONE thing

Before Creating PR

  • [ ] Total lines < 400 (ideal < 200)
  • [ ] All commits are atomic
  • [ ] No "WIP" or "fixup" commits
  • [ ] PR title describes the change
  • [ ] Description explains why, not just what

Red Flags (Stop and Split)

  • ❌ Commit message needs "and"
  • ❌ > 10 files in one commit
  • ❌ > 400 lines in one commit
  • ❌ Mix of features, fixes, and refactors
  • ❌ "I'll clean this up later"

Quick Reference

Thresholds

Files:  ≀ 5 = 🟒  |  6-10 = 🟑  |  > 10 = πŸ”΄
Lines:  ≀ 200 = 🟒  |  201-400 = 🟑  |  > 400 = πŸ”΄
Time:   ≀ 30min = 🟒  |  30-60min = 🟑  |  > 60min = πŸ”΄

Commands

# Quick status
git diff --shortstat HEAD

# Detailed file list
git diff --stat HEAD

# Partial staging
git add -p

# Check before PR
git diff main --shortstat

Commit Now If

  • βœ… Tests just passed
  • βœ… > 200 lines changed
  • βœ… > 5 files changed
  • βœ… About to switch tasks
  • βœ… Current state is "working"

# Supported AI Coding Agents

This skill is compatible with the SKILL.md standard and works with all major AI coding agents:

Learn more about the SKILL.md standard and how to use these skills with your preferred AI coding agent.