3 #include "parse-options.h"
8 #include "run-command.h"
13 static GIT_PATH_FUNC(git_path_bisect_terms, "BISECT_TERMS")
14 static GIT_PATH_FUNC(git_path_bisect_expected_rev, "BISECT_EXPECTED_REV")
15 static GIT_PATH_FUNC(git_path_bisect_ancestors_ok, "BISECT_ANCESTORS_OK")
16 static GIT_PATH_FUNC(git_path_bisect_start, "BISECT_START")
17 static GIT_PATH_FUNC(git_path_bisect_log, "BISECT_LOG")
18 static GIT_PATH_FUNC(git_path_head_name, "head-name")
19 static GIT_PATH_FUNC(git_path_bisect_names, "BISECT_NAMES")
20 static GIT_PATH_FUNC(git_path_bisect_first_parent, "BISECT_FIRST_PARENT")
22 static const char * const git_bisect_helper_usage[] = {
23 N_("git bisect--helper --bisect-reset [<commit>]"),
24 N_("git bisect--helper --bisect-write [--no-log] <state> <revision> <good_term> <bad_term>"),
25 N_("git bisect--helper --bisect-check-and-set-terms <command> <good_term> <bad_term>"),
26 N_("git bisect--helper --bisect-next-check <good_term> <bad_term> [<term>]"),
27 N_("git bisect--helper --bisect-terms [--term-good | --term-old | --term-bad | --term-new]"),
28 N_("git bisect--helper --bisect-start [--term-{old,good}=<term> --term-{new,bad}=<term>]"
29 " [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<paths>...]"),
30 N_("git bisect--helper --bisect-next"),
31 N_("git bisect--helper --bisect-auto-next"),
32 N_("git bisect--helper --bisect-state (bad|new) [<rev>]"),
33 N_("git bisect--helper --bisect-state (good|old) [<rev>...]"),
37 struct add_bisect_ref_data {
38 struct rev_info *revs;
39 unsigned int object_flags;
47 static void free_terms(struct bisect_terms *terms)
49 FREE_AND_NULL(terms->term_good);
50 FREE_AND_NULL(terms->term_bad);
53 static void set_terms(struct bisect_terms *terms, const char *bad,
56 free((void *)terms->term_good);
57 terms->term_good = xstrdup(good);
58 free((void *)terms->term_bad);
59 terms->term_bad = xstrdup(bad);
62 static const char vocab_bad[] = "bad|new";
63 static const char vocab_good[] = "good|old";
65 static int bisect_autostart(struct bisect_terms *terms);
68 * Check whether the string `term` belongs to the set of strings
69 * included in the variable arguments.
72 static int one_of(const char *term, ...)
78 va_start(matches, term);
79 while (!res && (match = va_arg(matches, const char *)))
80 res = !strcmp(term, match);
87 * return code BISECT_INTERNAL_SUCCESS_MERGE_BASE
88 * and BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND are codes
89 * that indicate special success.
92 static int is_bisect_success(enum bisect_error res)
95 res == BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND ||
96 res == BISECT_INTERNAL_SUCCESS_MERGE_BASE;
99 static int write_in_file(const char *path, const char *mode, const char *format, va_list args)
104 if (strcmp(mode, "w") && strcmp(mode, "a"))
105 BUG("write-in-file does not support '%s' mode", mode);
106 fp = fopen(path, mode);
108 return error_errno(_("cannot open file '%s' in mode '%s'"), path, mode);
109 res = vfprintf(fp, format, args);
112 int saved_errno = errno;
115 return error_errno(_("could not write to file '%s'"), path);
121 static int write_to_file(const char *path, const char *format, ...)
126 va_start(args, format);
127 res = write_in_file(path, "w", format, args);
133 static int append_to_file(const char *path, const char *format, ...)
138 va_start(args, format);
139 res = write_in_file(path, "a", format, args);
145 static int check_term_format(const char *term, const char *orig_term)
148 char *new_term = xstrfmt("refs/bisect/%s", term);
150 res = check_refname_format(new_term, 0);
154 return error(_("'%s' is not a valid term"), term);
156 if (one_of(term, "help", "start", "skip", "next", "reset",
157 "visualize", "view", "replay", "log", "run", "terms", NULL))
158 return error(_("can't use the builtin command '%s' as a term"), term);
161 * In theory, nothing prevents swapping completely good and bad,
162 * but this situation could be confusing and hasn't been tested
163 * enough. Forbid it for now.
166 if ((strcmp(orig_term, "bad") && one_of(term, "bad", "new", NULL)) ||
167 (strcmp(orig_term, "good") && one_of(term, "good", "old", NULL)))
168 return error(_("can't change the meaning of the term '%s'"), term);
173 static int write_terms(const char *bad, const char *good)
177 if (!strcmp(bad, good))
178 return error(_("please use two different terms"));
180 if (check_term_format(bad, "bad") || check_term_format(good, "good"))
183 res = write_to_file(git_path_bisect_terms(), "%s\n%s\n", bad, good);
188 static int bisect_reset(const char *commit)
190 struct strbuf branch = STRBUF_INIT;
193 if (strbuf_read_file(&branch, git_path_bisect_start(), 0) < 1) {
194 printf(_("We are not bisecting.\n"));
197 strbuf_rtrim(&branch);
199 struct object_id oid;
201 if (get_oid_commit(commit, &oid))
202 return error(_("'%s' is not a valid commit"), commit);
203 strbuf_addstr(&branch, commit);
206 if (!ref_exists("BISECT_HEAD")) {
207 struct strvec argv = STRVEC_INIT;
209 strvec_pushl(&argv, "checkout", branch.buf, "--", NULL);
210 if (run_command_v_opt(argv.v, RUN_GIT_CMD)) {
211 error(_("could not check out original"
212 " HEAD '%s'. Try 'git bisect"
213 " reset <commit>'."), branch.buf);
214 strbuf_release(&branch);
221 strbuf_release(&branch);
222 return bisect_clean_state();
225 static void log_commit(FILE *fp, char *fmt, const char *state,
226 struct commit *commit)
228 struct pretty_print_context pp = {0};
229 struct strbuf commit_msg = STRBUF_INIT;
230 char *label = xstrfmt(fmt, state);
232 format_commit_message(commit, "%s", &commit_msg, &pp);
234 fprintf(fp, "# %s: [%s] %s\n", label, oid_to_hex(&commit->object.oid),
237 strbuf_release(&commit_msg);
241 static int bisect_write(const char *state, const char *rev,
242 const struct bisect_terms *terms, int nolog)
244 struct strbuf tag = STRBUF_INIT;
245 struct object_id oid;
246 struct commit *commit;
250 if (!strcmp(state, terms->term_bad)) {
251 strbuf_addf(&tag, "refs/bisect/%s", state);
252 } else if (one_of(state, terms->term_good, "skip", NULL)) {
253 strbuf_addf(&tag, "refs/bisect/%s-%s", state, rev);
255 res = error(_("Bad bisect_write argument: %s"), state);
259 if (get_oid(rev, &oid)) {
260 res = error(_("couldn't get the oid of the rev '%s'"), rev);
264 if (update_ref(NULL, tag.buf, &oid, NULL, 0,
265 UPDATE_REFS_MSG_ON_ERR)) {
270 fp = fopen(git_path_bisect_log(), "a");
272 res = error_errno(_("couldn't open the file '%s'"), git_path_bisect_log());
276 commit = lookup_commit_reference(the_repository, &oid);
277 log_commit(fp, "%s", state, commit);
280 fprintf(fp, "git bisect %s %s\n", state, rev);
285 strbuf_release(&tag);
289 static int check_and_set_terms(struct bisect_terms *terms, const char *cmd)
291 int has_term_file = !is_empty_or_missing_file(git_path_bisect_terms());
293 if (one_of(cmd, "skip", "start", "terms", NULL))
296 if (has_term_file && strcmp(cmd, terms->term_bad) &&
297 strcmp(cmd, terms->term_good))
298 return error(_("Invalid command: you're currently in a "
299 "%s/%s bisect"), terms->term_bad,
302 if (!has_term_file) {
303 if (one_of(cmd, "bad", "good", NULL)) {
304 set_terms(terms, "bad", "good");
305 return write_terms(terms->term_bad, terms->term_good);
307 if (one_of(cmd, "new", "old", NULL)) {
308 set_terms(terms, "new", "old");
309 return write_terms(terms->term_bad, terms->term_good);
316 static int mark_good(const char *refname, const struct object_id *oid,
317 int flag, void *cb_data)
319 int *m_good = (int *)cb_data;
324 static const char need_bad_and_good_revision_warning[] =
325 N_("You need to give me at least one %s and %s revision.\n"
326 "You can use \"git bisect %s\" and \"git bisect %s\" for that.");
328 static const char need_bisect_start_warning[] =
329 N_("You need to start by \"git bisect start\".\n"
330 "You then need to give me at least one %s and %s revision.\n"
331 "You can use \"git bisect %s\" and \"git bisect %s\" for that.");
333 static int decide_next(const struct bisect_terms *terms,
334 const char *current_term, int missing_good,
337 if (!missing_good && !missing_bad)
342 if (missing_good && !missing_bad &&
343 !strcmp(current_term, terms->term_good)) {
346 * have bad (or new) but not good (or old). We could bisect
347 * although this is less optimum.
349 warning(_("bisecting only with a %s commit"), terms->term_bad);
353 * TRANSLATORS: Make sure to include [Y] and [n] in your
354 * translation. The program will only accept English input
357 yesno = git_prompt(_("Are you sure [Y/n]? "), PROMPT_ECHO);
358 if (starts_with(yesno, "N") || starts_with(yesno, "n"))
363 if (!is_empty_or_missing_file(git_path_bisect_start()))
364 return error(_(need_bad_and_good_revision_warning),
365 vocab_bad, vocab_good, vocab_bad, vocab_good);
367 return error(_(need_bisect_start_warning),
368 vocab_good, vocab_bad, vocab_good, vocab_bad);
371 static int bisect_next_check(const struct bisect_terms *terms,
372 const char *current_term)
374 int missing_good = 1, missing_bad = 1;
375 char *bad_ref = xstrfmt("refs/bisect/%s", terms->term_bad);
376 char *good_glob = xstrfmt("%s-*", terms->term_good);
378 if (ref_exists(bad_ref))
381 for_each_glob_ref_in(mark_good, good_glob, "refs/bisect/",
382 (void *) &missing_good);
387 return decide_next(terms, current_term, missing_good, missing_bad);
390 static int get_terms(struct bisect_terms *terms)
392 struct strbuf str = STRBUF_INIT;
396 fp = fopen(git_path_bisect_terms(), "r");
403 strbuf_getline_lf(&str, fp);
404 terms->term_bad = strbuf_detach(&str, NULL);
405 strbuf_getline_lf(&str, fp);
406 terms->term_good = strbuf_detach(&str, NULL);
411 strbuf_release(&str);
415 static int bisect_terms(struct bisect_terms *terms, const char *option)
417 if (get_terms(terms))
418 return error(_("no terms defined"));
420 if (option == NULL) {
421 printf(_("Your current terms are %s for the old state\n"
422 "and %s for the new state.\n"),
423 terms->term_good, terms->term_bad);
426 if (one_of(option, "--term-good", "--term-old", NULL))
427 printf("%s\n", terms->term_good);
428 else if (one_of(option, "--term-bad", "--term-new", NULL))
429 printf("%s\n", terms->term_bad);
431 return error(_("invalid argument %s for 'git bisect terms'.\n"
432 "Supported options are: "
433 "--term-good|--term-old and "
434 "--term-bad|--term-new."), option);
439 static int bisect_append_log_quoted(const char **argv)
442 FILE *fp = fopen(git_path_bisect_log(), "a");
443 struct strbuf orig_args = STRBUF_INIT;
448 if (fprintf(fp, "git bisect start") < 1) {
453 sq_quote_argv(&orig_args, argv);
454 if (fprintf(fp, "%s\n", orig_args.buf) < 1)
459 strbuf_release(&orig_args);
463 static int add_bisect_ref(const char *refname, const struct object_id *oid,
466 struct add_bisect_ref_data *data = cb;
468 add_pending_oid(data->revs, refname, oid, data->object_flags);
473 static int prepare_revs(struct bisect_terms *terms, struct rev_info *revs)
476 struct add_bisect_ref_data cb = { revs };
477 char *good = xstrfmt("%s-*", terms->term_good);
480 * We cannot use terms->term_bad directly in
481 * for_each_glob_ref_in() and we have to append a '*' to it,
482 * otherwise for_each_glob_ref_in() will append '/' and '*'.
484 char *bad = xstrfmt("%s*", terms->term_bad);
487 * It is important to reset the flags used by revision walks
488 * as the previous call to bisect_next_all() in turn
489 * sets up a revision walk.
491 reset_revision_walk();
492 init_revisions(revs, NULL);
493 setup_revisions(0, NULL, revs, NULL);
494 for_each_glob_ref_in(add_bisect_ref, bad, "refs/bisect/", &cb);
495 cb.object_flags = UNINTERESTING;
496 for_each_glob_ref_in(add_bisect_ref, good, "refs/bisect/", &cb);
497 if (prepare_revision_walk(revs))
498 res = error(_("revision walk setup failed\n"));
505 static int bisect_skipped_commits(struct bisect_terms *terms)
509 struct rev_info revs;
510 struct commit *commit;
511 struct pretty_print_context pp = {0};
512 struct strbuf commit_name = STRBUF_INIT;
514 res = prepare_revs(terms, &revs);
518 fp = fopen(git_path_bisect_log(), "a");
520 return error_errno(_("could not open '%s' for appending"),
521 git_path_bisect_log());
523 if (fprintf(fp, "# only skipped commits left to test\n") < 0)
524 return error_errno(_("failed to write to '%s'"), git_path_bisect_log());
526 while ((commit = get_revision(&revs)) != NULL) {
527 strbuf_reset(&commit_name);
528 format_commit_message(commit, "%s",
530 fprintf(fp, "# possible first %s commit: [%s] %s\n",
531 terms->term_bad, oid_to_hex(&commit->object.oid),
536 * Reset the flags used by revision walks in case
537 * there is another revision walk after this one.
539 reset_revision_walk();
541 strbuf_release(&commit_name);
546 static int bisect_successful(struct bisect_terms *terms)
548 struct object_id oid;
549 struct commit *commit;
550 struct pretty_print_context pp = {0};
551 struct strbuf commit_name = STRBUF_INIT;
552 char *bad_ref = xstrfmt("refs/bisect/%s",terms->term_bad);
555 read_ref(bad_ref, &oid);
556 commit = lookup_commit_reference_by_name(bad_ref);
557 format_commit_message(commit, "%s", &commit_name, &pp);
559 res = append_to_file(git_path_bisect_log(), "# first %s commit: [%s] %s\n",
560 terms->term_bad, oid_to_hex(&commit->object.oid),
563 strbuf_release(&commit_name);
568 static enum bisect_error bisect_next(struct bisect_terms *terms, const char *prefix)
570 enum bisect_error res;
572 if (bisect_autostart(terms))
573 return BISECT_FAILED;
575 if (bisect_next_check(terms, terms->term_good))
576 return BISECT_FAILED;
578 /* Perform all bisection computation */
579 res = bisect_next_all(the_repository, prefix);
581 if (res == BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND) {
582 res = bisect_successful(terms);
583 return res ? res : BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND;
584 } else if (res == BISECT_ONLY_SKIPPED_LEFT) {
585 res = bisect_skipped_commits(terms);
586 return res ? res : BISECT_ONLY_SKIPPED_LEFT;
591 static enum bisect_error bisect_auto_next(struct bisect_terms *terms, const char *prefix)
593 if (bisect_next_check(terms, NULL))
596 return bisect_next(terms, prefix);
599 static enum bisect_error bisect_start(struct bisect_terms *terms, const char **argv, int argc)
602 int first_parent_only = 0;
603 int i, has_double_dash = 0, must_write_terms = 0, bad_seen = 0;
604 int flags, pathspec_pos;
605 enum bisect_error res = BISECT_OK;
606 struct string_list revs = STRING_LIST_INIT_DUP;
607 struct string_list states = STRING_LIST_INIT_DUP;
608 struct strbuf start_head = STRBUF_INIT;
609 struct strbuf bisect_names = STRBUF_INIT;
610 struct object_id head_oid;
611 struct object_id oid;
614 if (is_bare_repository())
618 * Check for one bad and then some good revisions
620 for (i = 0; i < argc; i++) {
621 if (!strcmp(argv[i], "--")) {
627 for (i = 0; i < argc; i++) {
628 const char *arg = argv[i];
629 if (!strcmp(argv[i], "--")) {
631 } else if (!strcmp(arg, "--no-checkout")) {
633 } else if (!strcmp(arg, "--first-parent")) {
634 first_parent_only = 1;
635 } else if (!strcmp(arg, "--term-good") ||
636 !strcmp(arg, "--term-old")) {
639 return error(_("'' is not a valid term"));
640 must_write_terms = 1;
641 free((void *) terms->term_good);
642 terms->term_good = xstrdup(argv[i]);
643 } else if (skip_prefix(arg, "--term-good=", &arg) ||
644 skip_prefix(arg, "--term-old=", &arg)) {
645 must_write_terms = 1;
646 free((void *) terms->term_good);
647 terms->term_good = xstrdup(arg);
648 } else if (!strcmp(arg, "--term-bad") ||
649 !strcmp(arg, "--term-new")) {
652 return error(_("'' is not a valid term"));
653 must_write_terms = 1;
654 free((void *) terms->term_bad);
655 terms->term_bad = xstrdup(argv[i]);
656 } else if (skip_prefix(arg, "--term-bad=", &arg) ||
657 skip_prefix(arg, "--term-new=", &arg)) {
658 must_write_terms = 1;
659 free((void *) terms->term_bad);
660 terms->term_bad = xstrdup(arg);
661 } else if (starts_with(arg, "--")) {
662 return error(_("unrecognized option: '%s'"), arg);
664 char *commit_id = xstrfmt("%s^{commit}", arg);
665 if (get_oid(commit_id, &oid) && has_double_dash)
666 die(_("'%s' does not appear to be a valid "
669 string_list_append(&revs, oid_to_hex(&oid));
676 * The user ran "git bisect start <sha1> <sha1>", hence did not
677 * explicitly specify the terms, but we are already starting to
678 * set references named with the default terms, and won't be able
679 * to change afterwards.
682 must_write_terms = 1;
683 for (i = 0; i < revs.nr; i++) {
685 string_list_append(&states, terms->term_good);
688 string_list_append(&states, terms->term_bad);
695 head = resolve_ref_unsafe("HEAD", 0, &head_oid, &flags);
697 if (get_oid("HEAD", &head_oid))
698 return error(_("bad HEAD - I need a HEAD"));
701 * Check if we are bisecting
703 if (!is_empty_or_missing_file(git_path_bisect_start())) {
704 /* Reset to the rev from where we started */
705 strbuf_read_file(&start_head, git_path_bisect_start(), 0);
706 strbuf_trim(&start_head);
708 struct strvec argv = STRVEC_INIT;
710 strvec_pushl(&argv, "checkout", start_head.buf,
712 if (run_command_v_opt(argv.v, RUN_GIT_CMD)) {
713 res = error(_("checking out '%s' failed."
714 " Try 'git bisect start "
721 /* Get the rev from where we start. */
722 if (!get_oid(head, &head_oid) &&
723 !starts_with(head, "refs/heads/")) {
724 strbuf_reset(&start_head);
725 strbuf_addstr(&start_head, oid_to_hex(&head_oid));
726 } else if (!get_oid(head, &head_oid) &&
727 skip_prefix(head, "refs/heads/", &head)) {
729 * This error message should only be triggered by
730 * cogito usage, and cogito users should understand
731 * it relates to cg-seek.
733 if (!is_empty_or_missing_file(git_path_head_name()))
734 return error(_("won't bisect on cg-seek'ed tree"));
735 strbuf_addstr(&start_head, head);
737 return error(_("bad HEAD - strange symbolic ref"));
742 * Get rid of any old bisect state.
744 if (bisect_clean_state())
745 return BISECT_FAILED;
748 * Write new start state
750 write_file(git_path_bisect_start(), "%s\n", start_head.buf);
752 if (first_parent_only)
753 write_file(git_path_bisect_first_parent(), "\n");
756 if (get_oid(start_head.buf, &oid) < 0) {
757 res = error(_("invalid ref: '%s'"), start_head.buf);
760 if (update_ref(NULL, "BISECT_HEAD", &oid, NULL, 0,
761 UPDATE_REFS_MSG_ON_ERR)) {
767 if (pathspec_pos < argc - 1)
768 sq_quote_argv(&bisect_names, argv + pathspec_pos);
769 write_file(git_path_bisect_names(), "%s\n", bisect_names.buf);
771 for (i = 0; i < states.nr; i++)
772 if (bisect_write(states.items[i].string,
773 revs.items[i].string, terms, 1)) {
778 if (must_write_terms && write_terms(terms->term_bad,
784 res = bisect_append_log_quoted(argv);
789 string_list_clear(&revs, 0);
790 string_list_clear(&states, 0);
791 strbuf_release(&start_head);
792 strbuf_release(&bisect_names);
796 res = bisect_auto_next(terms, NULL);
797 if (!is_bisect_success(res))
798 bisect_clean_state();
802 static inline int file_is_not_empty(const char *path)
804 return !is_empty_or_missing_file(path);
807 static int bisect_autostart(struct bisect_terms *terms)
812 if (file_is_not_empty(git_path_bisect_start()))
815 fprintf_ln(stderr, _("You need to start by \"git bisect "
818 if (!isatty(STDIN_FILENO))
822 * TRANSLATORS: Make sure to include [Y] and [n] in your
823 * translation. The program will only accept English input
826 yesno = git_prompt(_("Do you want me to do it for you "
827 "[Y/n]? "), PROMPT_ECHO);
828 res = tolower(*yesno) == 'n' ?
829 -1 : bisect_start(terms, empty_strvec, 0);
834 static enum bisect_error bisect_state(struct bisect_terms *terms, const char **argv,
838 int i, verify_expected = 1;
839 struct object_id oid, expected;
840 struct strbuf buf = STRBUF_INIT;
841 struct oid_array revs = OID_ARRAY_INIT;
844 return error(_("Please call `--bisect-state` with at least one argument"));
846 if (bisect_autostart(terms))
847 return BISECT_FAILED;
850 if (check_and_set_terms(terms, state) ||
851 !one_of(state, terms->term_good, terms->term_bad, "skip", NULL))
852 return BISECT_FAILED;
856 if (argc > 1 && !strcmp(state, terms->term_bad))
857 return error(_("'git bisect %s' can take only one argument."), terms->term_bad);
860 const char *head = "BISECT_HEAD";
861 enum get_oid_result res_head = get_oid(head, &oid);
863 if (res_head == MISSING_OBJECT) {
865 res_head = get_oid(head, &oid);
869 error(_("Bad rev input: %s"), head);
870 oid_array_append(&revs, &oid);
874 * All input revs must be checked before executing bisect_write()
875 * to discard junk revs.
878 for (; argc; argc--, argv++) {
879 if (get_oid(*argv, &oid)){
880 error(_("Bad rev input: %s"), *argv);
881 oid_array_clear(&revs);
882 return BISECT_FAILED;
884 oid_array_append(&revs, &oid);
887 if (strbuf_read_file(&buf, git_path_bisect_expected_rev(), 0) < the_hash_algo->hexsz ||
888 get_oid_hex(buf.buf, &expected) < 0)
889 verify_expected = 0; /* Ignore invalid file contents */
890 strbuf_release(&buf);
892 for (i = 0; i < revs.nr; i++) {
893 if (bisect_write(state, oid_to_hex(&revs.oid[i]), terms, 0)) {
894 oid_array_clear(&revs);
895 return BISECT_FAILED;
897 if (verify_expected && !oideq(&revs.oid[i], &expected)) {
898 unlink_or_warn(git_path_bisect_ancestors_ok());
899 unlink_or_warn(git_path_bisect_expected_rev());
904 oid_array_clear(&revs);
905 return bisect_auto_next(terms, NULL);
908 int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
922 int res = 0, nolog = 0;
923 struct option options[] = {
924 OPT_CMDMODE(0, "bisect-reset", &cmdmode,
925 N_("reset the bisection state"), BISECT_RESET),
926 OPT_CMDMODE(0, "bisect-write", &cmdmode,
927 N_("write out the bisection state in BISECT_LOG"), BISECT_WRITE),
928 OPT_CMDMODE(0, "check-and-set-terms", &cmdmode,
929 N_("check and set terms in a bisection state"), CHECK_AND_SET_TERMS),
930 OPT_CMDMODE(0, "bisect-next-check", &cmdmode,
931 N_("check whether bad or good terms exist"), BISECT_NEXT_CHECK),
932 OPT_CMDMODE(0, "bisect-terms", &cmdmode,
933 N_("print out the bisect terms"), BISECT_TERMS),
934 OPT_CMDMODE(0, "bisect-start", &cmdmode,
935 N_("start the bisect session"), BISECT_START),
936 OPT_CMDMODE(0, "bisect-next", &cmdmode,
937 N_("find the next bisection commit"), BISECT_NEXT),
938 OPT_CMDMODE(0, "bisect-auto-next", &cmdmode,
939 N_("verify the next bisection state then checkout the next bisection commit"), BISECT_AUTO_NEXT),
940 OPT_CMDMODE(0, "bisect-state", &cmdmode,
941 N_("mark the state of ref (or refs)"), BISECT_STATE),
942 OPT_BOOL(0, "no-log", &nolog,
943 N_("no log for BISECT_WRITE")),
946 struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
948 argc = parse_options(argc, argv, prefix, options,
949 git_bisect_helper_usage,
950 PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN);
953 usage_with_options(git_bisect_helper_usage, options);
958 return error(_("--bisect-reset requires either no argument or a commit"));
959 return !!bisect_reset(argc ? argv[0] : NULL);
961 if (argc != 4 && argc != 5)
962 return error(_("--bisect-write requires either 4 or 5 arguments"));
963 set_terms(&terms, argv[3], argv[2]);
964 res = bisect_write(argv[0], argv[1], &terms, nolog);
966 case CHECK_AND_SET_TERMS:
968 return error(_("--check-and-set-terms requires 3 arguments"));
969 set_terms(&terms, argv[2], argv[1]);
970 res = check_and_set_terms(&terms, argv[0]);
972 case BISECT_NEXT_CHECK:
973 if (argc != 2 && argc != 3)
974 return error(_("--bisect-next-check requires 2 or 3 arguments"));
975 set_terms(&terms, argv[1], argv[0]);
976 res = bisect_next_check(&terms, argc == 3 ? argv[2] : NULL);
980 return error(_("--bisect-terms requires 0 or 1 argument"));
981 res = bisect_terms(&terms, argc == 1 ? argv[0] : NULL);
984 set_terms(&terms, "bad", "good");
985 res = bisect_start(&terms, argv, argc);
989 return error(_("--bisect-next requires 0 arguments"));
991 res = bisect_next(&terms, prefix);
993 case BISECT_AUTO_NEXT:
995 return error(_("--bisect-auto-next requires 0 arguments"));
997 res = bisect_auto_next(&terms, prefix);
1000 set_terms(&terms, "bad", "good");
1002 res = bisect_state(&terms, argv, argc);
1005 BUG("unknown subcommand %d", cmdmode);
1010 * Handle early success
1011 * From check_merge_bases > check_good_are_ancestors_of_bad > bisect_next_all
1013 if ((res == BISECT_INTERNAL_SUCCESS_MERGE_BASE) || (res == BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND))