DEV Community

Dane Hillard
Dane Hillard

Posted on • Updated on

Hunt bugs with git-bisect

I recently implemented a "sticky toolbar" feature on our site. It was one of the first times I'd composed something new from the existing Vue components we'd built for the rest of the page, and it was a heck of a lot of fun. The features of the toolbar sort of came together without a lot of work other than the CSS to get the positioning right. I felt pretty good when I finally merged that code.

A day later, I was perusing the site near the end of the day and happened upon an issue. The styling was borked in one of the dropdown menus in the toolbar. I naturally worried my recent change had caused the issue and that I'd somehow missed it. I checked that the latest commit on master was indeed exhibiting the issue locally, and sure enough it was. A few other changes had come in since mine, so I checked out the last commit from my change. I ran the build and refreshed the page, but everything looked good.

I was relieved not to have caused the regression, but that meant I didn't know where the bug was introduced. I spent a good 30 minutes inspecting elements and CSS in Chrome DevTools trying to understand what changed before remembering there was a better way. git-bisect to the rescue!

git-bisect is a tool for running a binary search through your commit history. It allows you to place goalposts that mark a particular commit as good or bad, incrementally narrowing the search space until you arrive at the commit that introduced a change. Most often you will start a git-bisect session and mark the latest commit as bad, since you already know there's an issue there:

$ git bisect start
$ git bisect bad

The next step is to figure out a time in the past when the bug wasn't there.
I had already found that my latest commit was okay, so I started there:

$ git bisect good a56f1b2  # The SHA of my latest commit
Bisecting: 24 revisions left to test after this (roughly 5 steps)
[ab6c7a77d...] Add social media icons (#197)

Here's where the magic happens. Git now knows that the latest commit has an issue, and a point in the past where the issue did not yet exist. I've set the bounds for the search space, and Git has dropped me onto a commit in the middle of the two I've specified.

βœ… . . . . . . . . . . . . v . . . . . . . . . . . . πŸ’”

Now I check: does the issue exist here? No. I can go ahead and tell Git:

$ git bisect good
Bisecting: 12 revisions left to test after this (roughly 4 steps)
[bb8c65a43...] Increase contrast for small text (#203)

Git has cut the search space in half and put me in the middle of it again.

βœ…βœ…βœ…βœ…βœ…βœ…βœ…βœ…βœ…βœ…βœ…βœ…βœ…βœ… . . . . . . v . . . . . . πŸ’”

Does the issue exist here? Ooh, it does! I let Git know:

$ git bisect bad
Bisecting: 6 revisions left to test after this (roughly 3 steps)
[97e12fab6...] Improve exception logging (#202)

We're getting closer.

βœ…βœ…βœ…βœ…βœ…βœ…βœ…βœ…βœ…βœ…βœ…βœ…βœ…βœ… . . . v . . . πŸ’”πŸ’”πŸ’”πŸ’”πŸ’”πŸ’”πŸ’”πŸ’”

After a few more steps, I finally have a single commit left and Git spits out the info for that specific commit to let me know:

$ git bisect bad
6c3853827... is the first bad commit
commit 6c3853827...
Author: Arthur Q. Dev
Date:   Thu Jan 10 16:11:12 2018 -0500

    Update shared menu styling (#199)

βœ…βœ…βœ…βœ…βœ…βœ…βœ…βœ…βœ…βœ…βœ…βœ…βœ…βœ…βœ…βœ…βœ…πŸ’₯πŸ’”πŸ’”πŸ’”πŸ’”πŸ’”πŸ’”πŸ’”πŸ’”πŸ’”πŸ’”πŸ’”

I can now see precisely what changed in the commit in question, usually making it much easier to see what specific code change caused the bug to happen. These good/bad steps only take as long as the test to determine if the issue is present, so the whole git-bisect session can take as little as a couple of minutes. Once you find the offending commit, you no longer have to speculate about what might've happened--you can look directly at the change and think critically about it.

You can use git-bisect for more than just bugs. Sometimes you just want to know when something changed. git-bisect also understands git bisect [old|new] natively, but if you're tracking down something different or prefer different terms you can pass them to git bisect start using --term-[old|new].

I don't always use git-bisect but, when I remember to, I love it. Check out the full documentation and fully rock this tool.

Top comments (10)

Collapse
 
david_j_eddy profile image
David J Eddy

This is great. Bisect ahs been familiar to me for some time now but never made sense. Little did I know that I was doing this same thing but manually. The icon.visuals made all the difference. Thank you for this.

Collapse
 
easyaspython profile image
Dane Hillard

Thanks for the feedback, I'm glad it helped!

Collapse
 
tabuz profile image
Trebuh

Something I did not know about. Can't wait ti use it first time! Thanks for sharing.

Collapse
 
easyaspython profile image
Dane Hillard

That's fantastic, I hope it goes well! Keep me posted πŸ˜„

Collapse
 
rhymes profile image
rhymes

Great explanation Dane, git bisect is amazing!

Collapse
 
easyaspython profile image
Dane Hillard

Thank you! I hope the visual helps some people conceptualize it better :)

Collapse
 
rhymes profile image
rhymes

It definitely does!

Collapse
 
ruvans profile image
Ruth Evans

I didn't know this existed! I'm going bug hunting tomorrow and this might come in useful, thank you 😁

Collapse
 
easyaspython profile image
Dane Hillard

Thanks for the feedback, let me know how it goes!

Collapse
 
mblayman profile image
Matt Layman

I love git bisect, and I think it's great that your article shows a visual representation of what it does. I think that will help a lot of people understand how awesome bisect is. Nice work!