Raw
1 #define USE_THE_REPOSITORY_VARIABLE
2 #define DISABLE_SIGN_COMPARE_WARNINGS
3
4 #include "builtin.h"
5 #include "copy.h"
6 #include "environment.h"
7 #include "gettext.h"
8 #include "hex.h"
9 #include "object-name.h"
10 #include "parse-options.h"
11 #include "bisect.h"
12 #include "refs.h"
13 #include "strvec.h"
14 #include "run-command.h"
15 #include "oid-array.h"
16 #include "path.h"
17 #include "prompt.h"
18 #include "quote.h"
19 #include "revision.h"
20
21 static GIT_PATH_FUNC(git_path_bisect_terms, "BISECT_TERMS")
22 static GIT_PATH_FUNC(git_path_bisect_ancestors_ok, "BISECT_ANCESTORS_OK")
23 static GIT_PATH_FUNC(git_path_bisect_start, "BISECT_START")
24 static GIT_PATH_FUNC(git_path_bisect_log, "BISECT_LOG")
25 static GIT_PATH_FUNC(git_path_bisect_names, "BISECT_NAMES")
26 static GIT_PATH_FUNC(git_path_bisect_first_parent, "BISECT_FIRST_PARENT")
27 static GIT_PATH_FUNC(git_path_bisect_run, "BISECT_RUN")
28
29 #define BUILTIN_GIT_BISECT_START_USAGE \
30 N_("git bisect start [--term-(bad|new)=<term-new> --term-(good|old)=<term-old>]\n" \
31 " [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<pathspec>...]")
32 #define BUILTIN_GIT_BISECT_BAD_USAGE \
33 N_("git bisect (bad|new|<term-new>) [<rev>]")
34 #define BUILTIN_GIT_BISECT_GOOD_USAGE \
35 N_("git bisect (good|old|<term-old>) [<rev>...]")
36 #define BUILTIN_GIT_BISECT_TERMS_USAGE \
37 "git bisect terms [--term-(good|old) | --term-(bad|new)]"
38 #define BUILTIN_GIT_BISECT_SKIP_USAGE \
39 N_("git bisect skip [(<rev>|<range>)...]")
40 #define BUILTIN_GIT_BISECT_NEXT_USAGE \
41 "git bisect next"
42 #define BUILTIN_GIT_BISECT_RESET_USAGE \
43 N_("git bisect reset [<commit>]")
44 #define BUILTIN_GIT_BISECT_VISUALIZE_USAGE \
45 "git bisect (visualize|view)"
46 #define BUILTIN_GIT_BISECT_REPLAY_USAGE \
47 N_("git bisect replay <logfile>")
48 #define BUILTIN_GIT_BISECT_LOG_USAGE \
49 "git bisect log"
50 #define BUILTIN_GIT_BISECT_RUN_USAGE \
51 N_("git bisect run <cmd> [<arg>...]")
52 #define BUILTIN_GIT_BISECT_HELP_USAGE \
53 "git bisect help"
54
55 static const char * const git_bisect_usage[] = {
56 BUILTIN_GIT_BISECT_START_USAGE,
57 BUILTIN_GIT_BISECT_BAD_USAGE,
58 BUILTIN_GIT_BISECT_GOOD_USAGE,
59 BUILTIN_GIT_BISECT_TERMS_USAGE,
60 BUILTIN_GIT_BISECT_SKIP_USAGE,
61 BUILTIN_GIT_BISECT_NEXT_USAGE,
62 BUILTIN_GIT_BISECT_RESET_USAGE,
63 BUILTIN_GIT_BISECT_VISUALIZE_USAGE,
64 BUILTIN_GIT_BISECT_REPLAY_USAGE,
65 BUILTIN_GIT_BISECT_LOG_USAGE,
66 BUILTIN_GIT_BISECT_RUN_USAGE,
67 BUILTIN_GIT_BISECT_HELP_USAGE,
68 NULL
69 };
70
71 struct add_bisect_ref_data {
72 struct rev_info *revs;
73 unsigned int object_flags;
74 };
75
76 struct bisect_terms {
77 char *term_good;
78 char *term_bad;
79 };
80
81 static void free_terms(struct bisect_terms *terms)
82 {
83 FREE_AND_NULL(terms->term_good);
84 FREE_AND_NULL(terms->term_bad);
85 }
86
87 static void set_terms(struct bisect_terms *terms, const char *bad,
88 const char *good)
89 {
90 free((void *)terms->term_good);
91 terms->term_good = xstrdup(good);
92 free((void *)terms->term_bad);
93 terms->term_bad = xstrdup(bad);
94 }
95
96 static const char vocab_bad[] = "bad|new";
97 static const char vocab_good[] = "good|old";
98
99 static int bisect_autostart(struct bisect_terms *terms);
100
101 /*
102 * Check whether the string `term` belongs to the set of strings
103 * included in the variable arguments.
104 */
105 LAST_ARG_MUST_BE_NULL
106 static int one_of(const char *term, ...)
107 {
108 int res = 0;
109 va_list matches;
110 const char *match;
111
112 va_start(matches, term);
113 while (!res && (match = va_arg(matches, const char *)))
114 res = !strcmp(term, match);
115 va_end(matches);
116
117 return res;
118 }
119
120 /*
121 * return code BISECT_INTERNAL_SUCCESS_MERGE_BASE
122 * and BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND are codes
123 * that indicate special success.
124 */
125
126 static int is_bisect_success(enum bisect_error res)
127 {
128 return !res ||
129 res == BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND ||
130 res == BISECT_INTERNAL_SUCCESS_MERGE_BASE;
131 }
132
133 static int write_in_file(const char *path, const char *mode, const char *format, va_list args)
134 {
135 FILE *fp = NULL;
136 int res = 0;
137
138 if (strcmp(mode, "w") && strcmp(mode, "a"))
139 BUG("write-in-file does not support '%s' mode", mode);
140 fp = fopen(path, mode);
141 if (!fp)
142 return error_errno(_("cannot open file '%s' in mode '%s'"), path, mode);
143 res = vfprintf(fp, format, args);
144
145 if (res < 0) {
146 int saved_errno = errno;
147 fclose(fp);
148 errno = saved_errno;
149 return error_errno(_("could not write to file '%s'"), path);
150 }
151
152 return fclose(fp);
153 }
154
155 __attribute__((format (printf, 2, 3)))
156 static int write_to_file(const char *path, const char *format, ...)
157 {
158 int res;
159 va_list args;
160
161 va_start(args, format);
162 res = write_in_file(path, "w", format, args);
163 va_end(args);
164
165 return res;
166 }
167
168 __attribute__((format (printf, 2, 3)))
169 static int append_to_file(const char *path, const char *format, ...)
170 {
171 int res;
172 va_list args;
173
174 va_start(args, format);
175 res = write_in_file(path, "a", format, args);
176 va_end(args);
177
178 return res;
179 }
180
181 static int print_file_to_stdout(const char *path)
182 {
183 int fd = open(path, O_RDONLY);
184 int ret = 0;
185
186 if (fd < 0)
187 return error_errno(_("cannot open file '%s' for reading"), path);
188 if (copy_fd(fd, 1) < 0)
189 ret = error_errno(_("failed to read '%s'"), path);
190 close(fd);
191 return ret;
192 }
193
194 static int check_term_format(const char *term, const char *orig_term)
195 {
196 int res;
197 char *new_term = xstrfmt("refs/bisect/%s", term);
198
199 res = check_refname_format(new_term, 0);
200 free(new_term);
201
202 if (res)
203 return error(_("'%s' is not a valid term"), term);
204
205 if (one_of(term, "help", "start", "skip", "next", "reset",
206 "visualize", "view", "replay", "log", "run", "terms", NULL))
207 return error(_("can't use the builtin command '%s' as a term"), term);
208
209 /*
210 * In theory, nothing prevents swapping completely good and bad,
211 * but this situation could be confusing and hasn't been tested
212 * enough. Forbid it for now.
213 */
214
215 if ((strcmp(orig_term, "bad") && one_of(term, "bad", "new", NULL)) ||
216 (strcmp(orig_term, "good") && one_of(term, "good", "old", NULL)))
217 return error(_("can't change the meaning of the term '%s'"), term);
218
219 return 0;
220 }
221
222 static int write_terms(const char *bad, const char *good)
223 {
224 int res;
225
226 if (!strcmp(bad, good))
227 return error(_("please use two different terms"));
228
229 if (check_term_format(bad, "bad") || check_term_format(good, "good"))
230 return -1;
231
232 res = write_to_file(git_path_bisect_terms(), "%s\n%s\n", bad, good);
233
234 return res;
235 }
236
237 static int bisect_reset(const char *commit)
238 {
239 struct strbuf branch = STRBUF_INIT;
240
241 if (!commit) {
242 if (!strbuf_read_file(&branch, git_path_bisect_start(), 0))
243 printf(_("We are not bisecting.\n"));
244 else
245 strbuf_rtrim(&branch);
246 } else {
247 struct object_id oid;
248
249 if (repo_get_oid_commit(the_repository, commit, &oid))
250 return error(_("'%s' is not a valid commit"), commit);
251 strbuf_addstr(&branch, commit);
252 }
253
254 if (branch.len && !refs_ref_exists(get_main_ref_store(the_repository), "BISECT_HEAD")) {
255 struct child_process cmd = CHILD_PROCESS_INIT;
256
257 cmd.git_cmd = 1;
258 strvec_pushl(&cmd.args, "checkout", "--ignore-other-worktrees",
259 branch.buf, "--", NULL);
260 if (run_command(&cmd)) {
261 error(_("could not check out original"
262 " HEAD '%s'. Try 'git bisect"
263 " reset <commit>'."), branch.buf);
264 strbuf_release(&branch);
265 return -1;
266 }
267 }
268
269 strbuf_release(&branch);
270 return bisect_clean_state();
271 }
272
273 static void log_commit(FILE *fp,
274 const char *fmt, const char *state,
275 struct commit *commit)
276 {
277 struct pretty_print_context pp = {0};
278 struct strbuf commit_msg = STRBUF_INIT;
279 char *label = xstrfmt(fmt, state);
280
281 repo_format_commit_message(the_repository, commit, "%s", &commit_msg,
282 &pp);
283
284 fprintf(fp, "# %s: [%s] %s\n", label, oid_to_hex(&commit->object.oid),
285 commit_msg.buf);
286
287 strbuf_release(&commit_msg);
288 free(label);
289 }
290
291 static int bisect_write(const char *state, const char *rev,
292 const struct bisect_terms *terms, int nolog)
293 {
294 struct strbuf tag = STRBUF_INIT;
295 struct object_id oid;
296 struct commit *commit;
297 FILE *fp = NULL;
298 int res = 0;
299
300 if (!strcmp(state, terms->term_bad)) {
301 strbuf_addf(&tag, "refs/bisect/%s", state);
302 } else if (one_of(state, terms->term_good, "skip", NULL)) {
303 strbuf_addf(&tag, "refs/bisect/%s-%s", state, rev);
304 } else {
305 res = error(_("Bad bisect_write argument: %s"), state);
306 goto finish;
307 }
308
309 if (repo_get_oid(the_repository, rev, &oid)) {
310 res = error(_("couldn't get the oid of the rev '%s'"), rev);
311 goto finish;
312 }
313
314 if (refs_update_ref(get_main_ref_store(the_repository), NULL, tag.buf, &oid, NULL, 0,
315 UPDATE_REFS_MSG_ON_ERR)) {
316 res = -1;
317 goto finish;
318 }
319
320 fp = fopen(git_path_bisect_log(), "a");
321 if (!fp) {
322 res = error_errno(_("couldn't open the file '%s'"), git_path_bisect_log());
323 goto finish;
324 }
325
326 commit = lookup_commit_reference(the_repository, &oid);
327 log_commit(fp, "%s", state, commit);
328
329 if (!nolog)
330 fprintf(fp, "git bisect %s %s\n", state, rev);
331
332 finish:
333 if (fp)
334 fclose(fp);
335 strbuf_release(&tag);
336 return res;
337 }
338
339 static int check_and_set_terms(struct bisect_terms *terms, const char *cmd)
340 {
341 int has_term_file = !is_empty_or_missing_file(git_path_bisect_terms());
342
343 if (one_of(cmd, "skip", "start", "terms", NULL))
344 return 0;
345
346 if (has_term_file && strcmp(cmd, terms->term_bad) &&
347 strcmp(cmd, terms->term_good))
348 return error(_("Invalid command: you're currently in a "
349 "%s/%s bisect"), terms->term_bad,
350 terms->term_good);
351
352 if (!has_term_file) {
353 if (one_of(cmd, "bad", "good", NULL)) {
354 set_terms(terms, "bad", "good");
355 return write_terms(terms->term_bad, terms->term_good);
356 }
357 if (one_of(cmd, "new", "old", NULL)) {
358 set_terms(terms, "new", "old");
359 return write_terms(terms->term_bad, terms->term_good);
360 }
361 }
362
363 return 0;
364 }
365
366 static int inc_nr(const struct reference *ref UNUSED, void *cb_data)
367 {
368 unsigned int *nr = (unsigned int *)cb_data;
369 (*nr)++;
370 return 0;
371 }
372
373 static const char need_bad_and_good_revision_warning[] =
374 N_("You need to give me at least one %s and %s revision.\n"
375 "You can use \"git bisect %s\" and \"git bisect %s\" for that.");
376
377 static const char need_bisect_start_warning[] =
378 N_("You need to start by \"git bisect start\".\n"
379 "You then need to give me at least one %s and %s revision.\n"
380 "You can use \"git bisect %s\" and \"git bisect %s\" for that.");
381
382 static int decide_next(const struct bisect_terms *terms,
383 const char *current_term, int missing_good,
384 int missing_bad)
385 {
386 if (!missing_good && !missing_bad)
387 return 0;
388 if (!current_term)
389 return -1;
390
391 if (missing_good && !missing_bad &&
392 !strcmp(current_term, terms->term_good)) {
393 char *yesno;
394 /*
395 * have bad (or new) but not good (or old). We could bisect
396 * although this is less optimum.
397 */
398 warning(_("bisecting only with a %s commit"), terms->term_bad);
399 if (!isatty(0))
400 return 0;
401 /*
402 * TRANSLATORS: Make sure to include [Y] and [n] in your
403 * translation. The program will only accept English input
404 * at this point.
405 */
406 yesno = git_prompt(_("Are you sure [Y/n]? "), PROMPT_ECHO);
407 if (starts_with(yesno, "N") || starts_with(yesno, "n"))
408 return -1;
409 return 0;
410 }
411
412 if (!is_empty_or_missing_file(git_path_bisect_start()))
413 return error(_(need_bad_and_good_revision_warning),
414 vocab_bad, vocab_good, vocab_bad, vocab_good);
415 else
416 return error(_(need_bisect_start_warning),
417 vocab_good, vocab_bad, vocab_good, vocab_bad);
418 }
419
420 static void bisect_status(struct bisect_state *state,
421 const struct bisect_terms *terms)
422 {
423 char *bad_ref = xstrfmt("refs/bisect/%s", terms->term_bad);
424 char *good_glob = xstrfmt("%s-*", terms->term_good);
425 struct refs_for_each_ref_options opts = {
426 .pattern = good_glob,
427 .prefix = "refs/bisect/",
428 .trim_prefix = strlen("refs/bisect/"),
429 };
430
431 if (refs_ref_exists(get_main_ref_store(the_repository), bad_ref))
432 state->nr_bad = 1;
433
434 refs_for_each_ref_ext(get_main_ref_store(the_repository),
435 inc_nr, &state->nr_good, &opts);
436
437 free(good_glob);
438 free(bad_ref);
439 }
440
441 __attribute__((format (printf, 1, 2)))
442 static void bisect_log_printf(const char *fmt, ...)
443 {
444 struct strbuf buf = STRBUF_INIT;
445 va_list ap;
446
447 va_start(ap, fmt);
448 strbuf_vaddf(&buf, fmt, ap);
449 va_end(ap);
450
451 printf("%s", buf.buf);
452 append_to_file(git_path_bisect_log(), "# %s", buf.buf);
453
454 strbuf_release(&buf);
455 }
456
457 static void bisect_print_status(const struct bisect_terms *terms)
458 {
459 struct bisect_state state = { 0 };
460
461 bisect_status(&state, terms);
462
463 /* If we had both, we'd already be started, and shouldn't get here. */
464 if (state.nr_good && state.nr_bad)
465 return;
466
467 if (!state.nr_good && !state.nr_bad)
468 bisect_log_printf(_("status: waiting for both '%s' and '%s' commits\n"),
469 terms->term_good, terms->term_bad);
470 else if (state.nr_good)
471 bisect_log_printf(Q_("status: waiting for '%s' commit, %d '%s' commit known\n",
472 "status: waiting for '%s' commit, %d '%s' commits known\n",
473 state.nr_good),
474 terms->term_bad, state.nr_good, terms->term_good);
475 else
476 bisect_log_printf(_("status: waiting for '%s' commit(s), '%s' commit known\n"),
477 terms->term_good, terms->term_bad);
478 }
479
480 static int bisect_next_check(const struct bisect_terms *terms,
481 const char *current_term)
482 {
483 struct bisect_state state = { 0 };
484 bisect_status(&state, terms);
485 return decide_next(terms, current_term, !state.nr_good, !state.nr_bad);
486 }
487
488 static int get_terms(struct bisect_terms *terms)
489 {
490 struct strbuf str = STRBUF_INIT;
491 FILE *fp = NULL;
492 int res = 0;
493
494 fp = fopen(git_path_bisect_terms(), "r");
495 if (!fp) {
496 res = -1;
497 goto finish;
498 }
499
500 free_terms(terms);
501 strbuf_getline_lf(&str, fp);
502 terms->term_bad = strbuf_detach(&str, NULL);
503 strbuf_getline_lf(&str, fp);
504 terms->term_good = strbuf_detach(&str, NULL);
505
506 finish:
507 if (fp)
508 fclose(fp);
509 strbuf_release(&str);
510 return res;
511 }
512
513 static int bisect_terms(struct bisect_terms *terms, const char *option)
514 {
515 if (get_terms(terms))
516 return error(_("no terms defined"));
517
518 if (!option) {
519 printf(_("Your current terms are '%s' for the old state\n"
520 "and '%s' for the new state.\n"),
521 terms->term_good, terms->term_bad);
522 return 0;
523 }
524 if (one_of(option, "--term-good", "--term-old", NULL))
525 printf("%s\n", terms->term_good);
526 else if (one_of(option, "--term-bad", "--term-new", NULL))
527 printf("%s\n", terms->term_bad);
528 else
529 return error(_("invalid argument %s for 'git bisect terms'.\n"
530 "Supported options are: "
531 "--term-good|--term-old and "
532 "--term-bad|--term-new."), option);
533
534 return 0;
535 }
536
537 static int bisect_append_log_quoted(const char **argv)
538 {
539 int res = 0;
540 FILE *fp = fopen(git_path_bisect_log(), "a");
541 struct strbuf orig_args = STRBUF_INIT;
542
543 if (!fp)
544 return -1;
545
546 if (fprintf(fp, "git bisect start") < 1) {
547 res = -1;
548 goto finish;
549 }
550
551 sq_quote_argv(&orig_args, argv);
552 if (fprintf(fp, "%s\n", orig_args.buf) < 1)
553 res = -1;
554
555 finish:
556 fclose(fp);
557 strbuf_release(&orig_args);
558 return res;
559 }
560
561 static int add_bisect_ref(const struct reference *ref, void *cb)
562 {
563 struct add_bisect_ref_data *data = cb;
564
565 add_pending_oid(data->revs, ref->name, ref->oid, data->object_flags);
566
567 return 0;
568 }
569
570 static int prepare_revs(struct bisect_terms *terms, struct rev_info *revs)
571 {
572 struct refs_for_each_ref_options opts = {
573 .prefix = "refs/bisect/",
574 .trim_prefix = strlen("refs/bisect/"),
575 };
576 int res = 0;
577 struct add_bisect_ref_data cb = { revs };
578 char *good = xstrfmt("%s-*", terms->term_good);
579
580 /*
581 * We cannot use terms->term_bad directly in
582 * for_each_glob_ref_in() and we have to append a '*' to it,
583 * otherwise for_each_glob_ref_in() will append '/' and '*'.
584 */
585 char *bad = xstrfmt("%s*", terms->term_bad);
586
587 /*
588 * It is important to reset the flags used by revision walks
589 * as the previous call to bisect_next_all() in turn
590 * sets up a revision walk.
591 */
592 reset_revision_walk();
593 repo_init_revisions(the_repository, revs, NULL);
594 setup_revisions(0, NULL, revs, NULL);
595
596 opts.pattern = bad;
597 refs_for_each_ref_ext(get_main_ref_store(the_repository),
598 add_bisect_ref, &cb, &opts);
599
600 cb.object_flags = UNINTERESTING;
601 opts.pattern = good;
602 refs_for_each_ref_ext(get_main_ref_store(the_repository),
603 add_bisect_ref, &cb, &opts);
604
605 if (prepare_revision_walk(revs))
606 res = error(_("revision walk setup failed"));
607
608 free(good);
609 free(bad);
610 return res;
611 }
612
613 static int bisect_skipped_commits(struct bisect_terms *terms)
614 {
615 int res;
616 FILE *fp = NULL;
617 struct rev_info revs;
618 struct commit *commit;
619 struct pretty_print_context pp = {0};
620 struct strbuf commit_name = STRBUF_INIT;
621
622 res = prepare_revs(terms, &revs);
623 if (res)
624 return res;
625
626 fp = fopen(git_path_bisect_log(), "a");
627 if (!fp)
628 return error_errno(_("could not open '%s' for appending"),
629 git_path_bisect_log());
630
631 if (fprintf(fp, "# only skipped commits left to test\n") < 0)
632 return error_errno(_("failed to write to '%s'"), git_path_bisect_log());
633
634 while ((commit = get_revision(&revs)) != NULL) {
635 strbuf_reset(&commit_name);
636 repo_format_commit_message(the_repository, commit, "%s",
637 &commit_name, &pp);
638 fprintf(fp, "# possible first '%s' commit: [%s] %s\n",
639 terms->term_bad, oid_to_hex(&commit->object.oid),
640 commit_name.buf);
641 }
642
643 /*
644 * Reset the flags used by revision walks in case
645 * there is another revision walk after this one.
646 */
647 reset_revision_walk();
648
649 strbuf_release(&commit_name);
650 release_revisions(&revs);
651 fclose(fp);
652 return 0;
653 }
654
655 static int bisect_successful(struct bisect_terms *terms)
656 {
657 struct object_id oid;
658 struct commit *commit;
659 struct pretty_print_context pp = {0};
660 struct strbuf commit_name = STRBUF_INIT;
661 char *bad_ref = xstrfmt("refs/bisect/%s",terms->term_bad);
662 int res;
663
664 refs_read_ref(get_main_ref_store(the_repository), bad_ref, &oid);
665 commit = lookup_commit_reference_by_name(bad_ref);
666 repo_format_commit_message(the_repository, commit, "%s", &commit_name,
667 &pp);
668
669 res = append_to_file(git_path_bisect_log(), "# first '%s' commit: [%s] %s\n",
670 terms->term_bad, oid_to_hex(&commit->object.oid),
671 commit_name.buf);
672
673 strbuf_release(&commit_name);
674 free(bad_ref);
675 return res;
676 }
677
678 static enum bisect_error bisect_next(struct bisect_terms *terms, const char *prefix)
679 {
680 enum bisect_error res;
681
682 if (bisect_autostart(terms))
683 return BISECT_FAILED;
684
685 if (bisect_next_check(terms, terms->term_good))
686 return BISECT_FAILED;
687
688 /* Perform all bisection computation */
689 res = bisect_next_all(the_repository, prefix);
690
691 if (res == BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND) {
692 res = bisect_successful(terms);
693 return res ? res : BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND;
694 } else if (res == BISECT_ONLY_SKIPPED_LEFT) {
695 res = bisect_skipped_commits(terms);
696 return res ? res : BISECT_ONLY_SKIPPED_LEFT;
697 }
698 return res;
699 }
700
701 static enum bisect_error bisect_auto_next(struct bisect_terms *terms, const char *prefix)
702 {
703 if (bisect_next_check(terms, NULL)) {
704 bisect_print_status(terms);
705 return BISECT_OK;
706 }
707
708 return bisect_next(terms, prefix);
709 }
710
711 static enum bisect_error bisect_start(struct bisect_terms *terms, int argc,
712 const char **argv)
713 {
714 int no_checkout = 0;
715 int first_parent_only = 0;
716 int i, has_double_dash = 0, must_write_terms = 0, bad_seen = 0;
717 int flags, pathspec_pos;
718 enum bisect_error res = BISECT_OK;
719 struct string_list revs = STRING_LIST_INIT_DUP;
720 struct string_list states = STRING_LIST_INIT_DUP;
721 struct strbuf start_head = STRBUF_INIT;
722 struct strbuf bisect_names = STRBUF_INIT;
723 struct object_id head_oid;
724 struct object_id oid;
725 const char *head;
726
727 if (is_bare_repository())
728 no_checkout = 1;
729
730 /*
731 * Check for one bad and then some good revisions
732 */
733 for (i = 0; i < argc; i++) {
734 if (!strcmp(argv[i], "--")) {
735 has_double_dash = 1;
736 break;
737 }
738 }
739
740 for (i = 0; i < argc; i++) {
741 const char *arg = argv[i];
742 if (!strcmp(argv[i], "--")) {
743 break;
744 } else if (!strcmp(arg, "--no-checkout")) {
745 no_checkout = 1;
746 } else if (!strcmp(arg, "--first-parent")) {
747 first_parent_only = 1;
748 } else if (!strcmp(arg, "--term-good") ||
749 !strcmp(arg, "--term-old")) {
750 i++;
751 if (argc <= i)
752 return error(_("'' is not a valid term"));
753 must_write_terms = 1;
754 free((void *) terms->term_good);
755 terms->term_good = xstrdup(argv[i]);
756 } else if (skip_prefix(arg, "--term-good=", &arg) ||
757 skip_prefix(arg, "--term-old=", &arg)) {
758 must_write_terms = 1;
759 free((void *) terms->term_good);
760 terms->term_good = xstrdup(arg);
761 } else if (!strcmp(arg, "--term-bad") ||
762 !strcmp(arg, "--term-new")) {
763 i++;
764 if (argc <= i)
765 return error(_("'' is not a valid term"));
766 must_write_terms = 1;
767 free((void *) terms->term_bad);
768 terms->term_bad = xstrdup(argv[i]);
769 } else if (skip_prefix(arg, "--term-bad=", &arg) ||
770 skip_prefix(arg, "--term-new=", &arg)) {
771 must_write_terms = 1;
772 free((void *) terms->term_bad);
773 terms->term_bad = xstrdup(arg);
774 } else if (starts_with(arg, "--")) {
775 return error(_("unrecognized option: '%s'"), arg);
776 } else if (!get_oidf(&oid, "%s^{commit}", arg)) {
777 string_list_append(&revs, oid_to_hex(&oid));
778 } else if (has_double_dash) {
779 die(_("'%s' does not appear to be a valid "
780 "revision"), arg);
781 } else {
782 break;
783 }
784 }
785 pathspec_pos = i;
786
787 /*
788 * The user ran "git bisect start <sha1> <sha1>", hence did not
789 * explicitly specify the terms, but we are already starting to
790 * set references named with the default terms, and won't be able
791 * to change afterwards.
792 */
793 if (revs.nr)
794 must_write_terms = 1;
795 for (i = 0; i < revs.nr; i++) {
796 if (bad_seen) {
797 string_list_append(&states, terms->term_good);
798 } else {
799 bad_seen = 1;
800 string_list_append(&states, terms->term_bad);
801 }
802 }
803
804 /*
805 * Verify HEAD
806 */
807 head = refs_resolve_ref_unsafe(get_main_ref_store(the_repository),
808 "HEAD", 0, &head_oid, &flags);
809 if (!head)
810 if (repo_get_oid(the_repository, "HEAD", &head_oid))
811 return error(_("bad HEAD - I need a HEAD"));
812
813 /*
814 * Check if we are bisecting
815 */
816 if (!is_empty_or_missing_file(git_path_bisect_start())) {
817 /* Reset to the rev from where we started */
818 strbuf_read_file(&start_head, git_path_bisect_start(), 0);
819 strbuf_trim(&start_head);
820 if (!no_checkout) {
821 struct child_process cmd = CHILD_PROCESS_INIT;
822
823 cmd.git_cmd = 1;
824 strvec_pushl(&cmd.args, "checkout", start_head.buf,
825 "--", NULL);
826 if (run_command(&cmd)) {
827 res = error(_("checking out '%s' failed."
828 " Try 'git bisect start "
829 "<valid-branch>'."),
830 start_head.buf);
831 goto finish;
832 }
833 }
834 } else {
835 /* Get the rev from where we start. */
836 if (!repo_get_oid(the_repository, head, &head_oid) &&
837 !starts_with(head, "refs/heads/")) {
838 strbuf_reset(&start_head);
839 strbuf_add_oid_hex(&start_head, &head_oid);
840 } else if (!repo_get_oid(the_repository, head, &head_oid) &&
841 skip_prefix(head, "refs/heads/", &head)) {
842 strbuf_addstr(&start_head, head);
843 } else {
844 return error(_("bad HEAD - strange symbolic ref"));
845 }
846 }
847
848 /*
849 * Get rid of any old bisect state.
850 */
851 if (bisect_clean_state())
852 return BISECT_FAILED;
853
854 /*
855 * Write new start state
856 */
857 write_file(git_path_bisect_start(), "%s\n", start_head.buf);
858
859 if (first_parent_only)
860 write_file(git_path_bisect_first_parent(), "\n");
861
862 if (no_checkout) {
863 if (repo_get_oid(the_repository, start_head.buf, &oid) < 0) {
864 res = error(_("invalid ref: '%s'"), start_head.buf);
865 goto finish;
866 }
867 if (refs_update_ref(get_main_ref_store(the_repository), NULL, "BISECT_HEAD", &oid, NULL, 0,
868 UPDATE_REFS_MSG_ON_ERR)) {
869 res = BISECT_FAILED;
870 goto finish;
871 }
872 }
873
874 if (pathspec_pos < argc - 1)
875 sq_quote_argv(&bisect_names, argv + pathspec_pos);
876 write_file(git_path_bisect_names(), "%s\n", bisect_names.buf);
877
878 for (i = 0; i < states.nr; i++)
879 if (bisect_write(states.items[i].string,
880 revs.items[i].string, terms, 1)) {
881 res = BISECT_FAILED;
882 goto finish;
883 }
884
885 if (must_write_terms && write_terms(terms->term_bad,
886 terms->term_good)) {
887 res = BISECT_FAILED;
888 goto finish;
889 }
890
891 res = bisect_append_log_quoted(argv);
892 if (res)
893 res = BISECT_FAILED;
894
895 finish:
896 string_list_clear(&revs, 0);
897 string_list_clear(&states, 0);
898 strbuf_release(&start_head);
899 strbuf_release(&bisect_names);
900 if (res)
901 return res;
902
903 res = bisect_auto_next(terms, NULL);
904 if (!is_bisect_success(res))
905 bisect_clean_state();
906 return res;
907 }
908
909 static inline int file_is_not_empty(const char *path)
910 {
911 return !is_empty_or_missing_file(path);
912 }
913
914 static int bisect_autostart(struct bisect_terms *terms)
915 {
916 int res;
917 const char *yesno;
918
919 if (file_is_not_empty(git_path_bisect_start()))
920 return 0;
921
922 fprintf_ln(stderr, _("You need to start by \"git bisect "
923 "start\"\n"));
924
925 if (!isatty(STDIN_FILENO))
926 return -1;
927
928 /*
929 * TRANSLATORS: Make sure to include [Y] and [n] in your
930 * translation. The program will only accept English input
931 * at this point.
932 */
933 yesno = git_prompt(_("Do you want me to do it for you "
934 "[Y/n]? "), PROMPT_ECHO);
935 res = tolower(*yesno) == 'n' ?
936 -1 : bisect_start(terms, 0, empty_strvec);
937
938 return res;
939 }
940
941 static enum bisect_error bisect_state(struct bisect_terms *terms, int argc,
942 const char **argv)
943 {
944 const char *state;
945 int i, verify_expected = 1;
946 struct object_id oid, expected;
947 struct oid_array revs = OID_ARRAY_INIT;
948
949 if (!argc)
950 return error(_("Please call `--bisect-state` with at least one argument"));
951
952 if (bisect_autostart(terms))
953 return BISECT_FAILED;
954
955 state = argv[0];
956 if (check_and_set_terms(terms, state) ||
957 !one_of(state, terms->term_good, terms->term_bad, "skip", NULL))
958 return BISECT_FAILED;
959
960 argv++;
961 argc--;
962 if (argc > 1 && !strcmp(state, terms->term_bad))
963 return error(_("'git bisect %s' can take only one argument."), terms->term_bad);
964
965 if (argc == 0) {
966 const char *head = "BISECT_HEAD";
967 enum get_oid_result res_head = repo_get_oid(the_repository,
968 head, &oid);
969
970 if (res_head == MISSING_OBJECT) {
971 head = "HEAD";
972 res_head = repo_get_oid(the_repository, head, &oid);
973 }
974
975 if (res_head)
976 error(_("Bad rev input: %s"), head);
977 oid_array_append(&revs, &oid);
978 }
979
980 /*
981 * All input revs must be checked before executing bisect_write()
982 * to discard junk revs.
983 */
984
985 for (; argc; argc--, argv++) {
986 struct commit *commit;
987
988 if (repo_get_oid(the_repository, *argv, &oid)){
989 error(_("Bad rev input: %s"), *argv);
990 oid_array_clear(&revs);
991 return BISECT_FAILED;
992 }
993
994 commit = lookup_commit_reference(the_repository, &oid);
995 if (!commit)
996 die(_("Bad rev input (not a commit): %s"), *argv);
997
998 oid_array_append(&revs, &commit->object.oid);
999 }
1000
1001 if (refs_read_ref(get_main_ref_store(the_repository), "BISECT_EXPECTED_REV", &expected))
1002 verify_expected = 0; /* Ignore invalid file contents */
1003
1004 for (i = 0; i < revs.nr; i++) {
1005 if (bisect_write(state, oid_to_hex(&revs.oid[i]), terms, 0)) {
1006 oid_array_clear(&revs);
1007 return BISECT_FAILED;
1008 }
1009 if (verify_expected && !oideq(&revs.oid[i], &expected)) {
1010 unlink_or_warn(git_path_bisect_ancestors_ok());
1011 refs_delete_ref(get_main_ref_store(the_repository),
1012 NULL, "BISECT_EXPECTED_REV", NULL,
1013 REF_NO_DEREF);
1014 verify_expected = 0;
1015 }
1016 }
1017
1018 oid_array_clear(&revs);
1019 return bisect_auto_next(terms, NULL);
1020 }
1021
1022 static enum bisect_error bisect_log(void)
1023 {
1024 int fd, status;
1025 const char* filename = git_path_bisect_log();
1026
1027 if (is_empty_or_missing_file(filename))
1028 return error(_("We are not bisecting."));
1029
1030 fd = open(filename, O_RDONLY);
1031 if (fd < 0)
1032 return BISECT_FAILED;
1033
1034 status = copy_fd(fd, STDOUT_FILENO);
1035 close(fd);
1036 return status ? BISECT_FAILED : BISECT_OK;
1037 }
1038
1039 static int process_replay_line(struct bisect_terms *terms, struct strbuf *line)
1040 {
1041 const char *p = line->buf + strspn(line->buf, " \t");
1042 char *word_end, *rev;
1043
1044 if ((!skip_prefix(p, "git bisect", &p) &&
1045 !skip_prefix(p, "git-bisect", &p)) || !isspace(*p))
1046 return 0;
1047 p += strspn(p, " \t");
1048
1049 word_end = (char *)p + strcspn(p, " \t");
1050 rev = word_end + strspn(word_end, " \t");
1051 *word_end = '\0'; /* NUL-terminate the word */
1052
1053 get_terms(terms);
1054 if (check_and_set_terms(terms, p))
1055 return -1;
1056
1057 if (!strcmp(p, "start")) {
1058 struct strvec argv = STRVEC_INIT;
1059 int res;
1060 sq_dequote_to_strvec(rev, &argv);
1061 res = bisect_start(terms, argv.nr, argv.v);
1062 strvec_clear(&argv);
1063 return res;
1064 }
1065
1066 if (one_of(p, terms->term_good,
1067 terms->term_bad, "skip", NULL))
1068 return bisect_write(p, rev, terms, 0);
1069
1070 if (!strcmp(p, "terms")) {
1071 struct strvec argv = STRVEC_INIT;
1072 int res;
1073 sq_dequote_to_strvec(rev, &argv);
1074 res = bisect_terms(terms, argv.nr == 1 ? argv.v[0] : NULL);
1075 strvec_clear(&argv);
1076 return res;
1077 }
1078 error(_("'%s'?? what are you talking about?"), p);
1079
1080 return -1;
1081 }
1082
1083 static enum bisect_error bisect_replay(struct bisect_terms *terms, const char *filename)
1084 {
1085 FILE *fp = NULL;
1086 enum bisect_error res = BISECT_OK;
1087 struct strbuf line = STRBUF_INIT;
1088
1089 if (is_empty_or_missing_file(filename))
1090 return error(_("cannot read file '%s' for replaying"), filename);
1091
1092 if (bisect_reset(NULL))
1093 return BISECT_FAILED;
1094
1095 fp = fopen(filename, "r");
1096 if (!fp)
1097 return BISECT_FAILED;
1098
1099 while ((strbuf_getline(&line, fp) != EOF) && !res)
1100 res = process_replay_line(terms, &line);
1101
1102 strbuf_release(&line);
1103 fclose(fp);
1104
1105 if (res)
1106 return BISECT_FAILED;
1107
1108 return bisect_auto_next(terms, NULL);
1109 }
1110
1111 static enum bisect_error bisect_skip(struct bisect_terms *terms, int argc,
1112 const char **argv)
1113 {
1114 int i;
1115 enum bisect_error res;
1116 struct strvec argv_state = STRVEC_INIT;
1117
1118 strvec_push(&argv_state, "skip");
1119
1120 for (i = 0; i < argc; i++) {
1121 const char *dotdot = strstr(argv[i], "..");
1122
1123 if (dotdot) {
1124 struct rev_info revs;
1125 struct commit *commit;
1126
1127 repo_init_revisions(the_repository, &revs, NULL);
1128 setup_revisions(2, argv + i - 1, &revs, NULL);
1129
1130 if (prepare_revision_walk(&revs))
1131 die(_("revision walk setup failed"));
1132 while ((commit = get_revision(&revs)) != NULL)
1133 strvec_push(&argv_state,
1134 oid_to_hex(&commit->object.oid));
1135
1136 reset_revision_walk();
1137 release_revisions(&revs);
1138 } else {
1139 strvec_push(&argv_state, argv[i]);
1140 }
1141 }
1142 res = bisect_state(terms, argv_state.nr, argv_state.v);
1143
1144 strvec_clear(&argv_state);
1145 return res;
1146 }
1147
1148 static int bisect_visualize(struct bisect_terms *terms, int argc,
1149 const char **argv)
1150 {
1151 struct child_process cmd = CHILD_PROCESS_INIT;
1152 struct strbuf sb = STRBUF_INIT;
1153
1154 if (bisect_next_check(terms, NULL) != 0)
1155 return BISECT_FAILED;
1156
1157 cmd.no_stdin = 1;
1158 if (!argc) {
1159 if ((getenv("DISPLAY") || getenv("SESSIONNAME") || getenv("MSYSTEM") ||
1160 getenv("SECURITYSESSIONID")) && exists_in_PATH("gitk")) {
1161 strvec_push(&cmd.args, "gitk");
1162 } else {
1163 strvec_push(&cmd.args, "log");
1164 cmd.git_cmd = 1;
1165 }
1166 } else {
1167 if (argv[0][0] == '-') {
1168 strvec_push(&cmd.args, "log");
1169 cmd.git_cmd = 1;
1170 } else if (strcmp(argv[0], "tig") && !starts_with(argv[0], "git"))
1171 cmd.git_cmd = 1;
1172
1173 strvec_pushv(&cmd.args, argv);
1174 }
1175
1176 strvec_pushl(&cmd.args, "--bisect", "--", NULL);
1177
1178 strbuf_read_file(&sb, git_path_bisect_names(), 0);
1179 sq_dequote_to_strvec(sb.buf, &cmd.args);
1180 strbuf_release(&sb);
1181
1182 return run_command(&cmd);
1183 }
1184
1185 static int get_first_good(const struct reference *ref, void *cb_data)
1186 {
1187 oidcpy(cb_data, ref->oid);
1188 return 1;
1189 }
1190
1191 static int do_bisect_run(const char *command)
1192 {
1193 struct child_process cmd = CHILD_PROCESS_INIT;
1194
1195 printf(_("running %s\n"), command);
1196 cmd.use_shell = 1;
1197 strvec_push(&cmd.args, command);
1198 return run_command(&cmd);
1199 }
1200
1201 static int verify_good(const struct bisect_terms *terms, const char *command)
1202 {
1203 int rc;
1204 enum bisect_error res;
1205 struct object_id good_rev;
1206 struct object_id current_rev;
1207 char *good_glob = xstrfmt("%s-*", terms->term_good);
1208 int no_checkout = refs_ref_exists(get_main_ref_store(the_repository),
1209 "BISECT_HEAD");
1210 struct refs_for_each_ref_options opts = {
1211 .pattern = good_glob,
1212 .prefix = "refs/bisect/",
1213 .trim_prefix = strlen("refs/bisect/"),
1214 };
1215
1216 refs_for_each_ref_ext(get_main_ref_store(the_repository),
1217 get_first_good, &good_rev, &opts);
1218 free(good_glob);
1219
1220 if (refs_read_ref(get_main_ref_store(the_repository), no_checkout ? "BISECT_HEAD" : "HEAD", &current_rev))
1221 return -1;
1222
1223 res = bisect_checkout(&good_rev, no_checkout);
1224 if (res != BISECT_OK)
1225 return -1;
1226
1227 rc = do_bisect_run(command);
1228
1229 res = bisect_checkout(&current_rev, no_checkout);
1230 if (res != BISECT_OK)
1231 return -1;
1232
1233 return rc;
1234 }
1235
1236 static int bisect_run(struct bisect_terms *terms, int argc, const char **argv)
1237 {
1238 int res = BISECT_OK;
1239 struct strbuf command = STRBUF_INIT;
1240 const char *new_state;
1241 int temporary_stdout_fd, saved_stdout;
1242 int is_first_run = 1;
1243
1244 if (bisect_next_check(terms, NULL))
1245 return BISECT_FAILED;
1246
1247 if (!argc) {
1248 error(_("bisect run failed: no command provided."));
1249 return BISECT_FAILED;
1250 }
1251
1252 sq_quote_argv(&command, argv);
1253 strbuf_ltrim(&command);
1254 while (1) {
1255 res = do_bisect_run(command.buf);
1256
1257 /*
1258 * Exit code 126 and 127 can either come from the shell
1259 * if it was unable to execute or even find the script,
1260 * or from the script itself. Check with a known-good
1261 * revision to avoid trashing the bisect run due to a
1262 * missing or non-executable script.
1263 */
1264 if (is_first_run && (res == 126 || res == 127)) {
1265 int rc = verify_good(terms, command.buf);
1266 is_first_run = 0;
1267 if (rc < 0 || 128 <= rc) {
1268 error(_("unable to verify %s on '%s' revision"),
1269 command.buf, terms->term_good);
1270 res = BISECT_FAILED;
1271 break;
1272 }
1273 if (rc == res) {
1274 error(_("bogus exit code %d for '%s' revision"),
1275 rc, terms->term_good);
1276 res = BISECT_FAILED;
1277 break;
1278 }
1279 }
1280
1281 if (res < 0 || 128 <= res) {
1282 error(_("bisect run failed: exit code %d from"
1283 " %s is < 0 or >= 128"), res, command.buf);
1284 break;
1285 }
1286
1287 if (res == 125)
1288 new_state = "skip";
1289 else if (!res)
1290 new_state = terms->term_good;
1291 else
1292 new_state = terms->term_bad;
1293
1294 temporary_stdout_fd = open(git_path_bisect_run(), O_CREAT | O_WRONLY | O_TRUNC, 0666);
1295
1296 if (temporary_stdout_fd < 0) {
1297 res = error_errno(_("cannot open file '%s' for writing"), git_path_bisect_run());
1298 break;
1299 }
1300
1301 fflush(stdout);
1302 saved_stdout = dup(1);
1303 dup2(temporary_stdout_fd, 1);
1304
1305 res = bisect_state(terms, 1, &new_state);
1306
1307 fflush(stdout);
1308 dup2(saved_stdout, 1);
1309 close(saved_stdout);
1310 close(temporary_stdout_fd);
1311
1312 print_file_to_stdout(git_path_bisect_run());
1313
1314 if (res == BISECT_ONLY_SKIPPED_LEFT)
1315 error(_("bisect run cannot continue any more"));
1316 else if (res == BISECT_INTERNAL_SUCCESS_MERGE_BASE) {
1317 puts(_("bisect run success"));
1318 res = BISECT_OK;
1319 } else if (res == BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND) {
1320 printf(_("bisect found first '%s' commit\n"), terms->term_bad);
1321 res = BISECT_OK;
1322 } else if (res) {
1323 error(_("bisect run failed: 'git bisect %s'"
1324 " exited with error code %d"), new_state, res);
1325 } else {
1326 continue;
1327 }
1328 break;
1329 }
1330
1331 strbuf_release(&command);
1332 return res;
1333 }
1334
1335 static int cmd_bisect__reset(int argc, const char **argv, const char *prefix UNUSED,
1336 struct repository *repo UNUSED)
1337 {
1338 if (argc > 1)
1339 return error(_("'%s' requires either no argument or a commit"),
1340 "git bisect reset");
1341 return bisect_reset(argc ? argv[0] : NULL);
1342 }
1343
1344 static int cmd_bisect__terms(int argc, const char **argv, const char *prefix UNUSED,
1345 struct repository *repo UNUSED)
1346 {
1347 int res;
1348 struct bisect_terms terms = { 0 };
1349
1350 if (argc > 1)
1351 return error(_("'%s' requires 0 or 1 argument"),
1352 "git bisect terms");
1353 res = bisect_terms(&terms, argc == 1 ? argv[0] : NULL);
1354 free_terms(&terms);
1355 return res;
1356 }
1357
1358 static int cmd_bisect__start(int argc, const char **argv, const char *prefix UNUSED,
1359 struct repository *repo UNUSED)
1360 {
1361 int res;
1362 struct bisect_terms terms = { 0 };
1363
1364 set_terms(&terms, "bad", "good");
1365 res = bisect_start(&terms, argc, argv);
1366 free_terms(&terms);
1367 return res;
1368 }
1369
1370 static int cmd_bisect__next(int argc, const char **argv UNUSED, const char *prefix,
1371 struct repository *repo UNUSED)
1372 {
1373 int res;
1374 struct bisect_terms terms = { 0 };
1375
1376 if (argc)
1377 return error(_("'%s' requires 0 arguments"),
1378 "git bisect next");
1379 get_terms(&terms);
1380 res = bisect_next(&terms, prefix);
1381 free_terms(&terms);
1382 return res;
1383 }
1384
1385 static int cmd_bisect__log(int argc UNUSED, const char **argv UNUSED,
1386 const char *prefix UNUSED,
1387 struct repository *repo UNUSED)
1388 {
1389 return bisect_log();
1390 }
1391
1392 static int cmd_bisect__replay(int argc, const char **argv, const char *prefix UNUSED,
1393 struct repository *repo UNUSED)
1394 {
1395 int res;
1396 struct bisect_terms terms = { 0 };
1397
1398 if (argc != 1)
1399 return error(_("no logfile given"));
1400 set_terms(&terms, "bad", "good");
1401 res = bisect_replay(&terms, argv[0]);
1402 free_terms(&terms);
1403 return res;
1404 }
1405
1406 static int cmd_bisect__skip(int argc, const char **argv, const char *prefix UNUSED,
1407 struct repository *repo UNUSED)
1408 {
1409 int res;
1410 struct bisect_terms terms = { 0 };
1411
1412 set_terms(&terms, "bad", "good");
1413 get_terms(&terms);
1414 res = bisect_skip(&terms, argc, argv);
1415 free_terms(&terms);
1416 return res;
1417 }
1418
1419 static int cmd_bisect__visualize(int argc, const char **argv, const char *prefix UNUSED,
1420 struct repository *repo UNUSED)
1421 {
1422 int res;
1423 struct bisect_terms terms = { 0 };
1424
1425 get_terms(&terms);
1426 res = bisect_visualize(&terms, argc, argv);
1427 free_terms(&terms);
1428 return res;
1429 }
1430
1431 static int cmd_bisect__run(int argc, const char **argv, const char *prefix UNUSED,
1432 struct repository *repo UNUSED)
1433 {
1434 int res;
1435 struct bisect_terms terms = { 0 };
1436
1437 if (!argc)
1438 return error(_("'%s' failed: no command provided."), "git bisect run");
1439 get_terms(&terms);
1440 res = bisect_run(&terms, argc, argv);
1441 free_terms(&terms);
1442 return res;
1443 }
1444
1445 int cmd_bisect(int argc,
1446 const char **argv,
1447 const char *prefix,
1448 struct repository *repo)
1449 {
1450 int res = 0;
1451 parse_opt_subcommand_fn *fn = NULL;
1452 struct option options[] = {
1453 OPT_SUBCOMMAND("reset", &fn, cmd_bisect__reset),
1454 OPT_SUBCOMMAND("terms", &fn, cmd_bisect__terms),
1455 OPT_SUBCOMMAND("start", &fn, cmd_bisect__start),
1456 OPT_SUBCOMMAND("next", &fn, cmd_bisect__next),
1457 OPT_SUBCOMMAND("log", &fn, cmd_bisect__log),
1458 OPT_SUBCOMMAND("replay", &fn, cmd_bisect__replay),
1459 OPT_SUBCOMMAND("skip", &fn, cmd_bisect__skip),
1460 OPT_SUBCOMMAND("visualize", &fn, cmd_bisect__visualize),
1461 OPT_SUBCOMMAND("view", &fn, cmd_bisect__visualize),
1462 OPT_SUBCOMMAND("run", &fn, cmd_bisect__run),
1463 OPT_END()
1464 };
1465 argc = parse_options(argc, argv, prefix, options, git_bisect_usage,
1466 PARSE_OPT_SUBCOMMAND_OPTIONAL);
1467
1468 if (!fn) {
1469 struct bisect_terms terms = { 0 };
1470
1471 if (!argc)
1472 usage_msg_opt(_("need a command"), git_bisect_usage, options);
1473
1474 if (!strcmp(argv[0], "help"))
1475 usage_with_options(git_bisect_usage, options);
1476
1477 set_terms(&terms, "bad", "good");
1478 get_terms(&terms);
1479 if (check_and_set_terms(&terms, argv[0]) ||
1480 !one_of(argv[0], terms.term_good, terms.term_bad, NULL))
1481 usage_msg_optf(_("unknown command: '%s'"), git_bisect_usage,
1482 options, argv[0]);
1483 res = bisect_state(&terms, argc, argv);
1484 free_terms(&terms);
1485 } else {
1486 argc--;
1487 argv++;
1488 res = fn(argc, argv, prefix, repo);
1489 }
1490
1491 return is_bisect_success(res) ? 0 : -res;
1492 }