Merge branch 'cc/skip' into HEAD
* 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
			
			
This commit is contained in:
		@ -16,8 +16,9 @@ The command takes various subcommands, and different options depending
 | 
				
			|||||||
on the subcommand:
 | 
					on the subcommand:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 git bisect start [<bad> [<good>...]] [--] [<paths>...]
 | 
					 git bisect start [<bad> [<good>...]] [--] [<paths>...]
 | 
				
			||||||
 git bisect bad <rev>
 | 
					 git bisect bad [<rev>]
 | 
				
			||||||
 git bisect good <rev>
 | 
					 git bisect good [<rev>...]
 | 
				
			||||||
 | 
					 git bisect skip [<rev>...]
 | 
				
			||||||
 git bisect reset [<branch>]
 | 
					 git bisect reset [<branch>]
 | 
				
			||||||
 git bisect visualize
 | 
					 git bisect visualize
 | 
				
			||||||
 git bisect replay <logfile>
 | 
					 git bisect replay <logfile>
 | 
				
			||||||
@ -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
 | 
					Then compile and test the one you chose to try. After that, tell
 | 
				
			||||||
bisect what the result was as usual.
 | 
					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
 | 
					Cutting down bisection by giving more parameters to bisect start
 | 
				
			||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 | 
					~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -167,14 +182,18 @@ $ git bisect run my_script
 | 
				
			|||||||
------------
 | 
					------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Note that the "run" script (`my_script` in the above example) should
 | 
					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
 | 
					exit with code 0 in case the current source code is good.  Exit with a
 | 
				
			||||||
code between 1 and 127 (included) in case the current source code is
 | 
					code between 1 and 127 (inclusive), except 125, if the current
 | 
				
			||||||
