shwldshwlda month ago

git hookスクリプトでstdinがブロックする問題をTTY判定で回避する

lefthookからシェルスクリプトを呼び出したとき、catread でstdinを読もうとするとスクリプトがハングする問題があった。Codex(OpenAI)に修正を任せたらサクッと直してくれた。

原因:

lefthookはスクリプトのstdinをパイプで接続する。ターミナルから直接実行した場合はstdinにユーザー入力が来るが、lefthook経由だとパイプの先に何もないので cat がEOFを待ち続けてブロックする。

解決:

# stdinがTTY(ターミナル)かパイプかを判定
if [ -t 0 ]; then
  # ターミナルから直接実行 → stdinを読める
  FILES=$(cat)
else
  # パイプ経由(lefthookなど) → stdinを読まずにfallback
  FILES=$(git diff --cached --name-only)
fi

調査の勘所:

  • [ -t 0 ] はファイルディスクリプタ0(stdin)がターミナルに接続されているかを判定するPOSIXの方法
  • git hookスクリプトはターミナル直接実行とhookマネージャ経由の両方で動くことを想定して、stdin以外のfallback(git diff --cached等)を用意しておくとよい
  • この手のシェルスクリプトの環境依存バグは、AIエージェントに任せると原因特定から修正まで速い