Part of resolving a bug is finding where and when that bug was introduced into your code. Not so much for blaming a specific person, but more for an understanding of how and maybe why the bug was introduced; and more over which versions of your app are affected.
Most of the time the bug was recently introduced and your CI notified you that stuff has been broken.
In order to find out when, how and by whom the build was broken, you'll have to dig into your git history and run your specs to see if they pass or not.
Running your specs for every commit in your history manually is very time consuming and boring. Luckily there are better ways, using plain old git.
## Binary search
Before I dive into git, it's important you understand how binary search works. If you already know this stuff, skip right to the next section.
You have a sorted array. This means there is some order to the elements you have. Presume you have an array of ints:
Now, we want to find the position (`n`) of `7` in this array using binary search so that `a[n] == 7`.
Binary search uses a divide and conquer strategy. You split the array in the middle. We have 10 elements, so a logical place would be to split the array at position `n = 5`, which has the value `42`.
Comparing `7 <=> 42` tells us that, because we have an ordered array, the value `7` should be in the first half of the array.
We can ignore the right half of the array for searching, and repeat this step for the left part, specifically:
Okay, again, we continue our search. We know have to split the array one way or the other, and we end up picking `n = 4`. We hit `33`. Surely the value of `7` must be on the left part of this.
_Note that although I don't show the whole array, I'm still using the index positions for the entire `a` array._
Now, there's not much to pick for us. This is 7. Right here at `n = 3`. Done!
Notice that the last step does not involve checking the value of the last element. We only have 1 element left, so we're finished.
If we had been looking for a value of 18, we would have also found `n = 3`. This means that we can search for non-existing values, which then return the index right before where that number should be inserted. This works because the array was ordered, so we can safely make such assumptions. Nice, huh?
## How does binary search relate to finding bugs?
Well, in the example above we were looking for an integer value. The test we use to evaluate is simple:
When we want to find the commit that broke our build we need a more clever way of comparing values.
This is where your test suite comes in. You have a failing spec now, so basically we're looking for the point in git history where that spec failed for the first time.
## Git bisect
Because it's not feasible to do a linear search over your entire commit history, we'll have to start by marking a _good_ and a _bad_ commit.
First we'll have to find a location in your git history where you know the app did not exhibit this bug.
More than likely, this place is your last stable release. If you used `git tag` to tag your release, you should be able to find out quickly if that release contains the bug.
Good. We now our latest commit was broken, so let's get started with that binary search!
You don't have to keep track of the git history and binary search position all by yourself: git does this for you. All you have to do is compare each commit that is presented to you with an expected result. E.g. does the `fancy_spec.rb` spec pass or not?
## Bisecting steps
First, let git know you want to do a binary search.