Claude Code Checkpoints and /rewind: Undo a Bad Edit, Know What Isn't Tracked, and Recover the Rest With Git

Claude Code checkpoints undo Claude's file edits, not Bash or manual changes. Run a /rewind drill, pick the right restore option, and recover the rest with git.

Matrix chart of Claude Code checkpoints in the rewind drill: five actions down the left (Restore code and conversation, Restore conversation, Restore code, Summarize from here, git restore) against four columns (app.js Edit tool, notes.txt Bash mv, README.md your editor, conversation history), each cell a labelled pill such as reverted, stays, rewound, kept, compressed, restored or untouched.Matrix chart of Claude Code checkpoints in the rewind drill: five actions down the left (Restore code and conversation, Restore conversation, Restore code, Summarize from here, git restore) against four columns (app.js Edit tool, notes.txt Bash mv, README.md your editor, conversation history), each cell a labelled pill such as reverted, stays, rewound, kept, compressed, restored or untouched.
Only git restores all three files in the drill. Rewind reverts only the app.js edits Claude's file tool made, and only the menu options touch the conversation. Original chart of documented behavior applied to this guide's worked example, based on Anthropic's Claude Code checkpointing docs and the git-restore documentation, fetched Oct 22, 2026.

You asked Claude to rework one function, it touched three files, and the tests went red. Claude Code checkpoints exist for that moment. Before each prompt that starts a turn, Claude Code saves the state of the files its editing tools change, and /rewind can put them back. The boundary is what catches people out. Checkpoints only see edits made through Claude’s own file-editing tools. A Bash mv, a fix you typed in your editor, or most subagent work survives a rewind untouched. This tutorial runs a short drill in a throwaway repository so you can watch both sides of that boundary, choose each restore option on purpose, and recover the rest with git.

The reader here uses Claude Code most days inside git repositories and wants a fast undo that never costs work. For a broader tour of the CLI, start with the Claude Code field guide. This piece covers one job only.

This week a short X post stated that boundary cleanly. On October 20, developer Cozy posted that every Claude Code prompt creates a checkpoint, that double-tapping Esc or running /rewind restores the code, the chat or both, and that edits made through Bash aren’t tracked, so keep git. Anthropic’s checkpointing documentation confirms all three points and fills in what a post that short has to leave out. Everything below is documented behavior from Anthropic’s and git’s official pages. The expected observations say what the docs predict should happen. They are not output we captured from a test run.

What Claude Code checkpoints capture, and what they ignore

The checkpointing page describes the mechanism in a few sentences. Claude Code captures the state of your code before each prompt you send that starts a turn, so every one of those prompts becomes a restore point. It keeps file snapshots for the 100 most recent checkpoints in a session. Checkpoints are saved with the conversation, which is why /rewind still works after you resume a session. Snapshots are not permanent, though. By default the retention sweep deletes a session’s file snapshots about 30 days after the session last saved one, and rewinding to a checkpoint whose snapshots are gone can fail with No files were restored.

The key word is “tracks”. Claude Code tracks changes made by its file editing tools, and the docs list everything that falls outside them:

Change Captured by a checkpoint? Documented reason
Claude edits or writes a file with its file-editing tools Yes This is what checkpointing tracks
Claude runs rm, mv or cp through Bash No These modifications cannot be undone through rewind
You edit a file in your editor Normally no Outside changes are captured only when they touch files the session also edits
Another concurrent Claude Code session edits the repo Normally no Same rule as manual edits
A forked skill (context: fork) running in the foreground Yes It edits your working tree during your own turn
Any other subagent, including a background forked skill or a background /code-review --fix Partly Rewind restores only files Claude had already edited in your conversation
A symlinked or hard-linked file No Skipped with a Restored the code, but skipped N files warning
A message you typed while Claude was still working No checkpoint of its own Marked No code restore; its edits count toward the prompt that started the turn

Anthropic's Claude Code Checkpointing documentation page on code.claude.com, showing the page title and its opening explanation of how Claude's file edits are tracked.
Anthropic's Checkpointing page in the Claude Code Docs (code.claude.com), captured Oct 2026. The top of the page introduces how Claude Code tracks Claude's file edits; further down, the page documents the rewind menu and its limitations. · Original source

