Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
414779f
Add step promote command to exchange branches between worktrees
max-sixty Jan 22, 2026
7f66a8f
Improve step promote command UX
max-sixty Jan 22, 2026
7822eae
Update snapshots after rebase on main
max-sixty Jan 22, 2026
b3326f4
Remove unnecessary run_command_in_dir from Repository
max-sixty Jan 22, 2026
193e16b
Add tests for bare repo and detached HEAD error paths
max-sixty Jan 22, 2026
a6cd5ec
Add test for detached HEAD in linked worktree
max-sixty Jan 22, 2026
f6d49c3
Address code review feedback from Codex
max-sixty Jan 22, 2026
03a61c5
Simplify promote error handling
max-sixty Jan 22, 2026
f74bfaa
Merge remote-tracking branch 'origin/main' into promote
max-sixty Jan 22, 2026
5b8d073
Merge branch 'main' into promote
max-sixty Jan 22, 2026
c12d205
Merge branch 'main' into promote
max-sixty Jan 24, 2026
0f245a8
Merge remote-tracking branch 'origin/main' into promote
max-sixty Jan 25, 2026
4e20e48
Merge main into promote
max-sixty Jan 27, 2026
be2bd3e
docs: add relocate to step operations list
max-sixty Jan 27, 2026
4686c7f
Merge main into promote
max-sixty Jan 30, 2026
1c373d8
Merge branch 'main' into promote
max-sixty Feb 19, 2026
05a0fdc
fix: update step subcommand count and snapshot after merge
max-sixty Feb 19, 2026
262c588
fix: harden promote swap with staging-before-switch and rollback
max-sixty Feb 19, 2026
a520a62
Merge branch 'main' into promote
max-sixty Feb 19, 2026
51708eb
fix: harden promote with symlink-safe checks, earlier stale detection…
max-sixty Feb 19, 2026
df9cec3
Merge branch 'main' into promote
max-sixty Feb 20, 2026
c0fb97d
test: improve promote coverage for codecov/patch
max-sixty Feb 20, 2026
cc28652
test: extract copy_and_remove and test remaining uncovered paths
max-sixty Feb 20, 2026
647018d
refactor: simplify exchange_branches rollback to data-driven loop
max-sixty Feb 20, 2026
d182234
refactor: remove restore_staged — stale staging detection suffices
max-sixty Feb 20, 2026
2d95e5a
fix: remove trailing blank line (fmt)
max-sixty Feb 20, 2026
d23fcf2
fix: use eager context formatting for non-hot paths
max-sixty Feb 20, 2026
1eec15a
fix: apply cargo fmt
max-sixty Feb 20, 2026
81ee164
ci: retrigger codecov check
max-sixty Feb 20, 2026
a15f5af
fix: check stale staging before ensure_clean, use git switch --detach
max-sixty Feb 20, 2026
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: 2 additions & 0 deletions docs/content/step.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ wt step push
- `diff` — Show all changes since branching (committed, staged, unstaged, untracked)
- `copy-ignored` — Copy gitignored files between worktrees
- `for-each` — [experimental] Run a command in every worktree
- `promote` — [experimental] Put a branch into the main worktree
- `relocate` — [experimental] Move worktrees to expected paths

## See also
Expand All @@ -61,6 +62,7 @@ Usage: <b><span class=c>wt step</span></b> <span class=c>[OPTIONS]</span> <span
<b><span class=c>diff</span></b> Show all changes since branching
<b><span class=c>copy-ignored</span></b> Copy gitignored files to another worktree
<b><span class=c>for-each</span></b> [experimental] Run command in each worktree
<b><span class=c>promote</span></b> [experimental] Put a branch into the main worktree
<b><span class=c>relocate</span></b> [experimental] Move worktrees to expected paths

