Find Buggy Commits Faster with git bisect run: Don’t Let Debugging Be a Nightmare

Git tutorial - IT technology blog
Git tutorial - IT technology blog

The Nightmare Called “Regression Bugs”

Monday morning at the office, a client reports an urgent production bug. You realize a critical feature has vanished, even though it worked perfectly last week. The real nightmare begins when looking at the Git history: the team merged over 200 commits in the past two weeks.

Manually reviewing every commit to find the breaking point is torture. Previously, I used git bisect the traditional way. I’d pick an old commit known to be good, select the current bad commit, and let Git jump to the middle. At each stop, I had to build the code, test it manually, then type git bisect good or bad. This process repeated 7-10 times until the culprit was found.

While faster than checking every commit, this still wasted time waiting for builds. Everything changed when I discovered the git bisect run command. Instead of babysitting the terminal, I just write a small test script and go grab a coffee. When I return, Git has pinpointed the exact commit causing the error. This technique saved me during a high-pressure release, uncovering a logic bug buried deep within 5,000 lines of new code.

Git bisect run – Let Your Computer Hunt Bugs for You

Git uses a binary search algorithm to optimize tracing. With a list of 1,000 commits, you only need a maximum of 10 checks to identify the exact location of the bug.

The difference with git bisect run is its ability to execute an automated script. Git automatically checks out the next commit and runs that script. Based on the return value, Git decides whether the commit is “good” or “bad” and continues jumping until it reaches the final result.

Operating Principles: The Power of Exit Codes

For git bisect run to work correctly, your script must return exit codes according to convention:

  • Exit code 0: The commit is working fine (Good).
  • Exit code from 1 to 127 (except 125): The commit is faulty (Bad).
  • Exit code 125: This commit cannot be tested (e.g., unrelated build error); Git will skip it and pick a nearby commit.

By simply writing a script (Bash, Python, Node.js…) that returns 0 on success and 1 on failure, you’ve automated the entire bug-tracing process.

Hands-on: Automating the Tracing Process

Suppose you have a Node.js project with a calculation logic error. You know tag v1.0 was correct, but the current HEAD gives the wrong result.

Step 1: Write a Test Script (test.sh)

Create a test.sh file to perform the automated checks. You should place this file in the parent directory (outside the repo) to prevent it from being affected when Git checks out different commits.

#!/bin/bash

# 1. Update dependencies if commits changed package.json
npm install

# 2. Run specific logic test script
# test_logic.js will throw an error if the result is not as expected
node test_logic.js

# 3. Return the status of the previous command
exit $?

If you only need to check if a file contains a specific buggy keyword, use grep for a quick solution:

#!/bin/bash
# If the string "buggy_function" is found, consider the commit bad
! grep -q "buggy_function" src/utils.js

Step 2: Activate Automated Mode

Open your terminal and command Git to start working:

git bisect start

# Mark the start and end points
git bisect bad
git bisect good v1.0

# Activate automated mode with the script
git bisect run sh ../test.sh

Git will start jumping through commits and running the script continuously. After a few minutes, the screen will display the most important notification:

f7a3b2c... is the first bad commit

Pro-Tips to Avoid Pitfalls

After applying this several times with a team of 8, I’ve gathered 4 key tips to maximize the effectiveness of bisect run:

  1. Clean Environment: The script should include cleanup or environment setup steps (like npm install). Otherwise, stale dependencies might skew test results between commits.
  2. Prioritize Speed: Git will run the script multiple times. Instead of running a 20-minute full test suite, write a small test case focused solely on the specific bug.
  3. File Paths: Always use absolute paths or place the script outside the project directory. This ensures the script isn’t lost or modified as Git travels back in time.
  4. Execution Permissions: Always remember to run chmod +x test.sh before starting on Linux or macOS.

Conclusion

Finding the buggy commit often accounts for 50% of the troubleshooting time. With git bisect run, you offload the most tedious task to your computer.

In a previous project, I encountered a broken CSS layout that was very hard to track down. I wrote a script using Puppeteer to take screenshots and compare pixels automatically. As a result, I found the exact commit that accidentally modified a global CSS variable after just 5 minutes of execution. Next time you face a difficult bug, don’t rush into the code manually—let Git be your detective.

Share: