From 04ac6eeadd2e5ea2df193fae72acbd8483cd0011 Mon Sep 17 00:00:00 2001 From: Kiet Ho Date: Fri, 30 Jan 2026 16:59:03 -0800 Subject: [PATCH 1/4] Clean up branch name logic --- .../routers/workspaces/procedures/create.ts | 61 +++++++++++-------- .../NewWorkspaceModal/NewWorkspaceModal.tsx | 37 ++++++----- 2 files changed, 54 insertions(+), 44 deletions(-) diff --git a/apps/desktop/src/lib/trpc/routers/workspaces/procedures/create.ts b/apps/desktop/src/lib/trpc/routers/workspaces/procedures/create.ts index a050b25fc87..20c3f1b8e97 100644 --- a/apps/desktop/src/lib/trpc/routers/workspaces/procedures/create.ts +++ b/apps/desktop/src/lib/trpc/routers/workspaces/procedures/create.ts @@ -267,6 +267,7 @@ export const createCreateProcedures = () => { branchName: z.string().optional(), baseBranch: z.string().optional(), useExistingBranch: z.boolean().optional(), + applyPrefix: z.boolean().optional().default(true), }), ) .mutation(async ({ input }) => { @@ -302,30 +303,42 @@ export const createCreateProcedures = () => { const { local, remote } = await listBranches(project.mainRepoPath); const existingBranches = [...local, ...remote]; - const globalSettings = localDb.select().from(settings).get(); - const projectOverrides = project.branchPrefixMode != null; - const prefixMode = projectOverrides - ? project.branchPrefixMode - : (globalSettings?.branchPrefixMode ?? "none"); - const customPrefix = projectOverrides - ? project.branchPrefixCustom - : globalSettings?.branchPrefixCustom; - - const rawPrefix = await getBranchPrefix({ - repoPath: project.mainRepoPath, - mode: prefixMode, - customPrefix, - }); - const rawAuthorPrefix = rawPrefix - ? sanitizeAuthorPrefix(rawPrefix) - : undefined; + // Compute prefix only if applyPrefix is true + let authorPrefix: string | undefined; + if (input.applyPrefix) { + const globalSettings = localDb.select().from(settings).get(); + const projectOverrides = project.branchPrefixMode != null; + const prefixMode = projectOverrides + ? project.branchPrefixMode + : (globalSettings?.branchPrefixMode ?? "none"); + const customPrefix = projectOverrides + ? project.branchPrefixCustom + : globalSettings?.branchPrefixCustom; + + const rawPrefix = await getBranchPrefix({ + repoPath: project.mainRepoPath, + mode: prefixMode, + customPrefix, + }); + const rawAuthorPrefix = rawPrefix + ? sanitizeAuthorPrefix(rawPrefix) + : undefined; - const existingSet = new Set( - existingBranches.map((b) => b.toLowerCase()), - ); - const prefixWouldCollide = - rawAuthorPrefix && existingSet.has(rawAuthorPrefix.toLowerCase()); - const authorPrefix = prefixWouldCollide ? undefined : rawAuthorPrefix; + const existingSet = new Set( + existingBranches.map((b) => b.toLowerCase()), + ); + const prefixWouldCollide = + rawAuthorPrefix && existingSet.has(rawAuthorPrefix.toLowerCase()); + authorPrefix = prefixWouldCollide ? undefined : rawAuthorPrefix; + } + + // Helper to apply prefix to a branch name + const applyPrefixToBranch = (name: string): string => { + if (authorPrefix) { + return `${authorPrefix}/${name}`; + } + return name; + }; let branch: string; if (existingBranchName) { @@ -337,7 +350,7 @@ export const createCreateProcedures = () => { branch = existingBranchName; } else if (input.branchName?.trim()) { const sanitized = sanitizeBranchName(input.branchName); - branch = authorPrefix ? `${authorPrefix}/${sanitized}` : sanitized; + branch = applyPrefixToBranch(sanitized); } else { branch = generateBranchName({ existingBranches, authorPrefix }); } diff --git a/apps/desktop/src/renderer/components/NewWorkspaceModal/NewWorkspaceModal.tsx b/apps/desktop/src/renderer/components/NewWorkspaceModal/NewWorkspaceModal.tsx index 3c62c54a302..00e3e3e42b4 100644 --- a/apps/desktop/src/renderer/components/NewWorkspaceModal/NewWorkspaceModal.tsx +++ b/apps/desktop/src/renderer/components/NewWorkspaceModal/NewWorkspaceModal.tsx @@ -47,17 +47,8 @@ import { } from "shared/utils/branch"; import { ExistingWorktreesList } from "./components/ExistingWorktreesList"; -function generateBranchFromTitle({ - title, - prefix, -}: { - title: string; - prefix: string | null; -}): string { - const slug = sanitizeSegment(title); - if (!slug) return ""; - - return prefix ? `${prefix}/${slug}` : slug; +function generateSlugFromTitle(title: string): string { + return sanitizeSegment(title); } type Mode = "existing" | "new" | "cloud"; @@ -139,13 +130,18 @@ export function NewWorkspaceModal() { setBaseBranch(null); }, [selectedProjectId]); - const generatedBranchName = generateBranchFromTitle({ - title, - prefix: resolvedPrefix, - }); - const branchNameToCreate = branchNameEdited + // Branch slug without prefix - sent to backend which applies prefix + const branchSlug = branchNameEdited ? sanitizeBranchName(branchName) - : generatedBranchName; + : generateSlugFromTitle(title); + + // Only apply prefix for auto-generated names, not custom + const applyPrefix = !branchNameEdited; + + const branchPreview = + branchSlug && applyPrefix && resolvedPrefix + ? `${resolvedPrefix}/${branchSlug}` + : branchSlug; const resetForm = () => { setSelectedProjectId(null); @@ -229,8 +225,9 @@ export function NewWorkspaceModal() { const result = await createWorkspace.mutateAsync({ projectId: selectedProjectId, name: workspaceName, - branchName: branchNameToCreate || undefined, + branchName: branchSlug || undefined, baseBranch: effectiveBaseBranch || undefined, + applyPrefix, }); handleClose(); @@ -356,7 +353,7 @@ export function NewWorkspaceModal() {

- {branchNameToCreate || "branch-name"} + {branchPreview || "branch-name"} from {effectiveBaseBranch} @@ -387,7 +384,7 @@ export function NewWorkspaceModal() { className="h-8 text-sm font-mono" placeholder="auto-generated" value={ - branchNameEdited ? branchName : generatedBranchName + branchNameEdited ? branchName : generateSlugFromTitle(title) } onChange={(e) => handleBranchNameChange(e.target.value) From 005f9dc4e6c0fc8d1a403aab484f1e0bc2830550 Mon Sep 17 00:00:00 2001 From: Kiet Ho Date: Fri, 30 Jan 2026 17:00:58 -0800 Subject: [PATCH 2/4] Clean up --- .../routers/workspaces/procedures/create.ts | 26 ++++++++----------- .../NewWorkspaceModal/NewWorkspaceModal.tsx | 2 -- 2 files changed, 11 insertions(+), 17 deletions(-) diff --git a/apps/desktop/src/lib/trpc/routers/workspaces/procedures/create.ts b/apps/desktop/src/lib/trpc/routers/workspaces/procedures/create.ts index 20c3f1b8e97..72154634f12 100644 --- a/apps/desktop/src/lib/trpc/routers/workspaces/procedures/create.ts +++ b/apps/desktop/src/lib/trpc/routers/workspaces/procedures/create.ts @@ -303,8 +303,7 @@ export const createCreateProcedures = () => { const { local, remote } = await listBranches(project.mainRepoPath); const existingBranches = [...local, ...remote]; - // Compute prefix only if applyPrefix is true - let authorPrefix: string | undefined; + let branchPrefix: string | undefined; if (input.applyPrefix) { const globalSettings = localDb.select().from(settings).get(); const projectOverrides = project.branchPrefixMode != null; @@ -320,7 +319,7 @@ export const createCreateProcedures = () => { mode: prefixMode, customPrefix, }); - const rawAuthorPrefix = rawPrefix + const sanitizedPrefix = rawPrefix ? sanitizeAuthorPrefix(rawPrefix) : undefined; @@ -328,17 +327,12 @@ export const createCreateProcedures = () => { existingBranches.map((b) => b.toLowerCase()), ); const prefixWouldCollide = - rawAuthorPrefix && existingSet.has(rawAuthorPrefix.toLowerCase()); - authorPrefix = prefixWouldCollide ? undefined : rawAuthorPrefix; + sanitizedPrefix && existingSet.has(sanitizedPrefix.toLowerCase()); + branchPrefix = prefixWouldCollide ? undefined : sanitizedPrefix; } - // Helper to apply prefix to a branch name - const applyPrefixToBranch = (name: string): string => { - if (authorPrefix) { - return `${authorPrefix}/${name}`; - } - return name; - }; + const withPrefix = (name: string): string => + branchPrefix ? `${branchPrefix}/${name}` : name; let branch: string; if (existingBranchName) { @@ -349,10 +343,12 @@ export const createCreateProcedures = () => { } branch = existingBranchName; } else if (input.branchName?.trim()) { - const sanitized = sanitizeBranchName(input.branchName); - branch = applyPrefixToBranch(sanitized); + branch = withPrefix(sanitizeBranchName(input.branchName)); } else { - branch = generateBranchName({ existingBranches, authorPrefix }); + branch = generateBranchName({ + existingBranches, + authorPrefix: branchPrefix, + }); } const worktreePath = join( diff --git a/apps/desktop/src/renderer/components/NewWorkspaceModal/NewWorkspaceModal.tsx b/apps/desktop/src/renderer/components/NewWorkspaceModal/NewWorkspaceModal.tsx index 00e3e3e42b4..077df586a39 100644 --- a/apps/desktop/src/renderer/components/NewWorkspaceModal/NewWorkspaceModal.tsx +++ b/apps/desktop/src/renderer/components/NewWorkspaceModal/NewWorkspaceModal.tsx @@ -130,12 +130,10 @@ export function NewWorkspaceModal() { setBaseBranch(null); }, [selectedProjectId]); - // Branch slug without prefix - sent to backend which applies prefix const branchSlug = branchNameEdited ? sanitizeBranchName(branchName) : generateSlugFromTitle(title); - // Only apply prefix for auto-generated names, not custom const applyPrefix = !branchNameEdited; const branchPreview = From afa421e7da9d34fb7271206b06158474c8f7e800 Mon Sep 17 00:00:00 2001 From: Kiet Ho Date: Fri, 30 Jan 2026 17:06:14 -0800 Subject: [PATCH 3/4] Use preview --- .../renderer/components/NewWorkspaceModal/NewWorkspaceModal.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/desktop/src/renderer/components/NewWorkspaceModal/NewWorkspaceModal.tsx b/apps/desktop/src/renderer/components/NewWorkspaceModal/NewWorkspaceModal.tsx index 077df586a39..e2eaa3ce0f4 100644 --- a/apps/desktop/src/renderer/components/NewWorkspaceModal/NewWorkspaceModal.tsx +++ b/apps/desktop/src/renderer/components/NewWorkspaceModal/NewWorkspaceModal.tsx @@ -382,7 +382,7 @@ export function NewWorkspaceModal() { className="h-8 text-sm font-mono" placeholder="auto-generated" value={ - branchNameEdited ? branchName : generateSlugFromTitle(title) + branchNameEdited ? branchName : branchPreview } onChange={(e) => handleBranchNameChange(e.target.value) From e0b469a2debe97bb97688c6e62266a40c2d3cd44 Mon Sep 17 00:00:00 2001 From: Kiet Ho Date: Fri, 30 Jan 2026 17:07:53 -0800 Subject: [PATCH 4/4] Lint --- .../components/NewWorkspaceModal/NewWorkspaceModal.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/desktop/src/renderer/components/NewWorkspaceModal/NewWorkspaceModal.tsx b/apps/desktop/src/renderer/components/NewWorkspaceModal/NewWorkspaceModal.tsx index e2eaa3ce0f4..ce724970e92 100644 --- a/apps/desktop/src/renderer/components/NewWorkspaceModal/NewWorkspaceModal.tsx +++ b/apps/desktop/src/renderer/components/NewWorkspaceModal/NewWorkspaceModal.tsx @@ -381,9 +381,7 @@ export function NewWorkspaceModal() { id="branch" className="h-8 text-sm font-mono" placeholder="auto-generated" - value={ - branchNameEdited ? branchName : branchPreview - } + value={branchNameEdited ? branchName : branchPreview} onChange={(e) => handleBranchNameChange(e.target.value) }