Debug using git bisect
Tags: softwaredevelopment, debugging, git
Published: 2020-05-11 06:57:48

---
title: "Debug using git bisect"
published: true
description: "Debug the problem from a long history of changes, tracked by Git, and find in which particular commit we've introduced the bug"
tags: SoftwareDevelopment, Debugging, Git
cover_image: https://images.unsplash.com/photo-1556075798-4825dfaaf498?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=2855&q=80
---

# What's git bisect?
I just learned about [git bisect](https://mirrors.edge.kernel.org/pub/software/scm/git/docs/git-bisect.html) from this {% twitter 1259656631291277312 %} and from the very first look of it, I was like - whooosh! It should be awesome. From the `man` page, it says this -

```
TLDR; git-bisect - Use binary search to find the commit that introduced a bug
```

So, that's kind of our day-to-day software engineering need, amirite? In the middle of our development of a particular feature, somehow we stumbled upon a situation where an existing code fragment is broken, but it shouldn't because we didn't touch (or actually couldn't remember) any related codes! What do we do then? I personally checkout to particular commits that I feel suspicious or check the file changes, but that's a hell lot of work to actually narrow down the bug. To automate this process, we can use `git bisect`.

This command uses a binary search algorithm to find which commit in our project’s history introduced a bug. First, we have to tell which one is the "bad" commit that is known to contain the bug, most of the cases that's where the *HEAD* is, but we can specify a commit hash also! Then, we have to mark a "good" commit where we specifically know everything was working fine. So, if you can remember the binary-search technique, we are marking the `low` and `high` indexes here! Then git bisect picks a commit between those two endpoints and asks us whether the selected commit is "good" or "bad". It continues narrowing down the range until it finds the exact commit that introduced the problem.

> In fact, git bisect can be used to find the commit that changed any property of our project; e.g., the commit that fixed a bug, or the commit that caused a benchmark’s performance to improve. To support this more general usage, the terms "old" and "new" can be used in place of "good" and "bad", or we can choose our own terms.

# How to use git bisect?
First, we have to start a bisect session and mark the good and bad commit hashes i.e. defining the boundary in which we'll search for the bug -

```
# startup git bisect
$ git bisect start

# give git a commit where there is not a bug
$ git bisect good <commit-hash>

# give git a commit where there is a bug
$ git bisect bad <commit-hash>

Bisecting: X revisions left to test after this (roughly Y steps)
[commit-hash] <commit-message>
```
Now, the process has been started automatically and git will start splitting the revisions in half and loading them up for us. It will checkout each revision and then ask us if the commit is good or bad. Then, we have to compile and test the code for that specific version to give a verdict to it i.e. good/bad! Our answer will be like this -
```
# If that version works correctly, type
$ git bisect good

# If that version is broken, type
$ git bisect bad

# Then git bisect will respond with something like
Bisecting: 12 revisions left to test after this (roughly 4 steps)
```
And after each prompt, it will use a binary search to very quickly narrow down the offending commit. The number of revisions we have between our “good” and “bad” commits will determine how long this process takes but it will still be quicker than individually checking out each commit. Roughly it takes log<sub>2</sub>(revisionCount) i.e. Y = log<sub>2</sub>(X)

We have to keep repeating the process: compile, test, and depending on whether it is good or bad hit `git bisect good` or `git bisect bad` to ask for the next commit that needs testing. And, eventually, there will be no more revisions left to inspect, and the command will print out a description of the first bad commit. The reference refs/bisect/bad will be left pointing at that commit.


Suppose we are trying to find the commit that broke a feature that was known to work in between these two commits `8c054db` and `5908ecf`. Now, after starting the git bisect session, we'll specify the good and bad commit -
```
$ git bisect start
$ git bisect good 5908ecf
$ git bisect bad 8c054db
```
And you'll see something similar to it, printed in your console -
```
Bisecting: 4 revisions left to test after this (roughly 2 steps)
[88f2ada15e8b2890b618e0300134deff9e4050c6] Add typography fixes
```
Here,  I have tested my code and it's working fine; let's mark it as good -
```
Bisecting: 4 revisions left to test after this (roughly 2 steps)
[88f2ada15e8b2890b618e0300134deff9e4050c6] Add typography fixes
$ git bisect good
```
Then, it'll give us this -
```
Bisecting: 2 revisions left to test after this (roughly 1 step)
[aa91d493c90a854b78a02fb10b8c097f323b9d4a] 1.1.0
```
After testing I've found that this is not working properly; so, let's put `git bisect bad`. Finally, it'll print this - 
```
aa91d493c90a854b78a02fb10b8c097f323b9d4a is the first bad commit
commit aa91d493c90a854b78a02fb10b8c097f323b9d4a
Author: uraniumreza <reza.uranium@gmail.com>
Date:   Sun May 10 19:37:40 2020 +0600

    1.1.0

 src/helper/validation.js            |   9 +++
 src/landing/components/ContactUs.js |  52 +++++++++++++---
 src/landing/service/api.js          |  12 +++
 3 files changed, 73 insertions(+), 11 deletions(-)
```
After finishing a bisect session i.e. you've successfully tracked down the bug, to clean up the bisection state and return to the original HEAD, we have to run the following command:
```
$ git bisect reset
```
By default, this will return our tree to the commit that was checked out before `git bisect start`. With an optional argument, we can return to a different commit instead:

```
$ git bisect reset <commit-hash>
```
For example, `git bisect reset bisect/bad` will checkout to the first bad revision, while `git bisect reset HEAD` will leave us to the current bisection commit and avoid switching commits at all

# Can we automate the process?
That was basically a manual approach of debugging, though it helps us automating the checkout process and narrowing down the buggy commit effectively. But we can run git bisect with a script (if we have a script that can tell if the current source code is good or bad) which will automate the whole process of compiling, testing, and marking the commit as good/bad!

```
# git bisect run <cmd> ...
$ git bisect run node bisect/index.js
```

> N.B. The script should exit with code 0 if the current source code is good/old, and exit with a code between 1 and 127 (inclusive), except 125, if the current source code is bad/new.

To know more about this feature please follow the reference section

## Reference
- https://git-scm.com/docs/git-bisect

---
Follow me on [twitter](https://twitter.com/uraniumreza) and RT if you loved it!