]> git.ipfire.org Git - thirdparty/git.git/blame - builtin/bisect--helper.c
Merge branch 'pb/ref-filter-with-crlf'
[thirdparty/git.git] / builtin / bisect--helper.c
CommitLineData
1bf072e3
CC
1#include "builtin.h"
2#include "cache.h"
3#include "parse-options.h"
4#include "bisect.h"
4ba1e5c4 5#include "refs.h"
5e82c3dd 6#include "dir.h"
dbbcd44f 7#include "strvec.h"
5e82c3dd 8#include "run-command.h"
129a6cf3 9#include "prompt.h"
06f5608c 10#include "quote.h"
517ecb31 11#include "revision.h"
1bf072e3 12
ecb3f373 13static GIT_PATH_FUNC(git_path_bisect_terms, "BISECT_TERMS")
b903674b
PB
14static GIT_PATH_FUNC(git_path_bisect_expected_rev, "BISECT_EXPECTED_REV")
15static GIT_PATH_FUNC(git_path_bisect_ancestors_ok, "BISECT_ANCESTORS_OK")
5e82c3dd 16static GIT_PATH_FUNC(git_path_bisect_start, "BISECT_START")
0f30233a 17static GIT_PATH_FUNC(git_path_bisect_log, "BISECT_LOG")
06f5608c
PB
18static GIT_PATH_FUNC(git_path_head_name, "head-name")
19static GIT_PATH_FUNC(git_path_bisect_names, "BISECT_NAMES")
e8861ffc 20static GIT_PATH_FUNC(git_path_bisect_first_parent, "BISECT_FIRST_PARENT")
ecb3f373 21
1bf072e3 22static const char * const git_bisect_helper_usage[] = {
5e82c3dd 23 N_("git bisect--helper --bisect-reset [<commit>]"),
0f30233a 24 N_("git bisect--helper --bisect-write [--no-log] <state> <revision> <good_term> <bad_term>"),
4fbdbd5b 25 N_("git bisect--helper --bisect-check-and-set-terms <command> <good_term> <bad_term>"),
129a6cf3 26 N_("git bisect--helper --bisect-next-check <good_term> <bad_term> [<term>]"),
450ebb73 27 N_("git bisect--helper --bisect-terms [--term-good | --term-old | --term-bad | --term-new]"),
ef4d9f8a 28 N_("git bisect--helper --bisect-start [--term-{new,bad}=<term> --term-{old,good}=<term>]"
e8861ffc 29 " [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<paths>...]"),
517ecb31
PB
30 N_("git bisect--helper --bisect-next"),
31 N_("git bisect--helper --bisect-auto-next"),
27257bc4
PB
32 N_("git bisect--helper --bisect-state (bad|new) [<rev>]"),
33 N_("git bisect--helper --bisect-state (good|old) [<rev>...]"),
1bf072e3
CC
34 NULL
35};
36
517ecb31
PB
37struct add_bisect_ref_data {
38 struct rev_info *revs;
39 unsigned int object_flags;
40};
41
0f30233a
PB
42struct bisect_terms {
43 char *term_good;
44 char *term_bad;
45};
46
47static void free_terms(struct bisect_terms *terms)
48{
49 FREE_AND_NULL(terms->term_good);
50 FREE_AND_NULL(terms->term_bad);
51}
52
53static 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
16538bfd
MR
62static const char vocab_bad[] = "bad|new";
63static const char vocab_good[] = "good|old";
129a6cf3 64
517ecb31
PB
65static int bisect_autostart(struct bisect_terms *terms);
66
4ba1e5c4
PB
67/*
68 * Check whether the string `term` belongs to the set of strings
69 * included in the variable arguments.
70 */
71LAST_ARG_MUST_BE_NULL
72static 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
88ad372f
PB
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
92static 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
7b4de74b
MR
99static 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
517ecb31 104 if (strcmp(mode, "w") && strcmp(mode, "a"))
7b4de74b
MR
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
121static 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
517ecb31
PB
133static 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
4ba1e5c4
PB
145static 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",
dbc349bb 157 "visualize", "view", "replay", "log", "run", "terms", NULL))
4ba1e5c4
PB
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
ecb3f373
PB
173static int write_terms(const char *bad, const char *good)
174{
ecb3f373
PB
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
7b4de74b 183 res = write_to_file(git_path_bisect_terms(), "%s\n%s\n", bad, good);
ecb3f373 184
7b4de74b 185 return res;
ecb3f373
PB
186}
187
5e82c3dd
PB
188static 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
de966e39 206 if (!ref_exists("BISECT_HEAD")) {
22f9b7f3 207 struct strvec argv = STRVEC_INIT;
5e82c3dd 208
22f9b7f3 209 strvec_pushl(&argv, "checkout", branch.buf, "--", NULL);
d70a9eb6 210 if (run_command_v_opt(argv.v, RUN_GIT_CMD)) {
51a0a4ed
TT
211 error(_("could not check out original"
212 " HEAD '%s'. Try 'git bisect"
213 " reset <commit>'."), branch.buf);
5e82c3dd 214 strbuf_release(&branch);
22f9b7f3 215 strvec_clear(&argv);
51a0a4ed 216 return -1;
5e82c3dd 217 }
22f9b7f3 218 strvec_clear(&argv);
5e82c3dd
PB
219 }
220
221 strbuf_release(&branch);
222 return bisect_clean_state();
223}
224
0f30233a
PB
225static 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
241static 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;
292731c4 248 int res = 0;
0f30233a
PB
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 {
292731c4 255 res = error(_("Bad bisect_write argument: %s"), state);
0f30233a
PB
256 goto finish;
257 }
258
259 if (get_oid(rev, &oid)) {
292731c4 260 res = error(_("couldn't get the oid of the rev '%s'"), rev);
0f30233a
PB
261 goto finish;
262 }
263
264 if (update_ref(NULL, tag.buf, &oid, NULL, 0,
265 UPDATE_REFS_MSG_ON_ERR)) {
292731c4 266 res = -1;
0f30233a
PB
267 goto finish;
268 }
269
270 fp = fopen(git_path_bisect_log(), "a");
271 if (!fp) {
292731c4 272 res = error_errno(_("couldn't open the file '%s'"), git_path_bisect_log());
0f30233a
PB
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
282finish:
283 if (fp)
284 fclose(fp);
285 strbuf_release(&tag);
292731c4 286 return res;
0f30233a
PB
287}
288
4fbdbd5b
PB
289static 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
129a6cf3
PB
316static 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
7c5cea72 324static const char need_bad_and_good_revision_warning[] =
129a6cf3
PB
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
7c5cea72 328static const char need_bisect_start_warning[] =
129a6cf3
PB
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
bfacfce7
TT
333static int decide_next(const struct bisect_terms *terms,
334 const char *current_term, int missing_good,
335 int missing_bad)
129a6cf3 336{
129a6cf3 337 if (!missing_good && !missing_bad)
bfacfce7
TT
338 return 0;
339 if (!current_term)
340 return -1;
129a6cf3
PB
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))
bfacfce7 351 return 0;
129a6cf3
PB
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"))
bfacfce7
TT
359 return -1;
360 return 0;
129a6cf3
PB
361 }
362
bfacfce7
TT
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
371static 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);
129a6cf3
PB
388}
389
450ebb73
PB
390static 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
408finish:
409 if (fp)
410 fclose(fp);
411 strbuf_release(&str);
412 return res;
413}
414
415static 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
06f5608c
PB
439static int bisect_append_log_quoted(const char **argv)
440{
292731c4 441 int res = 0;
06f5608c
PB
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) {
292731c4 449 res = -1;
06f5608c
PB
450 goto finish;
451 }
452
453 sq_quote_argv(&orig_args, argv);
454 if (fprintf(fp, "%s\n", orig_args.buf) < 1)
292731c4 455 res = -1;
06f5608c
PB
456
457finish:
458 fclose(fp);
459 strbuf_release(&orig_args);
292731c4 460 return res;
06f5608c
PB
461}
462
517ecb31
PB
463static 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
473static 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
505static 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
546static 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
568static 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
591static 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
88ad372f 599static enum bisect_error bisect_start(struct bisect_terms *terms, const char **argv, int argc)
06f5608c 600{
be5fe200 601 int no_checkout = 0;
e8861ffc 602 int first_parent_only = 0;
06f5608c 603 int i, has_double_dash = 0, must_write_terms = 0, bad_seen = 0;
88ad372f
PB
604 int flags, pathspec_pos;
605 enum bisect_error res = BISECT_OK;
06f5608c
PB
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;
e8861ffc
AL
633 } else if (!strcmp(arg, "--first-parent")) {
634 first_parent_only = 1;
06f5608c
PB
635 } else if (!strcmp(arg, "--term-good") ||
636 !strcmp(arg, "--term-old")) {
4d9005ff
CMAB
637 i++;
638 if (argc <= i)
639 return error(_("'' is not a valid term"));
06f5608c
PB
640 must_write_terms = 1;
641 free((void *) terms->term_good);
4d9005ff 642 terms->term_good = xstrdup(argv[i]);
06f5608c
PB
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")) {
4d9005ff
CMAB
650 i++;
651 if (argc <= i)
652 return error(_("'' is not a valid term"));
06f5608c
PB
653 must_write_terms = 1;
654 free((void *) terms->term_bad);
4d9005ff 655 terms->term_bad = xstrdup(argv[i]);
06f5608c
PB
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);
4d9005ff 661 } else if (starts_with(arg, "--")) {
06f5608c 662 return error(_("unrecognized option: '%s'"), arg);
73c6de06 663 } else if (!get_oidf(&oid, "%s^{commit}", arg)) {
06f5608c 664 string_list_append(&revs, oid_to_hex(&oid));
73c6de06
CC
665 } else if (has_double_dash) {
666 die(_("'%s' does not appear to be a valid "
667 "revision"), arg);
668 } else {
669 break;
06f5608c
PB
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) {
22f9b7f3 707 struct strvec argv = STRVEC_INIT;
06f5608c 708
22f9b7f3 709 strvec_pushl(&argv, "checkout", start_head.buf,
f6d8942b 710 "--", NULL);
d70a9eb6 711 if (run_command_v_opt(argv.v, RUN_GIT_CMD)) {
292731c4 712 res = error(_("checking out '%s' failed."
06f5608c
PB
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())
88ad372f 744 return BISECT_FAILED;
06f5608c
PB
745
746 /*
747 * Write new start state
748 */
749 write_file(git_path_bisect_start(), "%s\n", start_head.buf);
750
e8861ffc
AL
751 if (first_parent_only)
752 write_file(git_path_bisect_first_parent(), "\n");
753
06f5608c 754 if (no_checkout) {
7877ac3d 755 if (get_oid(start_head.buf, &oid) < 0) {
292731c4 756 res = error(_("invalid ref: '%s'"), start_head.buf);
7877ac3d
JS
757 goto finish;
758 }
06f5608c
PB
759 if (update_ref(NULL, "BISECT_HEAD", &oid, NULL, 0,
760 UPDATE_REFS_MSG_ON_ERR)) {
88ad372f 761 res = BISECT_FAILED;
06f5608c
PB
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)) {
88ad372f 773 res = BISECT_FAILED;
06f5608c
PB
774 goto finish;
775 }
776
777 if (must_write_terms && write_terms(terms->term_bad,
778 terms->term_good)) {
88ad372f 779 res = BISECT_FAILED;
06f5608c
PB
780 goto finish;
781 }
782
292731c4
TT
783 res = bisect_append_log_quoted(argv);
784 if (res)
88ad372f 785 res = BISECT_FAILED;
06f5608c
PB
786
787finish:
788 string_list_clear(&revs, 0);
789 string_list_clear(&states, 0);
790 strbuf_release(&start_head);
791 strbuf_release(&bisect_names);
88ad372f
PB
792 if (res)
793 return res;
794
795 res = bisect_auto_next(terms, NULL);
796 if (!is_bisect_success(res))
797 bisect_clean_state();
292731c4 798 return res;
06f5608c
PB
799}
800
09535f05
PB
801static inline int file_is_not_empty(const char *path)
802{
803 return !is_empty_or_missing_file(path);
804}
805
806static 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
27257bc4
PB
833static 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
1bf072e3
CC
907int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
908{
4ba1e5c4 909 enum {
5c517fe3 910 BISECT_RESET = 1,
4fbdbd5b 911 BISECT_WRITE,
129a6cf3 912 CHECK_AND_SET_TERMS,
450ebb73 913 BISECT_NEXT_CHECK,
06f5608c 914 BISECT_TERMS,
09535f05
PB
915 BISECT_START,
916 BISECT_AUTOSTART,
517ecb31 917 BISECT_NEXT,
27257bc4
PB
918 BISECT_AUTO_NEXT,
919 BISECT_STATE
4ba1e5c4 920 } cmdmode = 0;
be5fe200 921 int res = 0, nolog = 0;
1bf072e3 922 struct option options[] = {
5e82c3dd
PB
923 OPT_CMDMODE(0, "bisect-reset", &cmdmode,
924 N_("reset the bisection state"), BISECT_RESET),
0f30233a
PB
925 OPT_CMDMODE(0, "bisect-write", &cmdmode,
926 N_("write out the bisection state in BISECT_LOG"), BISECT_WRITE),
4fbdbd5b
PB
927 OPT_CMDMODE(0, "check-and-set-terms", &cmdmode,
928 N_("check and set terms in a bisection state"), CHECK_AND_SET_TERMS),
129a6cf3
PB
929 OPT_CMDMODE(0, "bisect-next-check", &cmdmode,
930 N_("check whether bad or good terms exist"), BISECT_NEXT_CHECK),
450ebb73
PB
931 OPT_CMDMODE(0, "bisect-terms", &cmdmode,
932 N_("print out the bisect terms"), BISECT_TERMS),
06f5608c
PB
933 OPT_CMDMODE(0, "bisect-start", &cmdmode,
934 N_("start the bisect session"), BISECT_START),
517ecb31
PB
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),
27257bc4
PB
939 OPT_CMDMODE(0, "bisect-state", &cmdmode,
940 N_("mark the state of ref (or refs)"), BISECT_STATE),
0f30233a 941 OPT_BOOL(0, "no-log", &nolog,
32ceace3 942 N_("no log for BISECT_WRITE")),
1bf072e3
CC
943 OPT_END()
944 };
0f30233a 945 struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
1bf072e3 946
37782920 947 argc = parse_options(argc, argv, prefix, options,
06f5608c
PB
948 git_bisect_helper_usage,
949 PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN);
1bf072e3 950
9e1c84df 951 if (!cmdmode)
1bf072e3
CC
952 usage_with_options(git_bisect_helper_usage, options);
953
9e1c84df 954 switch (cmdmode) {
5e82c3dd
PB
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);
0f30233a
PB
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;
4fbdbd5b
PB
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;
129a6cf3
PB
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;
450ebb73
PB
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;
06f5608c
PB
982 case BISECT_START:
983 set_terms(&terms, "bad", "good");
be5fe200 984 res = bisect_start(&terms, argv, argc);
06f5608c 985 break;
517ecb31
PB
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;
27257bc4 998 case BISECT_STATE:
09535f05 999 set_terms(&terms, "bad", "good");
27257bc4
PB
1000 get_terms(&terms);
1001 res = bisect_state(&terms, argv, argc);
09535f05 1002 break;
9e1c84df 1003 default:
ef5aef5e 1004 BUG("unknown subcommand %d", cmdmode);
9e1c84df 1005 }
0f30233a 1006 free_terms(&terms);
45b63708
PB
1007
1008 /*
1009 * Handle early success
1010 * From check_merge_bases > check_good_are_ancestors_of_bad > bisect_next_all
1011 */
517ecb31 1012 if ((res == BISECT_INTERNAL_SUCCESS_MERGE_BASE) || (res == BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND))
45b63708
PB
1013 res = BISECT_OK;
1014
30276765 1015 return -res;
1bf072e3 1016}