はじめに

「昨日まで動いていたのに、今日突然バグが発生した」「どのコミットでバグが混入したのかわからない」。このような状況は、チーム開発において頻繁に発生します。コミット履歴が数百件ある場合、1件ずつ確認するのは現実的ではありません。

git bisectは、二分探索(バイナリサーチ)アルゴリズムを使って、バグを引き起こしたコミットを効率的に特定するコマンドです。たとえば1000件のコミットがあっても、約10回のテストでバグの原因コミットを見つけられます。

本記事では、git bisectの仕組みから基本操作、自動テストとの連携まで実践的に解説します。この記事を読み終えると、以下のことができるようになります。

  • git bisectの二分探索アルゴリズムを理解できる
  • git bisect startgit bisect goodgit bisect badgit bisect resetを使いこなせる
  • git bisect runで自動テストと連携してバグを自動特定できる
  • テスト不可能なコミットをgit bisect skipでスキップできる

実行環境と前提条件

本記事の内容は、以下の環境で動作確認を行っています。

項目 要件
Git 2.40以上
OS Windows 10/11、macOS 12以上、Ubuntu 22.04以上
ターミナル コマンドプロンプト、PowerShell、Terminal.app、bash等
エディタ VS Code推奨

前提条件として、以下の知識があることを想定しています。

  • コマンドライン操作の基礎知識(cdls/dirmkdir等)
  • テキストエディタの基本操作
  • Gitの基本コマンド(git loggit checkoutgit switch)の理解

git bisectの仕組み:二分探索アルゴリズム

git bisectは、二分探索(バイナリサーチ)アルゴリズムを使ってバグの原因コミットを特定します。この手法により、コミット数に対して対数的な回数(O(log n))でバグを発見できます。

二分探索の基本原理

二分探索は、ソートされたデータの中から目的の値を効率的に見つけるアルゴリズムです。git bisectでは、コミット履歴を「正常(good)」と「異常(bad)」の2つの状態に分け、その境界を見つけます。

1
2
3
4
5
6
過去 ─────────────────────────────────────────────► 現在
  │                                                    │
  ▼                                                    ▼
[good] ─ [good] ─ [good] ─ [???] ─ [bad] ─ [bad] ─ [bad]
                              └─ バグが混入したコミット

bisectの探索ステップ数

git bisectが必要とするステップ数は、コミット数nに対して約log₂(n)回です。

コミット数 最大ステップ数
10件 約4回
100件 約7回
1,000件 約10回
10,000件 約14回

たとえば1000件のコミットがあっても、最大10回程度のテストでバグの原因コミットを特定できます。

git bisectの基本操作:start/good/bad/reset

git bisectを使ったバグ特定の基本的な流れを解説します。

bisect startでセッションを開始する

まず、git bisect startでbisectセッションを開始します。

1
2
# bisectセッションを開始
git bisect start

開始時に「bad」(バグがあるコミット)と「good」(バグがないコミット)を同時に指定することもできます。

1
2
# HEADをbad、v1.0タグをgoodとして開始
git bisect start HEAD v1.0

bisect badで異常なコミットをマークする

現在のコミット(通常はHEAD)にバグがあることをgit bisect badで伝えます。

1
2
3
4
5
# 現在のコミットをbadとしてマーク
git bisect bad

# 特定のコミットをbadとしてマーク
git bisect bad a1b2c3d

bisect goodで正常なコミットをマークする

バグが存在しない(正常に動作する)コミットをgit bisect goodで伝えます。

1
2
3
4
5
# 特定のタグやコミットをgoodとしてマーク
git bisect good v1.0

# コミットハッシュでマーク
git bisect good e4f5g6h

goodとbadの両方をマークすると、Gitは自動的に中間のコミットをチェックアウトします。

1
2
3
$ git bisect good v1.0
Bisecting: 50 revisions left to test after this (roughly 6 steps)
[abc123def456...] Fix: update configuration

テスト結果に応じてgood/badをマークする

チェックアウトされたコミットでテストを実行し、結果に応じてマークします。

1
2
3
4
5
# バグが再現する場合
git bisect bad

# バグが再現しない場合
git bisect good

この操作を繰り返すと、最終的にバグを導入したコミットが特定されます。

1
2
3
4
5
6
7
8
9
$ git bisect bad
abc123def456789 is the first bad commit
commit abc123def456789
Author: developer <dev@example.com>
Date:   Mon Jan 1 10:00:00 2026 +0900

    Add new feature

:100644 100644 1234567... 89abcde... M      src/main.js

