Skip to content

Commit 619268b

Browse files
henrikjeclaude
andcommitted
feat(create): allow --branch without value for interactive branch picker
arb create --branch (no value) now opens an interactive branch picker and derives the workspace name from the selected branch. Uses Commander's optional value syntax so --branch alone sets true as a sentinel while --branch <name> preserves existing behavior. Guards added for non-TTY (requires explicit value) and --yes (conflicts with interactive picker). Shell completion updated for both bash and zsh. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 39a5591 commit 619268b

File tree

8 files changed

+187
-60
lines changed

8 files changed

+187
-60
lines changed
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Optional --branch value for interactive branch picker
2+
3+
Date: 2026-03-28
4+
5+
## Context
6+
7+
`arb create --branch <name>` requires an explicit branch name. Users sometimes know they want to base a workspace on an existing remote branch but don't remember the exact name. Bare `arb create` already offers an interactive branch picker, but it prompts for the workspace name first — the user wants the reverse: pick a branch, then derive the workspace name from it. The question is how to signal "I want the branch picker, but I'll choose interactively" within the existing CLI surface.
8+
9+
## Options
10+
11+
### Commander optional value — change `<branch>` to `[branch]`
12+
13+
Change the option from `-b, --branch <branch>` (required value) to `-b, --branch [branch]` (optional value). When the flag is present without a value, Commander sets the option to `true` instead of a string. This sentinel triggers the interactive branch picker flow.
14+
15+
- **Pros:** Natural syntax (`arb create --branch`), no new flags, reuses the existing `-b` short form, all existing `--branch <value>` behavior is unchanged.
16+
- **Cons:** `arb create --branch repo-a` parses `repo-a` as the branch value (not a positional repo). However, this is already the current behavior with required value — no regression. No existing option in the codebase uses optional value syntax, making this the first instance.
17+
18+
### Separate boolean flag (`--pick-branch`)
19+
20+
Add a new flag that triggers the branch picker. Keep `--branch <branch>` as a required-value option.
21+
22+
- **Pros:** No parsing ambiguity at all.
23+
- **Cons:** Adds a new flag for a concept already expressed by `--branch`. Requires short flag allocation or goes long-only. Two flags for the same concept feels redundant and violates the GUIDELINES.md preference for minimal flag proliferation.
24+
25+
## Decision
26+
27+
Use Commander optional value (`[branch]`).
28+
29+
## Reasoning
30+
31+
The syntax matches the user's mental model: "I want a branch, I just don't know which one yet." It reuses the existing flag without proliferation and fits Commander v14's explicit support for optional option arguments. The only parsing edge case (non-flag tokens after `--branch` being consumed as the value) already exists in the current required-value form, so there is no regression. Users wanting bare `--branch` with positional repos write `arb create myws repo-a --branch` (flag at end) or use `--all-repos`.
32+
33+
## Consequences
34+
35+
`--branch` now has three states: absent (`undefined`), bare flag (`true`), or string value. All code that reads `options.branch` as a string must use `typeof options.branch === "string"` instead of truthiness checks. Non-interactive mode (piped, CI) and `--yes` both reject bare `--branch` with clear error messages. This is the first optional-value option in the codebase — if the pattern proves clean, it could be reused elsewhere (e.g. `--base` could theoretically do the same for base branch selection).

docs/daily-use.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ arb create dark-mode --branch "feat/dark-mode" --base develop --all-repos
2323
- `arb create` (no args) runs a guided flow (name, repos, branch).
2424
- `arb create <name>` prompts for repos only and uses `<name>` as the branch by default.
2525
- `arb create --branch <branch>` derives the workspace name from the branch tail (text after the last `/`).
26+
- `arb create --branch` (no value) opens an interactive branch picker and derives the workspace name from the selected branch.
2627

2728
If you've configured default repos with `arb repo default`, they are pre-selected in the interactive picker and used as the fallback when no repos are specified in non-interactive mode. See [Managing workspaces - Default repos](workspaces.md#default-repos) for details.
2829

docs/workspaces.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@ Created workspace collab-work (2 repos) on branch feat/payments
9595

9696
When run as bare `arb create` (no args or flags), arb fetches the selected repos and presents a branch selector that lists all remote branches across the selected repos. This makes it easy to discover and check out existing branches without having to remember exact names. The selector labels the default suggestion as "(new branch)" or "(existing branch)" and offers an "Enter a different name..." option for custom input.
9797

98+
You can also use `arb create --branch` (without a value) to get the same interactive branch picker while deriving the workspace name from the selected branch — useful when you know you want an existing branch but don't remember the exact name. Combine with a workspace name (`arb create myws --branch`) to use the picker without automatic name derivation.
99+
98100
This is useful when you want to resume work on an existing feature, collaborate on a branch someone else started, or set up a local workspace after switching machines. The per-repo output tells you exactly what happened — whether each branch was created fresh, checked out from a remote, or attached from a local copy.
99101

100102
## Attach and detach repos

shell/arb.bash

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ __arb_complete_create() {
258258
return
259259
fi
260260
local prev="${COMP_WORDS[COMP_CWORD-1]}"
261-
if [[ "$prev" == "-b" || "$prev" == "--branch" || "$prev" == "--base" ]]; then
261+
if [[ "$prev" == "--base" ]]; then
262262
return # branch name, no completion
263263
fi
264264
# Complete repo names

shell/arb.zsh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,7 @@ _arb() {
295295
;;
296296
create)
297297
_arguments \
298-
'(-b --branch)'{-b,--branch}'[Branch name]:branch:' \
298+
'(-b --branch)'{-b,--branch}'[Branch name (omit value for interactive picker)]::branch:' \
299299
'--base[Base branch to branch from]:branch:' \
300300
'(-a --all-repos)'{-a,--all-repos}'[Include all repos in this root]' \
301301
'(-y --yes)'{-y,--yes}'[Skip interactive prompts and use configured defaults]' \

src/commands/create.test.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,16 @@ describe("create helpers", () => {
3737
).toBe(false);
3838
});
3939

40+
test("returns false when --branch is used without value (boolean true)", () => {
41+
expect(
42+
shouldShowBranchPasteHint(
43+
"claude/improve-arb-create-ux-Ipru1",
44+
true,
45+
"Invalid workspace name 'x': must not contain '/'",
46+
),
47+
).toBe(false);
48+
});
49+
4050
test("returns false for non-slash workspace validation errors", () => {
4151
expect(
4252
shouldShowBranchPasteHint("bad name", undefined, "Invalid workspace name 'x': must not contain whitespace"),

0 commit comments

Comments
 (0)