Two consequences drive the rest of this guide. First, a rewind does not take the whole folder back in time. It puts back the files Claude’s tools changed. Second, if you hand-edit a file that Claude has also edited, a code restore can sweep up your edit too, because that file is tracked. Anthropic’s Agent SDK checkpointing page adds one more limit worth keeping in mind for interactive work: creating, moving or deleting directories is not undone by rewinding.

Before you start: build a scratch repository

You need four things: Claude Code installed and signed in, git on your PATH, a terminal, and an editor that can save a file. Run the drill in a throwaway directory rather than a real project. A code restore overwrites files, and the checkpointing page describes no way to undo a restore.

  1. Create the repository and three files, then commit them as the baseline:
mkdir rewind-drill && cd rewind-drill
git init
cat > app.js <<'EOF'
function greet(name) {
  return "Hello, " + name;
}
module.exports = { greet };
EOF
printf 'Drill notes\n' > notes.txt
printf '# Rewind drill\n' > README.md
git add app.js notes.txt README.md
git commit -m "baseline"
git status
  1. Confirm the baseline. git status should report a clean working tree with nothing to commit. That commit is your floor. Whatever the rewind does, git restore can bring any committed file back to this state.
  2. Open README.md in your editor now so it is ready for the manual edit.

Why three files? Each has a different author and sits on a different side of the checkpoint boundary. Only Claude’s edit tool will ever change app.js. Only a shell command will change notes.txt. Only you will change README.md. After the rewind, each file shows you which system owned it.

Run the three-prompt drill

Start a session with claude from inside rewind-drill. Send these prompts one at a time and wait for each turn to finish, because a message typed mid-turn gets no checkpoint of its own.

  1. Prompt 1: In app.js, change greet so it returns "Hi, " + name + "." Use your file edit tool, not a shell command. Approve the edit. Claude Code took a checkpoint before this turn began, and that checkpoint holds the baseline app.js.
  2. Prompt 2: Run exactly this shell command and nothing else: mv notes.txt NOTES.md Approve the Bash call. This turn also gets a checkpoint, but the rename itself happens outside the file-editing tools.
  3. Manual edit: in your editor, add the line Manual line added outside Claude Code. to README.md and save. This creates no checkpoint, because you did not send a prompt.
  4. Prompt 3: Add a one-line comment above greet in app.js that says what it returns. Approve the edit. This is a second tracked change to the same file.
  5. Run /diff to preview what the checkpoint layer can see. The interactive mode reference explains that its turn views come from Claude’s file edits rather than from git, so a change Claude makes through a shell command appears only under Current, the working-tree view. You should get turn views for the two prompts that edited app.js. The rename and the README line should appear only under Current.

Fill in this prediction sheet before you open the rewind menu. It is the core skill of the drill: know the outcome before you press Enter.

Change How it was made Checkpoint sees it? Expected after Restore code at prompt 1
greet returns "Hi, " + name + "." Prompt 1, file edit tool Yes Reverted to baseline
notes.txt renamed to NOTES.md Prompt 2, Bash mv No Rename stays
Extra line in README.md Your editor, between prompts 2 and 3 No, Claude never edited this file Line stays
Comment above greet Prompt 3, file edit tool Yes Reverted, because it came after the checkpoint

The last row surprises people. Rewinding to an early prompt reverts every tracked edit made after it, not just that prompt’s own edit. To keep prompt 1’s change and drop only prompt 3’s, select prompt 3 instead.

Open the rewind menu and pick a checkpoint on purpose

  1. Clear the prompt box first. When it contains text, pressing Esc twice clears the draft instead of opening the menu. The cleared text goes to your input history, so Up brings it back afterwards.
  2. Press Esc twice on the empty prompt, or type /rewind. The commands reference lists /checkpoint and /undo as aliases.
  3. Read the list of prompts you sent during the session and move to prompt 1, the app.js change. Acting on a prompt returns you to the state just before it, which is why a conversation restore hands that prompt back to you to re-send or edit.
  4. Read the actions before choosing. The two code restore options appear only when the selected checkpoint has tracked file changes to revert. On prompt 1 you should see all six: Restore code and conversation, Restore conversation, Restore code, Summarize from here, Summarize up to here, and Never mind.
  5. Choose with the arrow keys, not by reflex. In GitHub issue #64615, the reporter described losing work when a habitual Enter accepted the default. An Anthropic maintainer reproduced the flow on v2.1.233. They found that the picker opens on “(current)”, so one stray Enter changes nothing, and that choosing an older checkpoint leads to a screen headed “Confirm you want to restore…” that previews the code change. The same reply acknowledged that Restore code and conversation is still the default option on that screen, and that the double-Esc trigger cannot currently be disabled or rebound. The issue was closed on Aug 17, 2026. On Aug 25 the reporter replied that a selection screen is not a yes/no confirmation.
  6. If anything looks unexpected, pick Never mind. It takes you back to the message list without changing anything.

