Skip to content

Add wt step relocate command#790

Merged
max-sixty merged 32 commits intomainfrom
reset-locations
Jan 26, 2026
Merged

Add wt step relocate command#790
max-sixty merged 32 commits intomainfrom
reset-locations

Conversation

@max-sixty
Copy link
Copy Markdown
Owner

Summary

  • Add wt step relocate command to move worktrees to their expected paths based on the worktree-path template
  • Handles swap/cycle scenarios automatically via temporary locations
  • Add --clobber flag to backup non-worktree paths at target locations
  • Add --commit flag to auto-commit dirty worktrees before relocating

Key behaviors

Swap handling: When worktrees are at each other's expected locations (e.g., alpha @ repo.beta, beta @ repo.alpha), the command automatically resolves via a temp location.

Main worktree: When main worktree has a non-default branch checked out, creates a new linked worktree at the expected path and switches main back to default branch.

Flags:

  • --dry-run: Preview what would be moved
  • --commit: Auto-commit dirty worktrees before relocating
  • --clobber: Backup non-worktree paths to <path>.bak-<timestamp>

Safety: --commit --clobber should handle most scenarios without failing.

Also includes

  • Path redaction improvements for clearer snapshot output (_PARENT_/<dir> instead of [PROJECT_ID])
  • macOS path canonicalization fixes for /var/private/var symlinks

Test plan

  • 11 integration tests covering: no mismatches, single mismatch, dry run, locked worktree, target exists, clobber backup, dirty without commit, main worktree, swap scenario, specific branches, multiple worktrees
  • All 923 tests pass
  • Lints pass

This was written by Claude Code on behalf of max-sixty

max-sixty and others added 3 commits January 21, 2026 15:53
Adds `wt step relocate` to move worktrees to their expected paths based on
the `worktree-path` template. Supports dry-run preview, filtering by branch
name, and auto-committing dirty worktrees. Handles special case of main
worktree by switching to default branch and creating a new worktree.
Implement full swap/cycle handling and non-worktree blocker management for
relocate command. Adds `--clobber` flag to automatically backup blocking
paths, dependency graph processing to handle worktree cycles via temporary
locations, and comprehensive spec documentation.

