Git & Command Line Tutorial · Git Superpowers · Lesson 20 of 20
Finding Bugs with git bisect
When something broke but you don't know which commit did it, git bisect binary-searches history, and git bisect run can do it automatically with a test script.
Binary search through history
You know version 1 worked and today's code is broken, with 200 commits in between. Testing each one would take forever; bisect halves the range each step, so 200 commits need about 8 tests.
git bisect start
git bisect bad # the current commit is broken
git bisect good v1.0 # this one worked
# Git checks out a commit in the middle: test it, then
git bisect good # or: git bisect bad
# ...repeat until Git names the first bad commit
git bisect reset # go back to where you started
Even better, git bisect run ./test.sh runs a script on each step (exit code 0 = good, 1 = bad) and finds the culprit with no manual work.
git init -b main --quiet calc && cd calc
cat > add.sh <<'EOF'
echo $(( $1 + $2 ))
EOF
git add . && git commit -m "Add calculator" --quiet
for i in 1 2 3 4 5; do echo "note $i" >> notes.txt; git add . && git commit -m "Update notes $i" --quiet; done
sed -i 's/+ \$2/- $2/' add.sh && git commit -am "Refactor arithmetic" --quiet # the bug
for i in 6 7 8; do echo "note $i" >> notes.txt; git add . && git commit -m "Update notes $i" --quiet; done
echo "today: 2 + 3 = $(bash add.sh 2 3) (wrong!)"
cat > test.sh <<'EOF'
[ "$(bash add.sh 2 3)" = "5" ]
EOF
git bisect start HEAD "$(git rev-list --max-parents=0 HEAD)" > /dev/null
bad=$(git bisect run bash test.sh 2>/dev/null | grep "is the first bad commit" | cut -d' ' -f1)
git bisect reset > /dev/null 2>&1
echo "first bad commit: $(git log --oneline -1 "$bad")"
Output
today: 2 + 3 = -1 (wrong!) first bad commit: fb66692 Refactor arithmetic
Run this on your computer — see “Get Started” for setup.
Test yourself
About how many steps does git bisect need to search 1,000 commits?
About 10About 1005001,000
Show answer
Answer: About 10