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;