Merge branch 'mr/bisect-in-c-2' into pu

Rewrite of the remainder of "git bisect" script in C continues.

* mr/bisect-in-c-2:
  bisect--helper: retire `--bisect-autostart` subcommand
  bisect--helper: retire `--write-terms` subcommand
  bisect--helper: retire `--check-expected-revs` subcommand
  bisect--helper: reimplement `bisect_state` & `bisect_head` shell functions in C
  bisect--helper: retire `--next-all` subcommand
  bisect--helper: retire `--bisect-clean-state` subcommand
  bisect--helper: finish porting `bisect_start()` to C
  bisect--helper: reimplement `bisect_next` and `bisect_auto_next` shell functions in C
  bisect--helper: reimplement `bisect_autostart` shell function in C
  bisect--helper: introduce new `write_in_file()` function
  bisect--helper: use '-res' in 'cmd_bisect__helper' return
  bisect--helper: fix `cmd_*()` function switch default return
This commit is contained in:
Junio C Hamano
2020-06-19 14:52:44 -07:00
3 changed files with 347 additions and 189 deletions

View File

@ -980,6 +980,12 @@ void read_bisect_terms(const char **read_bad, const char **read_good)
* the bisection process finished successfully.
* In this case the calling function or command should not turn a
* BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND return code into an error or a non zero exit code.
*
* Checking BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND
* in bisect_helper::bisect_next() and only transforming it to 0 at
* the end of bisect_helper::cmd_bisect__helper() helps bypassing
* all the code related to finding a commit to test.
*
* If no_checkout is non-zero, the bisection process does not
* checkout the trial commit but instead simply updates BISECT_HEAD.
*/
@ -1064,6 +1070,8 @@ enum bisect_error bisect_next_all(struct repository *r, const char *prefix, int
"Bisecting: %d revisions left to test after this %s\n",
nr), nr, steps_msg);
free(steps_msg);
/* Clean up objects used, as they will be reused. */
clear_commit_marks_all(ALL_REV_FLAGS);
return bisect_checkout(bisect_rev, no_checkout);
}

View File

