git bisect 500行のログを読まずに破損コミットを検出する
生産環境で問題が発生したコミットをgitログから検索するのをやめましょう。git bisectは、範囲内のコミット数に関わらず、約9ステップで履歴を二分検索します。以下に、完全なワークフロー、実際のセッションの注釈、および注意すべきポイントを示します。
50件のコミットを2週間でプッシュしました。どこかで何かが壊れました。3週間前まで通過していたテストが今、失敗しています。 git log --oneline 読むべきでない200行を表示します。
選択肢があります:差分を眺めて目が血を流るまで、 git checkout ランダムなコミットを手動で確認する、または2007年からgitに含まれており、すべてのインストールに付随するツールを使用します。
git bisect あなたのコミット履歴を二分検索します。1つのコミットを壊れたものとして、1つを正常なものとしてマークし、その間のコミットをチェックアウトして、検索範囲を半分に切り詰めます。500件のコミットで原因を特定するのは約9ステップです。ほとんどの開発者はこれを使いません。
仕組み
全体のワークフローは、以下の3コマンドで開始できます:
git bisect start
git bisect bad # current state is broken
git bisect good v2.4.0 # last known-good tag or commit hash
Gitは、その2つのポイントの間のコミットをチェックアウトします。バグがあるかどうかをテストし、結果を報告します:
git bisect good # bug is NOT present here
# or
git bisect bad # bug IS present here
Gitは範囲を切り詰め、次の中央点を選択します。繰り返し、それがあなたに言うまで続けます abc1234 is the first bad commit。終了時:
git bisect reset # returns you to your original branch
特別なフラグ、設定、プラグインは必要ありません。すべてのリポジトリ、おそらくインストールされているgitバージョンで動作します。
実際のバイセクトセッション(注釈付き)
ここに完全なセッションがあります。関数が正しいJSONを返すようになったが、最近のリファクタリング後にnullを返すようになった——最近のコミットに明らかな原因がありませんでした:
$ git bisect start
$ git bisect bad HEAD # current commit is broken
$ git bisect good 3f8a12b # commit from 2 weeks ago, worked fine
Bisecting: 24 revisions left to test after this (roughly 5 steps)
[c9e41f0] Refactor: extract auth middleware
$ npm test -- --grep "parseResponse" # ← run your check here
# FAIL
$ git bisect bad
Bisecting: 12 revisions left to test after this (roughly 4 steps)
[a77b2d1] Fix: update retry logic in fetch wrapper
$ npm test -- --grep "parseResponse"
# PASS
$ git bisect good
Bisecting: 6 revisions left to test after this (roughly 3 steps)
[91e0bc3] Refactor: consolidate response handlers
$ npm test -- --grep "parseResponse"
# FAIL
$ git bisect bad
Bisecting: 2 revisions left to test after this (roughly 2 steps)
[b44c19f] Chore: remove deprecated serialization helpers
$ npm test -- --grep "parseResponse"
# FAIL
$ git bisect bad
Bisecting: 1 revision left to test after this (roughly 1 step)
[8d3e77a] Fix: normalize response envelope for new API version
$ npm test -- --grep "parseResponse"
# PASS
$ git bisect good
91e0bc3e1f4d is the first bad commit
commit 91e0bc3e1f4d
Author: Dev <dev@example.com>
Date: Mon Apr 14 11:23:07 2026
Refactor: consolidate response handlers
src/http/response.js | 14 +++---
$ git bisect reset # ← always do this when done
50件のコミット範囲を5ステップで。『レスポンスハンドラーを統合』というコミットが、何かが依存しているシリアル化呼び出しを静かに削除しました。バイセクトを使わなければ、あなたは差分を1時間読み続けたでしょう。
自動化
チェックをスクリプトとして表現できる場合——成功時には0、失敗時には非0を返す——git bisectは完全に手動で動作します:
git bisect start
git bisect bad HEAD
git bisect good v2.4.0
git bisect run npm test -- --grep "parseResponse"
Gitは各中央点をチェックアウトし、スクリプトを実行し、最初の不良コミットを報告します。テストが10秒以内に実行できる場合、このプロセスはあなたが離れて戻って答えを知るまでに十分に速いです。
実行スクリプトの終了コードの意味:
- 0 — コミットは正常
- 1–124 — コミットは不良
- 125 — そのコミットをスキップ(ビルドが壊れている、テストできない)
プレビューするには 125 そのコミットがコンパイルできないか、テストインフラが壊れている場合、bisectはそれをスキップし、次の候補に進みます。
バイセクトがgit blameを上回るとき
git blame 行の最後に触れた人の情報を示します。特定の行が間違っていることが分かっている場合に役立ちます。 git bisect 原因がどこにあるか分からない場合、症状が行動的な場合に役立ちます。
bisectを使うべきとき:
- 再現可能なリグレッションがあるが、特定のファイルにたどり着けない場合
- プロダクションの動作が変わったが、最近の履歴に明らかな原因がない場合
- 「v2.3では動いていたが、v2.5では壊れた」で、その間に80件以上のコミットがある場合
- テストが特定の日付の周りから一貫して失敗した場合
バイセクト中に2つのコミットの出力の比較を行うとき、その両方を テキスト差分ツールに貼り付けることが、ターミナルでの統一差分を読むよりも速い——特に出力がJSONやシリアル化されたオブジェクトの塊の場合。 はたらくことが、速い——特に出力がJSONやシリアル化されたオブジェクトの塊の場合。
コモン・ゴッチャス
忘れないでください git bisect reset. バイセクトは、デタッチされたHEAD状態でコミットをチェックアウトします。セッション中にブランチを切り替えてもリセットしないと、バイセクトの状態が古くなり、混乱します。答えを見つけた後でも、常にリセットしてください。
マージコミットは範囲を歪めます。 範囲に長期間存在していた機能ブランチがマージされた場合、バイセクトはそのブランチのコミットの順番を非自明な順番に配置する可能性があります。まず git log --oneline --no-merges good..bad を実行して範囲に何があるかを理解してください。
テストの再現性がすべてです。 チェックが不安定——タイミングに敏感、環境に依存、または外部サービスにアクセスする場合——バイセクトは無効な結果を提供します。自動化する前に、テストが決定論的であることを確認してください。
バイセクトが特定するコミットは、動作が変わった場所であり、必ずしもバグが存在する場所ではありません。 時々、正しいリファクタリングが既存の仮定を暴露した場合があります。結果を「ここから読み始め」として扱い、『このコミットをリバースすれば終わり』としないでください。
定期的にgitの履歴をデバッグする場合、 Git チートシート IO Toolsでは、bisect、blame、logフラグ、reflogがすべて1ページにまとまっています——次回何か謎が起こったときにブックマークしておく価値があります。
