Skip to content

Bisect

git bisect uses binary search to find the specific commit that introduced a bug. Given a known-good commit and a known-bad commit, it checks out commits between them, narrowing the range by half each iteration until it identifies the exact culprit.

When a bug is discovered in production, you may need to search through hundreds or thousands of commits to find when it was introduced. Linear search (checking each commit one by one) has O(n)O(n) time complexity. Binary search reduces this to O(log2n)O(\log_2 n):

Commits to searchLinear stepsBinary steps
1001007
1,0001,00010
10,00010,00014
100,000100,00017
Terminal window
## Start a bisect session
$ git bisect start
## Mark the current commit as bad (bug is present)
$ git bisect bad
# Mark a known-good commit
$ git bisect good v2.5.0
# Git checks out a commit halfway between v2.5.0 and HEAD
# Build and test the code...
# If the bug is present:
$ git bisect bad
# If the bug is NOT present:
$ git bisect good
# Repeat until git identifies the culprit:
# a3f2b1c0 is the first bad commit
# commit a3f2b1c0
# Author: Developer <dev@example.com>
# Date: Mon Jun 2 10:00:00 2025
#
# Refactor authentication module
flowchart TD
    A["git bisect start"] --> B["git bisect bad HEAD"]
    B --> C["git bisect good v2.5.0"]
    C --> D["Git checks out<br/>midpoint commit"]
    D --> E{"Test:<br/>is bug present?"}
    E -->|Yes| F["git bisect bad"]
    E -->|No| G["git bisect good"]
    F --> H{"Range<br/>narrowed to 1?"}
    G --> H
    H -->|No| D
    H -->|Yes| I["Culprit identified!<br/>git bisect reset"]

    style I fill:#e8f5e9
Terminal window
# Equivalent to the above, in a single command
$ git bisect start HEAD v2.5.0

For bugs that can be detected by a script (exit code 0 = good, non-zero = bad), you can automate the entire process:

# Define a test script
$ cat > test_bug.sh << "EOF'
#!/bin/bash
make build
./run_tests --suite auth
EOF
$ chmod +x test_bug.sh
# Run automated bisect
$ git bisect start HEAD v2.5.0
$ git bisect run ./test_bug.sh
# Git automatically tests each midpoint and identifies the culprit
# a3f2b1c0 is the first bad commit

The run command will:

  1. Check out each midpoint commit.
  2. Run the script.
  3. Mark the commit as bad if the script exits non-zero, good if it exits zero.
  4. Continue until the range is narrowed to one commit.