DEV Community

Omer Saleem
Omer Saleem

Posted on Originally published at omerbinsaleem.com

Why commits in a git worktree ran no husky hooks

Originally published at omerbinsaleem.com by Omer Bin Saleem (Omer Saleem).

In a linked worktree, husky's runner folder was missing, so commits ran no hooks at all. Copying it in exposed a second trap, and a local clone fixed both.

How to do it

  1. Check first whether hooks run at all. Husky's runner folder .husky/_ is generated and gitignored, and core.hooksPath=.husky/_ resolves per worktree. A linked worktree has no such folder, so commits there ran no pre-commit, commit-msg or pre-push hook.
  2. Copying .husky/_ in makes the hooks run, but a hook that falls back to Docker can still fail. Our gitleaks step mounted only the worktree, whose .git file points at <main>/.git/worktrees/<name>, outside the mount, so it stopped with "not a git repository".
  3. Commit from a local clone instead: git clone -q --no-checkout <main repo> <dir>. A local clone hardlinks the objects, so the container can read them. Do not use --shared, because its alternates point at host paths.
  4. In the clone, run checkout --detach <origin/branch SHA> and remote set-url origin <remote URL>, copy user.name and user.email, cp -R .husky/_, set core.hooksPath .husky/_, and symlink node_modules. Commit and push from there, and delete the clone once git ls-remote shows the SHA.
  5. Read the working tree after each commit. The clone's local main was 114 commits behind, so lint-staged's nx format:write reformatted 30 app files that were never staged. The commit held only the staged files; git show --name-only HEAD, git status and git restore --worktree -- . cleared the rest.
  6. Keep the guard rails while you fix it: never --no-verify, and do not quietly install a local gitleaks, since every future commit would move off the pinned Docker version.

Prompt to copy

I commit from a linked git worktree in a repo that uses husky. Check whether hooks really run here: read `git config core.hooksPath`, check that folder exists in this worktree, and list the hooks that would fire. Never use --no-verify or install a tool. If the runner is missing or a Docker hook cannot see the repo, set up a local clone with `git clone --no-checkout` (never --shared) at my branch SHA, copy the hooks folder and git identity, symlink node_modules, and show each command before running it. After the commit, show `git status` so I can restore files a formatter touched outside the commit.
Enter fullscreen mode Exit fullscreen mode

I am Omer Bin Saleem, a frontend chapter lead who builds with AI every day. One practical AI hack a day at omerbinsaleem.com. LinkedIn: omer-bin-saleem · Instagram: @iomerbinsaleem.

Written with AI assistance, from my own work notes.

Top comments (1)

Collapse
 
vikash_ruhil_a43b452d4a88 profile image
vikash ruhil •

Nice writeup. Two things that might let some people skip the clone step:

  • .husky/_ is just generated output, so running npx husky (or whatever your prepare script runs) inside the worktree recreates it there. Worth adding to whatever script creates your worktrees so a new one never starts hookless.
  • For the Docker fallback, the worktree's .git file holds an absolute path into <main>/.git/worktrees/<name>. If the container also mounts $(git rev-parse --git-common-dir) at the same absolute path, git inside the container can resolve it and gitleaks sees a normal repo.

And +1 on never reaching for --no-verify. A quick git config core.hooksPath plus an ls of that folder at the start of a worktree session is cheap insurance.