From 08d2dc173802d08b6c134c3b892658316aafe5bf Mon Sep 17 00:00:00 2001 From: tonymmm1 Date: Fri, 29 May 2026 18:19:23 -0400 Subject: [PATCH] Fix ambiguous git worktree start points --- apps/server/src/vcs/GitVcsDriverCore.test.ts | 43 ++++++++++++++++++++ apps/server/src/vcs/GitVcsDriverCore.ts | 34 +++++++++++++++- 2 files changed, 75 insertions(+), 2 deletions(-) diff --git a/apps/server/src/vcs/GitVcsDriverCore.test.ts b/apps/server/src/vcs/GitVcsDriverCore.test.ts index 00f40a69aa7..70726e1c7f4 100644 --- a/apps/server/src/vcs/GitVcsDriverCore.test.ts +++ b/apps/server/src/vcs/GitVcsDriverCore.test.ts @@ -285,6 +285,49 @@ it.layer(TestLayer)("GitVcsDriver core integration", (it) => { assert.equal(yield* fileSystem.exists(worktreePath), false); }), ); + + it.effect("creates a new worktree when the base branch name is also a remote ref", () => + Effect.gen(function* () { + const cwd = yield* makeTmpDir(); + const remote = yield* makeTmpDir("git-vcs-driver-remote-"); + const { initialBranch } = yield* initRepoWithCommit(cwd); + const pathService = yield* Path.Path; + const worktreePath = pathService.join( + yield* makeTmpDir("git-worktrees-"), + "feature-ambiguous-worktree", + ); + const driver = yield* GitVcsDriver.GitVcsDriver; + + yield* git(remote, ["init", "--bare"]); + yield* git(cwd, ["remote", "add", initialBranch, remote]); + yield* git(cwd, ["push", initialBranch, `${initialBranch}:${initialBranch}`]); + yield* git(cwd, [ + "fetch", + initialBranch, + `${initialBranch}:refs/remotes/${initialBranch}/${initialBranch}`, + ]); + + const refs = yield* git(cwd, ["show-ref", initialBranch]); + assert.include(refs, `refs/heads/${initialBranch}`); + assert.include(refs, `refs/remotes/${initialBranch}/${initialBranch}`); + + const created = yield* driver.createWorktree({ + cwd, + path: worktreePath, + refName: initialBranch, + newRefName: "feature/ambiguous-worktree", + }); + + assert.equal(created.worktree.path, worktreePath); + assert.equal(created.worktree.refName, "feature/ambiguous-worktree"); + assert.equal( + yield* git(worktreePath, ["branch", "--show-current"]), + "feature/ambiguous-worktree", + ); + + yield* driver.removeWorktree({ cwd, path: worktreePath }); + }), + ); }); describe("commit context", () => { diff --git a/apps/server/src/vcs/GitVcsDriverCore.ts b/apps/server/src/vcs/GitVcsDriverCore.ts index 7a4fb6dd46f..7f701c6589e 100644 --- a/apps/server/src/vcs/GitVcsDriverCore.ts +++ b/apps/server/src/vcs/GitVcsDriverCore.ts @@ -963,6 +963,35 @@ export const makeGitVcsDriverCore = Effect.fn("makeGitVcsDriverCore")(function* Effect.map(parseRemoteNamesInGitOrder), ); + const qualifyWorktreeStartPoint = Effect.fn("qualifyWorktreeStartPoint")(function* ( + cwd: string, + refName: string, + ) { + if (refName.startsWith("refs/")) { + return refName; + } + + const isLocalBranch = yield* branchExists(cwd, refName); + if (isLocalBranch) { + return `refs/heads/${refName}`; + } + + const remoteNames = yield* listRemoteNames(cwd).pipe(Effect.catch(() => Effect.succeed([]))); + const parsedRemoteRef = parseRemoteRefWithRemoteNames(refName, remoteNames); + if (parsedRemoteRef) { + const isRemoteBranch = yield* remoteBranchExists( + cwd, + parsedRemoteRef.remoteName, + parsedRemoteRef.branchName, + ); + if (isRemoteBranch) { + return `refs/remotes/${parsedRemoteRef.remoteName}/${parsedRemoteRef.branchName}`; + } + } + + return refName; + }); + const resolvePublishBranchName = Effect.fn("resolvePublishBranchName")(function* ( cwd: string, branchName: string, @@ -1876,9 +1905,10 @@ export const makeGitVcsDriverCore = Effect.fn("makeGitVcsDriverCore")(function* const sanitizedBranch = targetBranch.replace(/\//g, "-"); const repoName = path.basename(input.cwd); const worktreePath = input.path ?? path.join(worktreesDir, repoName, sanitizedBranch); + const startPoint = yield* qualifyWorktreeStartPoint(input.cwd, input.refName); const args = input.newRefName - ? ["worktree", "add", "-b", input.newRefName, worktreePath, input.refName] - : ["worktree", "add", worktreePath, input.refName]; + ? ["worktree", "add", "-b", input.newRefName, worktreePath, startPoint] + : ["worktree", "add", worktreePath, startPoint]; yield* executeGit("GitVcsDriver.createWorktree", input.cwd, args, { fallbackErrorMessage: "git worktree add failed",