Skip to content

Commit

Permalink
Merge branch 'cc/skip' into HEAD
Browse files Browse the repository at this point in the history
* cc/skip:
  Bisect: add "skip" to the short usage string.
  Bisect run: "skip" current commit if script exit code is 125.
  Bisect: add a "bisect replay" test case.
  Bisect: add "bisect skip" to the documentation.
  Bisect: refactor "bisect_{bad,good,skip}" into "bisect_state".
  Bisect: refactor some logging into "bisect_write".
  Bisect: refactor "bisect_write_*" functions.
  Bisect: implement "bisect skip" to mark untestable revisions.
  Bisect: fix some white spaces and empty lines breakages.
  rev-list documentation: add "--bisect-all".
  rev-list: implement --bisect-all
  • Loading branch information
Junio C Hamano committed Oct 31, 2007
2 parents 7ae4dd0 + 6ca8b97 commit 9725bb8
Show file tree
Hide file tree
Showing 7 changed files with 410 additions and 108 deletions.
29 changes: 24 additions & 5 deletions Documentation/git-bisect.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@ The command takes various subcommands, and different options depending
on the subcommand:

git bisect start [<bad> [<good>...]] [--] [<paths>...]
git bisect bad <rev>
git bisect good <rev>
git bisect bad [<rev>]
git bisect good [<rev>...]
git bisect skip [<rev>...]
git bisect reset [<branch>]
git bisect visualize
git bisect replay <logfile>
Expand Down Expand Up @@ -134,6 +135,20 @@ $ git reset --hard HEAD~3 # try 3 revs before what
Then compile and test the one you chose to try. After that, tell
bisect what the result was as usual.

Bisect skip
~~~~~~~~~~~~

Instead of choosing by yourself a nearby commit, you may just want git
to do it for you using:

------------
$ git bisect skip # Current version cannot be tested
------------

But computing the commit to test may be slower afterwards and git may
eventually not be able to tell the first bad among a bad and one or
more "skip"ped commits.

Cutting down bisection by giving more parameters to bisect start
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Expand Down Expand Up @@ -167,14 +182,18 @@ $ git bisect run my_script
------------

Note that the "run" script (`my_script` in the above example) should
exit with code 0 in case the current source code is good and with a
code between 1 and 127 (included) in case the current source code is
bad.
exit with code 0 in case the current source code is good. Exit with a
code between 1 and 127 (inclusive), except 125, if the current
source code is bad.

Any other exit code will abort the automatic bisect process. (A
program that does "exit(-1)" leaves $? = 255, see exit(3) manual page,
the value is chopped with "& 0377".)

The special exit code 125 should be used when the current source code
cannot be tested. If the "run" script exits with this code, the current
revision will be skipped, see `git bisect skip` above.

