Skip to content

Commit 10c3bc1

Browse files
authored
fix: run checkout hooks when worktree already exists (#71) (#72)
Previously, `wt checkout` skipped pre/post checkout hooks when the worktree already existed due to an early return. Now hooks run regardless of whether the worktree is new or existing.
1 parent 967ed9a commit 10c3bc1

3 files changed

Lines changed: 49 additions & 1 deletion

File tree

docs/configuration.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ Hooks let you run custom commands before or after `wt` operations. Define them i
9898
| `pre_pr` / `post_pr` | Before/after `wt pr` |
9999
| `pre_mr` / `post_mr` | Before/after `wt mr` |
100100

101-
Hooks only run when a **new worktree is actually created** (or removed). If a worktree already exists, the early-return path skips hooks entirely.
101+
Checkout hooks (`pre_checkout` / `post_checkout`) run both when a new worktree is created **and** when checking out an existing worktree. Create and remove hooks run only when a worktree is actually created or removed.
102102

103103
**Environment variables** available in hook commands:
104104

e2e/scenarios/hooks.yaml

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,44 @@ scenarios:
5151
expect:
5252
output_contains: "HOOK_RAN"
5353

54+
- name: checkout_hooks_run_on_existing_worktree
55+
description: Pre/post checkout hooks execute even when worktree already exists
56+
skip_os: [windows]
57+
skip_shellenv: true
58+
setup:
59+
- create_branch: existing-co-branch
60+
steps:
61+
# First checkout creates the worktree (no hook config yet)
62+
- run: $WT_BIN checkout existing-co-branch
63+
expect:
64+
exit_code: 0
65+
- cd: $REPO_DIR
66+
# Second checkout with hooks configured — hooks should still run
67+
- run: mkdir -p "$TEST_DIR/config" && printf '[hooks]\npost_checkout = ["touch $WT_PATH/.existing-hook-ran"]\n' > "$TEST_DIR/config/config.toml" && WT_CONFIG="$TEST_DIR/config/config.toml" $WT_BIN checkout existing-co-branch
68+
expect:
69+
exit_code: 0
70+
output_contains: "already exists"
71+
- run: test -f "$WORKTREE_ROOT/test-repo/existing-co-branch/.existing-hook-ran" && echo "HOOK_RAN" || echo "HOOK_MISSING"
72+
expect:
73+
output_contains: "HOOK_RAN"
74+
75+
- name: pre_checkout_hook_aborts_existing_worktree
76+
description: Pre-checkout hook failure prevents checkout of existing worktree
77+
skip_os: [windows]
78+
skip_shellenv: true
79+
setup:
80+
- create_branch: abort-co-branch
81+
steps:
82+
# First checkout creates the worktree
83+
- run: $WT_BIN checkout abort-co-branch
84+
expect:
85+
exit_code: 0
86+
- cd: $REPO_DIR
87+
# Second checkout with failing pre_checkout hook — should abort
88+
- run: mkdir -p "$TEST_DIR/config" && printf '[hooks]\npre_checkout = ["false"]\n' > "$TEST_DIR/config/config.toml" && WT_CONFIG="$TEST_DIR/config/config.toml" $WT_BIN checkout abort-co-branch
89+
expect:
90+
exit_code: 1
91+
5492
- name: pre_remove_hook_runs
5593
description: Pre-remove hook executes before worktree removal
5694
skip_os: [windows]

main.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -915,6 +915,16 @@ var checkoutCmd = &cobra.Command{
915915

916916
// Check if worktree already exists
917917
if existingPath, exists := worktreeExists(branch); exists {
918+
hookEnv := buildHookEnv(info, branch, existingPath)
919+
920+
// Run pre-checkout hooks
921+
if err := runHooks("pre_checkout", getHooks("pre_checkout"), hookEnv); err != nil {
922+
return fmt.Errorf("pre-checkout hook failed: %w", err)
923+
}
924+
925+
// Run post-checkout hooks (warn only)
926+
_ = runHooks("post_checkout", getHooks("post_checkout"), hookEnv)
927+
918928
if isJSONOutput() {
919929
return emitJSONSuccess(cmd, map[string]any{
920930
"status": "exists",

0 commit comments

Comments
 (0)