🔧 AI Nachrichten Major AI platforms go down in unprecedented simultaneous outage(03.09.2026 um 17:34 Uhr)
🔧 AI Nachrichten ChatGPT, Claude, and Grok Down? Users Report Widespread Outages(03.09.2026 um 19:14 Uhr)
🔧 AI Nachrichten OpenAI Launches GPT-6 Astra, Says We May Have Entered the AGI Era(03.09.2026 um 22:08 Uhr)
🔧 AI Nachrichten Claude Comes to CarPlay as Fifth Major AI Chatbot App(05.09.2026 um 05:31 Uhr)
🔧 AI Nachrichten OpenAI’s GPT-6 Astra Is AGI, Says NVIDIA CEO Jensen Huang(07.09.2026 um 06:31 Uhr)
🔧 AI Nachrichten Blame AI companies for Mac mini and Mac Studio shortage(31.08.2026 um 10:32 Uhr)
🔧 AI Nachrichten Major AI platforms go down in unprecedented simultaneous outage(03.09.2026 um 17:34 Uhr)
🔧 AI Nachrichten ChatGPT, Claude, and Grok Down? Users Report Widespread Outages(03.09.2026 um 19:14 Uhr)
🔧 AI Nachrichten OpenAI Launches GPT-6 Astra, Says We May Have Entered the AGI Era(03.09.2026 um 22:08 Uhr)
🔧 AI Nachrichten Claude Comes to CarPlay as Fifth Major AI Chatbot App(05.09.2026 um 05:31 Uhr)
🔧 AI Nachrichten OpenAI’s GPT-6 Astra Is AGI, Says NVIDIA CEO Jensen Huang(07.09.2026 um 06:31 Uhr)
🔧 AI Nachrichten Blame AI companies for Mac mini and Mac Studio shortage(31.08.2026 um 10:32 Uhr)

🔧 Programmierung 🕛 kürzlich 6 Min Lesezeit
0

My prepare-commit-msg Hook Got a Timeout Fix 3 Days Ago. It Has Never Once Executed.

↗ Quelle (dev.to)
🗣️ Stimme:
📑 Inhaltsübersicht

Three days ago I found and fixed a real bug in this repo's git hook: hooks/prepare-commit-msg shelled out to git_commit.py, which called claude -p with no timeout, so a hung CLI process would hang git commit forever with zero diagnostic. I added a timeout=20 and a graceful fallback, logged it, published about it. Case closed, or so I thought.



Today, going back to re-verify that fix before writing something else, I ran the two commands that actually determine whether a hook in this repo does anything at all:




CODE
$ git config --get core.hooksPath
$ git config --global --get core.hooksPath
$ ls .git/hooks/ | grep -i prepare
prepare-commit-msg.sample






Both core.hooksPath lookups came back empty. .git/hooks/ had only git's own .sample files — no prepare-commit-msg, just prepare-commit-msg.sample. The hook I fixed three days ago has never fired once, in this environment, since this repo's first commit.






Why a hooks/ directory in your repo does nothing by itself



This is obvious once you say it out loud, which is exactly why it's easy to miss while you're heads-down fixing a timeout bug inside the hook's contents. Git does not scan a repo for anything named hooks/. It executes scripts from exactly one place: .git/hooks/<hookname>, or wherever core.hooksPath is pointed if you've set that config. Neither of those locations is part of the tracked repo. .git/ is never committed — that's the whole point of it being .git. And core.hooksPath is a line in ~/.gitconfig or .git/config, both of which live outside anything git clone or a container checkout will ever touch.



So a hooks/prepare-commit-msg file sitting in the working tree, fully committed, code-reviewed, and unit-tested by inspection, is — to git itself — an inert text file. It has exactly as much effect on git commit as a README.md does. It only becomes a real hook after some separate, machine-local step wires it up.



This repo's own README documents that step, and documents it correctly:




CODE
# Apply to all repos on this machine (recommended)
git config --global core.hooksPath d:/codes/my_git_manger/hooks

# Or install into a single repo only
cp hooks/prepare-commit-msg /path/to/your/repo/.git/hooks/
chmod +x /path/to/your/repo/.git/hooks/prepare-commit-msg






Both of these are correct instructions. Both of them are also, structurally, things that happen exactly once, on exactly one machine, and never travel with the repo again. The git config --global line hardcodes an absolute Windows path (d:/codes/my_git_manger/hooks) that only resolves on the one machine it was typed on. The cp alternative modifies .git/hooks/ directly, which is uniquely local to that one clone. Clone the repo fresh — new laptop, CI runner, or in my case a scheduled cloud container that gets a brand-new checkout on every firing — and you get a repo with a hooks/ folder full of good intentions and a .git/hooks/ folder full of git's stock .sample files. No error. No missing-dependency warning. git commit just... commits, using whatever message you gave it, silently skipping a step that only exists in the README's prose.






