Published: May 17, 2022 • 3 min read
Something is broken, you can’t figure out why, and you’re wondering: how and when did this break?
Maybe there are a lot of changes to consider, and isolating that breaking change is hard.
Or, maybe you’re curious how things break in your organization so you can improve.
The command-line tool for this situation is
git bisect. Git bisect is a
binary search through your Git commit history. Let’s walk through it.
HEAD, and something is broken. A white screen. An
Indicate this as your starting point with
$ git bisect start (git)-[master|bisect]-$
Now we’re at
master in a bisect, per the prompt.
Note that this commit is broken with
$ git bisect bad (git)-[master|bisect]-$
You can verify that it did something with
git show, or any command that shows
$ git show commit 8bec317a (HEAD -> master, refs/bisect/bad)
bad ref at the end.
Now, we need to find a commit in the past where things worked. I usually jump back twenty commits to start. When in doubt, jump farther.
$ git checkout HEAD~20 Note: switching to 'HEAD~20'.
Test your code again. Still broken? If so, jump back again.
Once you find a place where it isn’t broken, that’s a ‘good’ place. Make a note:
$ git bisect good Bisecting: 22 revisions left to test after this (roughly 5 steps) [69d80fa4acjad4bd38e0b802ab87d4a6a3279c40] Merge pull request #8 from repo/branch
As the prompt explains, we are roughly five steps from an answer!
Time to bisect. Test your code again. Still broken? If so, make a note:
$ git bisect bad Bisecting: 11 revisions left to test after this (roughly 4 steps) [56988ajc43ab972baf43984a18f4580971cc2450] Remove deprecation warning
Or, if it isn’t broken, swap
Keep this up until there are no more commits to test. You’ll see a conclusion like this:
(git)-[v0.2.21~1|bisect]-$ git bisect bad c66d2c2daja91def4aaaf107da9136c43861296f is the first bad commit commit c66d2c2daja91def4aaaf107da9136c43861296f Author: Some Dev <email@example.com> Date: Tue Aug 28 14:57:00 2018 -0700 Quickpush to fix all the bugs 😅 example.gemspec | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
show your bad commit to learn more.
$ git show c66d2c2daja91def4aaaf107da9136c43861296f
Lastly, exit with
$ git bisect reset Switched to branch 'master'
# Start $ git bisect start # Test your feature and find out it's broken $ git bisect bad # Travel backwards $ git checkout HEAD~<n> # Test your feature and find out it works $ git bisect good # The bisect continues...
Got a program that returns
0 for success or
1 for error, like a unit test?
Use it to automate your bisect.
$ git bisect start $ git bisect bad $ git checkout <good-ref> $ git bisect good $ git bisect run <rspec spec/demonstrates_the_feature_spec.rb>
For bisect to be useful, you must be committing atomically. If your practice is to squash-merge PR’s, or commit swaths of unrelated code with each commit, bisect is only going to tell you that something broke when you merged in a ton of changes. That isn’t typically useful information.
Why bother with this technique? Why not just fix the issue and move on?
My advice is to try it a few times when you’re stuck debugging and see. When I have used it, I’ve felt like a forensic scientist, able to glean insights about a tough problem. Insights that would have taken me much longer to arrive at another way.
bisect? How has it helped you? Let me know in the comments.
✉️ Get better at programming by learning with me. Subscribe to Jake Worth's Newsletter for bi-weekly ideas, creations, and curated resources from across the world of programming. Join me today!
Blog of Jake Worth, software engineer in Maine.