How to Set Up Automatic Git Commit and Revert on Failure in AI Coding Workflows
Problem
When I use AI to help with coding, I often end up with a mess. The AI makes a change, something breaks, then it makes another change to fix that break, which breaks something else. After 10 minutes, I have a tangled mess of broken code and no idea how to get back to a working state.
Here’s what happened in one session:
AI: Let me fix the import error.[Changes 3 files]
AI: Now let me fix the type error.[Changes 2 more files]
AI: There's a test failing.[Changes another file]
Me: Wait, the original feature is broken now.AI: Let me fix that.[Changes 4 files]
Me: Stop! I just want to go back to before this started.At this point, I have 10 uncommitted changes, no working tests, and no clear way to undo just the broken parts. The AI tried to be helpful, but each fix created new problems that compounded.
What happened?
I was using AI in a naive way: let it make all the changes it wants, then deal with the aftermath. This works fine for simple tasks, but for complex refactoring or multi-file changes, it creates a cascade of problems.
The issue is that AI doesn’t naturally work in an atomic way. It sees a problem, fixes it, sees another problem, fixes that too. Without a rollback mechanism, errors stack on top of each other.
I found a Reddit discussion where developers shared a better pattern for AI coding workflows. The key insight: treat each AI action as an atomic unit that must pass verification before it sticks.
The Atomic Pattern
The pattern is simple but powerful:
┌─────────────────────────────────────────────────────────┐│ Make ONE atomic change ││ ↓ ││ git commit immediately ││ ↓ ││ Run verification tests ││ ↓ ││ ┌─────────────┐ ││ │ Tests pass? │──Yes──→ Keep the commit ││ └─────────────┘ ││ │ ││ No ││ ↓ ││ git revert HEAD (auto-rollback) │└─────────────────────────────────────────────────────────┘This pattern ensures two things:
- Every improvement stacks - Good changes are saved
- Every failure auto-reverts - Bad changes disappear
How to implement this?
Let me show you how I set this up in my workflow.
Step 1: Create a verification script
First, I created a script that runs my verification checks:
#!/bin/bashset -e
# Run lintingnpm run lint
# Run testsnpm test
# Run type checkingnpm run typecheck
echo "All checks passed!"This script returns exit code 0 if everything passes, non-zero if anything fails.
Step 2: Create the atomic workflow script
Then I created a script that wraps the commit-and-verify pattern:
#!/bin/bash
COMMIT_MSG="$1"
if [ -z "$COMMIT_MSG" ]; then echo "Usage: ./atomic-commit.sh 'commit message'" exit 1fi
# Check if there are changes to commitif git diff --quiet && git diff --staged --quiet; then echo "No changes to commit" exit 0fi
# Commit the changesgit add -Agit commit -m "$COMMIT_MSG"
# Store the commit hash for potential revertCOMMIT_HASH=$(git rev-parse HEAD)
# Run verificationecho "Running verification..."if ./verify.sh; then echo "Verification passed. Commit kept: $COMMIT_HASH"else echo "Verification failed. Reverting commit..." git revert --no-edit HEAD echo "Commit reverted. Check the error output above." exit 1fiStep 3: Use it in AI coding sessions
Now when I work with AI, I ask it to make small, focused changes and run this script after each one:
Me: Add error handling to the fetchUserData function. Use atomic-commit.sh after.
AI: [Makes the change]Running verification... ✓ Lint passed ✓ Tests passed ✓ Type check passedVerification passed. Commit kept: abc1234If verification fails:
Me: Refactor the auth module. Use atomic-commit.sh after.
AI: [Makes the change]Running verification... ✓ Lint passed ✗ Tests failed: 2 tests failingVerification failed. Reverting commit...Commit reverted. Check the error output above.The broken changes are gone. I’m back to a clean state.
Why this works
I think the key reasons this pattern works are:
1. Small atomic changes are easier to debug
When a change fails, I know exactly which commit caused the problem. I don’t have to hunt through 10 files of changes.
2. Rollback removes the temptation to “just fix it”
Without rollback, I’d be tempted to let the AI keep fixing the broken tests it created. With rollback, I’m forced to step back and reconsider the approach.
3. Clean state means clean context
AI works better with clean context. When I revert a bad change, the AI doesn’t have to reason about broken code that shouldn’t exist.
4. Each commit is a checkpoint
If I realize later that a change was wrong, I can use git revert on that specific commit. The history is clean and navigable.
Common mistakes I made
Mistake 1: Making changes too large
At first, I asked the AI to “refactor the entire module” in one atomic commit. This often failed because the change touched too many things at once. I learned to break large tasks into smaller pieces:
# Too large"Add error handling to all API endpoints"
# Better - break into atomic pieces"Add error handling to the user endpoint""Add error handling to the product endpoint""Add error handling to the order endpoint"Mistake 2: Verification that’s too slow
My initial verification script ran the entire test suite, which took 5 minutes. This made the atomic workflow painful. I split verification into two levels:
#!/bin/bash# Quick verification for small changesnpm run lintnpm run test -- --related --bailnpm run typecheckQuick verification runs in seconds. Full verification runs before pushing.
Mistake 3: Forgetting to commit before verification
Sometimes I’d run the AI, it would make changes, and I’d forget to use atomic-commit.sh. Then something would break and I’d have uncommitted changes with no clean rollback. I added a pre-check to remind myself:
# Check for uncommitted changes from previous sessionsif ! git diff --quiet || ! git diff --staged --quiet; then echo "WARNING: You have uncommitted changes." echo "Run this script after each AI change to keep your history clean." read -p "Continue anyway? (y/n) " -n 1 -r echo if [[ ! $REPLY =~ ^[Yy]$ ]]; then exit 1 fifiUsing with Claude Code
If you use Claude Code, you can set up a hook to automate this. In your CLAUDE.md:
## Atomic Change Rule
**Trigger:** After making code changes**Action:**1. Stage all changes with git add2. Commit with descriptive message3. Run verification (lint, test, typecheck)4. If verification fails, revert the commit and explain the failureThis makes the atomic pattern automatic. Claude will commit, verify, and rollback without you having to ask.
Summary
In this post, I showed how to set up automatic git commit and revert on failure in AI coding workflows. The key point is the atomic pattern: make one small change, commit immediately, verify, and automatically revert if tests fail. This prevents error accumulation and keeps your codebase in a clean, working state.
The rollback-on-failure piece is the most underrated part of this pattern. Without it, errors stack on top of each other until you lose track of what broke and when. With it, you get a clean slate after every failed attempt, and your git history tells a clear story of what worked.
Final Words + More Resources
My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me
Here are also the most important links from this article along with some further resources that will help you in this scope:
Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!
Comments