GitHub issue #64615 in the anthropics/claude-code repository, showing the bug report title about /rewind (Esc Esc) reverting code by default and the issue's Closed status.
GitHub issue #64615 in anthropics/claude-code, captured from github.com in Oct 2026, showing the report that /rewind defaults to Restore code and conversation. A maintainer later closed it after describing the confirm-and-preview screen. · Original source

Compare the three restore options on one checkpoint

For the first pass, choose Restore code at prompt 1. It reverts the file changes and keeps the conversation, so Claude’s earlier replies stay on screen while you inspect the files.

Option Files on disk Conversation Prompt box afterwards Reach for it when
Restore code and conversation Tracked edits after the point are reverted Rewound to that message Original prompt restored for re-sending The approach and the code are both wrong
Restore conversation Unchanged Rewound to that message Original prompt restored The code is fine but the chat went somewhere unhelpful
Restore code Tracked edits after the point are reverted Kept as is Not described in the docs The reasoning was useful but the edits were bad
Never mind Unchanged Unchanged Back to the message list You are not sure yet

Here is what the docs predict after Restore code. app.js is back to the baseline, with both the prompt 1 change and the prompt 3 comment gone, because both were tracked edits made after the selected point. NOTES.md still exists and notes.txt is still missing. README.md still has your manual line. Compare that with your prediction sheet. If a row came out differently, the troubleshooting table below names the usual cause.

Matrix chart of Claude Code checkpoints in the rewind drill: five actions down the left (Restore code and conversation, Restore conversation, Restore code, Summarize from here, git restore) against four columns (app.js Edit tool, notes.txt Bash mv, README.md your editor, conversation history), each cell a labelled pill such as reverted, stays, rewound, kept, compressed, restored or untouched.Matrix chart of Claude Code checkpoints in the rewind drill: five actions down the left (Restore code and conversation, Restore conversation, Restore code, Summarize from here, git restore) against four columns (app.js Edit tool, notes.txt Bash mv, README.md your editor, conversation history), each cell a labelled pill such as reverted, stays, rewound, kept, compressed, restored or untouched.
Only git restores all three files in the drill. Rewind reverts only the app.js edits Claude's file tool made, and only the menu options touch the conversation. Original chart of documented behavior applied to this guide's worked example, based on Anthropic's Claude Code checkpointing docs and the git-restore documentation, fetched Oct 22, 2026.

To try the other two options yourself, roll the scratch repo back as described in the last section, repeat the three prompts, and choose differently. Watch the conversation side the second time. Both conversation restores put the original prompt back into the input field.

One trap applies to every conversation restore. Rewound messages can come back if you exit before your next prompt, because Claude Code saves the rewound conversation together with that next prompt. Send any prompt before you exit. If the messages have already returned, run /rewind, select the same prompt, and choose Restore conversation. Files you restored stay as the rewind left them.

Recover what the rewind left behind with git

The rewind did its part. The rename and the manual edit are now git’s job. git restore restores working-tree paths from the index by default, or from another commit when you pass --source.

# 1. See what is still different from the baseline
git status
# 2. Read the manual edit before deciding to keep or drop it
git diff README.md
# 3. Bring back the file that Bash renamed away
git restore notes.txt
# 4. Remove the untracked copy the rename created
rm NOTES.md
# 5. Optional: drop the manual line too
git restore README.md
# 6. Confirm you are back at the floor
git status
  1. Run git status. You should see notes.txt reported as deleted, NOTES.md as untracked, and README.md as modified. app.js should not appear, which shows the rewind restored it to exactly the committed content.
  2. Run git diff README.md and read the added line. This step protects real work. In a real project the manual edit might be the fix you wanted to keep.
  3. Run git restore notes.txt. The file comes back from the index.
  4. Delete NOTES.md. It was never committed, so git has nothing to restore it from, and git restore will not remove it for you.
  5. Run git restore README.md only if you want the manual line gone.
  6. Run git status again. A clean working tree means recovery is complete.

