bisect--helper.c 26 KB

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