Since git-bisect already asks rev-list to find the midpoint (and rev-list consequently counts the number of commits), rev-list can pass it the maximal number of commits. As a bonus, this avoids an extra call to rev-list. Miscalculation noticed by Uwe, implementation suggested by Linus. Signed-off-by: Johannes Schindelin <johannes.schindelin@xxxxxx> --- On Wed, 21 Mar 2007, Linus Torvalds wrote: > On Wed, 21 Mar 2007, Uwe Kleine-König wrote: > > > > Up to now the number printed was calculated assuming that the > > current revision to test is bad. Given that it's not possible > > that this always matches the number of suspicious revs if the > > current one is good, the maximum of both is taken now. > > How about adding a new flag to "git-rev-list", to make it count > both ways? Did I understand you correctly? Documentation/git-rev-list.txt | 8 ++++++++ builtin-rev-list.c | 40 +++++++++++++++++++++++++++++++++------- git-bisect.sh | 7 +++---- 3 files changed, 44 insertions(+), 11 deletions(-) diff --git a/Documentation/git-rev-list.txt b/Documentation/git-rev-list.txt index 4f145ea..5f6f2a3 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,13 @@ 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 a line ready to be +eval'ed by the shell. This line will assign the name of the midpoint +revision to the variable 'rev', and the maximal number of commits to +be tested after this revision to 'nr'. + -- Commit Ordering diff --git a/builtin-rev-list.c b/builtin-rev-list.c index c2db5a5..b653975 100644 --- a/builtin-rev-list.c +++ b/builtin-rev-list.c @@ -36,12 +36,12 @@ 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; -static int bisect_list; static int show_timestamp; static int hdr_termination; static const char *header_prefix; @@ -168,7 +168,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 *nr_bad, int *nr_good) { int nr, closest; struct commit_list *p, *best; @@ -198,8 +199,20 @@ static struct commit_list *find_bisection(struct commit_list *list) closest = distance; } } - if (best) + if (best) { best->next = NULL; + /* + * The variable nr_bad holds the number of revisions + * to be tested if "best" is marked as bad, and nr_good + * the number if "best" is marked as good. + * + * Since the given range is <good>..<bad>, we have to + * subtract one, because both <good> and <bad> were + * already tested. + */ + *nr_bad = nr - closest - 1; + *nr_good = closest - 1; + } return best; } @@ -224,7 +237,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 read_from_stdin = 0, bisect_list = 0, bisect_show_vars = 0; git_config(git_default_config); init_revisions(&revs, prefix); @@ -247,6 +260,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 +303,16 @@ 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 nr_bad = 0, nr_good = 0; + revs.commits = find_bisection(revs.commits, &nr_bad, &nr_good); + if (bisect_show_vars) { + printf("rev=%s;nr=%d;\n", !revs.commits ? "" : + sha1_to_hex(revs.commits->item->object.sha1), + nr_bad > nr_good ? nr_bad : nr_good); + return 0; + } + } traverse_commit_list(&revs, show_commit, show_object); diff --git a/git-bisect.sh b/git-bisect.sh index b1c3a6b..cd5e3c9 100755 --- a/git-bisect.sh +++ b/git-bisect.sh @@ -138,9 +138,9 @@ bisect_next() { bisect_autostart bisect_next_check fail bad=$(git-rev-parse --verify refs/bisect/bad) && - good=$(git-rev-parse --sq --revs-only --not \ - $(cd "$GIT_DIR" && ls refs/bisect/good-*)) && - rev=$(eval "git-rev-list --bisect $good $bad -- $(cat $GIT_DIR/BISECT_NAMES)") || exit + good=$(git-rev-parse --revs-only --not \ + $(cd "$GIT_DIR" && ls refs/bisect/good-*)) || exit + eval "$(git-rev-list --bisect-vars $good $bad -- $(cat $GIT_DIR/BISECT_NAMES))" || exit if [ -z "$rev" ]; then echo "$bad was both good and bad" exit 1 @@ -150,7 +150,6 @@ bisect_next() { git-diff-tree --pretty $rev exit 0 fi - nr=$(eval "git-rev-list $rev $good -- $(cat $GIT_DIR/BISECT_NAMES)" | wc -l) || exit echo "Bisecting: $nr revisions left to test after this" echo "$rev" > "$GIT_DIR/refs/heads/new-bisect" git checkout -q new-bisect || exit -- 1.5.1.rc1.2306.g3d2f