Hunting Bugs with git bisect

Reviewed & published by Brayan K

"It worked last week, it's broken now, and there are 300 commits in between." By the end of this lesson you'll use git bisect to binary-search your history and pinpoint the exact commit that introduced a bug — often in under ten checks, and fully automated.

Part of the free Git course at LearnCodingFast — hands-on lessons with worked examples and the output they print, plus practice exercises and a quick quiz.

What You'll Learn

1️⃣ Starting a Bisect

Tell Git two things: a bad commit where the bug exists, and a good commit where it didn't. Git then checks out a commit halfway between them and asks you to test it. Each answer halves the range, so even hundreds of commits resolve in about log₂(n) steps.

# A bug appeared "somewhere in the last few hundred commits". Checking them
# one by one would be brutal. git bisect does a BINARY SEARCH instead:
# halve the range each step until one commit is left.

# 1) Start a bisect session
git bisect start

# 2) Mark the current (broken) commit as bad
git bisect bad

# 3) Mark a commit you know was working as good (a hash, tag, or HEAD~50)
git bisect good v1.0

# Git now checks out a commit halfway between good and bad and asks you
# to test it. You answer "git bisect good" or "git bisect bad" each time.

2️⃣ Answering good / bad

At each stop, build and test the checked-out commit, then report the result. Git keeps narrowing until one commit remains and announces it as the first bad commit. Whatever happens, finish with git bisect reset to return to your original branch.

# At each step Git stops on a commit. Build/run your test, then tell Git
# what you found. It keeps halving the range automatically.

git bisect bad      # this commit still has the bug
# ...Git jumps to a new midpoint...
git bisect good     # this one works fine
# ...repeat until one commit is left...

# When the search narrows to a single culprit, Git announces it:
#   <hash> is the first bad commit

# ALWAYS clean up afterwards — this returns you to your original branch:
git bisect reset

3️⃣ Automating with bisect run

The real power is git bisect run. Give it a command whose exit code decides the verdict — 0 for good, non-zero for bad — and Git tests every midpoint itself, hands-free. Your project's test suite is the perfect script. The special code 125 tells bisect to skip an untestable commit.

# The real magic: automate the whole thing. Give bisect a script (or one
# command) that returns exit 0 when the commit is GOOD and non-zero when BAD.
# bisect runs it at every step and finds the culprit with zero typing.

git bisect start HEAD v1.0          # bad=HEAD, good=v1.0 in one line
git bisect run npm test             # exit 0 = good, non-zero = bad

# Use your project's test command — anything with a meaningful exit code:
#   git bisect run ./run-tests.sh
#   git bisect run sh -c '! grep -q BUG app.txt'
#
# Special exit code 125 tells bisect "skip — this commit can't be tested".

Your turn. Drive a full automated bisect from start to reset. Fill in the three blanks.

# 🎯 YOUR TURN — replace each ___ then run it in a repo with a known bug.
# Goal: let bisect find the first broken commit for you.

# 1) Begin the session
git bisect ___                # 👉 the subcommand that opens a bisect

# 2) Mark the current commit as broken
git bisect bad

# 3) Mark an older, working commit as good
git bisect good HEAD~10

# 4) Automate the search with your test command
git bisect ___ npm test       # 👉 the subcommand that runs a test each step

# 5) Clean up and return to your branch
git bisect ___                # 👉 the subcommand that ends the session

# ✅ Expected: Git prints "<hash> is the first bad commit".

Common Errors (and the fix)

Pro Tips

📋 Quick Reference

CommandPurpose
git bisect startBegin a bisect session
git bisect bad / goodMark the current commit broken / working
git bisect run cmdAutomate using a script's exit code
git bisect skipSkip an untestable commit
git bisect resetEnd the session, restore your branch
git bisect log / replayRecord / re-run your answers

Mini-Challenge: Catch the Regression

No commands given this time — just the plan. Run a fully automated bisect and name the commit that introduced a bug.

# 🎯 MINI-CHALLENGE: catch the regression automatically.
# No commands given — just the plan. Run each step in a real repo.
#
# 1. Identify the broken state (HEAD) and a commit you know worked
# 2. Start a session: git bisect start HEAD <good-commit>
# 3. Write a one-line test that exits 0 when good, non-zero when bad
# 4. Let "git bisect run <your-test>" drive the search to the end
# 5. Read off the first bad commit, then run "git bisect reset"
#
# ✅ Expected: bisect names the exact first bad commit, and reset returns
#    you to your original branch with no bisect state left over.

