You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Thanks for git-wt — it's become a core part of my daily multi-worktree workflow.
Summary
When creating a new worktree with git wt <new-branch> <start-point>, if <start-point> is a bare branch name that does not exist locally but exists on exactly one remote (e.g. develop right after a clone, or in gitflow repos where develop is rarely checked out locally), the underlying git worktree add -b <new-branch> <path> <start-point> triggers git's branch DWIM: the -b <new-branch> is silently ignored, and a local branch named after <start-point> (e.g. develop) is created and checked out instead.
The worktree directory is still named after <new-branch>, so the mismatch is easy to miss — you keep working and committing directly onto a branch named develop while believing you are on your feature branch.
flowchart TD
A["git wt my-feature develop<br/>(→ git worktree add -b my-feature <path> develop)"] --> B{"'develop' resolves<br/>locally?"}
B -- "yes" --> C["✅ new branch 'my-feature'<br/>at develop"]
B -- "no" --> D{"matches exactly one<br/>remote branch?"}
D -- "no" --> E["✅ error:<br/>invalid reference"]
D -- "yes" --> F["⚠️ DWIM: new_branch = 'develop'<br/>-b my-feature is silently clobbered"]
F --> G["worktree dir: …/my-feature/ (as requested)<br/>checked-out branch: develop (not requested)"]
Loading
The end state that makes this so easy to miss:
../work-wt/my-feature/ <- directory named as requested
HEAD -> refs/heads/develop <- but the branch is not ('my-feature' was never created)
Reproduction
tmp=$(mktemp -d)&&cd"$tmp"
git init --bare remote.git
git init work &&cd work
git config user.email t@t && git config user.name t
git commit --allow-empty -m init
git remote add origin ../remote.git && git push -q origin main
git checkout -qb develop && git commit --allow-empty -m dev && git push -q origin develop
git checkout -q main && git branch -qD develop # develop now exists only on the remote
git wt my-feature develop
git -C ../work-wt/my-feature branch --show-current
Actual
Preparing worktree (new branch 'develop')
branch 'develop' set up to track 'origin/develop'.
...
develop <- checked-out branch, despite asking for my-feature
Expected
Either a worktree on a new branch my-feature starting from origin/develop, or an error telling me the start-point is ambiguous / remote-only.
Environment
git-wt v0.29.0 (also reproduced on v0.15.0)
git 2.50.1 (Apple Git-155), macOS
Plain git worktree add -b my-feature <path> develop reproduces the same behavior, and --no-guess-remote does not prevent it — so this is git's behavior, not a git-wt bug per se. But since git wt <branch> <start-point> is a first-class git-wt interface, git-wt is in a good position to guard against it.
Root cause (git side)
This actually appears to be a bug in git itself, where the implementation contradicts its own documentation. git-worktree(1) says the remote DWIM applies only when "neither -b nor -B nor --detach are used", but the two-positional-args code path in builtin/worktree.c only excludes --detach and unconditionally overwrites the -b value:
} elseif (ac==2) {
...
commit=lookup_commit_reference_by_name(branch);
if (!commit) {
remote=unique_tracking_name(branch, &oid, NULL);
if (remote) {
new_branch=branch; /* clobbers the -b argument */branch=new_branch_to_free=remote;
}
}
The same code is present at least as far back as v2.20.0 (2018), so even if it gets fixed upstream, git-wt users will be running affected git versions for a long time — which I think justifies a guard in git-wt regardless.
Why this is easy to miss
I think a few things conspired to keep this hidden (in git core for 7+ years, and here):
The docs say it can't happen. Reading git-worktree(1) actively convinces you that -b makes this safe, so nobody suspects this path — neither users nor wrapper authors.
The precondition is narrow. The name must be missing locally and exist on exactly one remote. Developers who work in a repo daily usually have develop checked out locally, so it mostly bites fresh clones, CI, and agent-driven workflows that create worktrees from a clean state.
The failure is self-masking. The directory is named after <new-branch>, everything downstream works, and the only clue is a single stderr line (new branch 'develop'). You typically notice at push/PR time — and then it's easy to blame yourself rather than the tool.
For the same reason, the current e2e suite can't hit it: start-points are exercised in remote-qualified form (origin/main~1), and test repos are created by cloning, so the branch always exists locally.
Proposal
This feels like a sibling of #179 ("error when start-point is specified for existing branch or worktree", i.e. don't let a start-point be silently ignored). Options, in my order of preference:
Error out: before running worktree add, verify <start-point> resolves as-is (e.g. git rev-parse --verify --quiet "<start-point>^{commit}" plus a check that it isn't a remote-only bare branch name). If it only matches refs/remotes/*/<start-point>, fail with a hint: did you mean "origin/<start-point>"?
Auto-qualify: if <start-point> matches exactly one remote branch and no local ref, rewrite it to the remote-qualified form and proceed (perhaps with a notice on stderr).
Happy to send a PR for whichever direction you prefer.
Thanks for git-wt — it's become a core part of my daily multi-worktree workflow.
Summary
When creating a new worktree with
git wt <new-branch> <start-point>, if<start-point>is a bare branch name that does not exist locally but exists on exactly one remote (e.g.developright after a clone, or in gitflow repos wheredevelopis rarely checked out locally), the underlyinggit worktree add -b <new-branch> <path> <start-point>triggers git's branch DWIM: the-b <new-branch>is silently ignored, and a local branch named after<start-point>(e.g.develop) is created and checked out instead.The worktree directory is still named after
<new-branch>, so the mismatch is easy to miss — you keep working and committing directly onto a branch nameddevelopwhile believing you are on your feature branch.flowchart TD A["git wt my-feature develop<br/>(→ git worktree add -b my-feature <path> develop)"] --> B{"'develop' resolves<br/>locally?"} B -- "yes" --> C["✅ new branch 'my-feature'<br/>at develop"] B -- "no" --> D{"matches exactly one<br/>remote branch?"} D -- "no" --> E["✅ error:<br/>invalid reference"] D -- "yes" --> F["⚠️ DWIM: new_branch = 'develop'<br/>-b my-feature is silently clobbered"] F --> G["worktree dir: …/my-feature/ (as requested)<br/>checked-out branch: develop (not requested)"]The end state that makes this so easy to miss:
Reproduction
Actual
Expected
Either a worktree on a new branch
my-featurestarting fromorigin/develop, or an error telling me the start-point is ambiguous / remote-only.Environment
git worktree add -b my-feature <path> developreproduces the same behavior, and--no-guess-remotedoes not prevent it — so this is git's behavior, not a git-wt bug per se. But sincegit wt <branch> <start-point>is a first-class git-wt interface, git-wt is in a good position to guard against it.Root cause (git side)
This actually appears to be a bug in git itself, where the implementation contradicts its own documentation.
git-worktree(1)says the remote DWIM applies only when "neither-bnor-Bnor--detachare used", but the two-positional-args code path inbuiltin/worktree.conly excludes--detachand unconditionally overwrites the-bvalue:The same code is present at least as far back as v2.20.0 (2018), so even if it gets fixed upstream, git-wt users will be running affected git versions for a long time — which I think justifies a guard in git-wt regardless.
Why this is easy to miss
I think a few things conspired to keep this hidden (in git core for 7+ years, and here):
git-worktree(1)actively convinces you that-bmakes this safe, so nobody suspects this path — neither users nor wrapper authors.developchecked out locally, so it mostly bites fresh clones, CI, and agent-driven workflows that create worktrees from a clean state.<new-branch>, everything downstream works, and the only clue is a single stderr line (new branch 'develop'). You typically notice at push/PR time — and then it's easy to blame yourself rather than the tool.origin/main~1), and test repos are created by cloning, so the branch always exists locally.Proposal
This feels like a sibling of #179 ("error when start-point is specified for existing branch or worktree", i.e. don't let a start-point be silently ignored). Options, in my order of preference:
worktree add, verify<start-point>resolves as-is (e.g.git rev-parse --verify --quiet "<start-point>^{commit}"plus a check that it isn't a remote-only bare branch name). If it only matchesrefs/remotes/*/<start-point>, fail with a hint:did you mean "origin/<start-point>"?<start-point>matches exactly one remote branch and no local ref, rewrite it to the remote-qualified form and proceed (perhaps with a notice on stderr).Happy to send a PR for whichever direction you prefer.