Table of Contents
Git offers a huge array of really useful tools for software development that are great to explore. Today I’ll talk about one of these: Git Bisect, very useful when we want to search for something specific within our code.
What is Git Bisect and how does it work?
Bisect comes form binary search algorithm, and it’s an efficient way to search through a large set of (sorted) data. By repetitive dividing the batch in half and performing some kind of validation check, we are able to scan through a huge amount of data in a limited number of iterations. Bisect could be performed manually, by simply “checking out” to a specific commit and looking through the code. Yet the provided implementation protects us from all sorts of possible errors and does a lot of manual labor for us.
When it’s a good time to use bisect? When you are not exactly sure when a specific change had happened in the code. It may be a bug hard to track when it was introduced, unwanted change, like a code deletion that was mistakenly removed. In all those cases bisect comes in handy.
For the purpose of example let’s simply say we have a bug. It’s hard to track which change has initially caused it, but we know for sure, a week ago it was not there! Perfect, let’s start bisecting.
Before you start bisecting, please store your unfinished work with commit or stash!
At first, we need to initialise the search, with:
git bisect start
Now we need to mark two commits with good and bad labels, to specify the boundaries for the search. I will mark the current HEAD as being bad, since the bug can be reproduced right now:
git bisect bad
Next we need to mark the place in time when we are sure everything was still working fine. Same thing, it may be specified with the commit’s SHA, tag or branch, or simply by checking out to a particular commit and marking it as good:
git checkout 1234567
git bisect good
or
git bisect good 1234567
From now on Git will start to move the HEAD between commits offering us a possibility to verify the state of the code at that moment in time. The instructions are quite self-explanatory; we may see something like this:
Bisecting: 191 revisions left to test after this (roughly 8 steps)
[commit_123] Add new transaction endpoint
Our task is to validate the code, whether it’s compiling and running the application or launching a test case for the given problem. Everything is up to a specific case. Git will run us through the history, step by step optimising the amount of validations we need to perform. Our job is just to let Git know if at that point in time the code was still “good” or it was already “bad” – “git bisect good” or “git bisect bad”. Git will automatically jump over to the next candidate where we need to state our judgment:
git bisect good
Bisecting: 95 revisions left to test after this (roughly 7 steps)
[commit_321] Replace the User model with new implementation
After a specified number of selections we will be prompted with the suspicious commit and all its information.
At the end, don’t forget to “reset”. Also don’t hesitate from resetting, at any given moment, in case something went wrong and you wish to start over. Therefore:
git bisect reset
Is what you need to gracefully finish the algorithm.
In case you forgot to do that, Git stores all the necessary data in the .git catalog in the root of your repository. Removing all the `BISECT_` files from there will probably fix a great part of possible problems with bisect you may encounter.
rm .git/BISECT_*
Ok, let’s recap a little. Open a terminal, if you haven’t done that yet, `cd` yourself to some git repo you happen to have somewhere around and let’s practice a little.
First, check if there are any pending changes and commit or stash them. Then do that:
git rev-list —max-parents=0 HEAD
This will give you your repo’s initial commit’s SHA.
You may want to simply bisect start or start passing the bad and good points (in that order) right away. Try this:
git bisect start first_commits_sha_number_here HEAD
You should see a fail message, well it makes sense right? Why would you want to look for a place that you have made thing’s right?
The bisect start may accept one or two revision params. Just the bad, or bad and good, so let’s fix it:
git bisect start HEAD first_commits_sha_number_here
HEAD is bad. First commit was good.
Now:
`git bisect good/bad`
You may also try `git bisect next` or `git bisect skip`. Those are meant to allow you to pass a commit in case it cannot be clearly validated.
After you end, try:
git bisect log
to see it all over again
git bisect run
to reply the fun, here worth mentioning “run” may accept a script to automatically verify the code.
Try also:
git bisect visualise
Which will open your default visual tool. Try to experiment with it, in the middle of bisecting.
Ok, final trick. I should have probably started with this one, but it would spoil all the fun for me of explaining you all this. And for all those who haven’t yet jumped to console, this is your last chance – just:
git bisect
There you go, a handy reminder:
usage: git bisect [help|start|bad|good|skip|next|reset|visualize|replay|log|run]
Summing up:
Bisect is an easy to use searching algorithm that allows us to scan even a huge history in a reasonably short time. It’s also non-invasive and relatively simple. Just remember to always start with a clean working directory and reset it after you are done! Feel free to use it anytime you are in need to search through your history.
Of course, the full manual is available by typing: `git help bisect`.
References:
- https://git-scm.com
- https://github.com/git/git
- https://git-scm.com/book/en/v2
- https://stackoverflow.com/questions/5188914/how-to-show-first-commit-by-git-log