Git Bisect — And Debugging Is Easy
Tags: github, git
Published: 2020-05-25 23:31:22

Once upon a time, there was a young developer who worked on a small side project, after a few hours he created a working version and started to refactor the code to make it nice, tidy, and clean. He refactored the code for a couple of hours and kept working neatly in small and meaningful commits. When he was pleased with his work he ran the code again but oh no, something terrible happened… the code didn’t work.

We have all been there, for me it happened a week ago, I sat in my bed and stared at my IDE rat me out that it was I who wrote that buggy code, _“I got only myself to git blame that’s for sure”_ I grinned with myself but after a second a light bulb popped with a new idea — 💡 **what if I can use Git to traverse through all of my commits and hunt down my bug**? fortunately, after a short search on Google I discovered that it is possible - using the simple git bisect command.

In this tutorial, we will explore the `git bisect` command. How it works, why, and how to use it so hopefully you will find it useful and powerful as I do!

## 🔮Debugging with Git
As you may know for git everything is about commits, a branch for that matter is nothing but a pointer to a single commit. This allowed git to traverse through the commits and provide a couple of debugging tools to help us debug our code: File Annotation(a.k.a ‘git blame’) and Binary Search.

> If you’d like to learn more about how git works under the hood and stores its data check out my recent [article](https://medium.com/@noabarki76/dont-underestimate-the-push-force-5cba944a246d) and [git documentation](https://git-scm.com/book/en/v2/Git-Branching-Branches-in-a-Nutshell) for further reading.

#### File Annotation — git blame
File annotation shows the last commit to modify each line of any file and done using the `git blame` command, this is often the most useful tool for tracking down a bug and know who is the one to blame. If you are not familiar with git’s file annotation I highly recommend you read about it form git [documentation](https://git-scm.com/docs/git-blame).

#### Binary Search — git bisect
A way to locate which commit introduced an issue using binary search through all the commits history of a particular branch. It’s done with the `git bisect` command which checks out each commit allowing you to run a test to see if the issue exists in this commit. When you’re hunting down a bug but you don’t know where to look for it and there were hundreds of commits since the last good commit you remember - the `git bisect` command is your answer.

![](https://dev-to-uploads.s3.amazonaws.com/i/lijckfem415xnp6h6eoz.png)

## 📽 Simple Scenario

Let’s say you worked on a new branch…

🥳 You worked for some time until you finally reach a good point with a good working product.

😌 You are also a responsible developer who wishes to keep his tree clean so you probably added a few commits along the way and had the following commits history:
```
*-----*--*---271cb1c (current)
```

💎 You decided it’s time to start refactoring the code, make it nicer and clean, eventually you ended up with the following commits history:

```
*-----*--*---271cb1c-*-66e0075-*-...--*---9c07a95 (current)
```


😰 Unfortunately, your code isn’t working properly at the current commit, apparently somewhere along the way a part of the code got broken.

🧐 You know that it had definitely worked before the refactor — when you added commit `271cb1c` — meaning there is a bug in the code between commit `271cb1c` and `9c07a95`, the only question is…. How do you find it?

👑 Enter `git bisect`.

## 🛠 How to use it
Inspired by Clint Eastwood I like to think about this part as the story of ‘The Good, the Bad and the Wizard’:

#### 🧙🏼‍♂️ The Wizard
Run the `git bisect start` command to startup the `git bisect` wizard.
#### 😈 The Bad
In `git` the binary search works by repeatedly dividing in half the commits that could contain the bug and narrowing down the possible commits to one, this makes the scope of the search essential. The way to define the `git bisect` wizard what is the searching scope is by running the `git bisect bad` command which tells `git` that the `current` commit is broken and contains a contagious bug.
#### 😇 The Good
The bad commit is only one end of the scope now we need to tell `git` when the last known good commit was, we do that by running git bisect `<good_commit>` command, for example in our case, the good commit was commit `271cb1c` so we’ll run the following command: 
```
git bisect 271cb1c
```
After running this command `git` will start checkout commits using binary search and allow at each commit to build the app and check whether or not the bug exists, all left for you to do is to make sure you tell `git` the status of the last `git bisect` command with either `git bisect bad` or `git bisect good` so it will continue to narrow down the possible commits, repeat until it finds the commit where the bug was introduced.
Let’s assume we checked out on commit `66e0075` and that we found out that the bug occurred before it so we run:
```
git bisect bad
```

#### 🙌🏻 Git is kind

Now `git` has all it needs to determine that the commit between commit `66e0075` and commit `271cb1cis` the commit where the bug introduced. When `git` finally finds the commit with the bug it prints all the information it has about it to help you figure out what happened that may have introduced this bug, for instance:
```
$ git bisect bad
66e00756e887030abcbde19ac3e10a7c2942036a is the first bad commit
commit 66e00756e887030abcbde19ac3e10a7c2942036a
Author: Noaa Barki <noaa@datree.io>
Date:   Sun Apr 26 12:10:56 2020 +0300
fix: added client
base/client.go                              
base/client_test.go                          
1 files changed, ......
 create mode 100644 base/client_test.go
```

#### 🧙🏼‍♂️The Wizard
Like every time-travel journey its important to go back to where it all began otherwise we might be checked out on a commit from the past and end up in a weird branch state. We go back to the present by running the simple `git bisect reset` command which shuts down the `git bisect` wizard and reset the `HEAD` to where we were before we started.

## 🤖 Automation
This is the part when `git bisect` really shines - one of `git bisect` subcommand is the `git bisect run` which accepts a command as an argument and allows to fully automate `git bisect`!
```
git bisect run <cmd>...
```
After running this command `git` automatically runs `cmd` on each checked-out commit and uses the return value of that call to decide if the commit is good or bad until it will find the first broken commit.

#### How to use it
First, you tell `git` the scope of the bisect by providing the bad and good commits:
```
$ git bisect start <bad_commit> <good_commit>
```
Then you `git bisect run` with your command and let `git` do all the work for you, for example:
```
$ git bisect start HEAD 991debbc8b9e05ddc217023a898109822a70dd60
$ git bisect run npm run test
```

The command can be any script that will exit 0 for “good commit” or non-0 “bad-commit”.

## 🌸 Summary
In this tutorial, you learned how to track down a bug using the `git bisect` command. Moreover, you learned how to automate it and by that reduce debugging time significantly. I hope you’ll try `git bisect` in the future when you’ll look for a nice solution for hunting down a bug.

Special thanks for my teammates at [datreeio](https://datree.io/) 🙏🏻