Rolling Back AI Code Changes Safely

Three commands cover 99% of rollback scenarios: stash, restore, reflog.

You let Claude Code run an autonomous task overnight; in the morning, 12 files are mangled, the new feature isn’t done, and the old one is broken. The most dangerous moment: you decide to “undo everything” — and a misplaced git checkout . or git reset --hard throws away the bits that were actually salvageable.

This guide lays out six rollback commands ordered by scope (“smallest undo first”), with side-by-side syntax and a table of “what gets undone, what survives.” Finally it shows how git reflog can rescue work from up to 90 days ago — even after a reset --hard you thought was final.

Common causes

Ordered by how urgent the rollback usually is.

1. AI did too much; you need to undo selectively

Most common. The agent ran for 20 minutes and changed 8 files. Three were what you wanted, five it invented. You want to keep three and discard five but don’t know how to undo per-file or per-hunk.

How to spot it: git diff --stat shows a long list of files; after review you can cleanly sort them into “keep” and “discard” piles.

2. Tests passed locally; CI failed

npm test is green locally, red on push. You suspect one of the AI commits introduced an environment-sensitive bug (path case, CRLF, dep version). You want to roll back to the last CI-green commit.

How to spot it: git log --oneline shows multiple AI commits; the last green CI build’s SHA is recoverable from GitHub Actions history or your CI dashboard.

3. You want the AI’s “plan” but not its “code”

The agent produced a reasonable execution plan (rename X, extract Y, add tests for Z), but the code quality was poor. You want to keep the commit messages / plan and throw the actual code changes away so another model can write them.

How to spot it: The commit messages / agent transcript are more valuable than the code diff.

4. AI changes are pushed but not merged

The PR is up on remote; no reviewer has approved yet. You want to force-reset your branch, but you’re worried about losing other commits if a teammate pushed in parallel.

How to spot it: git log @{u}..HEAD lists commits not yet on remote; git log HEAD..@{u} lists commits where remote is ahead.

5. AI changes are merged to main

The hardest case. Changes are on the main branch; teammates may have pulled. You can’t reset — only git revert to generate inverse commits.

How to spot it: git log main --grep="<AI commit>" shows the commit is on main.

6. AI ran git commit --amend or rebase and rewrote history

The agent executed git commit --amend or git rebase -i and the commit you wanted to keep is gone. Only reflog can save you here.

How to spot it: git log no longer shows a commit you’re certain existed yesterday.

Shortest path to fix

Step 1: Snapshot before you do anything

# Safety branch — recoverable even if every later command goes wrong
git branch backup/before-rollback-$(date +%Y%m%d-%H%M)

# Stash dirty working tree too
git stash push -u -m "before rollback $(date)"

git stash with -u includes untracked files; -m adds a message so you can find it later in git stash list.

Step 2: Pick the right command for the scope

This table covers 99% of cases. Confirm current state first, then pick a command.

What to undoCommandUndoesKeeps
One file’s unstaged changesgit restore <file>That file back to HEADOther files, staged area
All unstaged changesgit restore .All unstaged editsStaged area, untracked
Staged but not committedgit restore --staged <file>Un-stages (keeps edits)File contents
Last commit, keep changesgit reset --soft HEAD~1The commitAll edits in staged area
Last commit, edits in working treegit reset HEAD~1Commit + stageEdits in unstaged
Last commit, drop everythinggit reset --hard HEAD~1Commit + editsNothing (but reflog saves you)
Selected hunks onlygit restore -p <file>Hunks you pickOther hunks
Pushed + merged commitgit revert <sha>Creates inverse commitHistory intact

Key distinction:

  • --soft = changes move to staged; --mixed (default) = unstaged; --hard = changes are removed from the tree (but reflog can still recover them)

Step 3: Use reflog to rescue “disappeared” changes

After reset --hard or --amend, the “lost” work isn’t actually lost — reflog retains it for 90 days.

git reflog              # every HEAD movement
# c9d3e5a HEAD@{0}: reset: moving to HEAD~1
# 8b4f2a1 HEAD@{1}: commit: AI: refactor user service
# 2e1c8d3 HEAD@{2}: commit: WIP

git checkout 8b4f2a1    # jump back to that state
git branch rescue 8b4f2a1  # or branch it for safety

git reflog --since="2 hours ago" narrows the window and cuts noise.

Step 4: Pushed-and-merged case — use revert

If the commit is already on main, do not force push. Generate an inverse commit:

git revert <bad-sha>                # single commit
git revert <bad-sha>^..<bad-sha2>   # a range
git revert -m 1 <merge-sha>         # revert a merge commit

revert produces a fresh commit safe to push.

Step 5: Restore from the Step 1 snapshot if the rollback itself went wrong

git stash list
# stash@{0}: On main: before rollback 2026-05-22

git stash apply stash@{0}    # apply but keep the stash
git stash pop stash@{0}      # apply and drop the stash

# or just check out the safety branch
git checkout backup/before-rollback-20260522-1430

Prevention

  • Working tree must be clean before letting the agent start: git status must show “nothing to commit”; stash any dirt first
  • Add to CLAUDE.md / AGENTS.md: “commit after every atomic change; never bundle unrelated edits into one commit” — smaller commits, smaller rollback loss
  • Prefix every agent commit with AI: (git config commit.template); then git log --grep="^AI:" --since="1 day" lists them all in one go
  • High-risk tasks (mass file deletion, lockfile changes, migrations) — tag before starting: git tag wip/before-<task>; rollback becomes one command
  • Forbid agents from running git reset --hard / git push --force / git rebase -i directly — those should require a human keystroke
  • Enable GitHub branch protection on main; disallow force push so that even if reflog expires, remote history is recoverable

Tags: #AI coding #Debug #Troubleshooting