feat: introduce wt adopt as core worktree management primitive#29
feat: introduce wt adopt as core worktree management primitive#29guodong-sq merged 5 commits intoblock:mainfrom
wt adopt as core worktree management primitive#29Conversation
Add `wt adopt` command that gives any existing git worktree the "wt treatment" — metadata import, Bazel symlink installation, and a marker file at $(git rev-parse --git-dir)/wt/adopted to track adoption state. This decouples worktree creation from wt management: worktrees created via plain `git worktree add` can now be retroactively adopted, and they don't need to live in the managed worktrees base directory. Refactor `wt add` to use adoption internally — it now does `git worktree add` followed by `wt_adopt_worktree()`, replacing the inline `install_metadata_for_worktree` and `install_bazel_symlinks_for_worktree` helpers that were moved to the new `lib/wt-adopt` library. New files: - lib/wt-adopt: marker helpers (is/mark/unmark_adopted, is_main_repo), Bazel symlink installation, and full adoption treatment function - bin/wt-adopt: user-facing command with CWD/path/branch-name modes, main-repo guard, and idempotent re-adopt prompt Also: shell completions, dispatch wiring, test helpers (assert_is_adopted/refute_is_adopted), unit + integration tests. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: Claude Code <noreply@anthropic.com> Ai-assisted: true
Adoption now checks for pre-existing metadata and Bazel directories before overwriting. The conflict check mirrors wt-metadata-import's vault-scanning logic so it detects the exact same set of files. Interactive sessions get a 3-option prompt: [O]verwrite — replace with vault contents [K]eep — adopt without importing metadata (Bazel symlinks still installed) [A]bort — cancel adoption Non-interactive sessions abort with an error listing the conflicts. New flags for bin/wt-adopt: --force skip conflict checks (overwrite without prompting) --redo re-run adoption treatment on already-adopted worktrees bin/wt-add now passes --force to wt_adopt_worktree since freshly created worktrees have no conflicts. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: Claude Code <noreply@anthropic.com> Ai-assisted: true
| if [[ "$keep_existing" != true ]]; then | ||
| local metadata_import="" | ||
| if [[ -n "${SCRIPT_DIR:-}" && -x "$SCRIPT_DIR/wt-metadata-import" ]]; then | ||
| metadata_import="$SCRIPT_DIR/wt-metadata-import" | ||
| elif [[ -x "$HOME/.wt/bin/wt-metadata-import" ]]; then | ||
| metadata_import="$HOME/.wt/bin/wt-metadata-import" | ||
| elif command -v wt-metadata-import >/dev/null 2>&1; then | ||
| metadata_import="wt-metadata-import" | ||
| fi | ||
|
|
||
| if [[ -n "$metadata_import" && -d "${WT_IDEA_FILES_BASE:-}" ]]; then | ||
| info "Importing metadata into worktree: $worktree_path" | ||
| "$metadata_import" -y "$WT_IDEA_FILES_BASE" "$worktree_path" | ||
| fi |
There was a problem hiding this comment.
failures here should get bubbled up so that a worktree is not stamped as "adopted" with metadata never imported and no user feedback in cases where import fails.
(I had this happened to me before where I deleted the symlink src of the metadata)
|
|
||
| # Resolve target worktree | ||
| if [[ -z "$TARGET_WORKTREE" ]]; then | ||
| TARGET_WORKTREE="$(pwd -P)" |
There was a problem hiding this comment.
When wt adopt is run with no arguments from a subdirectory inside a worktree (e.g., /repo-java/orders/src/main), TARGET_WORKTREE is set to the current physical directory via pwd -P, not to the worktree's root. All downstream treatment then operates on that subdirectory: wt-metadata-import installs vault contents into the subdirectory, and wt_install_bazel_symlinks creates bazel-out/bazel-bin symlinks inside it. Only wt_mark_adopted is unaffected because it uses git -C "$worktree_path" rev-parse --git-dir.
| fi | ||
|
|
||
| ln -s "$target" "$dst_link" | ||
| echo " ✓ $symlink_name -> $target" |
|
|
||
| install_metadata_for_worktree "$worktree_path" | ||
| install_bazel_symlinks_for_worktree "$worktree_path" | ||
| wt_adopt_worktree --force "$(cd "$worktree_path" && pwd)" |
There was a problem hiding this comment.
should these be pwd -P as well?
1. Metadata import failure now prevents adoption marker from being written. If wt-metadata-import exits non-zero, wt_adopt_worktree returns 1 and the worktree is not stamped as adopted. 2. CWD mode (`wt adopt` with no args) now resolves to the worktree root via `git rev-parse --show-toplevel`, not `pwd -P`. Running from a subdirectory no longer installs metadata/symlinks into the wrong location. 3. Use `info` log utility in wt_install_bazel_symlinks instead of raw `echo` for consistency with the rest of the codebase. 4. Use `pwd -P` (physical path) in all wt_adopt_worktree call sites in bin/wt-add to match codebase conventions and avoid macOS symlink issues (e.g. /var -> /private/var). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: Claude Code <noreply@anthropic.com> Ai-assisted: true
The interactive "keep" prompt test requires expect(1) to simulate a TTY. Skip gracefully in CI environments where expect is not installed. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: Claude Code <noreply@anthropic.com> Ai-assisted: true
Extract TTY check into _wt_is_interactive() function in lib/wt-adopt so tests can override it. Removes the expect(1) dependency that broke CI (not installed on GitHub Actions runners). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: Claude Code <noreply@anthropic.com> Ai-assisted: true
Implements major parts of #18
Add
wt adoptcommand that gives any existing git worktree thewttreatment — metadata import, Bazel symlink installation, and a marker file at$(git rev-parse --git-dir)/wt/adoptedto track adoption state.This decouples worktree creation from
wtmanagement: worktrees created via plaingit worktree addcan now be retroactively adopted, and they don't need to live in the managed worktrees base directory.Refactor
wt addto use adoption internally — it now doesgit worktree addfollowed bywt_adopt_worktree(), replacing the inlineinstall_metadata_for_worktreeandinstall_bazel_symlinks_for_worktreehelpers that were moved to the newlib/wt-adoptlibrary.New files:
lib/wt-adopt: marker helpers (is/mark/unmark_adopted,is_main_repo), Bazel symlink installation, conflict detection, and full adoption treatment functionbin/wt-adopt: user-facing command with CWD/path/branch-name modes, main-repo guard, and--force/--redoflagsOverwrite protection
Adoption now detects pre-existing metadata and Bazel directories before overwriting. The conflict check scans the vault using the same
findlogic aswt-metadata-import, so it detects the exact same set of files that would be imported.Interactive sessions get a 3-option prompt:
Non-interactive sessions abort with an error listing the conflicts.
Bazel symlinks (
bazel-out, etc.) are only flagged as conflicts when they are real directories — existing symlinks are always safe to replace.Flags
--force--redo--forceon an already-adopted worktree also triggers re-run (implies--redo).Also: shell completions, dispatch wiring, test helpers (
assert_is_adopted/refute_is_adopted), unit + integration tests (36 adopt-specific tests).TODO
wt list