From 0898578c11ce1d37b51fd4cc4dd5373e269410ad Mon Sep 17 00:00:00 2001 From: Shirone Date: Wed, 14 Jan 2026 18:36:14 +0100 Subject: [PATCH] fix: Include remote branches in PR base selection even when local branch exists The branch listing logic now correctly shows remote branches (e.g., "origin/main") even if a local branch with the same base name exists, since users need remote branches as PR base targets. Also extracted duplicate state reset logic in create-pr-dialog into a reusable function. --- .../routes/worktree/routes/list-branches.ts | 12 ++--- .../board-view/dialogs/create-pr-dialog.tsx | 49 +++++++------------ 2 files changed, 25 insertions(+), 36 deletions(-) diff --git a/apps/server/src/routes/worktree/routes/list-branches.ts b/apps/server/src/routes/worktree/routes/list-branches.ts index 84beee40..c6db10fc 100644 --- a/apps/server/src/routes/worktree/routes/list-branches.ts +++ b/apps/server/src/routes/worktree/routes/list-branches.ts @@ -92,12 +92,12 @@ export function createListBranchesHandler() { // Skip HEAD pointers like "origin/HEAD" if (cleanName.includes('/HEAD')) return; - // Extract the branch name without the remote prefix for deduplication - // e.g., "origin/main" -> "main" - const branchNameWithoutRemote = cleanName.replace(/^[^/]+\//, ''); - - // Only add remote branches that don't exist locally (to avoid duplicates) - if (!localBranchNames.has(branchNameWithoutRemote)) { + // Only add remote branches if a branch with the exact same name isn't already + // in the list. This avoids duplicates if a local branch is named like a remote one. + // Note: We intentionally include remote branches even when a local branch with the + // same base name exists (e.g., show "origin/main" even if local "main" exists), + // since users need to select remote branches as PR base targets. + if (!localBranchNames.has(cleanName)) { branches.push({ name: cleanName, // Keep full name like "origin/main" isCurrent: false, diff --git a/apps/ui/src/components/views/board-view/dialogs/create-pr-dialog.tsx b/apps/ui/src/components/views/board-view/dialogs/create-pr-dialog.tsx index 59906dee..125e8416 100644 --- a/apps/ui/src/components/views/board-view/dialogs/create-pr-dialog.tsx +++ b/apps/ui/src/components/views/board-view/dialogs/create-pr-dialog.tsx @@ -59,6 +59,21 @@ export function CreatePRDialog({ // Track whether an operation completed that warrants a refresh const operationCompletedRef = useRef(false); + // Common state reset function to avoid duplication + const resetState = useCallback(() => { + setTitle(''); + setBody(''); + setCommitMessage(''); + setBaseBranch(defaultBaseBranch); + setIsDraft(false); + setError(null); + setPrUrl(null); + setBrowserUrl(null); + setShowBrowserFallback(false); + operationCompletedRef.current = false; + setBranches([]); + }, [defaultBaseBranch]); + // Fetch branches for autocomplete const fetchBranches = useCallback(async () => { if (!worktree?.path) return; @@ -87,39 +102,13 @@ export function CreatePRDialog({ // Reset state when dialog opens or worktree changes useEffect(() => { + // Reset all state on both open and close + resetState(); if (open) { - // Reset form fields - setTitle(''); - setBody(''); - setCommitMessage(''); - setBaseBranch(defaultBaseBranch); - setIsDraft(false); - setError(null); - // Also reset result states when opening for a new worktree - // This prevents showing stale PR URLs from previous worktrees - setPrUrl(null); - setBrowserUrl(null); - setShowBrowserFallback(false); - // Reset operation tracking - operationCompletedRef.current = false; - // Reset branches and fetch fresh ones - setBranches([]); + // Fetch fresh branches when dialog opens fetchBranches(); - } else { - // Reset everything when dialog closes - setTitle(''); - setBody(''); - setCommitMessage(''); - setBaseBranch(defaultBaseBranch); - setIsDraft(false); - setError(null); - setPrUrl(null); - setBrowserUrl(null); - setShowBrowserFallback(false); - operationCompletedRef.current = false; - setBranches([]); } - }, [open, worktree?.path, defaultBaseBranch, fetchBranches]); + }, [open, worktree?.path, resetState, fetchBranches]); const handleCreate = async () => { if (!worktree) return;