fix(snapshot): reverting in a session can wipe out other files that have changed
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:
- The snapshot index is shared across all sessions in a project
git add .from a subdirectory only updates that subdirectory's entries in the indexrestore()usedcheckout-index -awhich restores ALL files in the indexdiff()usedcwd(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 usingls-treeand only restores those specific filesdiff()now usescwd(Instance.directory)so the-- .path spec is relative to the session directory
Steps to Reproduce
- 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"
- Run opencode from
backend/, make a change, then exit:
cd /tmp/testproject/backend
opencode
# Ask it to modify server.go, then exit
- 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"
- 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"
- 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).