After three GSoC/Outreachy students spent an incredible effort on this, it is finally time to put a neat little bow on it, or maybe more like a big bow, maybe even a very large one, seeing as it takes quite a while to tie (half a year at the time of writing)... Changes since v4: * rebased onto sg/parse-options-subcommand * migrated to OPT_SUBCOMMAND(). * As a consequence, this patch series is now unfortunately very large. And the range-diff is much less useful than I'd like because of the extensive changes that were de facto made a precondition to moving this patch series further. Junio, I would have liked to keep the scope (and burden for the reviewers) substantially smaller, maybe you can help with the review? Changes since v3: * Rebased because of merge conflicts with ab/plug-leak-in-revisions. * Fixed the bug that git bisect --bisect-terms 1 2 wanted to auto-start a bisection if running with a git executable built at the in-between state at patch "bisect: move even the command-line parsing to bisect--helper". Since this bug was "fixed" in v3 by the very next patch, "bisect: teach the bisect--helper command to show the correct usage strings", v4 avoids introducing this bug simply by letting these two patches trade places. The range-diff admittedly looks quite awful because both patches overlap quite a bit in the lines they modify. The end result is the same, though, the diff between v3's and v4's builtin/bisect.c would be empty if I hadn't been forced to rebase. * Added a test case to ensure that this bug won't be introduced again. This test case is the only actual difference relative to v3 of this patch series. Changes since v2: * We're now careful to provide identical usage strings upon git bisect -h and git bisect bogus. * When a bogus command is provided, we now error out instead of trying to start a git bisect run. * Rebased onto main to avoid plenty of merge conflicts with rs/bisect-executable-not-found, ac/usage-string-fixups and with cd/bisect-messages-from-pre-flight-states. Changes since v1: * Added a regression test to "bisect run: fix the error message". * Added a patch to address an error message that double-single-quoted the command. * Reworked the logic in "bisect--helper: make --bisect-state optional" to delay showing the usage upon an unknown command, which should make the code a lot less confusing. * Split out the change that moved the BISECT_STATE case to the end of the switch block. * Added a patch that replaces the return error() calls in cmd_bisect_helper() with die() calls, to avoid returning -1 as an exit code. * Dropped the use of parse_options() for the single purpose of handling -h; This is now done explicitly. * Simplified the diff of "bisect: move even the option parsing to bisect--helper" by modifying argc and argv instead of modifying all the function calls using those variables. * In the "Turn git bisect into a full built-in" patch, changed the name of the variable holding the usage to use the builtin_ prefix used in other built-ins, too. * Removed the trailing dot from the commit message of "Turn git bisect into a full built-in". Johannes Schindelin (16): bisect--helper: retire the --no-log option bisect--helper: really retire --bisect-next-check bisect--helper: really retire `--bisect-autostart` bisect--helper: simplify exit code computation bisect--helper: make `terms` an explicit singleton bisect--helper: make the order consistently `argc, argv` bisect--helper: migrate to OPT_SUBCOMMAND() bisect: verify that a bogus option won't try to start a bisection bisect run: fix the error message bisect: avoid double-quoting when printing the failed command bisect--helper: calling `bisect_state()` without an argument is a bug bisect--helper: make `state` optional bisect: move even the command-line parsing to `bisect--helper` Turn `git bisect` into a full built-in bisect: remove Cogito-related code bisect: no longer try to clean up left-over `.git/head-name` files Makefile | 3 +- bisect.c | 3 - builtin.h | 2 +- builtin/{bisect--helper.c => bisect.c} | 679 ++++++++++++++----------- git-bisect.sh | 84 --- git.c | 2 +- t/t6030-bisect-porcelain.sh | 21 +- 7 files changed, 406 insertions(+), 388 deletions(-) rename builtin/{bisect--helper.c => bisect.c} (67%) delete mode 100755 git-bisect.sh base-commit: 8f9d80f6c06369b563c76ec46c462e740a1a2cf0 Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-1132%2Fdscho%2Fbisect-in-c-v5 Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1132/dscho/bisect-in-c-v5 Pull-Request: https://github.com/gitgitgadget/git/pull/1132 Range-diff vs v4: 4: 5bfaf0334c3 = 1: 05262b6a7d1 bisect--helper: retire the --no-log option 5: e85f236304b = 2: 1e43148864a bisect--helper: really retire --bisect-next-check 6: b94b7bb4fd0 = 3: 1a1649d9d0d bisect--helper: really retire `--bisect-autostart` -: ----------- > 4: 9ab30552c6a bisect--helper: simplify exit code computation -: ----------- > 5: 92b3b116ef8 bisect--helper: make `terms` an explicit singleton 11: ce508583e45 ! 6: c9dc0281e38 bisect--helper: return only correct exit codes in `cmd_*()` @@ Metadata Author: Johannes Schindelin <Johannes.Schindelin@xxxxxx> ## Commit message ## - bisect--helper: return only correct exit codes in `cmd_*()` + bisect--helper: make the order consistently `argc, argv` - Exit codes cannot be negative, but `error()` returns -1. + In C, the natural order is for `argc` to come before `argv` by virtue of + the `main()` function declaring the parameters in precisely that order. - Let's just go with the common pattern and call `die()` in - `cmd_bisect__helper()` when incorrect arguments were detected. + It is confusing & distracting, then, when readers familiar with the C + language read code where that order is switched around. + + Let's just change the order and avoid that type of developer friction. Signed-off-by: Johannes Schindelin <johannes.schindelin@xxxxxx> ## builtin/bisect--helper.c ## +@@ builtin/bisect--helper.c: static enum bisect_error bisect_auto_next(const char *prefix) + return bisect_next(prefix); + } + +-static enum bisect_error bisect_start(const char **argv, int argc) ++static enum bisect_error bisect_start(int argc, const char **argv) + { + int no_checkout = 0; + int first_parent_only = 0; +@@ builtin/bisect--helper.c: static int bisect_autostart(void) + yesno = git_prompt(_("Do you want me to do it for you " + "[Y/n]? "), PROMPT_ECHO); + res = tolower(*yesno) == 'n' ? +- -1 : bisect_start(empty_strvec, 0); ++ -1 : bisect_start(0, empty_strvec); + + return res; + } + +-static enum bisect_error bisect_state(const char **argv, +- int argc) ++static enum bisect_error bisect_state(int argc, const char **argv) + { + const char *state; + int i, verify_expected = 1; +@@ builtin/bisect--helper.c: static int process_replay_line(struct strbuf *line) + struct strvec argv = STRVEC_INIT; + int res; + sq_dequote_to_strvec(rev, &argv); +- res = bisect_start(argv.v, argv.nr); ++ res = bisect_start(argv.nr, argv.v); + strvec_clear(&argv); + return res; + } +@@ builtin/bisect--helper.c: static enum bisect_error bisect_replay(const char *filename) + return bisect_auto_next(NULL); + } + +-static enum bisect_error bisect_skip(const char **argv, int argc) ++static enum bisect_error bisect_skip(int argc, const char **argv) + { + int i; + enum bisect_error res; +@@ builtin/bisect--helper.c: static enum bisect_error bisect_skip(const char **argv, int argc) + strvec_push(&argv_state, argv[i]); + } + } +- res = bisect_state(argv_state.v, argv_state.nr); ++ res = bisect_state(argv_state.nr, argv_state.v); + + strvec_clear(&argv_state); + return res; + } + +-static int bisect_visualize(const char **argv, int argc) ++static int bisect_visualize(int argc, const char **argv) + { + struct strvec args = STRVEC_INIT; + int flags = RUN_COMMAND_NO_STDIN, res = 0; +@@ builtin/bisect--helper.c: static int verify_good(const char **quoted_argv) + return rc; + } + +-static int bisect_run(const char **argv, int argc) ++static int bisect_run(int argc, const char **argv) + { + int res = BISECT_OK; + struct strbuf command = STRBUF_INIT; +@@ builtin/bisect--helper.c: static int bisect_run(const char **argv, int argc) + saved_stdout = dup(1); + dup2(temporary_stdout_fd, 1); + +- res = bisect_state(&new_state, 1); ++ res = bisect_state(1, &new_state); + + fflush(stdout); + dup2(saved_stdout, 1); @@ builtin/bisect--helper.c: int cmd_bisect__helper(int argc, const char **argv, const char *prefix) break; - case BISECT_TERMS: - if (argc > 1) -- return error(_("--bisect-terms requires 0 or 1 argument")); -+ die(_("--bisect-terms requires 0 or 1 argument")); - res = bisect_terms(&terms, argc == 1 ? argv[0] : NULL); - break; - case BISECT_SKIP: -@@ builtin/bisect--helper.c: int cmd_bisect__helper(int argc, const char **argv, const char *prefix) + case BISECT_START: + set_terms("bad", "good"); +- res = bisect_start(argv, argc); ++ res = bisect_start(argc, argv); break; case BISECT_NEXT: if (argc) -- return error(_("--bisect-next requires 0 arguments")); -+ die(_("--bisect-next requires 0 arguments")); - get_terms(&terms); - res = bisect_next(&terms, prefix); - break; - case BISECT_RESET: - if (argc > 1) -- return error(_("--bisect-reset requires either no argument or a commit")); -+ die(_("--bisect-reset requires either no argument or a commit")); - res = bisect_reset(argc ? argv[0] : NULL); - break; - case BISECT_VISUALIZE: @@ builtin/bisect--helper.c: int cmd_bisect__helper(int argc, const char **argv, const char *prefix) - break; - case BISECT_REPLAY: - if (argc != 1) -- return error(_("no logfile given")); -+ die(_("no logfile given")); - set_terms(&terms, "bad", "good"); - res = bisect_replay(&terms, argv[0]); + case BISECT_STATE: + set_terms("bad", "good"); + get_terms(); +- res = bisect_state(argv, argc); ++ res = bisect_state(argc, argv); break; case BISECT_LOG: if (argc) -- return error(_("--bisect-log requires 0 arguments")); -+ die(_("--bisect-log requires 0 arguments")); - res = bisect_log(); +@@ builtin/bisect--helper.c: int cmd_bisect__helper(int argc, const char **argv, const char *prefix) + case BISECT_SKIP: + set_terms("bad", "good"); + get_terms(); +- res = bisect_skip(argv, argc); ++ res = bisect_skip(argc, argv); + break; + case BISECT_VISUALIZE: + get_terms(); +- res = bisect_visualize(argv, argc); ++ res = bisect_visualize(argc, argv); break; case BISECT_RUN: if (!argc) -- return error(_("bisect run failed: no command provided.")); -+ die(_("bisect run failed: no command provided.")); - get_terms(&terms); - res = bisect_run(&terms, argv, argc); + return error(_("bisect run failed: no command provided.")); + get_terms(); +- res = bisect_run(argv, argc); ++ res = bisect_run(argc, argv); break; + default: + BUG("unknown subcommand %d", cmdmode); -: ----------- > 7: 5b7a3d58b4f bisect--helper: migrate to OPT_SUBCOMMAND() 1: 30ddbd7affc = 8: ba537af7066 bisect: verify that a bogus option won't try to start a bisection 2: 97dd2da8f89 ! 9: 409492ad830 bisect run: fix the error message @@ Commit message Signed-off-by: Johannes Schindelin <johannes.schindelin@xxxxxx> ## builtin/bisect--helper.c ## -@@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, const char **argv, int argc) +@@ builtin/bisect--helper.c: static int cmd_bisect_run(int argc, const char **argv, const char *prefix) printf(_("bisect found first bad commit")); res = BISECT_OK; } else if (res) { 3: 5571e0f76ff ! 10: bc5efc8fbfe bisect: avoid double-quoting when printing the failed command @@ Commit message Signed-off-by: Johannes Schindelin <johannes.schindelin@xxxxxx> ## builtin/bisect--helper.c ## -@@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, const char **argv, int argc) +@@ builtin/bisect--helper.c: static int cmd_bisect_run(int argc, const char **argv, const char *prefix) if (res < 0 || 128 <= res) { error(_("bisect run failed: exit code %d from" 7: aad3c9a0850 ! 11: 8a0adfe3867 bisect--helper: using `--bisect-state` without an argument is a bug @@ Metadata Author: Johannes Schindelin <Johannes.Schindelin@xxxxxx> ## Commit message ## - bisect--helper: using `--bisect-state` without an argument is a bug + bisect--helper: calling `bisect_state()` without an argument is a bug - The `bisect--helper` command is not expected to be used directly by the - user. Therefore, it is a bug if it receives no argument to the - `--bisect-state` command mode, not a user error. Which means that we - need to call `BUG()` instead of `die()`. + The `bisect_state()` function is now a purely internal function and must + be called with a valid state, everything else is a bug. Signed-off-by: Johannes Schindelin <johannes.schindelin@xxxxxx> ## builtin/bisect--helper.c ## -@@ builtin/bisect--helper.c: static enum bisect_error bisect_state(struct bisect_terms *terms, const char **a +@@ builtin/bisect--helper.c: static enum bisect_error bisect_state(int argc, const char **argv, + struct strbuf buf = STRBUF_INIT; struct oid_array revs = OID_ARRAY_INIT; - if (!argc) -- return error(_("Please call `--bisect-state` with at least one argument")); ++ if (!argc) + BUG("bisect_state() called without argument"); - if (bisect_autostart(terms)) + if (bisect_autostart(prefix)) return BISECT_FAILED; 8: 375a46dca9f < -: ----------- bisect--helper: align the sub-command order with git-bisect.sh 9: c57f63f6a61 ! 12: 189d2b3ba46 bisect--helper: make `--bisect-state` optional @@ Metadata Author: Johannes Schindelin <Johannes.Schindelin@xxxxxx> ## Commit message ## - bisect--helper: make `--bisect-state` optional + bisect--helper: make `state` optional In preparation for making `git bisect` a real built-in, let's prepare the `bisect--helper` built-in to handle `git bisect--helper good` and - `git bisect--helper bad`, i.e. do not require the `--bisect-state` - option to be passed explicitly. + `git bisect--helper bad`, i.e. do not require the `state` subcommand to + be passed explicitly. Signed-off-by: Johannes Schindelin <johannes.schindelin@xxxxxx> ## builtin/bisect--helper.c ## -@@ builtin/bisect--helper.c: static const char * const git_bisect_helper_usage[] = { - N_("git bisect--helper --bisect-start [--term-{new,bad}=<term> --term-{old,good}=<term>]" - " [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<paths>...]"), - "git bisect--helper --bisect-next", -- N_("git bisect--helper --bisect-state (bad|new) [<rev>]"), -- N_("git bisect--helper --bisect-state (good|old) [<rev>...]"), -+ N_("git bisect--helper [--bisect-state] (bad|new) [<rev>]"), -+ N_("git bisect--helper [--bisect-state] (good|old) [<rev>...]"), - N_("git bisect--helper --bisect-replay <filename>"), - N_("git bisect--helper --bisect-skip [(<rev>|<range>)...]"), - "git bisect--helper --bisect-visualize", -@@ builtin/bisect--helper.c: int cmd_bisect__helper(int argc, const char **argv, const char *prefix) - git_bisect_helper_usage, - PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN); +@@ builtin/bisect--helper.c: static int cmd_bisect_run(int argc, const char **argv, const char *prefix) -- if (!cmdmode) -- usage_with_options(git_bisect_helper_usage, options); -- -- switch (cmdmode) { -+ switch (cmdmode ? cmdmode : BISECT_STATE) { - case BISECT_START: - set_terms(&terms, "bad", "good"); - res = bisect_start(&terms, argv, argc); + int cmd_bisect__helper(int argc, const char **argv, const char *prefix) + { ++ struct strvec args = STRVEC_INIT; + parse_opt_subcommand_fn *fn = NULL; + int res = 0; + struct option options[] = { @@ builtin/bisect--helper.c: int cmd_bisect__helper(int argc, const char **argv, const char *prefix) - case BISECT_STATE: - set_terms(&terms, "bad", "good"); - get_terms(&terms); -+ if (!cmdmode && -+ (!argc || check_and_set_terms(&terms, argv[0]))) { -+ char *msg = xstrfmt(_("unknown command: '%s'"), argv[0]); -+ usage_msg_opt(msg, git_bisect_helper_usage, options); -+ } - res = bisect_state(&terms, argv, argc); - break; - case BISECT_TERMS: + }; + + argc = parse_options(argc, argv, prefix, options, +- bisect_usage, 0); ++ bisect_usage, PARSE_OPT_SUBCOMMAND_OPTIONAL); ++ ++ if (!fn) { ++ if (!argc) ++ usage_msg_opt(_("need a command"), bisect_usage, ++ options); ++ ++ set_terms("bad", "good"); ++ get_terms(); ++ if (check_and_set_terms(argv[0])) ++ usage_msg_optf(_("unknown command: '%s'"), bisect_usage, ++ options, argv[0]); ++ ++ strvec_push(&args, "state"); ++ strvec_pushv(&args, argv); ++ argc = args.nr; ++ argv = args.v; ++ fn = cmd_bisect_state; ++ } + + res = fn(argc, argv, prefix); + free_terms(); ++ strvec_clear(&args); + + return is_bisect_success(res) ? 0 : -res; + } ## git-bisect.sh ## @@ git-bisect.sh: case "$#" in start) - git bisect--helper --bisect-start "$@" ;; + git bisect--helper start "$@" ;; bad|good|new|old|"$TERM_BAD"|"$TERM_GOOD") -- git bisect--helper --bisect-state "$cmd" "$@" ;; +- git bisect--helper state "$cmd" "$@" ;; + git bisect--helper "$cmd" "$@" ;; skip) - git bisect--helper --bisect-skip "$@" || exit;; + git bisect--helper skip "$@" || exit;; next) 10: 87f53469a72 < -: ----------- bisect--helper: move the `BISECT_STATE` case to the end 12: 5dbe233e4ec < -: ----------- bisect: teach the `bisect--helper` command to show the correct usage strings 13: d56f2a14060 ! 13: 32bf74e3050 bisect: move even the command-line parsing to `bisect--helper` @@ Commit message On our journey to a fully built-in `git bisect`, this is the last step. - Side note: The `parse-options` API is not at all set up to parse - subcommands such as `git bisect start`, `git bisect reset`, etc. - Instead of fighting an up-hill battle trying to "fix" that, we simply - roll the same type of manual subcommand parsing as we already do e.g. - in `builtin/bundle.c`. - Signed-off-by: Johannes Schindelin <johannes.schindelin@xxxxxx> ## builtin/bisect--helper.c ## -@@ builtin/bisect--helper.c: static const char *bisect_usage = - N_("git bisect [help|start|bad|good|new|old|terms|skip|next|reset|" - "visualize|view|replay|log|run]"); - --static const char * const bisect_long_usage[] = { -+static const char *bisect_long_usage = - N_("git bisect [help|start|bad|good|new|old|terms|skip|next|reset|" - "visualize|view|replay|log|run]\n" - "\n" -@@ builtin/bisect--helper.c: static const char * const bisect_long_usage[] = { - "git bisect run <cmd>...\n" - "\tuse <cmd>... to automatically bisect.\n" - "\n" -- "Please use \"git help bisect\" to get the full man page."), -- NULL --}; -+ "Please use \"git help bisect\" to get the full man page."); - - struct add_bisect_ref_data { - struct rev_info *revs; -@@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, const char **argv, int argc) - - int cmd_bisect__helper(int argc, const char **argv, const char *prefix) - { -- enum { -- BISECT_START = 1, -- BISECT_STATE, -- BISECT_TERMS, -- BISECT_SKIP, -- BISECT_NEXT, -- BISECT_RESET, -- BISECT_VISUALIZE, -- BISECT_REPLAY, -- BISECT_LOG, -- BISECT_RUN, -- } cmdmode = 0; - int res = 0; -- struct option options[] = { -- OPT_CMDMODE(0, "bisect-start", &cmdmode, -- N_("start the bisect session"), BISECT_START), -- OPT_CMDMODE(0, "bisect-state", &cmdmode, -- N_("mark the state of ref (or refs)"), BISECT_STATE), -- OPT_CMDMODE(0, "bisect-terms", &cmdmode, -- N_("print out the bisect terms"), BISECT_TERMS), -- OPT_CMDMODE(0, "bisect-skip", &cmdmode, -- N_("skip some commits for checkout"), BISECT_SKIP), -- OPT_CMDMODE(0, "bisect-next", &cmdmode, -- N_("find the next bisection commit"), BISECT_NEXT), -- OPT_CMDMODE(0, "bisect-reset", &cmdmode, -- N_("reset the bisection state"), BISECT_RESET), -- OPT_CMDMODE(0, "bisect-visualize", &cmdmode, -- N_("visualize the bisection"), BISECT_VISUALIZE), -- OPT_CMDMODE(0, "bisect-replay", &cmdmode, -- N_("replay the bisection process from the given file"), BISECT_REPLAY), -- OPT_CMDMODE(0, "bisect-log", &cmdmode, -- N_("list the bisection steps so far"), BISECT_LOG), -- OPT_CMDMODE(0, "bisect-run", &cmdmode, -- N_("use <cmd>... to automatically bisect"), BISECT_RUN), -- OPT_END() -- }; - struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL }; -+ const char *command = argc > 1 ? argv[1] : "help"; -+ -+ if (!strcmp("-h", command) || !strcmp("help", command)) -+ usage(bisect_long_usage); - -- argc = parse_options(argc, argv, prefix, options, -- bisect_long_usage, -- PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN); -+ argc -= 2; -+ argv += 2; - -- switch (cmdmode ? cmdmode : BISECT_STATE) { -- case BISECT_START: -+ if (!strcmp("start", command)) { - set_terms(&terms, "bad", "good"); - res = bisect_start(&terms, argv, argc); -- break; -- case BISECT_TERMS: -+ } else if (!strcmp("terms", command)) { - if (argc > 1) -- die(_("--bisect-terms requires 0 or 1 argument")); -+ die(_("'terms' requires 0 or 1 argument")); - res = bisect_terms(&terms, argc == 1 ? argv[0] : NULL); -- break; -- case BISECT_SKIP: -+ } else if (!strcmp("skip", command)) { - set_terms(&terms, "bad", "good"); - get_terms(&terms); - res = bisect_skip(&terms, argv, argc); -- break; -- case BISECT_NEXT: -+ } else if (!strcmp("next", command)) { - if (argc) -- die(_("--bisect-next requires 0 arguments")); -+ die(_("'next' requires 0 arguments")); - get_terms(&terms); - res = bisect_next(&terms, prefix); -- break; -- case BISECT_RESET: -+ } else if (!strcmp("reset", command)) { - if (argc > 1) -- die(_("--bisect-reset requires either no argument or a commit")); -+ die(_("'reset' requires either no argument or a commit")); - res = bisect_reset(argc ? argv[0] : NULL); -- break; -- case BISECT_VISUALIZE: -+ } else if (one_of(command, "visualize", "view", NULL)) { - get_terms(&terms); - res = bisect_visualize(&terms, argv, argc); -- break; -- case BISECT_REPLAY: -+ } else if (!strcmp("replay", command)) { - if (argc != 1) - die(_("no logfile given")); - set_terms(&terms, "bad", "good"); - res = bisect_replay(&terms, argv[0]); -- break; -- case BISECT_LOG: -+ } else if (!strcmp("log", command)) { - if (argc) -- die(_("--bisect-log requires 0 arguments")); -+ die(_("'log' requires 0 arguments")); - res = bisect_log(); -- break; -- case BISECT_RUN: -+ } else if (!strcmp("run", command)) { - if (!argc) - die(_("bisect run failed: no command provided.")); - get_terms(&terms); - res = bisect_run(&terms, argv, argc); -- break; -- case BISECT_STATE: -- if (argc && -- !file_is_not_empty(git_path_bisect_start()) && -- !one_of(argv[0], "bad", "good", "new", "old", NULL)) -+ } else { -+ if (!file_is_not_empty(git_path_bisect_start()) && -+ !one_of(command, "bad", "good", "new", "old", NULL)) - usage(bisect_usage); - set_terms(&terms, "bad", "good"); - get_terms(&terms); -- if (!cmdmode && -- (!argc || check_and_set_terms(&terms, argv[0]))) -+ if (check_and_set_terms(&terms, command)) - usage(bisect_usage); -+ /* shift the `command` back in */ -+ argc++; -+ argv--; - res = bisect_state(&terms, argv, argc); -- break; -- default: -- BUG("unknown subcommand %d", cmdmode); - } -+ - free_terms(&terms); - - /* +@@ builtin/bisect--helper.c: int cmd_bisect__helper(int argc, const char **argv, const char *prefix) + OPT_SUBCOMMAND("terms", &fn, cmd_bisect_terms), + OPT_SUBCOMMAND("start", &fn, cmd_bisect_start), + OPT_SUBCOMMAND("next", &fn, cmd_bisect_next), +- OPT_SUBCOMMAND("state", &fn, cmd_bisect_state), + OPT_SUBCOMMAND("log", &fn, cmd_bisect_log), + OPT_SUBCOMMAND("replay", &fn, cmd_bisect_replay), + OPT_SUBCOMMAND("skip", &fn, cmd_bisect_skip), ## git-bisect.sh ## @@ git-bisect.sh: Please use "git help bisect" to get the full man page.' @@ git-bisect.sh: Please use "git help bisect" to get the full man page.' - help) - git bisect -h ;; - start) -- git bisect--helper --bisect-start "$@" ;; +- git bisect--helper start "$@" ;; - bad|good|new|old|"$TERM_BAD"|"$TERM_GOOD") - git bisect--helper "$cmd" "$@" ;; - skip) -- git bisect--helper --bisect-skip "$@" || exit;; +- git bisect--helper skip "$@" || exit;; - next) - # Not sure we want "next" at the UI level anymore. -- git bisect--helper --bisect-next "$@" || exit ;; +- git bisect--helper next "$@" || exit ;; - visualize|view) -- git bisect--helper --bisect-visualize "$@" || exit;; +- git bisect--helper visualize "$@" || exit;; - reset) -- git bisect--helper --bisect-reset "$@" ;; +- git bisect--helper reset "$@" ;; - replay) -- git bisect--helper --bisect-replay "$@" || exit;; +- git bisect--helper replay "$@" || exit;; - log) -- git bisect--helper --bisect-log || exit ;; +- git bisect--helper log || exit ;; - run) -- git bisect--helper --bisect-run "$@" || exit;; +- git bisect--helper run "$@" || exit;; - terms) -- git bisect--helper --bisect-terms "$@" || exit;; +- git bisect--helper terms "$@" || exit;; - *) - usage ;; - esac 14: 378d6d22737 ! 14: a8f08f5e0cb Turn `git bisect` into a full built-in @@ builtin.h: int cmd_am(int argc, const char **argv, const char *prefix); int cmd_bugreport(int argc, const char **argv, const char *prefix); ## builtin/bisect--helper.c => builtin/bisect.c ## -@@ builtin/bisect.c: static int bisect_run(struct bisect_terms *terms, const char **argv, int argc) +@@ builtin/bisect.c: static int cmd_bisect_run(int argc, const char **argv, const char *prefix) return res; } -int cmd_bisect__helper(int argc, const char **argv, const char *prefix) +int cmd_bisect(int argc, const char **argv, const char *prefix) { - int res = 0; - struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL }; + struct strvec args = STRVEC_INIT; + parse_opt_subcommand_fn *fn = NULL; ## git-bisect.sh (deleted) ## @@ @@ git-bisect.sh (deleted) ## git.c ## @@ git.c: static struct cmd_struct commands[] = { - { "annotate", cmd_annotate, RUN_SETUP | NO_PARSEOPT }, + { "annotate", cmd_annotate, RUN_SETUP }, { "apply", cmd_apply, RUN_SETUP_GENTLY }, { "archive", cmd_archive, RUN_SETUP_GENTLY }, - { "bisect--helper", cmd_bisect__helper, RUN_SETUP }, 15: 33566b86d77 ! 15: a96489310d3 bisect: remove Cogito-related code @@ builtin/bisect.c: static GIT_PATH_FUNC(git_path_bisect_expected_rev, "BISECT_EXP static GIT_PATH_FUNC(git_path_bisect_names, "BISECT_NAMES") static GIT_PATH_FUNC(git_path_bisect_first_parent, "BISECT_FIRST_PARENT") static GIT_PATH_FUNC(git_path_bisect_run, "BISECT_RUN") -@@ builtin/bisect.c: static enum bisect_error bisect_start(struct bisect_terms *terms, const char **a +@@ builtin/bisect.c: static int cmd_bisect_start(int argc, const char **argv, const char *prefix) strbuf_addstr(&start_head, oid_to_hex(&head_oid)); } else if (!get_oid(head, &head_oid) && skip_prefix(head, "refs/heads/", &head)) { 16: 334664f23a8 = 16: bfa7aa19f03 bisect: no longer try to clean up left-over `.git/head-name` files -- gitgitgadget