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