@@ -32,6 +32,7 @@ static const char * const git_bisect_helper_usage[] = {
N_("git bisect--helper --bisect-autostart"),
N_("git bisect--helper --bisect-state (bad|new) [<rev>]"),
N_("git bisect--helper --bisect-state (good|old) [<rev>...]"),
+ N_("git bisect--helper --bisect-replay <filename>"),
NULL
};
@@ -904,6 +905,121 @@ static int bisect_log(void)
return status ? -1 : 0;
}
+static int get_next_word(const char *line, int pos, struct strbuf *word)
+{
+ int i, len = strlen(line), begin = 0;
+
+ strbuf_reset(word);
+ for (i = pos; i < len; i++) {
+ if (line[i] == ' ' && begin)
+ return i + 1;
+
+ if (!begin)
+ begin = 1;
+ strbuf_addch(word, line[i]);
+ }
+
+ return i;
+}
+
+static int process_line(struct bisect_terms *terms, struct strbuf *line, struct strbuf *word)
+{
+ int res = 0;
+ int pos = 0;
+
+ while (pos < line->len) {
+ pos = get_next_word(line->buf, pos, word);
+
+ if (!strcmp(word->buf, "git"))
+ continue;
+ else if (!strcmp(word->buf, "git-bisect"))
+ continue;
+ else if (!strcmp(word->buf, "bisect"))
+ continue;
+ else if (starts_with(word->buf, "#"))
+ break;
+
+ get_terms(terms);
+ if (check_and_set_terms(terms, word->buf))
+ return -1;
+
+ if (!strcmp(word->buf, "start")) {
+ struct argv_array argv = ARGV_ARRAY_INIT;
+ int res;
+ sq_dequote_to_argv_array(line->buf+pos, &argv);
+ res = bisect_start(terms, 0, argv.argv, argv.argc);
+ argv_array_clear(&argv);
+ if (res)
+ return -1;
+ break;
+ }
+
+ if (one_of(word->buf, terms->term_good,
+ terms->term_bad, "skip", NULL)) {
+ if (bisect_write(word->buf, line->buf+pos, terms, 0))
+ return -1;
+ break;
+ }
+
+ if (!strcmp(word->buf, "terms")) {
+ struct argv_array argv = ARGV_ARRAY_INIT;
+ int res;
+ sq_dequote_to_argv_array(line->buf+pos, &argv);
+ res = bisect_terms(terms, argv.argc == 1 ? argv.argv[0] : NULL);
+ argv_array_clear(&argv);
+ if (res)
+ return -1;
+ break;
+ }
+
+ error(_("Replay file contains rubbish (\"%s\")"),
+ word->buf);
+ res = -1;
+ }
+ return res;
+}
+
+static int process_replay_file(FILE *fp, struct bisect_terms *terms)
+{
+ struct strbuf line = STRBUF_INIT;
+ struct strbuf word = STRBUF_INIT;
+ int res = 0;
+
+ while (strbuf_getline(&line, fp) != EOF) {
+ res = process_line(terms, &line, &word);
+ if (res)
+ break;
+ }
+
+ strbuf_release(&line);
+ strbuf_release(&word);
+ return res;
+}
+
+static int bisect_replay(struct bisect_terms *terms, const char *filename)
+{
+ FILE *fp = NULL;
+ int res = 0;
+
+ if (is_empty_or_missing_file(filename))
+ return error(_("cannot read file '%s' for replaying"), filename);
+
+ if (bisect_reset(NULL))
+ return -1;
+
+ fp = fopen(filename, "r");
+ if (!fp)
+ return -1;
+
+ res = process_replay_file(fp, terms);
+ fclose(fp);
+
+ if (res)
+ return -1;
+
+ return bisect_auto_next(terms, NULL);
+}
+
int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
{
enum {
@@ -917,7 +1033,8 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
BISECT_AUTO_NEXT,
BISECT_AUTOSTART,
BISECT_STATE,
- BISECT_LOG
+ BISECT_LOG,
+ BISECT_REPLAY
} cmdmode = 0;
int no_checkout = 0, res = 0, nolog = 0;
struct option options[] = {
@@ -943,6 +1060,8 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
N_("mark the state of ref (or refs)"), BISECT_STATE),
OPT_CMDMODE(0, "bisect-log", &cmdmode,
N_("output the contents of BISECT_LOG"), BISECT_LOG),
+ OPT_CMDMODE(0, "bisect-replay", &cmdmode,
+ N_("replay the bisection process from the given file"), BISECT_REPLAY),
OPT_BOOL(0, "no-checkout", &no_checkout,
N_("update BISECT_HEAD instead of checking out the current commit")),
OPT_BOOL(0, "no-log", &nolog,
@@ -1020,6 +1139,12 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
return error(_("--bisect-log requires 0 arguments"));
res = bisect_log();
break;
+ case BISECT_REPLAY:
+ if (argc != 1)
+ return error(_("no logfile given"));
+ set_terms(&terms, "bad", "good");
+ res = bisect_replay(&terms, argv[0]);
+ break;
default:
return error("BUG: unknown subcommand '%d'", cmdmode);
}
@@ -77,36 +77,6 @@ bisect_visualize() {
eval '"$@"' --bisect -- $(cat "$GIT_DIR/BISECT_NAMES")
}
-bisect_replay () {
- file="$1"
- test "$#" -eq 1 || die "$(gettext "No logfile given")"
- test -r "$file" || die "$(eval_gettext "cannot read \$file for replaying")"
- git bisect--helper --bisect-reset || exit
- while read git bisect command rev
- do
- test "$git $bisect" = "git bisect" || test "$git" = "git-bisect" || continue
- if test "$git" = "git-bisect"
- then
- rev="$command"
- command="$bisect"
- fi
- get_terms
- git bisect--helper --check-and-set-terms "$command" "$TERM_GOOD" "$TERM_BAD" || exit
- get_terms
- case "$command" in
- start)
- eval "git bisect--helper --bisect-start $rev" ;;
- "$TERM_GOOD"|"$TERM_BAD"|skip)
- git bisect--helper --bisect-write "$command" "$rev" "$TERM_GOOD" "$TERM_BAD" || exit;;
- terms)
- git bisect--helper --bisect-terms $rev || exit;;
- *)
- die "$(gettext "?? what are you talking about?")" ;;
- esac
- done <"$file"
- git bisect--helper --bisect-auto-next
-}
-
bisect_run () {
git bisect--helper --bisect-next-check $TERM_GOOD $TERM_BAD fail || exit
@@ -202,7 +172,7 @@ case "$#" in
reset)
git bisect--helper --bisect-reset "$@" ;;
replay)
- bisect_replay "$@" ;;
+ git bisect--helper --bisect-replay "$@" ;;
log)
git bisect--helper --bisect-log ;;
run)