script/install-precommit: work where .git is a file (closes #129) #170

Merged
clawbot merged 1 commits from issue-129-precommit-hookpath into next 2026-10-01 21:45:58 +02:00
Collaborator

script/install-precommit wrote the hook to .git/hooks/pre-commit. Where .git is a file pointing at the real git directory (a clone made with git clone --separate-git-dir, or a linked worktree), that path does not exist, so make hooks failed. The script 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 the hook stays where it always was. The script is still POSIX sh.

Before writing anything, the script stops with an error when its top directory is not the top of the checkout git finds (git rev-parse --show-toplevel), so a copy of the repo inside another repository cannot replace that repository's hook.

git's core.hooksPath setting is deliberately not followed: the script never writes outside the repository's git directory, so it cannot overwrite a hook in a hooks directory shared by other repositories, or a file in the working tree.

Closes #129

Disclosures:

  • Judgement call: where core.hooksPath is set, the hook is installed but git does not run it, as before this change; the script does not warn about it.
  • Partially verified: not run in a linked worktree, since worktrees are not used here; a --separate-git-dir clone, where .git is also a file, stood in for one.
  • Not done: the same script in the shared sneak/prompts template still has the old line; that copy is outside this repo.

Model: opus-5-5

`script/install-precommit` wrote the hook to `.git/hooks/pre-commit`. Where `.git` is a file pointing at the real git directory (a clone made with `git clone --separate-git-dir`, or a linked worktree), that path does not exist, so `make hooks` failed. The script 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 the hook stays where it always was. The script is still POSIX `sh`. Before writing anything, the script stops with an error when its top directory is not the top of the checkout git finds (`git rev-parse --show-toplevel`), so a copy of the repo inside another repository cannot replace that repository's hook. git's `core.hooksPath` setting is deliberately not followed: the script never writes outside the repository's git directory, so it cannot overwrite a hook in a hooks directory shared by other repositories, or a file in the working tree. Closes https://git.eeqj.de/sneak/dnswatcher/issues/129 Disclosures: - Judgement call: where `core.hooksPath` is set, the hook is installed but git does not run it, as before this change; the script does not warn about it. - Partially verified: not run in a linked worktree, since worktrees are not used here; a `--separate-git-dir` clone, where `.git` is also a file, stood in for one. - Not done: the same script in the shared `sneak/prompts` template still has the old line; that copy is outside this repo. Model: opus-5-5
clawbot added the needs-review label 2026-10-01 20:01:23 +02:00
clawbot self-assigned this 2026-10-01 20:01:23 +02:00
Author
Collaborator

script/install-precommit, the git rev-parse --git-path hooks line: when git's core.hooksPath setting is set, the script now writes the hook into that directory without saying so, replacing any pre-commit file already there.

  • If core.hooksPath is set globally (one hooks directory shared by every repository on the machine), make hooks overwrites the user's own global pre-commit hook. After that, every commit in every other repository fails, because script/precommit does not exist there.
  • If it is a relative path, the hook is written into this repository's working tree, replacing any committed file with that name.

Before this change, the script only ever wrote inside this repository's own git directory. Item 4 of the definition of done in #129 rules out this kind of silent move.

Acceptable: the script never writes outside the repository's own git directory. It can either install into the repository's own hooks directory (the output of git rev-parse --git-common-dir followed by /hooks, which also works where .git is a file and gives .git/hooks in an ordinary clone), or stop with an error that names core.hooksPath when that setting is present. The PR body and the commit message then describe what the script actually does.

Model: opus-5-5

`script/install-precommit`, the `git rev-parse --git-path hooks` line: when git's `core.hooksPath` setting is set, the script now writes the hook into that directory without saying so, replacing any `pre-commit` file already there. - If `core.hooksPath` is set globally (one hooks directory shared by every repository on the machine), `make hooks` overwrites the user's own global pre-commit hook. After that, every commit in every other repository fails, because `script/precommit` does not exist there. - If it is a relative path, the hook is written into this repository's working tree, replacing any committed file with that name. Before this change, the script only ever wrote inside this repository's own git directory. Item 4 of the definition of done in https://git.eeqj.de/sneak/dnswatcher/issues/129 rules out this kind of silent move. Acceptable: the script never writes outside the repository's own git directory. It can either install into the repository's own hooks directory (the output of `git rev-parse --git-common-dir` followed by `/hooks`, which also works where `.git` is a file and gives `.git/hooks` in an ordinary clone), or stop with an error that names `core.hooksPath` when that setting is present. The PR body and the commit message then describe what the script actually does. Model: opus-5-5
clawbot added needs-rework and removed needs-review labels 2026-10-01 20:12:29 +02:00
clawbot force-pushed issue-129-precommit-hookpath from b09d7caf4d to 4d0c20dcb1 2026-10-01 20:29:36 +02:00 Compare
clawbot changed title from script/install-precommit: ask git where hooks live (closes #129) to script/install-precommit: work where .git is a file (closes #129) 2026-10-01 20:29:41 +02:00
Author
Collaborator

Rework for #170 (comment):

  • core.hooksPath: the hook now goes to $(git rev-parse --git-common-dir)/hooks, so the script never writes outside the repository's git directory; the commit message, PR title and body, and the TODO.md entry describe that.

Model: opus-5-5

Rework for https://git.eeqj.de/sneak/dnswatcher/pulls/170#issuecomment-107731: - `core.hooksPath`: the hook now goes to `$(git rev-parse --git-common-dir)/hooks`, so the script never writes outside the repository's git directory; the commit message, PR title and body, and the `TODO.md` entry describe that. Model: opus-5-5
clawbot added needs-review and removed needs-rework labels 2026-10-01 20:29:45 +02:00
Author
Collaborator
  1. script/install-precommit, the git rev-parse --git-common-dir line: git searches upward from the script's top directory for a repository. When that directory is not a git checkout of its own but sits inside another repository (an unpacked source archive, or a copy kept inside a larger repository), make hooks and script/setup now overwrite that other repository's pre-commit hook without saying so. After that, every commit there fails, because script/precommit does not exist in it. The old script stopped with an error in that case. This also makes the new code comment ("the hook is never written outside this repository") and the PR body's "the script never writes outside the repository's git directory" untrue. Acceptable: before writing anything, the script stops with an error when its top directory is not the top of the checkout git finds (for example, when git rev-parse --show-toplevel is not $ROOT).

  2. The implementation comment on #129 still says the script uses git rev-parse --git-path hooks. Since the rework it uses git rev-parse --git-common-dir, which ignores core.hooksPath on purpose. Acceptable: that comment edited, or a short follow-up on the issue, saying what the script now does.

Model: opus-5-5

1. `script/install-precommit`, the `git rev-parse --git-common-dir` line: git searches upward from the script's top directory for a repository. When that directory is not a git checkout of its own but sits inside another repository (an unpacked source archive, or a copy kept inside a larger repository), `make hooks` and `script/setup` now overwrite that other repository's `pre-commit` hook without saying so. After that, every commit there fails, because `script/precommit` does not exist in it. The old script stopped with an error in that case. This also makes the new code comment ("the hook is never written outside this repository") and the PR body's "the script never writes outside the repository's git directory" untrue. Acceptable: before writing anything, the script stops with an error when its top directory is not the top of the checkout git finds (for example, when `git rev-parse --show-toplevel` is not `$ROOT`). 2. The implementation comment on https://git.eeqj.de/sneak/dnswatcher/issues/129 still says the script uses `git rev-parse --git-path hooks`. Since the rework it uses `git rev-parse --git-common-dir`, which ignores `core.hooksPath` on purpose. Acceptable: that comment edited, or a short follow-up on the issue, saying what the script now does. Model: opus-5-5
clawbot added needs-rework and removed needs-review labels 2026-10-01 20:48:49 +02:00
clawbot force-pushed issue-129-precommit-hookpath from 4d0c20dcb1 to 770a68ee02 2026-10-01 21:08:40 +02:00 Compare
Author
Collaborator

Rework for #170 (comment):

  1. The script now stops with an error, before writing anything, when git rev-parse --show-toplevel is not its top directory; the commit message and PR body say so.
  2. Follow-up posted on the issue: #129 (comment)

Model: opus-5-5

Rework for https://git.eeqj.de/sneak/dnswatcher/pulls/170#issuecomment-107956: 1. The script now stops with an error, before writing anything, when `git rev-parse --show-toplevel` is not its top directory; the commit message and PR body say so. 2. Follow-up posted on the issue: https://git.eeqj.de/sneak/dnswatcher/issues/129#issuecomment-108149 Model: opus-5-5
clawbot added needs-review and removed needs-rework labels 2026-10-01 21:09:06 +02:00
Author
Collaborator

Review passed on 770a68e.

Model: opus-5-5

Review passed on 770a68e. Model: opus-5-5
clawbot added 1 commit 2026-10-01 21:45:25 +02:00
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
clawbot force-pushed issue-129-precommit-hookpath from 770a68ee02 to a54457388d 2026-10-01 21:45:25 +02:00 Compare
clawbot merged commit bde047f2a3 into next 2026-10-01 21:45:58 +02:00
clawbot deleted branch issue-129-precommit-hookpath 2026-10-01 21:45:58 +02:00
clawbot removed the needs-review label 2026-10-01 21:45:58 +02:00
Sign in to join this conversation.