]> git.ipfire.org Git - thirdparty/git.git/blob - builtin/bisect--helper.c
Merge branch 'en/strmap'
[thirdparty/git.git] / builtin / bisect--helper.c
1 #include "builtin.h"
2 #include "cache.h"
3 #include "parse-options.h"
4 #include "bisect.h"
5 #include "refs.h"
6 #include "dir.h"
7 #include "strvec.h"
8 #include "run-command.h"
9 #include "prompt.h"
10 #include "quote.h"
11 #include "revision.h"
12
13 static GIT_PATH_FUNC(git_path_bisect_terms, "BISECT_TERMS")
14 static GIT_PATH_FUNC(git_path_bisect_expected_rev, "BISECT_EXPECTED_REV")
15 static GIT_PATH_FUNC(git_path_bisect_ancestors_ok, "BISECT_ANCESTORS_OK")
16 static GIT_PATH_FUNC(git_path_bisect_start, "BISECT_START")
17 static GIT_PATH_FUNC(git_path_bisect_log, "BISECT_LOG")
18 static GIT_PATH_FUNC(git_path_head_name, "head-name")
19 static GIT_PATH_FUNC(git_path_bisect_names, "BISECT_NAMES")
20 static GIT_PATH_FUNC(git_path_bisect_first_parent, "BISECT_FIRST_PARENT")
21
22 static const char * const git_bisect_helper_usage[] = {
23 N_("git bisect--helper --bisect-reset [<commit>]"),
24 N_("git bisect--helper --bisect-write [--no-log] <state> <revision> <good_term> <bad_term>"),
25 N_("git bisect--helper --bisect-check-and-set-terms <command> <good_term> <bad_term>"),
26 N_("git bisect--helper --bisect-next-check <good_term> <bad_term> [<term>]"),
27 N_("git bisect--helper --bisect-terms [--term-good | --term-old | --term-bad | --term-new]"),
28 N_("git bisect--helper --bisect-start [--term-{new,bad}=<term> --term-{old,good}=<term>]"
29 " [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<paths>...]"),
30 N_("git bisect--helper --bisect-next"),
31 N_("git bisect--helper --bisect-auto-next"),
32 N_("git bisect--helper --bisect-state (bad|new) [<rev>]"),
33 N_("git bisect--helper --bisect-state (good|old) [<rev>...]"),
34 NULL
35 };
36
37 struct add_bisect_ref_data {
38 struct rev_info *revs;
39 unsigned int object_flags;
40 };
41
42 struct bisect_terms {
43 char *term_good;
44 char *term_bad;
45 };
46
47 static void free_terms(struct bisect_terms *terms)
48 {
49 FREE_AND_NULL(terms->term_good);
50 FREE_AND_NULL(terms->term_bad);
51 }
52
53 static void set_terms(struct bisect_terms *terms, const char *bad,
54 const char *good)
55 {
56 free((void *)terms->term_good);
57 terms->term_good = xstrdup(good);
58 free((void *)terms->term_bad);
59 terms->term_bad = xstrdup(bad);
60 }
61
62 static const char vocab_bad[] = "bad|new";
63 static const char vocab_good[] = "good|old";
64
65 static int bisect_autostart(struct bisect_terms *terms);
66
67 /*
68 * Check whether the string `term` belongs to the set of strings
69 * included in the variable arguments.
70 */
71 LAST_ARG_MUST_BE_NULL
72 static int one_of(const char *term, ...)
73 {
74 int res = 0;
75 va_list matches;
76 const char *match;
77
78 va_start(matches, term);
79 while (!res && (match = va_arg(matches, const char *)))
80 res = !strcmp(term, match);
81 va_end(matches);
82
83 return res;
84 }
85
86 /*
87 * return code BISECT_INTERNAL_SUCCESS_MERGE_BASE
88 * and BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND are codes
89 * that indicate special success.
90 */
91
92 static int is_bisect_success(enum bisect_error res)
93 {
94 return !res ||
95 res == BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND ||
96 res == BISECT_INTERNAL_SUCCESS_MERGE_BASE;
97 }
98
99 static int write_in_file(const char *path, const char *mode, const char *format, va_list args)
100 {
101 FILE *fp = NULL;
102 int res = 0;
103
104 if (strcmp(mode, "w") && strcmp(mode, "a"))
105 BUG("write-in-file does not support '%s' mode", mode);
106 fp = fopen(path, mode);
107 if (!fp)
108 return error_errno(_("cannot open file '%s' in mode '%s'"), path, mode);
109 res = vfprintf(fp, format, args);
110
111 if (res < 0) {
112 int saved_errno = errno;
113 fclose(fp);
114 errno = saved_errno;
115 return error_errno(_("could not write to file '%s'"), path);
116 }
117
118 return fclose(fp);
119 }
120
121 static int write_to_file(const char *path, const char *format, ...)
122 {
123 int res;
124 va_list args;
125
126 va_start(args, format);
127 res = write_in_file(path, "w", format, args);
128 va_end(args);
129
130 return res;
131 }
132
133 static int append_to_file(const char *path, const char *format, ...)
134 {
135 int res;
136 va_list args;
137
138 va_start(args, format);
139 res = write_in_file(path, "a", format, args);
140 va_end(args);
141
142 return res;
143 }
144
145 static int check_term_format(const char *term, const char *orig_term)
146 {
147 int res;
148 char *new_term = xstrfmt("refs/bisect/%s", term);
149
150 res = check_refname_format(new_term, 0);
151 free(new_term);
152
153 if (res)
154 return error(_("'%s' is not a valid term"), term);
155
156 if (one_of(term, "help", "start", "skip", "next", "reset",
157 "visualize", "view", "replay", "log", "run", "terms", NULL))
158 return error(_("can't use the builtin command '%s' as a term"), term);
159
160 /*
161 * In theory, nothing prevents swapping completely good and bad,
162 * but this situation could be confusing and hasn't been tested
163 * enough. Forbid it for now.
164 */
165
166 if ((strcmp(orig_term, "bad") && one_of(term, "bad", "new", NULL)) ||
167 (strcmp(orig_term, "good") && one_of(term, "good", "old", NULL)))
168 return error(_("can't change the meaning of the term '%s'"), term);
169
170 return 0;
171 }
172
173 static int write_terms(const char *bad, const char *good)
174 {
175 int res;
176
177 if (!strcmp(bad, good))
178 return error(_("please use two different terms"));
179
180 if (check_term_format(bad, "bad") || check_term_format(good, "good"))
181 return -1;
182
183 res = write_to_file(git_path_bisect_terms(), "%s\n%s\n", bad, good);
184
185 return res;
186 }
187
188 static int bisect_reset(const char *commit)
189 {
190 struct strbuf branch = STRBUF_INIT;
191
192 if (!commit) {
193 if (strbuf_read_file(&branch, git_path_bisect_start(), 0) < 1) {
194 printf(_("We are not bisecting.\n"));
195 return 0;
196 }
197 strbuf_rtrim(&branch);
198 } else {
199 struct object_id oid;
200
201 if (get_oid_commit(commit, &oid))
202 return error(_("'%s' is not a valid commit"), commit);
203 strbuf_addstr(&branch, commit);
204 }
205
206 if (!ref_exists("BISECT_HEAD")) {
207 struct strvec argv = STRVEC_INIT;
208
209 strvec_pushl(&argv, "checkout", branch.buf, "--", NULL);
210 if (run_command_v_opt(argv.v, RUN_GIT_CMD)) {
211 error(_("could not check out original"
212 " HEAD '%s'. Try 'git bisect"
213 " reset <commit>'."), branch.buf);
214 strbuf_release(&branch);
215 strvec_clear(&argv);
216 return -1;
217 }
218 strvec_clear(&argv);
219 }
220
221 strbuf_release(&branch);
222 return bisect_clean_state();
223 }
224
225 static void log_commit(FILE *fp, char *fmt, const char *state,
226 struct commit *commit)
227 {
228 struct pretty_print_context pp = {0};
229 struct strbuf commit_msg = STRBUF_INIT;
230 char *label = xstrfmt(fmt, state);
231
232 format_commit_message(commit, "%s", &commit_msg, &pp);
233
234 fprintf(fp, "# %s: [%s] %s\n", label, oid_to_hex(&commit->object.oid),
235 commit_msg.buf);
236
237 strbuf_release(&commit_msg);
238 free(label);
239 }
240
241 static int bisect_write(const char *state, const char *rev,
242 const struct bisect_terms *terms, int nolog)
243 {
244 struct strbuf tag = STRBUF_INIT;
245 struct object_id oid;
246 struct commit *commit;
247 FILE *fp = NULL;
248 int res = 0;
249
250 if (!strcmp(state, terms->term_bad)) {
251 strbuf_addf(&tag, "refs/bisect/%s", state);
252 } else if (one_of(state, terms->term_good, "skip", NULL)) {
253 strbuf_addf(&tag, "refs/bisect/%s-%s", state, rev);
254 } else {
255 res = error(_("Bad bisect_write argument: %s"), state);
256 goto finish;
257 }
258
259 if (get_oid(rev, &oid)) {
260 res = error(_("couldn't get the oid of the rev '%s'"), rev);
261 goto finish;
262 }
263
264 if (update_ref(NULL, tag.buf, &oid, NULL, 0,
265 UPDATE_REFS_MSG_ON_ERR)) {
266 res = -1;
267 goto finish;
268 }
269
270 fp = fopen(git_path_bisect_log(), "a");
271 if (!fp) {
272 res = error_errno(_("couldn't open the file '%s'"), git_path_bisect_log());
273 goto finish;
274 }
275
276 commit = lookup_commit_reference(the_repository, &oid);
277 log_commit(fp, "%s", state, commit);
278
279 if (!nolog)
280 fprintf(fp, "git bisect %s %s\n", state, rev);
281
282 finish:
283 if (fp)
284 fclose(fp);
285 strbuf_release(&tag);
286 return res;
287 }
288
289 static int check_and_set_terms(struct bisect_terms *terms, const char *cmd)
290 {
291 int has_term_file = !is_empty_or_missing_file(git_path_bisect_terms());
292
293 if (one_of(cmd, "skip", "start", "terms", NULL))
294 return 0;
295
296 if (has_term_file && strcmp(cmd, terms->term_bad) &&
297 strcmp(cmd, terms->term_good))
298 return error(_("Invalid command: you're currently in a "
299 "%s/%s bisect"), terms->term_bad,
300 terms->term_good);
301
302 if (!has_term_file) {
303 if (one_of(cmd, "bad", "good", NULL)) {
304 set_terms(terms, "bad", "good");
305 return write_terms(terms->term_bad, terms->term_good);
306 }
307 if (one_of(cmd, "new", "old", NULL)) {
308 set_terms(terms, "new", "old");
309 return write_terms(terms->term_bad, terms->term_good);
310 }
311 }
312
313 return 0;
314 }
315
316 static int mark_good(const char *refname, const struct object_id *oid,
317 int flag, void *cb_data)
318 {
319 int *m_good = (int *)cb_data;
320 *m_good = 0;
321 return 1;
322 }
323
324 static const char need_bad_and_good_revision_warning[] =
325 N_("You need to give me at least one %s and %s revision.\n"
326 "You can use \"git bisect %s\" and \"git bisect %s\" for that.");
327
328 static const char need_bisect_start_warning[] =
329 N_("You need to start by \"git bisect start\".\n"
330 "You then need to give me at least one %s and %s revision.\n"
331 "You can use \"git bisect %s\" and \"git bisect %s\" for that.");
332
333 static int decide_next(const struct bisect_terms *terms,
334 const char *current_term, int missing_good,
335 int missing_bad)
336 {
337 if (!missing_good && !missing_bad)
338 return 0;
339 if (!current_term)
340 return -1;
341
342 if (missing_good && !missing_bad &&
343 !strcmp(current_term, terms->term_good)) {
344 char *yesno;
345 /*
346 * have bad (or new) but not good (or old). We could bisect
347 * although this is less optimum.
348 */
349 warning(_("bisecting only with a %s commit"), terms->term_bad);
350 if (!isatty(0))
351 return 0;
352 /*
353 * TRANSLATORS: Make sure to include [Y] and [n] in your
354 * translation. The program will only accept English input
355 * at this point.
356 */
357 yesno = git_prompt(_("Are you sure [Y/n]? "), PROMPT_ECHO);
358 if (starts_with(yesno, "N") || starts_with(yesno, "n"))
359 return -1;
360 return 0;
361 }
362
363 if (!is_empty_or_missing_file(git_path_bisect_start()))
364 return error(_(need_bad_and_good_revision_warning),
365 vocab_bad, vocab_good, vocab_bad, vocab_good);
366 else
367 return error(_(need_bisect_start_warning),
368 vocab_good, vocab_bad, vocab_good, vocab_bad);
369 }
370
371 static int bisect_next_check(const struct bisect_terms *terms,
372 const char *current_term)
373 {
374 int missing_good = 1, missing_bad = 1;
375 char *bad_ref = xstrfmt("refs/bisect/%s", terms->term_bad);
376 char *good_glob = xstrfmt("%s-*", terms->term_good);
377
378 if (ref_exists(bad_ref))
379 missing_bad = 0;
380
381 for_each_glob_ref_in(mark_good, good_glob, "refs/bisect/",
382 (void *) &missing_good);
383
384 free(good_glob);
385 free(bad_ref);
386
387 return decide_next(terms, current_term, missing_good, missing_bad);
388 }
389
390 static int get_terms(struct bisect_terms *terms)
391 {
392 struct strbuf str = STRBUF_INIT;
393 FILE *fp = NULL;
394 int res = 0;
395
396 fp = fopen(git_path_bisect_terms(), "r");
397 if (!fp) {
398 res = -1;
399 goto finish;
400 }
401
402 free_terms(terms);
403 strbuf_getline_lf(&str, fp);
404 terms->term_bad = strbuf_detach(&str, NULL);
405 strbuf_getline_lf(&str, fp);
406 terms->term_good = strbuf_detach(&str, NULL);
407
408 finish:
409 if (fp)
410 fclose(fp);
411 strbuf_release(&str);
412 return res;
413 }
414
415 static int bisect_terms(struct bisect_terms *terms, const char *option)
416 {
417 if (get_terms(terms))
418 return error(_("no terms defined"));
419
420 if (option == NULL) {
421 printf(_("Your current terms are %s for the old state\n"
422 "and %s for the new state.\n"),
423 terms->term_good, terms->term_bad);
424 return 0;
425 }
426 if (one_of(option, "--term-good", "--term-old", NULL))
427 printf("%s\n", terms->term_good);
428 else if (one_of(option, "--term-bad", "--term-new", NULL))
429 printf("%s\n", terms->term_bad);
430 else
431 return error(_("invalid argument %s for 'git bisect terms'.\n"
432 "Supported options are: "
433 "--term-good|--term-old and "
434 "--term-bad|--term-new."), option);
435
436 return 0;
437 }
438
439 static int bisect_append_log_quoted(const char **argv)
440 {
441 int res = 0;
442 FILE *fp = fopen(git_path_bisect_log(), "a");
443 struct strbuf orig_args = STRBUF_INIT;
444
445 if (!fp)
446 return -1;
447
448 if (fprintf(fp, "git bisect start") < 1) {
449 res = -1;
450 goto finish;
451 }
452
453 sq_quote_argv(&orig_args, argv);
454 if (fprintf(fp, "%s\n", orig_args.buf) < 1)
455 res = -1;
456
457 finish:
458 fclose(fp);
459 strbuf_release(&orig_args);
460 return res;
461 }
462
463 static int add_bisect_ref(const char *refname, const struct object_id *oid,
464 int flags, void *cb)
465 {
466 struct add_bisect_ref_data *data = cb;
467
468 add_pending_oid(data->revs, refname, oid, data->object_flags);
469
470 return 0;
471 }
472
473 static int prepare_revs(struct bisect_terms *terms, struct rev_info *revs)
474 {
475 int res = 0;
476 struct add_bisect_ref_data cb = { revs };
477 char *good = xstrfmt("%s-*", terms->term_good);
478
479 /*
480 * We cannot use terms->term_bad directly in
481 * for_each_glob_ref_in() and we have to append a '*' to it,
482 * otherwise for_each_glob_ref_in() will append '/' and '*'.
483 */
484 char *bad = xstrfmt("%s*", terms->term_bad);
485
486 /*
487 * It is important to reset the flags used by revision walks
488 * as the previous call to bisect_next_all() in turn
489 * sets up a revision walk.
490 */
491 reset_revision_walk();
492 init_revisions(revs, NULL);
493 setup_revisions(0, NULL, revs, NULL);
494 for_each_glob_ref_in(add_bisect_ref, bad, "refs/bisect/", &cb);
495 cb.object_flags = UNINTERESTING;
496 for_each_glob_ref_in(add_bisect_ref, good, "refs/bisect/", &cb);
497 if (prepare_revision_walk(revs))
498 res = error(_("revision walk setup failed\n"));
499
500 free(good);
501 free(bad);
502 return res;
503 }
504
505 static int bisect_skipped_commits(struct bisect_terms *terms)
506 {
507 int res;
508 FILE *fp = NULL;
509 struct rev_info revs;
510 struct commit *commit;
511 struct pretty_print_context pp = {0};
512 struct strbuf commit_name = STRBUF_INIT;
513
514 res = prepare_revs(terms, &revs);
515 if (res)
516 return res;
517
518 fp = fopen(git_path_bisect_log(), "a");
519 if (!fp)
520 return error_errno(_("could not open '%s' for appending"),
521 git_path_bisect_log());
522
523 if (fprintf(fp, "# only skipped commits left to test\n") < 0)
524 return error_errno(_("failed to write to '%s'"), git_path_bisect_log());
525
526 while ((commit = get_revision(&revs)) != NULL) {
527 strbuf_reset(&commit_name);
528 format_commit_message(commit, "%s",
529 &commit_name, &pp);
530 fprintf(fp, "# possible first %s commit: [%s] %s\n",
531 terms->term_bad, oid_to_hex(&commit->object.oid),
532 commit_name.buf);
533 }
534
535 /*
536 * Reset the flags used by revision walks in case
537 * there is another revision walk after this one.
538 */
539 reset_revision_walk();
540
541 strbuf_release(&commit_name);
542 fclose(fp);
543 return 0;
544 }
545
546 static int bisect_successful(struct bisect_terms *terms)
547 {
548 struct object_id oid;
549 struct commit *commit;
550 struct pretty_print_context pp = {0};
551 struct strbuf commit_name = STRBUF_INIT;
552 char *bad_ref = xstrfmt("refs/bisect/%s",terms->term_bad);
553 int res;
554
555 read_ref(bad_ref, &oid);
556 commit = lookup_commit_reference_by_name(bad_ref);
557 format_commit_message(commit, "%s", &commit_name, &pp);
558
559 res = append_to_file(git_path_bisect_log(), "# first %s commit: [%s] %s\n",
560 terms->term_bad, oid_to_hex(&commit->object.oid),
561 commit_name.buf);
562
563 strbuf_release(&commit_name);
564 free(bad_ref);
565 return res;
566 }
567
568 static enum bisect_error bisect_next(struct bisect_terms *terms, const char *prefix)
569 {
570 enum bisect_error res;
571
572 if (bisect_autostart(terms))
573 return BISECT_FAILED;
574
575 if (bisect_next_check(terms, terms->term_good))
576 return BISECT_FAILED;
577
578 /* Perform all bisection computation */
579 res = bisect_next_all(the_repository, prefix);
580
581 if (res == BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND) {
582 res = bisect_successful(terms);
583 return res ? res : BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND;
584 } else if (res == BISECT_ONLY_SKIPPED_LEFT) {
585 res = bisect_skipped_commits(terms);
586 return res ? res : BISECT_ONLY_SKIPPED_LEFT;
587 }
588 return res;
589 }
590
591 static enum bisect_error bisect_auto_next(struct bisect_terms *terms, const char *prefix)
592 {
593 if (bisect_next_check(terms, NULL))
594 return BISECT_OK;
595
596 return bisect_next(terms, prefix);
597 }
598
599 static enum bisect_error bisect_start(struct bisect_terms *terms, const char **argv, int argc)
600 {
601 int no_checkout = 0;
602 int first_parent_only = 0;
603 int i, has_double_dash = 0, must_write_terms = 0, bad_seen = 0;
604 int flags, pathspec_pos;
605 enum bisect_error res = BISECT_OK;
606 struct string_list revs = STRING_LIST_INIT_DUP;
607 struct string_list states = STRING_LIST_INIT_DUP;
608 struct strbuf start_head = STRBUF_INIT;
609 struct strbuf bisect_names = STRBUF_INIT;
610 struct object_id head_oid;
611 struct object_id oid;
612 const char *head;
613
614 if (is_bare_repository())
615 no_checkout = 1;
616
617 /*
618 * Check for one bad and then some good revisions
619 */
620 for (i = 0; i < argc; i++) {
621 if (!strcmp(argv[i], "--")) {
622 has_double_dash = 1;
623 break;
624 }
625 }
626
627 for (i = 0; i < argc; i++) {
628 const char *arg = argv[i];
629 if (!strcmp(argv[i], "--")) {
630 break;
631 } else if (!strcmp(arg, "--no-checkout")) {
632 no_checkout = 1;
633 } else if (!strcmp(arg, "--first-parent")) {
634 first_parent_only = 1;
635 } else if (!strcmp(arg, "--term-good") ||
636 !strcmp(arg, "--term-old")) {
637 i++;
638 if (argc <= i)
639 return error(_("'' is not a valid term"));
640 must_write_terms = 1;
641 free((void *) terms->term_good);
642 terms->term_good = xstrdup(argv[i]);
643 } else if (skip_prefix(arg, "--term-good=", &arg) ||
644 skip_prefix(arg, "--term-old=", &arg)) {
645 must_write_terms = 1;
646 free((void *) terms->term_good);
647 terms->term_good = xstrdup(arg);
648 } else if (!strcmp(arg, "--term-bad") ||
649 !strcmp(arg, "--term-new")) {
650 i++;
651 if (argc <= i)
652 return error(_("'' is not a valid term"));
653 must_write_terms = 1;
654 free((void *) terms->term_bad);
655 terms->term_bad = xstrdup(argv[i]);
656 } else if (skip_prefix(arg, "--term-bad=", &arg) ||
657 skip_prefix(arg, "--term-new=", &arg)) {
658 must_write_terms = 1;
659 free((void *) terms->term_bad);
660 terms->term_bad = xstrdup(arg);
661 } else if (starts_with(arg, "--")) {
662 return error(_("unrecognized option: '%s'"), arg);
663 } else if (!get_oidf(&oid, "%s^{commit}", arg)) {
664 string_list_append(&revs, oid_to_hex(&oid));
665 } else if (has_double_dash) {
666 die(_("'%s' does not appear to be a valid "
667 "revision"), arg);
668 } else {
669 break;
670 }
671 }
672 pathspec_pos = i;
673
674 /*
675 * The user ran "git bisect start <sha1> <sha1>", hence did not
676 * explicitly specify the terms, but we are already starting to
677 * set references named with the default terms, and won't be able
678 * to change afterwards.
679 */
680 if (revs.nr)
681 must_write_terms = 1;
682 for (i = 0; i < revs.nr; i++) {
683 if (bad_seen) {
684 string_list_append(&states, terms->term_good);
685 } else {
686 bad_seen = 1;
687 string_list_append(&states, terms->term_bad);
688 }
689 }
690
691 /*
692 * Verify HEAD
693 */
694 head = resolve_ref_unsafe("HEAD", 0, &head_oid, &flags);
695 if (!head)
696 if (get_oid("HEAD", &head_oid))
697 return error(_("bad HEAD - I need a HEAD"));
698
699 /*
700 * Check if we are bisecting
701 */
702 if (!is_empty_or_missing_file(git_path_bisect_start())) {
703 /* Reset to the rev from where we started */
704 strbuf_read_file(&start_head, git_path_bisect_start(), 0);
705 strbuf_trim(&start_head);
706 if (!no_checkout) {
707 struct strvec argv = STRVEC_INIT;
708
709 strvec_pushl(&argv, "checkout", start_head.buf,
710 "--", NULL);
711 if (run_command_v_opt(argv.v, RUN_GIT_CMD)) {
712 res = error(_("checking out '%s' failed."
713 " Try 'git bisect start "
714 "<valid-branch>'."),
715 start_head.buf);
716 goto finish;
717 }
718 }
719 } else {
720 /* Get the rev from where we start. */
721 if (!get_oid(head, &head_oid) &&
722 !starts_with(head, "refs/heads/")) {
723 strbuf_reset(&start_head);
724 strbuf_addstr(&start_head, oid_to_hex(&head_oid));
725 } else if (!get_oid(head, &head_oid) &&
726 skip_prefix(head, "refs/heads/", &head)) {
727 /*
728 * This error message should only be triggered by
729 * cogito usage, and cogito users should understand
730 * it relates to cg-seek.
731 */
732 if (!is_empty_or_missing_file(git_path_head_name()))
733 return error(_("won't bisect on cg-seek'ed tree"));
734 strbuf_addstr(&start_head, head);
735 } else {
736 return error(_("bad HEAD - strange symbolic ref"));
737 }
738 }
739
740 /*
741 * Get rid of any old bisect state.
742 */
743 if (bisect_clean_state())
744 return BISECT_FAILED;
745
746 /*
747 * Write new start state
748 */
749 write_file(git_path_bisect_start(), "%s\n", start_head.buf);
750
751 if (first_parent_only)
752 write_file(git_path_bisect_first_parent(), "\n");
753
754 if (no_checkout) {
755 if (get_oid(start_head.buf, &oid) < 0) {
756 res = error(_("invalid ref: '%s'"), start_head.buf);
757 goto finish;
758 }
759 if (update_ref(NULL, "BISECT_HEAD", &oid, NULL, 0,
760 UPDATE_REFS_MSG_ON_ERR)) {
761 res = BISECT_FAILED;
762 goto finish;
763 }
764 }
765
766 if (pathspec_pos < argc - 1)
767 sq_quote_argv(&bisect_names, argv + pathspec_pos);
768 write_file(git_path_bisect_names(), "%s\n", bisect_names.buf);
769
770 for (i = 0; i < states.nr; i++)
771 if (bisect_write(states.items[i].string,
772 revs.items[i].string, terms, 1)) {
773 res = BISECT_FAILED;
774 goto finish;
775 }
776
777 if (must_write_terms && write_terms(terms->term_bad,
778 terms->term_good)) {
779 res = BISECT_FAILED;
780 goto finish;
781 }
782
783 res = bisect_append_log_quoted(argv);
784 if (res)
785 res = BISECT_FAILED;
786
787 finish:
788 string_list_clear(&revs, 0);
789 string_list_clear(&states, 0);
790 strbuf_release(&start_head);
791 strbuf_release(&bisect_names);
792 if (res)
793 return res;
794
795 res = bisect_auto_next(terms, NULL);
796 if (!is_bisect_success(res))
797 bisect_clean_state();
798 return res;
799 }
800
801 static inline int file_is_not_empty(const char *path)
802 {
803 return !is_empty_or_missing_file(path);
804 }
805
806 static int bisect_autostart(struct bisect_terms *terms)
807 {
808 int res;
809 const char *yesno;
810
811 if (file_is_not_empty(git_path_bisect_start()))
812 return 0;
813
814 fprintf_ln(stderr, _("You need to start by \"git bisect "
815 "start\"\n"));
816
817 if (!isatty(STDIN_FILENO))
818 return -1;
819
820 /*
821 * TRANSLATORS: Make sure to include [Y] and [n] in your
822 * translation. The program will only accept English input
823 * at this point.
824 */
825 yesno = git_prompt(_("Do you want me to do it for you "
826 "[Y/n]? "), PROMPT_ECHO);
827 res = tolower(*yesno) == 'n' ?
828 -1 : bisect_start(terms, empty_strvec, 0);
829
830 return res;
831 }
832
833 static enum bisect_error bisect_state(struct bisect_terms *terms, const char **argv,
834 int argc)
835 {
836 const char *state;
837 int i, verify_expected = 1;
838 struct object_id oid, expected;
839 struct strbuf buf = STRBUF_INIT;
840 struct oid_array revs = OID_ARRAY_INIT;
841
842 if (!argc)
843 return error(_("Please call `--bisect-state` with at least one argument"));
844
845 if (bisect_autostart(terms))
846 return BISECT_FAILED;
847
848 state = argv[0];
849 if (check_and_set_terms(terms, state) ||
850 !one_of(state, terms->term_good, terms->term_bad, "skip", NULL))
851 return BISECT_FAILED;
852
853 argv++;
854 argc--;
855 if (argc > 1 && !strcmp(state, terms->term_bad))
856 return error(_("'git bisect %s' can take only one argument."), terms->term_bad);
857
858 if (argc == 0) {
859 const char *head = "BISECT_HEAD";
860 enum get_oid_result res_head = get_oid(head, &oid);
861
862 if (res_head == MISSING_OBJECT) {
863 head = "HEAD";
864 res_head = get_oid(head, &oid);
865 }
866
867 if (res_head)
868 error(_("Bad rev input: %s"), head);
869 oid_array_append(&revs, &oid);
870 }
871
872 /*
873 * All input revs must be checked before executing bisect_write()
874 * to discard junk revs.
875 */
876
877 for (; argc; argc--, argv++) {
878 if (get_oid(*argv, &oid)){
879 error(_("Bad rev input: %s"), *argv);
880 oid_array_clear(&revs);
881 return BISECT_FAILED;
882 }
883 oid_array_append(&revs, &oid);
884 }
885
886 if (strbuf_read_file(&buf, git_path_bisect_expected_rev(), 0) < the_hash_algo->hexsz ||
887 get_oid_hex(buf.buf, &expected) < 0)
888 verify_expected = 0; /* Ignore invalid file contents */
889 strbuf_release(&buf);
890
891 for (i = 0; i < revs.nr; i++) {
892 if (bisect_write(state, oid_to_hex(&revs.oid[i]), terms, 0)) {
893 oid_array_clear(&revs);
894 return BISECT_FAILED;
895 }
896 if (verify_expected && !oideq(&revs.oid[i], &expected)) {
897 unlink_or_warn(git_path_bisect_ancestors_ok());
898 unlink_or_warn(git_path_bisect_expected_rev());
899 verify_expected = 0;
900 }
901 }
902
903 oid_array_clear(&revs);
904 return bisect_auto_next(terms, NULL);
905 }
906
907 int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
908 {
909 enum {
910 BISECT_RESET = 1,
911 BISECT_WRITE,
912 CHECK_AND_SET_TERMS,
913 BISECT_NEXT_CHECK,
914 BISECT_TERMS,
915 BISECT_START,
916 BISECT_AUTOSTART,
917 BISECT_NEXT,
918 BISECT_AUTO_NEXT,
919 BISECT_STATE
920 } cmdmode = 0;
921 int res = 0, nolog = 0;
922 struct option options[] = {
923 OPT_CMDMODE(0, "bisect-reset", &cmdmode,
924 N_("reset the bisection state"), BISECT_RESET),
925 OPT_CMDMODE(0, "bisect-write", &cmdmode,
926 N_("write out the bisection state in BISECT_LOG"), BISECT_WRITE),
927 OPT_CMDMODE(0, "check-and-set-terms", &cmdmode,
928 N_("check and set terms in a bisection state"), CHECK_AND_SET_TERMS),
929 OPT_CMDMODE(0, "bisect-next-check", &cmdmode,
930 N_("check whether bad or good terms exist"), BISECT_NEXT_CHECK),
931 OPT_CMDMODE(0, "bisect-terms", &cmdmode,
932 N_("print out the bisect terms"), BISECT_TERMS),
933 OPT_CMDMODE(0, "bisect-start", &cmdmode,
934 N_("start the bisect session"), BISECT_START),
935 OPT_CMDMODE(0, "bisect-next", &cmdmode,
936 N_("find the next bisection commit"), BISECT_NEXT),
937 OPT_CMDMODE(0, "bisect-auto-next", &cmdmode,
938 N_("verify the next bisection state then checkout the next bisection commit"), BISECT_AUTO_NEXT),
939 OPT_CMDMODE(0, "bisect-state", &cmdmode,
940 N_("mark the state of ref (or refs)"), BISECT_STATE),
941 OPT_BOOL(0, "no-log", &nolog,
942 N_("no log for BISECT_WRITE")),
943 OPT_END()
944 };
945 struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
946
947 argc = parse_options(argc, argv, prefix, options,
948 git_bisect_helper_usage,
949 PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN);
950
951 if (!cmdmode)
952 usage_with_options(git_bisect_helper_usage, options);
953
954 switch (cmdmode) {
955 case BISECT_RESET:
956 if (argc > 1)
957 return error(_("--bisect-reset requires either no argument or a commit"));
958 return !!bisect_reset(argc ? argv[0] : NULL);
959 case BISECT_WRITE:
960 if (argc != 4 && argc != 5)
961 return error(_("--bisect-write requires either 4 or 5 arguments"));
962 set_terms(&terms, argv[3], argv[2]);
963 res = bisect_write(argv[0], argv[1], &terms, nolog);
964 break;
965 case CHECK_AND_SET_TERMS:
966 if (argc != 3)
967 return error(_("--check-and-set-terms requires 3 arguments"));
968 set_terms(&terms, argv[2], argv[1]);
969 res = check_and_set_terms(&terms, argv[0]);
970 break;
971 case BISECT_NEXT_CHECK:
972 if (argc != 2 && argc != 3)
973 return error(_("--bisect-next-check requires 2 or 3 arguments"));
974 set_terms(&terms, argv[1], argv[0]);
975 res = bisect_next_check(&terms, argc == 3 ? argv[2] : NULL);
976 break;
977 case BISECT_TERMS:
978 if (argc > 1)
979 return error(_("--bisect-terms requires 0 or 1 argument"));
980 res = bisect_terms(&terms, argc == 1 ? argv[0] : NULL);
981 break;
982 case BISECT_START:
983 set_terms(&terms, "bad", "good");
984 res = bisect_start(&terms, argv, argc);
985 break;
986 case BISECT_NEXT:
987 if (argc)
988 return error(_("--bisect-next requires 0 arguments"));
989 get_terms(&terms);
990 res = bisect_next(&terms, prefix);
991 break;
992 case BISECT_AUTO_NEXT:
993 if (argc)
994 return error(_("--bisect-auto-next requires 0 arguments"));
995 get_terms(&terms);
996 res = bisect_auto_next(&terms, prefix);
997 break;
998 case BISECT_STATE:
999 set_terms(&terms, "bad", "good");
1000 get_terms(&terms);
1001 res = bisect_state(&terms, argv, argc);
1002 break;
1003 default:
1004 BUG("unknown subcommand %d", cmdmode);
1005 }
1006 free_terms(&terms);
1007
1008 /*
1009 * Handle early success
1010 * From check_merge_bases > check_good_are_ancestors_of_bad > bisect_next_all
1011 */
1012 if ((res == BISECT_INTERNAL_SUCCESS_MERGE_BASE) || (res == BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND))
1013 res = BISECT_OK;
1014
1015 return -res;
1016 }