Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/src/content/docs/switch.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ $ wt switch https://github.com/owner/repo/pull/123 # ...or paste the PR's URL

The `--create` flag creates a new branch from `--base` — the default branch unless specified. Without `--create`, the branch must already exist. Switching to a remote branch (e.g., `wt switch feature` when only `origin/feature` exists) creates a local tracking branch.

`--create` from a remote base is the exception. For the branch it creates, `wt` defaults git's `branch.autoSetupMerge` to `simple` instead of git's own `true`, so the new branch tracks its base only when the two share a name: `--create release --base origin/release` tracks `origin/release`, while `--create feature --base origin/release` — and the bare `--base release` that resolves to it — gets no upstream. Git's default would have `feature` track `origin/release`, so under `push.default = upstream` a bare `git push` would push the new work to `release`. A `branch.autoSetupMerge` set in git config takes precedence over that default. Publishing such a branch takes `git push --set-upstream origin <branch>`, or git's `push.autoSetupRemote = true` set once, after which a bare `git push` from the new worktree publishes it and configures its tracking.
`--create` from a remote base is the exception. The branch it creates tracks its base only when the two share a name: `--create release --base origin/release` tracks `origin/release`, while `--create feature --base origin/release` — and the bare `--base release` that resolves to it — gets no upstream. Git's default would have `feature` track `origin/release`, so under `push.default = upstream` a bare `git push` would push the new work to `release`. `wt` runs the creation under git's own `branch.autoSetupMerge = simple` rule whatever the config file says, so the outcome is the same everywhere. Publishing such a branch takes `git push --set-upstream origin <branch>`, or git's `push.autoSetupRemote = true` set once, after which a bare `git push` from the new worktree publishes it and configures its tracking.

## Creating worktrees

Expand Down
2 changes: 1 addition & 1 deletion plugins/worktrunk/skills/worktrunk/reference/switch.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ $ wt switch https://github.com/owner/repo/pull/123 # ...or paste the PR's URL

The `--create` flag creates a new branch from `--base` — the default branch unless specified. Without `--create`, the branch must already exist. Switching to a remote branch (e.g., `wt switch feature` when only `origin/feature` exists) creates a local tracking branch.

`--create` from a remote base is the exception. For the branch it creates, `wt` defaults git's `branch.autoSetupMerge` to `simple` instead of git's own `true`, so the new branch tracks its base only when the two share a name: `--create release --base origin/release` tracks `origin/release`, while `--create feature --base origin/release` — and the bare `--base release` that resolves to it — gets no upstream. Git's default would have `feature` track `origin/release`, so under `push.default = upstream` a bare `git push` would push the new work to `release`. A `branch.autoSetupMerge` set in git config takes precedence over that default. Publishing such a branch takes `git push --set-upstream origin <branch>`, or git's `push.autoSetupRemote = true` set once, after which a bare `git push` from the new worktree publishes it and configures its tracking.
`--create` from a remote base is the exception. The branch it creates tracks its base only when the two share a name: `--create release --base origin/release` tracks `origin/release`, while `--create feature --base origin/release` — and the bare `--base release` that resolves to it — gets no upstream. Git's default would have `feature` track `origin/release`, so under `push.default = upstream` a bare `git push` would push the new work to `release`. `wt` runs the creation under git's own `branch.autoSetupMerge = simple` rule whatever the config file says, so the outcome is the same everywhere. Publishing such a branch takes `git push --set-upstream origin <branch>`, or git's `push.autoSetupRemote = true` set once, after which a bare `git push` from the new worktree publishes it and configures its tracking.

## Creating worktrees

Expand Down
2 changes: 1 addition & 1 deletion skills/worktrunk/reference/switch.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion src/cli/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -627,7 +627,7 @@ $ wt switch https://github.com/owner/repo/pull/123 # ...or paste the PR's URL

The `--create` flag creates a new branch from `--base` — the default branch unless specified. Without `--create`, the branch must already exist. Switching to a remote branch (e.g., `wt switch feature` when only `origin/feature` exists) creates a local tracking branch.

`--create` from a remote base is the exception. For the branch it creates, `wt` defaults git's `branch.autoSetupMerge` to `simple` instead of git's own `true`, so the new branch tracks its base only when the two share a name: `--create release --base origin/release` tracks `origin/release`, while `--create feature --base origin/release` — and the bare `--base release` that resolves to it — gets no upstream. Git's default would have `feature` track `origin/release`, so under `push.default = upstream` a bare `git push` would push the new work to `release`. A `branch.autoSetupMerge` set in git config takes precedence over that default. Publishing such a branch takes `git push --set-upstream origin <branch>`, or git's `push.autoSetupRemote = true` set once, after which a bare `git push` from the new worktree publishes it and configures its tracking.
`--create` from a remote base is the exception. The branch it creates tracks its base only when the two share a name: `--create release --base origin/release` tracks `origin/release`, while `--create feature --base origin/release` — and the bare `--base release` that resolves to it — gets no upstream. Git's default would have `feature` track `origin/release`, so under `push.default = upstream` a bare `git push` would push the new work to `release`. `wt` runs the creation under git's own `branch.autoSetupMerge = simple` rule whatever the config file says, so the outcome is the same everywhere. Publishing such a branch takes `git push --set-upstream origin <branch>`, or git's `push.autoSetupRemote = true` set once, after which a bare `git push` from the new worktree publishes it and configures its tracking.

