Checkpoint Commit Patterns: Git Strategies for AI-Assisted Development

James Phoenix
James Phoenix

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:

Udemy Bestseller

Learn Prompt Engineering

My O'Reilly book adapted for hands-on learning. Build production-ready prompts with practical exercises.

4.5/5 rating
306,000+ learners
View Course
  • 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

References

Topics
Ai WorkflowsBest PracticesCheckpointsCollaborationCommitsGitIncremental DevelopmentRecoverySafety PatternsVersion Control

More Insights

Cover Image for Own Your Control Plane

Own Your Control Plane

If you use someone else’s task manager, you inherit all of their abstractions. In a world where LLMs make software a solved problem, the cost of ownership has flipped.

James Phoenix
James Phoenix
Cover Image for Indexed PRD and Design Doc Strategy

Indexed PRD and Design Doc Strategy

A documentation-driven development pattern where a single `index.md` links all PRDs and design documents, creating navigable context for both humans and AI agents.

James Phoenix
James Phoenix