From 351e8c0e5afdf6a5e45f9324b66f3d9ec363e913 Mon Sep 17 00:00:00 2001 From: Alejandro Tamayo Date: Fri, 24 Apr 2026 16:02:40 +0200 Subject: [PATCH] fix(worktree): base new worktrees on origin/ by default MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Follow-up to #35. The pre-create fetch was gated on `branchType !== "local"`, but the new-chat UI auto-selected the local variant of the default branch whenever both local and remote existed — so in the common case (local `main` tracking `origin/main`) the fetch never ran and worktrees inherited whatever stale state the user had locally. - Auto-select prefers the remote variant of the default branch, so the worktree starts from a fresh `origin/`. - `git fetch origin ` now runs whenever origin exists, regardless of branch type. Failures remain best-effort. User's local branch is left untouched. Explicit local branch selection is still honored. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/main/lib/git/worktree.ts | 7 ++++--- src/renderer/features/agents/main/new-chat-form.tsx | 10 ++++++---- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/main/lib/git/worktree.ts b/src/main/lib/git/worktree.ts index 463c02f57..d74d8de2f 100644 --- a/src/main/lib/git/worktree.ts +++ b/src/main/lib/git/worktree.ts @@ -971,9 +971,10 @@ export async function createWorktreeForChat( const baseBranch = selectedBaseBranch || await getDefaultBranch(projectPath); // Best-effort: refresh origin/ so the worktree is based on the - // latest remote state. Skipped for local-type branches (user opted into a - // local ref) and when no origin remote exists. Never blocks creation. - if (branchType !== "local" && (await hasOriginRemote(projectPath))) { + // latest remote state. Skipped only when there is no origin remote. Never + // blocks creation — failures (including local-only branches with no matching + // remote ref) are logged and swallowed. + if (await hasOriginRemote(projectPath)) { try { await withGitLock(projectPath, async () => { const netGit = createGitForNetwork(projectPath); diff --git a/src/renderer/features/agents/main/new-chat-form.tsx b/src/renderer/features/agents/main/new-chat-form.tsx index baa598342..c904d75fa 100644 --- a/src/renderer/features/agents/main/new-chat-form.tsx +++ b/src/renderer/features/agents/main/new-chat-form.tsx @@ -985,12 +985,14 @@ export function NewChatForm({ validatedProject?.id && !selectedBranch ) { - // Find the default branch in the branches list to get its type - // Prefer local over remote if both exist + // Find the default branch in the branches list to get its type. + // Prefer remote over local so new worktrees are based on the freshest + // origin state. Only fall back to local if the default branch has no + // remote counterpart. const defaultBranchObj = branches.find( - (b) => b.name === branchesQuery.data.defaultBranch && b.isDefault && b.type === "local", - ) || branches.find( (b) => b.name === branchesQuery.data.defaultBranch && b.isDefault && b.type === "remote", + ) || branches.find( + (b) => b.name === branchesQuery.data.defaultBranch && b.isDefault && b.type === "local", ) // Fallback to "local" if branch not found in list (shouldn't happen but prevents empty selector) const branchType = defaultBranchObj?.type || "local"