I have done the following
Steps to reproduce
- Clone the repo and run
make pre-commit in the main checkout.
- Add a worktree:
git worktree add /tmp/wt-test.
- From
/tmp/wt-test, attempt to make any commit (e.g. git commit --allow-empty -m "test").
Expected: the pre-commit hook runs make check from the worktree.
Actual: the commit fails with bash: ...: Not a directory from the hook wrapper, because the wrapper tries to exec pre-commit.fmt at a path that does not exist inside a worktree.
Problem description
The generated hook line at Makefile:325 is:
PRECOMMIT_NOFMT=${PRECOMMIT_NOFMT} $(git rev-parse --show-toplevel)/.git/hooks/pre-commit.fmt
In a worktree:
git rev-parse --show-toplevel resolves to the worktree's checkout path (e.g. /tmp/wt-test).
.git inside a worktree is a file containing gitdir: ... (not a directory), so <worktree>/.git/hooks/pre-commit.fmt is invalid.
- Bash errors with "Not a directory."
The actual pre-commit.fmt lives in the main repo's .git/hooks/, but the wrapper's path computation never finds it.
The same assumption breaks the pre-commit: target itself (Makefile:322-327) — cp scripts/pre-commit.fmt .git/hooks won't work from inside a worktree either, because .git is a file there.
Proposed fix: use git rev-parse --git-path hooks to resolve the shared hooks directory; it works correctly in both the main repo and any worktree.
.PHONY: pre-commit
pre-commit:
$(eval HOOKS_DIR := $(shell git rev-parse --git-path hooks))
cp scripts/pre-commit.fmt $(HOOKS_DIR)/
touch $(HOOKS_DIR)/pre-commit
cat $(HOOKS_DIR)/pre-commit | grep -v 'hooks/pre-commit\.fmt' > /tmp/pre-commit.new || true
echo 'PRECOMMIT_NOFMT=$${PRECOMMIT_NOFMT} $$(git rev-parse --git-path hooks/pre-commit.fmt)' >> /tmp/pre-commit.new
mv /tmp/pre-commit.new $(HOOKS_DIR)/pre-commit
chmod +x $(HOOKS_DIR)/pre-commit
Verified inside /tmp/wt-test: git rev-parse --git-path hooks/pre-commit.fmt correctly returns the existing file path in the main repo's .git/hooks/.
Happy to send a PR for this.
Environment
- OS: macOS 26.4 (Darwin 25.4.0)
- Xcode: Command Line Tools (Swift 6.2.4)
- Container: 89fa98c (main, debug build)
Code of Conduct
I have done the following
Steps to reproduce
make pre-commitin the main checkout.git worktree add /tmp/wt-test./tmp/wt-test, attempt to make any commit (e.g.git commit --allow-empty -m "test").Expected: the pre-commit hook runs
make checkfrom the worktree.Actual: the commit fails with
bash: ...: Not a directoryfrom the hook wrapper, because the wrapper tries to execpre-commit.fmtat a path that does not exist inside a worktree.Problem description
The generated hook line at
Makefile:325is:In a worktree:
git rev-parse --show-toplevelresolves to the worktree's checkout path (e.g./tmp/wt-test)..gitinside a worktree is a file containinggitdir: ...(not a directory), so<worktree>/.git/hooks/pre-commit.fmtis invalid.The actual
pre-commit.fmtlives in the main repo's.git/hooks/, but the wrapper's path computation never finds it.The same assumption breaks the
pre-commit:target itself (Makefile:322-327) —cp scripts/pre-commit.fmt .git/hookswon't work from inside a worktree either, because.gitis a file there.Proposed fix: use
git rev-parse --git-path hooksto resolve the shared hooks directory; it works correctly in both the main repo and any worktree.Verified inside
/tmp/wt-test:git rev-parse --git-path hooks/pre-commit.fmtcorrectly returns the existing file path in the main repo's.git/hooks/.Happy to send a PR for this.
Environment
Code of Conduct