[PR #7774] fix(snapshot): reverting in a session can wipe out other files that have changed #12510

Open
opened 2026-02-16 18:17:25 -05:00 by yindo · 0 comments
Owner

Original Pull Request: https://github.com/anomalyco/opencode/pull/7774

State: open
Merged: No


Summary

Fixes #7775

Fixes a bug where running opencode from a subdirectory and clicking "undo revert" would overwrite files in other directories with stale versions from weeks ago.

Problem

When running opencode from a subdirectory (e.g., project/frontend/), the unrevert operation would restore stale versions of files in other directories (e.g., project/backend/). This happened because:

  1. The snapshot index is shared across all sessions in a project
  2. git add . from a subdirectory only updates that subdirectory's entries in the index
  3. restore() used checkout-index -a which restores ALL files in the index
  4. diff() used cwd(Instance.worktree) showing diffs for unrelated directories

Solution

Scope both restore() and diff() to Instance.directory:

  • restore() now lists files under the session directory prefix using ls-tree and only restores those specific files
  • diff() now uses cwd(Instance.directory) so the -- . path spec is relative to the session directory

Steps to Reproduce

  1. Create a project with multiple subdirectories:
mkdir -p /tmp/testproject/frontend /tmp/testproject/backend
cd /tmp/testproject
git init && git config user.email "test@test.com" && git config user.name "Test"
echo 'console.log("frontend")' > frontend/app.ts
echo 'println("backend ORIGINAL")' > backend/server.go
git add . && git commit -m "Initial"
  1. Run opencode from backend/, make a change, then exit:
cd /tmp/testproject/backend
opencode
# Ask it to modify server.go, then exit
  1. Update backend externally (simulates multitasking with different agents or personally making edits outside of opencode):
echo 'println("backend CURRENT")' > backend/server.go
git add . && git commit -m "Update backend"
  1. Run opencode from frontend/, make a change, revert, then unrevert:
cd /tmp/testproject/frontend
opencode
# Ask it to modify app.ts
# Click "Revert" on the assistant's message
# Click "Undo Revert"
  1. Check if backend was corrupted:
cat /tmp/testproject/backend/server.go
# BUG: Shows "backend ORIGINAL" (stale version)
# FIXED: Shows "backend CURRENT" (unchanged)

Testing

  • All existing snapshot tests pass
  • Manually verified the fix prevents stale file restoration
  • Verified revert/unrevert still works correctly for files in the session directory

Bug History

Traced the origin of this bug through git history:

Date Commit Change Impact
Jul 1, 2025 11d042be2 Original snapshot implementation using isomorphic-git with per-session snapshots Safe - each session isolated
Jul 24, 2025 284c01018 Refactored to shell git commands with checkout-index -a -f Bug introduced - restores ALL files in index
Sep 1, 2025 f993541e0 Changed from per-session to per-project snapshots Bug became severe - sessions now share snapshot index

The original per-session implementation was safe because each session had its own isolated snapshot directory. The bug was introduced when refactoring to shell git commands (checkout-index -a restores all files regardless of cwd), and became a real problem when snapshots became shared per-project (stale entries from other sessions persist in the shared index).

**Original Pull Request:** https://github.com/anomalyco/opencode/pull/7774 **State:** open **Merged:** No --- ## Summary Fixes #7775 Fixes a bug where running opencode from a subdirectory and clicking "undo revert" would overwrite files in other directories with stale versions from weeks ago. ## Problem When running opencode from a subdirectory (e.g., `project/frontend/`), the unrevert operation would restore stale versions of files in other directories (e.g., `project/backend/`). This happened because: 1. The snapshot index is shared across all sessions in a project 2. `git add .` from a subdirectory only updates that subdirectory's entries in the index 3. `restore()` used `checkout-index -a` which restores ALL files in the index 4. `diff()` used `cwd(Instance.worktree)` showing diffs for unrelated directories ## Solution Scope both `restore()` and `diff()` to `Instance.directory`: - `restore()` now lists files under the session directory prefix using `ls-tree` and only restores those specific files - `diff()` now uses `cwd(Instance.directory)` so the `-- .` path spec is relative to the session directory ## Steps to Reproduce 1. Create a project with multiple subdirectories: ```bash mkdir -p /tmp/testproject/frontend /tmp/testproject/backend cd /tmp/testproject git init && git config user.email "test@test.com" && git config user.name "Test" echo 'console.log("frontend")' > frontend/app.ts echo 'println("backend ORIGINAL")' > backend/server.go git add . && git commit -m "Initial" ``` 2. Run opencode from `backend/`, make a change, then exit: ```bash cd /tmp/testproject/backend opencode # Ask it to modify server.go, then exit ``` 3. Update backend externally (simulates multitasking with different agents or personally making edits outside of opencode): ```bash echo 'println("backend CURRENT")' > backend/server.go git add . && git commit -m "Update backend" ``` 4. Run opencode from `frontend/`, make a change, revert, then unrevert: ```bash cd /tmp/testproject/frontend opencode # Ask it to modify app.ts # Click "Revert" on the assistant's message # Click "Undo Revert" ``` 5. Check if backend was corrupted: ```bash cat /tmp/testproject/backend/server.go # BUG: Shows "backend ORIGINAL" (stale version) # FIXED: Shows "backend CURRENT" (unchanged) ``` ## Testing - All existing snapshot tests pass - Manually verified the fix prevents stale file restoration - Verified revert/unrevert still works correctly for files in the session directory ## Bug History Traced the origin of this bug through git history: | Date | Commit | Change | Impact | |------|--------|--------|--------| | Jul 1, 2025 | `11d042be2` | Original snapshot implementation using `isomorphic-git` with **per-session** snapshots | Safe - each session isolated | | Jul 24, 2025 | `284c01018` | Refactored to shell git commands with `checkout-index -a -f` | **Bug introduced** - restores ALL files in index | | Sep 1, 2025 | `f993541e0` | Changed from per-session to **per-project** snapshots | **Bug became severe** - sessions now share snapshot index | The original per-session implementation was safe because each session had its own isolated snapshot directory. The bug was introduced when refactoring to shell git commands (`checkout-index -a` restores all files regardless of cwd), and became a real problem when snapshots became shared per-project (stale entries from other sessions persist in the shared index).
yindo added the pull-request label 2026-02-16 18:17:25 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: anomalyco/opencode#12510