Troubleshooting Git History: Discover Problematic Commits with git bisect
Published at March 23, 2024.
Let's think that we are working on a giant project. Everyday lots of pull requests are merged to the repository. New features, bug fixes, improvements. Everything goes well.
We have unit tests, integration tests, e2e tests, code reviews, CI pipelines to check the code quality and possible issues, QA processes and all.
But every now and then, things can break apart. A new issue can be introduced without us even noticing.
And now we have a production
bug, have no idea what caused it and we want to be able to find the root cause as soon as possible to either fix it or to roll it back.
We can jump right into code and try to find out the root cause, check the recently merged pull requests, ask teammates if anyone worked on that part of the project etc.
But there is actually a very easy way of finding out the commit which introduced the issue.
Enter git bisect
git
is an incredibly powerful tool when it comes to version control. It has many commands and most of the times knowing only a handful of those is all enough.
And git bisect
is definitely one of them.
Simply, if we know a point in the git
history where the issue was not there, git bisect
can be used to search the history to find the problematic commit by using a binary search algorithm.
We just point a good (a commit in the history without the issue) and a bad (a commit in the history with the issue) and let git bisect
to help us find the root cause.
Example
Let's say we have the following git
history.
We know that the issue was not there up until 24184b1
commit, which has the message feature c
. So, this is the last "good" point in the history that we know without the issue.
We don't know when the issue was introduced. So we will choose the latest commit as the "bad" point here.
We run the following command to start the bisect process.
Now, git bisect
wants us to enter a good and a bad commit. Let's set the most recent commit as the "bad" one.
And set feature c
commit as the "good" one.
We switched to the feature g
commit which is right in the middle of feature c
(good) and feature k
(bad) commits. So, the binary search algorithm started as we can see.
And at every step, git bisect
tells us how many possible steps remained to find the problematic commit.
We will run the project in our local environment, check if the issue is there or not.
Let's say the issue is not there. So, we can mark feature g
as a good commit.
Now we switched to feature i
commit, which is in the middle of feature g
(good) and feature k
(bad) commits.
Once again, let's run the project and check if the issue is there or not.
Let's say the issue is there. So, we mark feature i
as a bad commit.
We are getting close. We switched to feature h
commit now.
Lastly, we run the project, check if the issue is there and let's say it is there.
So, we will mark feature h
commit as a bad one.
Now we know the issue was first introduced with feature h
commit.
We can check the file changes it introduced and easily find the root cause of the issue.
Lastly, we can run the following command to finish git bisect
.
Conclusion
As we know, binary search can work on sorted lists and git bisect
uses it in a way. So, we might consider having a linear git
history. It is not a 100% requirement for git bisect
, but it is most effective and straightforward to use on a linear history. And one of the easiest way of doing this is using squash merges for pull requests.
It is out of the scope of this article, but configuring it is generally easy. We just need to check the documentation of the "tool" we are using for git
(GitHub, GitLab, Bitbucket etc.). Having a linear git
history makes it easy to see the progress of the project and find out issues.
And we don't need to wait for a production
issue to try git bisect
, of course. If we encounter problems between multiple commits while working on a branch, git bisect
can be a valuable tool for improving the efficiency of the debugging process and easily pinpointing the root cause.
Thanks for reading!