What /undo really reverts in OpenCode, and how to recover when it doesn't
/undo sounds like one action. In OpenCode it is two: remove recent conversation, and restore files from a snapshot. A snapshot is a saved copy of the working tree that OpenCode keeps outside your repository, so it can put files back without making a commit. When the two halves agree, undo feels clean. When they disagree, you get the reports this page is about: the message disappeared but the files did not, or the files went back to a state from weeks ago and took current work with them.
The files half is the part that surprises people. It is best effort, it has a scope, and it is not a backup.
Run opencode --version first. A 1.x version is V1, a 2.x version is V2. This page leads with V2 and keeps the V1 differences in the table below. The commands here were checked on OpenCode 2.1.4.
Checked against OpenCode's documentation on 27 October 2026.
Status, 27 October 2026: the reports behind this page are closed, but closure is not proof of a fix. #5474 and #4704 were closed as not planned; #10287 was closed automatically as completed after 60 days of inactivity on 22 April 2026 while a comment on 28 July 2026 said it still happened; #6845 was closed after a 2 MiB cap, with later comments reporting growth. A subdirectory start was reported to let a shared snapshot index overwrite files outside it (#7775).
The two halves of an undo#
In V2, /undo stages a rollback: it restores the affected files and puts the removed prompt back in the composer so you can edit it. Submitting the edited prompt commits the staged rollback. Before you submit, /redo cancels it and restores the conversation and files you had before the undo. You can also select an earlier message and choose Revert to stage a rollback to that point.
In V1, /undo removes the most recent user message, all responses after it, and any file changes. /redo becomes available after an undo and restores the message and its file changes. V1's docs describe the file side as Git-backed and say the project must be a Git repository.
| Item | V1 (1.x) | V2 (2.x) |
|---|---|---|
| File restore | Git-backed, in a Git repository | Snapshot store, in a Git repository |
| Outside Git | No file restore | Conversation rollback only |
| Setting to turn it off | snapshot: false | snapshots: false |
The V2 location comes from packages/core/src/snapshot.ts at commit f993a89: under the data directory, snapshot/, then the project ID and worktree hash. The V1 path is the one in the issue reports, not a documented layout; check your own data directory before deleting anything.
What a snapshot covers#
V2's snapshots page is worth reading as a scope list rather than a feature list.
| Content | Captured? | Example |
|---|---|---|
| Tracked files in the active directory | Yes | packages/app/src/app.tsx |
| Non-ignored untracked files up to 2 MiB each | Yes | packages/app/notes.txt |
| Git-ignored files | No | packages/app/dist/app.js |
| An untracked file larger than 2 MiB | No | packages/app/debug.log |
| Files outside the active directory | No | packages/server/src/index.ts |
The active directory is the directory the session was opened in, inside the Git worktree (the checkout the session was opened in). A session opened in packages/app captures eligible files below it, not the rest of the repository.
A rollback restores only paths attributed to assistant steps after the selected conversation boundary. Each path returns to its state before the first reverted step; a file created by those steps is removed if it did not exist at the boundary. Paths not attributed to those steps are left alone. Current edits to an affected path can be overwritten, so review the restored summary and git diff before continuing.
Capture is best effort: if either the before or after snapshot is unavailable, the conversation continues, but that step may have no file changes to restore. A snapshot is not a transaction either: shell commands can change services, processes, network resources, databases, Git state, ignored output, or files outside the active directory, and undo does not reverse those.
Why the files did not change#
Most "undo did nothing" cases fall into one of these.
- The project is not a Git repository. Neither version promises file restore without one. V2's docs say conversation rollback still works; V1's docs only promise file changes in a Git repository.
- Capture is best effort and scoped. A missing before/after pair leaves the files unchanged while the message goes; on 1.x, a first session in a new folder was reported to fail until a restart (#4704). Only the active directory is captured: ignored files, untracked files over 2 MiB, files outside it, and Git metadata are not. Snapshots can also be off: V1 uses
snapshot: false, V2 usessnapshots: false. - The change was external. Package installs, database writes, background processes, and network calls are not files in the snapshot. Undo cannot bring them back or take them away.
Sometimes undo worked and you did not like the result. A report on 1.x described files returning to a weeks-old state and deleting committed code from the working tree (#10287). That needs the recovery steps below.
Recover without making it worse#
Stop the agent first. More tool calls on a worktree you do not understand make the diff harder to read.
- Look at the worktree. Run
git status --shortandgit diff --stat, thengit difffor the files that matter. Check what changed; do not run another prompt until you have read it. - If the undo went too far, try
/redobefore resubmitting. V2's/redocancels a staged rollback. Once you submit the restored prompt, the rollback is committed and/redois no longer the way back. V1's/redoworks after an undo. - Restore individual files from Git. If the content is in
HEAD,git restore --source=HEAD -- path/to/fileputs that version in the working tree.git restore path/to/filerestores from the index, so check what is staged first. Only the files you name change. - If the agent committed the change, use the commit history.
git log --onelineshows what happened.git revert <commit>adds a commit that reverses an earlier one, which is safer on a shared branch than rewriting history. - If the snapshot store looks broken, move it aside rather than deleting it. On 1.x, a reported repair was to close OpenCode, move
~/.local/share/opencode/snapshot/globalaside, and restart (#4704). It is a user report, not a documented repair, and it gives up that store's history. On V2, find the data directory withopencode debug paths data, then move only the affected project's directory undersnapshot/. Never touch the repository's own.git. - If snapshots were disabled, turn them back on. V1:
snapshotinopencode.json. V2:snapshotsinopencode.jsonc. New work is captured; old work is not retroactive. - If the file is outside the scope, use Git or your editor's local history. A file ignored by Git, over 2 MiB, or outside the active directory was never in the snapshot. Use a commit, a stash, or the editor's local history.
The order matters: /redo is cheap while staged, Git restore is targeted, and deleting a store gives up history. Running the agent again is not recovery.
The disk cost is real#
Snapshots store file contents in a separate Git object database. It is not your repository, but it can grow like one. On 1.x, reports described the snapshot folder reaching 169 GB and 300 GB (#6845). A 2 MiB per-file cap keeps large binaries out, but many small files can still accumulate. The objects can contain complete file contents; treat the directory as sensitive.
Measure before you delete:
# V2
du -sh "$(opencode debug paths data)/snapshot"
# V1: `opencode debug paths` lists every path; use its data line
opencode debug paths
du -sh ~/.local/share/opencode/snapshotDisabling snapshots stops future capture; it does not delete what is stored. V1 uses "snapshot": false; V2 uses "snapshots": false.
A safer habit#
- Commit or stash before asking for a risky change. That is a recovery point outside the snapshot scope.
- After any undo, read
git diffbefore you continue; the conversation and the files are allowed to disagree. - Do not use
/undoas your backup. It misses ignored files, files outside the active directory, and external side effects.
Where to go next#
- OpenCode guides — the hub for the set.
- Why your OpenCode plugin or hook isn't running — when a guard never fired.
- Why OpenCode permission rules don't fire — when an action must be enforced.
- Where did my OpenCode session go? — for conversation recovery.