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:
Junio C Hamano 2007-10-30 21:38:07 -07:00
commit 9725bb8b85
7 changed files with 410 additions and 108 deletions

View file

@ -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>
@ -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
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -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

View file

@ -34,6 +34,7 @@ SYNOPSIS
[ \--pretty | \--header ]
[ \--bisect ]
[ \--bisect-vars ]
[ \--bisect-all ]
[ \--merge ]
[ \--reverse ]
[ \--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
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

View file

@ -9,6 +9,7 @@
#include "revision.h"
#include "list-objects.h"
#include "builtin.h"
#include "log-tree.h"
/* bits #0-15 in revision.h */
@ -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;
@ -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
@ -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
@ -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;
@ -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++;
}
@ -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;
@ -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;
}
@ -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);
@ -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;
@ -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;
/*
@ -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,

View file

@ -1,12 +1,14 @@
#!/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>...]
reset bisect state and start bisection.
git bisect bad [<rev>]
mark <rev> a known-bad revision.
git bisect good [<rev>...]
mark <rev>... known-good revisions.
git bisect skip [<rev>...]
mark <rev>... untestable revisions.
git bisect next
find next bisection to test and check it out.
git bisect reset [<branch>]
@ -64,7 +66,7 @@ bisect_start() {
branch=`cat "$GIT_DIR/head-name"`
else
branch=master
fi
fi
git checkout $branch || exit
;;
refs/heads/*)
@ -95,75 +97,74 @@ bisect_start() {
arg="$1"
case "$arg" in
--)
shift
shift
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 &&
die "'$arg' does not appear to be a valid revision"
break
}
if [ $bad_seen -eq 0 ]; then
bad_seen=1
bisect_write_bad "$rev"
else
bisect_write_good "$rev"
fi
shift
case $bad_seen in
0) state='bad' ; bad_seen=1 ;;
*) state='good' ;;
esac
bisect_write "$state" "$rev" 'nolog'
shift
;;
esac
done
done
sq "$@" >"$GIT_DIR/BISECT_NAMES"
echo "git-bisect start$orig_args" >>"$GIT_DIR/BISECT_LOG"
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
case "$#" in
0)
rev=$(git rev-parse --verify HEAD) ;;
1)
rev=$(git rev-parse --verify "$1^{commit}") ;;
state=$1
case "$#,$state" in
0,*)
die "Please call 'bisect_state' with at least one argument." ;;
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 ;;
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
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_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() {
missing_good= missing_bad=
git show-ref -q --verify refs/bisect/bad || missing_bad=t
@ -206,17 +207,97 @@ bisect_auto_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() {
case "$#" in 0) ;; *) usage ;; esac
case "$#" in 0) ;; *) usage ;; esac
bisect_autostart
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) &&
good=$(git for-each-ref --format='^%(objectname)' \
"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 "$eval") &&
eval=$(filter_skipped "$eval" "$skip") &&
eval "$eval" || exit
if [ -z "$bisect_rev" ]; then
@ -224,11 +305,16 @@ bisect_next() {
exit 1
fi
if [ "$bisect_rev" = "$bad" ]; then
exit_if_skipped_commits "$bisect_tried"
echo "$bisect_rev is first bad commit"
git diff-tree --pretty $bisect_rev
exit 0
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 "$bisect_rev" >"$GIT_DIR/refs/heads/new-bisect"
git checkout -q new-bisect || exit
@ -250,12 +336,10 @@ bisect_reset() {
else
branch=master
fi ;;
1) git show-ref --verify --quiet -- "refs/heads/$1" || {
echo >&2 "$1 does not seem to be a valid branch"
exit 1
}
1) git show-ref --verify --quiet -- "refs/heads/$1" ||
die "$1 does not seem to be a valid branch"
branch="$1" ;;
*)
*)
usage ;;
esac
if git checkout "$branch"; then
@ -273,10 +357,7 @@ bisect_clean_state() {
}
bisect_replay () {
test -r "$1" || {
echo >&2 "cannot read $1 for replaying"
exit 1
}
test -r "$1" || die "cannot read $1 for replaying"
bisect_reset
while read bisect command rev
do
@ -284,21 +365,11 @@ bisect_replay () {
case "$command" in
start)
cmd="bisect_start $rev"
eval "$cmd"
;;
good)
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"
;;
eval "$cmd" ;;
good|bad|skip)
bisect_write "$command" "$rev" ;;
*)
echo >&2 "?? what are you talking about?"
exit 1 ;;
die "?? what are you talking about?" ;;
esac
done <"$1"
bisect_auto_next
@ -320,24 +391,31 @@ bisect_run () {
exit $res
fi
# Use "bisect_good" or "bisect_bad"
# depending on run success or failure.
if [ $res -gt 0 ]; then
next_bisect='bisect_bad'
# Find current state depending on run success or failure.
# A special exit code of 125 means cannot test.
if [ $res -eq 125 ]; then
state='skip'
elif [ $res -gt 0 ]; then
state='bad'
else
next_bisect='bisect_good'
state='good'
fi
# We have to use a subshell because bisect_good or
# bisect_bad functions can exit.
( $next_bisect > "$GIT_DIR/BISECT_RUN" )
# We have to use a subshell because "bisect_state" can exit.
( bisect_state $state > "$GIT_DIR/BISECT_RUN" )
res=$?
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
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
fi
@ -359,10 +437,8 @@ case "$#" in
case "$cmd" in
start)
bisect_start "$@" ;;
bad)
bisect_bad "$@" ;;
good)
bisect_good "$@" ;;
bad|good|skip)
bisect_state "$cmd" "$@" ;;
next)
# Not sure we want "next" at the UI level anymore.
bisect_next "$@" ;;

View file

@ -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;
struct name_decoration *decoration;

View file

@ -12,5 +12,6 @@ int log_tree_diff_flush(struct rev_info *);
int log_tree_commit(struct rev_info *, struct commit *);
int log_tree_opt_parse(struct rev_info *, const char **, int);
void show_log(struct rev_info *opt, const char *sep);
void show_decorations(struct commit *commit);
#endif

View file

@ -71,6 +71,63 @@ test_expect_success 'bisect start with one bad and good' '
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
# introduced "Another" into hello.
test_expect_success \
@ -99,6 +156,67 @@ test_expect_success \
grep "$HASH4 is first bad commit" my_bisect_log.txt &&
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