You’ve probably used – or at least watched someone use – git bisect before. It’s a great way to track down which commit introduced a bug. It usually looks something like this:

git bisect start

git bisect good [ref before bug existed]

git bisect bad [ref after bug was introduced...often HEAD]

[Check if bug is there…yup!]

git bisect bad

[Check for the bug…no.]

git bisect good

[Check for bug…no.]

git bisect good

[Bug? Yes.]

git bisect bad

[SHA where bug was introduced is isolated. Yay!]

git bisect reset

As you might know, there’s a way to have a script automatically do all the tedious good/bad checking for you: git bisect run. What you might not know is how easy it is to use.

When I go to fix a bug, usually the first thing I do is write a failing test that should pass when the bug is fixed. This forces me to think about the problem in very concrete terms, and gives me an indicator to know when I’ve fixed it. TDD.

As it turns out, this test is all you need to use git bisect run!

Normally, the test would probably go in an existing file in the test/spec directory. To start with, though, let’s put it in its own file. Because git bisect works by checking out lots of commits, a new file is your best bet for avoiding potential merge conflicts.

C’est tout. That’s it. We’re ready to use git bisect run.

git bisect start

git bisect good [ref before bug existed]

git bisect bad [ref after bug was introduced]

git bisect run [command to run your test]

[Lots of automated checking and test output]

[SHA where bug was introduced is isolated. Yay!]

git bisect reset

Now that you’ve found the offending ref and run git bisect reset it’s safe to move your test to the appropriate file.

Quick addendum:

Why would you care when the bug was introduced? Why not just fix it and move on?

  • In many cases, you really don’t
  • If your project actively maintains multiple versions, knowing where the bug was introduced will tell you which are affected without having to test every last one
  • If you’re having a hard time figuring out what’s causing the bug, sometimes looking at the commit that introduced it can narrow it down
  • If you want to do some kind of post-mortem to figure out who wrote the bug, why a test wasn’t written, etc