For a bigger mess, restore the whole tree from the last commit, including the index, with the top-of-tree pathspec documented on the same page:

git restore --source=HEAD --staged --worktree :/

If you committed during the session and want an older baseline, put that commit in --source. Afterwards, check git status for untracked files and delete the ones you do not want.

Notice the division of labour. Git returns everything to the last commit. Rewind is finer-grained between commits: it can drop prompt 3’s edit while keeping prompt 1’s, which git cannot do unless you committed between them.

Free context with Summarize from here and Summarize up to here

The same menu manages context, and neither summarize option touches files on disk. The original messages stay in the session transcript, so Claude can still refer back to them.

Action What it compresses Where you land Use it for
Summarize from here The selected message and everything after it The original prompt is back in the input field A long debugging tangent you want out of the way
Summarize up to here Everything before the selected message End of the conversation, empty input A long setup preamble that is crowding out recent work
/compact The whole conversation so far Same session General space-saving when no single tangent stands out
/clear Nothing; it starts a new conversation A new session A new task
/branch or claude --continue --fork-session Nothing; it copies A branch you can return from Trying a different approach while keeping the original intact
  1. Open the menu, select the message at the boundary, and highlight a Summarize option with the arrow keys.
  2. To steer the summary, type instructions where the row reads add context (optional), then press Enter. Pressing the option’s number key summarizes immediately with no instructions.
  3. Look for the Summarized conversation marker where the compressed messages were. That marker is your confirmation that it worked.

The docs call summarizing “like a targeted /compact”. The same caution applies: a summary can drop the one detail your next step needs. The checks in our compaction-summary lint carry over directly. One more recovery path: if you ran /clear earlier in the same Claude Code process, the rewind menu shows a /resume <session-id> (previous session) entry at the top that reopens the conversation you cleared. It disappears when you exit.

Decision table: which undo to reach for

Decide by who wrote the change, then by what you want to keep.

Situation Choose What changes What stays Is git needed?
Wrong approach: code and chat both went bad Restore code and conversation at the prompt before the detour Tracked files and chat Bash, manual and most subagent changes Yes, if any of those happened
Bad code, useful chat Restore code Tracked files The conversation Only for untracked changes
Good code, chat drifted Restore conversation Chat only All files No
Long tangent eating context Summarize from here Chat is compressed Files, transcript No
Long preamble eating context Summarize up to here Earlier chat is compressed Later messages, files No
Bash deleted or moved files git restore <path> Committed paths Untracked files Yes, rewind cannot help
Background subagent edited files Rewind for files the main chat had edited, git for the rest Shared files The subagent’s other files Yes
Symlinked or hard-linked file Ask Claude to reverse the edit, edit it yourself, or use git That file only Everything else If committed
Resumed session from days ago /rewind as normal Tracked files, if snapshots remain Anything past retention Yes, if No files were restored
Message marked No code restore Select the prompt that started the turn Edits from the whole turn Earlier turns No

Decision diagram for Claude Code checkpoints: a card reading A change you want back feeds a dark pill asking who wrote it, which fans out on curved arrows to five outcome cards: Claude's file-edit tool leads to /rewind, Restore code; Bash, shell or your editor leads to git restore; subagent, other files leads to git restore; symlink or hard link leads to edit it back, or git; snapshots past retention, outlined in red, leads to git, then raise retention.Decision diagram for Claude Code checkpoints: a card reading A change you want back feeds a dark pill asking who wrote it, which fans out on curved arrows to five outcome cards: Claude's file-edit tool leads to /rewind, Restore code; Bash, shell or your editor leads to git restore; subagent, other files leads to git restore; symlink or hard link leads to edit it back, or git; snapshots past retention, outlined in red, leads to git, then raise retention.
Decide by who wrote the change: rewind covers only edits from Claude's file tools in the session, while Bash, editor, most subagent and swept-snapshot cases fall back to git. Original diagram based on Anthropic's Claude Code checkpointing documentation, fetched Oct 22, 2026.