<b><span class=g>Options:</span></b>
Expand Down
2 changes: 2 additions & 0 deletions skills/worktrunk/reference/step.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ wt step push
- `diff` — Show all changes since branching (committed, staged, unstaged, untracked)
- `copy-ignored` — Copy gitignored files between worktrees
- `for-each` — [experimental] Run a command in every worktree
- `promote` — [experimental] Put a branch into the main worktree
- `relocate` — [experimental] Move worktrees to expected paths

## Command reference
Expand All @@ -47,6 +48,7 @@ Usage: <b><span class=c>wt step</span></b> <span class=c>[OPTIONS]</span> <span
<b><span class=c>diff</span></b> Show all changes since branching
<b><span class=c>copy-ignored</span></b> Copy gitignored files to another worktree
<b><span class=c>for-each</span></b> [experimental] Run command in each worktree
<b><span class=c>promote</span></b> [experimental] Put a branch into the main worktree
<b><span class=c>relocate</span></b> [experimental] Move worktrees to expected paths

<b><span class=g>Options:</span></b>
Expand Down
1 change: 1 addition & 0 deletions src/cli/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1027,6 +1027,7 @@ wt step push
- `diff` — Show all changes since branching (committed, staged, unstaged, untracked)
- `copy-ignored` — Copy gitignored files between worktrees
- `for-each` — [experimental] Run a command in every worktree
- `promote` — [experimental] Put a branch into the main worktree
- `relocate` — [experimental] Move worktrees to expected paths

## See also
Expand Down
51 changes: 51 additions & 0 deletions src/cli/step.rs
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,57 @@ Note: This command is experimental and may change in future versions.
args: Vec<String>,
},

/// \[experimental\] Put a branch into the main worktree
///
/// The displaced branch moves to the promoted branch's worktree.
#[command(
after_long_help = r#"**Experimental.** Use promote for temporary testing when the main worktree has special significance (Docker Compose, IDE configs, heavy build artifacts anchored to project root), and hooks & tools aren't yet set up to run on arbitrary worktrees. The idiomatic Worktrunk workflow does not use `promote`; instead each worktree has a full environment. `promote` is the only Worktrunk command which changes a branch in an existing worktree.

## Example

```console
# from ~/project (main worktree)
$ wt step promote feature
```

Before:

```
Branch Path
@ main ~/project
+ feature ~/project.feature
```

After:

```
Branch Path
@ feature ~/project
+ main ~/project.feature
```

To restore: `wt step promote main` from anywhere, or just `wt step promote` from the main worktree.

Without an argument, promotes the current branch — or restores the default branch if run from the main worktree.

## Requirements

- Both worktrees must be clean
- The branch must have an existing worktree

## Gitignored files

Gitignored files are swapped along with the branches so each worktree keeps the artifacts that belong to its branch. See [copy-ignored](/step/#copy-ignored) for filtering with `.worktreeinclude`.
"#
)]
Promote {
/// Branch to promote to main worktree
///
/// Defaults to current branch, or default branch from main worktree.
#[arg(add = crate::completion::worktree_only_completer())]
branch: Option<String>,
},

/// \[experimental\] Move worktrees to expected paths
///
/// Relocates worktrees whose path doesn't match the `worktree-path` template.
Expand Down
4 changes: 2 additions & 2 deletions src/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ pub(crate) use merge::{MergeOptions, handle_merge};
#[cfg(unix)]
pub(crate) use select::handle_select;
pub(crate) use step_commands::{
RebaseResult, SquashResult, handle_rebase, handle_squash, step_commit, step_copy_ignored,
step_diff, step_relocate, step_show_squash_prompt,
PromoteResult, RebaseResult, SquashResult, handle_promote, handle_rebase, handle_squash,
step_commit, step_copy_ignored, step_diff, step_relocate, step_show_squash_prompt,
};
pub(crate) use worktree::{
OperationMode, handle_remove, handle_remove_current, is_worktree_at_expected_path,
Expand Down
Loading
Loading