## Creating worktrees

Expand Down
42 changes: 28 additions & 14 deletions src/commands/worktree/switch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -468,8 +468,9 @@ fn parse_ref_shortcut(input: &str) -> Option<(RefType, u32)> {
/// returns the remote-qualified form so the validation in
/// [`resolve_switch_target`] doesn't reject `wt switch -c new --base
/// remote-only-branch`. Git's rev-parse doesn't auto-expand `foo` to
/// `refs/remotes/origin/foo`. The new branch's upstream is unset downstream
/// to keep `git push` from targeting the base.
/// `refs/remotes/origin/foo`. The remote-qualified form is also what lets the
/// creation site's `branch.autoSetupMerge = simple` see a remote branch at all,
/// so `--base release` and `--base origin/release` set up the same tracking.
Comment thread
worktrunk-bot marked this conversation as resolved.
Outdated
fn resolve_base_ref(
repo: &Repository,
base: &str,
Expand Down Expand Up @@ -1044,22 +1045,35 @@ fn execute_switch(
let worktree_path_str = worktree_path.to_string_lossy();
let mut args: Vec<&str> = Vec::new();

// Safety: for an explicitly requested branch, default
// `branch.autoSetupMerge` to `simple` rather than git's
// `true`. Under `true`, `git worktree add -b feature
// origin/main` sets `feature` to track `origin/main`, so a
// bare `git push` under `push.default = upstream` pushes the
// new work to `main` (#713). `simple` is git's own narrower
// mode: it sets tracking only when the new branch's name
// matches the remote branch's, which is exactly the case
// where inherited tracking is correct. An explicit setting
// wins — `wt` picks a different default, it does not override
// the user's configuration.
// Safety: for an explicitly requested branch, `wt` decides
// tracking rather than the user's `branch.autoSetupMerge`.
// `-c` outranks every config file, so the outcome is the same
// on every machine. Git's `simple` is the rule `wt` wants: an
// upstream only when the new branch's name matches the remote
// branch it starts from, which is exactly when inherited
// tracking is right. Git's default `true`, and `always`, would
// have `--create feature --base origin/release` track
// `origin/release`, so a bare `git push` under
// `push.default = upstream` pushes the new work to `release`
// (#713); `false` and `inherit` would deny `--create release
// --base origin/release` the tracking that is the point of a
// same-named branch.
//
// `wt` sets git's rule rather than picking `--track` /
// `--no-track` from a name comparison of its own, because only
// git maps the base back to a remote branch through the fetch
// refspec. Splitting `<remote>/<branch>` reads
// `team/fork/release` as branch `fork/release`, so the verdict
// inverts both ways, and a refspec that renames into a
// sub-namespace does the same. `--track` is also a hard demand
// where `simple` is best-effort: it fails the whole command
// when the base isn't refspec-mapped, as in a single-branch
// clone holding a hand-fetched ref.
//
// Only the `--create` paths need it. The DWIM paths below
// create `feature` from `origin/feature`, where the names
// match and `simple` and `true` agree.
if *create_branch && repo.config_value("branch.autoSetupMerge")?.is_none() {
if *create_branch {
args.extend(["-c", "branch.autoSetupMerge=simple"]);
}

Expand Down
10 changes: 5 additions & 5 deletions src/commands/worktree/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,11 @@ pub enum CreationMethod {
/// When `--base pr:N` / `--base mr:N` (same-repo) is paired with `--create`,
/// the user's intent is "create a new branch tracking the PR/MR's source
/// branch on the remote", so `git push` from the new worktree pushes back
/// to that PR/MR. `git worktree add -b new <bare-name>` doesn't set up
/// tracking on its own (only `<remote>/<branch>` triggers DWIM, and even
/// then we'd unset it via the issue-#713 safety check), so we capture the
/// (remote, branch) pair here and configure tracking explicitly after
/// `git worktree add` succeeds. `None` for any other base resolution.
/// to that PR/MR. The base here is the PR/MR's source branch under its
/// bare name, which `branch.autoSetupMerge = simple` never reads as a
/// remote branch, so it sets no tracking — we capture the (remote,
/// branch) pair and configure tracking explicitly after `git worktree
/// add` succeeds. `None` for any other base resolution.
Comment thread
worktrunk-bot marked this conversation as resolved.
Outdated
base_pr_upstream: Option<(String, String)>,
},
/// Fork PR/MR: fetch from refs/pull/N/head or refs/merge-requests/N/head,
Expand Down
Loading
Loading