How lefthook works — why you should never run install in a linked worktree
Environment
- lefthook v2.1.6
- git v2.54.0
Background
- git executes files with reserved names, such as
pre-commit, located under.git/hooksat specific points in its workflow. This is a built-in feature of git. - Initially, the directory only contains example files suffixed with
.sample, so no hooks run. Once you create an executable file with the exact reserved name, that git hook will run from then on. lefthook installgenerates a shell script that says “find the lefthook binary and run it,” and places it at.git/hooks/pre-*. At this point, the path to the lefthook binary is hardcoded into the script.- Every time a git hook fires, the lefthook binary reads the jobs described in the
lefthook.ymlDSL and executes them. This is why changes to jobs in the yml take effect immediately, without re-runninglefthook install.
How lefthook runs, step by step
- A git command is executed
- git runs the hook script in
.git/hooks - The git hook script runs the lefthook binary
- The lefthook binary executes the jobs registered in
lefthook.yml
Why this matters
Creating a new git worktree does not create a new .git/hooks. A git repository has exactly one .git/hooks, shared across all worktrees.
As long as you run lefthook install only in the primary worktree, everything is fine.
But if you run lefthook install in a newly created linked worktree, the lefthook binary path registered in .git/hooks gets hardcoded to the binary inside that linked worktree.
While the linked worktree is alive, nothing goes wrong. But when you delete the linked worktree, the lefthook binary is deleted along with it.
After that, git hooks still fire without raising any error. All you get is a message: “Can’t find lefthook in PATH”. The lefthook binary was removed together with the linked worktree. If you put blind faith in lefthook, you may end up feeling betrayed.
20260604
Leave a comment