git bisect run — Automated Bug Hunting
Computer test kare, computer good/bad bole, tu bas result dekh — yeh hai automated bisect.
Manual bisect requires you to test each commit yourself and run git bisect good or git bisect bad repeatedly. For 10 steps, that means 10 manual tests. Boring, error-prone, and slow.
If you have an automated test that fails for the bug, git bisect run does EVERYTHING automatically. You write a test script. Git runs it at each commit. The script returns an exit code. Git marks the commit good or bad automatically. No human interaction needed.
The power: 1000 commits, 10 automated steps, zero human interaction. Go get coffee while bisect works. Come back to "abc1234 is the first bad commit."
When to use bisect run: you have a failing test, a reproducible crash, or a build error that can be checked programmatically.
When NOT to use: visual bugs, subjective issues, non-deterministic bugs — things a script cannot reliably test.
# Manual bisect — you do the testing
git bisect start
git bisect bad HEAD
git bisect good v1.0.0
# Git checks out commit → YOU run tests → YOU say good/bad
# Repeat 10 times... boring, error-prone, slow
# Automated bisect — script does the testing
git bisect start
git bisect bad HEAD
git bisect good v1.0.0
git bisect run ./test-script.sh
# Git checks out commit → SCRIPT runs tests → SCRIPT returns exit code
# Git automatically marks good/bad → moves to next commit
# ... all automatically ...
# "abc1234 is the first bad commit"
# You just watch. Coffee time.
Your test script communicates with git bisect through EXIT CODES. This is the only language bisect understands — not text output, not print statements, not console logs. Just exit codes.
Exit code 0: "This commit is GOOD" — the bug is NOT present.
Exit code 1-124, 126-127: "This commit is BAD" — the bug IS present.
Exit code 125: "Cannot test this commit" — SKIP it. Use for broken builds, missing dependencies, migration failures.
Exit code 128+: ERROR — stop bisect entirely. Something is wrong with the script itself.
Most test frameworks return exit code 0 on pass, non-zero on fail. This maps perfectly to bisect:
npm testreturns 0 if all tests pass, 1 if any fails. Perfect for bisect run!pytestreturns 0 on pass, 1 on fail. Perfect.go testreturns 0 on pass, 1 on fail. Perfect.
# Exit code meanings for git bisect run:
# 0 = good (bug not present)
# 1-124 = bad (bug present)
# 125 = skip (cannot test this commit)
# 126-127 = bad (bug present)
# 128+ = error (stop bisect, something wrong)
# Simple test script
cat > test-bug.sh << 'EOF'
#!/bin/bash
# Run the test suite
npm test
# npm test returns:
# 0 if all tests pass (good)
# 1 if any test fails (bad)
EOF
chmod +x test-bug.sh
# More explicit version
cat > test-bug-explicit.sh << 'EOF'
#!/bin/bash
if npm test; then
exit 0 # good — tests pass, bug not present
else
exit 1 # bad — tests fail, bug is present
fi
EOF
chmod +x test-bug-explicit.sh
npm test, pytest, go test — they all return 0 on pass and 1 on fail. For many projects, git bisect run npm test just works. You only need a custom script when you need to install dependencies, build, or handle edge cases like exit code 125.Your script must be DETERMINISTIC: same commit + same script = same result every time. If your script returns different exit codes for the same commit, bisect will give wrong answers.
Your script must be FAST: it runs multiple times. 10 runs of a 5-minute test = 50 minutes. Keep it short. Target only the relevant test.
Your script must be SELF-CONTAINED: install dependencies, build, and test within the script if needed. Bisect checks out old commits where your current setup might not work.
Use exit code 125 for commits that cannot be tested. Build broken? Exit 125. Dependency missing? Exit 125. Git will skip those commits and try nearby ones.
Script pattern: build → test → return exit code.
Always make the script executable: chmod +x script.sh.
For compiled languages, your script should compile AND run. If compilation fails → exit 125 (skip).
# Complete bisect test script template
cat > bisect-test.sh << 'EOF'
#!/bin/bash
set -e
# 1. Install dependencies (skip if fails)
npm install --silent 2>/dev/null || exit 125
# 2. Build the project (skip if fails)
npm run build --silent 2>/dev/null || exit 125
# 3. Run the TARGETED test (not full suite)
npx jest tests/login.test.js --no-coverage 2>/dev/null
exit $?
EOF
chmod +x bisect-test.sh
# Test it manually first!
./bisect-test.sh; echo "Exit code: $?"
# Should return 0 or 1 for normal commits
# Should return 125 for commits that can't build
# Then use with bisect
git bisect run ./bisect-test.sh
JavaScript/Node.js: git bisect run npm test — works directly if your test suite has a failing test for the bug.
Python: git bisect run pytest tests/test_login.py — target specific test file.
Go: git bisect run go test ./pkg/auth/... — test specific package.
Custom script: for bugs that don't have a test yet, write a quick reproduction script.
Build failures: git bisect run make — find which commit broke the build.
Performance regressions: script that measures execution time and returns 1 if too slow.
# Example 1: Node.js project — find which commit broke a test
git bisect start
git bisect bad HEAD
git bisect good v2.0.0
git bisect run npm test
# npm test runs, returns 0 or 1, bisect handles the rest
# Example 2: Custom reproduction script for a crash
cat > reproduce-crash.sh << 'EOF'
#!/bin/bash
# Build the project
npm run build || exit 125 # skip if build fails
# Run the app and check if it crashes
timeout 5 node dist/app.js --test-mode
if [ $? -eq 0 ]; then
exit 0 # app ran successfully — good
else
exit 1 # app crashed — bad
fi
EOF
chmod +x reproduce-crash.sh
git bisect run ./reproduce-crash.sh
# Example 3: Python — find which commit broke specific test
git bisect start
git bisect bad HEAD
git bisect good v1.5.0
git bisect run pytest tests/test_api.py::test_login
# Example 4: Go — find build failure
git bisect start
git bisect bad HEAD
git bisect good v3.0.0
git bisect run go build ./...
If bisect run gets stuck or gives wrong results, interrupt it with Ctrl+C and run git bisect reset.
Common problems and fixes:
- Script not executable →
chmod +x script.sh - Script depends on files not in repo → add them or handle in script
- Build fails at some commits → return exit code 125 to skip
- Test is flaky → run test multiple times in script, return bad only if consistently fails
- Missing dependencies → install in script or use exit 125
For large repos, bisect run can be slow because each step may require npm install or make.
Optimize: cache dependencies, install only what changed, use incremental builds.
# Handling flaky tests in bisect run
cat > robust-bisect.sh << 'EOF'
#!/bin/bash
# Install deps (skip if impossible)
npm ci --silent 2>/dev/null || exit 125
# Run test 3 times — only mark bad if consistently fails
FAIL_COUNT=0
for i in 1 2 3; do
npx jest tests/login.test.js --no-coverage 2>/dev/null || FAIL_COUNT=$((FAIL_COUNT+1))
done
if [ $FAIL_COUNT -ge 2 ]; then
exit 1 # consistently bad
else
exit 0 # probably good (maybe 1 flaky failure)
fi
EOF
# Smart dependency caching
cat > smart-bisect.sh << 'EOF'
#!/bin/bash
# Only reinstall if package.json changed
if [ ! -d "node_modules" ] || [ package.json -nt node_modules ]; then
npm install --silent 2>/dev/null || exit 125
fi
npx jest tests/login.test.js --no-coverage 2>/dev/null
exit $?
EOF
Lo kar liya — Key Points:
- ✅ git bisect run automates the testing — you provide a script, Git runs it at each commit
- ✅ Exit code 0 = good (no bug), 1-124 and 126-127 = bad (bug exists), 125 = skip (cannot test)
- ✅ Most test frameworks (npm test, pytest, go test) return 0 on pass and 1 on fail — perfect for bisect run
- ✅ Your test script must be deterministic, fast, and self-contained — it runs multiple times automatically
- ✅ Use exit code 125 for commits that cannot be tested (build failures, missing dependencies)
- ✅ Target your test script to the specific bug — don't run the entire test suite if only one test fails
- ✅ Always chmod +x your script before running bisect run — non-executable scripts cause immediate failure
Want to track your progress?
Log in to save your place and pick up where you left off.
Progress track karna chahte ho?
Login karo apni progress save karne ke liye aur jahan chhoda tha wahan se shuru karo.
Login