git bisect:「どのコミットで壊れたか」を一本のコマンドにする

退行調査の難所は二分探索ではなく「壊れている」の定義です。自動で判定するスクリプトを先に書けば、bisect は n 回のビルドを log n 回に縮めます。

git bisect の本当の壁は探索ではありません。「壊れているかどうか」を自分で答えられる判定を用意することが壁です。それが無ければ、人が毎回アプリを起動して good と bad を打ち込むことになり、ほとんど楽になりません。

まず判定スクリプトを書く

「壊れている」をコマンドの終了コードで定義します。0 が good、それ以外が bad です。

#!/usr/bin/env bash
# scripts/bisect-repro.sh
set -euo pipefail
npm run build
node scripts/check-the-thing.mjs

このスクリプトが bad で失敗し good で成功する限り、bisect は無人で走ります。

git bisect start
git bisect bad HEAD
git bisect good v1.4.0
git bisect run ./scripts/bisect-repro.sh

git bisect run は候補を checkout し、スクリプトを実行し、終了コードで印を付け、最初の bad を出力します。

good は本当に good でなければならない

一番よくある事故は起点が近すぎることです。直前のリリースを good にしたのに、その時点で既にバグがあった場合、区間そのものが誤りで、最後には無関係なコミットに行き着きます。

確認は地味ですが効きます。候補の good で判定スクリプトを一度走らせるのです。失敗するなら、さらに遡ります。

終了コード 125

125 は「このコミットは判定できない」の意味で、bisect はそれを飛ばします。ビルドが通らない中間コミットで効きます。

if ! npm run build > /dev/null 2>&1; then
  exit 125   # ここはビルドできないので飛ばす
fi

これが無いと、途中の一度のビルド失敗で探索全体が無効になります。

覚えるのではなく記録する

git bisect log > /tmp/bisect.log    # 途中で保存
git bisect replay /tmp/bisect.log   # あとで再現

調査が終わったら最初に git bisect reset を実行してください。でなければ detached HEAD のまま作業を続けることになります。ログは残し、修正後に issue へ貼れば、次に同じ問題に当たった人は最初からやり直さずに済みます。

bisect が節約するのは探索の手数ではありません。判定を書くことで、バグの境界を考えさせられることです。

← 記事一覧に戻る

コメント

…