diff --git a/src/services/__tests__/file-watcher.test.ts b/src/services/__tests__/file-watcher.test.ts index 10e8679..ac7fa02 100644 --- a/src/services/__tests__/file-watcher.test.ts +++ b/src/services/__tests__/file-watcher.test.ts @@ -91,6 +91,17 @@ describe('FileWatcher debounce / cooldown / suppress state machine', () => { expect(onChange).not.toHaveBeenCalled(); }); + it('watches the worktree registry, not each worktree\'s private state', () => { + // `worktrees/**` also matched every worktree's runtime files (index.lock, + // FETCH_HEAD, COMMIT_EDITMSG, logs/**). In a linked worktree that set is + // our OWN gitdir, so the panel's git commands fed its own watcher — an + // endless refresh that restarted any in-flight history search. Only the + // registry entries `worktree list` actually reports are worth watching. + const patterns = h.watchers.map(w => w.pattern.pattern); + expect(patterns).toContain('worktrees/*/{HEAD,gitdir,locked}'); + expect(patterns).not.toContain('worktrees/**'); + }); + it('does not fire when disabled', () => { fw.enabled = false; fireOn('**', `${REPO}/src/a.ts`); diff --git a/src/services/file-watcher.ts b/src/services/file-watcher.ts index 329e0b5..341ab3a 100644 --- a/src/services/file-watcher.ts +++ b/src/services/file-watcher.ts @@ -36,7 +36,15 @@ export class FileWatcher implements vscode.Disposable { this.addWatcher(new vscode.RelativePattern(this.commonDir, 'refs/stash')); this.addWatcher(new vscode.RelativePattern(this.commonDir, 'packed-refs')); this.addWatcher(new vscode.RelativePattern(this.commonDir, 'config')); - this.addWatcher(new vscode.RelativePattern(this.commonDir, 'worktrees/**')); + // Only the registry entries `git worktree list` reports: the admin dir + // appearing/disappearing (gitdir), where each worktree points (HEAD), and + // its lock state. NOT `worktrees/**` — that also matched every worktree's + // private runtime state (index, index.lock, FETCH_HEAD, COMMIT_EDITMSG, + // logs/**). For a linked worktree that state IS our own gitdir, so the + // panel's own `git status` retriggered its own watcher: a refresh loop + // that also restarted any in-flight history search. For a main repo it + // meant every git command in a sibling worktree forced a full refresh. + this.addWatcher(new vscode.RelativePattern(this.commonDir, 'worktrees/*/{HEAD,gitdir,locked}')); // Watch working tree for file changes (exclude heavy dirs via specific patterns) // Using {src,lib,app,...}/** would be too restrictive, so we watch ** but filter