#66210

Worktree creation hangs with a prek (post-checkout) hook

OpenYura52opened 3d ago

Reproduction steps

  1. Create a new Git repository and commit a single prek.toml file to it:
# prek.toml
default_install_hook_types = ["post-checkout"]

[[repos]]
repo = "local"
hooks = [
    {
        id = "git-version",
        name = "Print Git version",
        entry = "git --version",
        language = "system",
        stages = ["post-checkout"],
        always_run = true,
        pass_filenames = false,
    },
]
  1. Run prek install from the root of the repository.

  2. Open the repository in Zed and try creating a new worktree using the top left worktree button.

Result: the worktree creation hangs. More precisely, the new checkout exists, but git worktree add waits on prek, which has a zombie child.

Possibly related:

P.S. The issue description and the minimal reproduction is drafted with LLM, and then fully reviewed and edited by myself.

Current vs. Expected behavior

Creating a worktree from the top-left worktree button leaves “Creating worktree…” spinning indefinitely instead of creating a new worktree and switching to it.

Zed version and system specs

  • macOS 15.8.1
  • Zed 1.25.3, build 20261023.131444
  • Homebrew Git 2.56.0
  • prek 0.5.7 (8569a4ac5)

Attach Zed log file

No response

Relevant Zed settings

settings.json
undefined

Relevant Keymap

keymap.json
undefined

(for AI issues) Model provider details

No response

If you are using WSL on Windows, what flavor of Linux are you using?

None

Activity

1
yeskunall2d ago

I reproduced this on macOS 15.8.1 arm64 with Zed Nightly 1.27.0+nightly.3483.37faef81f74fc1bb08be9939c4cffc8ede6ced2f, prek 0.5.7 (8569a4ac5) and Apple Git 2.50.1.

  1. In a disposable repository, I committed the minimal prek.toml below and ran prek install.
  2. I opened the repository in a separate window of the running Nightly instance.
  3. I opened git: worktree from the command palette, entered a new worktree name and confirmed creation.

The checkout existed, but Zed did not switch to it. The status bar kept showing git worktree add (detached). Process snapshots at 1, 22 and 23 seconds showed Git waiting on prek, with a zombie child under prek. The editor remained responsive: I could open the command palette and filter its actions while the Git operation was stuck. I then stopped only the disposable prek process.

I expected the trivial hook to finish and Zed to switch to the new worktree. Running git worktree add --detach from the shell with the same installed hook completed successfully.

Minimal prek.toml used
default_install_hook_types = ["post-checkout"]

[[repos]]
repo = "local"
hooks = [
    { id = "git-version", name = "Print Git version", entry = "git --version", language = "system", stages = ["post-checkout"], always_run = true, pass_filenames = false },
]
Additional controls and signal-mask observations

Replacing the hook with a plain shell script running git --version let UI worktree creation finish and switch normally.

In separate diagnostic runs, I used a Python wrapper to inspect the inherited signal mask before executing the same prek binary. Shell launches had an empty mask; Nightly launches had SIGCHLD blocked. Preserving that mask completed in one run and hung with a zombie child in another. Unblocking only SIGCHLD before executing prek let creation finish.

This points toward inherited signal masking, but the masked runs were not deterministic. These were diagnostic controls, not a tested production fix. The original reproduction above used prek’s generated hook without that wrapper.

The worktree path still launches Git inside a background executor task in create_worktree, whereas #44212 changed the separate direct-hook execution path.