The subagent row deserves care. Per the checkpointing docs, a forked skill running in the foreground is rewound as usual, while any other subagent’s edits to files the main conversation had not touched stay put. If your team has started using forked subagents in scripts, the fork subagents migration runbook explains which ones run where.

Build the safety net before risky prompts

Checkpoints are, in Anthropic’s words, “designed for quick, session-level recovery” and are “not a replacement for version control”. Set up the floor before you need it.

  • [ ] Make a deliberate commit before any prompt you would hesitate to run twice, such as a refactor, a dependency upgrade or a migration.
  • [ ] Give risky work its own branch or worktree, so a full reset never touches your main line.
  • [ ] In prompts, ask Claude to change files with its edit tools when you want the change to be rewindable, and save shell rm/mv steps until after a commit.
  • [ ] Run git status before opening the rewind menu, so you know which uncommitted changes a code restore could overwrite.
  • [ ] Raise retention if you often rewind sessions that are weeks old.
  • [ ] Keep enough local history to reconstruct a bad night. Our fleet replay guide covers transcript evidence beyond a single session.

The checkpointing page says to set cleanupPeriodDays to keep snapshots longer. User settings live in ~/.claude/settings.json, and the settings reference warns that the file is strict JSON: comments or trailing commas produce a Settings Error at the next start. The value below is an example, not a recommendation:

{
  "$schema": "https://json.schemastore.org/claude-code-settings.json",
  "cleanupPeriodDays": 60
}

After saving, run /status and check that the Setting sources line includes User settings. The same key governs automatic session cleanup more broadly, so read the session cleanup and retention audit before raising it on a shared machine.

Some people would rather have no code restore at all. The environment variables reference documents CLAUDE_CODE_DISABLE_FILE_CHECKPOINTING: set it to 1 and /rewind cannot restore code changes. It overrides the fileCheckpointingEnabled setting, and it can go in a settings env block:

{
  "env": {
    "CLAUDE_CODE_DISABLE_FILE_CHECKPOINTING": "1"
  }
}

In the issue thread, one user reported that with it set, the rewind went straight to a conversation rollback with no menu. That is one person’s observation, not documented behavior. For most readers the better trade is to keep checkpoints, commit often, and choose each option deliberately.

Scripted rollback with the Agent SDK

If you run agents from code, the Agent SDK has the same safety valve. File checkpointing backs up files before Claude changes them with the Write, Edit and NotebookEdit tools. rewind_files() in Python, or rewindFiles() in TypeScript, restores those files. It does not rewind the conversation. On a rewind, Claude Code deletes files it created and restores modified files to their content at that point.

  1. Enable checkpointing and ask for user-message UUIDs in the stream. Without replay-user-messages, message.uuid is missing.
  2. Capture the first user message UUID and the session ID while the stream runs.
  3. To rewind after the stream completes, resume the session with an empty prompt, enable checkpointing on the resumed session too, and call the rewind from inside the response loop.

This is Anthropic’s lead Python example from that page:

import asyncio
from claude_agent_sdk import (
    ClaudeSDKClient,
    ClaudeAgentOptions,
    UserMessage,
    ResultMessage,
)


async def main():
    # Step 1: Enable checkpointing
    options = ClaudeAgentOptions(
        enable_file_checkpointing=True,
        permission_mode="acceptEdits",  # Auto-accept file edits without prompting
        extra_args={
            "replay-user-messages": None
        },  # Required to receive checkpoint UUIDs in the response stream
    )

    checkpoint_id = None
    session_id = None

    # Run the query and capture checkpoint UUID and session ID
    async with ClaudeSDKClient(options) as client:
        await client.query("Refactor the authentication module")

        # Step 2: Capture checkpoint UUID from the first user message
        async for message in client.receive_response():
            if isinstance(message, UserMessage) and message.uuid and not checkpoint_id:
                checkpoint_id = message.uuid
            if isinstance(message, ResultMessage) and not session_id:
                session_id = message.session_id

    # Step 3: Later, rewind by resuming the session with an empty prompt
    if checkpoint_id and session_id:
        async with ClaudeSDKClient(
            ClaudeAgentOptions(enable_file_checkpointing=True, resume=session_id)
        ) as client:
            await client.query("")  # Empty prompt to open the connection
            async for message in client.receive_response():
                await client.rewind_files(checkpoint_id)
                break
        print(f"Rewound to checkpoint: {checkpoint_id}")


