From f3231a4258a07bd4bba3004d61cf34311b478327 Mon Sep 17 00:00:00 2001 From: Amrit Subramanian Date: Fri, 24 Oct 2025 19:02:46 -0400 Subject: [PATCH] Add branch name validation for worktree creation Prevents creation of worktrees with branch names that already exist. Shows real-time validation with red error text when a duplicate branch name is entered. Validates against both local and remote branches. Co-Authored-By: Claude --- index.html | 3 ++- renderer.ts | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/index.html b/index.html index 8a23804..719345a 100644 --- a/index.html +++ b/index.html @@ -86,7 +86,8 @@
- Custom branch name for worktree (will also be used as session name) + + Custom branch name for worktree (will also be used as session name)
diff --git a/renderer.ts b/renderer.ts index 8f14100..950bf5f 100644 --- a/renderer.ts +++ b/renderer.ts @@ -221,6 +221,7 @@ async function loadAndPopulateBranches( selectedBranch?: string ): Promise { const branches = await ipcRenderer.invoke("get-branches", directory); + existingBranches = branches; parentBranchSelect.innerHTML = ""; if (branches.length === 0) { @@ -758,6 +759,13 @@ ipcRenderer.on("session-created", (_event, sessionId: string, persistedSession: if (setupCommandsTextarea) { setupCommandsTextarea.value = ""; } + + // Reset validation state + const branchNameError = document.getElementById("branch-name-error"); + const branchNameHelp = document.getElementById("branch-name-help"); + branchNameError?.classList.add("hidden"); + branchNameHelp?.classList.remove("hidden"); + existingBranches = []; }); // Handle session reopened @@ -808,8 +816,44 @@ const localDescription = document.getElementById("local-description"); const browseDirBtn = document.getElementById("browse-dir"); const cancelBtn = document.getElementById("cancel-session"); const createBtn = document.getElementById("create-session") as HTMLButtonElement; +const branchNameInput = document.getElementById("branch-name") as HTMLInputElement; +const branchNameError = document.getElementById("branch-name-error"); +const branchNameHelp = document.getElementById("branch-name-help"); let selectedDirectory = ""; +let existingBranches: string[] = []; + +// Validate branch name +function validateBranchName(): boolean { + const branchName = branchNameInput?.value.trim(); + + if (!branchName) { + // Empty branch name is allowed (it's optional) + branchNameError?.classList.add("hidden"); + branchNameHelp?.classList.remove("hidden"); + return true; + } + + // Check if branch already exists + const branchExists = existingBranches.some(branch => + branch === branchName || branch === `origin/${branchName}` + ); + + if (branchExists) { + branchNameError?.classList.remove("hidden"); + branchNameHelp?.classList.add("hidden"); + return false; + } else { + branchNameError?.classList.add("hidden"); + branchNameHelp?.classList.remove("hidden"); + return true; + } +} + +// Add input event listener for branch name validation +branchNameInput?.addEventListener("input", () => { + validateBranchName(); +}); // Toggle skip permissions checkbox visibility based on coding agent codingAgentSelect?.addEventListener("change", () => { @@ -914,6 +958,10 @@ cancelBtn?.addEventListener("click", () => { projectDirInput.value = ""; selectedDirectory = ""; parentBranchSelect.innerHTML = ''; + branchNameInput.value = ""; + branchNameError?.classList.add("hidden"); + branchNameHelp?.classList.remove("hidden"); + existingBranches = []; }); // Create session button @@ -931,6 +979,12 @@ createBtn?.addEventListener("click", () => { return; } + // Validate branch name doesn't already exist for worktree sessions + if (sessionType === SessionType.WORKTREE && !validateBranchName()) { + alert("Cannot create worktree: branch already exists"); + return; + } + const setupCommandsTextarea = document.getElementById("setup-commands") as HTMLTextAreaElement; const setupCommandsText = setupCommandsTextarea?.value.trim(); const setupCommands = setupCommandsText