Find regressions with git bisect
When a bug appears in production but you know it worked in a previous release, manually reviewing hundreds of commits is tedious. Git bisect automates the search using binary search: you mark a known-good commit, mark a known-bad commit, provide a test command, and git automatically finds the exact commit that introduced the regression.
Automated Bisecting
The most powerful approach is automated bisecting with a test script. Suppose you're working on a Flutter application and discover a bug in your feature branch:
git bisect start git bisect bad feature/someNewFeatureWip # Current broken state git bisect good develop # Last known working state git bisect run sh -c 'flutter build && flutter test'
Git will checkout commits between good and bad, run your test at each step, and narrow down the problematic commit. The test command should exit with code 0 for success (good) or non-zero for failure (bad).
Manual Bisecting for Complex Issues
Not all bugs are caught by automated tests. For UI regressions, performance issues, or subtle behavior changes, you can bisect manually:
git bisect start git bisect bad HEAD git bisect good v1.2.0 # Git checks out a commit in the middle # Test manually, then mark it: git bisect good # or: git bisect bad # Repeat until git identifies the problematic commit
Manual bisecting is slower but works when reproduction requires human judgment or when tests don't cover the specific failure mode.
Best Practices
- Write atomic commits: Each commit should be a single logical change. Mixed changes make it hard to understand what caused the regression once you find the culprit.
-
Keep commits buildable: If intermediate commits don't compile, bisecting becomes painful.
Use
git bisect skipto bypass unbuildable commits. - Use fast tests: Bisecting runs your test repeatedly. A 10-minute test suite over 100 commits means 16+ hours of waiting. Create a minimal reproduction test for bisecting.
- Script the reproduction: Even for "manual" issues, try to script the setup. This makes bisecting faster and more consistent.
Advanced: Custom Test Scripts
You can use more sophisticated test scripts that handle setup and cleanup:
#!/bin/bash # bisect_test.sh # Clean previous build artifacts make clean # Build current commit make || exit 125 # 125 = untestable (skip) # Run specific test ./run_test --timeout=30 || exit 1 # 1 = bad exit 0 # 0 = good
Then run: git bisect run ./bisect_test.sh
Exit code 125 tells git to skip commits that can't be tested (broken build, missing dependencies, etc.).