asyncio.run(main())

The acceptEdits permission mode approves edits without asking, so use it only in a scratch project. Once you have both IDs, you can also rewind from a shell. The bare CLI needs the environment variable, and the --rewind-files flag is accepted even though claude --help does not list it:

CLAUDE_CODE_ENABLE_SDK_FILE_CHECKPOINTING=true claude -p --resume <session-id> --rewind-files <checkpoint-uuid>

On success the docs say it prints Files rewound to state at message <checkpoint-uuid> and exits without sending a prompt. The SDK has the same blind spots as the interactive feature: Bash changes are not tracked, subagent edits are not tracked except a foreground forked skill, checkpoints belong to the session that created them, and directory operations and remote files are out of scope. From v2.1.216, a rewind skips symlinks, hard links and other non-regular files and counts them in skippedLinks on the result.

Troubleshooting rewinds that did not do what you expected

Symptom Likely cause Fix What you should see after the fix
Only Restore conversation, the summarize options and Never mind appear No tracked file edits after that checkpoint, or file checkpointing is disabled Select an earlier prompt that preceded an edit; check that CLAUDE_CODE_DISABLE_FILE_CHECKPOINTING is unset Restore code options appear for a prompt that preceded a tracked edit
Restored the code, but skipped N files Those tracked paths are symlinks or hard links, for example dotfile-manager configs or pnpm hard links Run /debug before restoring; the log at ~/.claude/debug/<session-id>.txt names each skipped path. Then reverse those edits by hand, or ask Claude to reverse the edit or edit the file yourself Skipped files show the content you intended
A rewind wiped a manual edit You edited a file the session had also edited, so it was tracked Recover from git if the edit was committed; otherwise retype it. Commit before restoring next time git diff shows your edit back
No files were restored The snapshots were deleted by the retention sweep Use git; raise cleanupPeriodDays for future sessions The file matches the git baseline
Rewound messages are back after you resumed You exited before sending another prompt /rewind, same prompt, Restore conversation, then send a prompt before exiting The rewound turns stay gone on the next resume
The checkpoint you wanted is missing after a resume or reboot You are in a different session, for example after /clear Use the /resume <session-id> (previous session) entry, or /resume the right session; see what survives a cold restart The original prompts are listed in the menu
Subagent changes were not reverted A background subagent edited files the main conversation never touched git restore those paths git status lists no subagent leftovers
A message is marked No code restore You typed it mid-turn, so it has no checkpoint of its own Select the prompt that started that turn and restore code The whole turn’s edits are reverted

Success checks and full rollback

You have finished the drill when every box below is ticked.

  • [ ] Before opening the menu, you predicted correctly which of the three changes each option would restore, and the prediction sheet matched the result.
  • [ ] After recovery, git status reports a clean working tree.
  • [ ] You can say, without checking, why the prompt 3 comment disappeared when you restored at prompt 1.
  • [ ] Your real projects have a deliberate commit before any prompt you consider risky.

To back out at any point:

  1. Inside the rewind menu, choose Never mind to leave without changes.
  2. To return the scratch repo to its baseline, run git restore --source=HEAD --staged --worktree :/, then delete any untracked leftovers that git status lists, such as NOTES.md.
  3. When you are done practising, exit Claude Code and delete the rewind-drill directory.

The habit worth keeping is the order of questions: who wrote this change, is it tracked, and is it committed. Answer those three before pressing Enter and the rewind menu becomes a precise tool rather than a gamble.

Sources

  1. Cozy (@Cozy2054934) on X, post of Oct 20, 2026: Every prompt creates a checkpoint; Bash edits aren’t tracked
  2. Anthropic, Claude Code Docs: Checkpointing
  3. Anthropic, Claude Code Docs: Rewind file changes with checkpointing (Agent SDK)
  4. Anthropic, Claude Code Docs: Interactive mode
  5. Anthropic, Claude Code Docs: Commands
  6. Anthropic, Claude Code Docs: Environment variables
  7. Anthropic, Claude Code Docs: Settings files and precedence
  8. GitHub, anthropics/claude-code: Issue #64615, /rewind default restores code without confirmation
  9. Git project: git-restore documentation
YOU'RE THROUGH THIS ONE.

Keep connecting the dots.

Back to the library