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 if (!commit) {
667 error(_("could not find commit for '%s'"), bad_ref);
668 free(bad_ref);
669 return BISECT_FAILED;
670 }
671 repo_format_commit_message(the_repository, commit, "%s", &commit_name,
672 &pp);
673
674 res = append_to_file(git_path_bisect_log(), "# first '%s' commit: [%s] %s\n",
675 terms->term_bad, oid_to_hex(&commit->object.oid),
676 commit_name.buf);
677
678 strbuf_release(&commit_name);
679 free(bad_ref);
680 return res;
681 }
682
683 static enum bisect_error bisect_next(struct bisect_terms *terms, const char *prefix)
684 {
685 enum bisect_error res;
686
687 if (bisect_autostart(terms))
688 return BISECT_FAILED;
689
690 if (bisect_next_check(terms, terms->term_good))
691 return BISECT_FAILED;
692
693 /* Perform all bisection computation */
694 res = bisect_next_all(the_repository, prefix);
695
696 if (res == BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND) {
697 res = bisect_successful(terms);
698 return res ? res : BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND;
699 } else if (res == BISECT_ONLY_SKIPPED_LEFT) {
700 res = bisect_skipped_commits(terms);
701 return res ? res : BISECT_ONLY_SKIPPED_LEFT;
702 }
703 return res;
704 }
705
706 static enum bisect_error bisect_auto_next(struct bisect_terms *terms, const char *prefix)
707 {
708 if (bisect_next_check(terms, NULL)) {
709 bisect_print_status(terms);
710 return BISECT_OK;
711 }
712
713 return bisect_next(terms, prefix);
714 }
715
716 static enum bisect_error bisect_start(struct bisect_terms *terms, int argc,
717 const char **argv)
718 {
719 int no_checkout = 0;
720 int first_parent_only = 0;
721 int i, has_double_dash = 0, must_write_terms = 0, bad_seen = 0;
722 int flags, pathspec_pos;
723 enum bisect_error res = BISECT_OK;
724 struct string_list revs = STRING_LIST_INIT_DUP;
725 struct string_list states = STRING_LIST_INIT_DUP;
726 struct strbuf start_head = STRBUF_INIT;
727 struct strbuf bisect_names = STRBUF_INIT;
728 struct object_id head_oid;
729 struct object_id oid;
730 const char *head;
731
732 if (is_bare_repository(the_repository))
733 no_checkout = 1;
734
735 /*
736 * Check for one bad and then some good revisions
737 */
738 for (i = 0; i < argc; i++) {
739 if (!strcmp(argv[i], "--")) {
740 has_double_dash = 1;
741 break;
742 }
743 }
744
745 for (i = 0; i < argc; i++) {
746 const char *arg = argv[i];
747 if (!strcmp(argv[i], "--")) {
748 break;
749 } else if (!strcmp(arg, "--no-checkout")) {
750 no_checkout = 1;
751 } else if (!strcmp(arg, "--first-parent")) {
752 first_parent_only = 1;
753 } else if (!strcmp(arg, "--term-good") ||
754 !strcmp(arg, "--term-old")) {
755 i++;
756 if (argc <= i)
757 return error(_("'' is not a valid term"));
758 must_write_terms = 1;
759 free((void *) terms->term_good);
760 terms->term_good = xstrdup(argv[i]);
761 } else if (skip_prefix(arg, "--term-good=", &arg) ||
762 skip_prefix(arg, "--term-old=", &arg)) {
763 must_write_terms = 1;
764 free((void *) terms->term_good);
765 terms->term_good = xstrdup(arg);
766 } else if (!strcmp(arg, "--term-bad") ||
767 !strcmp(arg, "--term-new")) {
768 i++;
769 if (argc <= i)
770 return error(_("'' is not a valid term"));
771 must_write_terms = 1;
772 free((void *) terms->term_bad);
773 terms->term_bad = xstrdup(argv[i]);
774 } else if (skip_prefix(arg, "--term-bad=", &arg) ||
775 skip_prefix(arg, "--term-new=", &arg)) {
776 must_write_terms = 1;
777 free((void *) terms->term_bad);
778 terms->term_bad = xstrdup(arg);
779 } else if (starts_with(arg, "--")) {
780 return error(_("unrecognized option: '%s'"), arg);
781 } else if (!get_oidf(&oid, "%s^{commit}", arg)) {
782 string_list_append(&revs, oid_to_hex(&oid));
783 } else if (has_double_dash) {
784 die(_("'%s' does not appear to be a valid "
785 "revision"), arg);
786 } else {
787 break;
788 }
789 }
790 pathspec_pos = i;
791
792 /*
793 * The user ran "git bisect start <sha1> <sha1>", hence did not
794 * explicitly specify the terms, but we are already starting to
795 * set references named with the default terms, and won't be able
796 * to change afterwards.
797 */
798 if (revs.nr)
799 must_write_terms = 1;
800 for (i = 0; i < revs.nr; i++) {
801 if (bad_seen) {
802 string_list_append(&states, terms->term_good);
803 } else {
804 bad_seen = 1;
805 string_list_append(&states, terms->term_bad);
806 }
807 }
808
809 /*
810 * Verify HEAD
811 */
812 head = refs_resolve_ref_unsafe(get_main_ref_store(the_repository),
813 "HEAD", 0, &head_oid, &flags);
814 if (!head) {
815 if (repo_get_oid(the_repository, "HEAD", &head_oid))
816 return error(_("bad HEAD - I need a HEAD"));
817 head = "HEAD";
818 }
819
820 /*
821 * Check if we are bisecting
822 */
823 if (!is_empty_or_missing_file(git_path_bisect_start())) {
824 /* Reset to the rev from where we started */
825 strbuf_read_file(&start_head, git_path_bisect_start(), 0);
826 strbuf_trim(&start_head);
827 if (!no_checkout) {
828 struct child_process cmd = CHILD_PROCESS_INIT;
829
830 cmd.git_cmd = 1;
831 strvec_pushl(&cmd.args, "checkout", start_head.buf,
832 "--", NULL);
833 if (run_command(&cmd)) {
834 res = error(_("checking out '%s' failed."
835 " Try 'git bisect start "
836 "<valid-branch>'."),
837 start_head.buf);
838 goto finish;
839 }
840 }
841 } else {
842 /* Get the rev from where we start. */
843 if (!repo_get_oid(the_repository, head, &head_oid) &&
844 !starts_with(head, "refs/heads/")) {
845 strbuf_reset(&start_head);
846 strbuf_add_oid_hex(&start_head, &head_oid);
847 } else if (!repo_get_oid(the_repository, head, &head_oid) &&
848 skip_prefix(head, "refs/heads/", &head)) {
849 strbuf_addstr(&start_head, head);
850 } else {
851 return error(_("bad HEAD - strange symbolic ref"));
852 }
853 }
854
855 /*
856 * Get rid of any old bisect state.
857 */
858 if (bisect_clean_state())
859 return BISECT_FAILED;
860
861 /*
862 * Write new start state
863 */
864 write_file(git_path_bisect_start(), "%s\n", start_head.buf);
865
866 if (first_parent_only)
867 write_file(git_path_bisect_first_parent(), "\n");
868
869 if (no_checkout) {
870 if (repo_get_oid(the_repository, start_head.buf, &oid) < 0) {
871 res = error(_("invalid ref: '%s'"), start_head.buf);
872 goto finish;
873 }
874 if (refs_update_ref(get_main_ref_store(the_repository), NULL, "BISECT_HEAD", &oid, NULL, 0,
875 UPDATE_REFS_MSG_ON_ERR)) {
876 res = BISECT_FAILED;
877 goto finish;
878 }
879 }
880
881 if (pathspec_pos < argc - 1)
882 sq_quote_argv(&bisect_names, argv + pathspec_pos);
883 write_file(git_path_bisect_names(), "%s\n", bisect_names.buf);
884
885 for (i = 0; i < states.nr; i++)
886 if (bisect_write(states.items[i].string,
887 revs.items[i].string, terms, 1)) {
888 res = BISECT_FAILED;
889 goto finish;
890 }
891
892 if (must_write_terms && write_terms(terms->term_bad,
893 terms->term_good)) {
894 res = BISECT_FAILED;
895 goto finish;
896 }
897
898 res = bisect_append_log_quoted(argv);
899 if (res)
900 res = BISECT_FAILED;
901
902 finish:
903 string_list_clear(&revs, 0);
904 string_list_clear(&states, 0);
905 strbuf_release(&start_head);
906 strbuf_release(&bisect_names);
907 if (res)
908 return res;
909
910 res = bisect_auto_next(terms, NULL);
911 if (!is_bisect_success(res))
912 bisect_clean_state();
913 return res;
914 }
915
916 static inline int file_is_not_empty(const char *path)
917 {
918 return !is_empty_or_missing_file(path);
919 }
920
921 static int bisect_autostart(struct bisect_terms *terms)
922 {
923 int res;
924 const char *yesno;
925
926 if (file_is_not_empty(git_path_bisect_start()))
927 return 0;
928
929 fprintf_ln(stderr, _("You need to start by \"git bisect "
930 "start\"\n"));
931
932 if (!isatty(STDIN_FILENO))
933 return -1;
934
935 /*
936 * TRANSLATORS: Make sure to include [Y] and [n] in your
937 * translation. The program will only accept English input
938 * at this point.
939 */
940 yesno = git_prompt(_("Do you want me to do it for you "
941 "[Y/n]? "), PROMPT_ECHO);
942 res = tolower(*yesno) == 'n' ?
943 -1 : bisect_start(terms, 0, empty_strvec);
944
945 return res;
946 }
947
948 static enum bisect_error bisect_state(struct bisect_terms *terms, int argc,
949 const char **argv)
950 {
951 const char *state;
952 int i, verify_expected = 1;
953 struct object_id oid, expected;
954 struct oid_array revs = OID_ARRAY_INIT;
955
956 if (!argc)
957 return error(_("Please call `--bisect-state` with at least one argument"));
958
959 if (bisect_autostart(terms))
960 return BISECT_FAILED;
961
962 state = argv[0];
963 if (check_and_set_terms(terms, state) ||
964 !one_of(state, terms->term_good, terms->term_bad, "skip", NULL))
965 return BISECT_FAILED;
966
967 argv++;
968 argc--;
969 if (argc > 1 && !strcmp(state, terms->term_bad))
970 return error(_("'git bisect %s' can take only one argument."), terms->term_bad);
971
972 if (argc == 0) {
973 const char *head = "BISECT_HEAD";
974 enum get_oid_result res_head = repo_get_oid(the_repository,
975 head, &oid);
976
977 if (res_head == MISSING_OBJECT) {
978 head = "HEAD";
979 res_head = repo_get_oid(the_repository, head, &oid);
980 }
981
982 if (res_head)
983 error(_("Bad rev input: %s"), head);
984 oid_array_append(&revs, &oid);
985 }
986
987 /*
988 * All input revs must be checked before executing bisect_write()
989 * to discard junk revs.
990 */
991
992 for (; argc; argc--, argv++) {
993 struct commit *commit;
994
995 if (repo_get_oid(the_repository, *argv, &oid)){
996 error(_("Bad rev input: %s"), *argv);
997 oid_array_clear(&revs);
998 return BISECT_FAILED;
999 }
1000
1001 commit = lookup_commit_reference(the_repository, &oid);
1002 if (!commit)
1003 die(_("Bad rev input (not a commit): %s"), *argv);
1004
1005 oid_array_append(&revs, &commit->object.oid);
1006 }
1007
1008 if (refs_read_ref(get_main_ref_store(the_repository), "BISECT_EXPECTED_REV", &expected))
1009 verify_expected = 0; /* Ignore invalid file contents */
1010
1011 for (i = 0; i < revs.nr; i++) {
1012 if (bisect_write(state, oid_to_hex(&revs.oid[i]), terms, 0)) {
1013 oid_array_clear(&revs);
1014 return BISECT_FAILED;
1015 }
1016 if (verify_expected && !oideq(&revs.oid[i], &expected)) {
1017 unlink_or_warn(git_path_bisect_ancestors_ok());
1018 refs_delete_ref(get_main_ref_store(the_repository),
1019 NULL, "BISECT_EXPECTED_REV", NULL,
1020 REF_NO_DEREF);
1021 verify_expected = 0;
1022 }
1023 }
1024
1025 oid_array_clear(&revs);
1026 return bisect_auto_next(terms, NULL);
1027 }
1028
1029 static enum bisect_error bisect_log(void)
1030 {
1031 int fd, status;
1032 const char* filename = git_path_bisect_log();
1033
1034 if (is_empty_or_missing_file(filename))
1035 return error(_("We are not bisecting."));
1036
1037 fd = open(filename, O_RDONLY);
1038 if (fd < 0)
1039 return BISECT_FAILED;
1040
1041 status = copy_fd(fd, STDOUT_FILENO);
1042 close(fd);
1043 return status ? BISECT_FAILED : BISECT_OK;
1044 }
1045
1046 static int process_replay_line(struct bisect_terms *terms, struct strbuf *line)
1047 {
1048 const char *p = line->buf + strspn(line->buf, " \t");
1049 char *word_end, *rev;
1050
1051 if ((!skip_prefix(p, "git bisect", &p) &&
1052 !skip_prefix(p, "git-bisect", &p)) || !isspace(*p))
1053 return 0;
1054 p += strspn(p, " \t");
1055
1056 word_end = (char *)p + strcspn(p, " \t");
1057 rev = word_end + strspn(word_end, " \t");
1058 *word_end = '\0'; /* NUL-terminate the word */
1059
1060 get_terms(terms);
1061 if (check_and_set_terms(terms, p))
1062 return -1;
1063
1064 if (!strcmp(p, "start")) {
1065 struct strvec argv = STRVEC_INIT;
1066 int res;
1067 sq_dequote_to_strvec(rev, &argv);
1068 res = bisect_start(terms, argv.nr, argv.v);
1069 strvec_clear(&argv);
1070 return res;
1071 }
1072
1073 if (one_of(p, terms->term_good,
1074 terms->term_bad, "skip", NULL))
1075 return bisect_write(p, rev, terms, 0);
1076
1077 if (!strcmp(p, "terms")) {
1078 struct strvec argv = STRVEC_INIT;
1079 int res;
1080 sq_dequote_to_strvec(rev, &argv);
1081 res = bisect_terms(terms, argv.nr == 1 ? argv.v[0] : NULL);
1082 strvec_clear(&argv);
1083 return res;
1084 }
1085 error(_("'%s'?? what are you talking about?"), p);
1086
1087 return -1;
1088 }
1089
1090 static enum bisect_error bisect_replay(struct bisect_terms *terms, const char *filename)
1091 {
1092 FILE *fp = NULL;
1093 enum bisect_error res = BISECT_OK;
1094 struct strbuf line = STRBUF_INIT;
1095
1096 if (is_empty_or_missing_file(filename))
1097 return error(_("cannot read file '%s' for replaying"), filename);
1098
1099 if (bisect_reset(NULL))
1100 return BISECT_FAILED;
1101
1102 fp = fopen(filename, "r");
1103 if (!fp)
1104 return BISECT_FAILED;
1105
1106 while ((strbuf_getline(&line, fp) != EOF) && !res)
1107 res = process_replay_line(terms, &line);
1108
1109 strbuf_release(&line);
1110 fclose(fp);
1111
1112 if (res)
1113 return BISECT_FAILED;
1114
1115 return bisect_auto_next(terms, NULL);
1116 }
1117
1118 static enum bisect_error bisect_skip(struct bisect_terms *terms, int argc,
1119 const char **argv)
1120 {
1121 int i;
1122 enum bisect_error res;
1123 struct strvec argv_state = STRVEC_INIT;
1124
1125 strvec_push(&argv_state, "skip");
1126
1127 for (i = 0; i < argc; i++) {
1128 const char *dotdot = strstr(argv[i], "..");
1129
1130 if (dotdot) {
1131 struct rev_info revs;
1132 struct commit *commit;
1133
1134 repo_init_revisions(the_repository, &revs, NULL);
1135 setup_revisions(2, argv + i - 1, &revs, NULL);
1136
1137 if (prepare_revision_walk(&revs))
1138 die(_("revision walk setup failed"));
1139 while ((commit = get_revision(&revs)) != NULL)
1140 strvec_push(&argv_state,
1141 oid_to_hex(&commit->object.oid));
1142
1143 reset_revision_walk();
1144 release_revisions(&revs);
1145 } else {
1146 strvec_push(&argv_state, argv[i]);
1147 }
1148 }
1149 res = bisect_state(terms, argv_state.nr, argv_state.v);
1150
1151 strvec_clear(&argv_state);
1152 return res;
1153 }
1154
1155 static int bisect_visualize(struct bisect_terms *terms, int argc,
1156 const char **argv)
1157 {
1158 struct child_process cmd = CHILD_PROCESS_INIT;
1159 struct strbuf sb = STRBUF_INIT;
1160
1161 if (bisect_next_check(terms, NULL) != 0)
1162 return BISECT_FAILED;
1163
1164 cmd.no_stdin = 1;
1165 if (!argc) {
1166 if ((getenv("DISPLAY") || getenv("SESSIONNAME") || getenv("MSYSTEM") ||
1167 getenv("SECURITYSESSIONID")) && exists_in_PATH("gitk")) {
1168 strvec_push(&cmd.args, "gitk");
1169 } else {
1170 strvec_push(&cmd.args, "log");
1171 cmd.git_cmd = 1;
1172 }
1173 } else {
1174 if (argv[0][0] == '-') {
1175 strvec_push(&cmd.args, "log");
1176 cmd.git_cmd = 1;
1177 } else if (strcmp(argv[0], "tig") && !starts_with(argv[0], "git"))
1178 cmd.git_cmd = 1;
1179
1180 strvec_pushv(&cmd.args, argv);
1181 }
1182
1183 strvec_pushl(&cmd.args, "--bisect", "--", NULL);
1184
1185 strbuf_read_file(&sb, git_path_bisect_names(), 0);
1186 sq_dequote_to_strvec(sb.buf, &cmd.args);
1187 strbuf_release(&sb);
1188
1189 return run_command(&cmd);
1190 }
1191
1192 static int get_first_good(const struct reference *ref, void *cb_data)
1193 {
1194 oidcpy(cb_data, ref->oid);
1195 return 1;
1196 }
1197
1198 static int do_bisect_run(const char *command)
1199 {
1200 struct child_process cmd = CHILD_PROCESS_INIT;
1201
1202 printf(_("running %s\n"), command);
1203 cmd.use_shell = 1;
1204 strvec_push(&cmd.args, command);
1205 return run_command(&cmd);
1206 }
1207
1208 static int verify_good(const struct bisect_terms *terms, const char *command)
1209 {
1210 int rc;
1211 enum bisect_error res;
1212 struct object_id good_rev;
1213 struct object_id current_rev;
1214 char *good_glob = xstrfmt("%s-*", terms->term_good);
1215 int no_checkout = refs_ref_exists(get_main_ref_store(the_repository),
1216 "BISECT_HEAD");
1217 struct refs_for_each_ref_options opts = {
1218 .pattern = good_glob,
1219 .prefix = "refs/bisect/",
1220 .trim_prefix = strlen("refs/bisect/"),
1221 };
1222
1223 refs_for_each_ref_ext(get_main_ref_store(the_repository),
1224 get_first_good, &good_rev, &opts);
1225 free(good_glob);
1226
1227 if (refs_read_ref(get_main_ref_store(the_repository), no_checkout ? "BISECT_HEAD" : "HEAD", &current_rev))
1228 return -1;
1229
1230 res = bisect_checkout(&good_rev, no_checkout);
1231 if (res != BISECT_OK)
1232 return -1;
1233
1234 rc = do_bisect_run(command);
1235
1236 res = bisect_checkout(&current_rev, no_checkout);
1237 if (res != BISECT_OK)
1238 return -1;
1239
1240 return rc;
1241 }
1242
1243 static int bisect_run(struct bisect_terms *terms, int argc, const char **argv)
1244 {
1245 int res = BISECT_OK;
1246 struct strbuf command = STRBUF_INIT;
1247 const char *new_state;
1248 int temporary_stdout_fd, saved_stdout;
1249 int is_first_run = 1;
1250
1251 if (bisect_next_check(terms, NULL))
1252 return BISECT_FAILED;
1253
1254 if (!argc) {
1255 error(_("bisect run failed: no command provided."));
1256 return BISECT_FAILED;
1257 }
1258
1259 sq_quote_argv(&command, argv);
1260 strbuf_ltrim(&command);
1261 while (1) {
1262 res = do_bisect_run(command.buf);
1263
1264 /*
1265 * Exit code 126 and 127 can either come from the shell
1266 * if it was unable to execute or even find the script,
1267 * or from the script itself. Check with a known-good
1268 * revision to avoid trashing the bisect run due to a
1269 * missing or non-executable script.
1270 */
1271 if (is_first_run && (res == 126 || res == 127)) {
1272 int rc = verify_good(terms, command.buf);
1273 is_first_run = 0;
1274 if (rc < 0 || 128 <= rc) {
1275 error(_("unable to verify %s on '%s' revision"),
1276 command.buf, terms->term_good);
1277 res = BISECT_FAILED;
1278 break;
1279 }
1280 if (rc == res) {
1281 error(_("bogus exit code %d for '%s' revision"),
1282 rc, terms->term_good);
1283 res = BISECT_FAILED;
1284 break;
1285 }
1286 }
1287
1288 if (res < 0 || 128 <= res) {
1289 error(_("bisect run failed: exit code %d from"
1290 " %s is < 0 or >= 128"), res, command.buf);
1291 break;
1292 }
1293
1294 if (res == 125)
1295 new_state = "skip";
1296 else if (!res)
1297 new_state = terms->term_good;
1298 else
1299 new_state = terms->term_bad;
1300
1301 temporary_stdout_fd = open(git_path_bisect_run(), O_CREAT | O_WRONLY | O_TRUNC, 0666);
1302
1303 if (temporary_stdout_fd < 0) {
1304 res = error_errno(_("cannot open file '%s' for writing"), git_path_bisect_run());
1305 break;
1306 }
1307
1308 fflush(stdout);
1309 saved_stdout = dup(1);
1310 dup2(temporary_stdout_fd, 1);
1311
1312 res = bisect_state(terms, 1, &new_state);
1313
1314 fflush(stdout);
1315 dup2(saved_stdout, 1);
1316 close(saved_stdout);
1317 close(temporary_stdout_fd);
1318
1319 print_file_to_stdout(git_path_bisect_run());
1320
1321 if (res == BISECT_ONLY_SKIPPED_LEFT)
1322 error(_("bisect run cannot continue any more"));
1323 else if (res == BISECT_INTERNAL_SUCCESS_MERGE_BASE) {
1324 puts(_("bisect run success"));
1325 res = BISECT_OK;
1326 } else if (res == BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND) {
1327 printf(_("bisect found first '%s' commit\n"), terms->term_bad);
1328 res = BISECT_OK;
1329 } else if (res) {
1330 error(_("bisect run failed: 'git bisect %s'"
1331 " exited with error code %d"), new_state, res);
1332 } else {
1333 continue;
1334 }
1335 break;
1336 }
1337
1338 strbuf_release(&command);
1339 return res;
1340 }
1341
1342 static int cmd_bisect__reset(int argc, const char **argv, const char *prefix UNUSED,
1343 struct repository *repo UNUSED)
1344 {
1345 if (argc > 1)
1346 return error(_("'%s' requires either no argument or a commit"),
1347 "git bisect reset");
1348 return bisect_reset(argc ? argv[0] : NULL);
1349 }
1350
1351 static int cmd_bisect__terms(int argc, const char **argv, const char *prefix UNUSED,
1352 struct repository *repo UNUSED)
1353 {
1354 int res;
1355 struct bisect_terms terms = { 0 };
1356
1357 if (argc > 1)
1358 return error(_("'%s' requires 0 or 1 argument"),
1359 "git bisect terms");
1360 res = bisect_terms(&terms, argc == 1 ? argv[0] : NULL);
1361 free_terms(&terms);
1362 return res;
1363 }
1364
1365 static int cmd_bisect__start(int argc, const char **argv, const char *prefix UNUSED,
1366 struct repository *repo UNUSED)
1367 {
1368 int res;
1369 struct bisect_terms terms = { 0 };
1370
1371 set_terms(&terms, "bad", "good");
1372 res = bisect_start(&terms, argc, argv);
1373 free_terms(&terms);
1374 return res;
1375 }
1376
1377 static int cmd_bisect__next(int argc, const char **argv UNUSED, const char *prefix,
1378 struct repository *repo UNUSED)
1379 {
1380 int res;
1381 struct bisect_terms terms = { 0 };
1382
1383 if (argc)
1384 return error(_("'%s' requires 0 arguments"),
1385 "git bisect next");
1386 get_terms(&terms);
1387 res = bisect_next(&terms, prefix);
1388 free_terms(&terms);
1389 return res;
1390 }
1391
1392 static int cmd_bisect__log(int argc UNUSED, const char **argv UNUSED,
1393 const char *prefix UNUSED,
1394 struct repository *repo UNUSED)
1395 {
1396 return bisect_log();
1397 }
1398
1399 static int cmd_bisect__replay(int argc, const char **argv, const char *prefix UNUSED,
1400 struct repository *repo UNUSED)
1401 {
1402 int res;
1403 struct bisect_terms terms = { 0 };
1404
1405 if (argc != 1)
1406 return error(_("no logfile given"));
1407 set_terms(&terms, "bad", "good");
1408 res = bisect_replay(&terms, argv[0]);
1409 free_terms(&terms);
1410 return res;
1411 }
1412
1413 static int cmd_bisect__skip(int argc, const char **argv, const char *prefix UNUSED,
1414 struct repository *repo UNUSED)
1415 {
1416 int res;
1417 struct bisect_terms terms = { 0 };
1418
1419 set_terms(&terms, "bad", "good");
1420 get_terms(&terms);
1421 res = bisect_skip(&terms, argc, argv);
1422 free_terms(&terms);
1423 return res;
1424 }
1425
1426 static int cmd_bisect__visualize(int argc, const char **argv, const char *prefix UNUSED,
1427 struct repository *repo UNUSED)
1428 {
1429 int res;
1430 struct bisect_terms terms = { 0 };
1431
1432 get_terms(&terms);
1433 res = bisect_visualize(&terms, argc, argv);
1434 free_terms(&terms);
1435 return res;
1436 }
1437
1438 static int cmd_bisect__run(int argc, const char **argv, const char *prefix UNUSED,
1439 struct repository *repo UNUSED)
1440 {
1441 int res;
1442 struct bisect_terms terms = { 0 };
1443
1444 if (!argc)
1445 return error(_("'%s' failed: no command provided."), "git bisect run");
1446 get_terms(&terms);
1447 res = bisect_run(&terms, argc, argv);
1448 free_terms(&terms);
1449 return res;
1450 }
1451
1452 int cmd_bisect(int argc,
1453 const char **argv,
1454 const char *prefix,
1455 struct repository *repo)
1456 {
1457 int res = 0;
1458 parse_opt_subcommand_fn *fn = NULL;
1459 struct option options[] = {
1460 OPT_SUBCOMMAND("reset", &fn, cmd_bisect__reset),
1461 OPT_SUBCOMMAND("terms", &fn, cmd_bisect__terms),
1462 OPT_SUBCOMMAND("start", &fn, cmd_bisect__start),
1463 OPT_SUBCOMMAND("next", &fn, cmd_bisect__next),
1464 OPT_SUBCOMMAND("log", &fn, cmd_bisect__log),
1465 OPT_SUBCOMMAND("replay", &fn, cmd_bisect__replay),
1466 OPT_SUBCOMMAND("skip", &fn, cmd_bisect__skip),
1467 OPT_SUBCOMMAND("visualize", &fn, cmd_bisect__visualize),
1468 OPT_SUBCOMMAND("view", &fn, cmd_bisect__visualize),
1469 OPT_SUBCOMMAND("run", &fn, cmd_bisect__run),
1470 OPT_END()
1471 };
1472 argc = parse_options(argc, argv, prefix, options, git_bisect_usage,
1473 PARSE_OPT_SUBCOMMAND_OPTIONAL);
1474
1475 if (!fn) {
1476 struct bisect_terms terms = { 0 };
1477
1478 if (!argc)
1479 usage_msg_opt(_("need a command"), git_bisect_usage, options);
1480
1481 if (!strcmp(argv[0], "help"))
1482 usage_with_options(git_bisect_usage, options);
1483
1484 set_terms(&terms, "bad", "good");
1485 get_terms(&terms);
1486 if (check_and_set_terms(&terms, argv[0]) ||
1487 !one_of(argv[0], terms.term_good, terms.term_bad, NULL))
1488 usage_msg_optf(_("unknown command: '%s'"), git_bisect_usage,
1489 options, argv[0]);
1490 res = bisect_state(&terms, argc, argv);
1491 free_terms(&terms);
1492 } else {
1493 argc--;
1494 argv++;
1495 res = fn(argc, argv, prefix, repo);
1496 }
1497
1498 return is_bisect_success(res) ? 0 : -res;
1499 }