Skip to content
Snippets Groups Projects
git-bisect-lk2009.txt 48.3 KiB
Newer Older
  • Learn to ignore specific revisions
  • 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475
    Fighting regressions with git bisect
    ====================================
    :Author: Christian Couder
    :Email: chriscool@tuxfamily.org
    :Date: 2009/11/08
    
    Abstract
    --------
    
    "git bisect" enables software users and developers to easily find the
    commit that introduced a regression. We show why it is important to
    have good tools to fight regressions. We describe how "git bisect"
    works from the outside and the algorithms it uses inside. Then we
    explain how to take advantage of "git bisect" to improve current
    practices. And we discuss how "git bisect" could improve in the
    future.
    
    
    Introduction to "git bisect"
    ----------------------------
    
    Git is a Distributed Version Control system (DVCS) created by Linus
    Torvalds and maintained by Junio Hamano.
    
    In Git like in many other Version Control Systems (VCS), the different
    states of the data that is managed by the system are called
    commits. And, as VCS are mostly used to manage software source code,
    sometimes "interesting" changes of behavior in the software are
    introduced in some commits.
    
    In fact people are specially interested in commits that introduce a
    "bad" behavior, called a bug or a regression. They are interested in
    these commits because a commit (hopefully) contains a very small set
    of source code changes. And it's much easier to understand and
    properly fix a problem when you only need to check a very small set of
    changes, than when you don't know where look in the first place.
    
    So to help people find commits that introduce a "bad" behavior, the
    "git bisect" set of commands was invented. And it follows of course
    that in "git bisect" parlance, commits where the "interesting
    behavior" is present are called "bad" commits, while other commits are
    called "good" commits. And a commit that introduce the behavior we are
    interested in is called a "first bad commit". Note that there could be
    more than one "first bad commit" in the commit space we are searching.
    
    So "git bisect" is designed to help find a "first bad commit". And to
    be as efficient as possible, it tries to perform a binary search.
    
    
    Fighting regressions overview
    -----------------------------
    
    Regressions: a big problem
    ~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    Regressions are a big problem in the software industry. But it's
    difficult to put some real numbers behind that claim.
    
    There are some numbers about bugs in general, like a NIST study in
    2002 <<1>> that said:
    
    _____________
    Software bugs, or errors, are so prevalent and so detrimental that
    they cost the U.S. economy an estimated $59.5 billion annually, or
    about 0.6 percent of the gross domestic product, according to a newly
    released study commissioned by the Department of Commerce's National
    Institute of Standards and Technology (NIST). At the national level,
    over half of the costs are borne by software users and the remainder
    by software developers/vendors.  The study also found that, although
    all errors cannot be removed, more than a third of these costs, or an
    estimated $22.2 billion, could be eliminated by an improved testing
    infrastructure that enables earlier and more effective identification
    and removal of software defects. These are the savings associated with
    finding an increased percentage (but not 100 percent) of errors closer
    to the development stages in which they are introduced. Currently,
    over half of all errors are not found until "downstream" in the
    development process or during post-sale software use.
    _____________
    
    And then:
    
    _____________
    Software developers already spend approximately 80 percent of
    development costs on identifying and correcting defects, and yet few
    products of any type other than software are shipped with such high
    levels of errors.
    _____________
    
    Eventually the conclusion started with:
    
    _____________
    The path to higher software quality is significantly improved software
    testing.
    _____________
    
    There are other estimates saying that 80% of the cost related to
    software is about maintenance <<2>>.
    
    Though, according to Wikipedia <<3>>:
    
    _____________
    A common perception of maintenance is that it is merely fixing
    bugs. However, studies and surveys over the years have indicated that
    the majority, over 80%, of the maintenance effort is used for
    non-corrective actions (Pigosky 1997). This perception is perpetuated
    by users submitting problem reports that in reality are functionality
    enhancements to the system.
    _____________
    
    But we can guess that improving on existing software is very costly
    because you have to watch out for regressions. At least this would
    make the above studies consistent among themselves.
    
    Of course some kind of software is developed, then used during some
    time without being improved on much, and then finally thrown away. In
    this case, of course, regressions may not be a big problem. But on the
    other hand, there is a lot of big software that is continually
    developed and maintained during years or even tens of years by a lot
    of people. And as there are often many people who depend (sometimes
    critically) on such software, regressions are a really big problem.
    
    One such software is the Linux kernel. And if we look at the Linux
    kernel, we can see that a lot of time and effort is spent to fight
    regressions. The release cycle start with a 2 weeks long merge
    window. Then the first release candidate (rc) version is tagged. And
    after that about 7 or 8 more rc versions will appear with around one
    week between each of them, before the final release.
    
    The time between the first rc release and the final release is
    supposed to be used to test rc versions and fight bugs and especially
    regressions. And this time is more than 80% of the release cycle
    time. But this is not the end of the fight yet, as of course it
    continues after the release.
    
    And then this is what Ingo Molnar (a well known Linux kernel
    developer) says about his use of git bisect:
    
    _____________
    I most actively use it during the merge window (when a lot of trees
    get merged upstream and when the influx of bugs is the highest) - and
    yes, there have been cases that i used it multiple times a day. My
    average is roughly once a day.
    _____________
    
    So regressions are fought all the time by developers, and indeed it is
    well known that bugs should be fixed as soon as possible, so as soon
    as they are found. That's why it is interesting to have good tools for
    this purpose.
    
    Other tools to fight regressions
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    So what are the tools used to fight regressions? They are nearly the
    same as those used to fight regular bugs. The only specific tools are
    test suites and tools similar as "git bisect".
    
    Test suites are very nice. But when they are used alone, they are
    supposed to be used so that all the tests are checked after each
    commit. This means that they are not very efficient, because many
    tests are run for no interesting result, and they suffer from
    combinatorial explosion.
    
    In fact the problem is that big software often has many different
    configuration options and that each test case should pass for each
    configuration after each commit. So if you have for each release: N
    configurations, M commits and T test cases, you should perform:
    
    -------------
    N * M * T tests
    -------------
    
    where N, M and T are all growing with the size your software.
    
    So very soon it will not be possible to completely test everything.
    
    And if some bugs slip through your test suite, then you can add a test
    to your test suite. But if you want to use your new improved test
    suite to find where the bug slipped in, then you will either have to
    emulate a bisection process or you will perhaps bluntly test each
    commit backward starting from the "bad" commit you have which may be
    very wasteful.
    
    "git bisect" overview
    ---------------------
    
    Starting a bisection
    ~~~~~~~~~~~~~~~~~~~~
    
    The first "git bisect" subcommand to use is "git bisect start" to
    start the search. Then bounds must be set to limit the commit
    space. This is done usually by giving one "bad" and at least one
    "good" commit. They can be passed in the initial call to "git bisect
    start" like this:
    
    -------------
    $ git bisect start [BAD [GOOD...]]
    -------------
    
    or they can be set using:
    
    -------------
    $ git bisect bad [COMMIT]
    -------------
    
    and:
    
    -------------
    $ git bisect good [COMMIT...]
    -------------
    
    where BAD, GOOD and COMMIT are all names that can be resolved to a
    commit.
    
    Then "git bisect" will checkout a commit of its choosing and ask the
    user to test it, like this:
    
    -------------
    $ git bisect start v2.6.27 v2.6.25
    Bisecting: 10928 revisions left to test after this (roughly 14 steps)
    [2ec65f8b89ea003c27ff7723525a2ee335a2b393] x86: clean up using max_low_pfn on 32-bit
    -------------
    
    Note that the example that we will use is really a toy example, we
    will be looking for the first commit that has a version like
    "2.6.26-something", that is the commit that has a "SUBLEVEL = 26" line
    in the top level Makefile. This is a toy example because there are
    better ways to find this commit with Git than using "git bisect" (for
    example "git blame" or "git log -S<string>").
    
    Driving a bisection manually
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    At this point there are basically 2 ways to drive the search. It can
    be driven manually by the user or it can be driven automatically by a
    script or a command.
    
    If the user is driving it, then at each step of the search, the user
    will have to test the current commit and say if it is "good" or "bad"
    using the "git bisect good" or "git bisect bad" commands respectively
    that have been described above. For example:
    
    -------------
    $ git bisect bad
    Bisecting: 5480 revisions left to test after this (roughly 13 steps)
    [66c0b394f08fd89236515c1c84485ea712a157be] KVM: kill file->f_count abuse in kvm
    -------------
    
    And after a few more steps like that, "git bisect" will eventually
    find a first bad commit:
    
    -------------
    $ git bisect bad
    2ddcca36c8bcfa251724fe342c8327451988be0d is the first bad commit
    commit 2ddcca36c8bcfa251724fe342c8327451988be0d
    Author: Linus Torvalds <torvalds@linux-foundation.org>
    Date:   Sat May 3 11:59:44 2008 -0700
    
        Linux 2.6.26-rc1
    
    :100644 100644 5cf82581... 4492984e... M      Makefile
    -------------
    
    At this point we can see what the commit does, check it out (if it's
    not already checked out) or tinker with it, for example:
    
    -------------
    $ git show HEAD
    commit 2ddcca36c8bcfa251724fe342c8327451988be0d
    Author: Linus Torvalds <torvalds@linux-foundation.org>
    Date:   Sat May 3 11:59:44 2008 -0700
    
        Linux 2.6.26-rc1
    
    diff --git a/Makefile b/Makefile
    index 5cf8258..4492984 100644
    --- a/Makefile
    +++ b/Makefile
    @@ -1,7 +1,7 @@
     VERSION = 2
     PATCHLEVEL = 6
    -SUBLEVEL = 25
    -EXTRAVERSION =
    +SUBLEVEL = 26
    +EXTRAVERSION = -rc1
     NAME = Funky Weasel is Jiggy wit it
    
     # *DOCUMENTATION*
    -------------
    
    And when we are finished we can use "git bisect reset" to go back to
    the branch we were in before we started bisecting:
    
    -------------
    $ git bisect reset
    Checking out files: 100% (21549/21549), done.
    Previous HEAD position was 2ddcca3... Linux 2.6.26-rc1
    Switched to branch 'master'
    -------------
    
    Driving a bisection automatically
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    The other way to drive the bisection process is to tell "git bisect"
    to launch a script or command at each bisection step to know if the
    current commit is "good" or "bad". To do that, we use the "git bisect
    run" command. For example:
    
    -------------
    $ git bisect start v2.6.27 v2.6.25
    Bisecting: 10928 revisions left to test after this (roughly 14 steps)
    [2ec65f8b89ea003c27ff7723525a2ee335a2b393] x86: clean up using max_low_pfn on 32-bit
    $
    $ git bisect run grep '^SUBLEVEL = 25' Makefile
    running grep ^SUBLEVEL = 25 Makefile
    Bisecting: 5480 revisions left to test after this (roughly 13 steps)
    [66c0b394f08fd89236515c1c84485ea712a157be] KVM: kill file->f_count abuse in kvm
    running grep ^SUBLEVEL = 25 Makefile
    SUBLEVEL = 25
    Bisecting: 2740 revisions left to test after this (roughly 12 steps)
    [671294719628f1671faefd4882764886f8ad08cb] V4L/DVB(7879): Adding cx18 Support for mxl5005s
    ...
    ...
    running grep ^SUBLEVEL = 25 Makefile
    Bisecting: 0 revisions left to test after this (roughly 0 steps)
    [2ddcca36c8bcfa251724fe342c8327451988be0d] Linux 2.6.26-rc1
    running grep ^SUBLEVEL = 25 Makefile
    2ddcca36c8bcfa251724fe342c8327451988be0d is the first bad commit
    commit 2ddcca36c8bcfa251724fe342c8327451988be0d
    Author: Linus Torvalds <torvalds@linux-foundation.org>
    Date:   Sat May 3 11:59:44 2008 -0700
    
        Linux 2.6.26-rc1
    
    :100644 100644 5cf82581... 4492984e... M      Makefile
    bisect run success
    -------------
    
    In this example, we passed "grep '^SUBLEVEL = 25' Makefile" as
    parameter to "git bisect run". This means that at each step, the grep
    command we passed will be launched. And if it exits with code 0 (that
    means success) then git bisect will mark the current state as
    "good". If it exits with code 1 (or any code between 1 and 127
    included, except the special code 125), then the current state will be
    marked as "bad".
    
    Exit code between 128 and 255 are special to "git bisect run". They
    make it stop immediately the bisection process. This is useful for
    example if the command passed takes too long to complete, because you
    can kill it with a signal and it will stop the bisection process.
    
    It can also be useful in scripts passed to "git bisect run" to "exit
    255" if some very abnormal situation is detected.
    
    Avoiding untestable commits
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    Sometimes it happens that the current state cannot be tested, for
    example if it does not compile because there was a bug preventing it
    at that time. This is what the special exit code 125 is for. It tells
    "git bisect run" that the current commit should be marked as
    untestable and that another one should be chosen and checked out.
    
    If the bisection process is driven manually, you can use "git bisect
    skip" to do the same thing. (In fact the special exit code 125 makes
    "git bisect run" use "git bisect skip" in the background.)
    
    Or if you want more control, you can inspect the current state using
    for example "git bisect visualize". It will launch gitk (or "git log"
    if the `DISPLAY` environment variable is not set) to help you find a
    better bisection point.
    
    Either way, if you have a string of untestable commits, it might
    happen that the regression you are looking for has been introduced by
    one of these untestable commits. In this case it's not possible to
    tell for sure which commit introduced the regression.
    
    So if you used "git bisect skip" (or the run script exited with
    special code 125) you could get a result like this:
    
    -------------
    There are only 'skip'ped commits left to test.
    The first bad commit could be any of:
    15722f2fa328eaba97022898a305ffc8172db6b1
    78e86cf3e850bd755bb71831f42e200626fbd1e0
    e15b73ad3db9b48d7d1ade32f8cd23a751fe0ace
    070eab2303024706f2924822bfec8b9847e4ac1b
    We cannot bisect more!
    -------------
    
    Saving a log and replaying it
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    If you want to show other people your bisection process, you can get a
    log using for example:
    
    -------------
    $ git bisect log > bisect_log.txt
    -------------
    
    And it is possible to replay it using:
    
    -------------
    $ git bisect replay bisect_log.txt
    -------------
    
    
    "git bisect" details
    --------------------
    
    Bisection algorithm
    ~~~~~~~~~~~~~~~~~~~
    
    As the Git commits form a directed acyclic graph (DAG), finding the
    best bisection commit to test at each step is not so simple. Anyway
    Linus found and implemented a "truly stupid" algorithm, later improved
    by Junio Hamano, that works quite well.
    
    So the algorithm used by "git bisect" to find the best bisection
    commit when there are no skipped commits is the following:
    
    1) keep only the commits that:
    
    a) are ancestor of the "bad" commit (including the "bad" commit itself),
    b) are not ancestor of a "good" commit (excluding the "good" commits).
    
    This means that we get rid of the uninteresting commits in the DAG.
    
    For example if we start with a graph like this:
    
    -------------
    G-Y-G-W-W-W-X-X-X-X
    	   \ /
    	    W-W-B
    	   /
    Y---G-W---W
     \ /   \
    Y-Y     X-X-X-X
    
    -> time goes this way ->
    -------------
    
    where B is the "bad" commit, "G" are "good" commits and W, X, and Y
    are other commits, we will get the following graph after this first
    step:
    
    -------------
    W-W-W
         \
          W-W-B
         /
    W---W
    -------------
    
    So only the W and B commits will be kept. Because commits X and Y will
    have been removed by rules a) and b) respectively, and because commits
    G are removed by rule b) too.
    
    Note for Git users, that it is equivalent as keeping only the commit
    given by:
    
    -------------
    git rev-list BAD --not GOOD1 GOOD2...
    -------------
    
    Also note that we don't require the commits that are kept to be
    descendants of a "good" commit. So in the following example, commits W
    and Z will be kept:
    
    -------------
    G-W-W-W-B
       /
    Z-Z
    -------------
    
    2) starting from the "good" ends of the graph, associate to each
    
       commit the number of ancestors it has plus one
    
    
    For example with the following graph where H is the "bad" commit and A
    and D are some parents of some "good" commits:
    
    -------------
    A-B-C
         \
          F-G-H
         /
    D---E
    -------------
    
    this will give:
    
    -------------
    1 2 3
    A-B-C
         \6 7 8
          F-G-H
    1   2/
    D---E
    -------------
    
    3) associate to each commit: min(X, N - X)
    
    where X is the value associated to the commit in step 2) and N is the
    total number of commits in the graph.
    
    In the above example we have N = 8, so this will give:
    
    -------------
    1 2 3
    A-B-C
         \2 1 0
          F-G-H
    1   2/
    D---E
    -------------
    
    4) the best bisection point is the commit with the highest associated
    
    
    So in the above example the best bisection point is commit C.
    
    5) note that some shortcuts are implemented to speed up the algorithm
    
    As we know N from the beginning, we know that min(X, N - X) can't be
    greater than N/2. So during steps 2) and 3), if we would associate N/2
    to a commit, then we know this is the best bisection point. So in this
    case we can just stop processing any other commit and return the
    current commit.
    
    Bisection algorithm debugging
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    For any commit graph, you can see the number associated with each
    commit using "git rev-list --bisect-all".
    
    For example, for the above graph, a command like:
    
    -------------
    $ git rev-list --bisect-all BAD --not GOOD1 GOOD2
    -------------
    
    would output something like:
    
    -------------
    e15b73ad3db9b48d7d1ade32f8cd23a751fe0ace (dist=3)
    15722f2fa328eaba97022898a305ffc8172db6b1 (dist=2)
    78e86cf3e850bd755bb71831f42e200626fbd1e0 (dist=2)
    a1939d9a142de972094af4dde9a544e577ddef0e (dist=2)
    070eab2303024706f2924822bfec8b9847e4ac1b (dist=1)
    a3864d4f32a3bf5ed177ddef598490a08760b70d (dist=1)
    a41baa717dd74f1180abf55e9341bc7a0bb9d556 (dist=1)
    9e622a6dad403b71c40979743bb9d5be17b16bd6 (dist=0)
    -------------
    
    Bisection algorithm discussed
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    First let's define "best bisection point". We will say that a commit X
    is a best bisection point or a best bisection commit if knowing its
    state ("good" or "bad") gives as much information as possible whether
    the state of the commit happens to be "good" or "bad".
    
    This means that the best bisection commits are the commits where the
    following function is maximum:
    
    -------------
    f(X) = min(information_if_good(X), information_if_bad(X))
    -------------
    
    where information_if_good(X) is the information we get if X is good
    and information_if_bad(X) is the information we get if X is bad.
    
    Now we will suppose that there is only one "first bad commit". This
    means that all its descendants are "bad" and all the other commits are
    "good". And we will suppose that all commits have an equal probability
    of being good or bad, or of being the first bad commit, so knowing the
    state of c commits gives always the same amount of information
    wherever these c commits are on the graph and whatever c is. (So we
    suppose that these commits being for example on a branch or near a
    good or a bad commit does not give more or less information).
    
    Let's also suppose that we have a cleaned up graph like one after step
    1) in the bisection algorithm above. This means that we can measure
    
       the information we get in terms of number of commit we can remove
       from the graph..
    
    
    And let's take a commit X in the graph.
    
    If X is found to be "good", then we know that its ancestors are all
    "good", so we want to say that:
    
    -------------
    information_if_good(X) = number_of_ancestors(X)  (TRUE)
    -------------
    
    And this is true because at step 1) b) we remove the ancestors of the
    "good" commits.
    
    If X is found to be "bad", then we know that its descendants are all
    "bad", so we want to say that:
    
    -------------
    information_if_bad(X) = number_of_descendants(X)  (WRONG)
    -------------
    
    But this is wrong because at step 1) a) we keep only the ancestors of
    the bad commit. So we get more information when a commit is marked as
    "bad", because we also know that the ancestors of the previous "bad"
    commit that are not ancestors of the new "bad" commit are not the
    first bad commit. We don't know if they are good or bad, but we know
    that they are not the first bad commit because they are not ancestor
    of the new "bad" commit.
    
    So when a commit is marked as "bad" we know we can remove all the
    commits in the graph except those that are ancestors of the new "bad"
    commit. This means that:
    
    -------------
    information_if_bad(X) = N - number_of_ancestors(X)  (TRUE)
    -------------
    
    where N is the number of commits in the (cleaned up) graph.
    
    So in the end this means that to find the best bisection commits we
    should maximize the function:
    
    -------------
    f(X) = min(number_of_ancestors(X), N - number_of_ancestors(X))
    -------------
    
    And this is nice because at step 2) we compute number_of_ancestors(X)
    and so at step 3) we compute f(X).
    
    Let's take the following graph as an example:
    
    -------------
                G-H-I-J
               /       \
    A-B-C-D-E-F         O
               \       /
                K-L-M-N
    -------------
    
    If we compute the following non optimal function on it:
    
    -------------
    g(X) = min(number_of_ancestors(X), number_of_descendants(X))
    -------------
    
    we get:
    
    -------------
                4 3 2 1
                G-H-I-J
    1 2 3 4 5 6/       \0
    A-B-C-D-E-F         O
               \       /
                K-L-M-N
                4 3 2 1
    -------------
    
    but with the algorithm used by git bisect we get:
    
    -------------
                7 7 6 5
                G-H-I-J
    1 2 3 4 5 6/       \0
    A-B-C-D-E-F         O
               \       /
                K-L-M-N
                7 7 6 5
    -------------
    
    So we chose G, H, K or L as the best bisection point, which is better
    than F. Because if for example L is bad, then we will know not only
    that L, M and N are bad but also that G, H, I and J are not the first
    bad commit (since we suppose that there is only one first bad commit
    and it must be an ancestor of L).
    
    So the current algorithm seems to be the best possible given what we
    initially supposed.
    
    Skip algorithm
    ~~~~~~~~~~~~~~
    
    When some commits have been skipped (using "git bisect skip"), then
    the bisection algorithm is the same for step 1) to 3). But then we use
    roughly the following steps:
    
    6) sort the commit by decreasing associated value
    
    7) if the first commit has not been skipped, we can return it and stop
    
    
    8) otherwise filter out all the skipped commits in the sorted list
    
    9) use a pseudo random number generator (PRNG) to generate a random
    
       number between 0 and 1
    
    
    10) multiply this random number with its square root to bias it toward
    
    
    11) multiply the result by the number of commits in the filtered list
    
        to get an index into this list
    
    
    12) return the commit at the computed index
    
    Skip algorithm discussed
    ~~~~~~~~~~~~~~~~~~~~~~~~
    
    After step 7) (in the skip algorithm), we could check if the second
    commit has been skipped and return it if it is not the case. And in
    fact that was the algorithm we used from when "git bisect skip" was
    developed in Git version 1.5.4 (released on February 1st 2008) until
    Git version 1.6.4 (released July 29th 2009).
    
    But Ingo Molnar and H. Peter Anvin (another well known linux kernel
    developer) both complained that sometimes the best bisection points
    all happened to be in an area where all the commits are
    untestable. And in this case the user was asked to test many
    untestable commits, which could be very inefficient.
    
    Indeed untestable commits are often untestable because a breakage was
    introduced at one time, and that breakage was fixed only after many
    other commits were introduced.
    
    This breakage is of course most of the time unrelated to the breakage
    we are trying to locate in the commit graph. But it prevents us to
    know if the interesting "bad behavior" is present or not.
    
    So it is a fact that commits near an untestable commit have a high
    probability of being untestable themselves. And the best bisection
    commits are often found together too (due to the bisection algorithm).
    
    This is why it is a bad idea to just chose the next best unskipped
    bisection commit when the first one has been skipped.
    
    We found that most commits on the graph may give quite a lot of
    information when they are tested. And the commits that will not on
    average give a lot of information are the one near the good and bad
    commits.
    
    So using a PRNG with a bias to favor commits away from the good and
    bad commits looked like a good choice.
    
    One obvious improvement to this algorithm would be to look for a
    commit that has an associated value near the one of the best bisection
    commit, and that is on another branch, before using the PRNG. Because
    if such a commit exists, then it is not very likely to be untestable
    too, so it will probably give more information than a nearly randomly
    chosen one.
    
    Checking merge bases
    ~~~~~~~~~~~~~~~~~~~~
    
    There is another tweak in the bisection algorithm that has not been
    described in the "bisection algorithm" above.
    
    We supposed in the previous examples that the "good" commits were
    ancestors of the "bad" commit. But this is not a requirement of "git
    bisect".
    
    Of course the "bad" commit cannot be an ancestor of a "good" commit,
    because the ancestors of the good commits are supposed to be
    "good". And all the "good" commits must be related to the bad commit.
    They cannot be on a branch that has no link with the branch of the
    "bad" commit. But it is possible for a good commit to be related to a
    bad commit and yet not be neither one of its ancestor nor one of its
    descendants.
    
    For example, there can be a "main" branch, and a "dev" branch that was
    forked of the main branch at a commit named "D" like this:
    
    -------------
    A-B-C-D-E-F-G  <--main
           \
            H-I-J  <--dev
    -------------
    
    The commit "D" is called a "merge base" for branch "main" and "dev"
    because it's the best common ancestor for these branches for a merge.
    
    Now let's suppose that commit J is bad and commit G is good and that
    we apply the bisection algorithm like it has been previously
    described.
    
    As described in step 1) b) of the bisection algorithm, we remove all
    the ancestors of the good commits because they are supposed to be good
    too.
    
    So we would be left with only:
    
    -------------
    H-I-J
    -------------
    
    But what happens if the first bad commit is "B" and if it has been
    fixed in the "main" branch by commit "F"?
    
    The result of such a bisection would be that we would find that H is
    the first bad commit, when in fact it's B. So that would be wrong!
    
    And yes it can happen in practice that people working on one branch
    are not aware that people working on another branch fixed a bug! It
    could also happen that F fixed more than one bug or that it is a
    revert of some big development effort that was not ready to be
    released.
    
    In fact development teams often maintain both a development branch and
    a maintenance branch, and it would be quite easy for them if "git
    bisect" just worked when they want to bisect a regression on the
    development branch that is not on the maintenance branch. They should
    be able to start bisecting using:
    
    -------------
    $ git bisect start dev main
    -------------
    
    To enable that additional nice feature, when a bisection is started
    and when some good commits are not ancestors of the bad commit, we
    first compute the merge bases between the bad and the good commits and
    we chose these merge bases as the first commits that will be checked
    out and tested.
    
    If it happens that one merge base is bad, then the bisection process
    is stopped with a message like:
    
    -------------
    The merge base BBBBBB is bad.
    This means the bug has been fixed between BBBBBB and [GGGGGG,...].
    -------------
    
    where BBBBBB is the sha1 hash of the bad merge base and [GGGGGG,...]
    is a comma separated list of the sha1 of the good commits.
    
    If some of the merge bases are skipped, then the bisection process
    continues, but the following message is printed for each skipped merge
    base:
    
    -------------
    Warning: the merge base between BBBBBB and [GGGGGG,...] must be skipped.
    So we cannot be sure the first bad commit is between MMMMMM and BBBBBB.
    We continue anyway.
    -------------
    
    where BBBBBB is the sha1 hash of the bad commit, MMMMMM is the sha1
    hash of the merge base that is skipped and [GGGGGG,...]  is a comma
    separated list of the sha1 of the good commits.
    
    So if there is no bad merge base, the bisection process continues as
    usual after this step.
    
    Best bisecting practices
    ------------------------
    
    Using test suites and git bisect together
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    If you both have a test suite and use git bisect, then it becomes less
    important to check that all tests pass after each commit. Though of
    course it is probably a good idea to have some checks to avoid
    breaking too many things because it could make bisecting other bugs
    more difficult.
    
    You can focus your efforts to check at a few points (for example rc
    and beta releases) that all the T test cases pass for all the N
    configurations. And when some tests don't pass you can use "git
    bisect" (or better "git bisect run"). So you should perform roughly:
    
    -------------
    c * N * T + b * M * log2(M) tests
    -------------
    
    where c is the number of rounds of test (so a small constant) and b is
    the ratio of bug per commit (hopefully a small constant too).
    
    So of course it's much better as it's O(N * T) vs O(N * T * M) if
    you would test everything after each commit.
    
    This means that test suites are good to prevent some bugs from being
    committed and they are also quite good to tell you that you have some
    bugs. But they are not so good to tell you where some bugs have been
    introduced. To tell you that efficiently, git bisect is needed.
    
    The other nice thing with test suites, is that when you have one, you
    already know how to test for bad behavior. So you can use this
    knowledge to create a new test case for "git bisect" when it appears
    that there is a regression. So it will be easier to bisect the bug and
    fix it. And then you can add the test case you just created to your
    test suite.
    
    So if you know how to create test cases and how to bisect, you will be
    subject to a virtuous circle:
    
    more tests => easier to create tests => easier to bisect => more tests
    
    So test suites and "git bisect" are complementary tools that are very
    powerful and efficient when used together.
    
    Bisecting build failures
    ~~~~~~~~~~~~~~~~~~~~~~~~
    
    You can very easily automatically bisect broken builds using something
    like:
    
    -------------
    $ git bisect start BAD GOOD
    $ git bisect run make
    -------------
    
    Passing sh -c "some commands" to "git bisect run"
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    For example:
    
    -------------
    $ git bisect run sh -c "make || exit 125; ./my_app | grep 'good output'"
    -------------
    
    On the other hand if you do this often, then it can be worth having
    scripts to avoid too much typing.
    
    Finding performance regressions
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    Here is an example script that comes slightly modified from a real
    world script used by Junio Hamano <<4>>.
    
    This script can be passed to "git bisect run" to find the commit that
    introduced a performance regression:
    
    -------------
    #!/bin/sh
    
    # Build errors are not what I am interested in.
    make my_app || exit 255
    
    # We are checking if it stops in a reasonable amount of time, so
    # let it run in the background...
    
    ./my_app >log 2>&1 &
    
    # ... and grab its process ID.
    pid=$!
    
    # ... and then wait for sufficiently long.
    sleep $NORMAL_TIME
    
    # ... and then see if the process is still there.
    if kill -0 $pid
    then
    	# It is still running -- that is bad.
    	kill $pid; sleep 1; kill $pid;
    	exit 1
    else
    	# It has already finished (the $pid process was no more),
    	# and we are happy.
    	exit 0
    fi
    -------------
    
    Following general best practices
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    It is obviously a good idea not to have commits with changes that
    knowingly break things, even if some other commits later fix the
    breakage.
    
    It is also a good idea when using any VCS to have only one small
    logical change in each commit.
    
    The smaller the changes in your commit, the most effective "git
    bisect" will be. And you will probably need "git bisect" less in the
    first place, as small changes are easier to review even if they are
    only reviewed by the committer.
    
    Another good idea is to have good commit messages. They can be very
    helpful to understand why some changes were made.
    
    These general best practices are very helpful if you bisect often.
    
    Avoiding bug prone merges
    ~~~~~~~~~~~~~~~~~~~~~~~~~
    
    First merges by themselves can introduce some regressions even when
    the merge needs no source code conflict resolution. This is because a
    semantic change can happen in one branch while the other branch is not
    aware of it.
    
    For example one branch can change the semantic of a function while the
    other branch add more calls to the same function.
    
    This is made much worse if many files have to be fixed to resolve
    conflicts. That's why such merges are called "evil merges". They can
    make regressions very difficult to track down. It can even be
    misleading to know the first bad commit if it happens to be such a
    merge, because people might think that the bug comes from bad conflict
    resolution when it comes from a semantic change in one branch.
    
    Anyway "git rebase" can be used to linearize history. This can be used
    either to avoid merging in the first place. Or it can be used to