You may often find that during bisect you want to have near-constant
tweaks (e.g., s/#define DEBUG 0/#define DEBUG 1/ in a header file, or
"revision that does not have this commit needs this patch applied to
Expand Down
16 changes: 16 additions & 0 deletions Documentation/git-rev-list.txt
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ SYNOPSIS
[ \--pretty | \--header ]
[ \--bisect ]
[ \--bisect-vars ]
[ \--bisect-all ]
[ \--merge ]
[ \--reverse ]
[ \--walk-reflogs ]
Expand Down Expand Up @@ -354,6 +355,21 @@ 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`.

--bisect-all::

This outputs all the commit objects between the included and excluded
commits, ordered by their distance to the included and excluded
commits. The farthest from them is displayed first. (This is the only
one displayed by `--bisect`.)

This is useful because it makes it easy to choose a good commit to
test when you want to avoid to test some of them for some reason (they
may not compile for example).

This option can be used along with `--bisect-vars`, in this case,
after all the sorted commit objects, there will be the same text as if
`--bisect-vars` had been used alone.

--

Commit Ordering
Expand Down
100 changes: 86 additions & 14 deletions builtin-rev-list.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "revision.h"
#include "list-objects.h"
#include "builtin.h"
#include "log-tree.h"

/* bits #0-15 in revision.h */

Expand Down Expand Up @@ -38,7 +39,8 @@ static const char rev_list_usage[] =
" --left-right\n"
" special purpose:\n"
" --bisect\n"
" --bisect-vars"
" --bisect-vars\n"
" --bisect-all"
;

static struct rev_info revs;
Expand Down Expand Up @@ -74,6 +76,7 @@ static void show_commit(struct commit *commit)
parents = parents->next;
}
}
show_decorations(commit);
if (revs.commit_format == CMIT_FMT_ONELINE)
putchar(' ');
else
Expand Down Expand Up @@ -278,6 +281,57 @@ static struct commit_list *best_bisection(struct commit_list *list, int nr)
return best;
}

struct commit_dist {
struct commit *commit;
int distance;
};

static int compare_commit_dist(const void *a_, const void *b_)
{
struct commit_dist *a, *b;

a = (struct commit_dist *)a_;
b = (struct commit_dist *)b_;
if (a->distance != b->distance)
return b->distance - a->distance; /* desc sort */
return hashcmp(a->commit->object.sha1, b->commit->object.sha1);
}

static struct commit_list *best_bisection_sorted(struct commit_list *list, int nr)
{
struct commit_list *p;
struct commit_dist *array = xcalloc(nr, sizeof(*array));
int cnt, i;

for (p = list, cnt = 0; p; p = p->next) {
int distance;
unsigned flags = p->item->object.flags;

if (revs.prune_fn && !(flags & TREECHANGE))
continue;
distance = weight(p);
if (nr - distance < distance)
distance = nr - distance;
array[cnt].commit = p->item;
array[cnt].distance = distance;
cnt++;
}
qsort(array, cnt, sizeof(*array), compare_commit_dist);
for (p = list, i = 0; i < cnt; i++) {
struct name_decoration *r = xmalloc(sizeof(*r) + 100);
struct object *obj = &(array[i].commit->object);

sprintf(r->name, "dist=%d", array[i].distance);
r->next = add_decoration(&name_decoration, obj, r);
p->item = array[i].commit;
p = p->next;
}
if (p)
p->next = NULL;
free(array);
return list;
}

/*
* zero or positive weight is the number of interesting commits it can
* reach, including itself. Especially, weight = 0 means it does not
Expand All @@ -292,7 +346,8 @@ static struct commit_list *best_bisection(struct commit_list *list, int nr)
* or positive distance.
*/
static struct commit_list *do_find_bisection(struct commit_list *list,
int nr, int *weights)
int nr, int *weights,
int find_all)
{
int n, counted;
struct commit_list *p;
Expand Down Expand Up @@ -351,7 +406,7 @@ static struct commit_list *do_find_bisection(struct commit_list *list,
clear_distance(list);

/* Does it happen to be at exactly half-way? */
if (halfway(p, nr))
if (!find_all && halfway(p, nr))
return p;
counted++;
}
Expand Down Expand Up @@ -389,19 +444,22 @@ static struct commit_list *do_find_bisection(struct commit_list *list,
weight_set(p, weight(q));

/* Does it happen to be at exactly half-way? */
if (halfway(p, nr))
if (!find_all && halfway(p, nr))
return p;
}
}

show_list("bisection 2 counted all", counted, nr, list);

/* Then find the best one */
return best_bisection(list, nr);
if (!find_all)
return best_bisection(list, nr);
else
return best_bisection_sorted(list, nr);
}

static struct commit_list *find_bisection(struct commit_list *list,
int *reaches, int *all)
int *reaches, int *all,
int find_all)
{
int nr, on_list;
struct commit_list *p, *best, *next, *last;
Expand Down Expand Up @@ -434,14 +492,13 @@ static struct commit_list *find_bisection(struct commit_list *list,
weights = xcalloc(on_list, sizeof(*weights));

/* Do the real work of finding bisection commit. */
best = do_find_bisection(list, nr, weights);

best = do_find_bisection(list, nr, weights, find_all);
if (best) {
best->next = NULL;
if (!find_all)
best->next = NULL;
*reaches = weight(best);
}
free(weights);

return best;
}

Expand All @@ -468,6 +525,7 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
int i;
int read_from_stdin = 0;
int bisect_show_vars = 0;
int bisect_find_all = 0;

git_config(git_default_config);
init_revisions(&revs, prefix);
Expand All @@ -490,6 +548,11 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
bisect_list = 1;
continue;
}
if (!strcmp(arg, "--bisect-all")) {
bisect_list = 1;
bisect_find_all = 1;
continue;
}
if (!strcmp(arg, "--bisect-vars")) {
bisect_list = 1;
bisect_show_vars = 1;
Expand Down Expand Up @@ -536,9 +599,11 @@ 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);
revs.commits = find_bisection(revs.commits, &reaches, &all,
bisect_find_all);
if (bisect_show_vars) {
int cnt;
char hex[41];
if (!revs.commits)
return 1;
/*
Expand All @@ -550,15 +615,22 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
* A bisect set of size N has (N-1) commits further
* to test, as we already know one bad one.
*/
cnt = all-reaches;
cnt = all - reaches;
if (cnt < reaches)
cnt = reaches;
strcpy(hex, sha1_to_hex(revs.commits->item->object.sha1));

if (bisect_find_all) {
traverse_commit_list(&revs, show_commit, show_object);
printf("------\n");
}

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),
hex,
cnt - 1,
all - reaches - 1,
reaches - 1,
Expand Down
Loading

0 comments on commit 9725bb8

Please sign in to comment.