bisect resetでセッションを終了する

バグの原因コミットを特定したら、git bisect resetでセッションを終了し、元のブランチに戻ります。

1
2
3
4
5
6
7
8
# bisectセッションを終了し、元のHEADに戻る
git bisect reset

# 特定のコミットに移動して終了
git bisect reset HEAD

# 見つかったbadコミットに移動して終了
git bisect reset bisect/bad

実践例:手動でバグの原因コミットを特定する

実際のバグ特定の流れを、具体的な例で解説します。

シナリオ:計算結果が正しくなくなった

ある計算機能が、最近のコミットで正しく動作しなくなったとします。1週間前のv1.2.0タグでは正常に動作していたことがわかっています。

ステップ1:bisectセッションを開始する

1
2
$ git bisect start
status: waiting for both good and bad commits

ステップ2:bad/goodコミットをマークする

1
2
3
4
5
6
7
8
# 現在のHEADはバグがある(bad)
$ git bisect bad
status: waiting for good commit(s), bad commit known

# v1.2.0では正常(good)
$ git bisect good v1.2.0
Bisecting: 25 revisions left to test after this (roughly 5 steps)
[def456abc789...] Refactor: extract utility functions

Gitは自動的に中間のコミット(def456abc789...)をチェックアウトします。

ステップ3:テストを実行して結果をマークする

チェックアウトされたコミットでテストを実行します。

1
2
3
4
5
6
7
8
9
# テストを実行(プロジェクトに応じたテストコマンド)
$ npm test
# または
$ python -m pytest tests/test_calculator.py

# テストが失敗した(バグがある)場合
$ git bisect bad
Bisecting: 12 revisions left to test after this (roughly 4 steps)
[789abc123def...] Update: improve error handling
1
2
3
4
# テストが成功した(バグがない)場合
$ git bisect good
Bisecting: 6 revisions left to test after this (roughly 3 steps)
[456def789abc...] Feature: add validation

ステップ4:原因コミットの特定

good/badのマークを繰り返すと、最終的にバグを導入したコミットが表示されます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
$ git bisect bad
abc789def123456 is the first bad commit
commit abc789def123456
Author: developer <dev@example.com>
Date:   Fri Dec 27 15:30:00 2025 +0900

    Fix: update calculation formula
    
    Changed the calculation method to improve performance.

:100644 100644 111222... 333444... M      src/calculator.js

ステップ5:原因を調査して修正する

特定されたコミットの変更内容を確認します。

1
2
3
4
5
# コミットの詳細を確認
$ git show abc789def123456

# 変更されたファイルの差分を確認
$ git diff abc789def123456^..abc789def123456

ステップ6:セッションを終了する

1
2
3
$ git bisect reset
Previous HEAD position was 456def789abc...
Switched to branch 'main'

git bisect runで自動テストと連携する

手動でのテストは時間がかかります。git bisect runを使えば、テストスクリプトを自動実行してバグを特定できます。

bisect runの基本構文

1
git bisect run <テストスクリプト> [引数...]

テストスクリプトは以下の終了コードを返す必要があります。

終了コード 意味
0 テスト成功(good)
1-124, 126, 127 テスト失敗(bad)
125 テスト不可(skip)

例1:makeでビルドテストを自動化する

ビルドが壊れたコミットを自動で特定します。

1
2
3
4
5
6
7
8
# bisectを開始
git bisect start HEAD v1.0 --

# makeコマンドでビルドテスト
git bisect run make

# セッション終了
git bisect reset

例2:テストスイートを自動実行する

特定のテストケースが失敗するコミットを特定します。

1
2
3
4
5
6
7
8
# bisectを開始
git bisect start HEAD origin/main --

# テストコマンドを実行
git bisect run npm test

# セッション終了
git bisect reset

例3:カスタムテストスクリプトを使用する

複雑な条件でテストする場合は、シェルスクリプトを作成します。

1
2
3
4
5
6
7
8
#!/bin/bash
# test_bug.sh

# ビルドが失敗したらスキップ(終了コード125)
make || exit 125

# テストを実行
./run_specific_test.sh

スクリプトに実行権限を付与して使用します。

1
2
3
4
chmod +x test_bug.sh
git bisect start HEAD v1.0 --
git bisect run ./test_bug.sh
git bisect reset

例4:ワンライナーでテストを実行する

簡単なテストならワンライナーで記述できます。

1
2
3
git bisect start HEAD HEAD~20 --
git bisect run sh -c 'make || exit 125; ./test_case.sh'
git bisect reset

