October 13, 2009 1 Comment
If you’ve ever had a bug that got introduced to an application you’re working on at some point, but haven’t been able to track down what caused it, then git has a really useful feature that you can use to track it down called bisect.
# First create a local branch to do the tracking in git checkout -b find_that_bug # Next, start bisecting! git bisect start
After that, you need to mark some commits or references that you know either contain or don’t contain the bug. In our case we know that the bug currently exists in master, so we github commits to find one old enough that we were sure wouldn’t have the bug.
# the master branch is broken git bisect bad master # but this commit is good git bisect good 0f54590e
This is where it starts to get fun. We were initially confused because we expected the next part to take a linear approach, but it wasn’t. Git tells you how many commits are between the two, that’s the number of commits left to check, (if they were the ones to introduce the bug). Then git will load up a commit somewhere in between and you mark it as either good or bad, depending if it’s got the bug checking either the unit tests, or in our case actually using the web interface. The smart thing is that it zips back and forwards between the good and bad end, zeroing in on the commit that introduced the bug, so you may only end up checking around 6 commits out of 40.
Once the “original bad commit” is found, git places you at the commit just before that, and you can look at the diff for what was changed in the bad commit, and try applying some of those changes if necessary to see exactly what it was that broke your code. In our case the offending change was something as innocuous as adding an extra closing div tag to a partial that was misleadingly enough not self contained, and the div wasn’t supposed to be closed.
All in all, we were pretty happy to have found the bug so quickly, and found git bisect incredibly useful. Seeing how useful it was made highlighted for me the necessity of self contained commits (e.g. when refactoring, commit the entire refactor. Don’t break something, commit, then fix it in a later commit if you can help it) because this will prevent you being able to find bugs for that feature with git bisect.