diff --git a/scripts/install-hooks.sh b/scripts/install-hooks.sh index dd2a768..4aad880 100755 --- a/scripts/install-hooks.sh +++ b/scripts/install-hooks.sh @@ -5,10 +5,13 @@ # (and so their hooks) run outside the sandbox. Re-run after changing anything in .githooks/. set -e cd "$(dirname "$0")/.." -if ! hooks=$(git rev-parse --git-path hooks 2>/dev/null); then +# Use the repo's own hooks directory, not `git rev-parse --git-path hooks`: that follows a +# (possibly global) core.hooksPath and would install these hooks for every repo. +if ! common=$(git rev-parse --git-common-dir 2>/dev/null); then echo "install-hooks: not a git checkout; skipping." >&2 exit 0 fi +hooks="$common/hooks" mkdir -p "$hooks" for hook in .githooks/*; do cp "$hook" "$hooks/" diff --git a/test/hooks.test.js b/test/hooks.test.js index f9feea9..e49d8b3 100644 --- a/test/hooks.test.js +++ b/test/hooks.test.js @@ -1,7 +1,7 @@ import { test, after } from "node:test"; import assert from "node:assert/strict"; import { spawnSync } from "node:child_process"; -import { mkdtempSync, rmSync, cpSync, statSync } from "node:fs"; +import { mkdtempSync, rmSync, cpSync, statSync, writeFileSync, existsSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { fileURLToPath } from "node:url"; @@ -74,6 +74,20 @@ test("install-hooks copies every hook into .git/hooks as an executable", () => { } }); +test("install-hooks ignores a global core.hooksPath", () => { + const repo = repoOn("fix/x"); + const elsewhere = mkdtempSync(join(tmpdir(), "todo-hooks-")); + dirs.push(elsewhere); + const globalConfig = join(elsewhere, "gitconfig"); + writeFileSync(globalConfig, `[core]\n\thooksPath = ${elsewhere}\n`); + cpSync(join(ROOT, "scripts"), join(repo, "scripts"), { recursive: true }); + cpSync(HOOKS, join(repo, ".githooks"), { recursive: true }); + const res = run("sh", [join(repo, "scripts", "install-hooks.sh")], { env: { ...env, GIT_CONFIG_GLOBAL: globalConfig } }); + assert.equal(res.status, 0, res.stderr); + assert.ok(existsSync(join(repo, ".git", "hooks", "pre-push"))); + assert.equal(existsSync(join(elsewhere, "pre-push")), false); +}); + test("install-hooks skips cleanly outside a git checkout", () => { const dir = mkdtempSync(join(tmpdir(), "todo-hooks-")); dirs.push(dir);