bashgitgit-bisect

How to perform a git bisect if I don't know which old commit is good?


In git, we have bisect to conveniently find the first bad commit, in this way:

git bisect start linux-next/master v2.6.26-rc8
git bisect run make kernel/fork.o

But the prerequisite is I know which old commit is good. In this example, it is v2.6.26-rc8.

What happens if I don't know which commit is good?

Is it possible to write a script, to reversely loop through the git commits, begin from current HEAD, from latest to oldest, and automatically test each commit, until the first good?


Solution

  • git bisect does a binary search through the commit history. good and bad simply provide boundaries for this search. Git then searches within that range for a commit which is "bad" and the previous one was "good".

    All that matters is the "good" commit is before the feature broke, and the "bad" commit is after the feature broke. If you're not sure when the feature broke, pick a commit before the feature was introduced.

    If you're not sure, pick a really old commit. You can even pick the first commit. This isn't as absurd as it sounds. Binary searches are very efficient; 10,000 commits can be searched in just log2(10000) tries or 13 tries.

    For example, let's say your commit history looks like this.

    a - b - c - d - e - f - g - h - i [main]
    

    You know the feature is broken now, you don't know when it was good, but you do know it was introduced at d. Pick c, the commit immediately before the feature was introduced, as the "good" commit.

    $ git bisect start
    $ git bisect bad
    $ git bisect good c
    
                                   HEAD
    a - b - c - d - e - f - g - h - i [main]
            g                       b
    

    Then git bisect will do a binary search of d - e - f - g - h until it finds a bad commit immediately after a good one.

    In this case it will start with f. Let's say that's bad.

    $ git bisect bad
    
                       HEAD
    a - b - c - d - e - f - g - h - i [main]
            g           b           b
    

    Git assumes everything after f is also bad. Then it might try d. Let's say that's good.

    $ git bisect good
    
               HEAD
    a - b - c - d - e - f - g - h - i [main]
            g   g       b           b
    

    Then it will try e. Let's say that's bad.

    $ git bisect bad
    
                   HEAD
    a - b - c - d - e - f - g - h - i [main]
            g   g   b   b           b
    

    e broke the feature.