39 | Finding Bugs with bisect |
Unit tests, code review, pair programming, and any number of practices help limit the number of bugs in your code. We all end up having to track down bugs, though. It’s part of software development. git bisect helps you limit the time you spend on this unpleasant task by helping you search through your repository’s history for the commit that introduced the bug.
git bisect works by dividing and conquering. You know that a particular commit has a bug in it, or is bad. You also know that a particular point in the past didn’t have that bug in it, or is good.
bisect takes the remaining commits, divides them in half, and sets your working tree to that midway point in the history. You can check your repository for the bug and mark it as either good or bad. Repeat until you narrow the list of possible commits down to the commit that introduced the bug.
You can skip a commit if there’s no way to test it. Be careful skipping commits, however. Skipping too many can make it impossible for Git to know which commit caused the bug.
After you’ve found the commit with the bug and determined how to fix it, you need to move back to the original branch where you started. git bisect reset takes care of that.
You can automate the process of marking a commit as good or bad with a script. It can be any shell script. The script must use its exit status code to mark whether the commit it is testing is good, is bad, or should be skipped. There are three possible exit code status that cause bisect to mark a commit as good, as bad, or as skipped:
0 to mark as good
1 or greater to mark as bad
125 to skip
Git changes your working tree between each test, so make sure that the script you give to git bisect run is independent of the repository history. Create the simplest possible test and put it outside of your working tree, and then use it there so git bisect doesn’t accidentally overwrite it.
What To Do... |
| prompt> git bisect start |
| prompt> git bisect bad |
| prompt> git bisect good <some commit id> |
| ... mark each commit as good or bad until you |
| ... have narrowed the list of commits down to the |
| ... commit with that introduces the bug |
| ... once you've found the commit and figured out |
| ... how to address it, run the following to return |
| ... back to the branch you started at |
| prompt> git bisect reset |
| prompt> git bisect start HEAD <some good commit id> |
| ... continue as above |
| prompt> git bisect start HEAD <some good commit id> |
| prompt> git bisect run /path/to/test/script |
| ... once you've figured out the fix |
| prompt> git bisect reset |
The commit to the right is HEAD, and the commit to the left is known to be good. git bisect cuts the repository in half, and through a process of elimination shows that HEAD^ is the commit that introduced the bug. Now, imagine there were 100 commits separating HEAD and the last known good commit!
Task 30, Viewing the Log
Task 32, Comparing Differences
Task 34, Assigning Blame
3.145.166.149