From a54457388db4d0e4de9ef932db8c23c997a297fd Mon Sep 17 00:00:00 2001 From: sneak Date: Thu, 1 Oct 2026 17:57:36 +0000 Subject: [PATCH] script/install-precommit: work where .git is a file (closes #129) The script wrote the hook to .git/hooks, which fails when .git is a file rather than a directory, as in a clone made with --separate-git-dir. It now asks git for the repository's own git directory with `git rev-parse --git-common-dir`, creates its hooks directory if missing, and writes the hook there. In an ordinary clone that is .git/hooks, so nothing moves. Before writing anything it stops with an error when its top directory is not the top of the checkout git finds, so a copy inside another repository cannot replace that repository's hook. git's core.hooksPath setting is not followed; where it is in force, git does not run the installed hook, as before. Model: opus-5-5 --- TODO.md | 4 ++-- script/install-precommit | 15 ++++++++++++++- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/TODO.md b/TODO.md index 8af2f80..614432b 100644 --- a/TODO.md +++ b/TODO.md @@ -20,6 +20,8 @@ https://git.eeqj.de/sneak/dnswatcher/issues/104 # Completed Steps +- 2026-10-01: `script/install-precommit` asks git for the repository's git + directory, so `make hooks` also works where `.git` is a file (closes #129). - 2026-10-01: `TODO.md` brought up to date: open issues listed by URL, every Completed Steps entry cut to at most two lines (closes #146). - 2026-10-01: wildcard CORS now applies only to the public routes, not to @@ -106,7 +108,5 @@ https://git.eeqj.de/sneak/dnswatcher/issues/104 - README accuracy sweep: https://git.eeqj.de/sneak/dnswatcher/issues/108 - README sections required by policy: https://git.eeqj.de/sneak/dnswatcher/issues/173 -- `script/install-precommit` in a linked worktree: - https://git.eeqj.de/sneak/dnswatcher/issues/129 - fixed root server order: https://git.eeqj.de/sneak/dnswatcher/issues/138 - review toward 1.0: https://git.eeqj.de/sneak/dnswatcher/issues/144 diff --git a/script/install-precommit b/script/install-precommit index 723bae1..c005c5e 100755 --- a/script/install-precommit +++ b/script/install-precommit @@ -7,7 +7,20 @@ ROOT="$(cd "$(dirname "$0")/.." && pwd -P)" main() { cd "$ROOT" - hook=".git/hooks/pre-commit" + # Stop if this directory is not the top of its own git checkout, for + # example a copy inside another repository, whose hook must not be + # replaced. + if [ "$(git rev-parse --show-toplevel)" != "$ROOT" ]; then + echo "install-precommit: $ROOT is not the top of a git checkout" >&2 + exit 1 + fi + # Ask git for the repository's own git directory: .git is a file, not + # a directory, in some checkouts (for example a clone made with + # --separate-git-dir). core.hooksPath is deliberately not followed, so + # the hook is never written outside this repository. + hooks="$(git rev-parse --git-common-dir)/hooks" + mkdir -p "$hooks" + hook="$hooks/pre-commit" printf '#!/bin/sh\nset -e\nscript/precommit\n' > "$hook" chmod +x "$hook" echo "pre-commit hook installed: runs script/precommit"