fix(worktree): collapse path-equal rows in worktree list

orca worktree list merged git-scan and stored-path spellings of the same
worktree, so master appeared twice. Dedupe by path and keep the branched
git row.

Preserves distinct repos that happen to share a branch name.
This commit is contained in:
Wooseong Kim
2026-08-21 22:57:56 -07:00
committed by Neil
parent 2b1254d681
commit 45efc5fe42
2 changed files with 40 additions and 1 deletions
@@ -61,6 +61,39 @@ function createDeps(repos: Repo[]): RepoWorktreeRowDeps & {
return { store, metaById, scanRepo, listFolderWorkspaces }
}
describe('path-equal worktree row collapse', () => {
it('keeps one row and prefers the git branch when the same path is listed twice', async () => {
const owner = repo('repo', '/home/me/repo')
const deps = createDeps([owner])
deps.scanRepo.mockResolvedValueOnce({
ok: true,
worktrees: [
{
path: '/home/me/repo',
head: '',
branch: '',
isBare: false,
isMainWorktree: true
},
{
path: '/home/me/./repo',
head: 'abc123',
branch: 'refs/heads/master',
isBare: false,
isMainWorktree: true
}
]
})
const rows = await resolveRepoWorktreeRows(deps, owner, deps.metaById, new Map())
expect(rows).toHaveLength(1)
expect(rows[0]).toMatchObject({
branch: 'refs/heads/master',
path: '/home/me/./repo'
})
})
})
describe('host-qualified scoped worktree resolution', () => {
it('scans only the selected local or SSH owner when repo ids and paths collide', async () => {
const owners = [
@@ -10,6 +10,7 @@ import type { WorktreeMeta } from '../../shared/worktree/meta-types'
import type { ProjectExecutionRuntimeResolution } from '../../shared/project-execution-runtime'
import type { Store } from '../persistence'
import { areWorktreePathsEqual, mergeWorktree } from '../ipc/worktree-logic'
import { dedupeWorktreesByPath } from '../ipc/worktree-path-comparison'
import { pruneLineageForMissingRepoWorktrees } from '../worktree-lineage-pruning'
import { getRepoOwnedWorktreeMeta } from '../worktree-metadata-ownership'
import { resolveLocalProjectRuntimesForRepos } from '../project-runtime-git-options'
@@ -121,7 +122,12 @@ export async function resolveRepoWorktreeRows(
RESOLVED_WORKTREE_REPO_TIMEOUT_MS,
null
)) ?? { ok: false, worktrees: listStoredWorktreeRowsForRepo(store, repo, repoOwnerCount) }
const gitWorktrees = scan.worktrees
const gitWorktrees = dedupeWorktreesByPath(
// Why: keep the git-scanned branch over a stored empty-branch clone of the same path (#15526).
[...scan.worktrees].sort(
(left, right) => Number(Boolean(right.branch)) - Number(Boolean(left.branch))
)
)
if (scan.ok) {
pruneLineageForMissingRepoWorktrees(store, repo, gitWorktrees)
}