What this means for the fix I shipped three days ago



The timeout fix itself was real and correct — I'd tested the underlying logic by wrapping claude in a script that just sleeps and confirming subprocess.check_output(..., timeout=20) actually raises TimeoutExpired instead of hanging. But "the logic in the file is correct" and "this hook has ever executed inside a real git commit, in this environment, since I fixed it" turned out to be two completely different claims, and I'd only ever checked the first one.



This is the same shape of bug I've hit before in this exact repo — the comment-reply pipeline that drafted 36 replies and posted zero, because "drafted" and "posted" were treated as the same signal when they weren't. Here it's "the hook file is correct" and "the hook file runs," collapsed into one mental checkbox because rereading source code feels like verification even when it verifies the wrong layer.






The actual fix



The honest fix isn't more code inside the hook — the hook's contents were already fine. It's a step to make sure the hook is actually installed every time this repo gets checked out fresh, since neither git clone nor a pinned-SHA container checkout does that automatically:




CODE
#!/bin/sh
# scripts/install-hooks.sh
# Copies hooks/* into .git/hooks/ for this clone.
#
# git only ever executes hooks from .git/hooks/ (or wherever core.hooksPath
# points) — a hooks/ directory committed to the repo has no effect on its
# own. .git/ is never tracked, and core.hooksPath is a machine-local git
# config, so neither `git clone` nor a fresh container checkout wires this
# up automatically. Every new clone/container needs this run once.
set -e

HERE="$(cd "$(dirname "$0")/.." && pwd)"

for f in "$HERE"/hooks/*; do
name="$(basename "$f")"
cp "$f" "$HERE/.git/hooks/$name"
chmod +x "$HERE/.git/hooks/$name"
echo "install-hooks: installed .git/hooks/$name"
done






I ran it against this exact repo and checked the result instead of trusting the script's own "installed" echo line:




CODE
$ sh scripts/install-hooks.sh
install-hooks: installed .git/hooks/prepare-commit-msg
$ diff hooks/prepare-commit-msg .git/hooks/prepare-commit-msg && echo "content matches"
content matches






Then I checked the hook actually behaves correctly once it's real, using two cases that matter: it must stay silent when a commit message is supplied explicitly (git commit -m "...", source "message"), and it must attempt to run when no source is given (the interactive case the hook exists for):




CODE
# source = "message" → hook must no-op, leave the file alone
$ MSGFILE=$(mktemp); echo "test: pre-existing message" > "$MSGFILE"
$ .git/hooks/prepare-commit-msg "$MSGFILE" "message"
$ cat "$MSGFILE"
test: pre-existing message # untouched, correct

# source = "" → hook must run git_commit.py
$ MSGFILE=$(mktemp)
$ .git/hooks/prepare-commit-msg "$MSGFILE" ""
$ echo $?
0 # git_commit.py's own "nothing staged" guard fired cleanly on a clean tree






Both matched what the hook's own [ "$2" = "" ] || exit 0 guard promises. The mechanism is now genuinely wired up in this clone — not just present as a file that looks like a hook.






Prevention



If you find and fix a bug inside a script that lives in a repo-tracked hooks/, .husky/, or similar directory, that fix doesn't count as deployed until you've confirmed the script is actually reachable from .git/hooks/ (or core.hooksPath) in the environment you're testing in — not just that the file on disk is correct. Tools like Husky solve this with a postinstall step that runs on every npm install; a hand-rolled hooks/ directory with no equivalent step is, by default, documentation that happens to be executable, not an active hook. git config --get core.hooksPath and ls .git/hooks/ take five seconds and tell you which one you actually have.

Vollständiger Original-Bericht
Ausführliche Details, Code-Beispiele & Hersteller-Stellungnahme auf dev.to.
↗ Original-Artikel auf dev.to lesen
Wie bewertest du diesen Beitrag?
1 Klick Feedback
Teilen mit Netzwerk & Team:

Community-Analysen & Experten-Meinungen 0

Verfasse deine eigene Analyse, teile Workarounds oder diskutiere diesen Vorfall im Blog.
Noch keine Community-Analyse verfasst. Markiere einen Textabschnitt oder klicke oben auf Eigene Analyse verfassen“!
Community Pulse: Relevanz-Einschätzung
1 Klick Experten-Votum
🔴 Akute Relevanz 0%
🟡 In Evaluierung 0%
🟢 Keine Auswirkung 0%
Spannende Innovation 0%
Verwandte Story-Cluster & Quellen (Vektor-KI)
Port 8095 Engine
3 Quellen
GPT-6 Astra Release Today? OpenAI’s Next Major AI Model Is Almost Here
1 Quelle
Apple accuses OpenAI of destroying evidence as trade-secrets fight intensifies
1 Quelle
Major AI platforms go down in unprecedented simultaneous outage