EnterWorktree (name mode) writes core.hooksPath into the shared repo config; ExitWorktree doesn't restore it

Status Closed — not planned
Reported on v2.1.97
Maintainer reply None cached
Activity 2 comments · opened Jun 10, 2026 · closed Jul 20, 2026

Environment

Claude Code desktop app on macOS 26.5.1 (CLI claude --version: 2.1.97). Multi-session use on the same repos via EnterWorktree/ExitWorktree, worktree.baseRef: "fresh".

Observed behavior (proven by controlled experiment)

Starting from core.hooksPath unset in a repo:

| Action | core.hooksPath afterwards |
|---|---|
| git worktree add (manual) | unset (clean) |
| EnterWorktree with path: (enter existing worktree) | unset (clean) |
| EnterWorktree with name: (create worktree) | <abs>/.git/hooks — written to the SHARED repo config |
| ExitWorktree action=remove afterwards | still <abs>/.git/hooks — not restored |

Because this lands in the shared .git/config, it outlives the worktree and applies to the main checkout and all other worktrees. Any repo that wires its versioned hooks via core.hooksPath (e.g. npm prepare → git config core.hooksPath .githooks) has them silently disabled for every checkout the moment any session creates a name-mode worktree — and re-disabled after every repair, since every new name-mode worktree rewrites it. We chased this as a mystery config-mutator across four repos before isolating it; combined with stale hook copies it produced an afternoon of blocked pushes across parallel sessions.

Related doc-vs-behavior gap

ExitWorktree action=remove documents "deletes the worktree directory and its branch", but after a mid-session git branch -m worktree-<name> task/<name> rename it (a) refuses removal counting already-pushed commits as discardable, and (b) after discard_changes: true removes the directory but leaves the renamed local branch behind.

Suggestions

  • Use extensions.worktreeConfig + per-worktree config.worktree for the hooksPath override instead of mutating shared state; or restore the prior value on exit.
  • Track the worktree by path rather than original branch name so a renamed branch is still recognized as the worktree's own.

Happy to provide the experiment transcript.

View original on GitHub ↗

This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