Key changes:
- Add `--clobber` flag to back up non-worktree paths at target locations
- Implement cycle detection and resolution using temp directory
- Build dependency graph to coordinate multi-worktree moves
- Handle main worktree relocation by creating new worktree + switching
- Add test cases for swap, clobber, and cycle scenarios
- Canonicalize temp home paths on macOS for snapshot consistency
- Refuse to clobber existing worktrees (would corrupt git metadata)
- Prefer non-main worktree when breaking cycles (git can't move main)
- Sanitize branch names for temp paths (feature/foo -> feature-foo)
- Track original path for shell cd in temp-relocated worktrees
- Show template errors as warnings instead of silently dropping

Co-Authored-By: Claude <noreply@anthropic.com>
@max-sixty max-sixty added the feedback-requested Looking for user feedback on this feature label Jan 22, 2026
max-sixty and others added 14 commits January 21, 2026 21:18
Co-Authored-By: Claude <noreply@anthropic.com>
Tests the commit_worktree_changes function by configuring a mock LLM
and verifying that dirty worktrees are auto-committed before relocating.

Co-Authored-By: Claude <noreply@anthropic.com>
- Change unreachable defensive code to expect() with explanation
- Simplify multi-line cformat! calls to single-line (improves LLVM coverage)
- Add test_relocate_mixed_success_and_skip to cover "relocated X, skipped Y" path
- Add test_relocate_dirty_with_commit to cover commit_worktree_changes function

Co-Authored-By: Claude <noreply@anthropic.com>
- Remove shell directory update for temp-to-final worktree moves
  (rare case where user is inside a worktree during cycle resolution)
- Simplify summary pluralization with inline closure
- Remove unused original_path tracking from temp_relocated

Co-Authored-By: Claude <noreply@anthropic.com>
Extract multi-line cformat! macro calls to single-line variables
to improve LLVM coverage instrumentation.

Co-Authored-By: Claude <noreply@anthropic.com>
The early return when no staged changes was unreachable - if is_dirty()
returned true, git add -A must stage something. Removing improves coverage
and follows fail-fast principles.

Co-Authored-By: Claude <noreply@anthropic.com>
- Remove redundant exists() check before create_dir_all
- Extract cformat! to single-line variable in commit_worktree_changes

Co-Authored-By: Claude <noreply@anthropic.com>
Reverts format_path_for_display changes that were unrelated to step relocate
and were reducing coverage percentage since they're in error paths.

Co-Authored-By: Claude <noreply@anthropic.com>
Resolve merge conflict in step_commands.rs imports.
Migrate output API: crate::output::print() → eprintln!()

Co-Authored-By: Claude <noreply@anthropic.com>
Fixes identified by adversarial testing:

1. Empty default branch validation - fails early with actionable error
   instead of confusing "git checkout ''" errors

2. Same-target conflict handling - `is_target_empty` now returns
   `Option<bool>` to gracefully skip when target is unexpectedly
   blocked (TOCTOU race or same-target conflict)

3. Main worktree rollback - if `git worktree add` fails after
   checkout, restore the original branch

Adds test for same-target scenario that previously panicked.

Co-Authored-By: Claude <noreply@anthropic.com>
@max-sixty
Copy link
Copy Markdown
Owner Author

@claude move the plan to a spec in a rust module; then remove it

@worktrunk-bot
Copy link
Copy Markdown
Collaborator

worktrunk-bot commented Jan 23, 2026

Claude finished @max-sixty's task in 6m 16s —— View job


Moving plan to Rust module spec

  • Read the plan file to understand content
  • Determine appropriate location in Rust codebase
  • Move content to Rust module
  • Remove original plan file
  • Run tests
  • Commit and push changes

Summary

Successfully moved the step relocate plan from .claude/plans/step-relocate-spec.md to the step_relocate function's doc comment in src/commands/step_commands.rs.

Changes:

  • Enhanced the function doc comment with the complete specification including:
    • Detailed flag descriptions
    • Comprehensive algorithm explanation with phases
    • Multiple scenario examples (simple, swap, chain, mixed, clobber, main worktree)
    • Implementation notes
    • Complete test case list
  • Deleted the original plan file

Testing:

  • All 15 step_relocate tests pass ✓
  • Clippy lints pass ✓
  • Formatting is correct ✓

The specification is now directly attached to the implementation, making it more discoverable for developers and keeping it synchronized with the code.

--- | Branch: reset-locations

github-actions Bot and others added 10 commits January 23, 2026 09:27
Moved the comprehensive plan from .claude/plans/step-relocate-spec.md
to a Rust doc comment on the step_relocate function. This makes the
specification more discoverable and keeps it synchronized with the
implementation.

The doc comment now includes:
- Complete flag descriptions
- Detailed algorithm explanation
- Multiple scenario examples (swap, chain, mixed, clobber, main worktree)
- Implementation notes
- Test case list

Co-authored-by: Maximilian Roos <max-sixty@users.noreply.github.com>
Add tests for:
- Template expansion error handling (invalid variable)
- Empty default branch validation (non-existent configured branch)

These cover lines 844-847 and 890-895 in step_commands.rs that were
flagged by codecov/patch.

Co-Authored-By: Claude <noreply@anthropic.com>
- Use gutter formatting for template error details (per output guidelines)
- Fix misleading summary when template errors occurred
- Show source path in temp-relocated worktree success messages
- Use bright-black styling for flags in hints (--commit, --clobber)
- Use concrete example in default branch error message

Co-Authored-By: Claude <noreply@anthropic.com>
Per output guidelines: every user-facing message needs symbol or gutter.
The dry-run preview now uses gutter formatting instead of plain indentation.

Co-Authored-By: Claude <noreply@anthropic.com>
The error message now suggests 'wt config state default-branch set main'
instead of the raw git config command.

Co-Authored-By: Claude <noreply@anthropic.com>
Extract commit staging and execution into CommitGenerator to eliminate
duplicate commit logic in step_relocate. Add show_progress parameter to
control progress message display for bulk operations. Add repo() accessor
to WorkingTree for repository access.
…ypes

Split the 500-line monolithic step_relocate function into a clean pipeline:
- gather_candidates() finds worktrees not at expected paths
- validate_candidates() checks locked/dirty, handles --commit
- RelocationExecutor encapsulates the dependency graph algorithm

New types document each stage: RelocationCandidate, ValidatedCandidate,
GatherResult, ValidationResult. The complex swap/cycle resolution logic
is now isolated in RelocationExecutor with clear methods for each phase.

Co-authored-by: Claude <noreply@anthropic.com>
Resolved conflict in resolve.rs: kept pub(crate) visibility for paths_match
(needed by relocate.rs module) while accepting main's removal of redundant
use statement.

Co-authored-by: Claude <noreply@anthropic.com>
max-sixty and others added 5 commits January 24, 2026 12:36
Resolved conflicts:
- src/main.rs: Combined imports (handle_logs_get from main, step_relocate from HEAD)
- tests/common/mod.rs: Kept main's refactor to use setup_snapshot_settings_impl
  (which already handles canonicalization internally)

Co-Authored-By: Claude <noreply@anthropic.com>
The test was using the old `args` field which no longer exists. The
command should be a complete shell string that receives the prompt
via stdin.

Co-Authored-By: Claude <noreply@anthropic.com>
Resolved conflict in paths_match by:
- Keeping pub(crate) visibility from this branch
- Using improved canonicalize_with_parents from main

Co-Authored-By: Claude <noreply@anthropic.com>
@max-sixty max-sixty merged commit c4b50bb into main Jan 26, 2026
21 checks passed
@max-sixty max-sixty deleted the reset-locations branch January 26, 2026 00:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feedback-requested Looking for user feedback on this feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants