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