From 7054b6089d413f3d466491f1e6e8f565f4aff031 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 21 Mar 2007 22:11:35 -0700 Subject: [PATCH 1/6] t6002: minor spelling fix. The test expects --bisect option can be configured with by setting $_bisect_option. So let's allow that uniformly. Signed-off-by: Junio C Hamano --- t/t6002-rev-list-bisect.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/t6002-rev-list-bisect.sh b/t/t6002-rev-list-bisect.sh index 7831e3461..fcb330276 100755 --- a/t/t6002-rev-list-bisect.sh +++ b/t/t6002-rev-list-bisect.sh @@ -163,7 +163,7 @@ test_sequence() # the bisection point is the head - this is the bad point. # -test_output_expect_success "--bisect l5 ^root" 'git-rev-list $_bisect_option l5 ^root' < Date: Wed, 21 Mar 2007 22:15:54 -0700 Subject: [PATCH 2/6] git-rev-list: add --bisect-vars option. This adds --bisect-vars option to rev-list. The output is suitable for `eval` in shell and defines five variables: - bisect_rev is the next revision to test. - bisect_nr is the expected number of commits to test after bisect_rev is tested. - bisect_good is the expected number of commits to test if bisect_rev turns out to be good. - bisect_bad is the expected number of commits to test if bisect_rev turns out to be bad. - bisect_all is the number of commits we are bisecting right now. The documentation text was partly stolen from Johannes Schindelin's patch. Signed-off-by: Junio C Hamano --- Documentation/git-rev-list.txt | 13 ++++++++ builtin-rev-list.c | 54 ++++++++++++++++++++++++++++++---- 2 files changed, 61 insertions(+), 6 deletions(-) diff --git a/Documentation/git-rev-list.txt b/Documentation/git-rev-list.txt index 4f145eaba..3fa45b81c 100644 --- a/Documentation/git-rev-list.txt +++ b/Documentation/git-rev-list.txt @@ -26,6 +26,7 @@ SYNOPSIS [ [\--objects | \--objects-edge] [ \--unpacked ] ] [ \--pretty | \--header ] [ \--bisect ] + [ \--bisect-vars ] [ \--merge ] [ \--reverse ] [ \--walk-reflogs ] @@ -249,6 +250,18 @@ introduces a regression is thus reduced to a binary search: repeatedly generate and test new 'midpoint's until the commit chain is of length one. +--bisect-vars:: + +This calculates the same as `--bisect`, but outputs text ready +to be eval'ed by the shell. These lines will assign the name of +the midpoint revision to the variable `bisect_rev`, and the +expected number of commits to be tested after `bisect_rev` is +tested to `bisect_nr`, the expected number of commits to be +tested if `bisect_rev` turns out to be good to `bisect_good`, +the expected number of commits to be tested if `bisect_rev` +turns out to be bad to `bisect_bad`, and the number of commits +we are bisecting right now to `bisect_all`. + -- Commit Ordering diff --git a/builtin-rev-list.c b/builtin-rev-list.c index c2db5a5b0..723e4d419 100644 --- a/builtin-rev-list.c +++ b/builtin-rev-list.c @@ -36,7 +36,8 @@ static const char rev_list_usage[] = " --abbrev=nr | --no-abbrev\n" " --abbrev-commit\n" " special purpose:\n" -" --bisect" +" --bisect\n" +" --bisect-vars" ; static struct rev_info revs; @@ -168,7 +169,8 @@ static void clear_distance(struct commit_list *list) } } -static struct commit_list *find_bisection(struct commit_list *list) +static struct commit_list *find_bisection(struct commit_list *list, + int *reaches, int *all) { int nr, closest; struct commit_list *p, *best; @@ -180,21 +182,23 @@ static struct commit_list *find_bisection(struct commit_list *list) nr++; p = p->next; } + *all = nr; closest = 0; best = list; for (p = list; p; p = p->next) { - int distance; + int distance, reach; if (revs.prune_fn && !(p->item->object.flags & TREECHANGE)) continue; - distance = count_distance(p); + distance = reach = count_distance(p); clear_distance(list); if (nr - distance < distance) distance = nr - distance; if (distance > closest) { best = p; + *reaches = reach; closest = distance; } } @@ -225,6 +229,7 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix) struct commit_list *list; int i; int read_from_stdin = 0; + int bisect_show_vars = 0; git_config(git_default_config); init_revisions(&revs, prefix); @@ -247,6 +252,11 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix) bisect_list = 1; continue; } + if (!strcmp(arg, "--bisect-vars")) { + bisect_list = 1; + bisect_show_vars = 1; + continue; + } if (!strcmp(arg, "--stdin")) { if (read_from_stdin++) die("--stdin given twice?"); @@ -285,8 +295,40 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix) if (revs.tree_objects) mark_edges_uninteresting(revs.commits, &revs, show_edge); - if (bisect_list) - revs.commits = find_bisection(revs.commits); + if (bisect_list) { + int reaches = reaches, all = all; + + revs.commits = find_bisection(revs.commits, + &reaches, &all); + if (bisect_show_vars) { + int cnt; + if (!revs.commits) + return 1; + /* + * revs.commits can reach "reaches" commits among + * "all" commits. If it is good, then there are + * (all-reaches) commits left to be bisected. + * On the other hand, if it is bad, then the set + * to bisect is "reaches". + * A bisect set of size N has (N-1) commits further + * to test, as we already know one bad one. + */ + cnt = all-reaches; + if (cnt < reaches) + cnt = reaches; + printf("bisect_rev=%s\n" + "bisect_nr=%d\n" + "bisect_good=%d\n" + "bisect_bad=%d\n" + "bisect_all=%d\n", + sha1_to_hex(revs.commits->item->object.sha1), + cnt - 1, + all - reaches - 1, + reaches - 1, + all); + return 0; + } + } traverse_commit_list(&revs, show_commit, show_object); From 1c4fea3a40e836dcee2f16091bf7bfba96c924d0 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 21 Mar 2007 22:16:24 -0700 Subject: [PATCH 3/6] git-rev-list --bisect: optimization This improves the performance of revision bisection. The idea is to avoid rather expensive count_distance() function, which counts the number of commits that are reachable from any given commit (including itself) in the set. When a commit has only one relevant parent commit, the number of commits the commit can reach is exactly the number of commits that the parent can reach plus one; instead of running count_distance() on commits that are on straight single strand of pearls, we can just add one to the parents' count. On the other hand, for a merge commit, because the commits reachable from one parent can be reachable from another parent, you cannot just add the parents' counts up plus one for the commit itself; that would overcount ancestors that are reachable from more than one parents. The algorithm used in the patch runs count_distance() on merge commits, and uses the util field of commit objects to remember them. After that, the number of commits reachable from each of the remaining commits is counted by finding a commit whose count is not yet known but the count for its (sole) parent is known, and adding one to the parent's count, until we assign numbers to everybody. Another small optimization is whenever we find a half-way commit (that is, a commit that can reach exactly half of the commits), we stop giving counts to remaining commits, as we will not find any better commit than we just found. The performance to bisect between v1.0.0 and v1.5.0 in git.git repository was improved by saying good and bad in turns from 3.68 seconds down to 1.26 seconds. Bisecting the kernel between v2.6.18 and v2.6.20 was sped up from 21.84 seconds down to 4.22 seconds. Signed-off-by: Junio C Hamano --- builtin-rev-list.c | 162 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 160 insertions(+), 2 deletions(-) diff --git a/builtin-rev-list.c b/builtin-rev-list.c index 723e4d419..b395ffeb0 100644 --- a/builtin-rev-list.c +++ b/builtin-rev-list.c @@ -207,6 +207,160 @@ static struct commit_list *find_bisection(struct commit_list *list, return best; } +static inline int commit_interesting(struct commit_list *elem) +{ + unsigned flags = elem->item->object.flags; + if (flags & UNINTERESTING) + return 0; + return (!revs.prune_fn || (flags & TREECHANGE)); +} + +static inline int weight(struct commit_list *elem) +{ + return *((int*)(elem->item->util)); +} + +static inline void weight_set(struct commit_list *elem, int weight) +{ + *((int*)(elem->item->util)) = weight; +} + +static int count_interesting_parents(struct commit_list *elem) +{ + int cnt = 0; + if (!elem->item->parents) + return cnt; + for (elem = elem->item->parents; elem; elem = elem->next) { + if (commit_interesting(elem)) + cnt++; + } + return cnt; +} + +static struct commit_list *find_bisection_2(struct commit_list *list, + int *reaches, int *all) +{ + int n, nr, counted, distance; + struct commit_list *p, *best; + int *weights; + + for (nr = 0, p = list; p; p = p->next) { + if (commit_interesting(p)) + nr++; + } + *all = nr; + weights = xcalloc(nr, sizeof(int*)); + counted = 0; + + for (n = 0, p = list; p; p = p->next) { + if (!commit_interesting(p)) + continue; + if (commit_interesting(p)) { + /* + * positive weight is the number of interesting + * commits it can reach, including itself. + * weight = 0 means it has one parent and + * its distance is unknown. + * weight < 0 means it has more than one + * parent and its distance is unknown. + */ + p->item->util = &weights[n++]; + switch (count_interesting_parents(p)) { + case 0: + weight_set(p, 1); + counted++; + break; + case 1: + weight_set(p, 0); + break; + default: + weight_set(p, -1); + break; + } + } + } + + /* + * If you have only one parent in the resulting set + * then you can reach one commit more than that parent + * can reach. So we do not have to run the expensive + * count_distance() for single strand of pearls. + * + * However, if you have more than one parents, you cannot + * just add their distance and one for yourself, since + * they usually reach the same ancestor and you would + * end up counting them twice that way. + * + * So we will first count distance of merges the usual + * way, and then fill the blanks using cheaper algorithm. + */ + for (p = list; p; p = p->next) { + if (!commit_interesting(p)) + continue; + n = weight(p); + if (0 <= n) + continue; + distance = count_distance(p); + clear_distance(p); + weight_set(p, distance); + + /* Does it happen to be at exactly half-way? */ + distance *= 2; + if (nr == distance || (nr+1) == distance) { + p->next = NULL; + *reaches = weight(p); + free(weights); + return p; + } + counted++; + } + + while (counted < nr) { + for (p = list; p; p = p->next) { + struct commit_list *q; + + if (!commit_interesting(p) || 0 < weight(p)) + continue; + for (q = p->item->parents; q; q = q->next) + if (commit_interesting(q) && 0 < weight(q)) + break; + if (!q) + continue; + weight_set(p, weight(q)+1); + counted++; + + /* Does it happen to be at exactly half-way? */ + distance = weight(p) * 2; + if (nr == distance || (nr+1) == distance) { + p->next = NULL; + *reaches = weight(p); + free(weights); + return p; + } + } + } + + /* Then find the best one */ + counted = 0; + best = list; + for (p = list; p; p = p->next) { + if (!commit_interesting(p)) + continue; + distance = weight(p); + if (nr - distance < distance) + distance = nr - distance; + if (distance > counted) { + best = p; + counted = distance; + *reaches = weight(p); + } + } + if (best) + best->next = NULL; + free(weights); + return best; +} + static void read_revisions_from_stdin(struct rev_info *revs) { char line[1000]; @@ -298,8 +452,12 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix) if (bisect_list) { int reaches = reaches, all = all; - revs.commits = find_bisection(revs.commits, - &reaches, &all); + if (!revs.prune_fn) + revs.commits = find_bisection_2(revs.commits, + &reaches, &all); + else + revs.commits = find_bisection(revs.commits, + &reaches, &all); if (bisect_show_vars) { int cnt; if (!revs.commits) From bab36bf57d7a565e0077e1f5d2e3a10afa319ecc Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Thu, 22 Mar 2007 23:22:07 -0700 Subject: [PATCH 4/6] t6004: add a bit more path optimization test. Signed-off-by: Junio C Hamano --- t/t6004-rev-list-path-optim.sh | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/t/t6004-rev-list-path-optim.sh b/t/t6004-rev-list-path-optim.sh index 5182dbb15..761f09b1e 100755 --- a/t/t6004-rev-list-path-optim.sh +++ b/t/t6004-rev-list-path-optim.sh @@ -7,7 +7,8 @@ test_description='git-rev-list trivial path optimization test' test_expect_success setup ' echo Hello > a && git add a && -git commit -m "Initial commit" a +git commit -m "Initial commit" a && +initial=$(git rev-parse --verify HEAD) ' test_expect_success path-optimization ' @@ -16,4 +17,35 @@ test_expect_success path-optimization ' test $(git-rev-list $commit -- . | wc -l) = 1 ' +test_expect_success 'further setup' ' + git checkout -b side && + echo Irrelevant >c && + git add c && + git commit -m "Side makes an irrelevant commit" && + echo "More Irrelevancy" >c && + git add c && + git commit -m "Side makes another irrelevant commit" && + echo Bye >a && + git add a && + git commit -m "Side touches a" && + side=$(git rev-parse --verify HEAD) && + echo "Yet more Irrelevancy" >c && + git add c && + git commit -m "Side makes yet another irrelevant commit" && + git checkout master && + echo Another >b && + git add b && + git commit -m "Master touches b" && + git merge side && + echo Touched >b && + git add b && + git commit -m "Master touches b again" +' + +test_expect_success 'path optimization 2' ' + ( echo "$side"; echo "$initial" ) >expected && + git rev-list HEAD -- a >actual && + diff -u expected actual +' + test_done From 2a4646904a3766abeca7741f15a481d79e97e9e7 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Fri, 23 Mar 2007 00:40:54 -0700 Subject: [PATCH 5/6] rev-list --bisect: Fix "halfway" optimization. If you have 5 commits in the set, commits that reach 2 or 3 commits are at halfway. If you have 6 commits, only commits that reach exactly 3 commits are at halfway. The earlier one is completely botched the math. Signed-off-by: Junio C Hamano --- builtin-rev-list.c | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/builtin-rev-list.c b/builtin-rev-list.c index 09e3a60bf..7075548e6 100644 --- a/builtin-rev-list.c +++ b/builtin-rev-list.c @@ -237,6 +237,27 @@ static int count_interesting_parents(struct commit_list *elem) return cnt; } +static inline int halfway(struct commit_list *p, int distance, int nr) +{ + /* + * Don't short-cut something we are not going to return! + */ + if (revs.prune_fn && !(p->item->object.flags & TREECHANGE)) + return 0; + + /* + * 2 and 3 are halfway of 5. + * 3 is halfway of 6 but 2 and 4 are not. + */ + distance *= 2; + switch (distance - nr) { + case -1: case 0: case 1: + return 1; + default: + return 0; + } +} + static struct commit_list *find_bisection_2(struct commit_list *list, int *reaches, int *all) { @@ -305,10 +326,9 @@ static struct commit_list *find_bisection_2(struct commit_list *list, weight_set(p, distance); /* Does it happen to be at exactly half-way? */ - distance *= 2; - if (nr == distance || (nr+1) == distance) { + if (halfway(p, distance, nr)) { p->next = NULL; - *reaches = weight(p); + *reaches = distance; free(weights); return p; } @@ -330,10 +350,10 @@ static struct commit_list *find_bisection_2(struct commit_list *list, counted++; /* Does it happen to be at exactly half-way? */ - distance = weight(p) * 2; - if (nr == distance || (nr+1) == distance) { + distance = weight(p); + if (halfway(p, distance, nr)) { p->next = NULL; - *reaches = weight(p); + *reaches = distance; free(weights); return p; } From 1daa09d9a833d3969b64e763865a58df56bc3871 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Fri, 23 Mar 2007 17:54:03 -0700 Subject: [PATCH 6/6] make the previous optimization work also on path-limited rev-list --bisect The trick is to give a child commit that is not tree-changing the same depth as its parent, so that the depth is propagated properly along strand of pearls. Signed-off-by: Junio C Hamano --- builtin-rev-list.c | 249 +++++++++++++++++++++++++++------------------ 1 file changed, 151 insertions(+), 98 deletions(-) diff --git a/builtin-rev-list.c b/builtin-rev-list.c index 7075548e6..f91685a40 100644 --- a/builtin-rev-list.c +++ b/builtin-rev-list.c @@ -169,51 +169,7 @@ static void clear_distance(struct commit_list *list) } } -static struct commit_list *find_bisection(struct commit_list *list, - int *reaches, int *all) -{ - int nr, closest; - struct commit_list *p, *best; - - nr = 0; - p = list; - while (p) { - if (!revs.prune_fn || (p->item->object.flags & TREECHANGE)) - nr++; - p = p->next; - } - closest = -1; - best = list; - *all = nr; - - for (p = list; p; p = p->next) { - int distance, reach; - - if (revs.prune_fn && !(p->item->object.flags & TREECHANGE)) - continue; - - distance = reach = count_distance(p); - clear_distance(list); - if (nr - distance < distance) - distance = nr - distance; - if (distance > closest) { - best = p; - *reaches = reach; - closest = distance; - } - } - if (best) - best->next = NULL; - return best; -} - -static inline int commit_interesting(struct commit_list *elem) -{ - unsigned flags = elem->item->object.flags; - if (flags & UNINTERESTING) - return 0; - return (!revs.prune_fn || (flags & TREECHANGE)); -} +#define DEBUG_BISECT 0 static inline int weight(struct commit_list *elem) { @@ -225,16 +181,17 @@ static inline void weight_set(struct commit_list *elem, int weight) *((int*)(elem->item->util)) = weight; } -static int count_interesting_parents(struct commit_list *elem) +static int count_interesting_parents(struct commit *commit) { - int cnt = 0; - if (!elem->item->parents) - return cnt; - for (elem = elem->item->parents; elem; elem = elem->next) { - if (commit_interesting(elem)) - cnt++; + struct commit_list *p; + int count; + + for (count = 0, p = commit->parents; p; p = p->next) { + if (p->item->object.flags & UNINTERESTING) + continue; + count++; } - return cnt; + return count; } static inline int halfway(struct commit_list *p, int distance, int nr) @@ -244,7 +201,8 @@ static inline int halfway(struct commit_list *p, int distance, int nr) */ if (revs.prune_fn && !(p->item->object.flags & TREECHANGE)) return 0; - + if (DEBUG_BISECT) + return 0; /* * 2 and 3 are halfway of 5. * 3 is halfway of 6 but 2 and 4 are not. @@ -258,49 +216,127 @@ static inline int halfway(struct commit_list *p, int distance, int nr) } } -static struct commit_list *find_bisection_2(struct commit_list *list, - int *reaches, int *all) +#if !DEBUG_BISECT +#define show_list(a,b,c,d) do { ; } while (0) +#else +static void show_list(const char *debug, int counted, int nr, + struct commit_list *list) { - int n, nr, counted, distance; - struct commit_list *p, *best; + struct commit_list *p; + + fprintf(stderr, "%s (%d/%d)\n", debug, counted, nr); + + for (p = list; p; p = p->next) { + struct commit_list *pp; + struct commit *commit = p->item; + unsigned flags = commit->object.flags; + enum object_type type; + unsigned long size; + char *buf = read_sha1_file(commit->object.sha1, &type, &size); + char *ep, *sp; + + fprintf(stderr, "%c%c%c ", + (flags & TREECHANGE) ? 'T' : ' ', + (flags & UNINTERESTING) ? 'U' : ' ', + (flags & COUNTED) ? 'C' : ' '); + if (commit->util) + fprintf(stderr, "%3d", weight(p)); + else + fprintf(stderr, "---"); + fprintf(stderr, " %.*s", 8, sha1_to_hex(commit->object.sha1)); + for (pp = commit->parents; pp; pp = pp->next) + fprintf(stderr, " %.*s", 8, + sha1_to_hex(pp->item->object.sha1)); + + sp = strstr(buf, "\n\n"); + if (sp) { + sp += 2; + for (ep = sp; *ep && *ep != '\n'; ep++) + ; + fprintf(stderr, " %.*s", (int)(ep - sp), sp); + } + fprintf(stderr, "\n"); + } +} +#endif /* DEBUG_BISECT */ + +/* + * zero or positive weight is the number of interesting commits it can + * reach, including itself. Especially, weight = 0 means it does not + * reach any tree-changing commits (e.g. just above uninteresting one + * but traversal is with pathspec). + * + * weight = -1 means it has one parent and its distance is yet to + * be computed. + * + * weight = -2 means it has more than one parent and its distance is + * unknown. After running count_distance() first, they will get zero + * or positive distance. + */ + +static struct commit_list *find_bisection(struct commit_list *list, + int *reaches, int *all) +{ + int n, nr, on_list, counted, distance; + struct commit_list *p, *best, *next, *last; int *weights; - for (nr = 0, p = list; p; p = p->next) { - if (commit_interesting(p)) + show_list("bisection 2 entry", 0, 0, list); + + /* + * Count the number of total and tree-changing items on the + * list, while reversing the list. + */ + for (nr = on_list = 0, last = NULL, p = list; + p; + p = next) { + unsigned flags = p->item->object.flags; + + next = p->next; + if (flags & UNINTERESTING) + continue; + p->next = last; + last = p; + if (!revs.prune_fn || (flags & TREECHANGE)) nr++; + on_list++; } + list = last; + show_list("bisection 2 sorted", 0, nr, list); + *all = nr; - weights = xcalloc(nr, sizeof(int*)); + weights = xcalloc(on_list, sizeof(int*)); counted = 0; for (n = 0, p = list; p; p = p->next) { - if (!commit_interesting(p)) - continue; - if (commit_interesting(p)) { - /* - * positive weight is the number of interesting - * commits it can reach, including itself. - * weight = 0 means it has one parent and - * its distance is unknown. - * weight < 0 means it has more than one - * parent and its distance is unknown. - */ - p->item->util = &weights[n++]; - switch (count_interesting_parents(p)) { - case 0: + struct commit *commit = p->item; + unsigned flags = commit->object.flags; + + p->item->util = &weights[n++]; + switch (count_interesting_parents(commit)) { + case 0: + if (!revs.prune_fn || (flags & TREECHANGE)) { weight_set(p, 1); counted++; - break; - case 1: - weight_set(p, 0); - break; - default: - weight_set(p, -1); - break; + show_list("bisection 2 count one", + counted, nr, list); } + /* + * otherwise, it is known not to reach any + * tree-changing commit and gets weight 0. + */ + break; + case 1: + weight_set(p, -1); + break; + default: + weight_set(p, -2); + break; } } + show_list("bisection 2 initialize", counted, nr, list); + /* * If you have only one parent in the resulting set * then you can reach one commit more than that parent @@ -316,13 +352,13 @@ static struct commit_list *find_bisection_2(struct commit_list *list, * way, and then fill the blanks using cheaper algorithm. */ for (p = list; p; p = p->next) { - if (!commit_interesting(p)) + if (p->item->object.flags & UNINTERESTING) continue; n = weight(p); - if (0 <= n) + if (n != -2) continue; distance = count_distance(p); - clear_distance(p); + clear_distance(list); weight_set(p, distance); /* Does it happen to be at exactly half-way? */ @@ -335,19 +371,37 @@ static struct commit_list *find_bisection_2(struct commit_list *list, counted++; } + show_list("bisection 2 count_distance", counted, nr, list); + while (counted < nr) { for (p = list; p; p = p->next) { struct commit_list *q; + unsigned flags = p->item->object.flags; - if (!commit_interesting(p) || 0 < weight(p)) + if (0 <= weight(p)) continue; - for (q = p->item->parents; q; q = q->next) - if (commit_interesting(q) && 0 < weight(q)) + for (q = p->item->parents; q; q = q->next) { + if (q->item->object.flags & UNINTERESTING) + continue; + if (0 <= weight(q)) break; + } if (!q) continue; - weight_set(p, weight(q)+1); - counted++; + + /* + * weight for p is unknown but q is known. + * add one for p itself if p is to be counted, + * otherwise inherit it from q directly. + */ + if (!revs.prune_fn || (flags & TREECHANGE)) { + weight_set(p, weight(q)+1); + counted++; + show_list("bisection 2 count one", + counted, nr, list); + } + else + weight_set(p, weight(q)); /* Does it happen to be at exactly half-way? */ distance = weight(p); @@ -360,11 +414,15 @@ static struct commit_list *find_bisection_2(struct commit_list *list, } } + show_list("bisection 2 counted all", counted, nr, list); + /* Then find the best one */ - counted = 0; + counted = -1; best = list; for (p = list; p; p = p->next) { - if (!commit_interesting(p)) + unsigned flags = p->item->object.flags; + + if (revs.prune_fn && !(flags & TREECHANGE)) continue; distance = weight(p); if (nr - distance < distance) @@ -472,12 +530,7 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix) if (bisect_list) { int reaches = reaches, all = all; - if (!revs.prune_fn) - revs.commits = find_bisection_2(revs.commits, - &reaches, &all); - else - revs.commits = find_bisection(revs.commits, - &reaches, &all); + revs.commits = find_bisection(revs.commits, &reaches, &all); if (bisect_show_vars) { int cnt; if (!revs.commits)