How to find a commit introducing a bug?

git bisect start
git bisect bad
git bisect good

To find a commit introducing a bug search your commits with git bisect. You will need to mark a working version of your code with git bisect good and the buggy version with git bisect bad.

After this, bisect will search your commits and let you decide if the given version has the bug or not, until you find the commit introducing the bug.

Let's try bisect with a simple example. We have a dummy ruby script, which is supposed to add two numbers, but the result is incorrect:

Layer 1
Terminal Example
ruby math.rb 2 3
-1

We know, that it worked, when it was first commited (commit with SHA 5dd0af3) and that it's not working in the current version (HEAD).

Layer 1
Terminal Example
git log --oneline
(HEAD -> main) Use if instead of case
2527a94 Fix operation name issue
322b7b5 Only support existing operators or nil
37ac958 Rename operations
15e4354 Use operation based on param
6927057 Support operator param
6c6725c Add division
cfb26cd Add multiplication
ba9a893 Add substraction
ccc2c6f Add arguments
5dd0af3 Rename addition to math
a944039 Add addition.rb

To start bisecting, we need to run git bisect start and mark one working and one failing version of our code. The currently checked out commit (HEAD) is failing, which we mark with git bisect bad. The working version we found earlier is marked with git bisect good 5dd0af3.

Layer 1
Terminal Example
git bisect start

git bisect bad

git bisect good 5dd0af3
Bisecting: 4 revisions left to test after this (roughly 2 steps)
[69270572fd6450f0b0f57f4a5e783a0099080577] Support operator param

After having marked the bad and the good version of the code, git starts bisecting with an automatic checkout of a version (6927057) we should test next.

We run the ruby script again, and see that it adds the numbers correctly. The bug was not yet introduced in this commit, which we mark with git bisect good.

Layer 1
Terminal Example
ruby math.rb 2 3
5
git bisect good
Bisecting: 2 revisions left to test after this (roughly 1 step)
[37ac958e3983e2869269da3f816c8dda8d2149f3] Rename operations

Git checks out the next commit for us to test (37ac958), in which the ruby script is not working properly and we mark the commit with git bisect bad.

Layer 1
Terminal Example
ruby math.rb 2 3
-1
git bisect bad
Bisecting: 0 revisions left to test after this (roughly 0 steps)
[15e435418ba2279217bae9ed70c65a112609234b] Use operation based on param

We need to repeat these steps of testing the script and marking the commit as good or bad until git finds and shows us the commit introducing the bug.

In this example it's commit "Rename operations" (37ac958):

Layer 1
Terminal Example
ruby math.rb 2 3
5
git bisect good
37ac958e3983e2869269da3f816c8dda8d2149f3 is the first bad commit
commit 37ac958e3983e2869269da3f816c8dda8d2149f3
Author: Tom Ato
Date:   Fri Dec 3 17:06:32 2021 +0100

    Rename operations

 math.rb | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

Once we found the bad commit, we can clean up the bisection state with git bisect reset and git will return to the original HEAD, where we started bisecting.

We can also show the changes introduced with the buggy commit and see where the operation return a + b was changed to return a - b, breaking our code.

Layer 1
Terminal Example
git bisect reset
Previous HEAD position was 15e4354 Use operation based on param
Switched to branch 'main'

git show 37ac958e3983e2869269da3f816c8dda8d2149f3
commit 37ac958e3983e2869269da3f816c8dda8d2149f3
Author: Tom Ato
Date:   Fri Dec 3 17:06:32 2021 +0100

    Rename operations

diff --git a/math.rb b/math.rb
index e819de6..f79219d 100644
--- a/math.rb
+++ b/math.rb
@@ -1,17 +1,17 @@

-def add(a, b)
-  return a + b
+def operation_add(a, b)
+  return a - b
 end

See git bisect to learn more about it.

Last modified on December 04, 2021.

You might also like