bad.
 | 
					source code is bad.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Any other exit code will abort the automatic bisect process. (A
 | 
					Any other exit code will abort the automatic bisect process. (A
 | 
				
			||||||
program that does "exit(-1)" leaves $? = 255, see exit(3) manual page,
 | 
					program that does "exit(-1)" leaves $? = 255, see exit(3) manual page,
 | 
				
			||||||
the value is chopped with "& 0377".)
 | 
					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
 | 
					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
 | 
					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
 | 
					"revision that does not have this commit needs this patch applied to
 | 
				
			||||||
 | 
				
			|||||||
@ -34,6 +34,7 @@ SYNOPSIS
 | 
				
			|||||||
	     [ \--pretty | \--header ]
 | 
						     [ \--pretty | \--header ]
 | 
				
			||||||
	     [ \--bisect ]
 | 
						     [ \--bisect ]
 | 
				
			||||||
	     [ \--bisect-vars ]
 | 
						     [ \--bisect-vars ]
 | 
				
			||||||
 | 
						     [ \--bisect-all ]
 | 
				
			||||||
	     [ \--merge ]
 | 
						     [ \--merge ]
 | 
				
			||||||
	     [ \--reverse ]
 | 
						     [ \--reverse ]
 | 
				
			||||||
	     [ \--walk-reflogs ]
 | 
						     [ \--walk-reflogs ]
 | 
				
			||||||
@ -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
 | 
					turns out to be bad to `bisect_bad`, and the number of commits
 | 
				
			||||||
we are bisecting right now to `bisect_all`.
 | 
					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
 | 
					Commit Ordering
 | 
				
			||||||
 | 
				
			|||||||
@ -9,6 +9,7 @@
 | 
				
			|||||||
#include "revision.h"
 | 
					#include "revision.h"
 | 
				
			||||||
#include "list-objects.h"
 | 
					#include "list-objects.h"
 | 
				
			||||||
#include "builtin.h"
 | 
					#include "builtin.h"
 | 
				
			||||||
 | 
					#include "log-tree.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* bits #0-15 in revision.h */
 | 
					/* bits #0-15 in revision.h */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -38,7 +39,8 @@ static const char rev_list_usage[] =
 | 
				
			|||||||
"    --left-right\n"
 | 
					"    --left-right\n"
 | 
				
			||||||
"  special purpose:\n"
 | 
					"  special purpose:\n"
 | 
				
			||||||
"    --bisect\n"
 | 
					"    --bisect\n"
 | 
				
			||||||
"    --bisect-vars"
 | 
					"    --bisect-vars\n"
 | 
				
			||||||
 | 
					"    --bisect-all"
 | 
				
			||||||
;
 | 
					;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct rev_info revs;
 | 
					static struct rev_info revs;
 | 
				
			||||||
@ -74,6 +76,7 @@ static void show_commit(struct commit *commit)
 | 
				
			|||||||
			parents = parents->next;
 | 
								parents = parents->next;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						show_decorations(commit);
 | 
				
			||||||
	if (revs.commit_format == CMIT_FMT_ONELINE)
 | 
						if (revs.commit_format == CMIT_FMT_ONELINE)
 | 
				
			||||||
		putchar(' ');
 | 
							putchar(' ');
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
@ -278,6 +281,57 @@ static struct commit_list *best_bisection(struct commit_list *list, int nr)
 | 
				
			|||||||
	return best;
 | 
						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
 | 
					 * zero or positive weight is the number of interesting commits it can
 | 
				
			||||||
 * reach, including itself.  Especially, weight = 0 means it does not
 | 
					 * reach, including itself.  Especially, weight = 0 means it does not
 | 
				
			||||||
@ -292,7 +346,8 @@ static struct commit_list *best_bisection(struct commit_list *list, int nr)
 | 
				
			|||||||
 * or positive distance.
 | 
					 * or positive distance.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static struct commit_list *do_find_bisection(struct commit_list *list,
 | 
					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;
 | 
						int n, counted;
 | 
				
			||||||
	struct commit_list *p;
 | 
						struct commit_list *p;
 | 
				
			||||||
@ -351,7 +406,7 @@ static struct commit_list *do_find_bisection(struct commit_list *list,
 | 
				
			|||||||
		clear_distance(list);
 | 
							clear_distance(list);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Does it happen to be at exactly half-way? */
 | 
							/* Does it happen to be at exactly half-way? */
 | 
				
			||||||
		if (halfway(p, nr))
 | 
							if (!find_all && halfway(p, nr))
 | 
				
			||||||
			return p;
 | 
								return p;
 | 
				
			||||||
		counted++;
 | 
							counted++;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@ -389,19 +444,22 @@ static struct commit_list *do_find_bisection(struct commit_list *list,
 | 
				
			|||||||
				weight_set(p, weight(q));
 | 
									weight_set(p, weight(q));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			/* Does it happen to be at exactly half-way? */
 | 
								/* Does it happen to be at exactly half-way? */
 | 
				
			||||||
			if (halfway(p, nr))
 | 
								if (!find_all && halfway(p, nr))
 | 
				
			||||||
				return p;
 | 
									return p;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	show_list("bisection 2 counted all", counted, nr, list);
 | 
						show_list("bisection 2 counted all", counted, nr, list);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Then find the best one */
 | 
						if (!find_all)
 | 
				
			||||||
	return best_bisection(list, nr);
 | 
							return best_bisection(list, nr);
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							return best_bisection_sorted(list, nr);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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 *reaches, int *all,
 | 
				
			||||||
 | 
										  int find_all)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int nr, on_list;
 | 
						int nr, on_list;
 | 
				
			||||||
	struct commit_list *p, *best, *next, *last;
 | 
						struct commit_list *p, *best, *next, *last;
 | 
				
			||||||
@ -434,14 +492,13 @@ static struct commit_list *find_bisection(struct commit_list *list,
 | 
				
			|||||||
	weights = xcalloc(on_list, sizeof(*weights));
 | 
						weights = xcalloc(on_list, sizeof(*weights));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Do the real work of finding bisection commit. */
 | 
						/* 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) {
 | 
						if (best) {
 | 
				
			||||||
		best->next = NULL;
 | 
							if (!find_all)
 | 
				
			||||||
 | 
								best->next = NULL;
 | 
				
			||||||
		*reaches = weight(best);
 | 
							*reaches = weight(best);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	free(weights);
 | 
						free(weights);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	return best;
 | 
						return best;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -468,6 +525,7 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
 | 
				
			|||||||
	int i;
 | 
						int i;
 | 
				
			||||||
	int read_from_stdin = 0;
 | 
						int read_from_stdin = 0;
 | 
				
			||||||
	int bisect_show_vars = 0;
 | 
						int bisect_show_vars = 0;
 | 
				
			||||||
 | 
						int bisect_find_all = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	git_config(git_default_config);
 | 
						git_config(git_default_config);
 | 
				
			||||||
	init_revisions(&revs, prefix);
 | 
						init_revisions(&revs, prefix);
 | 
				
			||||||
@ -490,6 +548,11 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
 | 
				
			|||||||
			bisect_list = 1;
 | 
								bisect_list = 1;
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							if (!strcmp(arg, "--bisect-all")) {
 | 
				
			||||||
 | 
								bisect_list = 1;
 | 
				
			||||||
 | 
								bisect_find_all = 1;
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		if (!strcmp(arg, "--bisect-vars")) {
 | 
							if (!strcmp(arg, "--bisect-vars")) {
 | 
				
			||||||
			bisect_list = 1;
 | 
								bisect_list = 1;
 | 
				
			||||||
			bisect_show_vars = 1;
 | 
								bisect_show_vars = 1;
 | 
				
			||||||
@ -536,9 +599,11 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
 | 
				
			|||||||
	if (bisect_list) {
 | 
						if (bisect_list) {
 | 
				
			||||||
		int reaches = reaches, all = all;
 | 
							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) {
 | 
							if (bisect_show_vars) {
 | 
				
			||||||
			int cnt;
 | 
								int cnt;
 | 
				
			||||||
 | 
								char hex[41];
 | 
				
			||||||
			if (!revs.commits)
 | 
								if (!revs.commits)
 | 
				
			||||||
				return 1;
 | 
									return 1;
 | 
				
			||||||
			/*
 | 
								/*
 | 
				
			||||||
@ -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
 | 
								 * A bisect set of size N has (N-1) commits further
 | 
				
			||||||
			 * to test, as we already know one bad one.
 | 
								 * to test, as we already know one bad one.
 | 
				
			||||||
			 */
 | 
								 */
 | 
				
			||||||
			cnt = all-reaches;
 | 
								cnt = all - reaches;
 | 
				
			||||||
			if (cnt < reaches)
 | 
								if (cnt < reaches)
 | 
				
			||||||
				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"
 | 
								printf("bisect_rev=%s\n"
 | 
				
			||||||
			       "bisect_nr=%d\n"
 | 
								       "bisect_nr=%d\n"
 | 
				
			||||||
			       "bisect_good=%d\n"
 | 
								       "bisect_good=%d\n"
 | 
				
			||||||
			       "bisect_bad=%d\n"
 | 
								       "bisect_bad=%d\n"
 | 
				
			||||||
			       "bisect_all=%d\n",
 | 
								       "bisect_all=%d\n",
 | 
				
			||||||
			       sha1_to_hex(revs.commits->item->object.sha1),
 | 
								       hex,
 | 
				
			||||||
			       cnt - 1,
 | 
								       cnt - 1,
 | 
				
			||||||
			       all - reaches - 1,
 | 
								       all - reaches - 1,
 | 
				
			||||||
			       reaches - 1,
 | 
								       reaches - 1,
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										252
									
								
								git-bisect.sh
									
									
									
									
									
								
							
							
						
						
									
										252
									
								
								git-bisect.sh
									
									
									
									
									
								
							@ -1,12 +1,14 @@
 | 
				
			|||||||
#!/bin/sh
 | 
					#!/bin/sh
 | 
				
			||||||
 | 
					
 | 
				
			||||||
USAGE='[start|bad|good|next|reset|visualize|replay|log|run]'
 | 
					USAGE='[start|bad|good|skip|next|reset|visualize|replay|log|run]'
 | 
				
			||||||
LONG_USAGE='git bisect start [<bad> [<good>...]] [--] [<pathspec>...]
 | 
					LONG_USAGE='git bisect start [<bad> [<good>...]] [--] [<pathspec>...]
 | 
				
			||||||
        reset bisect state and start bisection.
 | 
					        reset bisect state and start bisection.
 | 
				
			||||||
git bisect bad [<rev>]
 | 
					git bisect bad [<rev>]
 | 
				
			||||||
        mark <rev> a known-bad revision.
 | 
					        mark <rev> a known-bad revision.
 | 
				
			||||||
git bisect good [<rev>...]
 | 
					git bisect good [<rev>...]
 | 
				
			||||||
        mark <rev>... known-good revisions.
 | 
					        mark <rev>... known-good revisions.
 | 
				
			||||||
 | 
					git bisect skip [<rev>...]
 | 
				
			||||||
 | 
					        mark <rev>... untestable revisions.
 | 
				
			||||||
git bisect next
 | 
					git bisect next
 | 
				
			||||||
        find next bisection to test and check it out.
 | 
					        find next bisection to test and check it out.
 | 
				
			||||||
git bisect reset [<branch>]
 | 
					git bisect reset [<branch>]
 | 
				
			||||||
@ -64,7 +66,7 @@ bisect_start() {
 | 
				
			|||||||
		    branch=`cat "$GIT_DIR/head-name"`
 | 
							    branch=`cat "$GIT_DIR/head-name"`
 | 
				
			||||||
		else
 | 
							else
 | 
				
			||||||
		    branch=master
 | 
							    branch=master
 | 
				
			||||||
	        fi
 | 
							fi
 | 
				
			||||||
		git checkout $branch || exit
 | 
							git checkout $branch || exit
 | 
				
			||||||
		;;
 | 
							;;
 | 
				
			||||||
	refs/heads/*)
 | 
						refs/heads/*)
 | 
				
			||||||
@ -95,75 +97,74 @@ bisect_start() {
 | 
				
			|||||||
	    arg="$1"
 | 
						    arg="$1"
 | 
				
			||||||
	    case "$arg" in
 | 
						    case "$arg" in
 | 
				
			||||||
	    --)
 | 
						    --)
 | 
				
			||||||
	        shift
 | 
							shift
 | 
				
			||||||
		break
 | 
							break
 | 
				
			||||||
		;;
 | 
							;;
 | 
				
			||||||
	    *)
 | 
						    *)
 | 
				
			||||||
	        rev=$(git rev-parse --verify "$arg^{commit}" 2>/dev/null) || {
 | 
							rev=$(git rev-parse --verify "$arg^{commit}" 2>/dev/null) || {
 | 
				
			||||||
		    test $has_double_dash -eq 1 &&
 | 
							    test $has_double_dash -eq 1 &&
 | 
				
			||||||
		        die "'$arg' does not appear to be a valid revision"
 | 
							        die "'$arg' does not appear to be a valid revision"
 | 
				
			||||||
		    break
 | 
							    break
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if [ $bad_seen -eq 0 ]; then
 | 
							case $bad_seen in
 | 
				
			||||||
		    bad_seen=1
 | 
							0) state='bad' ; bad_seen=1 ;;
 | 
				
			||||||
		    bisect_write_bad "$rev"
 | 
							*) state='good' ;;
 | 
				
			||||||
		else
 | 
							esac
 | 
				
			||||||
		    bisect_write_good "$rev"
 | 
							bisect_write "$state" "$rev" 'nolog'
 | 
				
			||||||
		fi
 | 
							shift
 | 
				
			||||||
	        shift
 | 
					 | 
				
			||||||
		;;
 | 
							;;
 | 
				
			||||||
	    esac
 | 
						    esac
 | 
				
			||||||
        done
 | 
						done
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sq "$@" >"$GIT_DIR/BISECT_NAMES"
 | 
						sq "$@" >"$GIT_DIR/BISECT_NAMES"
 | 
				
			||||||
	echo "git-bisect start$orig_args" >>"$GIT_DIR/BISECT_LOG"
 | 
						echo "git-bisect start$orig_args" >>"$GIT_DIR/BISECT_LOG"
 | 
				
			||||||
	bisect_auto_next
 | 
						bisect_auto_next
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bisect_bad() {
 | 
					bisect_write() {
 | 
				
			||||||
 | 
						state="$1"
 | 
				
			||||||
 | 
						rev="$2"
 | 
				
			||||||
 | 
						nolog="$3"
 | 
				
			||||||
 | 
						case "$state" in
 | 
				
			||||||
 | 
							bad)		tag="$state" ;;
 | 
				
			||||||
 | 
							good|skip)	tag="$state"-"$rev" ;;
 | 
				
			||||||
 | 
							*)		die "Bad bisect_write argument: $state" ;;
 | 
				
			||||||
 | 
						esac
 | 
				
			||||||
 | 
						echo "$rev" >"$GIT_DIR/refs/bisect/$tag"
 | 
				
			||||||
 | 
						echo "# $state: "$(git show-branch $rev) >>"$GIT_DIR/BISECT_LOG"
 | 
				
			||||||
 | 
						test -z "$nolog" && echo "git-bisect $state $rev" >>"$GIT_DIR/BISECT_LOG"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bisect_state() {
 | 
				
			||||||
	bisect_autostart
 | 
						bisect_autostart
 | 
				
			||||||
	case "$#" in
 | 
						state=$1
 | 
				
			||||||
	0)
 | 
						case "$#,$state" in
 | 
				
			||||||
		rev=$(git rev-parse --verify HEAD) ;;
 | 
						0,*)
 | 
				
			||||||
	1)
 | 
							die "Please call 'bisect_state' with at least one argument." ;;
 | 
				
			||||||
		rev=$(git rev-parse --verify "$1^{commit}") ;;
 | 
						1,bad|1,good|1,skip)
 | 
				
			||||||
 | 
							rev=$(git rev-parse --verify HEAD) ||
 | 
				
			||||||
 | 
								die "Bad rev input: HEAD"
 | 
				
			||||||
 | 
							bisect_write "$state" "$rev" ;;
 | 
				
			||||||
 | 
						2,bad)
 | 
				
			||||||
 | 
							rev=$(git rev-parse --verify "$2^{commit}") ||
 | 
				
			||||||
 | 
								die "Bad rev input: $2"
 | 
				
			||||||
 | 
							bisect_write "$state" "$rev" ;;
 | 
				
			||||||
 | 
						*,good|*,skip)
 | 
				
			||||||
 | 
							shift
 | 
				
			||||||
 | 
							revs=$(git rev-parse --revs-only --no-flags "$@") &&
 | 
				
			||||||
 | 
								test '' != "$revs" || die "Bad rev input: $@"
 | 
				
			||||||
 | 
							for rev in $revs
 | 
				
			||||||
 | 
							do
 | 
				
			||||||
 | 
								rev=$(git rev-parse --verify "$rev^{commit}") ||
 | 
				
			||||||
 | 
									die "Bad rev commit: $rev^{commit}"
 | 
				
			||||||
 | 
								bisect_write "$state" "$rev"
 | 
				
			||||||
 | 
							done ;;
 | 
				
			||||||
	*)
 | 
						*)
 | 
				
			||||||
		usage ;;
 | 
							usage ;;
 | 
				
			||||||
	esac || exit
 | 
					 | 
				
			||||||
	bisect_write_bad "$rev"
 | 
					 | 
				
			||||||
	echo "git-bisect bad $rev" >>"$GIT_DIR/BISECT_LOG"
 | 
					 | 
				
			||||||
	bisect_auto_next
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bisect_write_bad() {
 | 
					 | 
				
			||||||
	rev="$1"
 | 
					 | 
				
			||||||
	echo "$rev" >"$GIT_DIR/refs/bisect/bad"
 | 
					 | 
				
			||||||
	echo "# bad: "$(git show-branch $rev) >>"$GIT_DIR/BISECT_LOG"
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bisect_good() {
 | 
					 | 
				
			||||||
	bisect_autostart
 | 
					 | 
				
			||||||
        case "$#" in
 | 
					 | 
				
			||||||
	0)    revs=$(git rev-parse --verify HEAD) || exit ;;
 | 
					 | 
				
			||||||
	*)    revs=$(git rev-parse --revs-only --no-flags "$@") &&
 | 
					 | 
				
			||||||
		test '' != "$revs" || die "Bad rev input: $@" ;;
 | 
					 | 
				
			||||||
	esac
 | 
						esac
 | 
				
			||||||
	for rev in $revs
 | 
					 | 
				
			||||||
	do
 | 
					 | 
				
			||||||
		rev=$(git rev-parse --verify "$rev^{commit}") || exit
 | 
					 | 
				
			||||||
		bisect_write_good "$rev"
 | 
					 | 
				
			||||||
		echo "git-bisect good $rev" >>"$GIT_DIR/BISECT_LOG"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	done
 | 
					 | 
				
			||||||
	bisect_auto_next
 | 
						bisect_auto_next
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bisect_write_good() {
 | 
					 | 
				
			||||||
	rev="$1"
 | 
					 | 
				
			||||||
	echo "$rev" >"$GIT_DIR/refs/bisect/good-$rev"
 | 
					 | 
				
			||||||
	echo "# good: "$(git show-branch $rev) >>"$GIT_DIR/BISECT_LOG"
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bisect_next_check() {
 | 
					bisect_next_check() {
 | 
				
			||||||
	missing_good= missing_bad=
 | 
						missing_good= missing_bad=
 | 
				
			||||||
	git show-ref -q --verify refs/bisect/bad || missing_bad=t
 | 
						git show-ref -q --verify refs/bisect/bad || missing_bad=t
 | 
				
			||||||
@ -206,17 +207,97 @@ bisect_auto_next() {
 | 
				
			|||||||
	bisect_next_check && bisect_next || :
 | 
						bisect_next_check && bisect_next || :
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					filter_skipped() {
 | 
				
			||||||
 | 
						_eval="$1"
 | 
				
			||||||
 | 
						_skip="$2"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if [ -z "$_skip" ]; then
 | 
				
			||||||
 | 
							eval $_eval
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						# Let's parse the output of:
 | 
				
			||||||
 | 
						# "git rev-list --bisect-vars --bisect-all ..."
 | 
				
			||||||
 | 
						eval $_eval | while read hash line
 | 
				
			||||||
 | 
						do
 | 
				
			||||||
 | 
							case "$VARS,$FOUND,$TRIED,$hash" in
 | 
				
			||||||
 | 
								# We display some vars.
 | 
				
			||||||
 | 
								1,*,*,*) echo "$hash $line" ;;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								# Split line.
 | 
				
			||||||
 | 
								,*,*,---*) ;;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								# We had nothing to search.
 | 
				
			||||||
 | 
								,,,bisect_rev*)
 | 
				
			||||||
 | 
									echo "bisect_rev="
 | 
				
			||||||
 | 
									VARS=1
 | 
				
			||||||
 | 
									;;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								# We did not find a good bisect rev.
 | 
				
			||||||
 | 
								# This should happen only if the "bad"
 | 
				
			||||||
 | 
								# commit is also a "skip" commit.
 | 
				
			||||||
 | 
								,,*,bisect_rev*)
 | 
				
			||||||
 | 
									echo "bisect_rev=$TRIED"
 | 
				
			||||||
 | 
									VARS=1
 | 
				
			||||||
 | 
									;;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								# We are searching.
 | 
				
			||||||
 | 
								,,*,*)
 | 
				
			||||||
 | 
									TRIED="${TRIED:+$TRIED|}$hash"
 | 
				
			||||||
 | 
									case "$_skip" in
 | 
				
			||||||
 | 
									*$hash*) ;;
 | 
				
			||||||
 | 
									*)
 | 
				
			||||||
 | 
										echo "bisect_rev=$hash"
 | 
				
			||||||
 | 
										echo "bisect_tried=\"$TRIED\""
 | 
				
			||||||
 | 
										FOUND=1
 | 
				
			||||||
 | 
										;;
 | 
				
			||||||
 | 
									esac
 | 
				
			||||||
 | 
									;;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								# We have already found a rev to be tested.
 | 
				
			||||||
 | 
								,1,*,bisect_rev*) VARS=1 ;;
 | 
				
			||||||
 | 
								,1,*,*) ;;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								# ???
 | 
				
			||||||
 | 
								*) die "filter_skipped error " \
 | 
				
			||||||
 | 
								    "VARS: '$VARS' " \
 | 
				
			||||||
 | 
								    "FOUND: '$FOUND' " \
 | 
				
			||||||
 | 
								    "TRIED: '$TRIED' " \
 | 
				
			||||||
 | 
								    "hash: '$hash' " \
 | 
				
			||||||
 | 
								    "line: '$line'"
 | 
				
			||||||
 | 
								;;
 | 
				
			||||||
 | 
							esac
 | 
				
			||||||
 | 
						done
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					exit_if_skipped_commits () {
 | 
				
			||||||
 | 
						_tried=$1
 | 
				
			||||||
 | 
						if expr "$_tried" : ".*[|].*" > /dev/null ; then
 | 
				
			||||||
 | 
							echo "There are only 'skip'ped commit left to test."
 | 
				
			||||||
 | 
							echo "The first bad commit could be any of:"
 | 
				
			||||||
 | 
							echo "$_tried" | sed -e 's/[|]/\n/g'
 | 
				
			||||||
 | 
							echo "We cannot bisect more!"
 | 
				
			||||||
 | 
							exit 2
 | 
				
			||||||
 | 
						fi
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bisect_next() {
 | 
					bisect_next() {
 | 
				
			||||||
        case "$#" in 0) ;; *) usage ;; esac
 | 
						case "$#" in 0) ;; *) usage ;; esac
 | 
				
			||||||
	bisect_autostart
 | 
						bisect_autostart
 | 
				
			||||||
	bisect_next_check good
 | 
						bisect_next_check good
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						skip=$(git for-each-ref --format='%(objectname)' \
 | 
				
			||||||
 | 
							"refs/bisect/skip-*" | tr '[\012]' ' ') || exit
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						BISECT_OPT=''
 | 
				
			||||||
 | 
						test -n "$skip" && BISECT_OPT='--bisect-all'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bad=$(git rev-parse --verify refs/bisect/bad) &&
 | 
						bad=$(git rev-parse --verify refs/bisect/bad) &&
 | 
				
			||||||
	good=$(git for-each-ref --format='^%(objectname)' \
 | 
						good=$(git for-each-ref --format='^%(objectname)' \
 | 
				
			||||||
		"refs/bisect/good-*" | tr '[\012]' ' ') &&
 | 
							"refs/bisect/good-*" | tr '[\012]' ' ') &&
 | 
				
			||||||
	eval="git rev-list --bisect-vars $good $bad --" &&
 | 
						eval="git rev-list --bisect-vars $BISECT_OPT $good $bad --" &&
 | 
				
			||||||
	eval="$eval $(cat "$GIT_DIR/BISECT_NAMES")" &&
 | 
						eval="$eval $(cat "$GIT_DIR/BISECT_NAMES")" &&
 | 
				
			||||||
	eval=$(eval "$eval") &&
 | 
						eval=$(filter_skipped "$eval" "$skip") &&
 | 
				
			||||||
	eval "$eval" || exit
 | 
						eval "$eval" || exit
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if [ -z "$bisect_rev" ]; then
 | 
						if [ -z "$bisect_rev" ]; then
 | 
				
			||||||
@ -224,11 +305,16 @@ bisect_next() {
 | 
				
			|||||||
		exit 1
 | 
							exit 1
 | 
				
			||||||
	fi
 | 
						fi
 | 
				
			||||||
	if [ "$bisect_rev" = "$bad" ]; then
 | 
						if [ "$bisect_rev" = "$bad" ]; then
 | 
				
			||||||
 | 
							exit_if_skipped_commits "$bisect_tried"
 | 
				
			||||||
		echo "$bisect_rev is first bad commit"
 | 
							echo "$bisect_rev is first bad commit"
 | 
				
			||||||
		git diff-tree --pretty $bisect_rev
 | 
							git diff-tree --pretty $bisect_rev
 | 
				
			||||||
		exit 0
 | 
							exit 0
 | 
				
			||||||
	fi
 | 
						fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						# We should exit here only if the "bad"
 | 
				
			||||||
 | 
						# commit is also a "skip" commit (see above).
 | 
				
			||||||
 | 
						exit_if_skipped_commits "$bisect_rev"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	echo "Bisecting: $bisect_nr revisions left to test after this"
 | 
						echo "Bisecting: $bisect_nr revisions left to test after this"
 | 
				
			||||||
	echo "$bisect_rev" >"$GIT_DIR/refs/heads/new-bisect"
 | 
						echo "$bisect_rev" >"$GIT_DIR/refs/heads/new-bisect"
 | 
				
			||||||
	git checkout -q new-bisect || exit
 | 
						git checkout -q new-bisect || exit
 | 
				
			||||||
@ -250,12 +336,10 @@ bisect_reset() {
 | 
				
			|||||||
	   else
 | 
						   else
 | 
				
			||||||
	       branch=master
 | 
						       branch=master
 | 
				
			||||||
	   fi ;;
 | 
						   fi ;;
 | 
				
			||||||
	1) git show-ref --verify --quiet -- "refs/heads/$1" || {
 | 
						1) git show-ref --verify --quiet -- "refs/heads/$1" ||
 | 
				
			||||||
	       echo >&2 "$1 does not seem to be a valid branch"
 | 
						       die "$1 does not seem to be a valid branch"
 | 
				
			||||||
	       exit 1
 | 
					 | 
				
			||||||
	   }
 | 
					 | 
				
			||||||
	   branch="$1" ;;
 | 
						   branch="$1" ;;
 | 
				
			||||||
        *)
 | 
						*)
 | 
				
			||||||
	    usage ;;
 | 
						    usage ;;
 | 
				
			||||||
	esac
 | 
						esac
 | 
				
			||||||
	if git checkout "$branch"; then
 | 
						if git checkout "$branch"; then
 | 
				
			||||||
@ -273,10 +357,7 @@ bisect_clean_state() {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bisect_replay () {
 | 
					bisect_replay () {
 | 
				
			||||||
	test -r "$1" || {
 | 
						test -r "$1" || die "cannot read $1 for replaying"
 | 
				
			||||||
		echo >&2 "cannot read $1 for replaying"
 | 
					 | 
				
			||||||
		exit 1
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	bisect_reset
 | 
						bisect_reset
 | 
				
			||||||
	while read bisect command rev
 | 
						while read bisect command rev
 | 
				
			||||||
	do
 | 
						do
 | 
				
			||||||
@ -284,21 +365,11 @@ bisect_replay () {
 | 
				
			|||||||
		case "$command" in
 | 
							case "$command" in
 | 
				
			||||||
		start)
 | 
							start)
 | 
				
			||||||
			cmd="bisect_start $rev"
 | 
								cmd="bisect_start $rev"
 | 
				
			||||||
			eval "$cmd"
 | 
								eval "$cmd" ;;
 | 
				
			||||||
			;;
 | 
							good|bad|skip)
 | 
				
			||||||
		good)
 | 
								bisect_write "$command" "$rev" ;;
 | 
				
			||||||
			echo "$rev" >"$GIT_DIR/refs/bisect/good-$rev"
 | 
					 | 
				
			||||||
			echo "# good: "$(git show-branch $rev) >>"$GIT_DIR/BISECT_LOG"
 | 
					 | 
				
			||||||
			echo "git-bisect good $rev" >>"$GIT_DIR/BISECT_LOG"
 | 
					 | 
				
			||||||
			;;
 | 
					 | 
				
			||||||
		bad)
 | 
					 | 
				
			||||||
			echo "$rev" >"$GIT_DIR/refs/bisect/bad"
 | 
					 | 
				
			||||||
			echo "# bad: "$(git show-branch $rev) >>"$GIT_DIR/BISECT_LOG"
 | 
					 | 
				
			||||||
			echo "git-bisect bad $rev" >>"$GIT_DIR/BISECT_LOG"
 | 
					 | 
				
			||||||
			;;
 | 
					 | 
				
			||||||
		*)
 | 
							*)
 | 
				
			||||||
			echo >&2 "?? what are you talking about?"
 | 
								die "?? what are you talking about?" ;;
 | 
				
			||||||
			exit 1 ;;
 | 
					 | 
				
			||||||
		esac
 | 
							esac
 | 
				
			||||||
	done <"$1"
 | 
						done <"$1"
 | 
				
			||||||
	bisect_auto_next
 | 
						bisect_auto_next
 | 
				
			||||||
@ -320,24 +391,31 @@ bisect_run () {
 | 
				
			|||||||
	  exit $res
 | 
						  exit $res
 | 
				
			||||||
      fi
 | 
					      fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      # Use "bisect_good" or "bisect_bad"
 | 
					      # Find current state depending on run success or failure.
 | 
				
			||||||
      # depending on run success or failure.
 | 
					      # A special exit code of 125 means cannot test.
 | 
				
			||||||
      if [ $res -gt 0 ]; then
 | 
					      if [ $res -eq 125 ]; then
 | 
				
			||||||
	  next_bisect='bisect_bad'
 | 
						  state='skip'
 | 
				
			||||||
 | 
					      elif [ $res -gt 0 ]; then
 | 
				
			||||||
 | 
						  state='bad'
 | 
				
			||||||
      else
 | 
					      else
 | 
				
			||||||
	  next_bisect='bisect_good'
 | 
						  state='good'
 | 
				
			||||||
      fi
 | 
					      fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      # We have to use a subshell because bisect_good or
 | 
					      # We have to use a subshell because "bisect_state" can exit.
 | 
				
			||||||
      # bisect_bad functions can exit.
 | 
					      ( bisect_state $state > "$GIT_DIR/BISECT_RUN" )
 | 
				
			||||||
      ( $next_bisect > "$GIT_DIR/BISECT_RUN" )
 | 
					 | 
				
			||||||
      res=$?
 | 
					      res=$?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      cat "$GIT_DIR/BISECT_RUN"
 | 
					      cat "$GIT_DIR/BISECT_RUN"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if grep "first bad commit could be any of" "$GIT_DIR/BISECT_RUN" \
 | 
				
			||||||
 | 
							> /dev/null; then
 | 
				
			||||||
 | 
						  echo >&2 "bisect run cannot continue any more"
 | 
				
			||||||
 | 
						  exit $res
 | 
				
			||||||
 | 
					      fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if [ $res -ne 0 ]; then
 | 
					      if [ $res -ne 0 ]; then
 | 
				
			||||||
	  echo >&2 "bisect run failed:"
 | 
						  echo >&2 "bisect run failed:"
 | 
				
			||||||
	  echo >&2 "$next_bisect exited with error code $res"
 | 
						  echo >&2 "'bisect_state $state' exited with error code $res"
 | 
				
			||||||
	  exit $res
 | 
						  exit $res
 | 
				
			||||||
      fi
 | 
					      fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -359,10 +437,8 @@ case "$#" in
 | 
				
			|||||||
    case "$cmd" in
 | 
					    case "$cmd" in
 | 
				
			||||||
    start)
 | 
					    start)
 | 
				
			||||||
        bisect_start "$@" ;;
 | 
					        bisect_start "$@" ;;
 | 
				
			||||||
    bad)
 | 
					    bad|good|skip)
 | 
				
			||||||
        bisect_bad "$@" ;;
 | 
					        bisect_state "$cmd" "$@" ;;
 | 
				
			||||||
    good)
 | 
					 | 
				
			||||||
        bisect_good "$@" ;;
 | 
					 | 
				
			||||||
    next)
 | 
					    next)
 | 
				
			||||||
        # Not sure we want "next" at the UI level anymore.
 | 
					        # Not sure we want "next" at the UI level anymore.
 | 
				
			||||||
        bisect_next "$@" ;;
 | 
					        bisect_next "$@" ;;
 | 
				
			||||||
 | 
				
			|||||||
@ -15,7 +15,7 @@ static void show_parents(struct commit *commit, int abbrev)
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void show_decorations(struct commit *commit)
 | 
					void show_decorations(struct commit *commit)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	const char *prefix;
 | 
						const char *prefix;
 | 
				
			||||||
	struct name_decoration *decoration;
 | 
						struct name_decoration *decoration;
 | 
				
			||||||
 | 
				
			|||||||
@ -12,5 +12,6 @@ int log_tree_diff_flush(struct rev_info *);
 | 
				
			|||||||
int log_tree_commit(struct rev_info *, struct commit *);
 | 
					int log_tree_commit(struct rev_info *, struct commit *);
 | 
				
			||||||
int log_tree_opt_parse(struct rev_info *, const char **, int);
 | 
					int log_tree_opt_parse(struct rev_info *, const char **, int);
 | 
				
			||||||
void show_log(struct rev_info *opt, const char *sep);
 | 
					void show_log(struct rev_info *opt, const char *sep);
 | 
				
			||||||
 | 
					void show_decorations(struct commit *commit);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
				
			|||||||
@ -71,6 +71,63 @@ test_expect_success 'bisect start with one bad and good' '
 | 
				
			|||||||
	git bisect next
 | 
						git bisect next
 | 
				
			||||||
'
 | 
					'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# $HASH1 is good, $HASH4 is bad, we skip $HASH3
 | 
				
			||||||
 | 
					# but $HASH2 is bad,
 | 
				
			||||||
 | 
					# so we should find $HASH2 as the first bad commit
 | 
				
			||||||
 | 
					test_expect_success 'bisect skip: successfull result' '
 | 
				
			||||||
 | 
						git bisect reset &&
 | 
				
			||||||
 | 
						git bisect start $HASH4 $HASH1 &&
 | 
				
			||||||
 | 
						git bisect skip &&
 | 
				
			||||||
 | 
						git bisect bad > my_bisect_log.txt &&
 | 
				
			||||||
 | 
						grep "$HASH2 is first bad commit" my_bisect_log.txt &&
 | 
				
			||||||
 | 
						git bisect reset
 | 
				
			||||||
 | 
					'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# $HASH1 is good, $HASH4 is bad, we skip $HASH3 and $HASH2
 | 
				
			||||||
 | 
					# so we should not be able to tell the first bad commit
 | 
				
			||||||
 | 
					# among $HASH2, $HASH3 and $HASH4
 | 
				
			||||||
 | 
					test_expect_success 'bisect skip: cannot tell between 3 commits' '
 | 
				
			||||||
 | 
						git bisect start $HASH4 $HASH1 &&
 | 
				
			||||||
 | 
						git bisect skip || return 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if git bisect skip > my_bisect_log.txt
 | 
				
			||||||
 | 
						then
 | 
				
			||||||
 | 
							echo Oops, should have failed.
 | 
				
			||||||
 | 
							false
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							test $? -eq 2 &&
 | 
				
			||||||
 | 
							grep "first bad commit could be any of" my_bisect_log.txt &&
 | 
				
			||||||
 | 
							! grep $HASH1 my_bisect_log.txt &&
 | 
				
			||||||
 | 
							grep $HASH2 my_bisect_log.txt &&
 | 
				
			||||||
 | 
							grep $HASH3 my_bisect_log.txt &&
 | 
				
			||||||
 | 
							grep $HASH4 my_bisect_log.txt &&
 | 
				
			||||||
 | 
							git bisect reset
 | 
				
			||||||
 | 
						fi
 | 
				
			||||||
 | 
					'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# $HASH1 is good, $HASH4 is bad, we skip $HASH3
 | 
				
			||||||
 | 
					# but $HASH2 is good,
 | 
				
			||||||
 | 
					# so we should not be able to tell the first bad commit
 | 
				
			||||||
 | 
					# among $HASH3 and $HASH4
 | 
				
			||||||
 | 
					test_expect_success 'bisect skip: cannot tell between 2 commits' '
 | 
				
			||||||
 | 
						git bisect start $HASH4 $HASH1 &&
 | 
				
			||||||
 | 
						git bisect skip || return 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if git bisect good > my_bisect_log.txt
 | 
				
			||||||
 | 
						then
 | 
				
			||||||
 | 
							echo Oops, should have failed.
 | 
				
			||||||
 | 
							false
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							test $? -eq 2 &&
 | 
				
			||||||
 | 
							grep "first bad commit could be any of" my_bisect_log.txt &&
 | 
				
			||||||
 | 
							! grep $HASH1 my_bisect_log.txt &&
 | 
				
			||||||
 | 
							! grep $HASH2 my_bisect_log.txt &&
 | 
				
			||||||
 | 
							grep $HASH3 my_bisect_log.txt &&
 | 
				
			||||||
 | 
							grep $HASH4 my_bisect_log.txt &&
 | 
				
			||||||
 | 
							git bisect reset
 | 
				
			||||||
 | 
						fi
 | 
				
			||||||
 | 
					'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# We want to automatically find the commit that
 | 
					# We want to automatically find the commit that
 | 
				
			||||||
# introduced "Another" into hello.
 | 
					# introduced "Another" into hello.
 | 
				
			||||||
test_expect_success \
 | 
					test_expect_success \
 | 
				
			||||||
@ -99,6 +156,67 @@ test_expect_success \
 | 
				
			|||||||
     grep "$HASH4 is first bad commit" my_bisect_log.txt &&
 | 
					     grep "$HASH4 is first bad commit" my_bisect_log.txt &&
 | 
				
			||||||
     git bisect reset'
 | 
					     git bisect reset'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# $HASH1 is good, $HASH5 is bad, we skip $HASH3
 | 
				
			||||||
 | 
					# but $HASH4 is good,
 | 
				
			||||||
 | 
					# so we should find $HASH5 as the first bad commit
 | 
				
			||||||
 | 
					HASH5=
 | 
				
			||||||
 | 
					test_expect_success 'bisect skip: add line and then a new test' '
 | 
				
			||||||
 | 
						add_line_into_file "5: Another new line." hello &&
 | 
				
			||||||
 | 
						HASH5=$(git rev-parse --verify HEAD) &&
 | 
				
			||||||
 | 
						git bisect start $HASH5 $HASH1 &&
 | 
				
			||||||
 | 
						git bisect skip &&
 | 
				
			||||||
 | 
						git bisect good > my_bisect_log.txt &&
 | 
				
			||||||
 | 
						grep "$HASH5 is first bad commit" my_bisect_log.txt &&
 | 
				
			||||||
 | 
						git bisect log > log_to_replay.txt
 | 
				
			||||||
 | 
						git bisect reset
 | 
				
			||||||
 | 
					'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_expect_success 'bisect skip and bisect replay' '
 | 
				
			||||||
 | 
						git bisect replay log_to_replay.txt > my_bisect_log.txt &&
 | 
				
			||||||
 | 
						grep "$HASH5 is first bad commit" my_bisect_log.txt &&
 | 
				
			||||||
 | 
						git bisect reset
 | 
				
			||||||
 | 
					'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					HASH6=
 | 
				
			||||||
 | 
					test_expect_success 'bisect run & skip: cannot tell between 2' '
 | 
				
			||||||
 | 
						add_line_into_file "6: Yet a line." hello &&
 | 
				
			||||||
 | 
						HASH6=$(git rev-parse --verify HEAD) &&
 | 
				
			||||||
 | 
						echo "#"\!"/bin/sh" > test_script.sh &&
 | 
				
			||||||
 | 
						echo "tail -1 hello | grep Ciao > /dev/null && exit 125" >> test_script.sh &&
 | 
				
			||||||
 | 
						echo "grep line hello > /dev/null" >> test_script.sh &&
 | 
				
			||||||
 | 
						echo "test \$? -ne 0" >> test_script.sh &&
 | 
				
			||||||
 | 
						chmod +x test_script.sh &&
 | 
				
			||||||
 | 
						git bisect start $HASH6 $HASH1 &&
 | 
				
			||||||
 | 
						if git bisect run ./test_script.sh > my_bisect_log.txt
 | 
				
			||||||
 | 
						then
 | 
				
			||||||
 | 
							echo Oops, should have failed.
 | 
				
			||||||
 | 
							false
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							test $? -eq 2 &&
 | 
				
			||||||
 | 
							grep "first bad commit could be any of" my_bisect_log.txt &&
 | 
				
			||||||
 | 
							! grep $HASH3 my_bisect_log.txt &&
 | 
				
			||||||
 | 
							! grep $HASH6 my_bisect_log.txt &&
 | 
				
			||||||
 | 
							grep $HASH4 my_bisect_log.txt &&
 | 
				
			||||||
 | 
							grep $HASH5 my_bisect_log.txt
 | 
				
			||||||
 | 
						fi
 | 
				
			||||||
 | 
					'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					HASH7=
 | 
				
			||||||
 | 
					test_expect_success 'bisect run & skip: find first bad' '
 | 
				
			||||||
 | 
						git bisect reset &&
 | 
				
			||||||
 | 
						add_line_into_file "7: Should be the last line." hello &&
 | 
				
			||||||
 | 
						HASH7=$(git rev-parse --verify HEAD) &&
 | 
				
			||||||
 | 
						echo "#"\!"/bin/sh" > test_script.sh &&
 | 
				
			||||||
 | 
						echo "tail -1 hello | grep Ciao > /dev/null && exit 125" >> test_script.sh &&
 | 
				
			||||||
 | 
						echo "tail -1 hello | grep day > /dev/null && exit 125" >> test_script.sh &&
 | 
				
			||||||
 | 
						echo "grep Yet hello > /dev/null" >> test_script.sh &&
 | 
				
			||||||
 | 
						echo "test \$? -ne 0" >> test_script.sh &&
 | 
				
			||||||
 | 
						chmod +x test_script.sh &&
 | 
				
			||||||
 | 
						git bisect start $HASH7 $HASH1 &&
 | 
				
			||||||
 | 
						git bisect run ./test_script.sh > my_bisect_log.txt &&
 | 
				
			||||||
 | 
						grep "$HASH6 is first bad commit" my_bisect_log.txt
 | 
				
			||||||
 | 
					'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
test_done
 | 
					test_done
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user