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