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
git status --short
git diff --stat
git diff --cached --stat
git diff --shortstat
Detailed Change Analysis
git diff --stat HEAD
git diff --numstat HEAD | awk '{add+=$1; del+=$2} END {print "+"add" -"del" total:"add+del}'
git status --porcelain | wc -l
Pre-Commit Check Script
#!/bin/bash
MAX_FILES=10
MAX_LINES=400
WARN_FILES=5
WARN_LINES=200
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)"
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
git diff main --stat
git diff main --shortstat
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
#!/b