Finding the bug between a bunch of commits (git bisect)

14 Dec 2023

I have been on an absolute roll making some highly needed changes to FormBackend over the past couple of days. It’s been a fun exploration of discovering all the new stuff Rails has to offer with Hotwire and all that. But I’ve been pretty lazy with running my tests, which led to authentication not working due to invalid CSRF token.. Hmm.. What a bummer.

There wasn’t any obvious change that seemed to have caused this, looking through the whole git diff and nothing obvious jumped out at me. Time for the good ol’ git bisect. You give git a good (where things are working) and bad (where things are broken, duh) commit - and it’ll bisect through it. Every time you give it feedback if things are working or not and eventually it’ll narrow it down to the commit where things are failing.

The way it does it is simple enough, it uses binary search. Finds the middle point of the commits and goes from there, keeping dividing the area into smaller and smaller bits till you find it.

If you don’t feel like doing it manually, there’s this great ruby gem: git-autobisect. Which will do most of the work automatically as you run it with the failing test and it’ll find the offending commit for you :)

With just the plain old git bisect you’d run it like so:

git bisect start 399a7058 d57072bc

It would do it’s thing and pick a commit that falls somewhat in the middle:

> git bisect start 399a7058 d57072bc
HEAD is now at 649acd78 Set current
Bisecting: 8 revisions left to test after this (roughly 3 steps)
[79cc37bc5082bcc2930089e30cf7029da80b7278] Remove create new project link from forms index page

You would do your thing, either run your failing test or go to the browser and try what was failing. If it is still broken, you would tell git that by running

git bisect bad

Git would pick a new commit for you, you would repeat the step and either run git bisect bad or git bisect good and you would continue like that until there’s only one commit left, which git would then checkout so you could inspect the changes. A nice built in feature instead of having to do it manually :)