During WordCamp Europe 2019 I had the pleasure of attending the following lightning talk: Find that bug you made months ago with GitBisect by David Needham. Truth is, I found it very interesting and I thought it is worth briefly summarizing what I learned there, since it teaches how to save a lot of time when finding and correcting an error that you have inadvertently entered in your code.
You made a mistake months ago, and a part of the site is broken. No one noticed at first, but now the client is upset, so you need to fix it…and fast! But where in the code was this bug introduced? What if David told you there’s a tool hidden within Git to quickly find when a bug was committed and then fix it? Git Bisect allows you to comb through dozens of commits at once and find the culprit in seconds, even when you don’t know when it happened or what file was edited. Once you understand the basics, David will take it a step further with automation.Summary of the talk on the WordCamp Europe 2019 website.
If you want to watch David’s talk, here you have the link:
How to (Shabbily) Find Where and When an Error Was Introduced
Imagine one of your users writes to you and tells you that they’ve encountered an error in your plugin. Damn! You know it has to be recent, as the issue they describe wasn’t there a few commits ago but… who’s the culprit? How do you find the exact commit in which the bug was introduced?
The simplest solution I can think of at first is to manually review your latest commits, one by one, so that you can find the exact moment where things go from “everything’s alright” to “here’s the bug!”
For instance, suppose your project has 100 commits and commit number 100 is what your client is using. The first thing you’ll probably want to do is reproduce the issue as described by your user, so you open your browser and give it a try. And, indeed, there it is! Then you go to commit 99 and repeat the process: you check whether the bug is also in commit 99 and, if it is, move to the next step. Commits 98, 97… you repeat the process over and over again until you reach a certain commit (73, for example), where everything works correctly. Where was the problem introduced? Exactly: commit 74.
It took you 100-73 = 27 attempts to find the faulty commit 🤷 but, hey, at leats you now know where the error appeared and you have full access to the changelog, so working in the solution should be straightforward. 💪
How to Find the Error Quickly and Effectively with Git Bisect
Now forget about the previous shabby solution and let’s use the method that David Needham explained in the WordCamp Europe 2019. We have an error in the most recent commit of the project and we want to find where that error was introduced… what do we do?
Well, the first thing is tell Git we want to bisect our code to find a culprit. To do this, simply enter the following command in the folder of our project:
Assuming we’re in HEAD, and given the fact that we know this commit fails (we reproduced the issue, remember?), let’s simply tell Git that the current commit is wrong:
Next we have to tell Git about one previous commit that we know (or think) is correct. For instance, let’s assume that we know the first commit of our project is correct (hash
c1fd602276). Let’s tell Git so:
bisect</span></span> good c1fd602276
As a result of this command, Git will tell you the number of commits between your last valid commit and the faulty one, as well as how many steps it’ll take to find the culprit:
as well as automatically selecting a commit between the two. In our example, Git has automatically selected commit 50 and is waiting for us to tell it whether this commit is right or wrong. Let’s assume it’s fine:
Since commit 1 was OK, and so is commit 50, Git assumes that commits 1 to 50 are also OK and therefore the issue must lie between 50 and 100 (HEAD). Then, Git looks for the commit that sits in the middle of commits 50 and HEAD (namely, 75) and, again, asks us “what about this one?” We check commit 75 and we see it’s not working, so we let it know:
and now Git knows that commits 75 to HEAD are wrong, so the culprit has to be between 50 and 75. Git Bisect repeats this process over and over, discarding half of the commits each time, until 6 steps we find the culprit in about 6 steps.
Pretty cool, huh? The possibilities offered by Git are amazing. It’s unbelievable how much time you can save if you know your tools a little better. I strongly recommend that do not miss David Needham’s talk (linked in this post), because he discovers a few more tricks I haven’t covered in this (short) post. I’m sure you’ll love them!