Summary
Git commits serve as safety checkpoints in AI-assisted development. Frequent, atomic commits after each successful change enable rapid recovery when AI-generated code fails, provide clear audit trails of what changed when, and give the next coding agent (or future you) the context to continue. This article covers commit timing, message conventions, branch strategies, and recovery patterns for AI workflows.
The Problem
AI coding agents generate code rapidly. A single session might touch dozens of files, add hundreds of lines, and refactor existing code. Without disciplined commit practices, you face several risks:
Risk 1: Lost progress on failure
AI generates 500 lines, but the last 50 break the build. Without intermediate commits, you must manually identify and revert the problematic changes.
Risk 2: Context loss across sessions
Fresh agents (RALPH Loop pattern) have no memory of previous work. Git history becomes the only record of what happened and why.
Risk 3: Debugging difficulty
When bugs appear days later, tracing which change introduced them requires clear, atomic commits with descriptive messages.
Risk 4: Collaboration confusion
Team members reviewing AI-generated changes need to understand what changed and why, not just see a massive diff.
The Solution
Treat git commits as checkpoints in a game. Commit frequently, after every successful change, so you can always reload from a known good state. Use consistent message conventions that capture the AI’s intent. Branch strategically to isolate experimental work.
Core Principles
Principle 1: Commit After Every Success
Every successful change deserves a commit:
┌─────────────────────────────────────────────────────────────────┐
│ AI generates code │
│ ↓ │
│ Run validation (compile, lint, test) │
│ ↓ │
│ Passes? ─┬─► Yes → COMMIT immediately │
│ │ │
│ └─► No → Fix before proceeding (no commit) │
└─────────────────────────────────────────────────────────────────┘
This creates a “ratchet effect” where progress is locked in and cannot be lost.
Principle 2: Commit Before Risk
Before any operation that might break things, create a safety checkpoint:
# Before major refactoring
git add -A && git commit -m "checkpoint: before refactoring auth module"
# Before running unfamiliar AI suggestions
git add -A && git commit -m "checkpoint: before applying AI suggestion for caching"
# Before deleting files
git add -A && git commit -m "checkpoint: before removing legacy endpoints"
If the risky operation fails, recovery is instant: git checkout .
Principle 3: Atomic Commits
Each commit should represent one logical change:
✗ Bad: "Updated auth, fixed bug, added tests, refactored utils"
✓ Good: Four separate commits:
1. "fix(auth): handle expired token gracefully"
2. "test(auth): add token expiration test cases"
3. "refactor(utils): extract date formatting helper"
4. "feat(auth): add refresh token endpoint"
Atomic commits make reverting, cherry-picking, and bisecting possible.
Principle 4: Descriptive Messages
Commit messages are documentation for future agents and humans:
✗ Bad: "fix bug"
✗ Bad: "update code"
✗ Bad: "wip"
✓ Good: "fix(auth): handle null user in token validation
The validateToken function crashed when user was deleted
from database but token still existed. Now returns
AuthResult.invalidUser instead of throwing.
Fixes: USER-1234"
Commit Message Conventions
Format for AI Workflows
Use a consistent format that captures what, why, and context:
<type>(<scope>): <subject>
[optional body explaining why, not what]
[optional footer with references]
Co-Authored-By: Claude <noreply@anthropic.com>
Types
feat New feature
fix Bug fix
refactor Code change that neither fixes nor adds
test Adding or updating tests
docs Documentation changes
style Formatting, no code change
chore Build process, dependencies
perf Performance improvement
ci CI/CD configuration
Examples
Feature addition:
feat(cart): add quantity validation on item update
Prevents negative quantities and limits max to 99.
Validation happens both client-side and in API.
Co-Authored-By: Claude <noreply@anthropic.com>
Bug fix:
fix(checkout): handle network timeout during payment
Added retry logic with exponential backoff.
Shows user-friendly error after 3 failed attempts.
Closes #456
Co-Authored-By: Claude <[email protected]>
Checkpoint commit:
checkpoint: before migrating to new auth system
Current state: all tests passing, auth working.
Next: replace JWT with session-based auth.
Co-Authored-By: Claude <noreply@anthropic.com>
RALPH iteration:
[progress]: complete task 3 of 7 - add user validation
- Added email format validation
- Added password strength requirements
- Tests passing (12 new test cases)
Next task: implement rate limiting
Co-Authored-By: Claude <[email protected]>
Commit Timing Patterns
Pattern 1: The Validation Gate
Commit only after validation passes:
// Pseudo-code for AI workflow
async function implementFeature(task: string): Promise<void> {
const code = await ai.generate(task);
await writeFiles(code);
// Validation gate
const valid = await validate(); // compile + lint + test
if (valid) {
await git.commit(`feat: ${task}`); // Lock in progress
} else {
await git.checkout('.'); // Revert to last good state
// Try different approach
}
}
Pattern 2: The Incremental Checkpoint
For complex tasks, commit after each successful sub-task:
Task: "Add user authentication system"
Increment 1: Add User model
→ Tests pass → Commit: "feat(auth): add User model"
Increment 2: Add password hashing
→ Tests pass → Commit: "feat(auth): add password hashing utilities"
Increment 3: Add login endpoint
→ Tests pass → Commit: "feat(auth): add POST /login endpoint"
Increment 4: Add token generation
→ Tests pass → Commit: "feat(auth): add JWT token generation"
Each commit is a recovery point. If increment 4 fails, you can revert to increment 3 and try a different approach.
Pattern 3: The Safety Bracket
Surround risky operations with checkpoint commits:
# BEFORE: Create safety checkpoint
git add -A && git commit -m "checkpoint: before database migration"
# RISKY OPERATION: Run migration
npx prisma migrate dev
# AFTER: Either commit success or revert
if [ $? -eq 0 ]; then
git add -A && git commit -m "chore(db): apply user table migration"
else
git checkout .
echo "Migration failed, reverted to checkpoint"
fi
Pattern 4: The End-of-Session Commit
In RALPH Loop workflows, always commit before session ends:
# End of RALPH iteration
git add -A
git commit -m "[progress]: end of session - completed tasks 1-3
Completed:
- Task 1: Add user validation (src/validators/user.ts)
- Task 2: Update API endpoint (src/routes/users.ts)
- Task 3: Add integration tests (tests/users.test.ts)
Next session should:
- Start with Task 4: Add rate limiting
- Review test coverage for edge cases
All tests passing. Build successful.
Co-Authored-By: Claude <[email protected]>"
This commit message gives the next agent full context.
Branch Strategies
Strategy 1: Feature Branches for AI Work
Isolate AI-generated changes from main:
# Create branch for AI task
git checkout -b feat/add-authentication
# AI does work, multiple commits
git commit -m "feat(auth): add User model"
git commit -m "feat(auth): add login endpoint"
git commit -m "feat(auth): add tests"
# Review and merge
git checkout main
git merge --no-ff feat/add-authentication
Benefits:
- Main branch always stable
- Can abandon branch if approach fails
- Clear history of what feature included
Strategy 2: Experimental Branches
For high-risk AI suggestions:
# Try risky approach on experimental branch
git checkout -b experiment/redis-caching
# AI implements caching
# If it works → merge to feature branch
# If it fails → delete branch, no harm done
git checkout feat/improve-performance
git merge experiment/redis-caching # or: git branch -D experiment/redis-caching
Strategy 3: Worktree Parallelism
Use git worktrees for parallel AI tasks:
# Main worktree: task A
cd project
# AI works on auth
# Second worktree: task B (parallel)
git worktree add ../project-cart feat/shopping-cart
cd ../project-cart
# AI works on cart
# Both can commit independently
# Merge when both complete
This enables running multiple AI agents simultaneously without conflicts.
Recovery Patterns
Recovery 1: Simple Revert
When the last change broke things:
# Revert uncommitted changes
git checkout .
# Or revert last commit
git revert HEAD
Recovery 2: Bisect for Bug Hunting
Find which commit introduced a bug:
git bisect start
git bisect bad HEAD # Current state is broken
git bisect good abc123 # This commit was working
# Git checks out middle commit
# Run tests
npm test
git bisect good # or bad, depending on test result
# Repeat until git identifies the problematic commit
Atomic commits make bisect effective. Large commits defeat it.
Recovery 3: Cherry-Pick Good Changes
When a branch went wrong but some commits are valuable:
# On main branch
git cherry-pick abc123 # Just the good commit
git cherry-pick def456 # Another good one
# Leave the bad commits behind
Recovery 4: Interactive Rebase for Cleanup
Before merging to main, clean up AI commit history:
git rebase -i HEAD~5
# In editor, combine related commits:
pick abc123 feat(auth): add User model
squash def456 fix(auth): fix User model typo
squash ghi789 fix(auth): add missing field
pick jkl012 feat(auth): add login endpoint
Result: Clean history with logical commits instead of trial-and-error noise.
Integration with RALPH Loop
The RALPH Loop uses git as external memory:
┌─────────────────────────────────────────────────────────────────┐
│ RALPH Iteration N │
├─────────────────────────────────────────────────────────────────┤
│ 1. Read git log to understand recent progress │
│ 2. Read TASKS.md / progress.txt for current state │
│ 3. Complete ONE task │
│ 4. Commit with descriptive message │
│ 5. Update tracking files │
│ 6. Exit (fresh context next iteration) │
└─────────────────────────────────────────────────────────────────┘
Git commits become the “save game” between iterations:
# What previous agent did (memory reconstruction)
git log --oneline -10
# f8bd993 [progress]: add user validation - all tests pass
# b1c32b7 [progress]: add password hashing utilities
# 0b6ebd0 [progress]: create User model
# 3922f65 [progress]: initial project setup
# Current agent continues from last commit
Commit Message Templates
For Features
feat(<scope>): <what was added>
<Why this feature was needed>
<Any notable implementation decisions>
<List of files added/changed>
Co-Authored-By: Claude <[email protected]>
For Bug Fixes
fix(<scope>): <what was fixed>
<Root cause of the bug>
<How this fix addresses it>
Fixes: <issue number or description>
Co-Authored-By: Claude <[email protected]>
For RALPH Progress
[progress]: <brief summary of completed work>
Completed:
- <Task 1>
- <Task 2>
Files changed:
- <file1>: <what changed>
- <file2>: <what changed>
Tests: <passing/failing status>
Build: <success/failure>
Next: <what next iteration should do>
Co-Authored-By: Claude <[email protected]>
For Checkpoints
checkpoint: before <risky operation>
Current state:
- All tests passing
- Build successful
- <any relevant state>
About to: <what risky thing is about to happen>
Rollback: git checkout . (or git revert HEAD)
Co-Authored-By: Claude <noreply@anthropic.com>
Best Practices
1. Never Commit Broken Code
# Always validate before commit
npm run lint && npm run test && git commit -m "..."
# Or use pre-commit hooks
# .husky/pre-commit
npm run lint
npm run test
2. Keep Commits Small
✗ Bad: 500 lines changed in one commit
✓ Good: 5 commits of ~100 lines each
Smaller commits = easier review, debug, and revert
3. Commit Tracked Files Explicitly
# ✗ Risky: might include unintended files
git add -A
# ✓ Safer: explicit file selection
git add src/auth.ts src/auth.test.ts
git commit -m "feat(auth): add authentication module"
4. Use Commit Templates
Create .gitmessage template:
<type>(<scope>): <subject>
# Why this change?
# What changed?
# Any caveats or notes?
Co-Authored-By: Claude <noreply@anthropic.com>
Configure git to use it:
git config commit.template .gitmessage
5. Review Diffs Before Committing
# Always review what you're committing
git diff --staged
# Especially important for AI-generated code
# AI might have changed more than you expected
Common Pitfalls
Pitfall 1: Mega-Commits
Problem: AI generates 1000 lines, all committed at once
# ✗ Bad
git add -A && git commit -m "implement auth system"
# 1000 lines, 15 files, impossible to review or revert partially
Solution: Commit incrementally during generation
Pitfall 2: WIP Commits
Problem: Cryptic work-in-progress commits
# ✗ Bad
git commit -m "wip"
git commit -m "fix"
git commit -m "update"
# No context for future debugging
Solution: Even quick commits need context
# ✓ Better
git commit -m "wip(auth): token validation - tests failing, investigating"
Pitfall 3: Committing Secrets
Problem: AI generates code with hardcoded credentials
# ✗ Dangerous
const API_KEY = "sk-live-abc123..." # Committed to git!
Solution: Use .gitignore and pre-commit checks
# .gitignore
.env
*.pem
*secret*
# Pre-commit hook: scan for secrets
npm run detect-secrets
Pitfall 4: Forgetting to Commit
Problem: Session ends without committing, progress lost
Solution: End-of-session commit ritual
# Before ending any AI session:
git status # What's uncommitted?
git add relevant-files
git commit -m "[progress]: end of session - <summary>"
Pitfall 5: Committing Generated Files
Problem: Committing build artifacts, node_modules, etc.
# ✗ Bad: huge commits, merge conflicts
git add -A # Includes node_modules, dist/, etc.
Solution: Proper .gitignore
# .gitignore
node_modules/
dist/
build/
.cache/
Measuring Success
Metrics to Track
interface CommitMetrics {
averageCommitSize: number; // Lines changed per commit
commitsPerFeature: number; // How atomic are features?
revertFrequency: number; // How often do we rollback?
bisectEffectiveness: number; // Can we find bugs with bisect?
messageQuality: number; // Are messages descriptive?
}
Healthy Patterns
Average commit size: <100 lines
Commits per feature: 3-10
Revert frequency: <5% of commits
Bisect effectiveness: Can find bug in <10 steps
Message quality: Reviewer understands without asking
Warning Signs
Average commit size: >500 lines → Break down work
Commits per feature: 1 → Commit more frequently
Revert frequency: >20% → Validate before committing
Bisect effectiveness: Can't use → Commits too large
Message quality: "wip", "fix" → Need better conventions
Related
- Agent Memory Patterns – Git as Tier 2 file-based memory for agents
- Incremental Development Pattern – Commit after each validated increment
- Clean Slate Trajectory Recovery – Git enables clean recovery from bad paths
- RALPH Loop – Git history as memory between iterations
- Event Sourcing for Agents – Git as lightweight event log
- Git Worktrees for Parallel Development – Run multiple AI tasks simultaneously
References
- Conventional Commits – Commit message specification
- Git Best Practices – Pro Git book
- Anthropic: Effective Harnesses – Long-running agent patterns

