git hooks とは、commit や push などの決まった時点で git が自動で走らせる台本(プログラム)の仕組みです。
- pre-commit・pre-push がいつ呼ばれ、何を受け取り、どの終了コードで commit や push を止めるか
- husky と core.hooksPath の関係と、hook が「在るのに走っていない」を見分ける測り方
- 長い pre-push の間に SSH が切れて push が落ちた記録と、ServerAliveInterval で直した形、--no-verify を使った回の後始末
当社は、コードの変更を AIエージェント の席に書かせ、手元の hook と merge queue の CI の 2 段で門を掛けています。この頁は、その手元の門(git hooks)で実際に詰まった記録を、git と husky と OpenSSH の公式の文書の定義と並べたものです。なお、Claude Code の hooks は Claude Code の側で動く別の仕組みで、この頁の git hooks とは別物です。
git hooks の仕組み: 置き場所と、止まる条件
git の文書(githooks)では、hook は hooks のディレクトリに置くプログラムで、既定の置き場は $GIT_DIR/hooks、core.hooksPath の設定で変えられます。実行の権限(executable bit)が無い hook は無視されます。
| hook | 呼ぶ命令と時点(公式の文書) | 受け取る物(公式の文書) | 0 以外で終わると(公式の文書) | 飛ばす印 |
|---|---|---|---|---|
pre-commit | git commit。commit の文言を受け取る前、commit を作る前 | 引数なし | commit を作らずに止まる | git commit --no-verify(-n)。pre-commit と commit-msg を飛ばす |
pre-push | git push。push を止めるために使える | 引数 2 つ(宛先の remote の名前と場所)。標準入力に 1 行ずつ <local-ref> <local-object-name> <remote-ref> <remote-object-name> | 何も push せずに止まる | git push --no-verify。pre-push を丸ごと飛ばす |
出典: githooks・git-commit・git-push(git-scm.com、2026-11-05 に確認)。
githooks の文書は、pre-push が remote へ繋ぐ前か後かを書いていません。当社の記録では、git は hook の前に GitHub へ SSH で繋いでいました(社の実測 2026-10-15・後の節)。
husky で hook をリポジトリに入れる
husky の公式の文書では、husky は「速い、現代のネイティブな git hooks」の道具で、git の core.hooksPath を使います。入れ方は次の 2 手です(husky Get Started、2026-11-05 に確認)。
npm install --save-dev husky(pnpm・Yarn・Bun にも同じ手がある)npx husky init。.husky/にpre-commitの台本を作り、package.jsonのprepareの台本を書き換える
hook を一時的に止めるには、-n/--no-verify を持つ命令ではそれを使い、持たない命令では HUSKY=0 git … とします。GUI から git を撃つと version manager が初期化されず、PATH に Node が無くて command not found になることがあり、husky は各 hook の前に ~/.config/husky/init.sh を読むので、そこに初期化を書きます(husky How To、2026-11-05 に確認)。
hook が「在る」と「走る」は別。当社の測り方
hook の門で最初に疑うべきは、そもそも走っているかです。当社は 2 回、走っていないのに気付きませんでした(社の実測 2026-09-29・2026-09-20)。
- 当社の棚のリポジトリでは、2026-09-18 以降
core.hooksPathが配線されておらず、pre-commit が 1 本も走っていませんでした。設定を測ると、撃つ前は空([])、配線後は[scripts/git-hooks]です(社の実測 2026-09-29)。 - 別のリポジトリでは、説明の紙が「手元の pre-commit は撤去済み」と書きながら、同じ紙の 4 行が存在しない hook を前提にしていました。共有の clone には
core.hooksPath=.husky/_の残骸が在り、外しました。hook の実体は無く、挙動は変わりません(社の実測 2026-09-20)。
「効いているか」の測り方も一度間違えました。[ -x <hooksPath>/pre-push ] で測ると、husky のローダが在るだけで真になる偽陽性でした(社の実測 2026-09-18)。今は git hook run pre-push を撃ち、stderr に cannot find a hook named が出ないことで測ります。終了コードは hook が無くても 0 なので、rc では測りません(社の実測 2026-09-18)。
| 測り方 | hook が在って走る時 | hook が無い・配線されていない時 | 使えるか |
|---|---|---|---|
[ -x <hooksPath>/pre-push ] | 真 | husky のローダが在るだけで真(偽陽性) | 使えない(社の実測 2026-09-18) |
git hook run pre-push の rc | hook の結果 | 0 | 使えない(社の実測 2026-09-18) |
git hook run pre-push の stderr | cannot find a hook named が出ない | cannot find a hook named が出る | 使う(社の実測 2026-09-18) |
git config core.hooksPath | 配線先が出る | 空 | 配線の有無だけ分かる(社の実測 2026-09-29) |
出典: 社の実測 2026-09-18・2026-09-29。
pre-push の間に SSH が切れ、ゲートは PASS なのに push が exit 141 で落ちた
当社の pre-push は、手元でゲート(試験の束)を撃ちます。ゲートの順番待ちが長く、admin の unit 試験まで走る回で、ゲートは PASS なのに git push が exit 141(SIGPIPE)で終わり、remote に載っていませんでした。1 つの席で 3 回、同じ日に 3 つの席が踏みました(社の実測 2026-10-15)。
原因は、git が hook の前に GitHub へ SSH で繋いでおり、hook が走っている間は無通信なので、その接続が切られることでした。hook は git が繋いだ後に走るので、hook の中では直せません(社の実測 2026-10-15)。
直した所: ホームの .ssh/config の ServerAliveInterval
OpenSSH の ssh_config の文書では、ServerAliveInterval は server から何も受け取らない秒数がこれを超えたら、暗号化された経路で応答を求める message を送る間隔で、既定は 0(送らない)です。ServerAliveCountMax は応答が無いまま送ってよい数で、既定は 3、超えると ssh は切ります(OpenBSD ssh_config、2026-11-05 に確認)。
当社は機体のホームの .ssh/config に次を足しました(社の実測 2026-10-15)。
Host github.com
ServerAliveInterval 30
ServerAliveCountMax 120
16 分眠るだけの hook で比べました(社の実測 2026-10-15)。
| 条件 | 結果 |
|---|---|
| keepalive あり(上の設定) | remote に着地、rc=0 |
陽性対照 ServerAliveInterval=0 | Connection to github.com closed by remote host、rc=141 |
出典: 社の実測 2026-10-15。
Host github.com に絞ったので、他の Host の設定が変わらないことを ssh -G で確かめています(社の実測 2026-10-15)。
もう 1 つの逃げ道: HTTPS で push する
HTTPS の push は hook の後に繋ぎ直すので、長い回でも着地しました(社の実測 2026-10-15)。
git -c credential.helper= -c 'credential.helper=!gh auth git-credential' \
push https://github.com/<org>/<repo>.git HEAD:refs/heads/<枝>
どちらの道でも、ゲートの PASS や push の exit を着地の証拠にせず、git ls-remote で remote の枝の先を測ります(社の実測 2026-10-15)。PASS の文字は「手元の試験が通った」しか言っていません。
--no-verify を使った 2 回と、その後の決まり
--no-verify は hook を丸ごと飛ばす印です(git-push・git-commit)。当社は 2 回使い、1 回は筋が通り、1 回は後始末が要りました。
| 日 | 飛ばした hook | 飛ばした理由 | 確かめた事 | 結果 |
|---|---|---|---|---|
| 2026-09-22 | pre-push(タグの push) | 門で 42 分止まった。同じ作業木で他の席の push 2 本も同じ門を走らせ、機体の load が 148 | そのタグの commit が merge queue の CI で 23 success/3 skipped | git push --no-verify origin <tag> で出した(社の実測 2026-09-22) |
| 2026-10-23 | pre-commit(型検査) | 取り込みの merge の commit を git commit --no-verify で作った | 型の誤りは 0 | unit 試験が 10 本赤。数を直す commit を hook を通して作り、unit 1003 本緑、pre-push を通して push(社の実測 2026-10-23) |
出典: 社の実測 2026-09-22・2026-10-23。
2 回目の赤は、両方の枝が 1 本ずつ仕事を足し、試験の期待の数が片方の分だけだったためで、型では捕まりません(社の実測 2026-10-23)。pre-commit を飛ばしても型の誤りが 0 だったことは、取り込みが正しい証拠になりませんでした。
それ以後、当社は --no-verify を使いません。hook が遅い・落ちるなら、その理由を直します(社の実測 2026-10-23)。1 回目のタグについては、CI 済みの commit を手元で撃ち直すだけなので、タグの push では pre-push を撃たない形を恒久の候補にしています(社の実測 2026-09-22)。手元で取り消したい変更がある時の手は、姉妹頁の git add の取り消し にまとめています。
pre-push の lint が 0.0 秒で落ちたら、hook より先に機体を見る
機体の /opt/homebrew/bin が丸ごと消え、npx が引けず、pre-push の lint が 0.0 秒・exit 1 で落ちました(社の実測 2026-10-24)。hook の中身は何も悪くありません。
- lint が 0.0 秒で exit 1 になっている
command -v npxが空ls /opt/homebrew/binで中身を見る
この順で見ると、hook の台本を疑って時間を使わずに済みます(社の実測 2026-10-24)。
よくある質問
pre-commit と pre-push はどう使い分ける?
pre-commit は git commit が commit を作る前に、pre-push は git push が push する前に呼ばれ、どちらも 0 以外で終わると止めます(githooks)。当社は pre-commit に型検査、pre-push に lint や試験の束を置いています(社の実測 2026-10-23・2026-10-24)。
git push --no-verify を使ってもよい?
--no-verify は pre-push を丸ごと飛ばします(git-push)。当社は型の誤り 0 でも試験が 10 本赤になった回を踏み、以後は使わず、hook が遅い理由の方を直しています(社の実測 2026-10-23)。
pre-push の後に push が exit 141 で落ちるのはなぜ?
当社の場合は、git が hook の前に SSH で繋いだ接続が、長い hook の間の無通信で切られていました(社の実測 2026-10-15)。ホームの .ssh/config の Host github.com に ServerAliveInterval 30 と ServerAliveCountMax 120 を足すと着地しました(社の実測 2026-10-15)。
husky を入れたのに hook が走らないのはなぜ?
husky は core.hooksPath を使うので(husky の公式の頁)、その設定が空なら hook は走りません。当社は配線が外れたまま pre-commit が 1 本も走っていなかった回があり(社の実測 2026-09-29)、今は git hook run pre-push の stderr に cannot find a hook named が出ないことで確かめています(社の実測 2026-09-18)。
出典
- githooks Documentation https://git-scm.com/docs/githooks (2026-11-05 に確認)
- git-commit Documentation https://git-scm.com/docs/git-commit (2026-11-05 に確認)
- git-push Documentation https://git-scm.com/docs/git-push (2026-11-05 に確認)
- Husky https://typicode.github.io/husky/ ・Get Started https://typicode.github.io/husky/get-started.html ・How To https://typicode.github.io/husky/how-to.html (2026-11-05 に確認)
- OpenBSD manual ssh_config(5) https://man.openbsd.org/ssh_config (2026-11-05 に確認)
- 社の実測 2026-09-18・2026-09-20・2026-09-22・2026-09-29・2026-10-15・2026-10-23・2026-10-24
ブルーランプ 記事の編集部/更新日 2026-11-05