# your commands here

🎉 Lesson Complete!

Practice quiz

What problem does git bisect solve?

  • Merging branches
  • Recovering deleted files
  • Finding the exact commit that introduced a bug via binary search
  • Renaming branches

Answer: Finding the exact commit that introduced a bug via binary search. git bisect binary-searches your history to pinpoint the first commit where a bug appeared.

Which command starts a bisect session?

  • git bisect start
  • git bisect run
  • git bisect begin
  • git bisect init

Answer: git bisect start. git bisect start opens a session; you then mark a good and a bad commit.

After 'git bisect start', what two markers do you give Git?

  • A branch and a tag
  • Two file paths
  • An author and a date
  • One known-good commit and one known-bad commit

Answer: One known-good commit and one known-bad commit. You mark a bad commit (bug present) and a good commit (bug absent) to bound the search.

Roughly how many tests does bisect need across 1,000 commits?

  • About 1,000
  • About 10
  • About 500
  • Exactly 2

Answer: About 10. Binary search needs about log2(N) steps — roughly 10 tests for 1,000 commits.

What does 'git bisect run <script>' do?

  • Automates bisect by using the script's exit code at each step
  • Runs the bug
  • Runs all commits at once
  • Reverts the bad commit

Answer: Automates bisect by using the script's exit code at each step. git bisect run executes your script at each step: exit 0 means good, non-zero means bad.

In a bisect run script, what exit code marks a commit as BAD?

  • 0
  • 125
  • Any non-zero code (except 125)
  • -1 only

Answer: Any non-zero code (except 125). Exit 0 = good, non-zero = bad. Exit 125 specially means 'skip / cannot test this commit'.

What does exit code 125 mean to git bisect run?

  • Bad commit
  • Skip this commit — it can't be tested
  • Good commit
  • Abort the bisect

Answer: Skip this commit — it can't be tested. 125 tells bisect the commit is untestable, so it skips it like git bisect skip.

What MUST you run when the bisect is finished?

  • git bisect end
  • git bisect stop
  • git checkout main
  • git bisect reset

Answer: git bisect reset. git bisect reset returns you to your original branch and ends the session cleanly.

If a commit can't be built or tested, which command skips it?

  • git bisect ignore
  • git bisect skip
  • git bisect pass
  • git bisect next

Answer: git bisect skip. git bisect skip moves past an untestable commit so bisect keeps narrowing the range.

What does bisect print when it finishes?

  • 'all commits are good'
  • 'merge complete'
  • '<hash> is the first bad commit'
  • nothing

Answer: '<hash> is the first bad commit'. Bisect reports the first bad commit, with its diff, so you know exactly what introduced the bug.

Continue this course

Frequently asked questions

How does git bisect work under the hood?

It does a binary search of your commit history. You give it one commit where the bug is present (bad) and one where it isn't (good). Git checks out the commit halfway between them and asks you to test it; your answer halves the remaining range each time. That's why it only needs about log2(N) tests — roughly 10 for a thousand commits.

What's the difference between marking good/bad manually and using bisect run?

Manual bisect checks out each midpoint and waits for you to type git bisect good or git bisect bad after testing. git bisect run automates that: you hand it a script or command whose exit code decides good (0) or bad (non-zero), and bisect drives the whole search to the answer without further input.

What do the exit codes mean in a bisect run script?

Exit 0 marks the commit good, any non-zero code (1–124, 126, 127) marks it bad, and the special code 125 means 'this commit can't be tested — skip it', the same as git bisect skip. Make sure your test script returns these correctly, or bisect will draw the wrong conclusion.

Do I have to run git bisect reset at the end?

Yes. During a bisect Git leaves you on a detached HEAD at whatever commit it last tested. git bisect reset returns you to the branch you started on and clears the bisect state. Forgetting it leaves you stranded on a random old commit, which is confusing.

What if a commit in the middle won't build or run?

Use git bisect skip (or exit 125 in a run script). Git will pick a nearby commit to test instead and keep narrowing. If several commits in a row are untestable, the result may be reported as a range, but bisect still gets you very close to the culprit.