git bisect skipでテスト不可能なコミットを処理する

ビルドが壊れているコミットや、テストに必要なファイルが欠けているコミットがある場合、git bisect skipでスキップできます。

skipの基本的な使い方

1
2
3
4
5
6
7
8
# 現在のコミットをスキップ
git bisect skip

# 特定のコミットをスキップ
git bisect skip abc123def

# 範囲をスキップ
git bisect skip v1.1..v1.2

skipを使う場面

状況 対処法
ビルドが失敗する git bisect skip
テスト環境が整わない git bisect skip
不完全なコミット git bisect skip

注意点:skipの制限

スキップしたコミットが原因コミットの隣接している場合、Gitは正確なコミットを特定できません。

1
2
3
4
5
6
$ git bisect skip
There are only 'skip'ped commits left to test.
The first bad commit could be any of:
 abc123...
 def456...
 ghi789...

この場合は、スキップしたコミットを手動で確認する必要があります。

git bisect logとreplayで作業を記録・再現する

bisectセッションの内容を記録し、後で再現できます。

bisect logで履歴を確認する

1
2
3
4
5
6
7
8
$ git bisect log
# bad: [abc123...] Current HEAD with bug
# good: [def456...] v1.0 release
git bisect start
git bisect bad abc123def456789
git bisect good def456abc789123
# good: [789abc...] Intermediate commit
git bisect good 789abcdef123456

bisect replayで再現する

ログをファイルに保存して再現できます。

1
2
3
4
5
6
7
8
9
# ログをファイルに保存
git bisect log > bisect.log

# 間違いがあれば編集
vim bisect.log

# セッションをリセットして再現
git bisect reset
git bisect replay bisect.log

高度なテクニック:パス指定とカスタム用語

特定のパスに限定してbisectを実行する

バグが特定のディレクトリやファイルに関連することがわかっている場合、パスを指定して探索を効率化できます。

1
2
3
4
5
# src/ディレクトリの変更に限定
git bisect start HEAD v1.0 -- src/

# 複数のパスを指定
git bisect start HEAD v1.0 -- src/calculator/ tests/

カスタム用語を使用する

バグ修正のコミットを探す場合など、「good/bad」が意味的にわかりにくい場合はカスタム用語を使用できます。

1
2
3
4
5
6
7
8
9
# パフォーマンス低下を調査(fast/slow)
git bisect start --term-old fast --term-new slow
git bisect slow HEAD
git bisect fast v1.0

# バグ修正を調査(broken/fixed)
git bisect start --term-old broken --term-new fixed
git bisect fixed HEAD
git bisect broken v1.0

old/newを使用する

「good/bad」の代わりに「old/new」を使うこともできます。

1
2
3
git bisect start
git bisect new HEAD    # 現在の状態を「new」としてマーク
git bisect old v1.0    # 過去の状態を「old」としてマーク

git bisectを使う際の注意点とベストプラクティス

注意点

項目 説明
クリーンな作業ツリー bisect中は作業ツリーの変更を避ける
テストの再現性 同じコミットで同じ結果が得られるテストを使用する
外部依存 データベースや外部サービスの状態に依存しないテストが望ましい
マージコミット --first-parentオプションで履歴を単純化できる

ベストプラクティス

  1. 再現可能なテストを用意する:bisectを始める前に、バグを確実に再現できるテストケースを作成します

  2. 範囲を絞り込む:可能な限り、goodとbadの範囲を狭く設定します

  3. 自動化を活用する:可能であればgit bisect runで自動化し、人的ミスを減らします

  4. ログを保存するgit bisect logで作業を記録しておけば、中断しても再開できます

  5. チェックアウト不要オプション:ビルド不要のテストなら--no-checkoutで高速化できます

1
2
# チェックアウトせずにbisectを実行
git bisect start --no-checkout HEAD v1.0

まとめ

git bisectは、二分探索アルゴリズムを使ってバグの原因コミットを効率的に特定する強力なツールです。

コマンド 用途
git bisect start bisectセッションを開始
git bisect bad バグがあるコミットをマーク
git bisect good 正常なコミットをマーク
git bisect skip テスト不可能なコミットをスキップ
git bisect run テストスクリプトを自動実行
git bisect reset セッションを終了
git bisect log 履歴を確認
git bisect replay ログから再現

1000件のコミットがあっても約10回のテストで原因を特定できるgit bisectは、効率的なデバッグに欠かせないツールです。特にgit bisect runと自動テストを組み合わせることで、完全自動でバグの原因コミットを見つけられます。

参考リンク