diff --git a/src/main/ipc/worktree-git-common-watch.test.ts b/src/main/ipc/worktree-git-common-watch.test.ts index eb6a62068f8..9cc70f1d7e0 100644 --- a/src/main/ipc/worktree-git-common-watch.test.ts +++ b/src/main/ipc/worktree-git-common-watch.test.ts @@ -128,6 +128,17 @@ describe('worktree git-common narrow watch (darwin)', () => { await vi.waitFor(() => { expect(subscribeMock).toHaveBeenCalledTimes(2) }) + + const receivedAfterRearm = received.length + childSubscriptions[0].callback(new Error('late error from replaced watcher'), []) + childSubscriptions[0].callback(null, [ + { type: 'create', path: join(worktreesDir, 'late-old-event') } + ]) + childSubscriptions[0].hooks.onInterruption?.() + + // A replaced watch cannot tear down its successor or report stale events. + expect(received).toHaveLength(receivedAfterRearm) + expect(childSubscriptions[1].unsubscribe).not.toHaveBeenCalled() }) it('reports a structural change after a watcher-child interruption', async () => { diff --git a/src/main/ipc/worktree-git-common-watch.ts b/src/main/ipc/worktree-git-common-watch.ts index e4a80723bd1..705963ed726 100644 --- a/src/main/ipc/worktree-git-common-watch.ts +++ b/src/main/ipc/worktree-git-common-watch.ts @@ -162,12 +162,14 @@ async function startGitCommonNarrowWatch( return false } let errored = false + let active = true // Why: parcel tears its native stream down when the watched root is // deleted (e.g. `git worktree prune` removing an empty worktrees dir) — // sometimes surfaced as an error, sometimes as a delete event for the // root. Either way: notify, drop the dead stream, and let the existence // poll re-arm when a future worktree add recreates the dir. const teardownAndRearm = (): void => { + active = false errored = true const current = subscription subscription = null @@ -180,7 +182,7 @@ async function startGitCommonNarrowWatch( const sub = await subscribeViaWatcherProcess( worktreesDir, (error, events) => { - if (disposed) { + if (disposed || !active) { return } if (error) { @@ -203,7 +205,7 @@ async function startGitCommonNarrowWatch( // Why: a watcher-child crash drops events during the automatic // resubscribe gap; report a structural change so worktrees re-sync. onInterruption: () => { - if (!disposed) { + if (!disposed && active) { onEvents([{ type: 'update', path: worktreesDir }]) } }