Skip to content

Commit 1348ee2

Browse files
henrikjeclaude
andcommitted
fix(delete): fetch each repo once across all candidate workspaces
Collecting worktree paths from N workspaces produced N distinct entries for the same underlying repo, bypassing Set deduplication and causing redundant fetches. Now deduplicates by repo name and fetches from canonical repo dirs in .arb/repos/, matching the pattern used by all other multi-repo fetch paths. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 658c446 commit 1348ee2

File tree

2 files changed

+21
-4
lines changed

2 files changed

+21
-4
lines changed

src/commands/delete.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -338,20 +338,21 @@ export function registerDeleteCommand(program: Command, getCtx: () => ArbContext
338338
// Pre-fetch repos across all candidate workspaces for fresh remote data
339339
const fetchWorkspaceRepos = async (workspaceNames: string[]) => {
340340
if (options.fetch === false) return;
341-
const allRepoDirs = new Set<string>();
342341
const allRepoNames = new Set<string>();
343342
for (const ws of workspaceNames) {
344343
const wsDir = `${ctx.arbRootDir}/${ws}`;
345344
for (const repoDir of workspaceRepoDirs(wsDir)) {
346-
allRepoDirs.add(repoDir);
347345
allRepoNames.add(basename(repoDir));
348346
}
349347
}
350-
if (allRepoDirs.size === 0) return;
348+
if (allRepoNames.size === 0) return;
349+
// Fetch from canonical repo dirs so each repo is only fetched once,
350+
// regardless of how many workspaces reference it.
351+
const allRepoDirs = [...allRepoNames].map((name) => `${ctx.reposDir}/${name}`);
351352
const cache = new GitCache();
352353
await assertMinimumGitVersion(cache);
353354
const remotesMap = await cache.resolveRemotesMap([...allRepoNames], ctx.reposDir);
354-
const fetchResults = await parallelFetch([...allRepoDirs], undefined, remotesMap);
355+
const fetchResults = await parallelFetch(allRepoDirs, undefined, remotesMap);
355356
reportFetchFailures([...allRepoNames], fetchResults);
356357
};
357358

test/integration/workspace-membership.test.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -947,4 +947,20 @@ describe("delete empty workspace", () => {
947947
expect(result.exitCode).toBe(0);
948948
expect(existsSync(join(env.projectDir, "my-feature"))).toBe(false);
949949
}));
950+
951+
test("arb delete --all-safe fetches each repo only once across multiple workspaces", () =>
952+
withEnv(async (env) => {
953+
// Create multiple workspaces all using the same single repo
954+
await arb(env, ["create", "ws-one", "repo-a"]);
955+
await arb(env, ["create", "ws-two", "repo-a"]);
956+
await arb(env, ["create", "ws-three", "repo-a"]);
957+
await git(join(env.projectDir, "ws-one/repo-a"), ["push", "-u", "origin", "ws-one"]);
958+
await git(join(env.projectDir, "ws-two/repo-a"), ["push", "-u", "origin", "ws-two"]);
959+
await git(join(env.projectDir, "ws-three/repo-a"), ["push", "-u", "origin", "ws-three"]);
960+
961+
const result = await arb(env, ["delete", "--all-safe", "--yes", "--force"]);
962+
expect(result.exitCode).toBe(0);
963+
// Should report "1 repo" fetched, not "3 repos"
964+
expect(result.output).toMatch(/Fetched 1 repo in/);
965+
}));
950966
});

0 commit comments

Comments
 (0)