From 1f1a71c4bf96ca4619b4352b55b6495ea58d7bcd Mon Sep 17 00:00:00 2001 From: Julius Marminge Date: Mon, 27 Jul 2026 22:44:10 +0200 Subject: [PATCH 1/2] Show origin ref in branch trigger label - Add origin-aware trigger label resolution - Cover local, remote, and empty branch states --- .../components/BranchToolbar.logic.test.ts | 55 +++++++++++++++++++ .../web/src/components/BranchToolbar.logic.ts | 20 +++++++ .../BranchToolbarBranchSelector.tsx | 19 +------ 3 files changed, 78 insertions(+), 16 deletions(-) diff --git a/apps/web/src/components/BranchToolbar.logic.test.ts b/apps/web/src/components/BranchToolbar.logic.test.ts index e59ffc8f68b..a681efc6879 100644 --- a/apps/web/src/components/BranchToolbar.logic.test.ts +++ b/apps/web/src/components/BranchToolbar.logic.test.ts @@ -9,6 +9,7 @@ import { resolveDraftEnvModeAfterBranchChange, resolveEffectiveEnvMode, resolveEnvModeLabel, + resolveBranchTriggerLabel, resolveBranchToolbarPrBranch, resolveBranchToolbarValue, resolveLockedWorkspaceLabel, @@ -174,6 +175,60 @@ describe("resolveBranchToolbarValue", () => { }); }); +describe("resolveBranchTriggerLabel", () => { + it("shows the origin ref when a new worktree will start from origin", () => { + expect( + resolveBranchTriggerLabel({ + activeWorktreePath: null, + effectiveEnvMode: "worktree", + resolvedActiveBranch: "main", + startFromOrigin: true, + }), + ).toBe("From origin/main"); + }); + + it("shows the local ref when start from origin is disabled", () => { + expect( + resolveBranchTriggerLabel({ + activeWorktreePath: null, + effectiveEnvMode: "worktree", + resolvedActiveBranch: "main", + startFromOrigin: false, + }), + ).toBe("From main"); + }); + + it("does not duplicate the origin prefix for an explicit remote ref", () => { + expect( + resolveBranchTriggerLabel({ + activeWorktreePath: null, + effectiveEnvMode: "worktree", + resolvedActiveBranch: "origin/feature/demo", + startFromOrigin: true, + }), + ).toBe("From origin/feature/demo"); + }); + + it("keeps current-checkout labels and empty state unchanged", () => { + expect( + resolveBranchTriggerLabel({ + activeWorktreePath: null, + effectiveEnvMode: "local", + resolvedActiveBranch: "main", + startFromOrigin: true, + }), + ).toBe("main"); + expect( + resolveBranchTriggerLabel({ + activeWorktreePath: null, + effectiveEnvMode: "worktree", + resolvedActiveBranch: null, + startFromOrigin: true, + }), + ).toBe("Select ref"); + }); +}); + describe("resolveBranchToolbarPrBranch", () => { it("uses the explicit thread branch when it matches the displayed branch", () => { expect( diff --git a/apps/web/src/components/BranchToolbar.logic.ts b/apps/web/src/components/BranchToolbar.logic.ts index 3549eff6eea..e2b104e387a 100644 --- a/apps/web/src/components/BranchToolbar.logic.ts +++ b/apps/web/src/components/BranchToolbar.logic.ts @@ -156,6 +156,26 @@ export function resolveBranchToolbarValue(input: { return currentGitBranch ?? activeThreadBranch; } +export function resolveBranchTriggerLabel(input: { + activeWorktreePath: string | null; + effectiveEnvMode: EnvMode; + resolvedActiveBranch: string | null; + startFromOrigin: boolean; +}): string { + const { activeWorktreePath, effectiveEnvMode, resolvedActiveBranch, startFromOrigin } = input; + if (!resolvedActiveBranch) { + return "Select ref"; + } + if (effectiveEnvMode === "worktree" && !activeWorktreePath) { + const baseRef = + startFromOrigin && !resolvedActiveBranch.startsWith("origin/") + ? `origin/${resolvedActiveBranch}` + : resolvedActiveBranch; + return `From ${baseRef}`; + } + return resolvedActiveBranch; +} + export function resolveBranchToolbarPrBranch(input: { activeThreadBranch: string | null; resolvedActiveBranch: string | null; diff --git a/apps/web/src/components/BranchToolbarBranchSelector.tsx b/apps/web/src/components/BranchToolbarBranchSelector.tsx index 74138fa5293..8fa0dd9789d 100644 --- a/apps/web/src/components/BranchToolbarBranchSelector.tsx +++ b/apps/web/src/components/BranchToolbarBranchSelector.tsx @@ -35,6 +35,7 @@ import { parsePullRequestReference } from "../pullRequestReference"; import { getSourceControlPresentation } from "../sourceControlPresentation"; import { deriveLocalBranchNameFromRemoteRef, + resolveBranchTriggerLabel, resolveBranchToolbarPrBranch, resolveBranchSelectionTarget, resolveBranchToolbarValue, @@ -81,21 +82,6 @@ function toBranchActionErrorMessage(error: unknown): string { return error instanceof Error ? error.message : "An error occurred."; } -function getBranchTriggerLabel(input: { - activeWorktreePath: string | null; - effectiveEnvMode: "local" | "worktree"; - resolvedActiveBranch: string | null; -}): string { - const { activeWorktreePath, effectiveEnvMode, resolvedActiveBranch } = input; - if (!resolvedActiveBranch) { - return "Select ref"; - } - if (effectiveEnvMode === "worktree" && !activeWorktreePath) { - return `From ${resolvedActiveBranch}`; - } - return resolvedActiveBranch; -} - export function BranchToolbarBranchSelector({ className, environmentId, @@ -584,10 +570,11 @@ export function BranchToolbarBranchSelector({ maybeFetchNextBranchPage(); }, [refs.length, maybeFetchNextBranchPage]); - const triggerLabel = getBranchTriggerLabel({ + const triggerLabel = resolveBranchTriggerLabel({ activeWorktreePath, effectiveEnvMode, resolvedActiveBranch, + startFromOrigin, }); // PR pill shown next to the branch selector when the active branch has one. From d91aa21abc5cf1e7e27485e2eada50bd041f83e3 Mon Sep 17 00:00:00 2001 From: Julius Marminge Date: Mon, 27 Jul 2026 22:58:32 +0200 Subject: [PATCH 2/2] Preserve explicit remote branch labels Use ref metadata to distinguish local branches from explicit remotes when displaying the worktree base. Co-authored-by: codex --- .../components/BranchToolbar.logic.test.ts | 41 +++++++++++++++++++ .../web/src/components/BranchToolbar.logic.ts | 11 ++++- .../BranchToolbarBranchSelector.tsx | 24 +++++++++++ 3 files changed, 74 insertions(+), 2 deletions(-) diff --git a/apps/web/src/components/BranchToolbar.logic.test.ts b/apps/web/src/components/BranchToolbar.logic.test.ts index a681efc6879..76336f1ef1f 100644 --- a/apps/web/src/components/BranchToolbar.logic.test.ts +++ b/apps/web/src/components/BranchToolbar.logic.test.ts @@ -182,17 +182,31 @@ describe("resolveBranchTriggerLabel", () => { activeWorktreePath: null, effectiveEnvMode: "worktree", resolvedActiveBranch: "main", + resolvedActiveBranchIsRemote: false, startFromOrigin: true, }), ).toBe("From origin/main"); }); + it("shows the origin ref for local branch names that contain slashes", () => { + expect( + resolveBranchTriggerLabel({ + activeWorktreePath: null, + effectiveEnvMode: "worktree", + resolvedActiveBranch: "feature/demo", + resolvedActiveBranchIsRemote: false, + startFromOrigin: true, + }), + ).toBe("From origin/feature/demo"); + }); + it("shows the local ref when start from origin is disabled", () => { expect( resolveBranchTriggerLabel({ activeWorktreePath: null, effectiveEnvMode: "worktree", resolvedActiveBranch: "main", + resolvedActiveBranchIsRemote: false, startFromOrigin: false, }), ).toBe("From main"); @@ -204,17 +218,31 @@ describe("resolveBranchTriggerLabel", () => { activeWorktreePath: null, effectiveEnvMode: "worktree", resolvedActiveBranch: "origin/feature/demo", + resolvedActiveBranchIsRemote: true, startFromOrigin: true, }), ).toBe("From origin/feature/demo"); }); + it("preserves an explicit ref from a non-origin remote", () => { + expect( + resolveBranchTriggerLabel({ + activeWorktreePath: null, + effectiveEnvMode: "worktree", + resolvedActiveBranch: "upstream/feature/demo", + resolvedActiveBranchIsRemote: true, + startFromOrigin: true, + }), + ).toBe("From upstream/feature/demo"); + }); + it("keeps current-checkout labels and empty state unchanged", () => { expect( resolveBranchTriggerLabel({ activeWorktreePath: null, effectiveEnvMode: "local", resolvedActiveBranch: "main", + resolvedActiveBranchIsRemote: false, startFromOrigin: true, }), ).toBe("main"); @@ -223,10 +251,23 @@ describe("resolveBranchTriggerLabel", () => { activeWorktreePath: null, effectiveEnvMode: "worktree", resolvedActiveBranch: null, + resolvedActiveBranchIsRemote: null, startFromOrigin: true, }), ).toBe("Select ref"); }); + + it("does not fabricate an origin ref while branch metadata is loading", () => { + expect( + resolveBranchTriggerLabel({ + activeWorktreePath: null, + effectiveEnvMode: "worktree", + resolvedActiveBranch: "upstream/feature/demo", + resolvedActiveBranchIsRemote: null, + startFromOrigin: true, + }), + ).toBe("From upstream/feature/demo"); + }); }); describe("resolveBranchToolbarPrBranch", () => { diff --git a/apps/web/src/components/BranchToolbar.logic.ts b/apps/web/src/components/BranchToolbar.logic.ts index e2b104e387a..d9737f17a32 100644 --- a/apps/web/src/components/BranchToolbar.logic.ts +++ b/apps/web/src/components/BranchToolbar.logic.ts @@ -160,15 +160,22 @@ export function resolveBranchTriggerLabel(input: { activeWorktreePath: string | null; effectiveEnvMode: EnvMode; resolvedActiveBranch: string | null; + resolvedActiveBranchIsRemote: boolean | null; startFromOrigin: boolean; }): string { - const { activeWorktreePath, effectiveEnvMode, resolvedActiveBranch, startFromOrigin } = input; + const { + activeWorktreePath, + effectiveEnvMode, + resolvedActiveBranch, + resolvedActiveBranchIsRemote, + startFromOrigin, + } = input; if (!resolvedActiveBranch) { return "Select ref"; } if (effectiveEnvMode === "worktree" && !activeWorktreePath) { const baseRef = - startFromOrigin && !resolvedActiveBranch.startsWith("origin/") + startFromOrigin && resolvedActiveBranchIsRemote === false ? `origin/${resolvedActiveBranch}` : resolvedActiveBranch; return `From ${baseRef}`; diff --git a/apps/web/src/components/BranchToolbarBranchSelector.tsx b/apps/web/src/components/BranchToolbarBranchSelector.tsx index 8fa0dd9789d..c4ae50a9e98 100644 --- a/apps/web/src/components/BranchToolbarBranchSelector.tsx +++ b/apps/web/src/components/BranchToolbarBranchSelector.tsx @@ -294,6 +294,29 @@ export function BranchToolbarBranchSelector({ canonicalActiveBranch, (_currentBranch: string | null, optimisticBranch: string | null) => optimisticBranch, ); + const listedActiveBranch = + resolvedActiveBranch === null ? null : (branchByName.get(resolvedActiveBranch) ?? null); + const activeBranchRefQuery = useEnvironmentQuery( + branchCwd !== null && resolvedActiveBranch !== null + ? vcsEnvironment.listRefs({ + environmentId, + input: { + cwd: branchCwd, + query: resolvedActiveBranch, + limit: 10, + }, + }) + : null, + ); + const queriedActiveBranch = activeBranchRefQuery.data?.refs.find( + (refName) => refName.name === resolvedActiveBranch, + ); + const resolvedActiveBranchIsRemote = + listedActiveBranch !== null + ? listedActiveBranch.isRemote === true + : queriedActiveBranch + ? queriedActiveBranch.isRemote === true + : null; const [isBranchActionPending, startBranchActionTransition] = useTransition(); const totalBranchCount = branchRefState.data?.totalCount ?? 0; const branchStatusText = isInitialBranchesLoadPending @@ -574,6 +597,7 @@ export function BranchToolbarBranchSelector({ activeWorktreePath, effectiveEnvMode, resolvedActiveBranch, + resolvedActiveBranchIsRemote, startFromOrigin, });