简体   繁体   中英

How does git bisect skip choose the next commit to try?

When using git bisect , one can run git bisect skip to mark the current commit as being an unbuildable / untestable one, to try and get Git to pick some other commit to test instead.

How does Git decide which commit to try after a git bisect skip ? Experimenting shows it's not just an adjacent commit, but I can't work out the pattern.

Edit : I'm aware the basic git bisect is a binary search, but I'm curious about git bisect skip , which is clearly doing something more complicated.

Experimentation shows it's not just picking an adjacent commit; the below creates 100 commits numbered 0–99 then starts bisecting them. The first commit git bisect picks is in the middle, but each git bisect skip thereafter seems to be more-or-less randomly selected.

$ git init
Initialized empty Git repository in .git/

$ for (( i=0; i<100; i++ )); do echo $i > file; git add file; git commit -m $i >/dev/null; done  # Create some dummy commits

$ git bisect start HEAD $(git rev-list --max-parents=0 HEAD)  # HEAD is bad, root commit is good.
Bisecting: 49 revisions left to test after this (roughly 6 steps)
[099e5cf2ccde625f92dc369da6cad0bdf2852ce4] 49

$ git bisect skip
Bisecting: 49 revisions left to test after this (roughly 6 steps)
[88c8208a7c4322222124167e49f07c741af7d3d8] 60

$ git bisect skip
Bisecting: 49 revisions left to test after this (roughly 6 steps)
[04695f2e5b2473c3ac72435c0dbfc3ba1375abda] 88

$ git bisect skip
Bisecting: 49 revisions left to test after this (roughly 6 steps)
[1e9bf3d29589bcac2d8c467245ae8d446c195252] 40

$ git bisect skip
Bisecting: 49 revisions left to test after this (roughly 6 steps)
[9459ed79e4112d674681c8f0f921127217c7ebc6] 13

I did some digging into the Git source code and found most of an answer myself...

As of Git v1.6.4 (specifically, as of commit ebc9529f ), Git uses "a PRNG (pseudo random number generator) with a bias" to determine which commit to try next after skipping one.

I can't say I follow the algorithm itself (which, as of v2.8.1, appears to be fundamentally untouched since it was first added), but the commit message does a reasonable job of explaining what's going on:

bisect: use a PRNG with a bias when skipping away from untestable commits

Using a PRNG (pseudo random number generator) with a bias should be better than alternating between 3 fixed ratios.

In repositories with many untestable commits it should prevent alternating between areas where many commits are untestable. The bias should favor commits that can give more information, so that the bisection process should not loose much efficiency.

HPA suggested to use a PRNG and found that the best bias is to raise a ratio between 0 and 1 given by the PRNG to the power 1.5.

So it looks as though Git picks the next commit to try at random, but the random distribution was picked to (hopefully) choose commits that give more information for the binary search and to avoid commits likely to be in regions of untestable commits.

As the name Git would suggest, the short answer is: It's non of your businness .

The idea behind git bisect is that you specify two endpoints and Git figure it a commit, in between, that it thinks is the useful one for the goal of reducing the number of test.

As the documentation says this is just a binary search, but doesn't specify what kind of algorithm is used

Then git bisect picks a commit between those two endpoints

It may not be a straightforward pick-the-middle-commit binary search, Git may employ any decision algorithm it want and it explicitly doesn't want you to know it so that you won't make assumptions on the commit that will be picked up.

When it comes to changing the picked up commit it gives you two possibilities:

  1. You manually choose the new commit. For example with git reset --hard .
  2. You tell Git to make a new choice, with git bisect skip .

In the latter case, as when you update the endpoints with good and bad , the decision is made by Git, the way it wants.


Out of curiosity I made simple single-branch repository and tried the git bisect skip command.
My version of Git picked up the previous commit.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM