 I made a mistake here in my title. I called it investigating regressions quickly using git bisect, but actually I think it would be more accurately accurate to say investigating regressions efficiently using git bisect, because the process of investigating regressions isn't necessarily a quick one, but using the right tools we can make it an efficient one when you do need to investigate regressions. How often do you say this to yourself? Well, it used to work. Maybe you've got a plug-in or a theme that you publish on the WordPress.org directory, and one of your users comes along and they report a bug, and you say to yourself, well, it used to work. Or the same thing for a client site, maybe you publish or manage client sites, and one of your clients comes along and they say, oh, some functionality's gone missing, or it doesn't work, and you say, you know, it used to work. So you've got yourself a regression, something that worked in the past that no longer works, and somebody's unfortunately noticed it. How do you go about investigating this? What's your kind of first step? Now, a lot of you will probably start to dig into the code that you think might be responsible for the bug. Sometimes that can work. Sometimes you might be lucky, and you might have a good idea of where this bug exists, and you can go about fixing it, but it's not necessarily the most efficient way to investigate regressions. A more practical approach is to start looking through the history of your code in the Git history and try and identify the point at which that bug was introduced, and once you find that point, you can then start to fix that bug based on the change that was made that broke it. You could do this manually. You could start trawling through your Git history, but maybe you'll be lucky, maybe you'll spot it in this history, and you hit the jackpot, but this isn't a really very efficient way of doing it. You really need an efficient way to traverse this history to quickly find the issue. Git version control system has a command called git bisect, and it traverses a given portion of Git history, and it bisects it. It divides it in half each time based on the feedback you give it. Each time it cuts this history in half, Git will ask you whether this is a good piece of code, i.e. does it work as expected, or is it a bad piece of code? Is it a point in history where the bug that you're investigating exists? It's a very efficient way of traversing through the history. Forgive me if you've heard me talk about this particular bug before, but this is a good example of a visual bug that I was able to debug using git bisect. This is an admin menu from a plug-in of mine called query monitor. One day I noticed that the hooks item in the admin menu had just disappeared, and I hadn't noticed. The problem is that I was only sure that this worked at the point where I'd done the previous stable release, and unfortunately I'd committed about 70 different changes since that point, so I didn't really want to start manually looking through that history. I wanted a quick way to identify the point where this bug was introduced. Instead of manually looking through the history, I used git bisect, and it works like this. First of all, you tell git bisect to start, and then you give git a point in your history where you know that the code was good, and in this case I know that the code at tag 2.6.10 was good, I know that that admin menu showed up then. And then you give it a point which was bad, and usually that's going to be the head of your current branch, the piece of code that you're working on at the moment. This is a point in code where I know that this bug is exhibited. Now what git bisect will do at this point is it will check out a commit from the middle of the history between those two points in time. And it will tell you here that we have 74 revisions between those two points in history, and git tells us there that this is going to take roughly six steps to pinpoint the problematic change. That's quite interesting because we've got 74 changes to look through, but git says it's only going to take us six steps to identify this problem. And it will tell us which commit it checks out. So our working copy of the code now is a version of the code roughly halfway between those two points in history. Now what we do is we go and look at the bug that has been introduced and see whether it is still exhibited at this point. And as we can see here, the hooks item in this menu doesn't appear, so we know that we are at a buggy point in the history. So what we'll do is we'll tell git this, we can type git bisect bad. This commit represents a point in history where the code was bad, so the bug has already been introduced at some point before this code. What git will do now is it will bisect that remaining piece of history. It will check out another commit in the middle of the remaining piece of history, and we will repeat this process. And here again it tells us the commit that it's checked out. Now this time the missing menu item has reappeared, so we now know that we're on a good piece of code. This must mean that we're at a point in history before the bug was introduced. So we will tell git this again, we'll say git bisect good. And this time git checks out a commit after this one, but before the previous known bad commit. And again git gives us some information there, it tells us which commit it checks out. Again halfway through the remaining piece of history. And what we will do is we will just repeat this process. Again we've got another good point in history here, so we'll tell git that this is good. And eventually if we repeat this process enough times, we will actually reduce this history down to the point where that bug was introduced. And git bisect tells us this. This commit hash here is the first bad commit, and it tells us the commit information and the author. Unfortunately it was me of course. It tells us the date and the commit message. And now what we can do to verify this is if we go and do a diff between that commit and the previous one, we can see that I accidentally removed a bunch of code that I shouldn't have removed. So we've identified that this is indeed the commit, the change that caused the bug. And to finalize it, we run a command called git bisect reset, and what this does is this resets our working copy back to the code that we were on, which is usually going to be the head of the master branch if we're working on that. So that did actually end up taking only six steps to bisect 74 pieces of history down to identifying the change that introduced that bug. Instead of manually going through 74 pieces of history, it's taken us just six steps using git bisect. This is a huge time saver. But we can do a bit better. Imagine if you identify an issue that you have no idea where it was introduced. It could have been months ago, it could have been years ago. You are potentially looking at hundreds or thousands of commits in your history to look through. Or imagine if maybe the bug was a little bit more complex than the one I showed you there, and it was quite an involved process to test the issue. It might end up being still a resource and time intensive process to find the commit that was the problem. So this process could actually end up taking quite a bit of time. We can automate this process using a sub-command called git bisect run. What this does is it accepts a script as a parameter which will do the testing for you. So instead of manually going and looking at that admin menu to see whether the item is present or not, I can write a simple script that will go and do that testing for me and it will automatically report it back to git bisect. This script doesn't need to be a real unit test or a real functional test. It just needs to be a script that you can run on the command line and one which will return the correct exit code depending on whether the code is buggy or not. So you can have a PHP script, you can write a BHAP feature, you can just have a regular shell script that returns the correct exit code. It's really entirely up to you. All git bisect cares about is the exit code. So let's take a look at an example. This is an automated version of the script that I can use to test that admin menu bug. So it's fairly straightforward. I'm setting up WordPress there by including wplote.php. I'm setting up a user that I know is an admin user. I'm bootstrapping WordPress and then I'm calling the method in my query monitor plugin that returns that admin menu. Then all I'm doing to actually test it is performing a very simple piece of logic that looks to see whether the particular menu item exists in that array of menu items. If it does, then I exit with exit code zero and that means success. That means this is a good piece of code. If not, then I exit with exit code one and that represents a bad piece of code. That's the same as typing git bisect bad. So if we call this script on the command line with git bisect run, we can pass that file name in through PHP with the dash F parameter. And when we run this git bisect will start running, but instead of manually asking us to check the code at that point at each point in time, it will call that script and that script will return an exit code and git will bisect each piece of history based on that exit code each time. Now my script there was pretty straightforward. It takes a split second to run. So this whole process just took a matter of seconds to run. Of course it took me much longer to actually write that script than it did for git to run it six times. And again, we get the same result there. So imagine if this was a large piece of history of hundreds or thousands of commits to run through, this is going to speed up things greatly. But we can do better, a little bit better anyway. There's one more tip that I want to tell you about and it's a parameter here which accepts a file path. So if you've got a rough idea of where you think your bug exists in the code base, you can run git bisect start and give it a path to that directory. And that will reduce the amount of history that you have to look through to only the history that concerns those files. And in the few times that I've run this, this has again greatly reduced the amount of history that I have to look through. Sometimes this results in just two or three steps to look through. So again, this really, really speeds up the amount of code and the amount of commits that you have to look through. I hope that you don't need this advice very often. I hope you don't have many regressions. Unfortunately, because I don't have to use git bisect very often, I usually have to refresh my memory. You usually have to go and look up the commands. Don't worry about it. Unless you've got an excellent memory, you probably will need to refresh your memory each time you use it. That's it from me. Thanks very much.