git bisect でバグがどのコミットで入ったか特定できた話、知らなかったら損してた

いつのまにか混入していたバグをgit bisectで追跡したら、数十のコミットを手動で確認する手間がなくなりました。コマンドの使い方と実際の体験をまとめます。

🙌 結論から

「いつの間にかバグが混入していて、どのコミットで入ったかわからない」という状況で git bisect を使ったら、数十のコミットを手動で追う必要がなく、原因のコミットをかなり速く特定できました!

二分探索で絞り込んでいくので、100コミットあっても 7〜8回の確認で特定できます(^o^)

これを知らないままコミット履歴を git log で地道にさかのぼっていたのは、相当な時間を無駄にしていたかもしれません(´;ω;`)

💡 git bisect とはなにか

git bisect は、バグが混入したコミットを二分探索で特定するための git コマンドです。

「このコミットはバグがある(bad)」「このコミットは正常(good)」と指定すると、git が間のコミットを順番に指定してくれます。

「bad か good か」を答え続けるだけで、自動的に対象のコミットまで絞り込んでくれるのが特徴です。

コミットが 50個あっても、確認するのは理論上 6回程度で済みます。手動でコミットをさかのぼるより圧倒的に速く特定できます。

👀 実際に使ってみた

先日、フォームのバリデーションが突然動かなくなるバグが発生しました。

直近2週間でいくつかのPRがマージされており、どのコミットで壊れたか追跡が必要な状況でした。

こんな流れで bisect を使いました。

# 二分探索を開始
git bisect start

# 今のコード(バグあり)
git bisect bad

# 正常だったとわかっている古いコミットのハッシュ
git bisect good a1b2c3d

# あとは git が checkout してくれる
# 各コミットで動作確認して、good か bad を答えるだけ
git bisect good   # 正常
git bisect bad    # バグあり

# 特定が完了したら
git bisect reset

10コミットをさかのぼる必要があると思っていましたが、実際に確認したのは 4回だけで済みました!

最終的に「バリデーション用のユーティリティ関数を整理したPR」のコミットが原因でした。意図せずエクスポートの形式が変わっていたようで、それを見落としていたことが原因でした(・_・;)

✨ 使ってみた感想

「git にこんな機能があったのか」と正直驚きました。

バグ調査でコミット履歴をさかのぼる作業って、時間も集中力もかなり消耗するんですよね。git bisect はその作業量をかなり減らしてくれます!

一点だけ注意が必要なのは、ビルドやテストが必要なプロジェクトでは、各コミットのチェックアウト後に毎回ビルドし直す必要があることです。

ただし git bisect run を使えば、確認スクリプトを自動化できます。

git bisect run npm test

テストが通れば good、落ちれば bad として自動判定してくれるので、完全に自動で特定まで持っていけます(。•̀ᴗ-)✧

テストが整備されているプロジェクトなら、コマンドを打った後はほぼ放置で結果が出てきます。

⏭ bisect skipで確認できないコミットを飛ばす

git bisect run で自動化していたら、途中でビルド自体が壊れているコミットに当たって処理が止まってしまったことがありました(・_・;)

そのコミットだけ依存パッケージのバージョンが壊れていて、良し悪しを判定する以前にテストが実行できない状態だったんです。

こういうときのために git bisect skip というコマンドがあります。

# 今のコミットは確認できないのでスキップする
git bisect skip

# 複数まとめてスキップすることもできる
git bisect skip abc1234 def5678

git bisect run の中で使うスクリプトなら、終了コード125を返すと「このコミットはスキップ」という意味になり、bisectが自動で隣のコミットに移動してくれます。

#!/bin/bash
npm install || exit 125  # インストールに失敗したらスキップ扱い
npm test

私はこのスクリプトを check.sh として保存して、git bisect run ./check.sh のように使うようにしました。

一点だけ注意が必要なのは、探しているバグのコミットのすぐ隣をスキップすると、正確な特定ができなくなることです。

そのケースでは Git が「このあたりのどれかです」という形で複数のコミットを提示してくれるので、最終的には目視で絞り込む必要があります。

とはいえ、自動化の途中で処理が完全に止まってしまうよりは、多少精度が落ちてもスキップして先に進めた方が実用的だと感じました!

パパ系Webエンジニア〜愛用ガジェット一覧 🛍️

この記事を書いている作業環境のガジェットを楽天ROOMにまとめています ✨ 在宅エンジニアのデスク作りの参考にどうぞ 🙌

👍 まとめ

git bisect は、いつ混入したかわからないバグを二分探索で素早く特定できるコマンドです。

「最近バグが出たけど、どのコミットか追えない」というシーンに、かなり刺さります!

git bisect run でテスト実行を自動化すれば、コマンドを打った後は待つだけで特定が完了します。

次にバグ原因を追跡するときは、まず git bisect を試してみてください(^_^)

※ gitのバージョンによってオプションの挙動が異なる場合があります。最新情報は Git公式ドキュメント をご確認ください👀