People rant about having to learn algorithmic questions for interviews. I get it — interview system is broken, but you ought to learn binary search at least.
Anyways, yet again I came across a real life application of Algorithms. This time in the OG tool git. git bisect - Use binary search to find the commit that introduced a bug ref. And Leetcode wanted you to know it First Bad Version
We use a monorepo at work. And people tend to make hundreds, if not thousands, commit in a single repo a day. On this day, our tests started failing, and the logs weren’t enough to debug or trace the root cause. The failing method depended on a configuration file that made a remote call using a specific role to obtain a token for running the tests. At some point, that configuration had been changed — a string was updated to reference a different account — which caused the failure.
Somehow, the bad change slipped through integration tests unnoticed. It was difficult to manually find the exact file or commit that introduced the issue since many commits had been made across the repository over the past few days.
That’s when a teammate from another team — who was facing the same test failures — ran a few “magical” commands and quickly identified the exact commit where things started to break. The basic idea was simple but brilliant: pick a known good commit and a known bad one, then run a binary search to find the exact commit that caused the failure.
It took a while since each test run was time-consuming, but eventually, it pinpointed the precise commit that introduced the issue. And sure enough, after reverting that commit, everything went back to green.
Here’s a small demo repository that shows how git bisect finds the first bad commit.
File tree:
git-bisect-demo/
├── calc.py # the library under test
├── test_calc.py # a pytest test for calc.add
└── test_script.sh # wrapper used by `git bisect run`
Good version of calc.py (commit where tests pass):
def add(a, b):
return a + b
if __name__ == "__main__":
print(add(2, 3))
Bad version of calc.py (commit that introduced the bug):
def add(a, b):
# accidental string concatenation when inputs are coerced to str
return str(a) + str(b)
if __name__ == "__main__":
print(add(2, 3))
test_calc.py (pytest):
import calc
def test_add():
assert calc.add(2, 3) == 5, "Addition failed!"
test_script.sh — used by git bisect run to return exit code 0 on success and non-zero on failure:
#!/usr/bin/env bash
set -e
pytest -q
Example commit history (chronological):
- Commit 1: Initial commit (good)
- Commit 2: Small refactor (still good)
- Commit 3: Bug introduced (bad)
- Commits 4..10: Non-functional edits / comments (remain bad)
We can run git bisect like this:
git bisect start
git bisect bad HEAD
git bisect good HEAD~9
git bisect run ./test_script.sh
status: waiting for both good and bad commits
status: waiting for good commit(s), bad commit known
Bisecting: 4 revisions left to test after this (roughly 2 steps)
[8dad374fd7c097c4fa3521c0b259e1eefe533520] Commit 5: more changes
running './test_script.sh'
Bisecting: 1 revision left to test after this (roughly 1 step)
[b982ed9373fe235fe61c74b15faf264bc7142398] Commit 3: introduced bug
running './test_script.sh'
Bisecting: 0 revisions left to test after this (roughly 0 steps)
[7b59759ca785572797e04f6b313bb0b735c22529] Commit 2: minor refactor
running './test_script.sh'
b982ed9373fe235fe61c74b15faf264bc7142398 is the first bad commit
commit b982ed9373fe235fe61c74b15faf264bc7142398
Author: Kevin
Date: Sun Nov 2 10:54:47 2025 -0500
Commit 3: introduced bug
calc.py | 10 +---------
1 file changed, 1 insertion(+), 9 deletions(-)
git bisect will checkout intermediate commits and run ./test_script.sh until it finds the first commit that makes the tests fail.