From 830d4e9a554d909ba1c1f20b2cdf8cebba1b2046 Mon Sep 17 00:00:00 2001 From: Ruan Gustavo Araujo da Silveira Date: Tue, 7 Apr 2026 10:35:56 -0300 Subject: [PATCH 1/3] fix: fall back to FETCH_HEAD checkout when gh pr checkout fails for branch names with / MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #3231 gh pr checkout internally runs `git checkout -b --track origin/`. When the branch name contains `/`, git cannot resolve the tracking ref inside a freshly created detached worktree, producing "starting point is not a branch". The fetch succeeds — only the tracking setup fails. Catch that specific error and fall back to `git checkout -b --no-track FETCH_HEAD`. push.autoSetupRemote=true (already set after worktree creation) handles push tracking without needing --track. --- .../lib/trpc/routers/workspaces/utils/git.ts | 48 ++++++++++++++----- 1 file changed, 36 insertions(+), 12 deletions(-) diff --git a/apps/desktop/src/lib/trpc/routers/workspaces/utils/git.ts b/apps/desktop/src/lib/trpc/routers/workspaces/utils/git.ts index 84033314620..5b5a7d11d49 100644 --- a/apps/desktop/src/lib/trpc/routers/workspaces/utils/git.ts +++ b/apps/desktop/src/lib/trpc/routers/workspaces/utils/git.ts @@ -1777,18 +1777,42 @@ export async function createWorktreeFromPr({ }); } - await execWithShellEnv( - "gh", - [ - "pr", - "checkout", - String(prInfo.number), - "--branch", - localBranchName, - "--force", - ], - { cwd: worktreePath, timeout: 120_000 }, - ); + try { + await execWithShellEnv( + "gh", + [ + "pr", + "checkout", + String(prInfo.number), + "--branch", + localBranchName, + "--force", + ], + { cwd: worktreePath, timeout: 120_000 }, + ); + } catch (ghError) { + const ghMsg = ghError instanceof Error ? ghError.message : String(ghError); + // `gh pr checkout` can fail with "is not a branch" when the branch name + // contains '/' (e.g. "user/feature-branch"). Git has trouble resolving + // "origin/user/feature-branch" as a tracking ref inside a worktree. + // gh already fetched the remote successfully, so FETCH_HEAD points to + // the right commit — fall back to creating the branch without tracking. + if (!ghMsg.includes("is not a branch")) { + throw ghError; + } + await execGitWithShellPath( + [ + "-C", + worktreePath, + "checkout", + "-b", + localBranchName, + "--no-track", + "FETCH_HEAD", + ], + { timeout: 30_000 }, + ); + } // Enable autoSetupRemote so `git push` just works without -u flag. await execGitWithShellPath( From 666e4f5d79fc9197b4a7bcded8c9aeaaefb95a77 Mon Sep 17 00:00:00 2001 From: Ruan Gustavo Araujo da Silveira Date: Tue, 7 Apr 2026 10:48:45 -0300 Subject: [PATCH 2/3] fix: use -B flag to force-replace branch in FETCH_HEAD fallback checkout --- apps/desktop/src/lib/trpc/routers/workspaces/utils/git.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/desktop/src/lib/trpc/routers/workspaces/utils/git.ts b/apps/desktop/src/lib/trpc/routers/workspaces/utils/git.ts index 5b5a7d11d49..bb56d1622b5 100644 --- a/apps/desktop/src/lib/trpc/routers/workspaces/utils/git.ts +++ b/apps/desktop/src/lib/trpc/routers/workspaces/utils/git.ts @@ -1805,7 +1805,7 @@ export async function createWorktreeFromPr({ "-C", worktreePath, "checkout", - "-b", + "-B", localBranchName, "--no-track", "FETCH_HEAD", From 919665d8907be59df741db917ef449f83e6c5cbe Mon Sep 17 00:00:00 2001 From: Ruan Gustavo Araujo da Silveira Date: Tue, 7 Apr 2026 10:49:41 -0300 Subject: [PATCH 3/3] fix: log fallback path when gh pr checkout fails with tracking error --- apps/desktop/src/lib/trpc/routers/workspaces/utils/git.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/desktop/src/lib/trpc/routers/workspaces/utils/git.ts b/apps/desktop/src/lib/trpc/routers/workspaces/utils/git.ts index bb56d1622b5..45f8bbaf76f 100644 --- a/apps/desktop/src/lib/trpc/routers/workspaces/utils/git.ts +++ b/apps/desktop/src/lib/trpc/routers/workspaces/utils/git.ts @@ -1800,6 +1800,9 @@ export async function createWorktreeFromPr({ if (!ghMsg.includes("is not a branch")) { throw ghError; } + console.log( + `[git] gh pr checkout failed with tracking error for PR #${prInfo.number}, falling back to FETCH_HEAD checkout`, + ); await execGitWithShellPath( [ "-C",