It happened on Friday (a build day), my team was working on final touch-ups to deliver that iteration’s build. One of my team members was keenly looking at the code.
“What are you looking for? “, I asked him.
“Someone has made a change that affected a small part of my work leading to a bug. I’m looking for that change”, he replied.
“Well. How much have you progressed? Are you in a logical state to figure out that commit? “, I asked him.
“I don’t have any clue till now”, he replied.
“Git provides a way to trace back a bug from where it has occurred. Let’s explore together”, I replied.
In a few minutes, we were able to find the commit where the bug originated. That’s because of one of the powerful commands in git called “Git Bisect”.
Let’s learn about Git Bisect below
What is Git Bisect?
git bisect uses binary search to find the commit that introduced a bug. It can also be used to find the commit that changed any property of your project. You define a bad commit (broken code) and a good commit (working code) and
git bisect helps you to quickly find that culprit commit either manually or automatically. But, you have to build and verify your project each time
git asks you to do.
Hope you’re a bit confused. Let’s understand it with an example.
Let’s create a new shell script that adds two numbers and prints the result on the console
I have created a file named
sum.sh and added the above code
Running the above file prints the result on the console as
Total = 30
Let’s make some dirty commits before breaking the code
For each of the above lines, I’ve made a commit. (Just to understand
git bisect clearly)
Let’s break the code now
I made the code to always print the result as
Total = 0 and added the commit as
Broke the code in this commit
Let’s ensure our code is really broken by running the script
We broke our code successfully. Let’s add 10 more commits after our breaking code
Again for each above line, I’ve made a commit.
So, my final list of commits is as follows,
Finally, our broken code is nested heavily before and after 10 commits.
We’re ready to find that culprit commit. Let’s see
git bisect it in action.
git bisect, we need to ensure that there are no changes left in the staging area and a working copy of our repo.
To start bisecting, we need to run
git bisect start, which will not show anything on the console. But we can find the status of bisect by running
We need to let it know which are good and bad commits. I’m setting
09bb72c (Latest commit) as
bad commit and
9e07971 (Commit where I added sum.sh file) as
good commit (Please refer above log screenshot to identify those commits).
My HEAD is currently at my latest commit. So, let’s set this as
bad a commit.
Let’s checkout to
9e07971 and set that as
git bisect has started to work. Look at the message from
git bisect good command. From the message, we can clearly infer that git has checked out to a random middle commit ([Arunachalam] 1st commit before breaking code). It also shows that there are 10 revisions left and roughly 3 steps to figure out that culprit commit.
Let’s run the script and verify.
As it’s working properly, we can classify this commit as
good commit by running
git bisect good.
Immediately, after I consider that commit as
good commit, git has switched to the next random commit within that range (The commit where we were before till the commit which we marked as bad).
Let’s run the script again and verify,
That’s a bad commit (The output of the total was not 30). After classifying it as a bad commit, git has checked out to the next random commit.
Let’s run the script and verify again,
That was a bad commit too. So, classified it as
bad commit. Git has checkout to the next closer commit.
Let’s run the script and verify again,
The result was wrong again. So, let’s classify it as
“BOOM!!! I caught that culprit commit”, says Git.
It also adds
- Author of the commit
- Date and time of commit
- Commit message
- Files changed in that commit
Really Great. Isn’t it?
That’s the same feeling me and my colleague experienced on the day, we were stuck on that issue.
git bisect resetto return to your actual code.
As usual, a few of my teammates raised questions about
git bisect me on some occasions. Let’s summarize them.
Kumar asked a good question, “What if I don’t know if a commit in the middle was good or bad? “.
That’s a good question, some people may face such a scenario. Git Bisect provides a command to handle such scenarios too.
git bisect skipcommand helps you to skip the particular commit and move on to the next commit
“How can I get out of bisect if I messed up with it? Or I found the actual reason for the bug in the middle of the bisect process? “, the question raised by Udhaya.
Yes. Thanks for that question Udhaya. I feel that’s the most important thing everyone should know.
git bisect resetcommand will reset the
bisectprocess. If you want to start again, you have to start from
git bisect start. Remember, we have to run the
resetcommand at the end of the
“Can I see the list of commits that I’ve marked as good/bad in the middle of the bisection process? “, the beautiful question raised by Raman.
“Yes. You can”, I replied.
git bisect logcommand lists all the commits that we have marked as good / bad in the bisection process. Here’s the list for the above scenario.
Curious Naras asked a crazy question.
“Remember, at the beginning of your session while defining about
git bisect you said, ‘
git bisect helps you to quickly find that culprit commit either manually or automatically. ‘. How can a git bisect automatically find a culprit commit? “.
That resembles his sharp concentration on my points. Let me answer this extraordinary question.
There exists an powerful command called
git bisect run. This helps to automatically find out the culprit commit.
If you have a script that can tell if the current source code is good or bad, you can bisect by issuing the command:
git bisect run my_script arguments
The script (
my_script) should exit with code 0 if the current source code is good, and exit with a code between 1 and 127 (inclusive), except 125, if the current source code is bad. Exiting with code 125 will skip the bisect.
Let’s automate the above scenario.
I’ve created a new file named
test.sh and added the above code. The above code runs the script file (
sum.sh) and get the output and verifies if the output is expected or wrong. It returns 0 (
good code) if the output is 30 or returns 1 (
bad code) if the output is 0 and returns 125 (
skip) if the output is neither of that.
Let’s try to find the same culprit commit with this automated script
I’ve started the bisect script. You can notice that I’ve given two hashes after
start the command. Those are bad (
09bb72c) and good (
9e07971) commits. From the message, you can see the bisect has started.
Let’s automatically find the culprit commit by running
“OooooooooH!!!”, Look at how crazy it runs.
The culprit commit was found in a fraction of a second. Yes. It found the commit in less than a second. But this may not happen for all. Because, when you’re working on a project, the actual verification scenario is to build the project. Definitely, a build command takes a lot of time to complete (Eg. yarn build / gradlew build).
That’s all about
git bisect. Hope you enjoyed reading this article.