Two related worktree/uncommitted-diff bugs found while reviewing an uncommitted diff in a linked git worktree (v0.7.0).
1. watchRepo never fires git_changed in linked worktrees
server/session.ts (~L476):
const gitDir = join(this.repoPath, '.git');
...
const indexPath = join(gitDir, 'index');
const headPath = join(gitDir, 'HEAD');
In a linked worktree (git worktree add), repoPath/.git is a file containing gitdir: /main/repo/.git/worktrees/<name>, not a directory. statSync(indexPath) / readFileSync(headPath) throw on every poll tick, the catch blocks swallow it, and git_changed never broadcasts — so open browser tabs never learn the working tree changed and keep rendering the stale diff (the server's getItemData('diff') is live, so a manual reload shows current state; the UI just never asks).
Fix: resolve the real git dir, e.g. git rev-parse --git-dir (or read the gitdir: pointer when .git is a file). Note the worktree's HEAD and its index both live in the per-worktree gitdir (.git/worktrees/<name>/).
2. Freshness diffs base...HEAD, but the UI diff includes the working tree
getBranchDiff (used by the diff item) deliberately includes uncommitted/staged changes ("so the review UI reflects the live state of the checkout"). But getBranchDiffRaw (used to compute analysis freshness) runs:
gitRun(repoPath, 'diff', '--raw', '--no-abbrev', `${baseBranch}...HEAD`);
With an entirely-uncommitted diff (no commits on the branch), that's empty — so read_analysis freshness reports every analyzed file in removedFiles, and a refresh flow trusting it would delete the whole analysis. The two functions should agree on what "the diff" is; getBranchDiffRaw could diff mergeBase → working tree over the same file set getBranchDiff computes.
Repro
git worktree add a branch, make working-tree-only changes (no commits).
claim_reviews + set_analysis, open the UI.
- Edit files — UI never refreshes (bug 1).
read_analysis → freshness lists all analyzed files as removedFiles (bug 2).
Two related worktree/uncommitted-diff bugs found while reviewing an uncommitted diff in a linked git worktree (v0.7.0).
1.
watchReponever firesgit_changedin linked worktreesserver/session.ts(~L476):In a linked worktree (
git worktree add),repoPath/.gitis a file containinggitdir: /main/repo/.git/worktrees/<name>, not a directory.statSync(indexPath)/readFileSync(headPath)throw on every poll tick, the catch blocks swallow it, andgit_changednever broadcasts — so open browser tabs never learn the working tree changed and keep rendering the stale diff (the server'sgetItemData('diff')is live, so a manual reload shows current state; the UI just never asks).Fix: resolve the real git dir, e.g.
git rev-parse --git-dir(or read thegitdir:pointer when.gitis a file). Note the worktree'sHEADand itsindexboth live in the per-worktree gitdir (.git/worktrees/<name>/).2. Freshness diffs
base...HEAD, but the UI diff includes the working treegetBranchDiff(used by the diff item) deliberately includes uncommitted/staged changes ("so the review UI reflects the live state of the checkout"). ButgetBranchDiffRaw(used to compute analysis freshness) runs:With an entirely-uncommitted diff (no commits on the branch), that's empty — so
read_analysisfreshness reports every analyzed file inremovedFiles, and a refresh flow trusting it would delete the whole analysis. The two functions should agree on what "the diff" is;getBranchDiffRawcould diffmergeBase→ working tree over the same file setgetBranchDiffcomputes.Repro
git worktree adda branch, make working-tree-only changes (no commits).claim_reviews+set_analysis, open the UI.read_analysis→ freshness lists all analyzed files asremovedFiles(bug 2).