opencode icon indicating copy to clipboard operation
opencode copied to clipboard

fix(snapshot): reverting in a session can wipe out other files that have changed

Open ryanwyler opened this issue 3 days ago • 2 comments

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 "[email protected]" && 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).

ryanwyler avatar Jan 11 '26 10:01 ryanwyler