Feat/custom worktree branch name - #6428
Conversation
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
| // A custom name skips the server's LLM branch naming: | ||
| // only temporary-pattern branches get renamed. | ||
| branch: | ||
| customWorktreeBranchName ?? buildTemporaryWorktreeBranchName(randomHex), |
There was a problem hiding this comment.
🟠 High components/ChatView.tsx:5248
customWorktreeBranchName can pass Git-invalid names such as feature.lock or foo.lock/bar to prepareWorktree.branch, so the conflict check passes and the first send fails during worktree creation. Validate the final branch name against Git's full ref-format rules, including slash-separated components ending in .lock, before dispatching it.
Also found in 1 other location(s)
packages/shared/src/git.ts:133
normalizeWorktreeBranchNamecan return names Git rejects because it never removes or rejects a slash-separated component ending in.lock(for example,feature.lockorteam.lock/topic). Git's ref-format rules explicitly forbid such components. The conflict query will not flag a nonexistent invalid ref, so send proceeds with this custom name and worktree/branch creation fails instead of creating the new thread.
🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/web/src/components/ChatView.tsx around line 5248:
`customWorktreeBranchName` can pass Git-invalid names such as `feature.lock` or `foo.lock/bar` to `prepareWorktree.branch`, so the conflict check passes and the first send fails during worktree creation. Validate the final branch name against Git's full ref-format rules, including slash-separated components ending in `.lock`, before dispatching it.
Also found in 1 other location(s):
- packages/shared/src/git.ts:133 -- `normalizeWorktreeBranchName` can return names Git rejects because it never removes or rejects a slash-separated component ending in `.lock` (for example, `feature.lock` or `team.lock/topic`). Git's ref-format rules explicitly forbid such components. The conflict query will not flag a nonexistent invalid ref, so send proceeds with this custom name and worktree/branch creation fails instead of creating the new thread.
ApprovabilityVerdict: Needs human review 3 blocking correctness issues found. This PR introduces a new user-facing feature for custom worktree branch naming with new UI components, state management, and send-flow integration. New features with this scope warrant human review. Additionally, there are High-severity findings about edge cases in branch conflict detection. You can customize Macroscope's approvability policy. Learn more. |
85e8859 to
efd6128
Compare
There was a problem hiding this comment.
Three consistency issues in the new BranchToolbarWorktreeNameInput control, all within the composer context strip it joins.
Posted via Macroscope — UI Consistency
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Want fixes drafted automatically? Bugbot Autofix can create code changes for findings. A team admin can enable Autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit efd6128. Configure here.
listRefs matches the query as a substring and pages the result, so an exact branch could fall off a 20-ref page and the gate would report the name as available. Ask for local refs only at the schema's max page size, and export that ceiling so the two stay in step.
| // result, so an exact match can fall off a short page. Locals | ||
| // only (remotes can't collide) at the max page size. | ||
| refKind: "local", | ||
| limit: GIT_LIST_BRANCHES_MAX_LIMIT, |
There was a problem hiding this comment.
🟠 High components/BranchToolbarWorktreeNameInput.tsx:55
When more than 200 local refs contain the typed text, an exact duplicate after the first page is omitted and the input is marked available; sending then fails when Git rejects creation of the existing branch. listRefs paginates the substring-filtered results, so use nextCursor to inspect all pages or perform a server-side exact-match check.
🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/web/src/components/BranchToolbarWorktreeNameInput.tsx around line 55:
When more than 200 local refs contain the typed text, an exact duplicate after the first page is omitted and the input is marked `available`; sending then fails when Git rejects creation of the existing branch. `listRefs` paginates the substring-filtered results, so use `nextCursor` to inspect all pages or perform a server-side exact-match check.
| const conflict = | ||
| checked && | ||
| (conflictRefsQuery.data?.refs.some( | ||
| (refName) => !refName.isRemote && refName.name === normalizedValue, |
There was a problem hiding this comment.
🟠 High components/BranchToolbarWorktreeNameInput.tsx:69
Conflict detection marks names as available when they have a /-boundary prefix relationship with an existing local branch, but Git rejects both feature vs feature/foo combinations. Worktree creation therefore fails on send; treat either name being the other name plus / as a conflict.
| (refName) => !refName.isRemote && refName.name === normalizedValue, | |
| (refName) => | |
| !refName.isRemote && | |
| (refName.name === normalizedValue || | |
| refName.name.startsWith(`${normalizedValue}/`) || | |
| normalizedValue.startsWith(`${refName.name}/`)), |
🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/web/src/components/BranchToolbarWorktreeNameInput.tsx around line 69:
Conflict detection marks names as `available` when they have a `/`-boundary prefix relationship with an existing local branch, but Git rejects both `feature` vs `feature/foo` combinations. Worktree creation therefore fails on send; treat either name being the other name plus `/` as a conflict.

What Changed
Allows the setting of a custom branch name when creating a new worktree from a new thread
Why
Fixes #6421, also adds a workflow / fixes a potential bug for #3044, #5359 #5734 and #967
Was initially developed on top of #6427 to round out some worktree features I found missing when comparing to other apps like VS Code, but its a pretty good stand alone feature addition so this gets its own PR
UI Changes
Before:

After:


Happy to make changes to the UI if the idea seems sound :D
Checklist
Note
Medium Risk
Touches first-message worktree creation and send gating; mistakes could block sends or create branches with wrong names, but scope is limited to draft worktree flows with explicit validation.
Overview
Adds an optional custom branch name when starting a new worktree from a draft (before the first send), instead of always using a temporary generated name.
The branch toolbar shows
BranchToolbarWorktreeNameInputonly for draft + worktree mode with no existing worktree path. Names are sanitized/normalized via new shared helpers (sanitizeWorktreeBranchNameInput,normalizeWorktreeBranchName), persisted on the draft asworktreeBranchName, and checked against local refs throughlistRefs(withGIT_LIST_BRANCHES_MAX_LIMITexported for a full local page). Send is blocked while validation is in flight or on conflict; a validated custom name is passed inprepareWorktree.branchand skips server LLM rename behavior for temporary branches.Minor toolbar layout tweaks (
shrink/flex-auto) accommodate the new control on mobile and desktop.Reviewed by Cursor Bugbot for commit 0eadfa0. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Add custom branch name input for new worktree creation in chat
BranchToolbarWorktreeNameInputcomponent that lets users type a custom branch name before sending the first message in new-worktree mode; input is sanitized per-keystroke viasanitizeWorktreeBranchNameInputand normalized vianormalizeWorktreeBranchName.vcsEnvironment.listRefs; conflicts are shown inline and block sending.worktreeBranchNamefield) so it survives navigation; on send, uses the validated name instead of a random hex fallback.sanitizeWorktreeBranchNameInputandnormalizeWorktreeBranchNamehelpers inpackages/shared/src/git.ts, with full test coverage.GIT_LIST_BRANCHES_MAX_LIMITfrompackages/contracts/src/git.tsfor use in the new component.Macroscope summarized 0eadfa0.