Spot the culprit commit with Git Bisect
Table of contents
Brief about Git Bisect
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 member 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 has originated. That’s because of one of the powerful command 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 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 console
Script to add 2 numbers and print the result
I have created a file named sum.sh
and added the above code
Result of sum of 2 numbers script
Running the above file prints the result on the console as Total = 30
Let’s make some dirty commits before breaking the code
Added comments for each commit
For each of the above line, I’ve made a commit. (Just to understand git bisect
clearly)
Let’s break the code now
Broken code
I made the code to always print the result as Total = 0
and added the commit message as Broke the code in this commit
Let’s ensure our code is really broken by running the script
Wrong output
We broken our code successfully. Let’s add 10 more commits after our breaking code
Added comments for each commit
Again for each above line, I’ve made a commit.
So, my final list of commits are as follows,
Git Bisect — Showing list of commits before and after breaking code
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
in action.
To begin git bisect
, we need to ensure that there's no changes left in staging area and working copy of our repo.
My repo is clean and does not have any changes
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*git status*
command
Git Bisect Start
We need to let git 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
commit.
Set latest commit as bad commit
Let’s checkout to 9e07971
and set that as good
commit,
Set the good commit
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's also show that there are 10 revisions left and roughly 3 steps to figure out that culprit commit.
Let’s run the script and verify.
Correct response
As it’s working properly, we can classify this commit as good commit
by running git bisect good
.
Good Commit
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,
Bad commit
That’s a bad commit (The output of total was not 30). After classifying it as a bad commit, git has checked out to next random commit.
Let’s run the script and verify again,
Bad commit
That was a bad commit too. So, classified it as bad commit
. Git has checkout to next closer commit.
Let’s run the script and verify again,
Bad commit
The result wrong again. So, let’s classify it as bad commit
.
BOOM!!! Caught that culprit commit
“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.
Run
***git bisect reset***
to return to your actual code.
As usual, few of my team mates raised questions about git bisect
to 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 scenario. Git Bisect provides a command to handle such scenario too.
***git bisect skip***
command 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 bisect process? “, question raised by Udhaya.
Yes. Thanks for that question Udhaya. I feel that’s the most important thing everyone should know.
***git bisect reset***
command will reset the*bisect*
process. If you want to start again, you have to start from*git bisect start*
. Remember, we have to run the*reset*
command at the end of the*bisect*
process too.
“Can I see the list of commits which I’ve marked as good / bad in the middle of bisection process? “, beautiful question raised by Raman.
“Yes. You can”
***git bisect log***
command lists all the commits that we have marked as good / bad in the bisection process. Here's the list for the above scenario.
Git Bisect Log
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 listening skills. Let me answer this extraordinary question.
There exists a 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.
Automated Verification Script
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 the 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
Git Bisect Start — Automated Script
You can notice that I’ve given two hashes after bisect start
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 bisect run
Git Bisect Run — Automatically find culprit commit
“OooooooooH!!!”, Look at how crazy it runs.
The culprit commit was found in fraction of 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 or run test cases. Definitely a build / test 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. Give a clap 👏 if you like this article. Subscribe to our newsletter to receive more such insightful articles that get delivered straight to your inbox.
Subscribe to my newsletter
Read articles from 5 Mins Learn directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by