@ -8,6 +8,7 @@
#include "run-command.h"
#include "prompt.h"
#include "quote.h"
#include "revision.h"
static GIT_PATH_FUNC(git_path_bisect_terms, "BISECT_TERMS")
static GIT_PATH_FUNC(git_path_bisect_expected_rev, "BISECT_EXPECTED_REV")
@ -19,9 +20,6 @@ static GIT_PATH_FUNC(git_path_head_name, "head-name")
static GIT_PATH_FUNC(git_path_bisect_names, "BISECT_NAMES")
static const char * const git_bisect_helper_usage[] = {
N_("git bisect--helper --next-all [--no-checkout]"),
N_("git bisect--helper --write-terms <bad_term> <good_term>"),
N_("git bisect--helper --bisect-clean-state"),
N_("git bisect--helper --bisect-reset [<commit>]"),
N_("git bisect--helper --bisect-write [--no-log] <state> <revision> <good_term> <bad_term>"),
N_("git bisect--helper --bisect-check-and-set-terms <command> <good_term> <bad_term>"),
@ -29,6 +27,10 @@ static const char * const git_bisect_helper_usage[] = {
N_("git bisect--helper --bisect-terms [--term-good | --term-old | --term-bad | --term-new]"),
N_("git bisect--helper --bisect-start [--term-{old,good}=<term> --term-{new,bad}=<term>]"
"[--no-checkout] [<bad> [<good>...]] [--] [<paths>...]"),
N_("git bisect--helper --bisect-next"),
N_("git bisect--helper --bisect-auto-next"),
N_("git bisect--helper --bisect-state (bad|new) [<rev>]"),
N_("git bisect--helper --bisect-state (good|old) [<rev>...]"),
NULL
};
@ -55,6 +57,8 @@ static void set_terms(struct bisect_terms *terms, const char *bad,
static const char vocab_bad[] = "bad|new";
static const char vocab_good[] = "good|old";
static int bisect_autostart(struct bisect_terms *terms);
/*
* Check whether the string `term` belongs to the set of strings
* included in the variable arguments.
@ -74,6 +78,28 @@ static int one_of(const char *term, ...)
return res;
}
static int write_in_file(const char *path, const char *mode, const char *format,...)
{
FILE *fp = NULL;
va_list args;
int res = 0;
if (!strcmp(mode, "a") && !strcmp(mode, "w"))
return error(_("wrong writing mode '%s'"), mode);
fp = fopen(path, mode);
if (!fp)
return error_errno(_("cannot open file '%s' in mode '%s'"), path, mode);
va_start(args, format);
res = vfprintf(fp, format, args);
va_end(args);
if (!res) {
fclose(fp);
return error_errno(_("could not write to file '%s'"), path);
}
return fclose(fp);
}
static int check_term_format(const char *term, const char *orig_term)
{
int res;
@ -104,7 +130,6 @@ static int check_term_format(const char *term, const char *orig_term)
static int write_terms(const char *bad, const char *good)
{
FILE *fp = NULL;
int res;
if (!strcmp(bad, good))
@ -113,12 +138,8 @@ static int write_terms(const char *bad, const char *good)
if (check_term_format(bad, "bad") || check_term_format(good, "good"))
return -1;
fp = fopen(git_path_bisect_terms(), "w");
if (!fp)
return error_errno(_("could not open the file BISECT_TERMS"));
res = write_in_file(git_path_bisect_terms(), "w", "%s\n%s\n", bad, good);
res = fprintf(fp, "%s\n%s\n", bad, good);
res |= fclose(fp);
return (res < 0) ? -1 : 0;
}
@ -421,11 +442,156 @@ finish:
return res;
}
static int bisect_start(struct bisect_terms *terms, int no_checkout,
static int register_good_ref(const char *refname,
const struct object_id *oid, int flags,
void *cb_data)
{
struct argv_array *rev_argv = cb_data;
argv_array_push(rev_argv, oid_to_hex(oid));
return 0;
}
static void prepare_rev_argv(struct bisect_terms *terms, struct argv_array *rev_argv)
{
char *term_good = xstrfmt("%s-*", terms->term_good);
argv_array_pushl(rev_argv, "skipped_commits", "refs/bisect/bad", "--not", NULL);
for_each_glob_ref_in(register_good_ref, term_good, "refs/bisect/", rev_argv);
free(term_good);
}
static int prepare_revs(struct bisect_terms *terms, struct rev_info *revs)
{
int res = 0;
struct argv_array rev_argv = ARGV_ARRAY_INIT;
prepare_rev_argv(terms, &rev_argv);
/*
* It is important to reset the flags used by revision walks
* as the previous call to bisect_next_all() in turn
* sets up a revision walk.
*/
reset_revision_walk();
init_revisions(revs, NULL);
rev_argv.argc = setup_revisions(rev_argv.argc, rev_argv.argv, revs, NULL);
if (prepare_revision_walk(revs))
res = error(_("revision walk setup failed\n"));
argv_array_clear(&rev_argv);
return res;
}
static int process_skipped_commits(FILE *fp, struct bisect_terms *terms, struct rev_info *revs)
{
struct commit *commit;
struct pretty_print_context pp = {0};
if (fprintf(fp, "# only skipped commits left to test\n") < 0)
return error_errno(_("failed to write to '%s'"), git_path_bisect_log());
while ((commit = get_revision(revs)) != NULL) {
struct strbuf commit_name = STRBUF_INIT;
format_commit_message(commit, "%s",
&commit_name, &pp);
fprintf(fp, "# possible first %s commit: [%s] %s\n",
terms->term_bad, oid_to_hex(&commit->object.oid),
commit_name.buf);
strbuf_release(&commit_name);
}
/*
* Reset the flags used by revision walks in case
* there is another revision walk after this one.
*/
reset_revision_walk();
return 0;
}
static int bisect_skipped_commits(struct bisect_terms *terms)
{
int res = 0;
FILE *fp = NULL;
struct rev_info revs;
fp = fopen(git_path_bisect_log(), "a");
if (!fp)
return error_errno(_("could not open '%s' for appending"),
git_path_bisect_log());
res = prepare_revs(terms, &revs);
if (!res)
res = process_skipped_commits(fp, terms, &revs);
fclose(fp);
return res;
}
static int bisect_successful(struct bisect_terms *terms)
{
struct object_id oid;
struct commit *commit;
struct pretty_print_context pp = {0};
struct strbuf commit_name = STRBUF_INIT;
char *bad_ref = xstrfmt("refs/bisect/%s",terms->term_bad);
int res;
read_ref(bad_ref, &oid);
printf("%s\n", bad_ref);
commit = lookup_commit_reference(the_repository, &oid);
format_commit_message(commit, "%s", &commit_name, &pp);
res = write_in_file(git_path_bisect_log(), "a", "# first %s commit: [%s] %s\n",
terms->term_bad, oid_to_hex(&oid),
commit_name.buf);
strbuf_release(&commit_name);
free(bad_ref);
return res;
}
static enum bisect_error bisect_next(struct bisect_terms *terms, const char *prefix)
{
int no_checkout;
enum bisect_error res;
bisect_autostart(terms);
if (bisect_next_check(terms, terms->term_good))
return BISECT_FAILED;
no_checkout = file_exists(git_path_bisect_head());
/* Perform all bisection computation, display and checkout */
res = bisect_next_all(the_repository, prefix, no_checkout);
if (res == BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND) {
res = bisect_successful(terms);
return res ? res : BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND;
} else if (res == BISECT_ONLY_SKIPPED_LEFT) {
res = bisect_skipped_commits(terms);
return res ? res : BISECT_ONLY_SKIPPED_LEFT;
}
return res;
}
static enum bisect_error bisect_auto_next(struct bisect_terms *terms, const char *prefix)
{
if (bisect_next_check(terms, NULL))
return BISECT_OK;
return bisect_next(terms, prefix);
}
static enum bisect_error bisect_start(struct bisect_terms *terms, int no_checkout,
const char **argv, int argc)
{
int i, has_double_dash = 0, must_write_terms = 0, bad_seen = 0;
int flags, pathspec_pos, res = 0;
int flags, pathspec_pos;
enum bisect_error res = BISECT_OK;
struct string_list revs = STRING_LIST_INIT_DUP;
struct string_list states = STRING_LIST_INIT_DUP;
struct strbuf start_head = STRBUF_INIT;
@ -483,9 +649,12 @@ static int bisect_start(struct bisect_terms *terms, int no_checkout,
return error(_("unrecognized option: '%s'"), arg);
} else {
char *commit_id = xstrfmt("%s^{commit}", arg);
if (get_oid(commit_id, &oid) && has_double_dash)
die(_("'%s' does not appear to be a valid "
"revision"), arg);
if (get_oid(commit_id, &oid) && has_double_dash) {
error(_("'%s' does not appear to be a valid "
"revision"), arg);
free(commit_id);
return BISECT_FAILED;
}
string_list_append(&revs, oid_to_hex(&oid));
free(commit_id);
@ -563,12 +732,12 @@ static int bisect_start(struct bisect_terms *terms, int no_checkout,
* Get rid of any old bisect state.
*/
if (bisect_clean_state())
return -1;
return BISECT_FAILED;
/*
* In case of mistaken revs or checkout error, or signals received,
* In case of mistaken revs or checkout error,
* "bisect_auto_next" below may exit or misbehave.
* We have to trap this to be able to clean up using
* We have to handle this to be able to clean up using
* "bisect_clean_state".
*/
@ -584,7 +753,7 @@ static int bisect_start(struct bisect_terms *terms, int no_checkout,
}
if (update_ref(NULL, "BISECT_HEAD", &oid, NULL, 0,
UPDATE_REFS_MSG_ON_ERR)) {
res = -1;
res = BISECT_FAILED;
goto finish;
}
}
@ -596,52 +765,153 @@ static int bisect_start(struct bisect_terms *terms, int no_checkout,
for (i = 0; i < states.nr; i++)
if (bisect_write(states.items[i].string,
revs.items[i].string, terms, 1)) {
res = -1;
res = BISECT_FAILED;
goto finish;
}
if (must_write_terms && write_terms(terms->term_bad,
terms->term_good)) {
res = -1;
res = BISECT_FAILED;
goto finish;
}
res = bisect_append_log_quoted(argv);
if (res)
res = -1;
res = BISECT_FAILED;
finish:
string_list_clear(&revs, 0);
string_list_clear(&states, 0);
strbuf_release(&start_head);
strbuf_release(&bisect_names);
if (res)
return res;
res = bisect_auto_next(terms, NULL);
/*
* In case of mistaken revs or checkout error, or signals received,
* "bisect_auto_next" below may exit or misbehave.
* We have to handle this to be able to clean up using
* "bisect_clean_state".
* return code BISECT_INTERNAL_SUCCESS_MERGE_BASE is special code
* that indicates special success.
* -> bisect_start()
* . res = bisect_auto_next()
* -> bisect_auto_next()
* . return bisect_next()
* -> bisect_next()
* . res = bisect_next_all()
* -> bisect_next_all()
* . res = check_good_are_ancestors_of_bad()
* -> check_good_are_ancestors_of_bad()
* . res = check_merge_bases()
* -> check_merge_bases()
* . res = BISECT_INTERNAL_SUCCESS_MERGE_BASE
*/
if (res && res != BISECT_INTERNAL_SUCCESS_MERGE_BASE)
bisect_clean_state();
return res;
}
static int bisect_autostart(struct bisect_terms *terms)
{
const char *yesno;
if (!is_empty_or_missing_file(git_path_bisect_start()))
return 0;
fprintf(stderr, _("You need to start by \"git bisect "
"start\"\n"));
if (!isatty(STDIN_FILENO))
return 1;
/*
* TRANSLATORS: Make sure to include [Y] and [n] in your
* translation. The program will only accept English input
* at this point.
*/
yesno = git_prompt(_("Do you want me to do it for you "
"[Y/n]? "), PROMPT_ECHO);
if (starts_with(yesno, _("n")) || starts_with(yesno, _("N")))
return 1;
return bisect_start(terms, 0, NULL, 0);
}
static int bisect_head(struct object_id *oid)
{
if (!file_exists(git_path_bisect_head()))
return get_oid("HEAD", oid);
return get_oid("BISECT_HEAD", oid);
}
static enum bisect_error bisect_state(struct bisect_terms *terms, const char **argv,
int argc)
{
const char *state;
const char *hex;
int i;
struct oid_array revs = OID_ARRAY_INIT;
struct object_id oid;
if (!argc)
return error(_("Please call `--bisect-state` with at least one argument"));
state = argv[0];
if (check_and_set_terms(terms, state) ||
!one_of(state, terms->term_good,terms->term_bad, "skip", NULL))
return BISECT_FAILED;
argv++;
argc--;
if (!strcmp(state, terms->term_bad) && (argc > 1))
return error(_("'git bisect %s' can take only one argument."),terms->term_bad);
if (argc == 0) {
if (bisect_head(&oid))
return error(_("Bad bisect_head rev input"));
hex = oid_to_hex(&oid);
if (bisect_write(state, hex, terms, 0))
return BISECT_FAILED;
check_expected_revs(&hex, 1);
return bisect_auto_next(terms, NULL);
}
/* Here argc > 0 */
for (; argc; argc--, argv++) {
struct object_id oid;
if (get_oid(*argv, &oid))
return error(_("Bad rev input: %s"), *argv);
oid_array_append(&revs, &oid);
}
for (i = 0; i < revs.nr; i++) {
hex = oid_to_hex(&revs.oid[i]);
if (bisect_write(state, hex, terms, 0)) {
oid_array_clear(&revs);
return BISECT_FAILED;
}
check_expected_revs(&hex, 1);
}
oid_array_clear(&revs);
return bisect_auto_next(terms, NULL);
}
int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
{
enum {
NEXT_ALL = 1,
WRITE_TERMS,
BISECT_CLEAN_STATE,
CHECK_EXPECTED_REVS,
BISECT_RESET,
BISECT_RESET = 1,
BISECT_WRITE,
CHECK_AND_SET_TERMS,
BISECT_NEXT_CHECK,
BISECT_TERMS,
BISECT_START
BISECT_START,
BISECT_NEXT,
BISECT_AUTO_NEXT,
BISECT_STATE
} cmdmode = 0;
int no_checkout = 0, res = 0, nolog = 0;
struct option options[] = {
OPT_CMDMODE(0, "next-all", &cmdmode,
N_("perform 'git bisect next'"), NEXT_ALL),
OPT_CMDMODE(0, "write-terms", &cmdmode,
N_("write the terms to .git/BISECT_TERMS"), WRITE_TERMS),
OPT_CMDMODE(0, "bisect-clean-state", &cmdmode,
N_("cleanup the bisection state"), BISECT_CLEAN_STATE),
OPT_CMDMODE(0, "check-expected-revs", &cmdmode,
N_("check for expected revs"), CHECK_EXPECTED_REVS),
OPT_CMDMODE(0, "bisect-reset", &cmdmode,
N_("reset the bisection state"), BISECT_RESET),
OPT_CMDMODE(0, "bisect-write", &cmdmode,
@ -654,6 +924,12 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
N_("print out the bisect terms"), BISECT_TERMS),
OPT_CMDMODE(0, "bisect-start", &cmdmode,
N_("start the bisect session"), BISECT_START),
OPT_CMDMODE(0, "bisect-next", &cmdmode,
N_("find the next bisection commit"), BISECT_NEXT),
OPT_CMDMODE(0, "bisect-auto-next", &cmdmode,
N_("verify the next bisection state then checkout the next bisection commit"), BISECT_AUTO_NEXT),
OPT_CMDMODE(0, "bisect-state", &cmdmode,
N_("mark the state of ref (or refs)"), BISECT_STATE),
OPT_BOOL(0, "no-checkout", &no_checkout,
N_("update BISECT_HEAD instead of checking out the current commit")),
OPT_BOOL(0, "no-log", &nolog,
@ -670,20 +946,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
usage_with_options(git_bisect_helper_usage, options);
switch (cmdmode) {
case NEXT_ALL:
res = bisect_next_all(the_repository, prefix, no_checkout);
break;
case WRITE_TERMS:
if (argc != 2)
return error(_("--write-terms requires two arguments"));
return write_terms(argv[0], argv[1]);
case BISECT_CLEAN_STATE:
if (argc != 0)
return error(_("--bisect-clean-state requires no arguments"));
return bisect_clean_state();
case CHECK_EXPECTED_REVS:
check_expected_revs(argv, argc);
return 0;
case BISECT_RESET:
if (argc > 1)
return error(_("--bisect-reset requires either no argument or a commit"));
@ -715,8 +977,25 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
set_terms(&terms, "bad", "good");
res = bisect_start(&terms, no_checkout, argv, argc);
break;
case BISECT_NEXT:
if (argc)
return error(_("--bisect-next requires 0 arguments"));
get_terms(&terms);
res = bisect_next(&terms, prefix);
break;
case BISECT_AUTO_NEXT:
if (argc)
return error(_("--bisect-auto-next requires 0 arguments"));
get_terms(&terms);
res = bisect_auto_next(&terms, prefix);
break;
case BISECT_STATE:
set_terms(&terms, "bad", "good");
get_terms(&terms);
res = bisect_state(&terms, argv, argc);
break;
default:
return error("BUG: unknown subcommand '%d'", cmdmode);
BUG("unknown subcommand %d", (int)cmdmode);
}
free_terms(&terms);
@ -724,8 +1003,8 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
* Handle early success
* From check_merge_bases > check_good_are_ancestors_of_bad > bisect_next_all
*/
if (res == BISECT_INTERNAL_SUCCESS_MERGE_BASE)
if ((res == BISECT_INTERNAL_SUCCESS_MERGE_BASE) || (res == BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND))
res = BISECT_OK;
return abs(res);
return -res;
}

View File

@ -39,59 +39,6 @@ _x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40"
TERM_BAD=bad
TERM_GOOD=good
bisect_head()
{
if test -f "$GIT_DIR/BISECT_HEAD"
then
echo BISECT_HEAD
else
echo HEAD
fi
}
bisect_autostart() {
test -s "$GIT_DIR/BISECT_START" || {
gettextln "You need to start by \"git bisect start\"" >&2
if test -t 0
then
# TRANSLATORS: Make sure to include [Y] and [n] in your
# translation. The program will only accept English input
# at this point.
gettext "Do you want me to do it for you [Y/n]? " >&2
read yesno
case "$yesno" in
[Nn]*)
exit ;;
esac
bisect_start
else
exit 1
fi
}
}
bisect_start() {
git bisect--helper --bisect-start $@ || exit
#
# Change state.
# In case of mistaken revs or checkout error, or signals received,
# "bisect_auto_next" below may exit or misbehave.
# We have to trap this to be able to clean up using
# "bisect_clean_state".
#
trap 'git bisect--helper --bisect-clean-state' 0
trap 'exit 255' 1 2 3 15
#
# Check if we can proceed to the next bisect state.
#
get_terms
bisect_auto_next
trap '-' 0
}
bisect_skip() {
all=''
for arg in "$@"
@ -104,81 +51,7 @@ bisect_skip() {
esac
all="$all $revs"
done
eval bisect_state 'skip' $all
}
bisect_state() {
bisect_autostart
state=$1
git bisect--helper --check-and-set-terms $state $TERM_GOOD $TERM_BAD || exit
get_terms
case "$#,$state" in
0,*)
die "Please call 'bisect_state' with at least one argument." ;;
1,"$TERM_BAD"|1,"$TERM_GOOD"|1,skip)
bisected_head=$(bisect_head)
rev=$(git rev-parse --verify "$bisected_head") ||
die "$(eval_gettext "Bad rev input: \$bisected_head")"
git bisect--helper --bisect-write "$state" "$rev" "$TERM_GOOD" "$TERM_BAD" || exit
git bisect--helper --check-expected-revs "$rev" ;;
2,"$TERM_BAD"|*,"$TERM_GOOD"|*,skip)
shift
hash_list=''
for rev in "$@"
do
sha=$(git rev-parse --verify "$rev^{commit}") ||
die "$(eval_gettext "Bad rev input: \$rev")"
hash_list="$hash_list $sha"
done
for rev in $hash_list
do
git bisect--helper --bisect-write "$state" "$rev" "$TERM_GOOD" "$TERM_BAD" || exit
done
git bisect--helper --check-expected-revs $hash_list ;;
*,"$TERM_BAD")
die "$(eval_gettext "'git bisect \$TERM_BAD' can take only one argument.")" ;;
*)
usage ;;
esac
bisect_auto_next
}
bisect_auto_next() {
git bisect--helper --bisect-next-check $TERM_GOOD $TERM_BAD && bisect_next || :
}
bisect_next() {
case "$#" in 0) ;; *) usage ;; esac
bisect_autostart
git bisect--helper --bisect-next-check $TERM_GOOD $TERM_BAD $TERM_GOOD|| exit
# Perform all bisection computation, display and checkout
git bisect--helper --next-all $(test -f "$GIT_DIR/BISECT_HEAD" && echo --no-checkout)
res=$?
# Check if we should exit because bisection is finished
if test $res -eq 10
then
bad_rev=$(git show-ref --hash --verify refs/bisect/$TERM_BAD)
bad_commit=$(git show-branch $bad_rev)
echo "# first $TERM_BAD commit: $bad_commit" >>"$GIT_DIR/BISECT_LOG"
exit 0
elif test $res -eq 2
then
echo "# only skipped commits left to test" >>"$GIT_DIR/BISECT_LOG"
good_revs=$(git for-each-ref --format="%(objectname)" "refs/bisect/$TERM_GOOD-*")
for skipped in $(git rev-list refs/bisect/$TERM_BAD --not $good_revs)
do
skipped_commit=$(git show-branch $skipped)
echo "# possible first $TERM_BAD commit: $skipped_commit" >>"$GIT_DIR/BISECT_LOG"
done
exit $res
fi
# Check for an error in the bisection process
test $res -ne 0 && exit $res
return 0
eval git bisect--helper --bisect-state 'skip' $all
}
bisect_visualize() {
@ -223,8 +96,7 @@ bisect_replay () {
get_terms
case "$command" in
start)
cmd="bisect_start $rev $tail"
eval "$cmd" ;;
eval "git bisect--helper --bisect-start $rev $tail" ;;
"$TERM_GOOD"|"$TERM_BAD"|skip)
git bisect--helper --bisect-write "$command" "$rev" "$TERM_GOOD" "$TERM_BAD" || exit;;
terms)
@ -234,7 +106,7 @@ bisect_replay () {
esac
done <"$file"
IFS="$oIFS"
bisect_auto_next
git bisect--helper --bisect-auto-next
}
bisect_run () {
@ -269,8 +141,7 @@ exit code \$res from '\$command' is < 0 or >= 128" >&2
state="$TERM_GOOD"
fi
# We have to use a subshell because "bisect_state" can exit.
( bisect_state $state >"$GIT_DIR/BISECT_RUN" )
git bisect--helper --bisect-state $state >"$GIT_DIR/BISECT_RUN"
res=$?
cat "$GIT_DIR/BISECT_RUN"
@ -285,7 +156,7 @@ exit code \$res from '\$command' is < 0 or >= 128" >&2
if [ $res -ne 0 ]
then
eval_gettextln "bisect run failed:
'bisect_state \$state' exited with error code \$res" >&2
'git bisect--helper --bisect-state \$state' exited with error code \$res" >&2
exit $res
fi
@ -324,14 +195,14 @@ case "$#" in
help)
git bisect -h ;;
start)
bisect_start "$@" ;;
git bisect--helper --bisect-start "$@" ;;
bad|good|new|old|"$TERM_BAD"|"$TERM_GOOD")
bisect_state "$cmd" "$@" ;;
git bisect--helper --bisect-state "$cmd" "$@" ;;
skip)
bisect_skip "$@" ;;
next)
# Not sure we want "next" at the UI level anymore.
bisect_next "$@" ;;
git bisect--helper --bisect-next "$@" || exit ;;
visualize|view)
bisect_visualize "$@" ;;
reset)