{"thread":{"id":"58746","subject":"\"git bisect run\" strips \"--log\" from the list of arguments","startedAt":"2022-11-04T06:32:31Z","lastAt":"2022-11-15T19:40:26Z","messageCount":106,"participants":["Lukáš Doktor","Jeff King","Đoàn Trần Công Danh","Ævar Arnfjörð Bjarmason","SZEDER Gábor","Taylor Blau","René Scharfe","Phillip Wood","Johannes Schindelin"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"466492","messageId":"1cb1c033-0525-7e62-8c09-81019bf26060@redhat.com","threadId":"58746","inReplyTo":null,"subject":"\"git bisect run\" strips \"--log\" from the list of arguments","fromName":"Lukáš Doktor","fromEmail":"ldoktor@redhat.com","sentAt":"2022-11-04T06:31:26Z","receivedAt":"2022-11-04T06:32:31Z","isPatch":false,"sender":{"key":"ldoktor@redhat.com","avatar":null},"body":"Hello folks,\n\nrecently I noticed a change of behavior in \"git bisect run\" and since git-2.34.1-1.fc35.x86_64 it's stripping \"--log\" arguments of my to-be-executed script.\n\nSteps to Reproduce:\n\n1. git bisect start BAD GOOD\n2. git bisect run ./myscript arg1 --log arg2 --log -- arg3 --log arg4\n\nResults with 2.34.1:\n\n    running  './myscript' 'arg1' 'arg2' '--' 'arg3' '--log' 'arg4'\n\nResults with 2.33.0:\n\n    running ./myscript arg1 --log arg2 --log -- arg3 --log arg4\n\nIs this expected? In https://bugzilla.redhat.com/show_bug.cgi?id=2139883 Todd suggested it might be related to\n\n    d1bbbe45df (bisect--helper: reimplement `bisect_run` shell function in C, 2021-09-13) \n\nbut I haven't tried it myself.\n\nRegards,\nLukáš"},{"id":"466494","messageId":"Y2TfUFkLUa2tHdS7@coredump.intra.peff.net","threadId":"58746","inReplyTo":"1cb1c033-0525-7e62-8c09-81019bf26060@redhat.com","subject":"Re: \"git bisect run\" strips \"--log\" from the list of arguments","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2022-11-04T09:45:52Z","receivedAt":"2022-11-04T09:45:59Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Fri, Nov 04, 2022 at 07:31:26AM +0100, Lukáš Doktor wrote:\n\n> Steps to Reproduce:\n> \n> 1. git bisect start BAD GOOD\n> 2. git bisect run ./myscript arg1 --log arg2 --log -- arg3 --log arg4\n> \n> Results with 2.34.1:\n> \n>     running  './myscript' 'arg1' 'arg2' '--' 'arg3' '--log' 'arg4'\n> \n> Results with 2.33.0:\n> \n>     running ./myscript arg1 --log arg2 --log -- arg3 --log arg4\n\nThanks for an easy reproduction recipe. I used this as an easy-to-see\ntest case, which works in any repo:\n\n  git bisect start HEAD HEAD~2 >/dev/null 2>&1\n  git bisect bisect run echo --log 2>&1 | grep running\n\n> Is this expected? In https://bugzilla.redhat.com/show_bug.cgi?id=2139883 Todd suggested it might be related to\n> \n>     d1bbbe45df (bisect--helper: reimplement `bisect_run` shell function in C, 2021-09-13) \n> \n> but I haven't tried it myself.\n\nYes, it bisects to that commit. +cc Christian, who mentored this gsoc\nproject.\n\nI think the problem is that we are now feeding the arguments to\nparse_options() in git bisect--helper, and it doesn't realize that it\nneeds to stop after seeing that we are in \"run\" mode.  And because\n\"--log\" is an option to git-bisect--helper (it is the opposite of\n\"--no-log\"), it is consumed there.\n\nAs you noticed, the \"--\" stops parsing, so the one between \"arg3\" and\n\"arg4\" is preserved.\n\nIt feels like the invocation of bisect--helper ought to be passing \"--\"\nitself to indicate the end of options, like:\n\ndiff --git a/git-bisect.sh b/git-bisect.sh\nindex 405cf76f2a..bd69e8d389 100755\n--- a/git-bisect.sh\n+++ b/git-bisect.sh\n@@ -75,7 +75,7 @@ case \"$#\" in\n \tlog)\n \t\tgit bisect--helper --bisect-log || exit ;;\n \trun)\n-\t\tgit bisect--helper --bisect-run \"$@\" || exit;;\n+\t\tgit bisect--helper --bisect-run -- \"$@\" || exit;;\n \tterms)\n \t\tgit bisect--helper --bisect-terms \"$@\" || exit;;\n \t*)\n\nbut there are two oddities:\n\n  1. We use PARSE_OPT_KEEP_DASHDASH, so it ends up in the final command.\n     We might be able to drop that; it goes back to 06f5608c14\n     (bisect--helper: `bisect_start` shell function partially in C,\n     2019-01-02), but I'm not sure which other modes might be relying on\n     it.\n\n  2. We are forwarding \"$@\" from the user. I'm not sure if they would\n     ever use \"--\" themselves to signal end of options. We might be OK\n     because \"bisect run\" does not take any other options (as far as I\n     know), so nobody would ever need to do that. I.e., I don't think\n     anybody would do:\n\n       git bisect run -- mycommand\n\n     because it will treat the \"--\" literally as a command name.\n\nSo we could possibly just add it in the script as above, and then\nunconditionally eat it in the C program. I.e., add this hunk:\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 28ef7ec2a4..2d6c77df2e 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1377,6 +1377,11 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\tres = bisect_visualize(&terms, argv, argc);\n \t\tbreak;\n \tcase BISECT_RUN:\n+\t\t/* consume \"--\" added by git-bisect.sh, but left by parse-options */\n+\t\tif (argc) {\n+\t\t\targc--;\n+\t\t\targv++;\n+\t\t}\n \t\tif (!argc)\n \t\t\treturn error(_(\"bisect run failed: no command provided.\"));\n \t\tget_terms(&terms);\n\nIt feels a bit hacky, but I think it would work, and there's no\npossibility of disrupting the other modes.\n\nThe other option is probably an elaborate parse-options callback, like\nthe diff below. But it's pretty horrible, too.\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 28ef7ec2a4..16f71fd59c 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1277,22 +1277,49 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n \treturn res;\n }\n \n+enum bisect_cmdmode {\n+\tBISECT_RESET = 1,\n+\tBISECT_NEXT_CHECK,\n+\tBISECT_TERMS,\n+\tBISECT_START,\n+\tBISECT_AUTOSTART,\n+\tBISECT_NEXT,\n+\tBISECT_STATE,\n+\tBISECT_LOG,\n+\tBISECT_REPLAY,\n+\tBISECT_SKIP,\n+\tBISECT_VISUALIZE,\n+\tBISECT_RUN,\n+};\n+\n+static int run_argc;\n+static const char **run_argv;\n+\n+static int parse_opt_bisect_run(struct parse_opt_ctx_t *ctx,\n+\t\t\t\tconst struct option *opt,\n+\t\t\t\tconst char *arg, int unset)\n+{\n+\tenum bisect_cmdmode *cmdmode = opt->value;\n+\n+\tBUG_ON_OPT_ARG(arg);\n+\tBUG_ON_OPT_NEG(unset);\n+\n+\t*cmdmode = BISECT_RUN;\n+\t/*\n+\t * Yuck, parse-options has no way to say \"done, and stop parsing\";\n+\t * it will keep going if we still have any argc left. So we have to\n+\t * stash the rest of the options ourselves.\n+\t */\n+\trun_argc = ctx->argc - 1;\n+\trun_argv = ctx->argv + 1;\n+\tctx->argc = 1;\n+\n+\treturn 0;\n+}\n+\n int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n {\n-\tenum {\n-\t\tBISECT_RESET = 1,\n-\t\tBISECT_NEXT_CHECK,\n-\t\tBISECT_TERMS,\n-\t\tBISECT_START,\n-\t\tBISECT_AUTOSTART,\n-\t\tBISECT_NEXT,\n-\t\tBISECT_STATE,\n-\t\tBISECT_LOG,\n-\t\tBISECT_REPLAY,\n-\t\tBISECT_SKIP,\n-\t\tBISECT_VISUALIZE,\n-\t\tBISECT_RUN,\n-\t} cmdmode = 0;\n+\tenum bisect_cmdmode cmdmode = 0;\n \tint res = 0, nolog = 0;\n \tstruct option options[] = {\n \t\tOPT_CMDMODE(0, \"bisect-reset\", &cmdmode,\n@@ -1315,8 +1342,10 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\t\t N_(\"skip some commits for checkout\"), BISECT_SKIP),\n \t\tOPT_CMDMODE(0, \"bisect-visualize\", &cmdmode,\n \t\t\t N_(\"visualize the bisection\"), BISECT_VISUALIZE),\n-\t\tOPT_CMDMODE(0, \"bisect-run\", &cmdmode,\n-\t\t\t N_(\"use <cmd>... to automatically bisect\"), BISECT_RUN),\n+\t\t{OPTION_LOWLEVEL_CALLBACK, 0, \"bisect-run\", &cmdmode, NULL,\n+\t\t\t N_(\"use <cmd>... to automatically bisect\"),\n+\t\t\t PARSE_OPT_NOARG|PARSE_OPT_NONEG,\n+\t\t\t NULL, 0, parse_opt_bisect_run},\n \t\tOPT_BOOL(0, \"no-log\", &nolog,\n \t\t\t N_(\"no log for BISECT_WRITE\")),\n \t\tOPT_END()\n@@ -1377,10 +1406,10 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\tres = bisect_visualize(&terms, argv, argc);\n \t\tbreak;\n \tcase BISECT_RUN:\n-\t\tif (!argc)\n+\t\tif (!run_argc)\n \t\t\treturn error(_(\"bisect run failed: no command provided.\"));\n \t\tget_terms(&terms);\n-\t\tres = bisect_run(&terms, argv, argc);\n+\t\tres = bisect_run(&terms, run_argv, run_argc);\n \t\tbreak;\n \tdefault:\n \t\tBUG(\"unknown subcommand %d\", cmdmode);\n\n-Peff\n"},{"id":"466497","messageId":"Y2Ty6KZT8iACqHf+@danh.dev","threadId":"58746","inReplyTo":"Y2TfUFkLUa2tHdS7@coredump.intra.peff.net","subject":"Re: \"git bisect run\" strips \"--log\" from the list of arguments","fromName":"Đoàn Trần Công Danh","fromEmail":"congdanhqx@gmail.com","sentAt":"2022-11-04T11:10:02Z","receivedAt":"2022-11-04T11:10:10Z","isPatch":false,"sender":{"key":"congdanhqx@gmail.com","avatar":"https://avatars.githubusercontent.com/u/42673067?v=4"},"body":"On 2022-11-04 05:45:52-0400, Jeff King <peff@peff.net> wrote:\n> On Fri, Nov 04, 2022 at 07:31:26AM +0100, Lukáš Doktor wrote:\n> \n> > Steps to Reproduce:\n> > \n> > 1. git bisect start BAD GOOD\n> > 2. git bisect run ./myscript arg1 --log arg2 --log -- arg3 --log arg4\n> > \n> > Results with 2.34.1:\n> > \n> >     running  './myscript' 'arg1' 'arg2' '--' 'arg3' '--log' 'arg4'\n> > \n> > Results with 2.33.0:\n> > \n> >     running ./myscript arg1 --log arg2 --log -- arg3 --log arg4\n> \n> Thanks for an easy reproduction recipe. I used this as an easy-to-see\n> test case, which works in any repo:\n> \n>   git bisect start HEAD HEAD~2 >/dev/null 2>&1\n>   git bisect bisect run echo --log 2>&1 | grep running\n> \n> > Is this expected? In https://bugzilla.redhat.com/show_bug.cgi?id=2139883 Todd suggested it might be related to\n> > \n> >     d1bbbe45df (bisect--helper: reimplement `bisect_run` shell function in C, 2021-09-13) \n> > \n> > but I haven't tried it myself.\n> \n> Yes, it bisects to that commit. +cc Christian, who mentored this gsoc\n> project.\n> \n> I think the problem is that we are now feeding the arguments to\n> parse_options() in git bisect--helper, and it doesn't realize that it\n> needs to stop after seeing that we are in \"run\" mode.  And because\n> \"--log\" is an option to git-bisect--helper (it is the opposite of\n> \"--no-log\"), it is consumed there.\n> \n> As you noticed, the \"--\" stops parsing, so the one between \"arg3\" and\n> \"arg4\" is preserved.\n> \n> It feels like the invocation of bisect--helper ought to be passing \"--\"\n> itself to indicate the end of options, like:\n\nI think we should use OPT_SUBCOMMAND to parse bisect--helper\nsubcommand instead, which would pave ways for easier converting to\nbuilt-int git-bisect. This huge patch, which could be splited into\n2 patches can fix the problem:\n---- 8< ----\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 1d2ce8a0e1..fe8aea7240 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1279,115 +1279,119 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n \treturn res;\n }\n \n+static int cmd_bisect__reset(int argc, const char **argv, const char *prefix UNUSED)\n+{\n+\tif (argc > 1)\n+\t\treturn error(_(\"--bisect-reset requires either no argument or a commit\"));\n+\treturn bisect_reset(argc ? argv[0] : NULL);\n+}\n+\n+static int cmd_bisect__terms(int argc, const char **argv, const char *prefix UNUSED)\n+{\n+\tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\n+\n+\tif (argc > 1)\n+\t\treturn error(_(\"--bisect-terms requires 0 or 1 argument\"));\n+\treturn bisect_terms(&terms, argc == 1 ? argv[0] : NULL);\n+}\n+\n+static int cmd_bisect__start(int argc, const char **argv, const char *prefix UNUSED)\n+{\n+\tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\n+\n+\tset_terms(&terms, \"bad\", \"good\");\n+\treturn bisect_start(&terms, argv, argc);\n+}\n+\n+static int cmd_bisect__next(int argc, const char **argv UNUSED, const char *prefix)\n+{\n+\tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\n+\n+\tif (argc)\n+\t\treturn error(_(\"--bisect-next requires 0 arguments\"));\n+\tget_terms(&terms);\n+\treturn bisect_next(&terms, prefix);\n+}\n+\n+static int cmd_bisect__state(int argc, const char **argv, const char *prefix UNUSED)\n+{\n+\tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\n+\n+\tset_terms(&terms, \"bad\", \"good\");\n+\tget_terms(&terms);\n+\treturn bisect_state(&terms, argv, argc);\n+}\n+\n+static int cmd_bisect__log(int argc, const char **argv UNUSED, const char *prefix UNUSED)\n+{\n+\tif (argc)\n+\t\treturn error(_(\"--bisect-log requires 0 arguments\"));\n+\treturn bisect_log();\n+}\n+\n+static int cmd_bisect__replay(int argc, const char **argv, const char *prefix UNUSED)\n+{\n+\tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\n+\n+\tif (argc != 1)\n+\t\treturn error(_(\"no logfile given\"));\n+\tset_terms(&terms, \"bad\", \"good\");\n+\treturn bisect_replay(&terms, argv[0]);\n+}\n+\n+static int cmd_bisect__skip(int argc, const char **argv, const char *prefix UNUSED)\n+{\n+\tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\n+\n+\tset_terms(&terms, \"bad\", \"good\");\n+\tget_terms(&terms);\n+\treturn bisect_skip(&terms, argv, argc);\n+}\n+\n+static int cmd_bisect__visualize(int argc, const char **argv, const char *prefix UNUSED)\n+{\n+\tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\n+\n+\tget_terms(&terms);\n+\treturn bisect_visualize(&terms, argv, argc);\n+}\n+\n+static int cmd_bisect__run(int argc, const char **argv, const char *prefix UNUSED)\n+{\n+\tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\n+\n+\tif (!argc)\n+\t\treturn error(_(\"bisect run failed: no command provided.\"));\n+\tget_terms(&terms);\n+\treturn bisect_run(&terms, argv, argc);\n+}\n+\n int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n {\n-\tenum {\n-\t\tBISECT_RESET = 1,\n-\t\tBISECT_NEXT_CHECK,\n-\t\tBISECT_TERMS,\n-\t\tBISECT_START,\n-\t\tBISECT_AUTOSTART,\n-\t\tBISECT_NEXT,\n-\t\tBISECT_STATE,\n-\t\tBISECT_LOG,\n-\t\tBISECT_REPLAY,\n-\t\tBISECT_SKIP,\n-\t\tBISECT_VISUALIZE,\n-\t\tBISECT_RUN,\n-\t} cmdmode = 0;\n-\tint res = 0, nolog = 0;\n+\tint res = 0;\n+\tparse_opt_subcommand_fn *fn = NULL;\n \tstruct option options[] = {\n-\t\tOPT_CMDMODE(0, \"bisect-reset\", &cmdmode,\n-\t\t\t N_(\"reset the bisection state\"), BISECT_RESET),\n-\t\tOPT_CMDMODE(0, \"bisect-next-check\", &cmdmode,\n-\t\t\t N_(\"check whether bad or good terms exist\"), BISECT_NEXT_CHECK),\n-\t\tOPT_CMDMODE(0, \"bisect-terms\", &cmdmode,\n-\t\t\t N_(\"print out the bisect terms\"), BISECT_TERMS),\n-\t\tOPT_CMDMODE(0, \"bisect-start\", &cmdmode,\n-\t\t\t N_(\"start the bisect session\"), BISECT_START),\n-\t\tOPT_CMDMODE(0, \"bisect-next\", &cmdmode,\n-\t\t\t N_(\"find the next bisection commit\"), BISECT_NEXT),\n-\t\tOPT_CMDMODE(0, \"bisect-state\", &cmdmode,\n-\t\t\t N_(\"mark the state of ref (or refs)\"), BISECT_STATE),\n-\t\tOPT_CMDMODE(0, \"bisect-log\", &cmdmode,\n-\t\t\t N_(\"list the bisection steps so far\"), BISECT_LOG),\n-\t\tOPT_CMDMODE(0, \"bisect-replay\", &cmdmode,\n-\t\t\t N_(\"replay the bisection process from the given file\"), BISECT_REPLAY),\n-\t\tOPT_CMDMODE(0, \"bisect-skip\", &cmdmode,\n-\t\t\t N_(\"skip some commits for checkout\"), BISECT_SKIP),\n-\t\tOPT_CMDMODE(0, \"bisect-visualize\", &cmdmode,\n-\t\t\t N_(\"visualize the bisection\"), BISECT_VISUALIZE),\n-\t\tOPT_CMDMODE(0, \"bisect-run\", &cmdmode,\n-\t\t\t N_(\"use <cmd>... to automatically bisect\"), BISECT_RUN),\n-\t\tOPT_BOOL(0, \"no-log\", &nolog,\n-\t\t\t N_(\"no log for BISECT_WRITE\")),\n+\t\tOPT_SUBCOMMAND(\"bisect-reset\", &fn, cmd_bisect__reset),\n+\t\tOPT_SUBCOMMAND(\"bisect-terms\", &fn, cmd_bisect__terms),\n+\t\tOPT_SUBCOMMAND(\"bisect-start\", &fn, cmd_bisect__start),\n+\t\tOPT_SUBCOMMAND(\"bisect-next\", &fn, cmd_bisect__next),\n+\t\tOPT_SUBCOMMAND(\"bisect-state\", &fn, cmd_bisect__state),\n+\t\tOPT_SUBCOMMAND(\"bisect-log\", &fn, cmd_bisect__log),\n+\t\tOPT_SUBCOMMAND(\"bisect-replay\", &fn, cmd_bisect__replay),\n+\t\tOPT_SUBCOMMAND(\"bisect-skip\", &fn, cmd_bisect__skip),\n+\t\tOPT_SUBCOMMAND(\"bisect-visualize\", &fn, cmd_bisect__visualize),\n+\t\tOPT_SUBCOMMAND(\"bisect-run\", &fn, cmd_bisect__run),\n \t\tOPT_END()\n \t};\n-\tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\n-\n \targc = parse_options(argc, argv, prefix, options,\n-\t\t\t     git_bisect_helper_usage,\n-\t\t\t     PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN_OPT);\n+\t\t\t     git_bisect_helper_usage, 0);\n \n-\tif (!cmdmode)\n+\tif (!fn)\n \t\tusage_with_options(git_bisect_helper_usage, options);\n+\targc--;\n+\targv++;\n \n-\tswitch (cmdmode) {\n-\tcase BISECT_RESET:\n-\t\tif (argc > 1)\n-\t\t\treturn error(_(\"--bisect-reset requires either no argument or a commit\"));\n-\t\tres = bisect_reset(argc ? argv[0] : NULL);\n-\t\tbreak;\n-\tcase BISECT_TERMS:\n-\t\tif (argc > 1)\n-\t\t\treturn error(_(\"--bisect-terms requires 0 or 1 argument\"));\n-\t\tres = bisect_terms(&terms, argc == 1 ? argv[0] : NULL);\n-\t\tbreak;\n-\tcase BISECT_START:\n-\t\tset_terms(&terms, \"bad\", \"good\");\n-\t\tres = bisect_start(&terms, argv, argc);\n-\t\tbreak;\n-\tcase BISECT_NEXT:\n-\t\tif (argc)\n-\t\t\treturn error(_(\"--bisect-next requires 0 arguments\"));\n-\t\tget_terms(&terms);\n-\t\tres = bisect_next(&terms, prefix);\n-\t\tbreak;\n-\tcase BISECT_STATE:\n-\t\tset_terms(&terms, \"bad\", \"good\");\n-\t\tget_terms(&terms);\n-\t\tres = bisect_state(&terms, argv, argc);\n-\t\tbreak;\n-\tcase BISECT_LOG:\n-\t\tif (argc)\n-\t\t\treturn error(_(\"--bisect-log requires 0 arguments\"));\n-\t\tres = bisect_log();\n-\t\tbreak;\n-\tcase BISECT_REPLAY:\n-\t\tif (argc != 1)\n-\t\t\treturn error(_(\"no logfile given\"));\n-\t\tset_terms(&terms, \"bad\", \"good\");\n-\t\tres = bisect_replay(&terms, argv[0]);\n-\t\tbreak;\n-\tcase BISECT_SKIP:\n-\t\tset_terms(&terms, \"bad\", \"good\");\n-\t\tget_terms(&terms);\n-\t\tres = bisect_skip(&terms, argv, argc);\n-\t\tbreak;\n-\tcase BISECT_VISUALIZE:\n-\t\tget_terms(&terms);\n-\t\tres = bisect_visualize(&terms, argv, argc);\n-\t\tbreak;\n-\tcase BISECT_RUN:\n-\t\tif (!argc)\n-\t\t\treturn error(_(\"bisect run failed: no command provided.\"));\n-\t\tget_terms(&terms);\n-\t\tres = bisect_run(&terms, argv, argc);\n-\t\tbreak;\n-\tdefault:\n-\t\tBUG(\"unknown subcommand %d\", cmdmode);\n-\t}\n-\tfree_terms(&terms);\n+\tres = fn(argc, argv, prefix);\n \n \t/*\n \t * Handle early success\ndiff --git a/git-bisect.sh b/git-bisect.sh\nindex 405cf76f2a..07a7257be4 100755\n--- a/git-bisect.sh\n+++ b/git-bisect.sh\n@@ -58,26 +58,26 @@ case \"$#\" in\n \thelp)\n \t\tgit bisect -h ;;\n \tstart)\n-\t\tgit bisect--helper --bisect-start \"$@\" ;;\n+\t\tgit bisect--helper bisect-start \"$@\" ;;\n \tbad|good|new|old|\"$TERM_BAD\"|\"$TERM_GOOD\")\n-\t\tgit bisect--helper --bisect-state \"$cmd\" \"$@\" ;;\n+\t\tgit bisect--helper bisect-state \"$cmd\" \"$@\" ;;\n \tskip)\n-\t\tgit bisect--helper --bisect-skip \"$@\" || exit;;\n+\t\tgit bisect--helper bisect-skip \"$@\" || exit;;\n \tnext)\n \t\t# Not sure we want \"next\" at the UI level anymore.\n-\t\tgit bisect--helper --bisect-next \"$@\" || exit ;;\n+\t\tgit bisect--helper bisect-next \"$@\" || exit ;;\n \tvisualize|view)\n-\t\tgit bisect--helper --bisect-visualize \"$@\" || exit;;\n+\t\tgit bisect--helper bisect-visualize \"$@\" || exit;;\n \treset)\n-\t\tgit bisect--helper --bisect-reset \"$@\" ;;\n+\t\tgit bisect--helper bisect-reset \"$@\" ;;\n \treplay)\n-\t\tgit bisect--helper --bisect-replay \"$@\" || exit;;\n+\t\tgit bisect--helper bisect-replay \"$@\" || exit;;\n \tlog)\n-\t\tgit bisect--helper --bisect-log || exit ;;\n+\t\tgit bisect--helper bisect-log || exit ;;\n \trun)\n-\t\tgit bisect--helper --bisect-run \"$@\" || exit;;\n+\t\tgit bisect--helper bisect-run \"$@\" || exit;;\n \tterms)\n-\t\tgit bisect--helper --bisect-terms \"$@\" || exit;;\n+\t\tgit bisect--helper bisect-terms \"$@\" || exit;;\n \t*)\n \t\tusage ;;\n \tesac\ndiff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh\nindex 83931d482f..e957772b05 100755\n--- a/t/t6030-bisect-porcelain.sh\n+++ b/t/t6030-bisect-porcelain.sh\n@@ -266,6 +266,17 @@ test_expect_success '\"git bisect run\" simple case' '\n \tgit bisect reset\n '\n \n+# We want to automatically find the commit that\n+# added \"Another\" into hello. We also want to make sure --log is not eaten\n+test_expect_success '\"git bisect run\" simple case' '\n+\tgit bisect start &&\n+\tgit bisect good $HASH1 &&\n+\tgit bisect bad $HASH4 &&\n+\tgit bisect run printf \"%s\\n\" --log >my_bisect_log.txt &&\n+\tgrep -e --log my_bisect_log.txt &&\n+\tgit bisect reset\n+'\n+\n # We want to automatically find the commit that\n # added \"Ciao\" into hello.\n test_expect_success '\"git bisect run\" with more complex \"git bisect start\"' '\n----- >8 -----\n\nI can turn this into 2 patches series if you thinks this is the right\ndirection.\n\n-- \nDanh\n"},{"id":"466499","messageId":"221104.86zgd7x85r.gmgdl@evledraar.gmail.com","threadId":"58746","inReplyTo":"Y2TfUFkLUa2tHdS7@coredump.intra.peff.net","subject":"Re: \"git bisect run\" strips \"--log\" from the list of arguments","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-04T11:36:12Z","receivedAt":"2022-11-04T11:37:27Z","isPatch":false,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Fri, Nov 04 2022, Jeff King wrote:\n\n> On Fri, Nov 04, 2022 at 07:31:26AM +0100, Lukáš Doktor wrote:\n>\n>> Steps to Reproduce:\n>> \n>> 1. git bisect start BAD GOOD\n>> 2. git bisect run ./myscript arg1 --log arg2 --log -- arg3 --log arg4\n>> \n>> Results with 2.34.1:\n>> \n>>     running  './myscript' 'arg1' 'arg2' '--' 'arg3' '--log' 'arg4'\n>> \n>> Results with 2.33.0:\n>> \n>>     running ./myscript arg1 --log arg2 --log -- arg3 --log arg4\n>\n> Thanks for an easy reproduction recipe. I used this as an easy-to-see\n> test case, which works in any repo:\n>\n>   git bisect start HEAD HEAD~2 >/dev/null 2>&1\n>   git bisect bisect run echo --log 2>&1 | grep running\n>\n>> Is this expected? In https://bugzilla.redhat.com/show_bug.cgi?id=2139883 Todd suggested it might be related to\n>> \n>>     d1bbbe45df (bisect--helper: reimplement `bisect_run` shell function in C, 2021-09-13) \n>> \n>> but I haven't tried it myself.\n>\n> Yes, it bisects to that commit. +cc Christian, who mentored this gsoc\n> project.\n>\n> I think the problem is that we are now feeding the arguments to\n> parse_options() in git bisect--helper, and it doesn't realize that it\n> needs to stop after seeing that we are in \"run\" mode.  And because\n> \"--log\" is an option to git-bisect--helper (it is the opposite of\n> \"--no-log\"), it is consumed there.\n>\n> As you noticed, the \"--\" stops parsing, so the one between \"arg3\" and\n> \"arg4\" is preserved.\n>\n> It feels like the invocation of bisect--helper ought to be passing \"--\"\n> itself to indicate the end of options, like:\n\nNormally you'd be righ, but there's a much easier way to do it in this\ncase: cherry-pick\nhttps://lore.kernel.org/git/05262b6a7d1b20a0d2f2ca2090be284ffb8c679c.1661885419.git.gitgitgadget@gmail.com/\n\nI.e. we're eating \"--log\" in particular, but could just stop\nunderstanding that option.\n\nI'll submit alternate fixes for this soon, I've been poking at various\n\"bisect\" behavior changes, and the commit that rewrote \"run\" introduced\na few other regressions....\n"},{"id":"466500","messageId":"cover.1667561761.git.congdanhqx@gmail.com","threadId":"58746","inReplyTo":"1cb1c033-0525-7e62-8c09-81019bf26060@redhat.com","subject":"[PATCH 0/3] Convert git-bisect--helper to OPT_SUBCOMMAND","fromName":"Đoàn Trần Công Danh","fromEmail":"congdanhqx@gmail.com","sentAt":"2022-11-04T11:40:09Z","receivedAt":"2022-11-04T11:40:31Z","isPatch":true,"sender":{"key":"congdanhqx@gmail.com","avatar":"https://avatars.githubusercontent.com/u/42673067?v=4"},"body":"\nThis series aims to fix the problem that bisect--helper incorrectly consumes\n\"--log\" when running:\n\n\tgit bisect run cmd --log\n\nThis also clears a way for turning git-bisect into a built-in in a later day.\n\nĐoàn Trần Công Danh (3):\n  bisect--helper: remove unused options\n  bisect--helper: move all subcommands into their own functions\n  bisect--helper: parse subcommand with OPT_SUBCOMMAND\n\n builtin/bisect--helper.c    | 228 ++++++++++++++++++++----------------\n git-bisect.sh               |  20 ++--\n t/t6030-bisect-porcelain.sh |  10 ++\n 3 files changed, 148 insertions(+), 110 deletions(-)\n\n-- \n2.38.1.157.gedabe22e0a\n\n"},{"id":"466501","messageId":"489785ca45a84cffb4a2c16da15a09034829b7c6.1667561761.git.congdanhqx@gmail.com","threadId":"58746","inReplyTo":"cover.1667561761.git.congdanhqx@gmail.com","subject":"[PATCH 1/3] bisect--helper: remove unused options","fromName":"Đoàn Trần Công Danh","fromEmail":"congdanhqx@gmail.com","sentAt":"2022-11-04T11:40:10Z","receivedAt":"2022-11-04T11:40:34Z","isPatch":true,"sender":{"key":"congdanhqx@gmail.com","avatar":"https://avatars.githubusercontent.com/u/42673067?v=4"},"body":"Signed-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>\n---\n builtin/bisect--helper.c | 7 +------\n 1 file changed, 1 insertion(+), 6 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 1d2ce8a0e1..5ec2e67f59 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1283,7 +1283,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n {\n \tenum {\n \t\tBISECT_RESET = 1,\n-\t\tBISECT_NEXT_CHECK,\n \t\tBISECT_TERMS,\n \t\tBISECT_START,\n \t\tBISECT_AUTOSTART,\n@@ -1295,12 +1294,10 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\tBISECT_VISUALIZE,\n \t\tBISECT_RUN,\n \t} cmdmode = 0;\n-\tint res = 0, nolog = 0;\n+\tint res = 0;\n \tstruct option options[] = {\n \t\tOPT_CMDMODE(0, \"bisect-reset\", &cmdmode,\n \t\t\t N_(\"reset the bisection state\"), BISECT_RESET),\n-\t\tOPT_CMDMODE(0, \"bisect-next-check\", &cmdmode,\n-\t\t\t N_(\"check whether bad or good terms exist\"), BISECT_NEXT_CHECK),\n \t\tOPT_CMDMODE(0, \"bisect-terms\", &cmdmode,\n \t\t\t N_(\"print out the bisect terms\"), BISECT_TERMS),\n \t\tOPT_CMDMODE(0, \"bisect-start\", &cmdmode,\n@@ -1319,8 +1316,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\t\t N_(\"visualize the bisection\"), BISECT_VISUALIZE),\n \t\tOPT_CMDMODE(0, \"bisect-run\", &cmdmode,\n \t\t\t N_(\"use <cmd>... to automatically bisect\"), BISECT_RUN),\n-\t\tOPT_BOOL(0, \"no-log\", &nolog,\n-\t\t\t N_(\"no log for BISECT_WRITE\")),\n \t\tOPT_END()\n \t};\n \tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\n-- \n2.38.1.157.gedabe22e0a\n\n"},{"id":"466502","messageId":"081f3f7f9501012404fb9e59ab6d94f632180b53.1667561761.git.congdanhqx@gmail.com","threadId":"58746","inReplyTo":"cover.1667561761.git.congdanhqx@gmail.com","subject":"[PATCH 2/3] bisect--helper: move all subcommands into their own functions","fromName":"Đoàn Trần Công Danh","fromEmail":"congdanhqx@gmail.com","sentAt":"2022-11-04T11:40:11Z","receivedAt":"2022-11-04T11:40:36Z","isPatch":true,"sender":{"key":"congdanhqx@gmail.com","avatar":"https://avatars.githubusercontent.com/u/42673067?v=4"},"body":"In a later change, we will use OPT_SUBCOMMAND to parse sub-commands to\navoid consuming non-option opts.\n\nSince OPT_SUBCOMMAND needs a function pointer to operate,\nlet's move it now.\n\nSigned-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>\n---\n builtin/bisect--helper.c | 155 ++++++++++++++++++++++++++++++---------\n 1 file changed, 121 insertions(+), 34 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 5ec2e67f59..292c6fd1dd 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1279,6 +1279,117 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n \treturn res;\n }\n \n+static int cmd_bisect__reset(int argc, const char **argv, const char *prefix UNUSED)\n+{\n+\tif (argc > 1)\n+\t\treturn error(_(\"--bisect-reset requires either no argument or a commit\"));\n+\treturn bisect_reset(argc ? argv[0] : NULL);\n+}\n+\n+static int cmd_bisect__terms(int argc, const char **argv, const char *prefix UNUSED)\n+{\n+\tint res;\n+\tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\n+\n+\tif (argc > 1)\n+\t\treturn error(_(\"--bisect-terms requires 0 or 1 argument\"));\n+\tres = bisect_terms(&terms, argc == 1 ? argv[0] : NULL);\n+\tfree_terms(&terms);\n+\treturn res;\n+}\n+\n+static int cmd_bisect__start(int argc, const char **argv, const char *prefix UNUSED)\n+{\n+\tint res;\n+\tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\n+\n+\tset_terms(&terms, \"bad\", \"good\");\n+\tres = bisect_start(&terms, argv, argc);\n+\tfree_terms(&terms);\n+\treturn res;\n+}\n+\n+static int cmd_bisect__next(int argc, const char **argv UNUSED, const char *prefix)\n+{\n+\tint res;\n+\tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\n+\n+\tif (argc)\n+\t\treturn error(_(\"--bisect-next requires 0 arguments\"));\n+\tget_terms(&terms);\n+\tres = bisect_next(&terms, prefix);\n+\tfree_terms(&terms);\n+\treturn res;\n+}\n+\n+static int cmd_bisect__state(int argc, const char **argv, const char *prefix UNUSED)\n+{\n+\tint res;\n+\tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\n+\n+\tset_terms(&terms, \"bad\", \"good\");\n+\tget_terms(&terms);\n+\tres = bisect_state(&terms, argv, argc);\n+\tfree_terms(&terms);\n+\treturn res;\n+}\n+\n+static int cmd_bisect__log(int argc, const char **argv UNUSED, const char *prefix UNUSED)\n+{\n+\tif (argc)\n+\t\treturn error(_(\"--bisect-log requires 0 arguments\"));\n+\treturn bisect_log();\n+}\n+\n+static int cmd_bisect__replay(int argc, const char **argv, const char *prefix UNUSED)\n+{\n+\tint res;\n+\tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\n+\n+\tif (argc != 1)\n+\t\treturn error(_(\"no logfile given\"));\n+\tset_terms(&terms, \"bad\", \"good\");\n+\tres = bisect_replay(&terms, argv[0]);\n+\tfree_terms(&terms);\n+\treturn res;\n+}\n+\n+static int cmd_bisect__skip(int argc, const char **argv, const char *prefix UNUSED)\n+{\n+\tint res;\n+\tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\n+\n+\tset_terms(&terms, \"bad\", \"good\");\n+\tget_terms(&terms);\n+\tres = bisect_skip(&terms, argv, argc);\n+\tfree_terms(&terms);\n+\treturn res;\n+}\n+\n+static int cmd_bisect__visualize(int argc, const char **argv, const char *prefix UNUSED)\n+{\n+\tint res;\n+\tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\n+\n+\tget_terms(&terms);\n+\tres = bisect_visualize(&terms, argv, argc);\n+\tfree_terms(&terms);\n+\treturn res;\n+}\n+\n+static int cmd_bisect__run(int argc, const char **argv, const char *prefix UNUSED)\n+{\n+\tint res;\n+\tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\n+\n+\tif (!argc)\n+\t\treturn error(_(\"bisect run failed: no command provided.\"));\n+\tget_terms(&terms);\n+\tres = bisect_run(&terms, argv, argc);\n+\tfree_terms(&terms);\n+\treturn res;\n+}\n+\n int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n {\n \tenum {\n@@ -1318,8 +1429,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\t\t N_(\"use <cmd>... to automatically bisect\"), BISECT_RUN),\n \t\tOPT_END()\n \t};\n-\tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\n-\n \targc = parse_options(argc, argv, prefix, options,\n \t\t\t     git_bisect_helper_usage,\n \t\t\t     PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN_OPT);\n@@ -1329,60 +1438,38 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \n \tswitch (cmdmode) {\n \tcase BISECT_RESET:\n-\t\tif (argc > 1)\n-\t\t\treturn error(_(\"--bisect-reset requires either no argument or a commit\"));\n-\t\tres = bisect_reset(argc ? argv[0] : NULL);\n+\t\tres = cmd_bisect__reset(argc, argv, prefix);\n \t\tbreak;\n \tcase BISECT_TERMS:\n-\t\tif (argc > 1)\n-\t\t\treturn error(_(\"--bisect-terms requires 0 or 1 argument\"));\n-\t\tres = bisect_terms(&terms, argc == 1 ? argv[0] : NULL);\n+\t\tres = cmd_bisect__terms(argc, argv, prefix);\n \t\tbreak;\n \tcase BISECT_START:\n-\t\tset_terms(&terms, \"bad\", \"good\");\n-\t\tres = bisect_start(&terms, argv, argc);\n+\t\tres = cmd_bisect__start(argc, argv, prefix);\n \t\tbreak;\n \tcase BISECT_NEXT:\n-\t\tif (argc)\n-\t\t\treturn error(_(\"--bisect-next requires 0 arguments\"));\n-\t\tget_terms(&terms);\n-\t\tres = bisect_next(&terms, prefix);\n+\t\tres = cmd_bisect__next(argc, argv, prefix);\n \t\tbreak;\n \tcase BISECT_STATE:\n-\t\tset_terms(&terms, \"bad\", \"good\");\n-\t\tget_terms(&terms);\n-\t\tres = bisect_state(&terms, argv, argc);\n+\t\tres = cmd_bisect__state(argc, argv, prefix);\n \t\tbreak;\n \tcase BISECT_LOG:\n-\t\tif (argc)\n-\t\t\treturn error(_(\"--bisect-log requires 0 arguments\"));\n-\t\tres = bisect_log();\n+\t\tres = cmd_bisect__log(argc, argv, prefix);\n \t\tbreak;\n \tcase BISECT_REPLAY:\n-\t\tif (argc != 1)\n-\t\t\treturn error(_(\"no logfile given\"));\n-\t\tset_terms(&terms, \"bad\", \"good\");\n-\t\tres = bisect_replay(&terms, argv[0]);\n+\t\tres = cmd_bisect__replay(argc, argv, prefix);\n \t\tbreak;\n \tcase BISECT_SKIP:\n-\t\tset_terms(&terms, \"bad\", \"good\");\n-\t\tget_terms(&terms);\n-\t\tres = bisect_skip(&terms, argv, argc);\n+\t\tres = cmd_bisect__skip(argc, argv, prefix);\n \t\tbreak;\n \tcase BISECT_VISUALIZE:\n-\t\tget_terms(&terms);\n-\t\tres = bisect_visualize(&terms, argv, argc);\n+\t\tres = cmd_bisect__visualize(argc, argv, prefix);\n \t\tbreak;\n \tcase BISECT_RUN:\n-\t\tif (!argc)\n-\t\t\treturn error(_(\"bisect run failed: no command provided.\"));\n-\t\tget_terms(&terms);\n-\t\tres = bisect_run(&terms, argv, argc);\n+\t\tres = cmd_bisect__run(argc, argv, prefix);\n \t\tbreak;\n \tdefault:\n \t\tBUG(\"unknown subcommand %d\", cmdmode);\n \t}\n-\tfree_terms(&terms);\n \n \t/*\n \t * Handle early success\n-- \n2.38.1.157.gedabe22e0a\n\n"},{"id":"466503","messageId":"76c585d22bf415e719762fcf5decf4b71efa5bfb.1667561761.git.congdanhqx@gmail.com","threadId":"58746","inReplyTo":"cover.1667561761.git.congdanhqx@gmail.com","subject":"[PATCH 3/3] bisect--helper: parse subcommand with OPT_SUBCOMMAND","fromName":"Đoàn Trần Công Danh","fromEmail":"congdanhqx@gmail.com","sentAt":"2022-11-04T11:40:12Z","receivedAt":"2022-11-04T11:40:48Z","isPatch":true,"sender":{"key":"congdanhqx@gmail.com","avatar":"https://avatars.githubusercontent.com/u/42673067?v=4"},"body":"As of it is, we're parsing subcommand with OPT_CMDMODE, which will\ncontinue to parse more options even if the command has been found.\n\nWhen we're running \"git bisect run\" with a command that expecting\na \"--log\" or \"--no-log\" arguments, or one of those \"--bisect-...\"\narguments, bisect--helper may mistakenly think those options are\nbisect--helper's option.\n\nWe may fix those problems by passing \"--\" when calling from\ngit-bisect.sh, and skip that \"--\" in bisect--helper. However, it may\ninterfere with user's \"--\".\n\nLet's parse subcommand with OPT_SUBCOMMAND since that API was born for\nthis specific use-case.\n\nReported-by: Lukáš Doktor <ldoktor@redhat.com>\nSigned-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>\n---\n builtin/bisect--helper.c    | 86 +++++++------------------------------\n git-bisect.sh               | 20 ++++-----\n t/t6030-bisect-porcelain.sh | 10 +++++\n 3 files changed, 36 insertions(+), 80 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 292c6fd1dd..c37cb89a90 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1392,84 +1392,30 @@ static int cmd_bisect__run(int argc, const char **argv, const char *prefix UNUSE\n \n int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n {\n-\tenum {\n-\t\tBISECT_RESET = 1,\n-\t\tBISECT_TERMS,\n-\t\tBISECT_START,\n-\t\tBISECT_AUTOSTART,\n-\t\tBISECT_NEXT,\n-\t\tBISECT_STATE,\n-\t\tBISECT_LOG,\n-\t\tBISECT_REPLAY,\n-\t\tBISECT_SKIP,\n-\t\tBISECT_VISUALIZE,\n-\t\tBISECT_RUN,\n-\t} cmdmode = 0;\n \tint res = 0;\n+\tparse_opt_subcommand_fn *fn = NULL;\n \tstruct option options[] = {\n-\t\tOPT_CMDMODE(0, \"bisect-reset\", &cmdmode,\n-\t\t\t N_(\"reset the bisection state\"), BISECT_RESET),\n-\t\tOPT_CMDMODE(0, \"bisect-terms\", &cmdmode,\n-\t\t\t N_(\"print out the bisect terms\"), BISECT_TERMS),\n-\t\tOPT_CMDMODE(0, \"bisect-start\", &cmdmode,\n-\t\t\t N_(\"start the bisect session\"), BISECT_START),\n-\t\tOPT_CMDMODE(0, \"bisect-next\", &cmdmode,\n-\t\t\t N_(\"find the next bisection commit\"), BISECT_NEXT),\n-\t\tOPT_CMDMODE(0, \"bisect-state\", &cmdmode,\n-\t\t\t N_(\"mark the state of ref (or refs)\"), BISECT_STATE),\n-\t\tOPT_CMDMODE(0, \"bisect-log\", &cmdmode,\n-\t\t\t N_(\"list the bisection steps so far\"), BISECT_LOG),\n-\t\tOPT_CMDMODE(0, \"bisect-replay\", &cmdmode,\n-\t\t\t N_(\"replay the bisection process from the given file\"), BISECT_REPLAY),\n-\t\tOPT_CMDMODE(0, \"bisect-skip\", &cmdmode,\n-\t\t\t N_(\"skip some commits for checkout\"), BISECT_SKIP),\n-\t\tOPT_CMDMODE(0, \"bisect-visualize\", &cmdmode,\n-\t\t\t N_(\"visualize the bisection\"), BISECT_VISUALIZE),\n-\t\tOPT_CMDMODE(0, \"bisect-run\", &cmdmode,\n-\t\t\t N_(\"use <cmd>... to automatically bisect\"), BISECT_RUN),\n+\t\tOPT_SUBCOMMAND(\"bisect-reset\", &fn, cmd_bisect__reset),\n+\t\tOPT_SUBCOMMAND(\"bisect-terms\", &fn, cmd_bisect__terms),\n+\t\tOPT_SUBCOMMAND(\"bisect-start\", &fn, cmd_bisect__start),\n+\t\tOPT_SUBCOMMAND(\"bisect-next\", &fn, cmd_bisect__next),\n+\t\tOPT_SUBCOMMAND(\"bisect-state\", &fn, cmd_bisect__state),\n+\t\tOPT_SUBCOMMAND(\"bisect-log\", &fn, cmd_bisect__log),\n+\t\tOPT_SUBCOMMAND(\"bisect-replay\", &fn, cmd_bisect__replay),\n+\t\tOPT_SUBCOMMAND(\"bisect-skip\", &fn, cmd_bisect__skip),\n+\t\tOPT_SUBCOMMAND(\"bisect-visualize\", &fn, cmd_bisect__visualize),\n+\t\tOPT_SUBCOMMAND(\"bisect-run\", &fn, cmd_bisect__run),\n \t\tOPT_END()\n \t};\n \targc = parse_options(argc, argv, prefix, options,\n-\t\t\t     git_bisect_helper_usage,\n-\t\t\t     PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN_OPT);\n+\t\t\t     git_bisect_helper_usage, 0);\n \n-\tif (!cmdmode)\n+\tif (!fn)\n \t\tusage_with_options(git_bisect_helper_usage, options);\n+\targc--;\n+\targv++;\n \n-\tswitch (cmdmode) {\n-\tcase BISECT_RESET:\n-\t\tres = cmd_bisect__reset(argc, argv, prefix);\n-\t\tbreak;\n-\tcase BISECT_TERMS:\n-\t\tres = cmd_bisect__terms(argc, argv, prefix);\n-\t\tbreak;\n-\tcase BISECT_START:\n-\t\tres = cmd_bisect__start(argc, argv, prefix);\n-\t\tbreak;\n-\tcase BISECT_NEXT:\n-\t\tres = cmd_bisect__next(argc, argv, prefix);\n-\t\tbreak;\n-\tcase BISECT_STATE:\n-\t\tres = cmd_bisect__state(argc, argv, prefix);\n-\t\tbreak;\n-\tcase BISECT_LOG:\n-\t\tres = cmd_bisect__log(argc, argv, prefix);\n-\t\tbreak;\n-\tcase BISECT_REPLAY:\n-\t\tres = cmd_bisect__replay(argc, argv, prefix);\n-\t\tbreak;\n-\tcase BISECT_SKIP:\n-\t\tres = cmd_bisect__skip(argc, argv, prefix);\n-\t\tbreak;\n-\tcase BISECT_VISUALIZE:\n-\t\tres = cmd_bisect__visualize(argc, argv, prefix);\n-\t\tbreak;\n-\tcase BISECT_RUN:\n-\t\tres = cmd_bisect__run(argc, argv, prefix);\n-\t\tbreak;\n-\tdefault:\n-\t\tBUG(\"unknown subcommand %d\", cmdmode);\n-\t}\n+\tres = fn(argc, argv, prefix);\n \n \t/*\n \t * Handle early success\ndiff --git a/git-bisect.sh b/git-bisect.sh\nindex 405cf76f2a..07a7257be4 100755\n--- a/git-bisect.sh\n+++ b/git-bisect.sh\n@@ -58,26 +58,26 @@ case \"$#\" in\n \thelp)\n \t\tgit bisect -h ;;\n \tstart)\n-\t\tgit bisect--helper --bisect-start \"$@\" ;;\n+\t\tgit bisect--helper bisect-start \"$@\" ;;\n \tbad|good|new|old|\"$TERM_BAD\"|\"$TERM_GOOD\")\n-\t\tgit bisect--helper --bisect-state \"$cmd\" \"$@\" ;;\n+\t\tgit bisect--helper bisect-state \"$cmd\" \"$@\" ;;\n \tskip)\n-\t\tgit bisect--helper --bisect-skip \"$@\" || exit;;\n+\t\tgit bisect--helper bisect-skip \"$@\" || exit;;\n \tnext)\n \t\t# Not sure we want \"next\" at the UI level anymore.\n-\t\tgit bisect--helper --bisect-next \"$@\" || exit ;;\n+\t\tgit bisect--helper bisect-next \"$@\" || exit ;;\n \tvisualize|view)\n-\t\tgit bisect--helper --bisect-visualize \"$@\" || exit;;\n+\t\tgit bisect--helper bisect-visualize \"$@\" || exit;;\n \treset)\n-\t\tgit bisect--helper --bisect-reset \"$@\" ;;\n+\t\tgit bisect--helper bisect-reset \"$@\" ;;\n \treplay)\n-\t\tgit bisect--helper --bisect-replay \"$@\" || exit;;\n+\t\tgit bisect--helper bisect-replay \"$@\" || exit;;\n \tlog)\n-\t\tgit bisect--helper --bisect-log || exit ;;\n+\t\tgit bisect--helper bisect-log || exit ;;\n \trun)\n-\t\tgit bisect--helper --bisect-run \"$@\" || exit;;\n+\t\tgit bisect--helper bisect-run \"$@\" || exit;;\n \tterms)\n-\t\tgit bisect--helper --bisect-terms \"$@\" || exit;;\n+\t\tgit bisect--helper bisect-terms \"$@\" || exit;;\n \t*)\n \t\tusage ;;\n \tesac\ndiff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh\nindex 83931d482f..a17027d574 100755\n--- a/t/t6030-bisect-porcelain.sh\n+++ b/t/t6030-bisect-porcelain.sh\n@@ -266,6 +266,16 @@ test_expect_success '\"git bisect run\" simple case' '\n \tgit bisect reset\n '\n \n+# We want to make sure --log is not eaten\n+test_expect_success '\"git bisect run\" simple case' '\n+\tgit bisect start &&\n+\tgit bisect good $HASH1 &&\n+\tgit bisect bad $HASH4 &&\n+\tgit bisect run printf \"%s\\n\" --log >my_bisect_log.txt &&\n+\tgrep -e --log my_bisect_log.txt &&\n+\tgit bisect reset\n+'\n+\n # We want to automatically find the commit that\n # added \"Ciao\" into hello.\n test_expect_success '\"git bisect run\" with more complex \"git bisect start\"' '\n-- \n2.38.1.157.gedabe22e0a\n\n"},{"id":"466505","messageId":"20221104123722.GA6942@szeder.dev","threadId":"58746","inReplyTo":"Y2TfUFkLUa2tHdS7@coredump.intra.peff.net","subject":"Re: \"git bisect run\" strips \"--log\" from the list of arguments","fromName":"SZEDER Gábor","fromEmail":"szeder.dev@gmail.com","sentAt":"2022-11-04T12:37:22Z","receivedAt":"2022-11-04T12:37:53Z","isPatch":false,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"On Fri, Nov 04, 2022 at 05:45:52AM -0400, Jeff King wrote:\n> On Fri, Nov 04, 2022 at 07:31:26AM +0100, Lukáš Doktor wrote:\n> \n> > Steps to Reproduce:\n> > \n> > 1. git bisect start BAD GOOD\n> > 2. git bisect run ./myscript arg1 --log arg2 --log -- arg3 --log arg4\n> > \n> > Results with 2.34.1:\n> > \n> >     running  './myscript' 'arg1' 'arg2' '--' 'arg3' '--log' 'arg4'\n> > \n> > Results with 2.33.0:\n> > \n> >     running ./myscript arg1 --log arg2 --log -- arg3 --log arg4\n> \n> Thanks for an easy reproduction recipe. I used this as an easy-to-see\n> test case, which works in any repo:\n> \n>   git bisect start HEAD HEAD~2 >/dev/null 2>&1\n>   git bisect bisect run echo --log 2>&1 | grep running\n> \n> > Is this expected? In https://bugzilla.redhat.com/show_bug.cgi?id=2139883 Todd suggested it might be related to\n> > \n> >     d1bbbe45df (bisect--helper: reimplement `bisect_run` shell function in C, 2021-09-13) \n> > \n> > but I haven't tried it myself.\n> \n> Yes, it bisects to that commit. +cc Christian, who mentored this gsoc\n> project.\n\nIt might bisect to that commit, but I don't think that commit is the\nreal culprit here.\n\n'git-bisect.sh' used to have a 'bisect_write' function (not\nsubcommand!), whose third positional parameter was a \"nolog\" flag.\nThis flag was only used when 'bisect_start' invoked it to write the\nstarting good and bad revisions.  Then 0f30233a11 (bisect--helper:\n`bisect_write` shell function in C, 2019-01-02) ported it to C as a\ncommand mode of 'bisect--helper', and:\n\n  - Added the '--no-log' option, but since 'bisect--helper' has\n    command modes not subcommands, all other command modes see and\n    handle that option as well.\n  - Converted all callsites of 'bisect_write' to invocations of 'git\n    bisect--helper --bisect-write', but while doing so that one\n    callsite in 'bisect_start' was misconverted, and instead of\n    passing the '--no-log' option, it still passed 'nolog' as\n    parameter.  Consequently, 'git bisect start' wrote a couple of\n    extra lines to '.git/BISECT_LOG'.\n\nThis bogus state didn't last long, however, because in the same patch\nseries 06f5608c14 (bisect--helper: `bisect_start` shell function\npartially in C, 2019-01-02) the C reimplementation of bisect_start()\nstarted calling the bisect_write() C function, this time with the\nright 'nolog' function parameter.  From then on there was no need for\nthe '--no-log' option in 'bisect--helper'.  Eventually all bisect\nsubcommands were ported to C as 'bisect--helper' command modes, each\ncalling the bisect_write() C function instead, but when the\n'--bisect-write' command mode was removed in 68efed8c8a\n(bisect--helper: retire `--bisect-write` subcommand, 2021-02-03) it\nforgot to remove that '--no-log' option.\n\n\n"},{"id":"466506","messageId":"Y2UJNzA1n498pThw@coredump.intra.peff.net","threadId":"58746","inReplyTo":"20221104123722.GA6942@szeder.dev","subject":"Re: \"git bisect run\" strips \"--log\" from the list of arguments","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2022-11-04T12:44:39Z","receivedAt":"2022-11-04T12:44:45Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Fri, Nov 04, 2022 at 01:37:22PM +0100, SZEDER Gábor wrote:\n\n> This bogus state didn't last long, however, because in the same patch\n> series 06f5608c14 (bisect--helper: `bisect_start` shell function\n> partially in C, 2019-01-02) the C reimplementation of bisect_start()\n> started calling the bisect_write() C function, this time with the\n> right 'nolog' function parameter.  From then on there was no need for\n> the '--no-log' option in 'bisect--helper'.  Eventually all bisect\n> subcommands were ported to C as 'bisect--helper' command modes, each\n> calling the bisect_write() C function instead, but when the\n> '--bisect-write' command mode was removed in 68efed8c8a\n> (bisect--helper: retire `--bisect-write` subcommand, 2021-02-03) it\n> forgot to remove that '--no-log' option.\n\nYeah, but I don't think \"--log\" or \"--no-log\" is really the bug, is it?\n\nThe same thing happens if my command is \"echo --bisect-run\". Obviously\nthat's less likely, but the bug is still that we are parsing random\noptions out of the supposedly opaque command.\n\n-Peff\n"},{"id":"466507","messageId":"Y2UJaRdiciKMFpHU@coredump.intra.peff.net","threadId":"58746","inReplyTo":"221104.86zgd7x85r.gmgdl@evledraar.gmail.com","subject":"Re: \"git bisect run\" strips \"--log\" from the list of arguments","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2022-11-04T12:45:29Z","receivedAt":"2022-11-04T12:45:42Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Fri, Nov 04, 2022 at 12:36:12PM +0100, Ævar Arnfjörð Bjarmason wrote:\n\n> > It feels like the invocation of bisect--helper ought to be passing \"--\"\n> > itself to indicate the end of options, like:\n> \n> Normally you'd be righ, but there's a much easier way to do it in this\n> case: cherry-pick\n> https://lore.kernel.org/git/05262b6a7d1b20a0d2f2ca2090be284ffb8c679c.1661885419.git.gitgitgadget@gmail.com/\n> \n> I.e. we're eating \"--log\" in particular, but could just stop\n> understanding that option.\n\nWe're not eating \"--log\" in particular, though. We're eating anything\nthat parse_options() understands. It would eat \"--bisect-start\", too.\nThat's less likely than \"--log\", but the fundamental problem would still\nremain.\n\n-Peff\n"},{"id":"466508","messageId":"Y2UKzV7ptjMdHcfh@coredump.intra.peff.net","threadId":"58746","inReplyTo":"Y2Ty6KZT8iACqHf+@danh.dev","subject":"Re: \"git bisect run\" strips \"--log\" from the list of arguments","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2022-11-04T12:51:25Z","receivedAt":"2022-11-04T12:51:31Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Fri, Nov 04, 2022 at 06:10:02PM +0700, Đoàn Trần Công Danh wrote:\n\n> I think we should use OPT_SUBCOMMAND to parse bisect--helper\n> subcommand instead, which would pave ways for easier converting to\n> built-int git-bisect. This huge patch, which could be splited into\n> 2 patches can fix the problem:\n\nYeah, I haven't really dug into the subcommand stuff before, but I\nnoticed while poking at the low-level callback code that it may stop the\nparsing.\n\nIf so, then yes, I think that fixes the problem. But does it break other\nmodes, that want to be parsing \"--log\"? It sounds from other responses\nin the thread that no, nobody actually cares about the \"--log\" flag (and\nthat matches my reading of the code; nobody looks at the nolog variable\nwe set).\n\nThe other obvious problem with switching to subcommands is that it\nchanges the caller-visible name (to drop the \"--\"). But that should be\nOK here, as we make no promises about what's in helper command like\nbisect--helper.\n\nSo yeah, that does seem like a better path forward.\n\n-Peff\n"},{"id":"466509","messageId":"Y2ULXomMI7vcDuZO@coredump.intra.peff.net","threadId":"58746","inReplyTo":"489785ca45a84cffb4a2c16da15a09034829b7c6.1667561761.git.congdanhqx@gmail.com","subject":"Re: [PATCH 1/3] bisect--helper: remove unused options","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2022-11-04T12:53:50Z","receivedAt":"2022-11-04T12:53:56Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Fri, Nov 04, 2022 at 06:40:10PM +0700, Đoàn Trần Công Danh wrote:\n\n> diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\n> index 1d2ce8a0e1..5ec2e67f59 100644\n> --- a/builtin/bisect--helper.c\n> +++ b/builtin/bisect--helper.c\n> @@ -1283,7 +1283,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n>  {\n>  \tenum {\n>  \t\tBISECT_RESET = 1,\n> -\t\tBISECT_NEXT_CHECK,\n>  \t\tBISECT_TERMS,\n>  \t\tBISECT_START,\n>  \t\tBISECT_AUTOSTART,\n\nOK, makes sense. It might be nice to mention in the commit message how\nwe got here. It looks like the callers that used this went away in\nd1bbbe45df (bisect--helper: reimplement `bisect_run` shell function in\nC, 2021-09-13) and 5e1f28d206 (bisect--helper: reimplement\n`bisect_visualize()` shell function in C, 2021-09-13).\n\n> @@ -1319,8 +1316,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n>  \t\t\t N_(\"visualize the bisection\"), BISECT_VISUALIZE),\n>  \t\tOPT_CMDMODE(0, \"bisect-run\", &cmdmode,\n>  \t\t\t N_(\"use <cmd>... to automatically bisect\"), BISECT_RUN),\n> -\t\tOPT_BOOL(0, \"no-log\", &nolog,\n> -\t\t\t N_(\"no log for BISECT_WRITE\")),\n\nLikewise digging up the history here lets us see why removing is the\nright thing (and the bug is not that it _should_ be used and isn't).\nGábor posted a summary of the history elsewhere in the thread.\n\n-Peff\n"},{"id":"466510","messageId":"Y2ULud3Cladlz2rZ@coredump.intra.peff.net","threadId":"58746","inReplyTo":"081f3f7f9501012404fb9e59ab6d94f632180b53.1667561761.git.congdanhqx@gmail.com","subject":"Re: [PATCH 2/3] bisect--helper: move all subcommands into their own functions","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2022-11-04T12:55:21Z","receivedAt":"2022-11-04T12:55:26Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Fri, Nov 04, 2022 at 06:40:11PM +0700, Đoàn Trần Công Danh wrote:\n\n> In a later change, we will use OPT_SUBCOMMAND to parse sub-commands to\n> avoid consuming non-option opts.\n> \n> Since OPT_SUBCOMMAND needs a function pointer to operate,\n> let's move it now.\n\nMakes sense, and splitting this into its own step makes it easier to\nverify.\n\n> +static int cmd_bisect__reset(int argc, const char **argv, const char *prefix UNUSED)\n\nThank you very much for putting the UNUSED markers here. It will save me\nthe trouble of handling it on my topic. :)\n\n-Peff\n"},{"id":"466511","messageId":"Y2UM6S+QUFkhz5d4@coredump.intra.peff.net","threadId":"58746","inReplyTo":"76c585d22bf415e719762fcf5decf4b71efa5bfb.1667561761.git.congdanhqx@gmail.com","subject":"Re: [PATCH 3/3] bisect--helper: parse subcommand with OPT_SUBCOMMAND","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2022-11-04T13:00:25Z","receivedAt":"2022-11-04T13:00:39Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Fri, Nov 04, 2022 at 06:40:12PM +0700, Đoàn Trần Công Danh wrote:\n\n> As of it is, we're parsing subcommand with OPT_CMDMODE, which will\n> continue to parse more options even if the command has been found.\n> \n> When we're running \"git bisect run\" with a command that expecting\n> a \"--log\" or \"--no-log\" arguments, or one of those \"--bisect-...\"\n> arguments, bisect--helper may mistakenly think those options are\n> bisect--helper's option.\n\nRight.\n\n> We may fix those problems by passing \"--\" when calling from\n> git-bisect.sh, and skip that \"--\" in bisect--helper. However, it may\n> interfere with user's \"--\".\n\nI think it won't interfere. A user can't put \"--\" as a separator now; it\ngets taken as part of the command. So if we consistently added one in\nthe caller and stripped it away in bisect--helper, that would work\ncorrectly (and if the user did have one later in their command, it would\nbe preserved as it is now).\n\nThat said, I do think your solution is nicer, and is potentially fixing\nsimilar problems in other subcommand modes, too.\n\n> Let's parse subcommand with OPT_SUBCOMMAND since that API was born for\n> this specific use-case.\n\nThe implication here being that OPT_SUBCOMMAND stops parsing as soon as\nit hits a subcommand, I assume.\n\n>  builtin/bisect--helper.c    | 86 +++++++------------------------------\n>  git-bisect.sh               | 20 ++++-----\n\nThe patch here looks sensible, but...\n\n> +# We want to make sure --log is not eaten\n> +test_expect_success '\"git bisect run\" simple case' '\n> +\tgit bisect start &&\n> +\tgit bisect good $HASH1 &&\n> +\tgit bisect bad $HASH4 &&\n> +\tgit bisect run printf \"%s\\n\" --log >my_bisect_log.txt &&\n> +\tgrep -e --log my_bisect_log.txt &&\n> +\tgit bisect reset\n> +'\n\n...since you removed --log in the first commit, I think this would pass\neven before this patch. You'd need to use another option like\n--bisect-reset to show the problem. Of course then it is trivial that\nthe patch fixes it, since \"--bisect-reset\" becomes \"bisect-reset\"\nafterwards. So there are no options left to parse at that point. But it\nwould be the best we could do to demonstrate it.\n\n-Peff\n"},{"id":"466513","messageId":"221104.86v8nuyiid.gmgdl@evledraar.gmail.com","threadId":"58746","inReplyTo":"Y2UJaRdiciKMFpHU@coredump.intra.peff.net","subject":"Re: \"git bisect run\" strips \"--log\" from the list of arguments","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-04T13:07:48Z","receivedAt":"2022-11-04T13:08:35Z","isPatch":false,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Fri, Nov 04 2022, Jeff King wrote:\n\n> On Fri, Nov 04, 2022 at 12:36:12PM +0100, Ævar Arnfjörð Bjarmason wrote:\n>\n>> > It feels like the invocation of bisect--helper ought to be passing \"--\"\n>> > itself to indicate the end of options, like:\n>> \n>> Normally you'd be righ, but there's a much easier way to do it in this\n>> case: cherry-pick\n>> https://lore.kernel.org/git/05262b6a7d1b20a0d2f2ca2090be284ffb8c679c.1661885419.git.gitgitgadget@gmail.com/\n>> \n>> I.e. we're eating \"--log\" in particular, but could just stop\n>> understanding that option.\n>\n> We're not eating \"--log\" in particular, though. We're eating anything\n> that parse_options() understands. It would eat \"--bisect-start\", too.\n> That's less likely than \"--log\", but the fundamental problem would still\n> remain.\n\nRight, I mean the regression's anyone's likely to care\nabout. I.e. that's an easy fix, I think run scripts using --bisect-*\noptions are probably unlikely to exist.\n\nBut yes, the ultimate fix is to use OPT_SUBCOMMAND(), but getting there\ntakes more time...\n"},{"id":"466515","messageId":"cover-00.13-00000000000-20221104T132117Z-avarab@gmail.com","threadId":"58746","inReplyTo":"1cb1c033-0525-7e62-8c09-81019bf26060@redhat.com","subject":"[PATCH 00/13] bisect: v2.30.0 \"run\" regressions + make it built-in","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-04T13:22:37Z","receivedAt":"2022-11-04T13:26:28Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"This fixes the regression Lukáš Doktor reported in [1], and also gets\nus the full way to a builtin/bisect.c and \"git rm git-bisect.sh\".\n\nOnly 1-4/13 here are needed to fix the \"git bisect run <cmd> [...]\n--log\" regression Lukáš reported, but as Jeff points out we'd still\nconflate \"--bisect-*\" with the user arguments. That's fixed in 11/13\nhere.\n\nThe 1-4/13 here also fixes other but probably more minor \"git bisect\nrun\" regressions in v2.30.0, we changed the output in a few ways\nwithout intending it. 4/13 gets us mostly back to v2.29.0 behavior,\n5/13 keeps the best of it and the current output.\n\nI think for the v2.30.0 regressions we're better off with just\nsomething like 1-4/13 here for now, and possibly 5/13 too.\n\nBut getting to the point of fixing the root cause of \"--bisect-*\"\nbeing conflated is going to take quite a bit of churn. In the\nside-thread Đoàn's diffstat is on the order of 1/2 of the size of this\nseries, and this gives us built-in \"bisect\".\n\nThe 6-13 here is something I had already for a couple of days, I was\nseeing if I could distill Johannes's [2] down to something much\nsmaller, to just make a beeline towards a built-in bisect.\n\nJohannes's refactors the \"term\" passing in [3], and Đoàn ends up\nneeding to do much the same in [4].\n\nHere in 9/13 I instead just extend the OPT_SUBCOMMAND() API so it's\nable to accept function callbacks with custom signatures, which\neliminates the need for most of that refactoring. 11/13 then makes use\nof it.\n\n1. https://lore.kernel.org/git/1cb1c033-0525-7e62-8c09-81019bf26060@redhat.com/\n2. https://lore.kernel.org/git/pull.1132.v6.git.1661885419.gitgitgadget@gmail.com/\n3. https://lore.kernel.org/git/92b3b116ef8f879192d9deb94d68b73e29d5dcd6.1661885419.git.gitgitgadget@gmail.com/\n4. https://lore.kernel.org/git/081f3f7f9501012404fb9e59ab6d94f632180b53.1667561761.git.congdanhqx@gmail.com/\n\nJohannes Schindelin (3):\n  bisect--helper: remove dead --bisect-{next-check,autostart} code\n  bisect--helper: make `state` optional\n  Turn `git bisect` into a full built-in\n\nÆvar Arnfjörð Bjarmason (10):\n  bisect tests: test for v2.30.0 \"bisect run\" regressions\n  bisect: refactor bisect_run() to match CodingGuidelines\n  bisect: fix output regressions in v2.30.0\n  bisect run: fix \"--log\" eating regression in v2.30.0\n  bisect run: keep some of the post-v2.30.0 output\n  bisect test: test exit codes on bad usage\n  bisect--helper: emit usage for \"git bisect\"\n  bisect--helper: have all functions take state, argc, argv, prefix\n  parse-options API: don't restrict OPT_SUBCOMMAND() to one *_fn  type\n  bisect--helper: convert to OPT_SUBCOMMAND_CB()\n\n Makefile                               |   3 +-\n builtin.h                              |   2 +-\n builtin/{bisect--helper.c => bisect.c} | 250 +++++++++++++------------\n git-bisect.sh                          |  84 ---------\n git.c                                  |   2 +-\n parse-options.c                        |   9 +-\n parse-options.h                        |  31 ++-\n t/t6030-bisect-porcelain.sh            | 109 +++++++++++\n 8 files changed, 277 insertions(+), 213 deletions(-)\n rename builtin/{bisect--helper.c => bisect.c} (86%)\n delete mode 100755 git-bisect.sh\n\n-- \n2.38.0.1452.g710f45c7951\n\n"},{"id":"466516","messageId":"patch-01.13-beb1ea22a27-20221104T132117Z-avarab@gmail.com","threadId":"58746","inReplyTo":"cover-00.13-00000000000-20221104T132117Z-avarab@gmail.com","subject":"[PATCH 01/13] bisect tests: test for v2.30.0 \"bisect run\" regressions","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-04T13:22:38Z","receivedAt":"2022-11-04T13:26:28Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Add three failing tests which succeed on v2.29.0, but due to the topic\nmerged at [1] (specifically [2]) have been failing since then. We'll\naddress those regressions in subsequent commits.\n\nThere was also a \"regression\" where:\n\n\tgit bisect run ./missing-script.sh\n\nWould count a non-existing script as \"good\", as the shell would exit\nwith 127. That edge case is a bit too insane to preserve, so let's not\nadd it to these regression tests.\n\n1. 0a4cb1f1f2f (Merge branch 'mr/bisect-in-c-4', 2021-09-23)\n2. d1bbbe45df8 (bisect--helper: reimplement `bisect_run` shell\n   function in C, 2021-09-13)\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t6030-bisect-porcelain.sh | 79 +++++++++++++++++++++++++++++++++++++\n 1 file changed, 79 insertions(+)\n\ndiff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh\nindex 83931d482fb..478e74e1f0f 100755\n--- a/t/t6030-bisect-porcelain.sh\n+++ b/t/t6030-bisect-porcelain.sh\n@@ -252,6 +252,85 @@ test_expect_success 'bisect skip: with commit both bad and skipped' '\n \tgrep $HASH4 my_bisect_log.txt\n '\n \n+test_bisect_run_args () {\n+\ttest_when_finished \"rm -f run.sh actual\" &&\n+\t>actual &&\n+\tcat >expect.args &&\n+\tcat <&6 >expect.out &&\n+\tcat <&7 >expect.err &&\n+\twrite_script run.sh <<-\\EOF &&\n+\twhile test $# != 0\n+\tdo\n+\t\techo \"<$1>\" &&\n+\t\tshift\n+\tdone >actual.args\n+\tEOF\n+\n+\ttest_when_finished \"git bisect reset\" &&\n+\tgit bisect start &&\n+\tgit bisect good $HASH1 &&\n+\tgit bisect bad $HASH4 &&\n+\tgit bisect run ./run.sh $@ >actual.out.raw 2>actual.err &&\n+\t# Prune just the log output\n+\tsed -n \\\n+\t\t-e '/^Author:/d' \\\n+\t\t-e '/^Date:/d' \\\n+\t\t-e '/^$/d' \\\n+\t\t-e '/^commit /d' \\\n+ \t\t-e '/^ /d' \\\n+\t\t-e 'p' \\\n+\t\t<actual.out.raw >actual.out &&\n+\ttest_cmp expect.out actual.out &&\n+\ttest_cmp expect.err actual.err &&\n+\ttest_cmp expect.args actual.args\n+}\n+\n+test_expect_failure 'git bisect run: args, stdout and stderr with no arguments' '\n+\ttest_bisect_run_args <<-\\EOF_ARGS 6<<-EOF_OUT 7<<-\\EOF_ERR\n+\tEOF_ARGS\n+\trunning ./run.sh\n+\t$HASH4 is the first bad commit\n+\tbisect run success\n+\tEOF_OUT\n+\tEOF_ERR\n+'\n+\n+test_expect_failure 'git bisect run: args, stdout and stderr: \"--\" argument' '\n+\ttest_bisect_run_args -- <<-\\EOF_ARGS 6<<-EOF_OUT 7<<-\\EOF_ERR\n+\t<-->\n+\tEOF_ARGS\n+\trunning ./run.sh --\n+\t$HASH4 is the first bad commit\n+\tbisect run success\n+\tEOF_OUT\n+\tEOF_ERR\n+'\n+\n+test_expect_failure 'git bisect run: args, stdout and stderr: \"--log foo --no-log bar\" arguments' '\n+\ttest_bisect_run_args --log foo --no-log bar <<-\\EOF_ARGS 6<<-EOF_OUT 7<<-\\EOF_ERR\n+\t<--log>\n+\t<foo>\n+\t<--no-log>\n+\t<bar>\n+\tEOF_ARGS\n+\trunning ./run.sh --log foo --no-log bar\n+\t$HASH4 is the first bad commit\n+\tbisect run success\n+\tEOF_OUT\n+\tEOF_ERR\n+'\n+\n+test_expect_failure 'git bisect run: args, stdout and stderr: \"--bisect-start\" argument' '\n+\ttest_bisect_run_args --bisect-start <<-\\EOF_ARGS 6<<-EOF_OUT 7<<-\\EOF_ERR\n+\t<--bisect-start>\n+\tEOF_ARGS\n+\trunning ./run.sh --bisect-start\n+\t$HASH4 is the first bad commit\n+\tbisect run success\n+\tEOF_OUT\n+\tEOF_ERR\n+'\n+\n # We want to automatically find the commit that\n # added \"Another\" into hello.\n test_expect_success '\"git bisect run\" simple case' '\n-- \n2.38.0.1452.g710f45c7951\n\n"},{"id":"466517","messageId":"patch-02.13-4af93ec9aa3-20221104T132117Z-avarab@gmail.com","threadId":"58746","inReplyTo":"cover-00.13-00000000000-20221104T132117Z-avarab@gmail.com","subject":"[PATCH 02/13] bisect: refactor bisect_run() to match CodingGuidelines","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-04T13:22:39Z","receivedAt":"2022-11-04T13:26:28Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"We didn't add \"{}\" to all \"if/else\" branches, and one \"error\" was\nmis-indented. Let's fix that first, which makes subsequent commits\nsmaller. In the case of the \"if\" we can simply early return instead.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/bisect--helper.c | 7 +++----\n 1 file changed, 3 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 28ef7ec2a48..7dd90da72d3 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1185,13 +1185,12 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n \tif (bisect_next_check(terms, NULL))\n \t\treturn BISECT_FAILED;\n \n-\tif (argc)\n-\t\tsq_quote_argv(&command, argv);\n-\telse {\n+\tif (!argc) {\n \t\terror(_(\"bisect run failed: no command provided.\"));\n \t\treturn BISECT_FAILED;\n \t}\n \n+\tsq_quote_argv(&command, argv);\n \tstrvec_push(&run_args, command.buf);\n \n \twhile (1) {\n@@ -1265,7 +1264,7 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n \t\t\tres = BISECT_OK;\n \t\t} else if (res) {\n \t\t\terror(_(\"bisect run failed: 'git bisect--helper --bisect-state\"\n-\t\t\t\" %s' exited with error code %d\"), new_state, res);\n+\t\t\t\t\" %s' exited with error code %d\"), new_state, res);\n \t\t} else {\n \t\t\tcontinue;\n \t\t}\n-- \n2.38.0.1452.g710f45c7951\n\n"},{"id":"466518","messageId":"patch-04.13-b10deee4827-20221104T132117Z-avarab@gmail.com","threadId":"58746","inReplyTo":"cover-00.13-00000000000-20221104T132117Z-avarab@gmail.com","subject":"[PATCH 04/13] bisect run: fix \"--log\" eating regression in v2.30.0","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-04T13:22:41Z","receivedAt":"2022-11-04T13:26:28Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"When d1bbbe45df8 (bisect--helper: reimplement `bisect_run` shell\nfunction in C, 2021-09-13) reimplemented parts of \"git bisect run\" in\nC we started parsing the command line that we'd pass to \"run\" with\ncmd_bisect__helper().\n\nUnfortunately this meant that we started eating \"--log\" and \"--no-log\"\non the command-line.\n\nIn the general case the fix for this would be more involved, but\nluckily we don't support any other option here (well, the other\nCMDMODE options, but that edge case is too obscure to worry about).\n\nAs noted in [1] we can simply remove the \"--no-log\" option. It was\nadded in 0f30233a11f (bisect--helper: `bisect_write` shell function in\nC, 2019-01-02), but has never been used.\n\nReported-by: Lukáš Doktor <ldoktor@redhat.com>\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/bisect--helper.c    | 4 +---\n t/t6030-bisect-porcelain.sh | 2 +-\n 2 files changed, 2 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex ee1509c198a..eb66ad491cd 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1294,7 +1294,7 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\tBISECT_VISUALIZE,\n \t\tBISECT_RUN,\n \t} cmdmode = 0;\n-\tint res = 0, nolog = 0;\n+\tint res = 0;\n \tstruct option options[] = {\n \t\tOPT_CMDMODE(0, \"bisect-reset\", &cmdmode,\n \t\t\t N_(\"reset the bisection state\"), BISECT_RESET),\n@@ -1318,8 +1318,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\t\t N_(\"visualize the bisection\"), BISECT_VISUALIZE),\n \t\tOPT_CMDMODE(0, \"bisect-run\", &cmdmode,\n \t\t\t N_(\"use <cmd>... to automatically bisect\"), BISECT_RUN),\n-\t\tOPT_BOOL(0, \"no-log\", &nolog,\n-\t\t\t N_(\"no log for BISECT_WRITE\")),\n \t\tOPT_END()\n \t};\n \tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\ndiff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh\nindex 30124b6f059..dc83034f036 100755\n--- a/t/t6030-bisect-porcelain.sh\n+++ b/t/t6030-bisect-porcelain.sh\n@@ -306,7 +306,7 @@ test_expect_success 'git bisect run: args, stdout and stderr: \"--\" argument' '\n \tEOF_ERR\n '\n \n-test_expect_failure 'git bisect run: args, stdout and stderr: \"--log foo --no-log bar\" arguments' '\n+test_expect_success 'git bisect run: args, stdout and stderr: \"--log foo --no-log bar\" arguments' '\n \ttest_bisect_run_args --log foo --no-log bar <<-\\EOF_ARGS 6<<-EOF_OUT 7<<-\\EOF_ERR\n \t<--log>\n \t<foo>\n-- \n2.38.0.1452.g710f45c7951\n\n"},{"id":"466519","messageId":"patch-03.13-03d704ca26f-20221104T132117Z-avarab@gmail.com","threadId":"58746","inReplyTo":"cover-00.13-00000000000-20221104T132117Z-avarab@gmail.com","subject":"[PATCH 03/13] bisect: fix output regressions in v2.30.0","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-04T13:22:40Z","receivedAt":"2022-11-04T13:26:28Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"When d1bbbe45df8 (bisect--helper: reimplement `bisect_run` shell\nfunction in C, 2021-09-13) reimplemented parts of \"git bisect run\" in\nC it changed the output we emitted so that:\n\n - The \"running ...\" line was now quoted\n - We lost the \\n after our output\n - We started saying \"bisect found ...\" instead of \"bisect run success\"\n\nArguably some of this is better now, but as d1bbbe45df8 did not\nadvocate for changing the output, let's revert this for now. It'll be\neasy to change it back if that's what we'd prefer.\n\nThis does not change the one remaining use of \"command.buf\" to emit\nthe quoted argument, as that's new in d1bbbe45df8.\n\nSome of these cases were not tested for in the tests added in the\npreceding commit, I didn't have time to fleshen those out, but a look\nat f1de981e8b6 will show that the other output being adjusted here is\nnow equivalent to what it was before d1bbbe45df8.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/bisect--helper.c    | 8 +++++---\n t/t6030-bisect-porcelain.sh | 4 ++--\n 2 files changed, 7 insertions(+), 5 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 7dd90da72d3..ee1509c198a 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1192,6 +1192,8 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n \n \tsq_quote_argv(&command, argv);\n \tstrvec_push(&run_args, command.buf);\n+\tstrbuf_reset(&command);\n+\tstrbuf_join_argv(&command, argc, argv, ' ');\n \n \twhile (1) {\n \t\tprintf(_(\"running %s\\n\"), command.buf);\n@@ -1257,13 +1259,13 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n \t\tif (res == BISECT_ONLY_SKIPPED_LEFT)\n \t\t\terror(_(\"bisect run cannot continue any more\"));\n \t\telse if (res == BISECT_INTERNAL_SUCCESS_MERGE_BASE) {\n-\t\t\tprintf(_(\"bisect run success\"));\n+\t\t\tputs(_(\"bisect run success\"));\n \t\t\tres = BISECT_OK;\n \t\t} else if (res == BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND) {\n-\t\t\tprintf(_(\"bisect found first bad commit\"));\n+\t\t\tputs(_(\"bisect run success\"));\n \t\t\tres = BISECT_OK;\n \t\t} else if (res) {\n-\t\t\terror(_(\"bisect run failed: 'git bisect--helper --bisect-state\"\n+\t\t\terror(_(\"bisect run failed: 'bisect-state\"\n \t\t\t\t\" %s' exited with error code %d\"), new_state, res);\n \t\t} else {\n \t\t\tcontinue;\ndiff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh\nindex 478e74e1f0f..30124b6f059 100755\n--- a/t/t6030-bisect-porcelain.sh\n+++ b/t/t6030-bisect-porcelain.sh\n@@ -285,7 +285,7 @@ test_bisect_run_args () {\n \ttest_cmp expect.args actual.args\n }\n \n-test_expect_failure 'git bisect run: args, stdout and stderr with no arguments' '\n+test_expect_success 'git bisect run: args, stdout and stderr with no arguments' '\n \ttest_bisect_run_args <<-\\EOF_ARGS 6<<-EOF_OUT 7<<-\\EOF_ERR\n \tEOF_ARGS\n \trunning ./run.sh\n@@ -295,7 +295,7 @@ test_expect_failure 'git bisect run: args, stdout and stderr with no arguments'\n \tEOF_ERR\n '\n \n-test_expect_failure 'git bisect run: args, stdout and stderr: \"--\" argument' '\n+test_expect_success 'git bisect run: args, stdout and stderr: \"--\" argument' '\n \ttest_bisect_run_args -- <<-\\EOF_ARGS 6<<-EOF_OUT 7<<-\\EOF_ERR\n \t<-->\n \tEOF_ARGS\n-- \n2.38.0.1452.g710f45c7951\n\n"},{"id":"466520","messageId":"patch-05.13-30626dd507a-20221104T132117Z-avarab@gmail.com","threadId":"58746","inReplyTo":"cover-00.13-00000000000-20221104T132117Z-avarab@gmail.com","subject":"[PATCH 05/13] bisect run: keep some of the post-v2.30.0 output","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-04T13:22:42Z","receivedAt":"2022-11-04T13:26:31Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Preceding commits fixed output and behavior regressions in\nd1bbbe45df8 (bisect--helper: reimplement `bisect_run` shell function\nin C, 2021-09-13), which did not claim to be changing the output of\n\"git bisect run\".\n\nBut some of the output it emitted was subjectively better, so once\nwe've asserted that we're back on v2.29.0 behavior, let's change some\nof it back:\n\n- We now quote the arguments again, but omit the first \" \" when\n  printing the \"running\" line.\n- Ditto for other cases where we emitted the argument\n- We say \"found first bad commit\" again, not just \"run success\"\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/bisect--helper.c    |  6 +++---\n t/t6030-bisect-porcelain.sh | 16 ++++++++--------\n 2 files changed, 11 insertions(+), 11 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex eb66ad491cd..5c0572d0672 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1192,8 +1192,8 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n \n \tsq_quote_argv(&command, argv);\n \tstrvec_push(&run_args, command.buf);\n-\tstrbuf_reset(&command);\n-\tstrbuf_join_argv(&command, argc, argv, ' ');\n+\t/* Quoted, but skip initial \" \" */\n+\tstrbuf_ltrim(&command);\n \n \twhile (1) {\n \t\tprintf(_(\"running %s\\n\"), command.buf);\n@@ -1262,7 +1262,7 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n \t\t\tputs(_(\"bisect run success\"));\n \t\t\tres = BISECT_OK;\n \t\t} else if (res == BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND) {\n-\t\t\tputs(_(\"bisect run success\"));\n+\t\t\tputs(_(\"bisect found first bad commit\"));\n \t\t\tres = BISECT_OK;\n \t\t} else if (res) {\n \t\t\terror(_(\"bisect run failed: 'bisect-state\"\ndiff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh\nindex dc83034f036..69fad3f94f6 100755\n--- a/t/t6030-bisect-porcelain.sh\n+++ b/t/t6030-bisect-porcelain.sh\n@@ -288,9 +288,9 @@ test_bisect_run_args () {\n test_expect_success 'git bisect run: args, stdout and stderr with no arguments' '\n \ttest_bisect_run_args <<-\\EOF_ARGS 6<<-EOF_OUT 7<<-\\EOF_ERR\n \tEOF_ARGS\n-\trunning ./run.sh\n+\trunning '\\''./run.sh'\\''\n \t$HASH4 is the first bad commit\n-\tbisect run success\n+\tbisect found first bad commit\n \tEOF_OUT\n \tEOF_ERR\n '\n@@ -299,9 +299,9 @@ test_expect_success 'git bisect run: args, stdout and stderr: \"--\" argument' '\n \ttest_bisect_run_args -- <<-\\EOF_ARGS 6<<-EOF_OUT 7<<-\\EOF_ERR\n \t<-->\n \tEOF_ARGS\n-\trunning ./run.sh --\n+\trunning '\\''./run.sh'\\'' '\\''--'\\''\n \t$HASH4 is the first bad commit\n-\tbisect run success\n+\tbisect found first bad commit\n \tEOF_OUT\n \tEOF_ERR\n '\n@@ -313,9 +313,9 @@ test_expect_success 'git bisect run: args, stdout and stderr: \"--log foo --no-lo\n \t<--no-log>\n \t<bar>\n \tEOF_ARGS\n-\trunning ./run.sh --log foo --no-log bar\n+\trunning '\\''./run.sh'\\'' '\\''--log'\\'' '\\''foo'\\'' '\\''--no-log'\\'' '\\''bar'\\''\n \t$HASH4 is the first bad commit\n-\tbisect run success\n+\tbisect found first bad commit\n \tEOF_OUT\n \tEOF_ERR\n '\n@@ -324,9 +324,9 @@ test_expect_failure 'git bisect run: args, stdout and stderr: \"--bisect-start\" a\n \ttest_bisect_run_args --bisect-start <<-\\EOF_ARGS 6<<-EOF_OUT 7<<-\\EOF_ERR\n \t<--bisect-start>\n \tEOF_ARGS\n-\trunning ./run.sh --bisect-start\n+\trunning '\\''./run.sh'\\'' '\\''--bisect-start'\\''\n \t$HASH4 is the first bad commit\n-\tbisect run success\n+\tbisect found first bad commit\n \tEOF_OUT\n \tEOF_ERR\n '\n-- \n2.38.0.1452.g710f45c7951\n\n"},{"id":"466521","messageId":"patch-06.13-e2a69bf8f3b-20221104T132117Z-avarab@gmail.com","threadId":"58746","inReplyTo":"cover-00.13-00000000000-20221104T132117Z-avarab@gmail.com","subject":"[PATCH 06/13] bisect test: test exit codes on bad usage","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-04T13:22:43Z","receivedAt":"2022-11-04T13:26:35Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Address a test blindspot, the \"log\" command is the odd one out because\n\"git-bisect.sh\" ignores any arguments it receives. Let's test both the\nexit codes we expect, and the stderr and stdout we're emitting.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t6030-bisect-porcelain.sh | 30 ++++++++++++++++++++++++++++++\n 1 file changed, 30 insertions(+)\n\ndiff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh\nindex 69fad3f94f6..eace0af637e 100755\n--- a/t/t6030-bisect-porcelain.sh\n+++ b/t/t6030-bisect-porcelain.sh\n@@ -34,6 +34,36 @@ HASH2=\n HASH3=\n HASH4=\n \n+test_bisect_usage () {\n+\tlocal code=\"$1\" &&\n+\tshift &&\n+\tcat >expect &&\n+\ttest_expect_code $code \"$@\" >out 2>actual &&\n+\ttest_must_be_empty out &&\n+\ttest_cmp expect actual\n+}\n+\n+test_expect_success 'bisect usage' '\n+\ttest_bisect_usage 255 git bisect reset extra1 extra2 <<-\\EOF &&\n+\terror: --bisect-reset requires either no argument or a commit\n+\tEOF\n+\ttest_bisect_usage 255 git bisect terms extra1 extra2 <<-\\EOF &&\n+\terror: --bisect-terms requires 0 or 1 argument\n+\tEOF\n+\ttest_bisect_usage 255 git bisect next extra1 <<-\\EOF &&\n+\terror: --bisect-next requires 0 arguments\n+\tEOF\n+\ttest_bisect_usage 1 git bisect log extra1 <<-\\EOF &&\n+\terror: We are not bisecting.\n+\tEOF\n+\ttest_bisect_usage 255 git bisect replay <<-\\EOF &&\n+\terror: no logfile given\n+\tEOF\n+\ttest_bisect_usage 255 git bisect run <<-\\EOF\n+\terror: bisect run failed: no command provided.\n+\tEOF\n+'\n+\n test_expect_success 'set up basic repo with 1 file (hello) and 4 commits' '\n      add_line_into_file \"1: Hello World\" hello &&\n      HASH1=$(git rev-parse --verify HEAD) &&\n-- \n2.38.0.1452.g710f45c7951\n\n"},{"id":"466522","messageId":"patch-07.13-8a78b37dd56-20221104T132117Z-avarab@gmail.com","threadId":"58746","inReplyTo":"cover-00.13-00000000000-20221104T132117Z-avarab@gmail.com","subject":"[PATCH 07/13] bisect--helper: emit usage for \"git bisect\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-04T13:22:44Z","receivedAt":"2022-11-04T13:26:37Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"In subsequent commits we'll be removing \"git-bisect.sh\" in favor of\npromoting \"bisect--helper\" to a \"bisect\" built-in.\n\nIn doing that we'll first need to have it support \"git bisect--helper\n<cmd>\" rather than \"git bisect--helper --<cmd>\", and then finally have\nits \"-h\" output claim to be \"bisect\" rather than \"bisect--helper\".\n\nInstead of suffering that churn let's start claiming to be \"git\nbisect\" now. In just a few commits this will be true, and in the\nmeantime emitting the \"wrong\" usage information from the helper is a\nsmall price to pay to avoid the churn.\n\nLet's also declare \"BUILTIN_*\" macros, when we eventually migrate the\nsub-commands themselves to parse_options() we'll be able to re-use the\nstrings. See 0afd556b2e1 (worktree: define subcommand -h in terms of\ncommand -h, 2022-10-13) for a recent example.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/bisect--helper.c | 51 ++++++++++++++++++++++++++++------------\n 1 file changed, 36 insertions(+), 15 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 5c0572d0672..b10ecee64cc 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -20,18 +20,40 @@ static GIT_PATH_FUNC(git_path_bisect_names, \"BISECT_NAMES\")\n static GIT_PATH_FUNC(git_path_bisect_first_parent, \"BISECT_FIRST_PARENT\")\n static GIT_PATH_FUNC(git_path_bisect_run, \"BISECT_RUN\")\n \n-static const char * const git_bisect_helper_usage[] = {\n-\tN_(\"git bisect--helper --bisect-reset [<commit>]\"),\n-\t\"git bisect--helper --bisect-terms [--term-good | --term-old | --term-bad | --term-new]\",\n-\tN_(\"git bisect--helper --bisect-start [--term-{new,bad}=<term> --term-{old,good}=<term>]\"\n-\t\t\t\t\t    \" [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<paths>...]\"),\n-\t\"git bisect--helper --bisect-next\",\n-\tN_(\"git bisect--helper --bisect-state (bad|new) [<rev>]\"),\n-\tN_(\"git bisect--helper --bisect-state (good|old) [<rev>...]\"),\n-\tN_(\"git bisect--helper --bisect-replay <filename>\"),\n-\tN_(\"git bisect--helper --bisect-skip [(<rev>|<range>)...]\"),\n-\t\"git bisect--helper --bisect-visualize\",\n-\tN_(\"git bisect--helper --bisect-run <cmd>...\"),\n+#define BUILTIN_GIT_BISECT_START_USAGE \\\n+\tN_(\"git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>]\" \\\n+\t   \"    [--no-checkout] [--first-parent] [<bad> [<good>...]] [--]\" \\\n+\t   \"    [<pathspec>...]\")\n+#define BUILTIN_GIT_BISECT_STATE_USAGE \\\n+\tN_(\"git bisect (good|bad) [<rev>...]\")\n+#define BUILTIN_GIT_BISECT_TERMS_USAGE \\\n+\t\"git bisect terms [--term-good | --term-bad]\"\n+#define BUILTIN_GIT_BISECT_SKIP_USAGE \\\n+\tN_(\"git bisect skip [(<rev>|<range>)...]\")\n+#define BUILTIN_GIT_BISECT_NEXT_USAGE \\\n+\t\"git bisect next\"\n+#define BUILTIN_GIT_BISECT_RESET_USAGE \\\n+\tN_(\"git bisect reset [<commit>]\")\n+#define BUILTIN_GIT_BISECT_VISUALIZE_USAGE \\\n+\t\"git bisect visualize\"\n+#define BUILTIN_GIT_BISECT_REPLAY_USAGE \\\n+\tN_(\"git bisect replay <logfile>\")\n+#define BUILTIN_GIT_BISECT_LOG_USAGE \\\n+\t\"git bisect log\"\n+#define BUILTIN_GIT_BISECT_RUN_USAGE \\\n+\tN_(\"git bisect run <cmd>...\")\n+\n+static const char * const git_bisect_usage[] = {\n+\tBUILTIN_GIT_BISECT_START_USAGE,\n+\tBUILTIN_GIT_BISECT_STATE_USAGE,\n+\tBUILTIN_GIT_BISECT_TERMS_USAGE,\n+\tBUILTIN_GIT_BISECT_SKIP_USAGE,\n+\tBUILTIN_GIT_BISECT_NEXT_USAGE,\n+\tBUILTIN_GIT_BISECT_RESET_USAGE,\n+\tBUILTIN_GIT_BISECT_VISUALIZE_USAGE,\n+\tBUILTIN_GIT_BISECT_REPLAY_USAGE,\n+\tBUILTIN_GIT_BISECT_LOG_USAGE,\n+\tBUILTIN_GIT_BISECT_RUN_USAGE,\n \tNULL\n };\n \n@@ -1322,12 +1344,11 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t};\n \tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\n \n-\targc = parse_options(argc, argv, prefix, options,\n-\t\t\t     git_bisect_helper_usage,\n+\targc = parse_options(argc, argv, prefix, options, git_bisect_usage,\n \t\t\t     PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN_OPT);\n \n \tif (!cmdmode)\n-\t\tusage_with_options(git_bisect_helper_usage, options);\n+\t\tusage_with_options(git_bisect_usage, options);\n \n \tswitch (cmdmode) {\n \tcase BISECT_RESET:\n-- \n2.38.0.1452.g710f45c7951\n\n"},{"id":"466523","messageId":"patch-09.13-2cb3807aa17-20221104T132117Z-avarab@gmail.com","threadId":"58746","inReplyTo":"cover-00.13-00000000000-20221104T132117Z-avarab@gmail.com","subject":"[PATCH 09/13] parse-options API: don't restrict OPT_SUBCOMMAND() to one *_fn type","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-04T13:22:46Z","receivedAt":"2022-11-04T13:26:40Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"When the OPT_SUBCOMMAND() API was implemented in [1] it did so by\nadding a new \"subcommand_fn\" member to \"struct option\", rather than\nallowing the user of the API to pick the type of the function.\n\nAn advantage of mandating that \"parse_opt_subcommand_fn\" must be used\nis that we'll get type checking for the function we're passing in, a\ndisadvantage is that we can't convert e.g. \"builtin/bisect--helper.c\"\neasily to it, as its callbacks need their own argument.\n\nLet's generalize this interface, while leaving in place a small hack\nto give the existing API users their type safety. We assign to\n\"typecheck_subcommand_fn\", but don't subsequently use it for\nanything. Instead we use the \"defval\" and \"value\" members.\n\nA subsequent commit will add a OPT_SUBCOMMAND() variant where the\n\"callback\" isn't our default \"parse_options_pick_subcommand\" (and that\ncaller won't be able to use the type checking).\n\n1. fa83cc834da (parse-options: add support for parsing subcommands,\n   2022-08-19)\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n parse-options.c |  9 ++++++---\n parse-options.h | 25 +++++++++++++++++++++----\n 2 files changed, 27 insertions(+), 7 deletions(-)\n\ndiff --git a/parse-options.c b/parse-options.c\nindex a1ec932f0f9..1d9e46c9dc7 100644\n--- a/parse-options.c\n+++ b/parse-options.c\n@@ -427,7 +427,8 @@ static enum parse_opt_result parse_subcommand(const char *arg,\n \tfor (; options->type != OPTION_END; options++)\n \t\tif (options->type == OPTION_SUBCOMMAND &&\n \t\t    !strcmp(options->long_name, arg)) {\n-\t\t\t*(parse_opt_subcommand_fn **)options->value = options->subcommand_fn;\n+\t\t\tif (options->callback(options, arg, 0))\n+\t\t\t\tBUG(\"OPT_SUBCOMMAND callback returning non-zero\");\n \t\t\treturn PARSE_OPT_SUBCOMMAND;\n \t\t}\n \n@@ -506,8 +507,10 @@ static void parse_options_check(const struct option *opts)\n \t\t\t       \"That case is not supported yet.\");\n \t\t\tbreak;\n \t\tcase OPTION_SUBCOMMAND:\n-\t\t\tif (!opts->value || !opts->subcommand_fn)\n-\t\t\t\toptbug(opts, \"OPTION_SUBCOMMAND needs a value and a subcommand function\");\n+\t\t\tif (!opts->value || !opts->callback)\n+\t\t\t\toptbug(opts, \"OPTION_SUBCOMMAND needs a value and a callback function\");\n+\t\t\tif (opts->ll_callback)\n+\t\t\t\toptbug(opts, \"OPTION_SUBCOMMAND uses callback, not ll_callback\");\n \t\t\tif (!subcommand_value)\n \t\t\t\tsubcommand_value = opts->value;\n \t\t\telse if (subcommand_value != opts->value)\ndiff --git a/parse-options.h b/parse-options.h\nindex b6ef86e0d15..61e3016c3fc 100644\n--- a/parse-options.h\n+++ b/parse-options.h\n@@ -128,19 +128,24 @@ typedef int parse_opt_subcommand_fn(int argc, const char **argv,\n  *\t\t\t the option takes optional argument.\n  *\n  * `callback`::\n- *   pointer to the callback to use for OPTION_CALLBACK\n+ *   pointer to the callback to use for OPTION_CALLBACK and OPTION_SUBCOMMAND.\n  *\n  * `defval`::\n  *   default value to fill (*->value) with for PARSE_OPT_OPTARG.\n  *   OPTION_{BIT,SET_INT} store the {mask,integer} to put in the value when met.\n+ *   OPTION_SUBCOMMAND stores the pointer the function selected for\n+ *   the subcommand.\n+ *\n  *   CALLBACKS can use it like they want.\n  *\n  * `ll_callback`::\n  *   pointer to the callback to use for OPTION_LOWLEVEL_CALLBACK\n  *\n  * `subcommand_fn`::\n- *   pointer to a function to use for OPTION_SUBCOMMAND.\n- *   It will be put in value when the subcommand is given on the command line.\n+ *   pointer to the callback used with OPT_SUBCOMMAND() and\n+ *   OPT_SUBCOMMAND_F(). Internally we store the same value in\n+ *   `defval`. This is only here to give the OPT_SUBCOMMAND{,_F}()\n+ *   common case type safety.\n  */\n struct option {\n \tenum parse_opt_type type;\n@@ -217,12 +222,24 @@ struct option {\n #define OPT_ALIAS(s, l, source_long_name) \\\n \t{ OPTION_ALIAS, (s), (l), (source_long_name) }\n \n+static inline int parse_options_pick_subcommand_cb(const struct option *option,\n+\t\t\t\t\t\t   const char *arg UNUSED,\n+\t\t\t\t\t\t   int unset UNUSED)\n+{\n+\tparse_opt_subcommand_fn *fn = (parse_opt_subcommand_fn *)option->defval;\n+\t*(parse_opt_subcommand_fn **)option->value = fn;\n+\treturn 0;\n+}\n+\n #define OPT_SUBCOMMAND_F(l, v, fn, f) { \\\n \t.type = OPTION_SUBCOMMAND, \\\n \t.long_name = (l), \\\n \t.value = (v), \\\n \t.flags = (f), \\\n-\t.subcommand_fn = (fn) }\n+\t.defval = (intptr_t)(fn), \\\n+\t.subcommand_fn = (fn), \\\n+\t.callback = parse_options_pick_subcommand_cb, \\\n+}\n #define OPT_SUBCOMMAND(l, v, fn)    OPT_SUBCOMMAND_F((l), (v), (fn), 0)\n \n /*\n-- \n2.38.0.1452.g710f45c7951\n\n"},{"id":"466524","messageId":"patch-08.13-cccad790187-20221104T132117Z-avarab@gmail.com","threadId":"58746","inReplyTo":"cover-00.13-00000000000-20221104T132117Z-avarab@gmail.com","subject":"[PATCH 08/13] bisect--helper: have all functions take state, argc, argv, prefix","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-04T13:22:45Z","receivedAt":"2022-11-04T13:26:43Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"In order to use the OPT_SUBCOMMAND() API in a subsequent commit give\nall of the bisect_*() functions a consistent prototype we'll be able\nto use.\n\nThe \"prefix\" parameter is only used by bisect_next(), bisect_log()\ndoesn't need any of them, etc. The UNUSED attribute helps us to sanity\ncheck the current use.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/bisect--helper.c | 70 ++++++++++++++++++++++++----------------\n 1 file changed, 42 insertions(+), 28 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex b10ecee64cc..32e427fa878 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -223,8 +223,10 @@ static int write_terms(const char *bad, const char *good)\n \treturn res;\n }\n \n-static int bisect_reset(const char *commit)\n+static int bisect_reset(struct bisect_terms *terms UNUSED, int argc, const char **argv,\n+\t\t\tconst char *prefix UNUSED)\n {\n+\tconst char *commit = argc ? argv[0] : NULL;\n \tstruct strbuf branch = STRBUF_INIT;\n \n \tif (!commit) {\n@@ -492,8 +494,10 @@ static int get_terms(struct bisect_terms *terms)\n \treturn res;\n }\n \n-static int bisect_terms(struct bisect_terms *terms, const char *option)\n+static int bisect_terms(struct bisect_terms *terms,  int argc, const char **argv,\n+\t\t\tconst char *prefix UNUSED)\n {\n+\tconst char *option = argc ? argv[0] : NULL;\n \tif (get_terms(terms))\n \t\treturn error(_(\"no terms defined\"));\n \n@@ -646,7 +650,8 @@ static int bisect_successful(struct bisect_terms *terms)\n \treturn res;\n }\n \n-static enum bisect_error bisect_next(struct bisect_terms *terms, const char *prefix)\n+static int bisect_next(struct bisect_terms *terms, int argc UNUSED,\n+\t\t       const char **argv UNUSED, const char *prefix)\n {\n \tenum bisect_error res;\n \n@@ -676,10 +681,11 @@ static enum bisect_error bisect_auto_next(struct bisect_terms *terms, const char\n \t\treturn BISECT_OK;\n \t}\n \n-\treturn bisect_next(terms, prefix);\n+\treturn bisect_next(terms, 0, empty_strvec, prefix);\n }\n \n-static enum bisect_error bisect_start(struct bisect_terms *terms, const char **argv, int argc)\n+static int bisect_start(struct bisect_terms *terms, int argc,\n+\t\t\tconst char **argv, const char *prefix UNUSED)\n {\n \tint no_checkout = 0;\n \tint first_parent_only = 0;\n@@ -907,13 +913,13 @@ static int bisect_autostart(struct bisect_terms *terms)\n \tyesno = git_prompt(_(\"Do you want me to do it for you \"\n \t\t\t     \"[Y/n]? \"), PROMPT_ECHO);\n \tres = tolower(*yesno) == 'n' ?\n-\t\t-1 : bisect_start(terms, empty_strvec, 0);\n+\t\t-1 : bisect_start(terms, 0, empty_strvec, NULL);\n \n \treturn res;\n }\n \n-static enum bisect_error bisect_state(struct bisect_terms *terms, const char **argv,\n-\t\t\t\t      int argc)\n+static int bisect_state(struct bisect_terms *terms, int argc,\n+\t\t\tconst char **argv, const char *prefix UNUSED)\n {\n \tconst char *state;\n \tint i, verify_expected = 1;\n@@ -993,7 +999,9 @@ static enum bisect_error bisect_state(struct bisect_terms *terms, const char **a\n \treturn bisect_auto_next(terms, NULL);\n }\n \n-static enum bisect_error bisect_log(void)\n+static int bisect_log(struct bisect_terms *terms UNUSED,\n+\t\t      int argc UNUSED, const char **argv UNUSED,\n+\t\t      const char *prefix UNUSED)\n {\n \tint fd, status;\n \tconst char* filename = git_path_bisect_log();\n@@ -1032,7 +1040,7 @@ static int process_replay_line(struct bisect_terms *terms, struct strbuf *line)\n \t\tstruct strvec argv = STRVEC_INIT;\n \t\tint res;\n \t\tsq_dequote_to_strvec(rev, &argv);\n-\t\tres = bisect_start(terms, argv.v, argv.nr);\n+\t\tres = bisect_start(terms, argv.nr, argv.v, NULL);\n \t\tstrvec_clear(&argv);\n \t\treturn res;\n \t}\n@@ -1045,7 +1053,7 @@ static int process_replay_line(struct bisect_terms *terms, struct strbuf *line)\n \t\tstruct strvec argv = STRVEC_INIT;\n \t\tint res;\n \t\tsq_dequote_to_strvec(rev, &argv);\n-\t\tres = bisect_terms(terms, argv.nr == 1 ? argv.v[0] : NULL);\n+\t\tres = bisect_terms(terms, argv.nr, argv.v, NULL);\n \t\tstrvec_clear(&argv);\n \t\treturn res;\n \t}\n@@ -1054,8 +1062,10 @@ static int process_replay_line(struct bisect_terms *terms, struct strbuf *line)\n \treturn -1;\n }\n \n-static enum bisect_error bisect_replay(struct bisect_terms *terms, const char *filename)\n+static int bisect_replay(struct bisect_terms *terms, int argc UNUSED,\n+\t\t\t const char **argv, const char *prefix UNUSED)\n {\n+\tconst char *filename = argv[0];\n \tFILE *fp = NULL;\n \tenum bisect_error res = BISECT_OK;\n \tstruct strbuf line = STRBUF_INIT;\n@@ -1063,7 +1073,7 @@ static enum bisect_error bisect_replay(struct bisect_terms *terms, const char *f\n \tif (is_empty_or_missing_file(filename))\n \t\treturn error(_(\"cannot read file '%s' for replaying\"), filename);\n \n-\tif (bisect_reset(NULL))\n+\tif (bisect_reset(NULL, 0, empty_strvec, NULL))\n \t\treturn BISECT_FAILED;\n \n \tfp = fopen(filename, \"r\");\n@@ -1082,7 +1092,9 @@ static enum bisect_error bisect_replay(struct bisect_terms *terms, const char *f\n \treturn bisect_auto_next(terms, NULL);\n }\n \n-static enum bisect_error bisect_skip(struct bisect_terms *terms, const char **argv, int argc)\n+static enum bisect_error bisect_skip(struct bisect_terms *terms,  int argc,\n+\t\t\t\t     const char **argv,\n+\t\t\t\t     const char *prefix UNUSED)\n {\n \tint i;\n \tenum bisect_error res;\n@@ -1112,13 +1124,14 @@ static enum bisect_error bisect_skip(struct bisect_terms *terms, const char **ar\n \t\t\tstrvec_push(&argv_state, argv[i]);\n \t\t}\n \t}\n-\tres = bisect_state(terms, argv_state.v, argv_state.nr);\n+\tres = bisect_state(terms, argv_state.nr, argv_state.v, NULL);\n \n \tstrvec_clear(&argv_state);\n \treturn res;\n }\n \n-static int bisect_visualize(struct bisect_terms *terms, const char **argv, int argc)\n+static int bisect_visualize(struct bisect_terms *terms, int argc,\n+\t\t\t    const char **argv, const char *prefix UNUSED)\n {\n \tstruct strvec args = STRVEC_INIT;\n \tint flags = RUN_COMMAND_NO_STDIN, res = 0;\n@@ -1195,7 +1208,8 @@ static int verify_good(const struct bisect_terms *terms,\n \treturn rc;\n }\n \n-static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n+static int bisect_run(struct bisect_terms *terms,  int argc,\n+\t\t      const char **argv, const char *prefix UNUSED)\n {\n \tint res = BISECT_OK;\n \tstruct strbuf command = STRBUF_INIT;\n@@ -1269,7 +1283,7 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n \t\tsaved_stdout = dup(1);\n \t\tdup2(temporary_stdout_fd, 1);\n \n-\t\tres = bisect_state(terms, &new_state, 1);\n+\t\tres = bisect_state(terms, 1, &new_state, NULL);\n \n \t\tfflush(stdout);\n \t\tdup2(saved_stdout, 1);\n@@ -1354,53 +1368,53 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \tcase BISECT_RESET:\n \t\tif (argc > 1)\n \t\t\treturn error(_(\"--bisect-reset requires either no argument or a commit\"));\n-\t\tres = bisect_reset(argc ? argv[0] : NULL);\n+\t\tres = bisect_reset(&terms, argc, argv, prefix);\n \t\tbreak;\n \tcase BISECT_TERMS:\n \t\tif (argc > 1)\n \t\t\treturn error(_(\"--bisect-terms requires 0 or 1 argument\"));\n-\t\tres = bisect_terms(&terms, argc == 1 ? argv[0] : NULL);\n+\t\tres = bisect_terms(&terms, argc, argv, prefix);\n \t\tbreak;\n \tcase BISECT_START:\n \t\tset_terms(&terms, \"bad\", \"good\");\n-\t\tres = bisect_start(&terms, argv, argc);\n+\t\tres = bisect_start(&terms, argc, argv, prefix);\n \t\tbreak;\n \tcase BISECT_NEXT:\n \t\tif (argc)\n \t\t\treturn error(_(\"--bisect-next requires 0 arguments\"));\n \t\tget_terms(&terms);\n-\t\tres = bisect_next(&terms, prefix);\n+\t\tres = bisect_next(&terms, argc, argv, prefix);\n \t\tbreak;\n \tcase BISECT_STATE:\n \t\tset_terms(&terms, \"bad\", \"good\");\n \t\tget_terms(&terms);\n-\t\tres = bisect_state(&terms, argv, argc);\n+\t\tres = bisect_state(&terms, argc, argv, prefix);\n \t\tbreak;\n \tcase BISECT_LOG:\n \t\tif (argc)\n \t\t\treturn error(_(\"--bisect-log requires 0 arguments\"));\n-\t\tres = bisect_log();\n+\t\tres = bisect_log(&terms, argc, argv, prefix);\n \t\tbreak;\n \tcase BISECT_REPLAY:\n \t\tif (argc != 1)\n \t\t\treturn error(_(\"no logfile given\"));\n \t\tset_terms(&terms, \"bad\", \"good\");\n-\t\tres = bisect_replay(&terms, argv[0]);\n+\t\tres = bisect_replay(&terms, argc, argv, prefix);\n \t\tbreak;\n \tcase BISECT_SKIP:\n \t\tset_terms(&terms, \"bad\", \"good\");\n \t\tget_terms(&terms);\n-\t\tres = bisect_skip(&terms, argv, argc);\n+\t\tres = bisect_skip(&terms, argc, argv, prefix);\n \t\tbreak;\n \tcase BISECT_VISUALIZE:\n \t\tget_terms(&terms);\n-\t\tres = bisect_visualize(&terms, argv, argc);\n+\t\tres = bisect_visualize(&terms, argc, argv, prefix);\n \t\tbreak;\n \tcase BISECT_RUN:\n \t\tif (!argc)\n \t\t\treturn error(_(\"bisect run failed: no command provided.\"));\n \t\tget_terms(&terms);\n-\t\tres = bisect_run(&terms, argv, argc);\n+\t\tres = bisect_run(&terms, argc, argv, prefix);\n \t\tbreak;\n \tdefault:\n \t\tBUG(\"unknown subcommand %d\", cmdmode);\n-- \n2.38.0.1452.g710f45c7951\n\n"},{"id":"466525","messageId":"patch-10.13-c82d0bc39f1-20221104T132117Z-avarab@gmail.com","threadId":"58746","inReplyTo":"cover-00.13-00000000000-20221104T132117Z-avarab@gmail.com","subject":"[PATCH 10/13] bisect--helper: remove dead --bisect-{next-check,autostart} code","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-04T13:22:47Z","receivedAt":"2022-11-04T13:27:00Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nIn 911aba14205 (bisect--helper: retire `--bisect-next-check` subcommand,\n2021-09-13), we removed the usage string and the implementation, but not\nactually the option.\n\nSince b0f6494f70f (bisect--helper: retire `--bisect-autostart`\nsubcommand, 2020-10-15), the `--bisect-autostart` option is no more. But\nwe kept the `enum` value of the command mode around. Let's drop it, too.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/bisect--helper.c | 4 ----\n 1 file changed, 4 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 32e427fa878..e13c60d54b2 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1318,10 +1318,8 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n {\n \tenum {\n \t\tBISECT_RESET = 1,\n-\t\tBISECT_NEXT_CHECK,\n \t\tBISECT_TERMS,\n \t\tBISECT_START,\n-\t\tBISECT_AUTOSTART,\n \t\tBISECT_NEXT,\n \t\tBISECT_STATE,\n \t\tBISECT_LOG,\n@@ -1334,8 +1332,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \tstruct option options[] = {\n \t\tOPT_CMDMODE(0, \"bisect-reset\", &cmdmode,\n \t\t\t N_(\"reset the bisection state\"), BISECT_RESET),\n-\t\tOPT_CMDMODE(0, \"bisect-next-check\", &cmdmode,\n-\t\t\t N_(\"check whether bad or good terms exist\"), BISECT_NEXT_CHECK),\n \t\tOPT_CMDMODE(0, \"bisect-terms\", &cmdmode,\n \t\t\t N_(\"print out the bisect terms\"), BISECT_TERMS),\n \t\tOPT_CMDMODE(0, \"bisect-start\", &cmdmode,\n-- \n2.38.0.1452.g710f45c7951\n\n"},{"id":"466526","messageId":"patch-11.13-d261c32ddd7-20221104T132117Z-avarab@gmail.com","threadId":"58746","inReplyTo":"cover-00.13-00000000000-20221104T132117Z-avarab@gmail.com","subject":"[PATCH 11/13] bisect--helper: convert to OPT_SUBCOMMAND_CB()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-04T13:22:48Z","receivedAt":"2022-11-04T13:27:00Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Have the \"bisect--helper\" take arguments like \"log\" instead of \"--log\"\nby using a new OPT_SUBCOMMAND_CB() variant of OPT_SUBCOMMAND(). As\ndiscussed in a preceding commit this allows for using OPT_SUBCOMMAND()\nwith custom function signatures.\n\nIt would be nice to also convert all of the callbacks to use\nparse_options(), [1] does. But due to using the new\nOPT_SUBCOMMAND_CB() here we can punt on that for now.\n\nNote that we're intentionally leaving the errors which mention\n\"--bisect-terms\", as opposed to \"terms\". We've been showing that bad\nusage information to users for a while now, and don't need to further\nenlarge this change now by changing all of \"--bisect-\" to \"\" (which\nalso occurs outside of this context).\n\nThis finally fixes the last obscure regression in \"git bisect run\" in\nv2.30.0. We'd previously addressed it eating the \"--log\" and\n\"--no-log\" options, but d1bbbe45df8 (bisect--helper: reimplement\n`bisect_run` shell function in C, 2021-09-13) also had us conflate the\ninternal-only \"--bisect-*\" options with user arguments.\n\n1. https://lore.kernel.org/git/e97e187bbec93b47f35e3dd42b4831f1c1d8658d.1661885419.git.gitgitgadget@gmail.com/\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/bisect--helper.c    | 110 ++++++++++++++----------------------\n git-bisect.sh               |  20 +++----\n parse-options.h             |   8 ++-\n t/t6030-bisect-porcelain.sh |   2 +-\n 4 files changed, 59 insertions(+), 81 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex e13c60d54b2..b62d3f4d418 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1314,107 +1314,79 @@ static int bisect_run(struct bisect_terms *terms,  int argc,\n \treturn res;\n }\n \n+typedef int bisect_fn(struct bisect_terms *terms, int argc, const char **argv,\n+\t\t      const char *prefix);\n+\n+static int pick_subcommand_cb(const struct option *option,\n+\t\t\t      const char *arg UNUSED, int unset UNUSED)\n+{\n+\tbisect_fn *fn = (bisect_fn *)option->defval;\n+\t*(bisect_fn **)option->value = fn;\n+\treturn 0;\n+}\n+\n int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n {\n-\tenum {\n-\t\tBISECT_RESET = 1,\n-\t\tBISECT_TERMS,\n-\t\tBISECT_START,\n-\t\tBISECT_NEXT,\n-\t\tBISECT_STATE,\n-\t\tBISECT_LOG,\n-\t\tBISECT_REPLAY,\n-\t\tBISECT_SKIP,\n-\t\tBISECT_VISUALIZE,\n-\t\tBISECT_RUN,\n-\t} cmdmode = 0;\n+\tbisect_fn *fn = NULL;\n \tint res = 0;\n+#define OPT_BISECT_SUBCMD(l, v, fn) \\\n+\tOPT_SUBCOMMAND_CB((l), (v), (fn), pick_subcommand_cb)\n \tstruct option options[] = {\n-\t\tOPT_CMDMODE(0, \"bisect-reset\", &cmdmode,\n-\t\t\t N_(\"reset the bisection state\"), BISECT_RESET),\n-\t\tOPT_CMDMODE(0, \"bisect-terms\", &cmdmode,\n-\t\t\t N_(\"print out the bisect terms\"), BISECT_TERMS),\n-\t\tOPT_CMDMODE(0, \"bisect-start\", &cmdmode,\n-\t\t\t N_(\"start the bisect session\"), BISECT_START),\n-\t\tOPT_CMDMODE(0, \"bisect-next\", &cmdmode,\n-\t\t\t N_(\"find the next bisection commit\"), BISECT_NEXT),\n-\t\tOPT_CMDMODE(0, \"bisect-state\", &cmdmode,\n-\t\t\t N_(\"mark the state of ref (or refs)\"), BISECT_STATE),\n-\t\tOPT_CMDMODE(0, \"bisect-log\", &cmdmode,\n-\t\t\t N_(\"list the bisection steps so far\"), BISECT_LOG),\n-\t\tOPT_CMDMODE(0, \"bisect-replay\", &cmdmode,\n-\t\t\t N_(\"replay the bisection process from the given file\"), BISECT_REPLAY),\n-\t\tOPT_CMDMODE(0, \"bisect-skip\", &cmdmode,\n-\t\t\t N_(\"skip some commits for checkout\"), BISECT_SKIP),\n-\t\tOPT_CMDMODE(0, \"bisect-visualize\", &cmdmode,\n-\t\t\t N_(\"visualize the bisection\"), BISECT_VISUALIZE),\n-\t\tOPT_CMDMODE(0, \"bisect-run\", &cmdmode,\n-\t\t\t N_(\"use <cmd>... to automatically bisect\"), BISECT_RUN),\n+\t\tOPT_BISECT_SUBCMD(\"reset\", &fn, bisect_reset),\n+\t\tOPT_BISECT_SUBCMD(\"terms\", &fn, bisect_terms),\n+\t\tOPT_BISECT_SUBCMD(\"start\", &fn, bisect_start),\n+\t\tOPT_BISECT_SUBCMD(\"next\", &fn, bisect_next),\n+\t\tOPT_BISECT_SUBCMD(\"state\", &fn, bisect_state),\n+\t\tOPT_BISECT_SUBCMD(\"log\", &fn, bisect_log),\n+\t\tOPT_BISECT_SUBCMD(\"replay\", &fn, bisect_replay),\n+\t\tOPT_BISECT_SUBCMD(\"skip\", &fn, bisect_skip),\n+\t\tOPT_BISECT_SUBCMD(\"visualize\", &fn, bisect_visualize),\n+\t\tOPT_BISECT_SUBCMD(\"run\", &fn, bisect_run),\n \t\tOPT_END()\n \t};\n+#undef OPT_BISECT_SUBCMD\n \tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\n \n \targc = parse_options(argc, argv, prefix, options, git_bisect_usage,\n-\t\t\t     PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN_OPT);\n+\t\t\t     0);\n \n-\tif (!cmdmode)\n-\t\tusage_with_options(git_bisect_usage, options);\n+\targc--;\n+\targv++;\n \n-\tswitch (cmdmode) {\n-\tcase BISECT_RESET:\n+\tif (fn == bisect_reset) {\n \t\tif (argc > 1)\n \t\t\treturn error(_(\"--bisect-reset requires either no argument or a commit\"));\n-\t\tres = bisect_reset(&terms, argc, argv, prefix);\n-\t\tbreak;\n-\tcase BISECT_TERMS:\n+\t} else if (fn == bisect_terms) {\n \t\tif (argc > 1)\n \t\t\treturn error(_(\"--bisect-terms requires 0 or 1 argument\"));\n-\t\tres = bisect_terms(&terms, argc, argv, prefix);\n-\t\tbreak;\n-\tcase BISECT_START:\n+\t} else if (fn == bisect_start) {\n \t\tset_terms(&terms, \"bad\", \"good\");\n-\t\tres = bisect_start(&terms, argc, argv, prefix);\n-\t\tbreak;\n-\tcase BISECT_NEXT:\n+\t} else if (fn == bisect_next) {\n+\t\tget_terms(&terms);\n \t\tif (argc)\n \t\t\treturn error(_(\"--bisect-next requires 0 arguments\"));\n-\t\tget_terms(&terms);\n-\t\tres = bisect_next(&terms, argc, argv, prefix);\n-\t\tbreak;\n-\tcase BISECT_STATE:\n+\t} else if (fn == bisect_state) {\n \t\tset_terms(&terms, \"bad\", \"good\");\n \t\tget_terms(&terms);\n-\t\tres = bisect_state(&terms, argc, argv, prefix);\n-\t\tbreak;\n-\tcase BISECT_LOG:\n+\t} else if (fn == bisect_log) {\n \t\tif (argc)\n \t\t\treturn error(_(\"--bisect-log requires 0 arguments\"));\n-\t\tres = bisect_log(&terms, argc, argv, prefix);\n-\t\tbreak;\n-\tcase BISECT_REPLAY:\n+\t} else if (fn == bisect_replay) {\n \t\tif (argc != 1)\n \t\t\treturn error(_(\"no logfile given\"));\n \t\tset_terms(&terms, \"bad\", \"good\");\n-\t\tres = bisect_replay(&terms, argc, argv, prefix);\n-\t\tbreak;\n-\tcase BISECT_SKIP:\n+\t} else if (fn == bisect_skip) {\n \t\tset_terms(&terms, \"bad\", \"good\");\n \t\tget_terms(&terms);\n-\t\tres = bisect_skip(&terms, argc, argv, prefix);\n-\t\tbreak;\n-\tcase BISECT_VISUALIZE:\n+\t} else if (fn == bisect_visualize) {\n \t\tget_terms(&terms);\n-\t\tres = bisect_visualize(&terms, argc, argv, prefix);\n-\t\tbreak;\n-\tcase BISECT_RUN:\n+\t} else if (fn == bisect_run) {\n \t\tif (!argc)\n \t\t\treturn error(_(\"bisect run failed: no command provided.\"));\n \t\tget_terms(&terms);\n-\t\tres = bisect_run(&terms, argc, argv, prefix);\n-\t\tbreak;\n-\tdefault:\n-\t\tBUG(\"unknown subcommand %d\", cmdmode);\n \t}\n+\n+\tres = fn(&terms, argc, argv, prefix);\n \tfree_terms(&terms);\n \n \t/*\ndiff --git a/git-bisect.sh b/git-bisect.sh\nindex 405cf76f2a3..e19847eba0d 100755\n--- a/git-bisect.sh\n+++ b/git-bisect.sh\n@@ -58,26 +58,26 @@ case \"$#\" in\n \thelp)\n \t\tgit bisect -h ;;\n \tstart)\n-\t\tgit bisect--helper --bisect-start \"$@\" ;;\n+\t\tgit bisect--helper start \"$@\" ;;\n \tbad|good|new|old|\"$TERM_BAD\"|\"$TERM_GOOD\")\n-\t\tgit bisect--helper --bisect-state \"$cmd\" \"$@\" ;;\n+\t\tgit bisect--helper state \"$cmd\" \"$@\" ;;\n \tskip)\n-\t\tgit bisect--helper --bisect-skip \"$@\" || exit;;\n+\t\tgit bisect--helper skip \"$@\" || exit;;\n \tnext)\n \t\t# Not sure we want \"next\" at the UI level anymore.\n-\t\tgit bisect--helper --bisect-next \"$@\" || exit ;;\n+\t\tgit bisect--helper next \"$@\" || exit ;;\n \tvisualize|view)\n-\t\tgit bisect--helper --bisect-visualize \"$@\" || exit;;\n+\t\tgit bisect--helper visualize \"$@\" || exit;;\n \treset)\n-\t\tgit bisect--helper --bisect-reset \"$@\" ;;\n+\t\tgit bisect--helper reset \"$@\" ;;\n \treplay)\n-\t\tgit bisect--helper --bisect-replay \"$@\" || exit;;\n+\t\tgit bisect--helper replay \"$@\" || exit;;\n \tlog)\n-\t\tgit bisect--helper --bisect-log || exit ;;\n+\t\tgit bisect--helper log || exit ;;\n \trun)\n-\t\tgit bisect--helper --bisect-run \"$@\" || exit;;\n+\t\tgit bisect--helper run \"$@\" || exit;;\n \tterms)\n-\t\tgit bisect--helper --bisect-terms \"$@\" || exit;;\n+\t\tgit bisect--helper terms \"$@\" || exit;;\n \t*)\n \t\tusage ;;\n \tesac\ndiff --git a/parse-options.h b/parse-options.h\nindex 61e3016c3fc..4e32b557174 100644\n--- a/parse-options.h\n+++ b/parse-options.h\n@@ -237,10 +237,16 @@ static inline int parse_options_pick_subcommand_cb(const struct option *option,\n \t.value = (v), \\\n \t.flags = (f), \\\n \t.defval = (intptr_t)(fn), \\\n-\t.subcommand_fn = (fn), \\\n \t.callback = parse_options_pick_subcommand_cb, \\\n }\n #define OPT_SUBCOMMAND(l, v, fn)    OPT_SUBCOMMAND_F((l), (v), (fn), 0)\n+#define OPT_SUBCOMMAND_CB(l, v, fn, cb) { \\\n+\t.type = OPTION_SUBCOMMAND, \\\n+\t.long_name = (l), \\\n+\t.value = (v), \\\n+\t.defval = (intptr_t)(fn), \\\n+\t.callback = (cb), \\\n+}\n \n /*\n  * parse_options() will filter out the processed options and leave the\ndiff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh\nindex eace0af637e..de47c87a6ff 100755\n--- a/t/t6030-bisect-porcelain.sh\n+++ b/t/t6030-bisect-porcelain.sh\n@@ -350,7 +350,7 @@ test_expect_success 'git bisect run: args, stdout and stderr: \"--log foo --no-lo\n \tEOF_ERR\n '\n \n-test_expect_failure 'git bisect run: args, stdout and stderr: \"--bisect-start\" argument' '\n+test_expect_success 'git bisect run: args, stdout and stderr: \"--bisect-start\" argument' '\n \ttest_bisect_run_args --bisect-start <<-\\EOF_ARGS 6<<-EOF_OUT 7<<-\\EOF_ERR\n \t<--bisect-start>\n \tEOF_ARGS\n-- \n2.38.0.1452.g710f45c7951\n\n"},{"id":"466527","messageId":"patch-12.13-13745e3f18f-20221104T132118Z-avarab@gmail.com","threadId":"58746","inReplyTo":"cover-00.13-00000000000-20221104T132117Z-avarab@gmail.com","subject":"[PATCH 12/13] bisect--helper: make `state` optional","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-04T13:22:49Z","receivedAt":"2022-11-04T13:27:00Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nIn preparation for making `git bisect` a real built-in, let's prepare\nthe `bisect--helper` built-in to handle `git bisect--helper good` and\n`git bisect--helper bad`, i.e. do not require the `state` subcommand to\nbe passed explicitly.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/bisect--helper.c | 21 ++++++++++++++++++---\n git-bisect.sh            | 17 +----------------\n 2 files changed, 19 insertions(+), 19 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex b62d3f4d418..c92197b0ea5 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1348,10 +1348,12 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\n \n \targc = parse_options(argc, argv, prefix, options, git_bisect_usage,\n-\t\t\t     0);\n+\t\t\t     PARSE_OPT_SUBCOMMAND_OPTIONAL);\n \n-\targc--;\n-\targv++;\n+\tif (fn) {\n+\t\targc--;\n+\t\targv++;\n+\t}\n \n \tif (fn == bisect_reset) {\n \t\tif (argc > 1)\n@@ -1386,6 +1388,19 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\tget_terms(&terms);\n \t}\n \n+\tif (!fn) {\n+\t\tif (!argc)\n+\t\t\tusage_msg_opt(_(\"need a command\"), git_bisect_usage,\n+\t\t\t\t      options);\n+\n+\t\tset_terms(&terms, \"bad\", \"good\");\n+\t\tget_terms(&terms);\n+\t\tif (check_and_set_terms(&terms, argv[0]))\n+\t\t\tusage_msg_optf(_(\"unknown command: '%s'\"),\n+\t\t\t\t       git_bisect_usage, options, argv[0]);\n+\t\tfn = bisect_state;\n+\t}\n+\n \tres = fn(&terms, argc, argv, prefix);\n \tfree_terms(&terms);\n \ndiff --git a/git-bisect.sh b/git-bisect.sh\nindex e19847eba0d..c6e12f60f83 100755\n--- a/git-bisect.sh\n+++ b/git-bisect.sh\n@@ -34,33 +34,18 @@ Please use \"git help bisect\" to get the full man page.'\n OPTIONS_SPEC=\n . git-sh-setup\n \n-TERM_BAD=bad\n-TERM_GOOD=good\n-\n-get_terms () {\n-\tif test -s \"$GIT_DIR/BISECT_TERMS\"\n-\tthen\n-\t\t{\n-\t\tread TERM_BAD\n-\t\tread TERM_GOOD\n-\t\t} <\"$GIT_DIR/BISECT_TERMS\"\n-\tfi\n-}\n \n case \"$#\" in\n 0)\n \tusage ;;\n *)\n \tcmd=\"$1\"\n-\tget_terms\n \tshift\n \tcase \"$cmd\" in\n \thelp)\n \t\tgit bisect -h ;;\n \tstart)\n \t\tgit bisect--helper start \"$@\" ;;\n-\tbad|good|new|old|\"$TERM_BAD\"|\"$TERM_GOOD\")\n-\t\tgit bisect--helper state \"$cmd\" \"$@\" ;;\n \tskip)\n \t\tgit bisect--helper skip \"$@\" || exit;;\n \tnext)\n@@ -79,6 +64,6 @@ case \"$#\" in\n \tterms)\n \t\tgit bisect--helper terms \"$@\" || exit;;\n \t*)\n-\t\tusage ;;\n+\t\tgit bisect--helper \"$cmd\" \"$@\" ;;\n \tesac\n esac\n-- \n2.38.0.1452.g710f45c7951\n\n"},{"id":"466528","messageId":"patch-13.13-37bed06ec4e-20221104T132118Z-avarab@gmail.com","threadId":"58746","inReplyTo":"cover-00.13-00000000000-20221104T132117Z-avarab@gmail.com","subject":"[PATCH 13/13] Turn `git bisect` into a full built-in","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-04T13:22:50Z","receivedAt":"2022-11-04T13:27:00Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nNow that the shell script hands off to the `bisect--helper` to do\n_anything_ (except to show the help), it is but a tiny step to let the\nhelper implement the actual `git bisect` command instead.\n\nThis retires `git-bisect.sh`, concluding a multi-year journey that many\nhands helped with, in particular Pranit Bauna, Tanushree Tumane and\nMiriam Rubio.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n Makefile                               |  3 +-\n builtin.h                              |  2 +-\n builtin/{bisect--helper.c => bisect.c} |  5 +-\n git-bisect.sh                          | 69 --------------------------\n git.c                                  |  2 +-\n 5 files changed, 4 insertions(+), 77 deletions(-)\n rename builtin/{bisect--helper.c => bisect.c} (99%)\n delete mode 100755 git-bisect.sh\n\ndiff --git a/Makefile b/Makefile\nindex 4927379184c..78785c6b843 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -627,7 +627,6 @@ THIRD_PARTY_SOURCES =\n # interactive shell sessions without exporting it.\n unexport CDPATH\n \n-SCRIPT_SH += git-bisect.sh\n SCRIPT_SH += git-difftool--helper.sh\n SCRIPT_SH += git-filter-branch.sh\n SCRIPT_SH += git-merge-octopus.sh\n@@ -1137,7 +1136,7 @@ BUILTIN_OBJS += builtin/am.o\n BUILTIN_OBJS += builtin/annotate.o\n BUILTIN_OBJS += builtin/apply.o\n BUILTIN_OBJS += builtin/archive.o\n-BUILTIN_OBJS += builtin/bisect--helper.o\n+BUILTIN_OBJS += builtin/bisect.o\n BUILTIN_OBJS += builtin/blame.o\n BUILTIN_OBJS += builtin/branch.o\n BUILTIN_OBJS += builtin/bugreport.o\ndiff --git a/builtin.h b/builtin.h\nindex 8901a34d6bf..aa955466b4e 100644\n--- a/builtin.h\n+++ b/builtin.h\n@@ -116,7 +116,7 @@ int cmd_am(int argc, const char **argv, const char *prefix);\n int cmd_annotate(int argc, const char **argv, const char *prefix);\n int cmd_apply(int argc, const char **argv, const char *prefix);\n int cmd_archive(int argc, const char **argv, const char *prefix);\n-int cmd_bisect__helper(int argc, const char **argv, const char *prefix);\n+int cmd_bisect(int argc, const char **argv, const char *prefix);\n int cmd_blame(int argc, const char **argv, const char *prefix);\n int cmd_branch(int argc, const char **argv, const char *prefix);\n int cmd_bugreport(int argc, const char **argv, const char *prefix);\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect.c\nsimilarity index 99%\nrename from builtin/bisect--helper.c\nrename to builtin/bisect.c\nindex c92197b0ea5..9d66da2148b 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect.c\n@@ -1325,7 +1325,7 @@ static int pick_subcommand_cb(const struct option *option,\n \treturn 0;\n }\n \n-int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n+int cmd_bisect(int argc, const char **argv, const char *prefix)\n {\n \tbisect_fn *fn = NULL;\n \tint res = 0;\n@@ -1370,9 +1370,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t} else if (fn == bisect_state) {\n \t\tset_terms(&terms, \"bad\", \"good\");\n \t\tget_terms(&terms);\n-\t} else if (fn == bisect_log) {\n-\t\tif (argc)\n-\t\t\treturn error(_(\"--bisect-log requires 0 arguments\"));\n \t} else if (fn == bisect_replay) {\n \t\tif (argc != 1)\n \t\t\treturn error(_(\"no logfile given\"));\ndiff --git a/git-bisect.sh b/git-bisect.sh\ndeleted file mode 100755\nindex c6e12f60f83..00000000000\n--- a/git-bisect.sh\n+++ /dev/null\n@@ -1,69 +0,0 @@\n-#!/bin/sh\n-\n-USAGE='[help|start|bad|good|new|old|terms|skip|next|reset|visualize|view|replay|log|run]'\n-LONG_USAGE='git bisect help\n-\tprint this long help message.\n-git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>]\n-\t\t [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<pathspec>...]\n-\treset bisect state and start bisection.\n-git bisect (bad|new) [<rev>]\n-\tmark <rev> a known-bad revision/\n-\t\ta revision after change in a given property.\n-git bisect (good|old) [<rev>...]\n-\tmark <rev>... known-good revisions/\n-\t\trevisions before change in a given property.\n-git bisect terms [--term-good | --term-bad]\n-\tshow the terms used for old and new commits (default: bad, good)\n-git bisect skip [(<rev>|<range>)...]\n-\tmark <rev>... untestable revisions.\n-git bisect next\n-\tfind next bisection to test and check it out.\n-git bisect reset [<commit>]\n-\tfinish bisection search and go back to commit.\n-git bisect (visualize|view)\n-\tshow bisect status in gitk.\n-git bisect replay <logfile>\n-\treplay bisection log.\n-git bisect log\n-\tshow bisect log.\n-git bisect run <cmd>...\n-\tuse <cmd>... to automatically bisect.\n-\n-Please use \"git help bisect\" to get the full man page.'\n-\n-OPTIONS_SPEC=\n-. git-sh-setup\n-\n-\n-case \"$#\" in\n-0)\n-\tusage ;;\n-*)\n-\tcmd=\"$1\"\n-\tshift\n-\tcase \"$cmd\" in\n-\thelp)\n-\t\tgit bisect -h ;;\n-\tstart)\n-\t\tgit bisect--helper start \"$@\" ;;\n-\tskip)\n-\t\tgit bisect--helper skip \"$@\" || exit;;\n-\tnext)\n-\t\t# Not sure we want \"next\" at the UI level anymore.\n-\t\tgit bisect--helper next \"$@\" || exit ;;\n-\tvisualize|view)\n-\t\tgit bisect--helper visualize \"$@\" || exit;;\n-\treset)\n-\t\tgit bisect--helper reset \"$@\" ;;\n-\treplay)\n-\t\tgit bisect--helper replay \"$@\" || exit;;\n-\tlog)\n-\t\tgit bisect--helper log || exit ;;\n-\trun)\n-\t\tgit bisect--helper run \"$@\" || exit;;\n-\tterms)\n-\t\tgit bisect--helper terms \"$@\" || exit;;\n-\t*)\n-\t\tgit bisect--helper \"$cmd\" \"$@\" ;;\n-\tesac\n-esac\ndiff --git a/git.c b/git.c\nindex ee7758dcb0e..f18a5750313 100644\n--- a/git.c\n+++ b/git.c\n@@ -492,7 +492,7 @@ static struct cmd_struct commands[] = {\n \t{ \"annotate\", cmd_annotate, RUN_SETUP },\n \t{ \"apply\", cmd_apply, RUN_SETUP_GENTLY },\n \t{ \"archive\", cmd_archive, RUN_SETUP_GENTLY },\n-\t{ \"bisect--helper\", cmd_bisect__helper, RUN_SETUP },\n+\t{ \"bisect\", cmd_bisect, RUN_SETUP },\n \t{ \"blame\", cmd_blame, RUN_SETUP },\n \t{ \"branch\", cmd_branch, RUN_SETUP | DELAY_PAGER_CONFIG },\n \t{ \"bugreport\", cmd_bugreport, RUN_SETUP_GENTLY },\n-- \n2.38.0.1452.g710f45c7951\n\n"},{"id":"466529","messageId":"221104.86r0yiygtd.gmgdl@evledraar.gmail.com","threadId":"58746","inReplyTo":"081f3f7f9501012404fb9e59ab6d94f632180b53.1667561761.git.congdanhqx@gmail.com","subject":"Re: [PATCH 2/3] bisect--helper: move all subcommands into their own functions","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-04T13:32:34Z","receivedAt":"2022-11-04T13:45:18Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Fri, Nov 04 2022, Đoàn Trần Công Danh wrote:\n\n> In a later change, we will use OPT_SUBCOMMAND to parse sub-commands to\n> avoid consuming non-option opts.\n>\n> Since OPT_SUBCOMMAND needs a function pointer to operate,\n> let's move it now.\n\nAs shown in\nhttps://lore.kernel.org/git/patch-11.13-d261c32ddd7-20221104T132117Z-avarab@gmail.com/\nthis can be much nicer in terms of avoiding these wrappers if we jsut\nteach parse-options.c to take our custom signature'd callback, but...\n\n> +static int cmd_bisect__reset(int argc, const char **argv, const char *prefix UNUSED)\n> +static int cmd_bisect__terms(int argc, const char **argv, const char *prefix UNUSED)\n> +static int cmd_bisect__start(int argc, const char **argv, const char *prefix UNUSED)\n....\n\n>  \tswitch (cmdmode) {\n>  \tcase BISECT_RESET:\n> -\t\tif (argc > 1)\n> -\t\t\treturn error(_(\"--bisect-reset requires either no argument or a commit\"));\n> -\t\tres = bisect_reset(argc ? argv[0] : NULL);\n> +\t\tres = cmd_bisect__reset(argc, argv, prefix);\n>  \t\tbreak;\n>  \tcase BISECT_TERMS:\n> -\t\tif (argc > 1)\n> -\t\t\treturn error(_(\"--bisect-terms requires 0 or 1 argument\"));\n> -\t\tres = bisect_terms(&terms, argc == 1 ? argv[0] : NULL);\n> +\t\tres = cmd_bisect__terms(argc, argv, prefix);\n>  \t\tbreak;\n>  \tcase BISECT_START:\n> -\t\tset_terms(&terms, \"bad\", \"good\");\n> -\t\tres = bisect_start(&terms, argv, argc);\n> +\t\tres = cmd_bisect__start(argc, argv, prefix);\n\nIf we're not going to do that this isn't too bad actually. s noted in my\nCL\n(https://lore.kernel.org/git/cover-00.13-00000000000-20221104T132117Z-avarab@gmail.com/)\nI started seeing if I could cut Johannes's built-in-bisect series down\nto size so we could have it merged sooner than later.\n\nIt ended up refactoring every single user of \"terms\" to take the\nfile-global instead of the variable on the stack, but this shows that\nthat's not something we need, even without a new parse-options.c API.\n\nB.t.w. you can cut down more on the verbosity by doing:\n\n\tstruct bisect_terms terms = { 0 };\n\nWhich is the same as \"{ .term_good = NULL, .term_bad = NULL }\". I left\nit in place in my version because I'm explicitly trying to avoid\ntouching anything we don't need to for a bisect built-in, but if we're\nrefactoring this anyway...\n\nI also think this could be further reduced in size a lot if we go for\nyour approach, i.e. make a helper function that these call, like:\n\n\tif (have_err)\n\t\treturn error(_(error_msg));\n        if (set_terms)\n\t\tset_terms(&terms, \"bad\", \"good\");\n\tif (get_terms)\n\t\tget_terms(&terms);\n\tres = !strcmp(iam, \"terms\") ? bisect_terms(&terms, argc == 1 ? argv[0] : NULL) :\n        \t!strcmp(iam, \"start\") ? bisect_start(&terms, argv, argc) :\n                [...];\n\tfree_terms(&terms);\n\treturn res;\n\nThen e.g. the body of \"terms\" is just:\n\n\treturn that_helper(argc, argv, prefix, \"terms\", /* iam */\n        \t\t  argc > 1, /* have err */ N_(\"--bisect-terms requires 0 or 1 argument\"), /* err msg */\n                          0, 0, /* get terms and set terms */);\n\nEtc., I think that might be worth it, as almost all of the contents of\nthese functions is just copy/pasted...\n"},{"id":"466530","messageId":"221104.86mt96ygj9.gmgdl@evledraar.gmail.com","threadId":"58746","inReplyTo":"76c585d22bf415e719762fcf5decf4b71efa5bfb.1667561761.git.congdanhqx@gmail.com","subject":"Re: [PATCH 3/3] bisect--helper: parse subcommand with OPT_SUBCOMMAND","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-04T13:46:18Z","receivedAt":"2022-11-04T13:51:13Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Fri, Nov 04 2022, Đoàn Trần Công Danh wrote:\n\n> As of it is, we're parsing subcommand with OPT_CMDMODE, which will\n> continue to parse more options even if the command has been found.\n>\n> When we're running \"git bisect run\" with a command that expecting\n> a \"--log\" or \"--no-log\" arguments, or one of those \"--bisect-...\"\n> arguments, bisect--helper may mistakenly think those options are\n> bisect--helper's option.\n>\n> We may fix those problems by passing \"--\" when calling from\n> git-bisect.sh, and skip that \"--\" in bisect--helper. However, it may\n> interfere with user's \"--\".\n>\n> Let's parse subcommand with OPT_SUBCOMMAND since that API was born for\n> this specific use-case.\n\nIf we go for this approch over my series, let's pretty please...\n\n> +\t\tOPT_SUBCOMMAND(\"bisect-reset\", &fn, cmd_bisect__reset),\n> +\t\tOPT_SUBCOMMAND(\"bisect-terms\", &fn, cmd_bisect__terms),\n\nNot call this \"bisect-reset\" etc, but just \"reset\", the whole point of\nthe greater problem here is...\n\n> -\t\tgit bisect--helper --bisect-start \"$@\" ;;\n> +\t\tgit bisect--helper bisect-start \"$@\" ;;\n\n...to be able to eventually remove this shimmy layer completely,\nwhich...\n\n>  \tbad|good|new|old|\"$TERM_BAD\"|\"$TERM_GOOD\")\n> -\t\tgit bisect--helper --bisect-state \"$cmd\" \"$@\" ;;\n> +\t\tgit bisect--helper bisect-state \"$cmd\" \"$@\" ;;\n\n...as you can see in my\nhttps://lore.kernel.org/git/patch-12.13-13745e3f18f-20221104T132118Z-avarab@gmail.com/\nwe still need to handle this special snowflake, but...\n\n\n>  \tskip)\n> -\t\tgit bisect--helper --bisect-skip \"$@\" || exit;;\n> +\t\tgit bisect--helper bisect-skip \"$@\" || exit;;\n>  \tnext)\n>  \t\t# Not sure we want \"next\" at the UI level anymore.\n> -\t\tgit bisect--helper --bisect-next \"$@\" || exit ;;\n> +\t\tgit bisect--helper bisect-next \"$@\" || exit ;;\n>  \tvisualize|view)\n> -\t\tgit bisect--helper --bisect-visualize \"$@\" || exit;;\n> +\t\tgit bisect--helper bisect-visualize \"$@\" || exit;;\n>  \treset)\n> -\t\tgit bisect--helper --bisect-reset \"$@\" ;;\n> +\t\tgit bisect--helper bisect-reset \"$@\" ;;\n>  \treplay)\n> -\t\tgit bisect--helper --bisect-replay \"$@\" || exit;;\n> +\t\tgit bisect--helper bisect-replay \"$@\" || exit;;\n\n...instead of doing all of this, get rid of most of this case statement, and just do:\n\n\tbad|good|...)\n\t\t[...]\n\t*)\n\t\tgit bisect--helper \"$cmd\" \"$@\" \n                ;;\n\n>  \tlog)\n> -\t\tgit bisect--helper --bisect-log || exit ;;\n> +\t\tgit bisect--helper bisect-log || exit ;;\n\nBut note that there are subtle behavior differences in some,\ne.g. because we do the \"|| exit\" we'll eat the exit code, and this one\nalso doesn't get parameters, so it should be left out of such a list\n(see tests in my topic for a regression check for that, we're currently\nflying blind in that area).\n\n> +# We want to make sure --log is not eaten\n> +test_expect_success '\"git bisect run\" simple case' '\n> +\tgit bisect start &&\n> +\tgit bisect good $HASH1 &&\n> +\tgit bisect bad $HASH4 &&\n> +\tgit bisect run printf \"%s\\n\" --log >my_bisect_log.txt &&\n> +\tgrep -e --log my_bisect_log.txt &&\n> +\tgit bisect reset\n> +'\n\nCheck out my 1/13 to see all the cases you missed:\nhttps://lore.kernel.org/git/patch-01.13-beb1ea22a27-20221104T132117Z-avarab@gmail.com/\n:)\n"},{"id":"466531","messageId":"Y2UbrCzTIvIbPbgX@danh.dev","threadId":"58746","inReplyTo":"221104.86r0yiygtd.gmgdl@evledraar.gmail.com","subject":"Re: [PATCH 2/3] bisect--helper: move all subcommands into their own functions","fromName":"Đoàn Trần Công Danh","fromEmail":"congdanhqx@gmail.com","sentAt":"2022-11-04T14:03:24Z","receivedAt":"2022-11-04T14:03:33Z","isPatch":true,"sender":{"key":"congdanhqx@gmail.com","avatar":"https://avatars.githubusercontent.com/u/42673067?v=4"},"body":"On 2022-11-04 14:32:34+0100, Ævar Arnfjörð Bjarmason <avarab@gmail.com> wrote:\n> \n> On Fri, Nov 04 2022, Đoàn Trần Công Danh wrote:\n> \n> > In a later change, we will use OPT_SUBCOMMAND to parse sub-commands to\n> > avoid consuming non-option opts.\n> >\n> > Since OPT_SUBCOMMAND needs a function pointer to operate,\n> > let's move it now.\n> \n> As shown in\n> https://lore.kernel.org/git/patch-11.13-d261c32ddd7-20221104T132117Z-avarab@gmail.com/\n> this can be much nicer in terms of avoiding these wrappers if we jsut\n> teach parse-options.c to take our custom signature'd callback, but...\n> \n> > +static int cmd_bisect__reset(int argc, const char **argv, const char *prefix UNUSED)\n> > +static int cmd_bisect__terms(int argc, const char **argv, const char *prefix UNUSED)\n> > +static int cmd_bisect__start(int argc, const char **argv, const char *prefix UNUSED)\n> ....\n> \n> >  \tswitch (cmdmode) {\n> >  \tcase BISECT_RESET:\n> > -\t\tif (argc > 1)\n> > -\t\t\treturn error(_(\"--bisect-reset requires either no argument or a commit\"));\n> > -\t\tres = bisect_reset(argc ? argv[0] : NULL);\n> > +\t\tres = cmd_bisect__reset(argc, argv, prefix);\n> >  \t\tbreak;\n> >  \tcase BISECT_TERMS:\n> > -\t\tif (argc > 1)\n> > -\t\t\treturn error(_(\"--bisect-terms requires 0 or 1 argument\"));\n> > -\t\tres = bisect_terms(&terms, argc == 1 ? argv[0] : NULL);\n> > +\t\tres = cmd_bisect__terms(argc, argv, prefix);\n> >  \t\tbreak;\n> >  \tcase BISECT_START:\n> > -\t\tset_terms(&terms, \"bad\", \"good\");\n> > -\t\tres = bisect_start(&terms, argv, argc);\n> > +\t\tres = cmd_bisect__start(argc, argv, prefix);\n> \n> If we're not going to do that this isn't too bad actually. s noted in my\n> CL\n> (https://lore.kernel.org/git/cover-00.13-00000000000-20221104T132117Z-avarab@gmail.com/)\n> I started seeing if I could cut Johannes's built-in-bisect series down\n> to size so we could have it merged sooner than later.\n> \n> It ended up refactoring every single user of \"terms\" to take the\n> file-global instead of the variable on the stack, but this shows that\n> that's not something we need, even without a new parse-options.c API.\n\nYes, I saw your patches, but I think adding a whole new\nparse-options.c API is a lot (taking a side the type-safety the new\nAPI introduced). If I were doing the new parse-options API without the\ntype safety, I probably make an API like:\n\n\tint (*subcommand_fn)(int argc, const char **argv, const char *prefix, void *ctx)\n\nWe would still have a non-safe 4th argument, but we won't need a new\ntypedef and picking_fn in every source file.\n\n> B.t.w. you can cut down more on the verbosity by doing:\n> \n> \tstruct bisect_terms terms = { 0 };\n> Which is the same as \"{ .term_good = NULL, .term_bad = NULL }\". I left\n> it in place in my version because I'm explicitly trying to avoid\n> touching anything we don't need to for a bisect built-in, but if we're\n> refactoring this anyway...\n\nSure. I'll see which direction is favourable by other people.\nYes, the free_terms is the one that increase the size of this patch,\n\n\n> I also think this could be further reduced in size a lot if we go for\n> your approach, i.e. make a helper function that these call, like:\n> \n> \tif (have_err)\n> \t\treturn error(_(error_msg));\n>         if (set_terms)\n> \t\tset_terms(&terms, \"bad\", \"good\");\n> \tif (get_terms)\n> \t\tget_terms(&terms);\n> \tres = !strcmp(iam, \"terms\") ? bisect_terms(&terms, argc == 1 ? argv[0] : NULL) :\n>         \t!strcmp(iam, \"start\") ? bisect_start(&terms, argv, argc) :\n\nHowever, if we're doing this, aren't we getting back to step 1:\nstrcmp to a list of subcommand instead of using OPT_SUBCOMMAND?\n\n>                 [...];\n> \tfree_terms(&terms);\n> \treturn res;\n> \n> Then e.g. the body of \"terms\" is just:\n> \n> \treturn that_helper(argc, argv, prefix, \"terms\", /* iam */\n>         \t\t  argc > 1, /* have err */ N_(\"--bisect-terms requires 0 or 1 argument\"), /* err msg */\n>                           0, 0, /* get terms and set terms */);\n> \n> Etc., I think that might be worth it, as almost all of the contents of\n> these functions is just copy/pasted...\n\n-- \nDanh\n"},{"id":"466532","messageId":"Y2Uckyj2JlpsxetS@danh.dev","threadId":"58746","inReplyTo":"221104.86mt96ygj9.gmgdl@evledraar.gmail.com","subject":"Re: [PATCH 3/3] bisect--helper: parse subcommand with OPT_SUBCOMMAND","fromName":"Đoàn Trần Công Danh","fromEmail":"congdanhqx@gmail.com","sentAt":"2022-11-04T14:07:15Z","receivedAt":"2022-11-04T14:07:50Z","isPatch":true,"sender":{"key":"congdanhqx@gmail.com","avatar":"https://avatars.githubusercontent.com/u/42673067?v=4"},"body":"On 2022-11-04 14:46:18+0100, Ævar Arnfjörð Bjarmason <avarab@gmail.com> wrote:\n> \n> On Fri, Nov 04 2022, Đoàn Trần Công Danh wrote:\n> \n> > As of it is, we're parsing subcommand with OPT_CMDMODE, which will\n> > continue to parse more options even if the command has been found.\n> >\n> > When we're running \"git bisect run\" with a command that expecting\n> > a \"--log\" or \"--no-log\" arguments, or one of those \"--bisect-...\"\n> > arguments, bisect--helper may mistakenly think those options are\n> > bisect--helper's option.\n> >\n> > We may fix those problems by passing \"--\" when calling from\n> > git-bisect.sh, and skip that \"--\" in bisect--helper. However, it may\n> > interfere with user's \"--\".\n> >\n> > Let's parse subcommand with OPT_SUBCOMMAND since that API was born for\n> > this specific use-case.\n> \n> If we go for this approch over my series, let's pretty please...\n> \n> > +\t\tOPT_SUBCOMMAND(\"bisect-reset\", &fn, cmd_bisect__reset),\n> > +\t\tOPT_SUBCOMMAND(\"bisect-terms\", &fn, cmd_bisect__terms),\n> \n> Not call this \"bisect-reset\" etc, but just \"reset\", the whole point of\n> the greater problem here is...\n\nYes, we should strip \"bisect-\" from those sub-commands.\n\n> \n> > -\t\tgit bisect--helper --bisect-start \"$@\" ;;\n> > +\t\tgit bisect--helper bisect-start \"$@\" ;;\n> \n> ...to be able to eventually remove this shimmy layer completely,\n> which...\n> \n> >  \tbad|good|new|old|\"$TERM_BAD\"|\"$TERM_GOOD\")\n> > -\t\tgit bisect--helper --bisect-state \"$cmd\" \"$@\" ;;\n> > +\t\tgit bisect--helper bisect-state \"$cmd\" \"$@\" ;;\n> \n> ...as you can see in my\n> https://lore.kernel.org/git/patch-12.13-13745e3f18f-20221104T132118Z-avarab@gmail.com/\n> we still need to handle this special snowflake, but...\n> \n> \n> >  \tskip)\n> > -\t\tgit bisect--helper --bisect-skip \"$@\" || exit;;\n> > +\t\tgit bisect--helper bisect-skip \"$@\" || exit;;\n> >  \tnext)\n> >  \t\t# Not sure we want \"next\" at the UI level anymore.\n> > -\t\tgit bisect--helper --bisect-next \"$@\" || exit ;;\n> > +\t\tgit bisect--helper bisect-next \"$@\" || exit ;;\n> >  \tvisualize|view)\n> > -\t\tgit bisect--helper --bisect-visualize \"$@\" || exit;;\n> > +\t\tgit bisect--helper bisect-visualize \"$@\" || exit;;\n> >  \treset)\n> > -\t\tgit bisect--helper --bisect-reset \"$@\" ;;\n> > +\t\tgit bisect--helper bisect-reset \"$@\" ;;\n> >  \treplay)\n> > -\t\tgit bisect--helper --bisect-replay \"$@\" || exit;;\n> > +\t\tgit bisect--helper bisect-replay \"$@\" || exit;;\n> \n> ...instead of doing all of this, get rid of most of this case statement, and just do:\n> \n> \tbad|good|...)\n> \t\t[...]\n> \t*)\n> \t\tgit bisect--helper \"$cmd\" \"$@\" \n>                 ;;\n> \n> >  \tlog)\n> > -\t\tgit bisect--helper --bisect-log || exit ;;\n> > +\t\tgit bisect--helper bisect-log || exit ;;\n> \n> But note that there are subtle behavior differences in some,\n> e.g. because we do the \"|| exit\" we'll eat the exit code, and this one\n\nNo, there're nothing different between \"|| exit\" and simply run the\ncommand, since \"|| exit\" will exit with old exit status code.\nI don't think there're any other different.\n\n> also doesn't get parameters, so it should be left out of such a list\n> (see tests in my topic for a regression check for that, we're currently\n> flying blind in that area).\n> \n> > +# We want to make sure --log is not eaten\n> > +test_expect_success '\"git bisect run\" simple case' '\n> > +\tgit bisect start &&\n> > +\tgit bisect good $HASH1 &&\n> > +\tgit bisect bad $HASH4 &&\n> > +\tgit bisect run printf \"%s\\n\" --log >my_bisect_log.txt &&\n> > +\tgrep -e --log my_bisect_log.txt &&\n> > +\tgit bisect reset\n> > +'\n> \n> Check out my 1/13 to see all the cases you missed:\n> https://lore.kernel.org/git/patch-01.13-beb1ea22a27-20221104T132117Z-avarab@gmail.com/\n> :)\n\n-- \nDanh\n"},{"id":"466565","messageId":"Y2WqoQ4opWoMHTiu@nand.local","threadId":"58746","inReplyTo":"cover-00.13-00000000000-20221104T132117Z-avarab@gmail.com","subject":"Re: [PATCH 00/13] bisect: v2.30.0 \"run\" regressions + make it built-in","fromName":"Taylor Blau","fromEmail":"me@ttaylorr.com","sentAt":"2022-11-05T00:13:21Z","receivedAt":"2022-11-05T00:13:28Z","isPatch":true,"sender":{"key":"me@ttaylorr.com","avatar":"https://avatars.githubusercontent.com/u/301000140?v=4"},"body":"On Fri, Nov 04, 2022 at 02:22:37PM +0100, Ævar Arnfjörð Bjarmason wrote:\n> This fixes the regression Lukáš Doktor reported in [1], and also gets\n> us the full way to a builtin/bisect.c and \"git rm git-bisect.sh\".\n\nCan you and Đoàn work together to find a way that your two series can\nwork together? Reading both, this is definitely a \"one or the other\"\nsituation currently, and I would much rather pick up a more targeted fix\nin the short-term.\n\nThanks,\nTaylor\n"},{"id":"466572","messageId":"df855ba1-52b1-1007-68e8-2e28e85b6822@web.de","threadId":"58746","inReplyTo":"patch-09.13-2cb3807aa17-20221104T132117Z-avarab@gmail.com","subject":"Re: [PATCH 09/13] parse-options API: don't restrict OPT_SUBCOMMAND() to one *_fn type","fromName":"René Scharfe","fromEmail":"l.s.r@web.de","sentAt":"2022-11-05T08:32:44Z","receivedAt":"2022-11-05T08:33:13Z","isPatch":true,"sender":{"key":"l.s.r@web.de","avatar":"https://avatars.githubusercontent.com/u/26122331?v=4"},"body":"Am 04.11.22 um 14:22 schrieb Ævar Arnfjörð Bjarmason:\n> When the OPT_SUBCOMMAND() API was implemented in [1] it did so by\n> adding a new \"subcommand_fn\" member to \"struct option\", rather than\n> allowing the user of the API to pick the type of the function.\n>\n> An advantage of mandating that \"parse_opt_subcommand_fn\" must be used\n> is that we'll get type checking for the function we're passing in, a\n> disadvantage is that we can't convert e.g. \"builtin/bisect--helper.c\"\n> easily to it, as its callbacks need their own argument.\n>\n> Let's generalize this interface, while leaving in place a small hack\n> to give the existing API users their type safety. We assign to\n> \"typecheck_subcommand_fn\", but don't subsequently use it for\n> anything. Instead we use the \"defval\" and \"value\" members.\n>\n> A subsequent commit will add a OPT_SUBCOMMAND() variant where the\n> \"callback\" isn't our default \"parse_options_pick_subcommand\" (and that\n> caller won't be able to use the type checking).\n>\n> 1. fa83cc834da (parse-options: add support for parsing subcommands,\n>    2022-08-19)\n>\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> ---\n>  parse-options.c |  9 ++++++---\n>  parse-options.h | 25 +++++++++++++++++++++----\n>  2 files changed, 27 insertions(+), 7 deletions(-)\n>\n> diff --git a/parse-options.c b/parse-options.c\n> index a1ec932f0f9..1d9e46c9dc7 100644\n> --- a/parse-options.c\n> +++ b/parse-options.c\n> @@ -427,7 +427,8 @@ static enum parse_opt_result parse_subcommand(const char *arg,\n>  \tfor (; options->type != OPTION_END; options++)\n>  \t\tif (options->type == OPTION_SUBCOMMAND &&\n>  \t\t    !strcmp(options->long_name, arg)) {\n> -\t\t\t*(parse_opt_subcommand_fn **)options->value = options->subcommand_fn;\n> +\t\t\tif (options->callback(options, arg, 0))\n> +\t\t\t\tBUG(\"OPT_SUBCOMMAND callback returning non-zero\");\n>  \t\t\treturn PARSE_OPT_SUBCOMMAND;\n>  \t\t}\n>\n> @@ -506,8 +507,10 @@ static void parse_options_check(const struct option *opts)\n>  \t\t\t       \"That case is not supported yet.\");\n>  \t\t\tbreak;\n>  \t\tcase OPTION_SUBCOMMAND:\n> -\t\t\tif (!opts->value || !opts->subcommand_fn)\n> -\t\t\t\toptbug(opts, \"OPTION_SUBCOMMAND needs a value and a subcommand function\");\n> +\t\t\tif (!opts->value || !opts->callback)\n> +\t\t\t\toptbug(opts, \"OPTION_SUBCOMMAND needs a value and a callback function\");\n> +\t\t\tif (opts->ll_callback)\n> +\t\t\t\toptbug(opts, \"OPTION_SUBCOMMAND uses callback, not ll_callback\");\n>  \t\t\tif (!subcommand_value)\n>  \t\t\t\tsubcommand_value = opts->value;\n>  \t\t\telse if (subcommand_value != opts->value)\n> diff --git a/parse-options.h b/parse-options.h\n> index b6ef86e0d15..61e3016c3fc 100644\n> --- a/parse-options.h\n> +++ b/parse-options.h\n> @@ -128,19 +128,24 @@ typedef int parse_opt_subcommand_fn(int argc, const char **argv,\n>   *\t\t\t the option takes optional argument.\n>   *\n>   * `callback`::\n> - *   pointer to the callback to use for OPTION_CALLBACK\n> + *   pointer to the callback to use for OPTION_CALLBACK and OPTION_SUBCOMMAND.\n>   *\n>   * `defval`::\n>   *   default value to fill (*->value) with for PARSE_OPT_OPTARG.\n>   *   OPTION_{BIT,SET_INT} store the {mask,integer} to put in the value when met.\n> + *   OPTION_SUBCOMMAND stores the pointer the function selected for\n> + *   the subcommand.\n> + *\n>   *   CALLBACKS can use it like they want.\n>   *\n>   * `ll_callback`::\n>   *   pointer to the callback to use for OPTION_LOWLEVEL_CALLBACK\n>   *\n>   * `subcommand_fn`::\n> - *   pointer to a function to use for OPTION_SUBCOMMAND.\n> - *   It will be put in value when the subcommand is given on the command line.\n> + *   pointer to the callback used with OPT_SUBCOMMAND() and\n> + *   OPT_SUBCOMMAND_F(). Internally we store the same value in\n> + *   `defval`. This is only here to give the OPT_SUBCOMMAND{,_F}()\n> + *   common case type safety.\n>   */\n>  struct option {\n>  \tenum parse_opt_type type;\n> @@ -217,12 +222,24 @@ struct option {\n>  #define OPT_ALIAS(s, l, source_long_name) \\\n>  \t{ OPTION_ALIAS, (s), (l), (source_long_name) }\n>\n> +static inline int parse_options_pick_subcommand_cb(const struct option *option,\n> +\t\t\t\t\t\t   const char *arg UNUSED,\n> +\t\t\t\t\t\t   int unset UNUSED)\n> +{\n> +\tparse_opt_subcommand_fn *fn = (parse_opt_subcommand_fn *)option->defval;\n> +\t*(parse_opt_subcommand_fn **)option->value = fn;\n\n->defval is of type intptr_t and ->value is a void pointer.  The result\nof converting a void pointer value to an intptr_t and back is a void\npointer equal to the original pointer if I read 6.3.2.3 (Pointers,\nparagraphs 5 and 6) and 7.18.1.4 (Integer types capable of holding\nobject pointers) in C99 correctly.\n\n6.3.2.3 paragraph 8 says that casting between function pointers of\ndifferent type is OK and you can get your original function pointer\nback and use it in a call if you convert it back to the right type.\n\nCasting between a function pointer and an object pointer is undefined,\nthough.  They don't have to be of the same size, so a function pointer\ndoesn't have to fit into an intptr_t.  I wouldn't be surprised if CHERI\n(https://www.cl.cam.ac.uk/research/security/ctsrd/cheri/) was an actual\nexample of that.\n\nWhy is this trickery needed?  Above you write that callbacks in\nbuiltin/bisect--helper.c can't use subcommand_fn because they need\ntheir own argument.  Can we extend subcommand_fn or use a global\nvariable to pass that extra thing instead?  The latter may be ugly, but\nat least it's valid C..\n\n> +\treturn 0;\n> +}\n> +\n>  #define OPT_SUBCOMMAND_F(l, v, fn, f) { \\\n>  \t.type = OPTION_SUBCOMMAND, \\\n>  \t.long_name = (l), \\\n>  \t.value = (v), \\\n>  \t.flags = (f), \\\n> -\t.subcommand_fn = (fn) }\n> +\t.defval = (intptr_t)(fn), \\\n> +\t.subcommand_fn = (fn), \\\n> +\t.callback = parse_options_pick_subcommand_cb, \\\n\nGetting the address of an inline function feels weird, but the compiler\nis free to emit to ignore that keyword and will provide an addressable\nfunction object here.\n\n> +}\n>  #define OPT_SUBCOMMAND(l, v, fn)    OPT_SUBCOMMAND_F((l), (v), (fn), 0)\n>\n>  /*\n\n"},{"id":"466573","messageId":"221104.86iljuyf0e.gmgdl@evledraar.gmail.com","threadId":"58746","inReplyTo":"cover.1667561761.git.congdanhqx@gmail.com","subject":"Re: [PATCH 0/3] Convert git-bisect--helper to OPT_SUBCOMMAND","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-04T13:55:29Z","receivedAt":"2022-11-05T11:07:05Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Fri, Nov 04 2022, Đoàn Trần Công Danh wrote:\n\n> This series aims to fix the problem that bisect--helper incorrectly consumes\n> \"--log\" when running:\n>\n> \tgit bisect run cmd --log\n\nI looked this over, and even though I'm obviously biased towards my own\nshiny toy I really like where the progression & end state here is going.\n\n> This also clears a way for turning git-bisect into a built-in in a later day.\n\nYes, but it would be much appreciated if you could take mine and/or\nJohannes's conversion series, locally rebase it on what you have, and\ncheck that any assumptions you've made here check out once we get to\nthat end goal.\n"},{"id":"466574","messageId":"Y2ZKHPkEXViv9wcp@danh.dev","threadId":"58746","inReplyTo":"df855ba1-52b1-1007-68e8-2e28e85b6822@web.de","subject":"Re: [PATCH 09/13] parse-options API: don't restrict OPT_SUBCOMMAND() to one *_fn type","fromName":"Đoàn Trần Công Danh","fromEmail":"congdanhqx@gmail.com","sentAt":"2022-11-05T11:34:17Z","receivedAt":"2022-11-05T11:34:27Z","isPatch":true,"sender":{"key":"congdanhqx@gmail.com","avatar":"https://avatars.githubusercontent.com/u/42673067?v=4"},"body":" \nOn 2022-11-05 09:32:44+0100, René Scharfe <l.s.r@web.de> wrote:\n> > diff --git a/parse-options.h b/parse-options.h\n> > index b6ef86e0d15..61e3016c3fc 100644\n> > --- a/parse-options.h\n> > +++ b/parse-options.h\n> > @@ -128,19 +128,24 @@ typedef int parse_opt_subcommand_fn(int argc, const char **argv,\n> >   *\t\t\t the option takes optional argument.\n> >   *\n> >   * `callback`::\n> > - *   pointer to the callback to use for OPTION_CALLBACK\n> > + *   pointer to the callback to use for OPTION_CALLBACK and OPTION_SUBCOMMAND.\n> >   *\n> >   * `defval`::\n> >   *   default value to fill (*->value) with for PARSE_OPT_OPTARG.\n> >   *   OPTION_{BIT,SET_INT} store the {mask,integer} to put in the value when met.\n> > + *   OPTION_SUBCOMMAND stores the pointer the function selected for\n> > + *   the subcommand.\n> > + *\n> >   *   CALLBACKS can use it like they want.\n> >   *\n> >   * `ll_callback`::\n> >   *   pointer to the callback to use for OPTION_LOWLEVEL_CALLBACK\n> >   *\n> >   * `subcommand_fn`::\n> > - *   pointer to a function to use for OPTION_SUBCOMMAND.\n> > - *   It will be put in value when the subcommand is given on the command line.\n> > + *   pointer to the callback used with OPT_SUBCOMMAND() and\n> > + *   OPT_SUBCOMMAND_F(). Internally we store the same value in\n> > + *   `defval`. This is only here to give the OPT_SUBCOMMAND{,_F}()\n> > + *   common case type safety.\n> >   */\n> >  struct option {\n> >  \tenum parse_opt_type type;\n> > @@ -217,12 +222,24 @@ struct option {\n> >  #define OPT_ALIAS(s, l, source_long_name) \\\n> >  \t{ OPTION_ALIAS, (s), (l), (source_long_name) }\n> >\n> > +static inline int parse_options_pick_subcommand_cb(const struct option *option,\n> > +\t\t\t\t\t\t   const char *arg UNUSED,\n> > +\t\t\t\t\t\t   int unset UNUSED)\n> > +{\n> > +\tparse_opt_subcommand_fn *fn = (parse_opt_subcommand_fn *)option->defval;\n> > +\t*(parse_opt_subcommand_fn **)option->value = fn;\n> \n> ->defval is of type intptr_t and ->value is a void pointer.  The result\n> of converting a void pointer value to an intptr_t and back is a void\n> pointer equal to the original pointer if I read 6.3.2.3 (Pointers,\n> paragraphs 5 and 6) and 7.18.1.4 (Integer types capable of holding\n> object pointers) in C99 correctly.\n> \n> 6.3.2.3 paragraph 8 says that casting between function pointers of\n> different type is OK and you can get your original function pointer\n> back and use it in a call if you convert it back to the right type.\n> \n> Casting between a function pointer and an object pointer is undefined,\n> though.  They don't have to be of the same size, so a function pointer\n> doesn't have to fit into an intptr_t.  I wouldn't be surprised if CHERI\n> (https://www.cl.cam.ac.uk/research/security/ctsrd/cheri/) was an actual\n> example of that.\n> \n> Why is this trickery needed?  Above you write that callbacks in\n> builtin/bisect--helper.c can't use subcommand_fn because they need\n> their own argument.  Can we extend subcommand_fn or use a global\n> variable to pass that extra thing instead?  The latter may be ugly, but\n> at least it's valid C..\n\nNot the author, but I fully agree with you, I think instead of adding new API\nfor some arbitrary subcommand_fn, I would change the subcommand_fn to\ntype:\n\n\tint (*)(int argc, const char **argv, const char *prefix, void *context)\n\nThe last argument would be an object pointer, which will be casted to\nthe correct type inside the callback.\n\nLet me cherry-picking this series on top of mine to see how things\nwould progress.\n\n> > +\treturn 0;\n> > +}\n> > +\n> >  #define OPT_SUBCOMMAND_F(l, v, fn, f) { \\\n> >  \t.type = OPTION_SUBCOMMAND, \\\n> >  \t.long_name = (l), \\\n> >  \t.value = (v), \\\n> >  \t.flags = (f), \\\n> > -\t.subcommand_fn = (fn) }\n> > +\t.defval = (intptr_t)(fn), \\\n> > +\t.subcommand_fn = (fn), \\\n> > +\t.callback = parse_options_pick_subcommand_cb, \\\n> \n> Getting the address of an inline function feels weird, but the compiler\n> is free to emit to ignore that keyword and will provide an addressable\n> function object here.\n> \n> > +}\n> >  #define OPT_SUBCOMMAND(l, v, fn)    OPT_SUBCOMMAND_F((l), (v), (fn), 0)\n> >\n> >  /*\n> \n\n-- \nDanh\n"},{"id":"466583","messageId":"221105.861qqhxz0o.gmgdl@evledraar.gmail.com","threadId":"58746","inReplyTo":"df855ba1-52b1-1007-68e8-2e28e85b6822@web.de","subject":"Re: [PATCH 09/13] parse-options API: don't restrict OPT_SUBCOMMAND() to one *_fn type","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-05T13:52:59Z","receivedAt":"2022-11-05T14:22:18Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Sat, Nov 05 2022, René Scharfe wrote:\n\n> Am 04.11.22 um 14:22 schrieb Ævar Arnfjörð Bjarmason:\n>> When the OPT_SUBCOMMAND() API was implemented in [1] it did so by\n>> adding a new \"subcommand_fn\" member to \"struct option\", rather than\n>> allowing the user of the API to pick the type of the function.\n>>\n>> An advantage of mandating that \"parse_opt_subcommand_fn\" must be used\n>> is that we'll get type checking for the function we're passing in, a\n>> disadvantage is that we can't convert e.g. \"builtin/bisect--helper.c\"\n>> easily to it, as its callbacks need their own argument.\n>>\n>> Let's generalize this interface, while leaving in place a small hack\n>> to give the existing API users their type safety. We assign to\n>> \"typecheck_subcommand_fn\", but don't subsequently use it for\n>> anything. Instead we use the \"defval\" and \"value\" members.\n>>\n>> A subsequent commit will add a OPT_SUBCOMMAND() variant where the\n>> \"callback\" isn't our default \"parse_options_pick_subcommand\" (and that\n>> caller won't be able to use the type checking).\n>>\n>> 1. fa83cc834da (parse-options: add support for parsing subcommands,\n>>    2022-08-19)\n>>\n>> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n>> ---\n>>  parse-options.c |  9 ++++++---\n>>  parse-options.h | 25 +++++++++++++++++++++----\n>>  2 files changed, 27 insertions(+), 7 deletions(-)\n>>\n>> diff --git a/parse-options.c b/parse-options.c\n>> index a1ec932f0f9..1d9e46c9dc7 100644\n>> --- a/parse-options.c\n>> +++ b/parse-options.c\n>> @@ -427,7 +427,8 @@ static enum parse_opt_result parse_subcommand(const char *arg,\n>>  \tfor (; options->type != OPTION_END; options++)\n>>  \t\tif (options->type == OPTION_SUBCOMMAND &&\n>>  \t\t    !strcmp(options->long_name, arg)) {\n>> -\t\t\t*(parse_opt_subcommand_fn **)options->value = options->subcommand_fn;\n>> +\t\t\tif (options->callback(options, arg, 0))\n>> +\t\t\t\tBUG(\"OPT_SUBCOMMAND callback returning non-zero\");\n>>  \t\t\treturn PARSE_OPT_SUBCOMMAND;\n>>  \t\t}\n>>\n>> @@ -506,8 +507,10 @@ static void parse_options_check(const struct option *opts)\n>>  \t\t\t       \"That case is not supported yet.\");\n>>  \t\t\tbreak;\n>>  \t\tcase OPTION_SUBCOMMAND:\n>> -\t\t\tif (!opts->value || !opts->subcommand_fn)\n>> -\t\t\t\toptbug(opts, \"OPTION_SUBCOMMAND needs a value and a subcommand function\");\n>> +\t\t\tif (!opts->value || !opts->callback)\n>> +\t\t\t\toptbug(opts, \"OPTION_SUBCOMMAND needs a value and a callback function\");\n>> +\t\t\tif (opts->ll_callback)\n>> +\t\t\t\toptbug(opts, \"OPTION_SUBCOMMAND uses callback, not ll_callback\");\n>>  \t\t\tif (!subcommand_value)\n>>  \t\t\t\tsubcommand_value = opts->value;\n>>  \t\t\telse if (subcommand_value != opts->value)\n>> diff --git a/parse-options.h b/parse-options.h\n>> index b6ef86e0d15..61e3016c3fc 100644\n>> --- a/parse-options.h\n>> +++ b/parse-options.h\n>> @@ -128,19 +128,24 @@ typedef int parse_opt_subcommand_fn(int argc, const char **argv,\n>>   *\t\t\t the option takes optional argument.\n>>   *\n>>   * `callback`::\n>> - *   pointer to the callback to use for OPTION_CALLBACK\n>> + *   pointer to the callback to use for OPTION_CALLBACK and OPTION_SUBCOMMAND.\n>>   *\n>>   * `defval`::\n>>   *   default value to fill (*->value) with for PARSE_OPT_OPTARG.\n>>   *   OPTION_{BIT,SET_INT} store the {mask,integer} to put in the value when met.\n>> + *   OPTION_SUBCOMMAND stores the pointer the function selected for\n>> + *   the subcommand.\n>> + *\n>>   *   CALLBACKS can use it like they want.\n>>   *\n>>   * `ll_callback`::\n>>   *   pointer to the callback to use for OPTION_LOWLEVEL_CALLBACK\n>>   *\n>>   * `subcommand_fn`::\n>> - *   pointer to a function to use for OPTION_SUBCOMMAND.\n>> - *   It will be put in value when the subcommand is given on the command line.\n>> + *   pointer to the callback used with OPT_SUBCOMMAND() and\n>> + *   OPT_SUBCOMMAND_F(). Internally we store the same value in\n>> + *   `defval`. This is only here to give the OPT_SUBCOMMAND{,_F}()\n>> + *   common case type safety.\n>>   */\n>>  struct option {\n>>  \tenum parse_opt_type type;\n>> @@ -217,12 +222,24 @@ struct option {\n>>  #define OPT_ALIAS(s, l, source_long_name) \\\n>>  \t{ OPTION_ALIAS, (s), (l), (source_long_name) }\n>>\n>> +static inline int parse_options_pick_subcommand_cb(const struct option *option,\n>> +\t\t\t\t\t\t   const char *arg UNUSED,\n>> +\t\t\t\t\t\t   int unset UNUSED)\n>> +{\n>> +\tparse_opt_subcommand_fn *fn = (parse_opt_subcommand_fn *)option->defval;\n>> +\t*(parse_opt_subcommand_fn **)option->value = fn;\n>\n> ->defval is of type intptr_t and ->value is a void pointer.  The result\n> of converting a void pointer value to an intptr_t and back is a void\n> pointer equal to the original pointer if I read 6.3.2.3 (Pointers,\n> paragraphs 5 and 6) and 7.18.1.4 (Integer types capable of holding\n> object pointers) in C99 correctly.\n>\n> 6.3.2.3 paragraph 8 says that casting between function pointers of\n> different type is OK and you can get your original function pointer\n> back and use it in a call if you convert it back to the right type.\n>\n> Casting between a function pointer and an object pointer is undefined,\n> though.  They don't have to be of the same size, so a function pointer\n> doesn't have to fit into an intptr_t.  I wouldn't be surprised if CHERI\n> (https://www.cl.cam.ac.uk/research/security/ctsrd/cheri/) was an actual\n> example of that.\n\nI should have called this out explicitly. I think you're right as far as\nwhat you're summarizing goes.\n\nTo elaborate on it, paragraph 8 of 6.3.2.3 says:\n\n\tA pointer to a function of one type may be converted to a\n\tpointer to a function of another type and back again; the result\n\tshall compare equal to the original pointer. If a converted\n\tpointer is used to call a function whose type is not compatible\n\twith the pointed-to type, the behavior is undefined.\n\nAnd 7.18.1.4 says, when discussing (among other things) \"intptr_t\"\n(\"[such\" added for clarity:\n\n\t[...]any valid [such] pointer to void can be converted to this\n\ttype, then converted back to pointer to void, and the result\n\twill compare equal to the original pointer:\n\nBut as you point out that doesn't say anything about whether a pointer\nto a function is a \"valid .. pointer to void\".\n\nI think that's an \"unportable\" extension covered in \"J.5 Common\nextensions\", specifically \"J.5.7 Function pointer casts\":\n\n\tA pointer to an object or to void may be cast to a pointer to a\n\tfunction, allowing data to be invoked as a function\n\nThus, since the standard already establishes that valid \"void *\" and\n\"intptr_t\" pointers can be cast'd back & forth, the J.5.7 bridges the\ngap between the two saying a function pointer can be converted to\neither.\n\nNow, I may be missing something here, but I was under the impression\nthat \"intptr_t\" wasn't special in any way here, and that any casting of\na function pointer to either it or a \"void *\" was what was made portable\nby \"J.5.7\". We're only discussing \"intptr_t\" here, so it's just a point\nof clarification.\n\nAnyway, like ssize_t and a few other things this is extended upon and\nmade standard by POSIX. I.e. we're basically talking about whether this\npasses:\n\n\tassert(sizeof(void (*)(void)) == sizeof(void*))\n\nAnd per POSIX\n(https://pubs.opengroup.org/onlinepubs/9699919799/functions/dlsym.html):\n\n\tNote that conversion from a void * pointer to a function pointer\n\tas in:\n\n\t\tfptr = (int (*)(int))dlsym(handle, \"my_function\");\n\n\tis not defined by the ISO C standard. This standard requires\n\tthis conversion to work correctly on conforming implementations.\n\nSo I think aside from other concerns this should be safe to use, as\nreal-world data backing that up we've had a intptr_t converted to a\nfunction pointer since v2.35.0: 5cb28270a1f (pack-objects: lazily set up\n\"struct rev_info\", don't leak, 2022-03-28).\n\n> Why is this trickery needed?  Above you write that callbacks in\n> builtin/bisect--helper.c can't use subcommand_fn because they need\n> their own argument.  Can we extend subcommand_fn or use a global\n> variable to pass that extra thing instead?  The latter may be ugly, but\n> at least it's valid C..\n\nYeah, there's ways around it. Less uglier in this case would probably be\nto just have the callback set a function pointer in your own custom\nstruct (which we'd point to with \"defval).\n\nI.e. if our callabck is the one to populate the \"fn\" even without J.5.7\nthere's no portability issue, and that's just a convenience.\n\n>> +\treturn 0;\n>> +}\n>> +\n>>  #define OPT_SUBCOMMAND_F(l, v, fn, f) { \\\n>>  \t.type = OPTION_SUBCOMMAND, \\\n>>  \t.long_name = (l), \\\n>>  \t.value = (v), \\\n>>  \t.flags = (f), \\\n>> -\t.subcommand_fn = (fn) }\n>> +\t.defval = (intptr_t)(fn), \\\n>> +\t.subcommand_fn = (fn), \\\n>> +\t.callback = parse_options_pick_subcommand_cb, \\\n>\n> Getting the address of an inline function feels weird, but the compiler\n> is free to emit to ignore that keyword and will provide an addressable\n> function object here.\n\n*nod*, I thought about adding this to parse-options-cb.c, but it seemed\n small enough...\n"},{"id":"466586","messageId":"1b158749-44b1-34e0-5b52-1d3bfad9bc9a@dunelm.org.uk","threadId":"58746","inReplyTo":"221105.861qqhxz0o.gmgdl@evledraar.gmail.com","subject":"Re: [PATCH 09/13] parse-options API: don't restrict OPT_SUBCOMMAND() to one *_fn type","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2022-11-05T16:36:19Z","receivedAt":"2022-11-05T16:36:30Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"On 05/11/2022 13:52, Ævar Arnfjörð Bjarmason wrote:\n> \n> On Sat, Nov 05 2022, René Scharfe wrote:\n> \n>> Am 04.11.22 um 14:22 schrieb Ævar Arnfjörð Bjarmason:\n>>> diff --git a/parse-options.h b/parse-options.h\n>>> index b6ef86e0d15..61e3016c3fc 100644\n>>> --- a/parse-options.h\n>>> +++ b/parse-options.h\n>>> @@ -128,19 +128,24 @@ typedef int parse_opt_subcommand_fn(int argc, const char **argv,\n>>>    *\t\t\t the option takes optional argument.\n>>>    *\n>>>    * `callback`::\n>>> - *   pointer to the callback to use for OPTION_CALLBACK\n>>> + *   pointer to the callback to use for OPTION_CALLBACK and OPTION_SUBCOMMAND.\n>>>    *\n>>>    * `defval`::\n>>>    *   default value to fill (*->value) with for PARSE_OPT_OPTARG.\n>>>    *   OPTION_{BIT,SET_INT} store the {mask,integer} to put in the value when met.\n>>> + *   OPTION_SUBCOMMAND stores the pointer the function selected for\n>>> + *   the subcommand.\n>>> + *\n>>>    *   CALLBACKS can use it like they want.\n>>>    *\n>>>    * `ll_callback`::\n>>>    *   pointer to the callback to use for OPTION_LOWLEVEL_CALLBACK\n>>>    *\n>>>    * `subcommand_fn`::\n>>> - *   pointer to a function to use for OPTION_SUBCOMMAND.\n>>> - *   It will be put in value when the subcommand is given on the command line.\n>>> + *   pointer to the callback used with OPT_SUBCOMMAND() and\n>>> + *   OPT_SUBCOMMAND_F(). Internally we store the same value in\n>>> + *   `defval`. This is only here to give the OPT_SUBCOMMAND{,_F}()\n>>> + *   common case type safety.\n>>>    */\n>>>   struct option {\n>>>   \tenum parse_opt_type type;\n>>> @@ -217,12 +222,24 @@ struct option {\n>>>   #define OPT_ALIAS(s, l, source_long_name) \\\n>>>   \t{ OPTION_ALIAS, (s), (l), (source_long_name) }\n>>>\n>>> +static inline int parse_options_pick_subcommand_cb(const struct option *option,\n>>> +\t\t\t\t\t\t   const char *arg UNUSED,\n>>> +\t\t\t\t\t\t   int unset UNUSED)\n>>> +{\n>>> +\tparse_opt_subcommand_fn *fn = (parse_opt_subcommand_fn *)option->defval;\n>>> +\t*(parse_opt_subcommand_fn **)option->value = fn;\n>>\n>> ->defval is of type intptr_t and ->value is a void pointer.  The result\n>> of converting a void pointer value to an intptr_t and back is a void\n>> pointer equal to the original pointer if I read 6.3.2.3 (Pointers,\n>> paragraphs 5 and 6) and 7.18.1.4 (Integer types capable of holding\n>> object pointers) in C99 correctly.\n>>\n>> 6.3.2.3 paragraph 8 says that casting between function pointers of\n>> different type is OK and you can get your original function pointer\n>> back and use it in a call if you convert it back to the right type.\n>>\n>> Casting between a function pointer and an object pointer is undefined,\n>> though.  They don't have to be of the same size, so a function pointer\n>> doesn't have to fit into an intptr_t.  I wouldn't be surprised if CHERI\n>> (https://www.cl.cam.ac.uk/research/security/ctsrd/cheri/) was an actual\n>> example of that.\n> \n> I should have called this out explicitly. I think you're right as far as\n> what you're summarizing goes.\n> \n> To elaborate on it, paragraph 8 of 6.3.2.3 says:\n> \n> \tA pointer to a function of one type may be converted to a\n> \tpointer to a function of another type and back again; the result\n> \tshall compare equal to the original pointer. If a converted\n> \tpointer is used to call a function whose type is not compatible\n> \twith the pointed-to type, the behavior is undefined.\n> \n> And 7.18.1.4 says, when discussing (among other things) \"intptr_t\"\n> (\"[such\" added for clarity:\n> \n> \t[...]any valid [such] pointer to void can be converted to this\n> \ttype, then converted back to pointer to void, and the result\n> \twill compare equal to the original pointer:\n> \n> But as you point out that doesn't say anything about whether a pointer\n> to a function is a \"valid .. pointer to void\".\n> \n> I think that's an \"unportable\" extension covered in \"J.5 Common\n> extensions\", specifically \"J.5.7 Function pointer casts\":\n> \n> \tA pointer to an object or to void may be cast to a pointer to a\n> \tfunction, allowing data to be invoked as a function\n\nThis is a common extension, it is _not_ guaranteed by the standard and \nso still undefined behavior unless your compiler happens to have \nimplemented that extension.\n\n> Thus, since the standard already establishes that valid \"void *\" and\n> \"intptr_t\" pointers can be cast'd back & forth, the J.5.7 bridges the\n> gap between the two saying a function pointer can be converted to\n> either.\n\nHow does J.5.7 bridge the gap when compilers are not required to \nimplement it?\n\n> Now, I may be missing something here, but I was under the impression\n> that \"intptr_t\" wasn't special in any way here, and that any casting of\n> a function pointer to either it or a \"void *\" was what was made portable\n> by \"J.5.7\"\n\nHow is it made portable by an \"unportable\" extension?\n\n> So I think aside from other concerns this should be safe to use, as\n> real-world data backing that up we've had a intptr_t converted to a\n> function pointer since v2.35.0: 5cb28270a1f (pack-objects: lazily set up\n> \"struct rev_info\", don't leak, 2022-03-28).\n\nSaying \"it works so it is fine\" is not a convincing argument that it is \ncompliant with the standard. If it is undefined then it may work now but \nnot in a future compiler.\n\n>> Why is this trickery needed?  Above you write that callbacks in\n>> builtin/bisect--helper.c can't use subcommand_fn because they need\n>> their own argument.  Can we extend subcommand_fn or use a global\n>> variable to pass that extra thing instead?  The latter may be ugly, but\n>> at least it's valid C..\n\nUnfortunately the current code relies on being able to cast function \npointers to void* so it is not just this patch that is relying on \nundefined behavior.\n\nBest Wishes\n\nPhillip\n"},{"id":"466587","messageId":"6b80fd93980ec5171fe0637cbd1a8173a5337da4.1667667058.git.congdanhqx@gmail.com","threadId":"58746","inReplyTo":"cover.1667667058.git.congdanhqx@gmail.com","subject":"[PATCH v2 1/3] bisect--helper: remove unused options","fromName":"Đoàn Trần Công Danh","fromEmail":"congdanhqx@gmail.com","sentAt":"2022-11-05T17:03:34Z","receivedAt":"2022-11-05T17:04:08Z","isPatch":true,"sender":{"key":"congdanhqx@gmail.com","avatar":"https://avatars.githubusercontent.com/u/42673067?v=4"},"body":"'git-bisect.sh' used to have a 'bisect_next_check' to check if we have\nboth good/bad, old/new terms set or not.  In commit 129a6cf344\n(bisect--helper: `bisect_next_check` shell function in C, 2019-01-02),\na subcommand for bisect--helper was introduced to port the check to C.\nSince d1bbbe45df (bisect--helper: reimplement `bisect_run` shell\nfunction in C, 2021-09-13), all users of 'bisect_next_check' was\nre-implemented in C, this subcommand was no longer used but we forgot\nto remove '--bisect-next-check'.\n\n'git-bisect.sh' also used to have a 'bisect_write' function, whose\nthird positional parameter was a \"nolog\" flag.  This flag was only used\nwhen 'bisect_start' invoked 'bisect_write' to write the starting good\nand bad revisions.  Then 0f30233a11 (bisect--helper: `bisect_write`\nshell function in C, 2019-01-02) ported it to C as a command mode of\n'bisect--helper', which (incorrectly) added the '--no-log' option,\nand convert the only place ('bisect_start') that call 'bisect_write'\nwith 'nolog' to 'git bisect--helper --bisect-write' with 'nolog'\ninstead of '--no-log', since 'bisect--helper' has command modes not\nsubcommands, all other command modes see and handle that option as well.\nThis bogus state didn't last long, however, because in the same patch\nseries 06f5608c14 (bisect--helper: `bisect_start` shell function\npartially in C, 2019-01-02) the C reimplementation of bisect_start()\nstarted calling the bisect_write() C function, this time with the\nright 'nolog' function parameter. From then on there was no need for\nthe '--no-log' option in 'bisect--helper'. Eventually all bisect\nsubcommands were ported to C as 'bisect--helper' command modes, each\ncalling the bisect_write() C function instead, but when the\n'--bisect-write' command mode was removed in 68efed8c8a\n(bisect--helper: retire `--bisect-write` subcommand, 2021-02-03) it\nforgot to remove that '--no-log' option.\n'--no-log' option had never been used and it's unused now.\n\nLet's remove --bisect-next-check and --no-log from option parsing.\n\nHelped-by: SZEDER Gábor <szeder.dev@gmail.com>\nSigned-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>\n---\n builtin/bisect--helper.c | 7 +------\n 1 file changed, 1 insertion(+), 6 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 1d2ce8a0e1..5ec2e67f59 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1283,7 +1283,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n {\n \tenum {\n \t\tBISECT_RESET = 1,\n-\t\tBISECT_NEXT_CHECK,\n \t\tBISECT_TERMS,\n \t\tBISECT_START,\n \t\tBISECT_AUTOSTART,\n@@ -1295,12 +1294,10 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\tBISECT_VISUALIZE,\n \t\tBISECT_RUN,\n \t} cmdmode = 0;\n-\tint res = 0, nolog = 0;\n+\tint res = 0;\n \tstruct option options[] = {\n \t\tOPT_CMDMODE(0, \"bisect-reset\", &cmdmode,\n \t\t\t N_(\"reset the bisection state\"), BISECT_RESET),\n-\t\tOPT_CMDMODE(0, \"bisect-next-check\", &cmdmode,\n-\t\t\t N_(\"check whether bad or good terms exist\"), BISECT_NEXT_CHECK),\n \t\tOPT_CMDMODE(0, \"bisect-terms\", &cmdmode,\n \t\t\t N_(\"print out the bisect terms\"), BISECT_TERMS),\n \t\tOPT_CMDMODE(0, \"bisect-start\", &cmdmode,\n@@ -1319,8 +1316,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\t\t N_(\"visualize the bisection\"), BISECT_VISUALIZE),\n \t\tOPT_CMDMODE(0, \"bisect-run\", &cmdmode,\n \t\t\t N_(\"use <cmd>... to automatically bisect\"), BISECT_RUN),\n-\t\tOPT_BOOL(0, \"no-log\", &nolog,\n-\t\t\t N_(\"no log for BISECT_WRITE\")),\n \t\tOPT_END()\n \t};\n \tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\n-- \n2.38.1.157.gedabe22e0a\n\n"},{"id":"466588","messageId":"a62ac72e241fee67e799abcd04ff54a04abd4f53.1667667058.git.congdanhqx@gmail.com","threadId":"58746","inReplyTo":"cover.1667667058.git.congdanhqx@gmail.com","subject":"[PATCH v2 3/3] bisect--helper: parse subcommand with OPT_SUBCOMMAND","fromName":"Đoàn Trần Công Danh","fromEmail":"congdanhqx@gmail.com","sentAt":"2022-11-05T17:03:36Z","receivedAt":"2022-11-05T17:04:08Z","isPatch":true,"sender":{"key":"congdanhqx@gmail.com","avatar":"https://avatars.githubusercontent.com/u/42673067?v=4"},"body":"As of it is, we're parsing subcommand with OPT_CMDMODE, which will\ncontinue to parse more options even if the command has been found.\n\nWhen we're running \"git bisect run\" with a command that expecting\na \"--log\" or \"--no-log\" arguments, or one of those \"--bisect-...\"\narguments, bisect--helper may mistakenly think those options are\nbisect--helper's option.\n\nWe may fix those problems by passing \"--\" when calling from\ngit-bisect.sh, and skip that \"--\" in bisect--helper. However, it may\ninterfere with user's \"--\".\n\nLet's parse subcommand with OPT_SUBCOMMAND since that API was born for\nthis specific use-case.\n\nReported-by: Lukáš Doktor <ldoktor@redhat.com>\nSigned-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>\n---\n builtin/bisect--helper.c    | 87 ++++++++-----------------------------\n git-bisect.sh               | 23 ++--------\n t/t6030-bisect-porcelain.sh | 10 +++++\n 3 files changed, 30 insertions(+), 90 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 292c6fd1dd..d4d813ebfc 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1392,84 +1392,31 @@ static int cmd_bisect__run(int argc, const char **argv, const char *prefix UNUSE\n \n int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n {\n-\tenum {\n-\t\tBISECT_RESET = 1,\n-\t\tBISECT_TERMS,\n-\t\tBISECT_START,\n-\t\tBISECT_AUTOSTART,\n-\t\tBISECT_NEXT,\n-\t\tBISECT_STATE,\n-\t\tBISECT_LOG,\n-\t\tBISECT_REPLAY,\n-\t\tBISECT_SKIP,\n-\t\tBISECT_VISUALIZE,\n-\t\tBISECT_RUN,\n-\t} cmdmode = 0;\n \tint res = 0;\n+\tparse_opt_subcommand_fn *fn = NULL;\n \tstruct option options[] = {\n-\t\tOPT_CMDMODE(0, \"bisect-reset\", &cmdmode,\n-\t\t\t N_(\"reset the bisection state\"), BISECT_RESET),\n-\t\tOPT_CMDMODE(0, \"bisect-terms\", &cmdmode,\n-\t\t\t N_(\"print out the bisect terms\"), BISECT_TERMS),\n-\t\tOPT_CMDMODE(0, \"bisect-start\", &cmdmode,\n-\t\t\t N_(\"start the bisect session\"), BISECT_START),\n-\t\tOPT_CMDMODE(0, \"bisect-next\", &cmdmode,\n-\t\t\t N_(\"find the next bisection commit\"), BISECT_NEXT),\n-\t\tOPT_CMDMODE(0, \"bisect-state\", &cmdmode,\n-\t\t\t N_(\"mark the state of ref (or refs)\"), BISECT_STATE),\n-\t\tOPT_CMDMODE(0, \"bisect-log\", &cmdmode,\n-\t\t\t N_(\"list the bisection steps so far\"), BISECT_LOG),\n-\t\tOPT_CMDMODE(0, \"bisect-replay\", &cmdmode,\n-\t\t\t N_(\"replay the bisection process from the given file\"), BISECT_REPLAY),\n-\t\tOPT_CMDMODE(0, \"bisect-skip\", &cmdmode,\n-\t\t\t N_(\"skip some commits for checkout\"), BISECT_SKIP),\n-\t\tOPT_CMDMODE(0, \"bisect-visualize\", &cmdmode,\n-\t\t\t N_(\"visualize the bisection\"), BISECT_VISUALIZE),\n-\t\tOPT_CMDMODE(0, \"bisect-run\", &cmdmode,\n-\t\t\t N_(\"use <cmd>... to automatically bisect\"), BISECT_RUN),\n+\t\tOPT_SUBCOMMAND(\"reset\", &fn, cmd_bisect__reset),\n+\t\tOPT_SUBCOMMAND(\"terms\", &fn, cmd_bisect__terms),\n+\t\tOPT_SUBCOMMAND(\"start\", &fn, cmd_bisect__start),\n+\t\tOPT_SUBCOMMAND(\"next\", &fn, cmd_bisect__next),\n+\t\tOPT_SUBCOMMAND(\"state\", &fn, cmd_bisect__state),\n+\t\tOPT_SUBCOMMAND(\"log\", &fn, cmd_bisect__log),\n+\t\tOPT_SUBCOMMAND(\"replay\", &fn, cmd_bisect__replay),\n+\t\tOPT_SUBCOMMAND(\"skip\", &fn, cmd_bisect__skip),\n+\t\tOPT_SUBCOMMAND(\"visualize\", &fn, cmd_bisect__visualize),\n+\t\tOPT_SUBCOMMAND(\"view\", &fn, cmd_bisect__visualize),\n+\t\tOPT_SUBCOMMAND(\"run\", &fn, cmd_bisect__run),\n \t\tOPT_END()\n \t};\n \targc = parse_options(argc, argv, prefix, options,\n-\t\t\t     git_bisect_helper_usage,\n-\t\t\t     PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN_OPT);\n+\t\t\t     git_bisect_helper_usage, 0);\n \n-\tif (!cmdmode)\n+\tif (!fn)\n \t\tusage_with_options(git_bisect_helper_usage, options);\n+\targc--;\n+\targv++;\n \n-\tswitch (cmdmode) {\n-\tcase BISECT_RESET:\n-\t\tres = cmd_bisect__reset(argc, argv, prefix);\n-\t\tbreak;\n-\tcase BISECT_TERMS:\n-\t\tres = cmd_bisect__terms(argc, argv, prefix);\n-\t\tbreak;\n-\tcase BISECT_START:\n-\t\tres = cmd_bisect__start(argc, argv, prefix);\n-\t\tbreak;\n-\tcase BISECT_NEXT:\n-\t\tres = cmd_bisect__next(argc, argv, prefix);\n-\t\tbreak;\n-\tcase BISECT_STATE:\n-\t\tres = cmd_bisect__state(argc, argv, prefix);\n-\t\tbreak;\n-\tcase BISECT_LOG:\n-\t\tres = cmd_bisect__log(argc, argv, prefix);\n-\t\tbreak;\n-\tcase BISECT_REPLAY:\n-\t\tres = cmd_bisect__replay(argc, argv, prefix);\n-\t\tbreak;\n-\tcase BISECT_SKIP:\n-\t\tres = cmd_bisect__skip(argc, argv, prefix);\n-\t\tbreak;\n-\tcase BISECT_VISUALIZE:\n-\t\tres = cmd_bisect__visualize(argc, argv, prefix);\n-\t\tbreak;\n-\tcase BISECT_RUN:\n-\t\tres = cmd_bisect__run(argc, argv, prefix);\n-\t\tbreak;\n-\tdefault:\n-\t\tBUG(\"unknown subcommand %d\", cmdmode);\n-\t}\n+\tres = fn(argc, argv, prefix);\n \n \t/*\n \t * Handle early success\ndiff --git a/git-bisect.sh b/git-bisect.sh\nindex 405cf76f2a..dfce4b4f44 100755\n--- a/git-bisect.sh\n+++ b/git-bisect.sh\n@@ -57,28 +57,11 @@ case \"$#\" in\n \tcase \"$cmd\" in\n \thelp)\n \t\tgit bisect -h ;;\n-\tstart)\n-\t\tgit bisect--helper --bisect-start \"$@\" ;;\n \tbad|good|new|old|\"$TERM_BAD\"|\"$TERM_GOOD\")\n-\t\tgit bisect--helper --bisect-state \"$cmd\" \"$@\" ;;\n-\tskip)\n-\t\tgit bisect--helper --bisect-skip \"$@\" || exit;;\n-\tnext)\n-\t\t# Not sure we want \"next\" at the UI level anymore.\n-\t\tgit bisect--helper --bisect-next \"$@\" || exit ;;\n-\tvisualize|view)\n-\t\tgit bisect--helper --bisect-visualize \"$@\" || exit;;\n-\treset)\n-\t\tgit bisect--helper --bisect-reset \"$@\" ;;\n-\treplay)\n-\t\tgit bisect--helper --bisect-replay \"$@\" || exit;;\n+\t\tgit bisect--helper state \"$cmd\" \"$@\" ;;\n \tlog)\n-\t\tgit bisect--helper --bisect-log || exit ;;\n-\trun)\n-\t\tgit bisect--helper --bisect-run \"$@\" || exit;;\n-\tterms)\n-\t\tgit bisect--helper --bisect-terms \"$@\" || exit;;\n+\t\tgit bisect--helper log || exit ;;\n \t*)\n-\t\tusage ;;\n+\t\tgit bisect--helper \"$cmd\" \"$@\" ;;\n \tesac\n esac\ndiff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh\nindex 83931d482f..6dbbe62eb2 100755\n--- a/t/t6030-bisect-porcelain.sh\n+++ b/t/t6030-bisect-porcelain.sh\n@@ -266,6 +266,16 @@ test_expect_success '\"git bisect run\" simple case' '\n \tgit bisect reset\n '\n \n+# We want to make sure no arguments has been eaten\n+test_expect_success '\"git bisect run\" simple case' '\n+\tgit bisect start &&\n+\tgit bisect good $HASH1 &&\n+\tgit bisect bad $HASH4 &&\n+\tgit bisect run printf \"%s %s\\n\" reset --bisect-skip >my_bisect_log.txt &&\n+\tgrep -e \"reset --bisect-skip\" my_bisect_log.txt &&\n+\tgit bisect reset\n+'\n+\n # We want to automatically find the commit that\n # added \"Ciao\" into hello.\n test_expect_success '\"git bisect run\" with more complex \"git bisect start\"' '\n-- \n2.38.1.157.gedabe22e0a\n\n"},{"id":"466589","messageId":"9d8a3cdd7a9472df01f67eb11ebac02a143d270b.1667667058.git.congdanhqx@gmail.com","threadId":"58746","inReplyTo":"cover.1667667058.git.congdanhqx@gmail.com","subject":"[PATCH v2 2/3] bisect--helper: move all subcommands into their own functions","fromName":"Đoàn Trần Công Danh","fromEmail":"congdanhqx@gmail.com","sentAt":"2022-11-05T17:03:35Z","receivedAt":"2022-11-05T17:04:08Z","isPatch":true,"sender":{"key":"congdanhqx@gmail.com","avatar":"https://avatars.githubusercontent.com/u/42673067?v=4"},"body":"In a later change, we will use OPT_SUBCOMMAND to parse sub-commands to\navoid consuming non-option opts.\n\nSince OPT_SUBCOMMAND needs a function pointer to operate,\nlet's move it now.\n\nSigned-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>\n---\n builtin/bisect--helper.c | 155 ++++++++++++++++++++++++++++++---------\n 1 file changed, 121 insertions(+), 34 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 5ec2e67f59..292c6fd1dd 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1279,6 +1279,117 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n \treturn res;\n }\n \n+static int cmd_bisect__reset(int argc, const char **argv, const char *prefix UNUSED)\n+{\n+\tif (argc > 1)\n+\t\treturn error(_(\"--bisect-reset requires either no argument or a commit\"));\n+\treturn bisect_reset(argc ? argv[0] : NULL);\n+}\n+\n+static int cmd_bisect__terms(int argc, const char **argv, const char *prefix UNUSED)\n+{\n+\tint res;\n+\tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\n+\n+\tif (argc > 1)\n+\t\treturn error(_(\"--bisect-terms requires 0 or 1 argument\"));\n+\tres = bisect_terms(&terms, argc == 1 ? argv[0] : NULL);\n+\tfree_terms(&terms);\n+\treturn res;\n+}\n+\n+static int cmd_bisect__start(int argc, const char **argv, const char *prefix UNUSED)\n+{\n+\tint res;\n+\tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\n+\n+\tset_terms(&terms, \"bad\", \"good\");\n+\tres = bisect_start(&terms, argv, argc);\n+\tfree_terms(&terms);\n+\treturn res;\n+}\n+\n+static int cmd_bisect__next(int argc, const char **argv UNUSED, const char *prefix)\n+{\n+\tint res;\n+\tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\n+\n+\tif (argc)\n+\t\treturn error(_(\"--bisect-next requires 0 arguments\"));\n+\tget_terms(&terms);\n+\tres = bisect_next(&terms, prefix);\n+\tfree_terms(&terms);\n+\treturn res;\n+}\n+\n+static int cmd_bisect__state(int argc, const char **argv, const char *prefix UNUSED)\n+{\n+\tint res;\n+\tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\n+\n+\tset_terms(&terms, \"bad\", \"good\");\n+\tget_terms(&terms);\n+\tres = bisect_state(&terms, argv, argc);\n+\tfree_terms(&terms);\n+\treturn res;\n+}\n+\n+static int cmd_bisect__log(int argc, const char **argv UNUSED, const char *prefix UNUSED)\n+{\n+\tif (argc)\n+\t\treturn error(_(\"--bisect-log requires 0 arguments\"));\n+\treturn bisect_log();\n+}\n+\n+static int cmd_bisect__replay(int argc, const char **argv, const char *prefix UNUSED)\n+{\n+\tint res;\n+\tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\n+\n+\tif (argc != 1)\n+\t\treturn error(_(\"no logfile given\"));\n+\tset_terms(&terms, \"bad\", \"good\");\n+\tres = bisect_replay(&terms, argv[0]);\n+\tfree_terms(&terms);\n+\treturn res;\n+}\n+\n+static int cmd_bisect__skip(int argc, const char **argv, const char *prefix UNUSED)\n+{\n+\tint res;\n+\tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\n+\n+\tset_terms(&terms, \"bad\", \"good\");\n+\tget_terms(&terms);\n+\tres = bisect_skip(&terms, argv, argc);\n+\tfree_terms(&terms);\n+\treturn res;\n+}\n+\n+static int cmd_bisect__visualize(int argc, const char **argv, const char *prefix UNUSED)\n+{\n+\tint res;\n+\tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\n+\n+\tget_terms(&terms);\n+\tres = bisect_visualize(&terms, argv, argc);\n+\tfree_terms(&terms);\n+\treturn res;\n+}\n+\n+static int cmd_bisect__run(int argc, const char **argv, const char *prefix UNUSED)\n+{\n+\tint res;\n+\tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\n+\n+\tif (!argc)\n+\t\treturn error(_(\"bisect run failed: no command provided.\"));\n+\tget_terms(&terms);\n+\tres = bisect_run(&terms, argv, argc);\n+\tfree_terms(&terms);\n+\treturn res;\n+}\n+\n int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n {\n \tenum {\n@@ -1318,8 +1429,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\t\t N_(\"use <cmd>... to automatically bisect\"), BISECT_RUN),\n \t\tOPT_END()\n \t};\n-\tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\n-\n \targc = parse_options(argc, argv, prefix, options,\n \t\t\t     git_bisect_helper_usage,\n \t\t\t     PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN_OPT);\n@@ -1329,60 +1438,38 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \n \tswitch (cmdmode) {\n \tcase BISECT_RESET:\n-\t\tif (argc > 1)\n-\t\t\treturn error(_(\"--bisect-reset requires either no argument or a commit\"));\n-\t\tres = bisect_reset(argc ? argv[0] : NULL);\n+\t\tres = cmd_bisect__reset(argc, argv, prefix);\n \t\tbreak;\n \tcase BISECT_TERMS:\n-\t\tif (argc > 1)\n-\t\t\treturn error(_(\"--bisect-terms requires 0 or 1 argument\"));\n-\t\tres = bisect_terms(&terms, argc == 1 ? argv[0] : NULL);\n+\t\tres = cmd_bisect__terms(argc, argv, prefix);\n \t\tbreak;\n \tcase BISECT_START:\n-\t\tset_terms(&terms, \"bad\", \"good\");\n-\t\tres = bisect_start(&terms, argv, argc);\n+\t\tres = cmd_bisect__start(argc, argv, prefix);\n \t\tbreak;\n \tcase BISECT_NEXT:\n-\t\tif (argc)\n-\t\t\treturn error(_(\"--bisect-next requires 0 arguments\"));\n-\t\tget_terms(&terms);\n-\t\tres = bisect_next(&terms, prefix);\n+\t\tres = cmd_bisect__next(argc, argv, prefix);\n \t\tbreak;\n \tcase BISECT_STATE:\n-\t\tset_terms(&terms, \"bad\", \"good\");\n-\t\tget_terms(&terms);\n-\t\tres = bisect_state(&terms, argv, argc);\n+\t\tres = cmd_bisect__state(argc, argv, prefix);\n \t\tbreak;\n \tcase BISECT_LOG:\n-\t\tif (argc)\n-\t\t\treturn error(_(\"--bisect-log requires 0 arguments\"));\n-\t\tres = bisect_log();\n+\t\tres = cmd_bisect__log(argc, argv, prefix);\n \t\tbreak;\n \tcase BISECT_REPLAY:\n-\t\tif (argc != 1)\n-\t\t\treturn error(_(\"no logfile given\"));\n-\t\tset_terms(&terms, \"bad\", \"good\");\n-\t\tres = bisect_replay(&terms, argv[0]);\n+\t\tres = cmd_bisect__replay(argc, argv, prefix);\n \t\tbreak;\n \tcase BISECT_SKIP:\n-\t\tset_terms(&terms, \"bad\", \"good\");\n-\t\tget_terms(&terms);\n-\t\tres = bisect_skip(&terms, argv, argc);\n+\t\tres = cmd_bisect__skip(argc, argv, prefix);\n \t\tbreak;\n \tcase BISECT_VISUALIZE:\n-\t\tget_terms(&terms);\n-\t\tres = bisect_visualize(&terms, argv, argc);\n+\t\tres = cmd_bisect__visualize(argc, argv, prefix);\n \t\tbreak;\n \tcase BISECT_RUN:\n-\t\tif (!argc)\n-\t\t\treturn error(_(\"bisect run failed: no command provided.\"));\n-\t\tget_terms(&terms);\n-\t\tres = bisect_run(&terms, argv, argc);\n+\t\tres = cmd_bisect__run(argc, argv, prefix);\n \t\tbreak;\n \tdefault:\n \t\tBUG(\"unknown subcommand %d\", cmdmode);\n \t}\n-\tfree_terms(&terms);\n \n \t/*\n \t * Handle early success\n-- \n2.38.1.157.gedabe22e0a\n\n"},{"id":"466590","messageId":"cover.1667667058.git.congdanhqx@gmail.com","threadId":"58746","inReplyTo":"cover.1667561761.git.congdanhqx@gmail.com","subject":"[PATCH v2 0/3] Convert git-bisect--helper to OPT_SUBCOMMAND","fromName":"Đoàn Trần Công Danh","fromEmail":"congdanhqx@gmail.com","sentAt":"2022-11-05T17:03:33Z","receivedAt":"2022-11-05T17:04:08Z","isPatch":true,"sender":{"key":"congdanhqx@gmail.com","avatar":"https://avatars.githubusercontent.com/u/42673067?v=4"},"body":"This series aims to fix the problem that bisect--helper incorrectly consumes\n\"--log\" when running:\n\n\tgit bisect run cmd --log\n\nThis also clears a way for turning git-bisect into a built-in in a later day.\n\nThe series that convert git-bisect to builtin will be posted later as a reply\nto this series\n\nĐoàn Trần Công Danh (3):\n  bisect--helper: remove unused options\n  bisect--helper: move all subcommands into their own functions\n  bisect--helper: parse subcommand with OPT_SUBCOMMAND\n\n builtin/bisect--helper.c    | 229 ++++++++++++++++++++----------------\n git-bisect.sh               |  23 +---\n t/t6030-bisect-porcelain.sh |  10 ++\n 3 files changed, 142 insertions(+), 120 deletions(-)\n\nRange-diff against v1:\n1:  abe480d1c9 ! 1:  6b80fd9398 bisect--helper: remove unused options\n    @@ Metadata\n      ## Commit message ##\n         bisect--helper: remove unused options\n     \n    +    'git-bisect.sh' used to have a 'bisect_next_check' to check if we have\n    +    both good/bad, old/new terms set or not.  In commit 129a6cf344\n    +    (bisect--helper: `bisect_next_check` shell function in C, 2019-01-02),\n    +    a subcommand for bisect--helper was introduced to port the check to C.\n    +    Since d1bbbe45df (bisect--helper: reimplement `bisect_run` shell\n    +    function in C, 2021-09-13), all users of 'bisect_next_check' was\n    +    re-implemented in C, this subcommand was no longer used but we forgot\n    +    to remove '--bisect-next-check'.\n    +\n    +    'git-bisect.sh' also used to have a 'bisect_write' function, whose\n    +    third positional parameter was a \"nolog\" flag.  This flag was only used\n    +    when 'bisect_start' invoked 'bisect_write' to write the starting good\n    +    and bad revisions.  Then 0f30233a11 (bisect--helper: `bisect_write`\n    +    shell function in C, 2019-01-02) ported it to C as a command mode of\n    +    'bisect--helper', which (incorrectly) added the '--no-log' option,\n    +    and convert the only place ('bisect_start') that call 'bisect_write'\n    +    with 'nolog' to 'git bisect--helper --bisect-write' with 'nolog'\n    +    instead of '--no-log', since 'bisect--helper' has command modes not\n    +    subcommands, all other command modes see and handle that option as well.\n    +    This bogus state didn't last long, however, because in the same patch\n    +    series 06f5608c14 (bisect--helper: `bisect_start` shell function\n    +    partially in C, 2019-01-02) the C reimplementation of bisect_start()\n    +    started calling the bisect_write() C function, this time with the\n    +    right 'nolog' function parameter. From then on there was no need for\n    +    the '--no-log' option in 'bisect--helper'. Eventually all bisect\n    +    subcommands were ported to C as 'bisect--helper' command modes, each\n    +    calling the bisect_write() C function instead, but when the\n    +    '--bisect-write' command mode was removed in 68efed8c8a\n    +    (bisect--helper: retire `--bisect-write` subcommand, 2021-02-03) it\n    +    forgot to remove that '--no-log' option.\n    +    '--no-log' option had never been used and it's unused now.\n    +\n    +    Let's remove --bisect-next-check and --no-log from option parsing.\n    +\n         Signed-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>\n     \n      ## builtin/bisect--helper.c ##\n2:  94ac8cb999 = 2:  9d8a3cdd7a bisect--helper: move all subcommands into their own functions\n3:  ae967cacd3 ! 3:  a62ac72e24 bisect--helper: parse subcommand with OPT_SUBCOMMAND\n    @@ builtin/bisect--helper.c: static int cmd_bisect__run(int argc, const char **argv\n     -\t\t\t N_(\"visualize the bisection\"), BISECT_VISUALIZE),\n     -\t\tOPT_CMDMODE(0, \"bisect-run\", &cmdmode,\n     -\t\t\t N_(\"use <cmd>... to automatically bisect\"), BISECT_RUN),\n    -+\t\tOPT_SUBCOMMAND(\"bisect-reset\", &fn, cmd_bisect__reset),\n    -+\t\tOPT_SUBCOMMAND(\"bisect-terms\", &fn, cmd_bisect__terms),\n    -+\t\tOPT_SUBCOMMAND(\"bisect-start\", &fn, cmd_bisect__start),\n    -+\t\tOPT_SUBCOMMAND(\"bisect-next\", &fn, cmd_bisect__next),\n    -+\t\tOPT_SUBCOMMAND(\"bisect-state\", &fn, cmd_bisect__state),\n    -+\t\tOPT_SUBCOMMAND(\"bisect-log\", &fn, cmd_bisect__log),\n    -+\t\tOPT_SUBCOMMAND(\"bisect-replay\", &fn, cmd_bisect__replay),\n    -+\t\tOPT_SUBCOMMAND(\"bisect-skip\", &fn, cmd_bisect__skip),\n    -+\t\tOPT_SUBCOMMAND(\"bisect-visualize\", &fn, cmd_bisect__visualize),\n    -+\t\tOPT_SUBCOMMAND(\"bisect-run\", &fn, cmd_bisect__run),\n    ++\t\tOPT_SUBCOMMAND(\"reset\", &fn, cmd_bisect__reset),\n    ++\t\tOPT_SUBCOMMAND(\"terms\", &fn, cmd_bisect__terms),\n    ++\t\tOPT_SUBCOMMAND(\"start\", &fn, cmd_bisect__start),\n    ++\t\tOPT_SUBCOMMAND(\"next\", &fn, cmd_bisect__next),\n    ++\t\tOPT_SUBCOMMAND(\"state\", &fn, cmd_bisect__state),\n    ++\t\tOPT_SUBCOMMAND(\"log\", &fn, cmd_bisect__log),\n    ++\t\tOPT_SUBCOMMAND(\"replay\", &fn, cmd_bisect__replay),\n    ++\t\tOPT_SUBCOMMAND(\"skip\", &fn, cmd_bisect__skip),\n    ++\t\tOPT_SUBCOMMAND(\"visualize\", &fn, cmd_bisect__visualize),\n    ++\t\tOPT_SUBCOMMAND(\"view\", &fn, cmd_bisect__visualize),\n    ++\t\tOPT_SUBCOMMAND(\"run\", &fn, cmd_bisect__run),\n      \t\tOPT_END()\n      \t};\n      \targc = parse_options(argc, argv, prefix, options,\n    @@ builtin/bisect--helper.c: static int cmd_bisect__run(int argc, const char **argv\n     \n      ## git-bisect.sh ##\n     @@ git-bisect.sh: case \"$#\" in\n    + \tcase \"$cmd\" in\n      \thelp)\n      \t\tgit bisect -h ;;\n    - \tstart)\n    +-\tstart)\n     -\t\tgit bisect--helper --bisect-start \"$@\" ;;\n    -+\t\tgit bisect--helper bisect-start \"$@\" ;;\n      \tbad|good|new|old|\"$TERM_BAD\"|\"$TERM_GOOD\")\n     -\t\tgit bisect--helper --bisect-state \"$cmd\" \"$@\" ;;\n    -+\t\tgit bisect--helper bisect-state \"$cmd\" \"$@\" ;;\n    - \tskip)\n    +-\tskip)\n     -\t\tgit bisect--helper --bisect-skip \"$@\" || exit;;\n    -+\t\tgit bisect--helper bisect-skip \"$@\" || exit;;\n    - \tnext)\n    - \t\t# Not sure we want \"next\" at the UI level anymore.\n    +-\tnext)\n    +-\t\t# Not sure we want \"next\" at the UI level anymore.\n     -\t\tgit bisect--helper --bisect-next \"$@\" || exit ;;\n    -+\t\tgit bisect--helper bisect-next \"$@\" || exit ;;\n    - \tvisualize|view)\n    +-\tvisualize|view)\n     -\t\tgit bisect--helper --bisect-visualize \"$@\" || exit;;\n    -+\t\tgit bisect--helper bisect-visualize \"$@\" || exit;;\n    - \treset)\n    +-\treset)\n     -\t\tgit bisect--helper --bisect-reset \"$@\" ;;\n    -+\t\tgit bisect--helper bisect-reset \"$@\" ;;\n    - \treplay)\n    +-\treplay)\n     -\t\tgit bisect--helper --bisect-replay \"$@\" || exit;;\n    -+\t\tgit bisect--helper bisect-replay \"$@\" || exit;;\n    ++\t\tgit bisect--helper state \"$cmd\" \"$@\" ;;\n      \tlog)\n     -\t\tgit bisect--helper --bisect-log || exit ;;\n    -+\t\tgit bisect--helper bisect-log || exit ;;\n    - \trun)\n    +-\trun)\n     -\t\tgit bisect--helper --bisect-run \"$@\" || exit;;\n    -+\t\tgit bisect--helper bisect-run \"$@\" || exit;;\n    - \tterms)\n    +-\tterms)\n     -\t\tgit bisect--helper --bisect-terms \"$@\" || exit;;\n    -+\t\tgit bisect--helper bisect-terms \"$@\" || exit;;\n    ++\t\tgit bisect--helper log || exit ;;\n      \t*)\n    - \t\tusage ;;\n    +-\t\tusage ;;\n    ++\t\tgit bisect--helper \"$cmd\" \"$@\" ;;\n      \tesac\n    + esac\n     \n      ## t/t6030-bisect-porcelain.sh ##\n     @@ t/t6030-bisect-porcelain.sh: test_expect_success '\"git bisect run\" simple case' '\n      \tgit bisect reset\n      '\n      \n    -+# We want to make sure --log is not eaten\n    ++# We want to make sure no arguments has been eaten\n     +test_expect_success '\"git bisect run\" simple case' '\n     +\tgit bisect start &&\n     +\tgit bisect good $HASH1 &&\n     +\tgit bisect bad $HASH4 &&\n    -+\tgit bisect run printf \"%s\\n\" --log >my_bisect_log.txt &&\n    -+\tgrep -e --log my_bisect_log.txt &&\n    ++\tgit bisect run printf \"%s %s\\n\" reset --bisect-skip >my_bisect_log.txt &&\n    ++\tgrep -e \"reset --bisect-skip\" my_bisect_log.txt &&\n     +\tgit bisect reset\n     +'\n     +\n-- \n2.38.1.157.gedabe22e0a\n\n"},{"id":"466591","messageId":"cover.1667667460.git.congdanhqx@gmail.com","threadId":"58746","inReplyTo":"cover.1667667058.git.congdanhqx@gmail.com","subject":"[PATCH 00/13] Turn git-bisect to be builtin","fromName":"Đoàn Trần Công Danh","fromEmail":"congdanhqx@gmail.com","sentAt":"2022-11-05T17:07:31Z","receivedAt":"2022-11-05T17:07:59Z","isPatch":true,"sender":{"key":"congdanhqx@gmail.com","avatar":"https://avatars.githubusercontent.com/u/42673067?v=4"},"body":"This series finish the git-bisect porting from shell script into a C builtin.\n\nThis series can't be applied cleaned on master, it needs to be applied on top\nof the series posted at:\nhttps://lore.kernel.org/git/cover.1667667058.git.congdanhqx@gmail.com/\nAND the series rs/no-more-run-command-v, which has been integrated to next.\n\nThere're two commits which were made by me, one of them is the reversal of the\nother, which I don't really like it but it's there to restore old behaviour\nuntil we justify the change of behaviours.\n\nJohannes Schindelin (2):\n  bisect--helper: make `state` optional\n  Turn `git bisect` into a full built-in\n\nÆvar Arnfjörð Bjarmason (6):\n  bisect tests: test for v2.30.0 \"bisect run\" regressions\n  bisect: refactor bisect_run() to match CodingGuidelines\n  bisect: fix output regressions in v2.30.0\n  bisect run: keep some of the post-v2.30.0 output\n  bisect test: test exit codes on bad usage\n  bisect--helper: emit usage for \"git bisect\"\n\nĐoàn Trần Công Danh (5):\n  bisect--helper: pass arg[cv] down to do_bisect_run\n  bisect--helper: remove unused arguments from do_bisect_run\n  bisect--helper: pretend we're real bisect when report error\n  bisect--helper: remove subcommand state\n  bisect--helper: log: allow arbitrary number of arguments\n\n Makefile                               |   3 +-\n builtin.h                              |   2 +-\n builtin/{bisect--helper.c => bisect.c} | 124 +++++++++++++++----------\n git-bisect.sh                          |   4 -\n git.c                                  |   2 +-\n t/t6030-bisect-porcelain.sh            | 109 ++++++++++++++++++++++\n 6 files changed, 186 insertions(+), 58 deletions(-)\n rename builtin/{bisect--helper.c => bisect.c} (92%)\n\n-- \n2.38.1.157.gedabe22e0a\n\n"},{"id":"466592","messageId":"5571bc36b84210e16ab8731fea8bf0ed8d62cca3.1667667460.git.congdanhqx@gmail.com","threadId":"58746","inReplyTo":"cover.1667667460.git.congdanhqx@gmail.com","subject":"[PATCH 01/13] bisect tests: test for v2.30.0 \"bisect run\" regressions","fromName":"Đoàn Trần Công Danh","fromEmail":"congdanhqx@gmail.com","sentAt":"2022-11-05T17:07:32Z","receivedAt":"2022-11-05T17:08:06Z","isPatch":true,"sender":{"key":"congdanhqx@gmail.com","avatar":"https://avatars.githubusercontent.com/u/42673067?v=4"},"body":"From: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n\nAdd three failing tests which succeed on v2.29.0, but due to the topic\nmerged at [1] (specifically [2]) have been failing since then. We'll\naddress those regressions in subsequent commits.\n\nThere was also a \"regression\" where:\n\n\tgit bisect run ./missing-script.sh\n\nWould count a non-existing script as \"good\", as the shell would exit\nwith 127. That edge case is a bit too insane to preserve, so let's not\nadd it to these regression tests.\n\n1. 0a4cb1f1f2f (Merge branch 'mr/bisect-in-c-4', 2021-09-23)\n2. d1bbbe45df8 (bisect--helper: reimplement `bisect_run` shell\n   function in C, 2021-09-13)\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\nSigned-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>\n---\n t/t6030-bisect-porcelain.sh | 79 +++++++++++++++++++++++++++++++++++++\n 1 file changed, 79 insertions(+)\n\ndiff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh\nindex 6dbbe62eb2..6901bbd202 100755\n--- a/t/t6030-bisect-porcelain.sh\n+++ b/t/t6030-bisect-porcelain.sh\n@@ -252,6 +252,85 @@ test_expect_success 'bisect skip: with commit both bad and skipped' '\n \tgrep $HASH4 my_bisect_log.txt\n '\n \n+test_bisect_run_args () {\n+\ttest_when_finished \"rm -f run.sh actual\" &&\n+\t>actual &&\n+\tcat >expect.args &&\n+\tcat <&6 >expect.out &&\n+\tcat <&7 >expect.err &&\n+\twrite_script run.sh <<-\\EOF &&\n+\twhile test $# != 0\n+\tdo\n+\t\techo \"<$1>\" &&\n+\t\tshift\n+\tdone >actual.args\n+\tEOF\n+\n+\ttest_when_finished \"git bisect reset\" &&\n+\tgit bisect start &&\n+\tgit bisect good $HASH1 &&\n+\tgit bisect bad $HASH4 &&\n+\tgit bisect run ./run.sh $@ >actual.out.raw 2>actual.err &&\n+\t# Prune just the log output\n+\tsed -n \\\n+\t\t-e '/^Author:/d' \\\n+\t\t-e '/^Date:/d' \\\n+\t\t-e '/^$/d' \\\n+\t\t-e '/^commit /d' \\\n+\t\t-e '/^ /d' \\\n+\t\t-e 'p' \\\n+\t\t<actual.out.raw >actual.out &&\n+\ttest_cmp expect.out actual.out &&\n+\ttest_cmp expect.err actual.err &&\n+\ttest_cmp expect.args actual.args\n+}\n+\n+test_expect_failure 'git bisect run: args, stdout and stderr with no arguments' '\n+\ttest_bisect_run_args <<-\\EOF_ARGS 6<<-EOF_OUT 7<<-\\EOF_ERR\n+\tEOF_ARGS\n+\trunning ./run.sh\n+\t$HASH4 is the first bad commit\n+\tbisect run success\n+\tEOF_OUT\n+\tEOF_ERR\n+'\n+\n+test_expect_failure 'git bisect run: args, stdout and stderr: \"--\" argument' '\n+\ttest_bisect_run_args -- <<-\\EOF_ARGS 6<<-EOF_OUT 7<<-\\EOF_ERR\n+\t<-->\n+\tEOF_ARGS\n+\trunning ./run.sh --\n+\t$HASH4 is the first bad commit\n+\tbisect run success\n+\tEOF_OUT\n+\tEOF_ERR\n+'\n+\n+test_expect_failure 'git bisect run: args, stdout and stderr: \"--log foo --no-log bar\" arguments' '\n+\ttest_bisect_run_args --log foo --no-log bar <<-\\EOF_ARGS 6<<-EOF_OUT 7<<-\\EOF_ERR\n+\t<--log>\n+\t<foo>\n+\t<--no-log>\n+\t<bar>\n+\tEOF_ARGS\n+\trunning ./run.sh --log foo --no-log bar\n+\t$HASH4 is the first bad commit\n+\tbisect run success\n+\tEOF_OUT\n+\tEOF_ERR\n+'\n+\n+test_expect_failure 'git bisect run: args, stdout and stderr: \"--bisect-start\" argument' '\n+\ttest_bisect_run_args --bisect-start <<-\\EOF_ARGS 6<<-EOF_OUT 7<<-\\EOF_ERR\n+\t<--bisect-start>\n+\tEOF_ARGS\n+\trunning ./run.sh --bisect-start\n+\t$HASH4 is the first bad commit\n+\tbisect run success\n+\tEOF_OUT\n+\tEOF_ERR\n+'\n+\n # We want to automatically find the commit that\n # added \"Another\" into hello.\n test_expect_success '\"git bisect run\" simple case' '\n-- \n2.38.1.157.gedabe22e0a\n\n"},{"id":"466593","messageId":"dc6ed4c4537a73910043aad70e1b62eb050a770c.1667667460.git.congdanhqx@gmail.com","threadId":"58746","inReplyTo":"cover.1667667460.git.congdanhqx@gmail.com","subject":"[PATCH 02/13] bisect: refactor bisect_run() to match CodingGuidelines","fromName":"Đoàn Trần Công Danh","fromEmail":"congdanhqx@gmail.com","sentAt":"2022-11-05T17:07:33Z","receivedAt":"2022-11-05T17:08:08Z","isPatch":true,"sender":{"key":"congdanhqx@gmail.com","avatar":"https://avatars.githubusercontent.com/u/42673067?v=4"},"body":"From: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n\nWe didn't add \"{}\" to all \"if/else\" branches, and one \"error\" was\nmis-indented. Let's fix that first, which makes subsequent commits\nsmaller. In the case of the \"if\" we can simply early return instead.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\nSigned-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>\n---\n builtin/bisect--helper.c | 7 +++----\n 1 file changed, 3 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex d4d813ebfc..ee1197c8b2 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1191,13 +1191,12 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n \tif (bisect_next_check(terms, NULL))\n \t\treturn BISECT_FAILED;\n \n-\tif (argc)\n-\t\tsq_quote_argv(&command, argv);\n-\telse {\n+\tif (!argc) {\n \t\terror(_(\"bisect run failed: no command provided.\"));\n \t\treturn BISECT_FAILED;\n \t}\n \n+\tsq_quote_argv(&command, argv);\n \twhile (1) {\n \t\tres = do_bisect_run(command.buf);\n \n@@ -1268,7 +1267,7 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n \t\t\tres = BISECT_OK;\n \t\t} else if (res) {\n \t\t\terror(_(\"bisect run failed: 'git bisect--helper --bisect-state\"\n-\t\t\t\" %s' exited with error code %d\"), new_state, res);\n+\t\t\t\t\" %s' exited with error code %d\"), new_state, res);\n \t\t} else {\n \t\t\tcontinue;\n \t\t}\n-- \n2.38.1.157.gedabe22e0a\n\n"},{"id":"466594","messageId":"8a815e231100b8bfcf2b03355cf11a36b2962a38.1667667460.git.congdanhqx@gmail.com","threadId":"58746","inReplyTo":"cover.1667667460.git.congdanhqx@gmail.com","subject":"[PATCH 03/13] bisect--helper: pass arg[cv] down to do_bisect_run","fromName":"Đoàn Trần Công Danh","fromEmail":"congdanhqx@gmail.com","sentAt":"2022-11-05T17:07:34Z","receivedAt":"2022-11-05T17:08:10Z","isPatch":true,"sender":{"key":"congdanhqx@gmail.com","avatar":"https://avatars.githubusercontent.com/u/42673067?v=4"},"body":"Commit d1bbbe45df8 (bisect--helper: reimplement `bisect_run` shell\nfunction in C, 2021-09-13) has changed the logging of bisect-run by\nadding one more space before argv[0], and single-quoting all arguments.\n\nIn a later change, we would like to restore the old behaviours,\nwhich would need information regarding argc and argv.\n\nLet's pass them down, now.\n\nSigned-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>\n---\n builtin/bisect--helper.c | 10 +++++-----\n 1 file changed, 5 insertions(+), 5 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex ee1197c8b2..35e5dc4bbf 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1141,7 +1141,7 @@ static int get_first_good(const char *refname UNUSED,\n \treturn 1;\n }\n \n-static int do_bisect_run(const char *command)\n+static int do_bisect_run(const char *command, int argc UNUSED, const char **argv UNUSED)\n {\n \tstruct child_process cmd = CHILD_PROCESS_INIT;\n \n@@ -1151,7 +1151,7 @@ static int do_bisect_run(const char *command)\n \treturn run_command(&cmd);\n }\n \n-static int verify_good(const struct bisect_terms *terms, const char *command)\n+static int verify_good(const struct bisect_terms *terms, const char *command, int argc, const char **argv)\n {\n \tint rc;\n \tenum bisect_error res;\n@@ -1171,7 +1171,7 @@ static int verify_good(const struct bisect_terms *terms, const char *command)\n \tif (res != BISECT_OK)\n \t\treturn -1;\n \n-\trc = do_bisect_run(command);\n+\trc = do_bisect_run(command, argc, argv);\n \n \tres = bisect_checkout(&current_rev, no_checkout);\n \tif (res != BISECT_OK)\n@@ -1198,7 +1198,7 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n \n \tsq_quote_argv(&command, argv);\n \twhile (1) {\n-\t\tres = do_bisect_run(command.buf);\n+\t\tres = do_bisect_run(command.buf, argc, argv);\n \n \t\t/*\n \t\t * Exit code 126 and 127 can either come from the shell\n@@ -1208,7 +1208,7 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n \t\t * missing or non-executable script.\n \t\t */\n \t\tif (is_first_run && (res == 126 || res == 127)) {\n-\t\t\tint rc = verify_good(terms, command.buf);\n+\t\t\tint rc = verify_good(terms, command.buf, argc, argv);\n \t\t\tis_first_run = 0;\n \t\t\tif (rc < 0) {\n \t\t\t\terror(_(\"unable to verify '%s' on good\"\n-- \n2.38.1.157.gedabe22e0a\n\n"},{"id":"466595","messageId":"31cd78f53878b09ae74e40994070fbc8c25102f7.1667667460.git.congdanhqx@gmail.com","threadId":"58746","inReplyTo":"cover.1667667460.git.congdanhqx@gmail.com","subject":"[PATCH 04/13] bisect: fix output regressions in v2.30.0","fromName":"Đoàn Trần Công Danh","fromEmail":"congdanhqx@gmail.com","sentAt":"2022-11-05T17:07:35Z","receivedAt":"2022-11-05T17:08:19Z","isPatch":true,"sender":{"key":"congdanhqx@gmail.com","avatar":"https://avatars.githubusercontent.com/u/42673067?v=4"},"body":"From: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n\nWhen d1bbbe45df8 (bisect--helper: reimplement `bisect_run` shell\nfunction in C, 2021-09-13) reimplemented parts of \"git bisect run\" in\nC it changed the output we emitted so that:\n\n - The \"running ...\" line was now quoted\n - We lost the \\n after our output\n - We started saying \"bisect found ...\" instead of \"bisect run success\"\n\nArguably some of this is better now, but as d1bbbe45df8 did not\nadvocate for changing the output, let's revert this for now. It'll be\neasy to change it back if that's what we'd prefer.\n\nThis does not change the one remaining use of \"command.buf\" to emit\nthe quoted argument, as that's new in d1bbbe45df8.\n\nSome of these cases were not tested for in the tests added in the\npreceding commit, I didn't have time to fleshen those out, but a look\nat f1de981e8b6 will show that the other output being adjusted here is\nnow equivalent to what it was before d1bbbe45df8.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\nSigned-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>\n---\n builtin/bisect--helper.c    | 13 ++++++++-----\n t/t6030-bisect-porcelain.sh |  8 ++++----\n 2 files changed, 12 insertions(+), 9 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 35e5dc4bbf..7416283d07 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1141,11 +1141,14 @@ static int get_first_good(const char *refname UNUSED,\n \treturn 1;\n }\n \n-static int do_bisect_run(const char *command, int argc UNUSED, const char **argv UNUSED)\n+static int do_bisect_run(const char *command, int argc, const char **argv)\n {\n \tstruct child_process cmd = CHILD_PROCESS_INIT;\n+\tstruct strbuf buf = STRBUF_INIT;\n \n-\tprintf(_(\"running %s\\n\"), command);\n+\tstrbuf_join_argv(&buf, argc, argv, ' ');\n+\tprintf(_(\"running %s\\n\"), buf.buf);\n+\tstrbuf_release(&buf);\n \tcmd.use_shell = 1;\n \tstrvec_push(&cmd.args, command);\n \treturn run_command(&cmd);\n@@ -1260,13 +1263,13 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n \t\tif (res == BISECT_ONLY_SKIPPED_LEFT)\n \t\t\terror(_(\"bisect run cannot continue any more\"));\n \t\telse if (res == BISECT_INTERNAL_SUCCESS_MERGE_BASE) {\n-\t\t\tprintf(_(\"bisect run success\"));\n+\t\t\tputs(_(\"bisect run success\"));\n \t\t\tres = BISECT_OK;\n \t\t} else if (res == BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND) {\n-\t\t\tprintf(_(\"bisect found first bad commit\"));\n+\t\t\tputs(_(\"bisect run success\"));\n \t\t\tres = BISECT_OK;\n \t\t} else if (res) {\n-\t\t\terror(_(\"bisect run failed: 'git bisect--helper --bisect-state\"\n+\t\t\terror(_(\"bisect run failed: 'bisect-state\"\n \t\t\t\t\" %s' exited with error code %d\"), new_state, res);\n \t\t} else {\n \t\t\tcontinue;\ndiff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh\nindex 6901bbd202..914ea564b9 100755\n--- a/t/t6030-bisect-porcelain.sh\n+++ b/t/t6030-bisect-porcelain.sh\n@@ -285,7 +285,7 @@ test_bisect_run_args () {\n \ttest_cmp expect.args actual.args\n }\n \n-test_expect_failure 'git bisect run: args, stdout and stderr with no arguments' '\n+test_expect_success 'git bisect run: args, stdout and stderr with no arguments' '\n \ttest_bisect_run_args <<-\\EOF_ARGS 6<<-EOF_OUT 7<<-\\EOF_ERR\n \tEOF_ARGS\n \trunning ./run.sh\n@@ -295,7 +295,7 @@ test_expect_failure 'git bisect run: args, stdout and stderr with no arguments'\n \tEOF_ERR\n '\n \n-test_expect_failure 'git bisect run: args, stdout and stderr: \"--\" argument' '\n+test_expect_success 'git bisect run: args, stdout and stderr: \"--\" argument' '\n \ttest_bisect_run_args -- <<-\\EOF_ARGS 6<<-EOF_OUT 7<<-\\EOF_ERR\n \t<-->\n \tEOF_ARGS\n@@ -306,7 +306,7 @@ test_expect_failure 'git bisect run: args, stdout and stderr: \"--\" argument' '\n \tEOF_ERR\n '\n \n-test_expect_failure 'git bisect run: args, stdout and stderr: \"--log foo --no-log bar\" arguments' '\n+test_expect_success 'git bisect run: args, stdout and stderr: \"--log foo --no-log bar\" arguments' '\n \ttest_bisect_run_args --log foo --no-log bar <<-\\EOF_ARGS 6<<-EOF_OUT 7<<-\\EOF_ERR\n \t<--log>\n \t<foo>\n@@ -320,7 +320,7 @@ test_expect_failure 'git bisect run: args, stdout and stderr: \"--log foo --no-lo\n \tEOF_ERR\n '\n \n-test_expect_failure 'git bisect run: args, stdout and stderr: \"--bisect-start\" argument' '\n+test_expect_success 'git bisect run: args, stdout and stderr: \"--bisect-start\" argument' '\n \ttest_bisect_run_args --bisect-start <<-\\EOF_ARGS 6<<-EOF_OUT 7<<-\\EOF_ERR\n \t<--bisect-start>\n \tEOF_ARGS\n-- \n2.38.1.157.gedabe22e0a\n\n"},{"id":"466596","messageId":"5ba3bafdd48b47320624d0db06f379bc0a4b8d4e.1667667460.git.congdanhqx@gmail.com","threadId":"58746","inReplyTo":"cover.1667667460.git.congdanhqx@gmail.com","subject":"[PATCH 05/13] bisect run: keep some of the post-v2.30.0 output","fromName":"Đoàn Trần Công Danh","fromEmail":"congdanhqx@gmail.com","sentAt":"2022-11-05T17:07:36Z","receivedAt":"2022-11-05T17:08:22Z","isPatch":true,"sender":{"key":"congdanhqx@gmail.com","avatar":"https://avatars.githubusercontent.com/u/42673067?v=4"},"body":"From: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n\nPreceding commits fixed output and behavior regressions in\nd1bbbe45df8 (bisect--helper: reimplement `bisect_run` shell function\nin C, 2021-09-13), which did not claim to be changing the output of\n\"git bisect run\".\n\nBut some of the output it emitted was subjectively better, so once\nwe've asserted that we're back on v2.29.0 behavior, let's change some\nof it back:\n\n- We now quote the arguments again, but omit the first \" \" when\n  printing the \"running\" line.\n- Ditto for other cases where we emitted the argument\n- We say \"found first bad commit\" again, not just \"run success\"\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\nSigned-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>\n---\n builtin/bisect--helper.c    | 12 ++++++------\n t/t6030-bisect-porcelain.sh | 16 ++++++++--------\n 2 files changed, 14 insertions(+), 14 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 7416283d07..f16b9df8fd 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1141,14 +1141,14 @@ static int get_first_good(const char *refname UNUSED,\n \treturn 1;\n }\n \n-static int do_bisect_run(const char *command, int argc, const char **argv)\n+static int do_bisect_run(const char *command, int argc UNUSED, const char **argv UNUSED)\n {\n \tstruct child_process cmd = CHILD_PROCESS_INIT;\n-\tstruct strbuf buf = STRBUF_INIT;\n+\tconst char *trimed = command;\n \n-\tstrbuf_join_argv(&buf, argc, argv, ' ');\n-\tprintf(_(\"running %s\\n\"), buf.buf);\n-\tstrbuf_release(&buf);\n+\twhile (*trimed && isspace(*trimed))\n+\t\ttrimed++;\n+\tprintf(_(\"running %s\\n\"), trimed);\n \tcmd.use_shell = 1;\n \tstrvec_push(&cmd.args, command);\n \treturn run_command(&cmd);\n@@ -1266,7 +1266,7 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n \t\t\tputs(_(\"bisect run success\"));\n \t\t\tres = BISECT_OK;\n \t\t} else if (res == BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND) {\n-\t\t\tputs(_(\"bisect run success\"));\n+\t\t\tputs(_(\"bisect found first bad commit\"));\n \t\t\tres = BISECT_OK;\n \t\t} else if (res) {\n \t\t\terror(_(\"bisect run failed: 'bisect-state\"\ndiff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh\nindex 914ea564b9..9e14e1e836 100755\n--- a/t/t6030-bisect-porcelain.sh\n+++ b/t/t6030-bisect-porcelain.sh\n@@ -288,9 +288,9 @@ test_bisect_run_args () {\n test_expect_success 'git bisect run: args, stdout and stderr with no arguments' '\n \ttest_bisect_run_args <<-\\EOF_ARGS 6<<-EOF_OUT 7<<-\\EOF_ERR\n \tEOF_ARGS\n-\trunning ./run.sh\n+\trunning '\\''./run.sh'\\''\n \t$HASH4 is the first bad commit\n-\tbisect run success\n+\tbisect found first bad commit\n \tEOF_OUT\n \tEOF_ERR\n '\n@@ -299,9 +299,9 @@ test_expect_success 'git bisect run: args, stdout and stderr: \"--\" argument' '\n \ttest_bisect_run_args -- <<-\\EOF_ARGS 6<<-EOF_OUT 7<<-\\EOF_ERR\n \t<-->\n \tEOF_ARGS\n-\trunning ./run.sh --\n+\trunning '\\''./run.sh'\\'' '\\''--'\\''\n \t$HASH4 is the first bad commit\n-\tbisect run success\n+\tbisect found first bad commit\n \tEOF_OUT\n \tEOF_ERR\n '\n@@ -313,9 +313,9 @@ test_expect_success 'git bisect run: args, stdout and stderr: \"--log foo --no-lo\n \t<--no-log>\n \t<bar>\n \tEOF_ARGS\n-\trunning ./run.sh --log foo --no-log bar\n+\trunning '\\''./run.sh'\\'' '\\''--log'\\'' '\\''foo'\\'' '\\''--no-log'\\'' '\\''bar'\\''\n \t$HASH4 is the first bad commit\n-\tbisect run success\n+\tbisect found first bad commit\n \tEOF_OUT\n \tEOF_ERR\n '\n@@ -324,9 +324,9 @@ test_expect_success 'git bisect run: args, stdout and stderr: \"--bisect-start\" a\n \ttest_bisect_run_args --bisect-start <<-\\EOF_ARGS 6<<-EOF_OUT 7<<-\\EOF_ERR\n \t<--bisect-start>\n \tEOF_ARGS\n-\trunning ./run.sh --bisect-start\n+\trunning '\\''./run.sh'\\'' '\\''--bisect-start'\\''\n \t$HASH4 is the first bad commit\n-\tbisect run success\n+\tbisect found first bad commit\n \tEOF_OUT\n \tEOF_ERR\n '\n-- \n2.38.1.157.gedabe22e0a\n\n"},{"id":"466597","messageId":"32ad47ddc521320dd67947b20fe548184d1a6b36.1667667460.git.congdanhqx@gmail.com","threadId":"58746","inReplyTo":"cover.1667667460.git.congdanhqx@gmail.com","subject":"[PATCH 06/13] bisect--helper: remove unused arguments from do_bisect_run","fromName":"Đoàn Trần Công Danh","fromEmail":"congdanhqx@gmail.com","sentAt":"2022-11-05T17:07:37Z","receivedAt":"2022-11-05T17:08:23Z","isPatch":true,"sender":{"key":"congdanhqx@gmail.com","avatar":"https://avatars.githubusercontent.com/u/42673067?v=4"},"body":"Those arguments become unused with previous commit, let's remove them\nnow.  This effectively reverts commit HEAD~3.\n\nSigned-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>\n---\n builtin/bisect--helper.c | 10 +++++-----\n 1 file changed, 5 insertions(+), 5 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex f16b9df8fd..b99cbb0dbe 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1141,7 +1141,7 @@ static int get_first_good(const char *refname UNUSED,\n \treturn 1;\n }\n \n-static int do_bisect_run(const char *command, int argc UNUSED, const char **argv UNUSED)\n+static int do_bisect_run(const char *command)\n {\n \tstruct child_process cmd = CHILD_PROCESS_INIT;\n \tconst char *trimed = command;\n@@ -1154,7 +1154,7 @@ static int do_bisect_run(const char *command, int argc UNUSED, const char **argv\n \treturn run_command(&cmd);\n }\n \n-static int verify_good(const struct bisect_terms *terms, const char *command, int argc, const char **argv)\n+static int verify_good(const struct bisect_terms *terms, const char *command)\n {\n \tint rc;\n \tenum bisect_error res;\n@@ -1174,7 +1174,7 @@ static int verify_good(const struct bisect_terms *terms, const char *command, in\n \tif (res != BISECT_OK)\n \t\treturn -1;\n \n-\trc = do_bisect_run(command, argc, argv);\n+\trc = do_bisect_run(command);\n \n \tres = bisect_checkout(&current_rev, no_checkout);\n \tif (res != BISECT_OK)\n@@ -1201,7 +1201,7 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n \n \tsq_quote_argv(&command, argv);\n \twhile (1) {\n-\t\tres = do_bisect_run(command.buf, argc, argv);\n+\t\tres = do_bisect_run(command.buf);\n \n \t\t/*\n \t\t * Exit code 126 and 127 can either come from the shell\n@@ -1211,7 +1211,7 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n \t\t * missing or non-executable script.\n \t\t */\n \t\tif (is_first_run && (res == 126 || res == 127)) {\n-\t\t\tint rc = verify_good(terms, command.buf, argc, argv);\n+\t\t\tint rc = verify_good(terms, command.buf);\n \t\t\tis_first_run = 0;\n \t\t\tif (rc < 0) {\n \t\t\t\terror(_(\"unable to verify '%s' on good\"\n-- \n2.38.1.157.gedabe22e0a\n\n"},{"id":"466598","messageId":"f212e6428855f0b0839bf6befd7c4703c505cc66.1667667460.git.congdanhqx@gmail.com","threadId":"58746","inReplyTo":"cover.1667667460.git.congdanhqx@gmail.com","subject":"[PATCH 07/13] bisect--helper: pretend we're real bisect when report error","fromName":"Đoàn Trần Công Danh","fromEmail":"congdanhqx@gmail.com","sentAt":"2022-11-05T17:07:38Z","receivedAt":"2022-11-05T17:08:35Z","isPatch":true,"sender":{"key":"congdanhqx@gmail.com","avatar":"https://avatars.githubusercontent.com/u/42673067?v=4"},"body":"In a later change, we will convert the bisect--helper to be builtin\nbisect. Let's start by pretending it's the real bisect when reporting\nerror.\n\nSigned-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>\n---\n builtin/bisect--helper.c | 13 ++++++++-----\n 1 file changed, 8 insertions(+), 5 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex b99cbb0dbe..6be4d8861e 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1284,7 +1284,8 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n static int cmd_bisect__reset(int argc, const char **argv, const char *prefix UNUSED)\n {\n \tif (argc > 1)\n-\t\treturn error(_(\"--bisect-reset requires either no argument or a commit\"));\n+\t\treturn error(_(\"'%s' requires either no argument or a commit\"),\n+\t\t\t     \"git bisect reset\");\n \treturn bisect_reset(argc ? argv[0] : NULL);\n }\n \n@@ -1294,7 +1295,8 @@ static int cmd_bisect__terms(int argc, const char **argv, const char *prefix UNU\n \tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\n \n \tif (argc > 1)\n-\t\treturn error(_(\"--bisect-terms requires 0 or 1 argument\"));\n+\t\treturn error(_(\"'%s' requires 0 or 1 argument\"),\n+\t\t\t     \"git bisect terms\");\n \tres = bisect_terms(&terms, argc == 1 ? argv[0] : NULL);\n \tfree_terms(&terms);\n \treturn res;\n@@ -1317,7 +1319,8 @@ static int cmd_bisect__next(int argc, const char **argv UNUSED, const char *pref\n \tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\n \n \tif (argc)\n-\t\treturn error(_(\"--bisect-next requires 0 arguments\"));\n+\t\treturn error(_(\"'%s' requires 0 arguments\"),\n+\t\t\t     \"git bisect next\");\n \tget_terms(&terms);\n \tres = bisect_next(&terms, prefix);\n \tfree_terms(&terms);\n@@ -1339,7 +1342,7 @@ static int cmd_bisect__state(int argc, const char **argv, const char *prefix UNU\n static int cmd_bisect__log(int argc, const char **argv UNUSED, const char *prefix UNUSED)\n {\n \tif (argc)\n-\t\treturn error(_(\"--bisect-log requires 0 arguments\"));\n+\t\treturn error(_(\"'%s' requires 0 arguments\"), \"git bisect log\");\n \treturn bisect_log();\n }\n \n@@ -1385,7 +1388,7 @@ static int cmd_bisect__run(int argc, const char **argv, const char *prefix UNUSE\n \tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\n \n \tif (!argc)\n-\t\treturn error(_(\"bisect run failed: no command provided.\"));\n+\t\treturn error(_(\"'%s' failed: no command provided.\"), \"git bisect run\");\n \tget_terms(&terms);\n \tres = bisect_run(&terms, argv, argc);\n \tfree_terms(&terms);\n-- \n2.38.1.157.gedabe22e0a\n\n"},{"id":"466599","messageId":"4c1beb8bf8e4237c3c03fc3298bb3e5979740e1b.1667667460.git.congdanhqx@gmail.com","threadId":"58746","inReplyTo":"cover.1667667460.git.congdanhqx@gmail.com","subject":"[PATCH 08/13] bisect test: test exit codes on bad usage","fromName":"Đoàn Trần Công Danh","fromEmail":"congdanhqx@gmail.com","sentAt":"2022-11-05T17:07:39Z","receivedAt":"2022-11-05T17:08:39Z","isPatch":true,"sender":{"key":"congdanhqx@gmail.com","avatar":"https://avatars.githubusercontent.com/u/42673067?v=4"},"body":"From: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n\nAddress a test blindspot, the \"log\" command is the odd one out because\n\"git-bisect.sh\" ignores any arguments it receives. Let's test both the\nexit codes we expect, and the stderr and stdout we're emitting.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\nSigned-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>\n---\n t/t6030-bisect-porcelain.sh | 30 ++++++++++++++++++++++++++++++\n 1 file changed, 30 insertions(+)\n\ndiff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh\nindex 9e14e1e836..01eaa368d9 100755\n--- a/t/t6030-bisect-porcelain.sh\n+++ b/t/t6030-bisect-porcelain.sh\n@@ -34,6 +34,36 @@ HASH2=\n HASH3=\n HASH4=\n \n+test_bisect_usage () {\n+\tlocal code=\"$1\" &&\n+\tshift &&\n+\tcat >expect &&\n+\ttest_expect_code $code \"$@\" >out 2>actual &&\n+\ttest_must_be_empty out &&\n+\ttest_cmp expect actual\n+}\n+\n+test_expect_success 'bisect usage' \"\n+\ttest_bisect_usage 1 git bisect reset extra1 extra2 <<-\\EOF &&\n+\terror: 'git bisect reset' requires either no argument or a commit\n+\tEOF\n+\ttest_bisect_usage 1 git bisect terms extra1 extra2 <<-\\EOF &&\n+\terror: 'git bisect terms' requires 0 or 1 argument\n+\tEOF\n+\ttest_bisect_usage 1 git bisect next extra1 <<-\\EOF &&\n+\terror: 'git bisect next' requires 0 arguments\n+\tEOF\n+\ttest_bisect_usage 1 git bisect log extra1 <<-\\EOF &&\n+\terror: We are not bisecting.\n+\tEOF\n+\ttest_bisect_usage 1 git bisect replay <<-\\EOF &&\n+\terror: no logfile given\n+\tEOF\n+\ttest_bisect_usage 1 git bisect run <<-\\EOF\n+\terror: 'git bisect run' failed: no command provided.\n+\tEOF\n+\"\n+\n test_expect_success 'set up basic repo with 1 file (hello) and 4 commits' '\n      add_line_into_file \"1: Hello World\" hello &&\n      HASH1=$(git rev-parse --verify HEAD) &&\n-- \n2.38.1.157.gedabe22e0a\n\n"},{"id":"466600","messageId":"b494a4cf4ecfbe1768b5879c3f70891f651f2529.1667667460.git.congdanhqx@gmail.com","threadId":"58746","inReplyTo":"cover.1667667460.git.congdanhqx@gmail.com","subject":"[PATCH 09/13] bisect--helper: emit usage for \"git bisect\"","fromName":"Đoàn Trần Công Danh","fromEmail":"congdanhqx@gmail.com","sentAt":"2022-11-05T17:07:40Z","receivedAt":"2022-11-05T17:08:42Z","isPatch":true,"sender":{"key":"congdanhqx@gmail.com","avatar":"https://avatars.githubusercontent.com/u/42673067?v=4"},"body":"From: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n\nIn subsequent commits we'll be removing \"git-bisect.sh\" in favor of\npromoting \"bisect--helper\" to a \"bisect\" built-in.\n\nIn doing that we'll first need to have it support \"git bisect--helper\n<cmd>\" rather than \"git bisect--helper --<cmd>\", and then finally have\nits \"-h\" output claim to be \"bisect\" rather than \"bisect--helper\".\n\nInstead of suffering that churn let's start claiming to be \"git\nbisect\" now. In just a few commits this will be true, and in the\nmeantime emitting the \"wrong\" usage information from the helper is a\nsmall price to pay to avoid the churn.\n\nLet's also declare \"BUILTIN_*\" macros, when we eventually migrate the\nsub-commands themselves to parse_options() we'll be able to re-use the\nstrings. See 0afd556b2e1 (worktree: define subcommand -h in terms of\ncommand -h, 2022-10-13) for a recent example.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\nSigned-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>\n---\n builtin/bisect--helper.c | 51 ++++++++++++++++++++++++++++------------\n 1 file changed, 36 insertions(+), 15 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 6be4d8861e..bfa160dbf2 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -20,18 +20,40 @@ static GIT_PATH_FUNC(git_path_bisect_names, \"BISECT_NAMES\")\n static GIT_PATH_FUNC(git_path_bisect_first_parent, \"BISECT_FIRST_PARENT\")\n static GIT_PATH_FUNC(git_path_bisect_run, \"BISECT_RUN\")\n \n-static const char * const git_bisect_helper_usage[] = {\n-\tN_(\"git bisect--helper --bisect-reset [<commit>]\"),\n-\t\"git bisect--helper --bisect-terms [--term-good | --term-old | --term-bad | --term-new]\",\n-\tN_(\"git bisect--helper --bisect-start [--term-{new,bad}=<term> --term-{old,good}=<term>]\"\n-\t\t\t\t\t    \" [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<paths>...]\"),\n-\t\"git bisect--helper --bisect-next\",\n-\tN_(\"git bisect--helper --bisect-state (bad|new) [<rev>]\"),\n-\tN_(\"git bisect--helper --bisect-state (good|old) [<rev>...]\"),\n-\tN_(\"git bisect--helper --bisect-replay <filename>\"),\n-\tN_(\"git bisect--helper --bisect-skip [(<rev>|<range>)...]\"),\n-\t\"git bisect--helper --bisect-visualize\",\n-\tN_(\"git bisect--helper --bisect-run <cmd>...\"),\n+#define BUILTIN_GIT_BISECT_START_USAGE \\\n+\tN_(\"git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>]\" \\\n+\t   \"    [--no-checkout] [--first-parent] [<bad> [<good>...]] [--]\" \\\n+\t   \"    [<pathspec>...]\")\n+#define BUILTIN_GIT_BISECT_STATE_USAGE \\\n+\tN_(\"git bisect (good|bad) [<rev>...]\")\n+#define BUILTIN_GIT_BISECT_TERMS_USAGE \\\n+\t\"git bisect terms [--term-good | --term-bad]\"\n+#define BUILTIN_GIT_BISECT_SKIP_USAGE \\\n+\tN_(\"git bisect skip [(<rev>|<range>)...]\")\n+#define BUILTIN_GIT_BISECT_NEXT_USAGE \\\n+\t\"git bisect next\"\n+#define BUILTIN_GIT_BISECT_RESET_USAGE \\\n+\tN_(\"git bisect reset [<commit>]\")\n+#define BUILTIN_GIT_BISECT_VISUALIZE_USAGE \\\n+\t\"git bisect visualize\"\n+#define BUILTIN_GIT_BISECT_REPLAY_USAGE \\\n+\tN_(\"git bisect replay <logfile>\")\n+#define BUILTIN_GIT_BISECT_LOG_USAGE \\\n+\t\"git bisect log\"\n+#define BUILTIN_GIT_BISECT_RUN_USAGE \\\n+\tN_(\"git bisect run <cmd>...\")\n+\n+static const char * const git_bisect_usage[] = {\n+\tBUILTIN_GIT_BISECT_START_USAGE,\n+\tBUILTIN_GIT_BISECT_STATE_USAGE,\n+\tBUILTIN_GIT_BISECT_TERMS_USAGE,\n+\tBUILTIN_GIT_BISECT_SKIP_USAGE,\n+\tBUILTIN_GIT_BISECT_NEXT_USAGE,\n+\tBUILTIN_GIT_BISECT_RESET_USAGE,\n+\tBUILTIN_GIT_BISECT_VISUALIZE_USAGE,\n+\tBUILTIN_GIT_BISECT_REPLAY_USAGE,\n+\tBUILTIN_GIT_BISECT_LOG_USAGE,\n+\tBUILTIN_GIT_BISECT_RUN_USAGE,\n \tNULL\n };\n \n@@ -1413,11 +1435,10 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\tOPT_SUBCOMMAND(\"run\", &fn, cmd_bisect__run),\n \t\tOPT_END()\n \t};\n-\targc = parse_options(argc, argv, prefix, options,\n-\t\t\t     git_bisect_helper_usage, 0);\n+\targc = parse_options(argc, argv, prefix, options, git_bisect_usage, 0);\n \n \tif (!fn)\n-\t\tusage_with_options(git_bisect_helper_usage, options);\n+\t\tusage_with_options(git_bisect_usage, options);\n \targc--;\n \targv++;\n \n-- \n2.38.1.157.gedabe22e0a\n\n"},{"id":"466601","messageId":"a53e0c61cac3252bc9119fbde05b6c4bd0a1a295.1667667460.git.congdanhqx@gmail.com","threadId":"58746","inReplyTo":"cover.1667667460.git.congdanhqx@gmail.com","subject":"[PATCH 10/13] bisect--helper: make `state` optional","fromName":"Đoàn Trần Công Danh","fromEmail":"congdanhqx@gmail.com","sentAt":"2022-11-05T17:07:41Z","receivedAt":"2022-11-05T17:08:51Z","isPatch":true,"sender":{"key":"congdanhqx@gmail.com","avatar":"https://avatars.githubusercontent.com/u/42673067?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nIn preparation for making `git bisect` a real built-in, let's prepare\nthe `bisect--helper` built-in to handle `git bisect--helper good` and\n`git bisect--helper bad`, i.e. do not require the `state` subcommand to\nbe passed explicitly.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\nSigned-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>\n---\n builtin/bisect--helper.c | 29 +++++++++++++++++++++--------\n git-bisect.sh            |  2 --\n 2 files changed, 21 insertions(+), 10 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex bfa160dbf2..3c7a16355a 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1435,14 +1435,27 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\tOPT_SUBCOMMAND(\"run\", &fn, cmd_bisect__run),\n \t\tOPT_END()\n \t};\n-\targc = parse_options(argc, argv, prefix, options, git_bisect_usage, 0);\n-\n-\tif (!fn)\n-\t\tusage_with_options(git_bisect_usage, options);\n-\targc--;\n-\targv++;\n-\n-\tres = fn(argc, argv, prefix);\n+\targc = parse_options(argc, argv, prefix, options, git_bisect_usage,\n+\t\t\t     PARSE_OPT_SUBCOMMAND_OPTIONAL);\n+\n+\tif (!fn) {\n+\t\tstruct bisect_terms terms = { 0 };\n+\n+\t\tif (!argc)\n+\t\t\tusage_msg_opt(_(\"need a command\"), git_bisect_usage, options);\n+\n+\t\tset_terms(&terms, \"bad\", \"good\");\n+\t\tget_terms(&terms);\n+\t\tif (check_and_set_terms(&terms, argv[0]))\n+\t\t\tusage_msg_optf(_(\"unknown command: '%s'\"), git_bisect_usage,\n+\t\t\t\t       options, argv[0]);\n+\t\tres = bisect_state(&terms, argv, argc);\n+\t\tfree_terms(&terms);\n+\t} else {\n+\t\targc--;\n+\t\targv++;\n+\t\tres = fn(argc, argv, prefix);\n+\t}\n \n \t/*\n \t * Handle early success\ndiff --git a/git-bisect.sh b/git-bisect.sh\nindex dfce4b4f44..9f6c8cc093 100755\n--- a/git-bisect.sh\n+++ b/git-bisect.sh\n@@ -57,8 +57,6 @@ case \"$#\" in\n \tcase \"$cmd\" in\n \thelp)\n \t\tgit bisect -h ;;\n-\tbad|good|new|old|\"$TERM_BAD\"|\"$TERM_GOOD\")\n-\t\tgit bisect--helper state \"$cmd\" \"$@\" ;;\n \tlog)\n \t\tgit bisect--helper log || exit ;;\n \t*)\n-- \n2.38.1.157.gedabe22e0a\n\n"},{"id":"466602","messageId":"8037667da0f3d9f91c8f2aa477e2e95fb7f0c24b.1667667460.git.congdanhqx@gmail.com","threadId":"58746","inReplyTo":"cover.1667667460.git.congdanhqx@gmail.com","subject":"[PATCH 11/13] bisect--helper: remove subcommand state","fromName":"Đoàn Trần Công Danh","fromEmail":"congdanhqx@gmail.com","sentAt":"2022-11-05T17:07:42Z","receivedAt":"2022-11-05T17:08:54Z","isPatch":true,"sender":{"key":"congdanhqx@gmail.com","avatar":"https://avatars.githubusercontent.com/u/42673067?v=4"},"body":"In previous change, we've made 'state' optional, and replaced all of its\nusage.\n\nLet's remove it, now.\n\nSigned-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>\n---\n builtin/bisect--helper.c | 13 -------------\n 1 file changed, 13 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 3c7a16355a..d645fe89dc 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1349,18 +1349,6 @@ static int cmd_bisect__next(int argc, const char **argv UNUSED, const char *pref\n \treturn res;\n }\n \n-static int cmd_bisect__state(int argc, const char **argv, const char *prefix UNUSED)\n-{\n-\tint res;\n-\tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\n-\n-\tset_terms(&terms, \"bad\", \"good\");\n-\tget_terms(&terms);\n-\tres = bisect_state(&terms, argv, argc);\n-\tfree_terms(&terms);\n-\treturn res;\n-}\n-\n static int cmd_bisect__log(int argc, const char **argv UNUSED, const char *prefix UNUSED)\n {\n \tif (argc)\n@@ -1426,7 +1414,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\tOPT_SUBCOMMAND(\"terms\", &fn, cmd_bisect__terms),\n \t\tOPT_SUBCOMMAND(\"start\", &fn, cmd_bisect__start),\n \t\tOPT_SUBCOMMAND(\"next\", &fn, cmd_bisect__next),\n-\t\tOPT_SUBCOMMAND(\"state\", &fn, cmd_bisect__state),\n \t\tOPT_SUBCOMMAND(\"log\", &fn, cmd_bisect__log),\n \t\tOPT_SUBCOMMAND(\"replay\", &fn, cmd_bisect__replay),\n \t\tOPT_SUBCOMMAND(\"skip\", &fn, cmd_bisect__skip),\n-- \n2.38.1.157.gedabe22e0a\n\n"},{"id":"466603","messageId":"3b13350977c5f8bc934805e908b57792ce1a9a4e.1667667460.git.congdanhqx@gmail.com","threadId":"58746","inReplyTo":"cover.1667667460.git.congdanhqx@gmail.com","subject":"[PATCH 12/13] bisect--helper: log: allow arbitrary number of arguments","fromName":"Đoàn Trần Công Danh","fromEmail":"congdanhqx@gmail.com","sentAt":"2022-11-05T17:07:43Z","receivedAt":"2022-11-05T17:09:03Z","isPatch":true,"sender":{"key":"congdanhqx@gmail.com","avatar":"https://avatars.githubusercontent.com/u/42673067?v=4"},"body":"In a later change, we would like to turn bisect into a builtin by\nrenaming bisect--helper.\n\nHowever, there's an oddity that \"git bisect log\" accepts any number of\narguments and it will just ignore them all.\n\nLet's prepare for the next step by ignoring any arguments passed to\n\"git bisect--helper log\"\n\nSigned-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>\n---\n builtin/bisect--helper.c | 4 +---\n git-bisect.sh            | 2 --\n 2 files changed, 1 insertion(+), 5 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex d645fe89dc..e61ce6556c 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1349,10 +1349,8 @@ static int cmd_bisect__next(int argc, const char **argv UNUSED, const char *pref\n \treturn res;\n }\n \n-static int cmd_bisect__log(int argc, const char **argv UNUSED, const char *prefix UNUSED)\n+static int cmd_bisect__log(int argc UNUSED, const char **argv UNUSED, const char *prefix UNUSED)\n {\n-\tif (argc)\n-\t\treturn error(_(\"'%s' requires 0 arguments\"), \"git bisect log\");\n \treturn bisect_log();\n }\n \ndiff --git a/git-bisect.sh b/git-bisect.sh\nindex 9f6c8cc093..f95b8103a9 100755\n--- a/git-bisect.sh\n+++ b/git-bisect.sh\n@@ -57,8 +57,6 @@ case \"$#\" in\n \tcase \"$cmd\" in\n \thelp)\n \t\tgit bisect -h ;;\n-\tlog)\n-\t\tgit bisect--helper log || exit ;;\n \t*)\n \t\tgit bisect--helper \"$cmd\" \"$@\" ;;\n \tesac\n-- \n2.38.1.157.gedabe22e0a\n\n"},{"id":"466604","messageId":"0441cf255473ea3d2ca8bb2fc46874ec207bbcee.1667667460.git.congdanhqx@gmail.com","threadId":"58746","inReplyTo":"cover.1667667460.git.congdanhqx@gmail.com","subject":"[PATCH 13/13] Turn `git bisect` into a full built-in","fromName":"Đoàn Trần Công Danh","fromEmail":"congdanhqx@gmail.com","sentAt":"2022-11-05T17:07:44Z","receivedAt":"2022-11-05T17:09:05Z","isPatch":true,"sender":{"key":"congdanhqx@gmail.com","avatar":"https://avatars.githubusercontent.com/u/42673067?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nNow that the shell script hands off to the `bisect--helper` to do\n_anything_ (except to show the help), it is but a tiny step to let the\nhelper implement the actual `git bisect` command instead.\n\nThis retires `git-bisect.sh`, concluding a multi-year journey that many\nhands helped with, in particular Pranit Bauna, Tanushree Tumane and\nMiriam Rubio.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>\n---\n Makefile                               | 3 +--\n builtin.h                              | 2 +-\n builtin/{bisect--helper.c => bisect.c} | 2 +-\n git.c                                  | 2 +-\n 4 files changed, 4 insertions(+), 5 deletions(-)\n rename builtin/{bisect--helper.c => bisect.c} (99%)\n\ndiff --git a/Makefile b/Makefile\nindex 4927379184..78785c6b84 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -627,7 +627,6 @@ THIRD_PARTY_SOURCES =\n # interactive shell sessions without exporting it.\n unexport CDPATH\n \n-SCRIPT_SH += git-bisect.sh\n SCRIPT_SH += git-difftool--helper.sh\n SCRIPT_SH += git-filter-branch.sh\n SCRIPT_SH += git-merge-octopus.sh\n@@ -1137,7 +1136,7 @@ BUILTIN_OBJS += builtin/am.o\n BUILTIN_OBJS += builtin/annotate.o\n BUILTIN_OBJS += builtin/apply.o\n BUILTIN_OBJS += builtin/archive.o\n-BUILTIN_OBJS += builtin/bisect--helper.o\n+BUILTIN_OBJS += builtin/bisect.o\n BUILTIN_OBJS += builtin/blame.o\n BUILTIN_OBJS += builtin/branch.o\n BUILTIN_OBJS += builtin/bugreport.o\ndiff --git a/builtin.h b/builtin.h\nindex 8901a34d6b..aa955466b4 100644\n--- a/builtin.h\n+++ b/builtin.h\n@@ -116,7 +116,7 @@ int cmd_am(int argc, const char **argv, const char *prefix);\n int cmd_annotate(int argc, const char **argv, const char *prefix);\n int cmd_apply(int argc, const char **argv, const char *prefix);\n int cmd_archive(int argc, const char **argv, const char *prefix);\n-int cmd_bisect__helper(int argc, const char **argv, const char *prefix);\n+int cmd_bisect(int argc, const char **argv, const char *prefix);\n int cmd_blame(int argc, const char **argv, const char *prefix);\n int cmd_branch(int argc, const char **argv, const char *prefix);\n int cmd_bugreport(int argc, const char **argv, const char *prefix);\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect.c\nsimilarity index 99%\nrename from builtin/bisect--helper.c\nrename to builtin/bisect.c\nindex e61ce6556c..fc13f683a1 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect.c\n@@ -1403,7 +1403,7 @@ static int cmd_bisect__run(int argc, const char **argv, const char *prefix UNUSE\n \treturn res;\n }\n \n-int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n+int cmd_bisect(int argc, const char **argv, const char *prefix)\n {\n \tint res = 0;\n \tparse_opt_subcommand_fn *fn = NULL;\ndiff --git a/git.c b/git.c\nindex 6662548986..a2deb15e46 100644\n--- a/git.c\n+++ b/git.c\n@@ -492,7 +492,7 @@ static struct cmd_struct commands[] = {\n \t{ \"annotate\", cmd_annotate, RUN_SETUP },\n \t{ \"apply\", cmd_apply, RUN_SETUP_GENTLY },\n \t{ \"archive\", cmd_archive, RUN_SETUP_GENTLY },\n-\t{ \"bisect--helper\", cmd_bisect__helper, RUN_SETUP },\n+\t{ \"bisect\", cmd_bisect, RUN_SETUP },\n \t{ \"blame\", cmd_blame, RUN_SETUP },\n \t{ \"branch\", cmd_branch, RUN_SETUP | DELAY_PAGER_CONFIG },\n \t{ \"bugreport\", cmd_bugreport, RUN_SETUP_GENTLY },\n-- \n2.38.1.157.gedabe22e0a\n\n"},{"id":"466605","messageId":"Y2aZuBxuXvMSt2Rc@danh.dev","threadId":"58746","inReplyTo":"9d8a3cdd7a9472df01f67eb11ebac02a143d270b.1667667058.git.congdanhqx@gmail.com","subject":"Re: [PATCH v2 2/3] bisect--helper: move all subcommands into their own functions","fromName":"Đoàn Trần Công Danh","fromEmail":"congdanhqx@gmail.com","sentAt":"2022-11-05T17:13:28Z","receivedAt":"2022-11-05T17:13:35Z","isPatch":true,"sender":{"key":"congdanhqx@gmail.com","avatar":"https://avatars.githubusercontent.com/u/42673067?v=4"},"body":"On 2022-11-06 00:03:35+0700, Đoàn Trần Công Danh <congdanhqx@gmail.com> wrote:\n> In a later change, we will use OPT_SUBCOMMAND to parse sub-commands to\n> avoid consuming non-option opts.\n> \n> Since OPT_SUBCOMMAND needs a function pointer to operate,\n> let's move it now.\n> \n> Signed-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>\n> ---\n>  builtin/bisect--helper.c | 155 ++++++++++++++++++++++++++++++---------\n>  1 file changed, 121 insertions(+), 34 deletions(-)\n> \n> diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\n> index 5ec2e67f59..292c6fd1dd 100644\n> --- a/builtin/bisect--helper.c\n> +++ b/builtin/bisect--helper.c\n> @@ -1279,6 +1279,117 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n>  \treturn res;\n>  }\n>  \n> +static int cmd_bisect__reset(int argc, const char **argv, const char *prefix UNUSED)\n> +{\n> +\tif (argc > 1)\n> +\t\treturn error(_(\"--bisect-reset requires either no argument or a commit\"));\n> +\treturn bisect_reset(argc ? argv[0] : NULL);\n> +}\n> +\n> +static int cmd_bisect__terms(int argc, const char **argv, const char *prefix UNUSED)\n> +{\n> +\tint res;\n> +\tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\n\nNote to self: I need to change this to\n\n\tstruct bisect_terms terms = { 0 };\n\nin the next revisions.\n\n\n-- \nDanh\n"},{"id":"466607","messageId":"25776063-a672-fc65-bed3-1bc8536ab8b3@web.de","threadId":"58746","inReplyTo":"221105.861qqhxz0o.gmgdl@evledraar.gmail.com","subject":"Re: [PATCH 09/13] parse-options API: don't restrict OPT_SUBCOMMAND() to one *_fn type","fromName":"René Scharfe","fromEmail":"l.s.r@web.de","sentAt":"2022-11-05T17:26:55Z","receivedAt":"2022-11-05T17:27:18Z","isPatch":true,"sender":{"key":"l.s.r@web.de","avatar":"https://avatars.githubusercontent.com/u/26122331?v=4"},"body":"Am 05.11.22 um 14:52 schrieb Ævar Arnfjörð Bjarmason:\n>\n> I think that's an \"unportable\" extension covered in \"J.5 Common\n> extensions\", specifically \"J.5.7 Function pointer casts\":\n>\n> \tA pointer to an object or to void may be cast to a pointer to a\n> \tfunction, allowing data to be invoked as a function\n>\n> Thus, since the standard already establishes that valid \"void *\" and\n> \"intptr_t\" pointers can be cast'd back & forth, the J.5.7 bridges the\n> gap between the two saying a function pointer can be converted to\n> either.\n>\n> Now, I may be missing something here, but I was under the impression\n> that \"intptr_t\" wasn't special in any way here, and that any casting of\n> a function pointer to either it or a \"void *\" was what was made portable\n> by \"J.5.7\".\n\nDo you mean \"possible\" or \"workable\" instead of \"portable\" here?  As you\nwrite above, J.5.7 is an extension, not (fully) portable.\n\n> Anyway, like ssize_t and a few other things this is extended upon and\n> made standard by POSIX. I.e. we're basically talking about whether this\n> passes:\n>\n> \tassert(sizeof(void (*)(void)) == sizeof(void*))\n>\n> And per POSIX\n> (https://pubs.opengroup.org/onlinepubs/9699919799/functions/dlsym.html):\n>\n> \tNote that conversion from a void * pointer to a function pointer\n> \tas in:\n>\n> \t\tfptr = (int (*)(int))dlsym(handle, \"my_function\");\n>\n> \tis not defined by the ISO C standard. This standard requires\n> \tthis conversion to work correctly on conforming implementations.\n\nConversion from object pointer to function pointer can still work if\nfunction pointers are wider.\n\n> So I think aside from other concerns this should be safe to use, as\n> real-world data backing that up we've had a intptr_t converted to a\n> function pointer since v2.35.0: 5cb28270a1f (pack-objects: lazily set up\n> \"struct rev_info\", don't leak, 2022-03-28).\n\nThat may not have reached unusual architectures, yet.  Let's replace\nthat cast with something boring before someone gets hurt.  Something\nlike this?\n\n\ndiff --git a/builtin/pack-objects.c b/builtin/pack-objects.c\nindex 573d0b20b7..9e6f1530c6 100644\n--- a/builtin/pack-objects.c\n+++ b/builtin/pack-objects.c\n@@ -4154,14 +4154,15 @@ struct po_filter_data {\n \tstruct rev_info revs;\n };\n\n-static struct list_objects_filter_options *po_filter_revs_init(void *value)\n+static int list_objects_filter_cb(const struct option *opt,\n+\t\t\t\t  const char *arg, int unset)\n {\n-\tstruct po_filter_data *data = value;\n+\tstruct po_filter_data *data = opt->value;\n\n \trepo_init_revisions(the_repository, &data->revs, NULL);\n \tdata->have_revs = 1;\n\n-\treturn &data->revs.filter;\n+\treturn opt_parse_list_objects_filter(&data->revs.filter, arg, unset);\n }\n\n int cmd_pack_objects(int argc, const char **argv, const char *prefix)\n@@ -4265,7 +4266,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)\n \t\t\t      &write_bitmap_index,\n \t\t\t      N_(\"write a bitmap index if possible\"),\n \t\t\t      WRITE_BITMAP_QUIET, PARSE_OPT_HIDDEN),\n-\t\tOPT_PARSE_LIST_OBJECTS_FILTER_INIT(&pfd, po_filter_revs_init),\n+\t\tOPT_PARSE_LIST_OBJECTS_FILTER_F(&pfd, list_objects_filter_cb),\n \t\tOPT_CALLBACK_F(0, \"missing\", NULL, N_(\"action\"),\n \t\t  N_(\"handling for missing objects\"), PARSE_OPT_NONEG,\n \t\t  option_parse_missing_action),\ndiff --git a/list-objects-filter-options.c b/list-objects-filter-options.c\nindex 5339660238..2e560c2fdb 100644\n--- a/list-objects-filter-options.c\n+++ b/list-objects-filter-options.c\n@@ -286,15 +286,9 @@ void parse_list_objects_filter(\n \t\tdie(\"%s\", errbuf.buf);\n }\n\n-int opt_parse_list_objects_filter(const struct option *opt,\n+int opt_parse_list_objects_filter(struct list_objects_filter_options *filter_options,\n \t\t\t\t  const char *arg, int unset)\n {\n-\tstruct list_objects_filter_options *filter_options = opt->value;\n-\topt_lof_init init = (opt_lof_init)opt->defval;\n-\n-\tif (init)\n-\t\tfilter_options = init(opt->value);\n-\n \tif (unset || !arg)\n \t\tlist_objects_filter_set_no_filter(filter_options);\n \telse\n@@ -302,6 +296,12 @@ int opt_parse_list_objects_filter(const struct option *opt,\n \treturn 0;\n }\n\n+int opt_parse_list_objects_filter_cb(const struct option *opt,\n+\t\t\t\t     const char *arg, int unset)\n+{\n+\treturn opt_parse_list_objects_filter(opt->value, arg, unset);\n+}\n+\n const char *list_objects_filter_spec(struct list_objects_filter_options *filter)\n {\n \tif (!filter->filter_spec.len)\ndiff --git a/list-objects-filter-options.h b/list-objects-filter-options.h\nindex 7eeadab2dd..fc6b4da06d 100644\n--- a/list-objects-filter-options.h\n+++ b/list-objects-filter-options.h\n@@ -107,31 +107,26 @@ void parse_list_objects_filter(\n \tstruct list_objects_filter_options *filter_options,\n \tconst char *arg);\n\n+int opt_parse_list_objects_filter(struct list_objects_filter_options *filter_options,\n+\t\t\t\t  const char *arg, int unset);\n+\n /**\n  * The opt->value to opt_parse_list_objects_filter() is either a\n  * \"struct list_objects_filter_option *\" when using\n  * OPT_PARSE_LIST_OBJECTS_FILTER().\n  *\n- * Or, if using no \"struct option\" field is used by the callback,\n- * except the \"defval\" which is expected to be an \"opt_lof_init\"\n- * function, which is called with the \"opt->value\" and must return a\n- * pointer to the \"\"struct list_objects_filter_option *\" to be used.\n- *\n- * The OPT_PARSE_LIST_OBJECTS_FILTER_INIT() can be used e.g. the\n- * \"struct list_objects_filter_option\" is embedded in a \"struct\n- * rev_info\", which the \"defval\" could be tasked with lazily\n- * initializing. See cmd_pack_objects() for an example.\n+ * Or, OPT_PARSE_LIST_OBJECTS_FILTER_F() can be used to specify a\n+ * custom callback function that may expect a different type.\n  */\n-int opt_parse_list_objects_filter(const struct option *opt,\n-\t\t\t\t  const char *arg, int unset);\n+int opt_parse_list_objects_filter_cb(const struct option *opt,\n+\t\t\t\t     const char *arg, int unset);\n typedef struct list_objects_filter_options *(*opt_lof_init)(void *);\n-#define OPT_PARSE_LIST_OBJECTS_FILTER_INIT(fo, init) \\\n+#define OPT_PARSE_LIST_OBJECTS_FILTER_F(fo, fn) \\\n \t{ OPTION_CALLBACK, 0, \"filter\", (fo), N_(\"args\"), \\\n-\t  N_(\"object filtering\"), 0, opt_parse_list_objects_filter, \\\n-\t  (intptr_t)(init) }\n+\t  N_(\"object filtering\"), 0, (fn) }\n\n #define OPT_PARSE_LIST_OBJECTS_FILTER(fo) \\\n-\tOPT_PARSE_LIST_OBJECTS_FILTER_INIT((fo), NULL)\n+\tOPT_PARSE_LIST_OBJECTS_FILTER_F((fo), opt_parse_list_objects_filter_cb)\n\n /*\n  * Translates abbreviated numbers in the filter's filter_spec into their\n"},{"id":"466615","messageId":"43ec357b-bbd2-6b17-58f4-676a8c5e1749@dunelm.org.uk","threadId":"58746","inReplyTo":"Y2ZKHPkEXViv9wcp@danh.dev","subject":"Re: [PATCH 09/13] parse-options API: don't restrict OPT_SUBCOMMAND() to one *_fn type","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2022-11-05T21:32:36Z","receivedAt":"2022-11-05T21:32:43Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Đoàn\n\nOn 05/11/2022 11:34, Đoàn Trần Công Danh wrote:\n>   \n> On 2022-11-05 09:32:44+0100, René Scharfe <l.s.r@web.de> wrote:\n>> Why is this trickery needed?  Above you write that callbacks in\n>> builtin/bisect--helper.c can't use subcommand_fn because they need\n>> their own argument.  Can we extend subcommand_fn or use a global\n>> variable to pass that extra thing instead?  The latter may be ugly, but\n>> at least it's valid C..\n> \n> Not the author, but I fully agree with you, I think instead of adding new API\n> for some arbitrary subcommand_fn, I would change the subcommand_fn to\n> type:\n> \n> \tint (*)(int argc, const char **argv, const char *prefix, void *context)\n> \n> The last argument would be an object pointer, which will be casted to\n> the correct type inside the callback.\n> \n> Let me cherry-picking this series on top of mine to see how things\n> would progress.\n\nUnfortunately the current implementation of OPT_SUBCOMMAND relies on \nreturning a function pointer though a void* variable which while widely \nsupported is undefined behavior. I wonder if an API like\n\ntypedef int (*subcommand_fn)(int, char**, char*);\ntypedef int (*subcommand_ctk_fn)(int, char**, char*, void*);\nstruct subcommand; /* opaque */\n\nOPT_SUBCOMMAND(name, value, func);\nOPT_SUMCOMMAND_CTX(name, value, func, ctx);\n\nint call_subcommand(struct subcommand* subcommand, int argc, char** \nargv, char* prefix);\n\n\nwhich would be used as\n\nint sub1_fn(int argc, char** argv, char* prefix, void* ctx)\n{\n\tstruct cmd_ctx cmd_ctx = ctx\n\t...\n}\n\nint sub2_fn(int argc, char** argv, char* prefix)\n{\n\t...\n}\n\nint cmd_foo(int argc, char** argv, char* prefix)\n{\n\tstruct cmd_ctx ctx = ...\n\tstruct subcommand cmd = { 0 };\n\t...\n\tstruct option opts[] = {\n\t\tOPT_SUBCOMMAND_CTX(\"sub1\", &cmd, sub_fn, &ctx);\n\t\tOPT_SUBCOMMAND(\"sub2\", &cmd, sub2_fn);\n\t};\n\targc = parse_options(argc, argv, prefix, &opts, usage, flags);\n\treturn call_subcommand(&cmd, argc, argv, prefix);\n}\n\n\nwould be an improvement. One can avoid having to mark the ctx parameter \nas UNUSED() if a subcommand does not need any context by using \nOPT_SUBCOMMAND() rather than OPT_SUBCOMMAND_CTX().\n\n\nThe implementation of call_subcommand() would look something like\n\nstruct subcommand {\n         void* ctx;\n         int has_ctx;\n         union {\n                 subcommand_fn fn;\n                 subcommand_ctx_fn ctx_fn;\n         };\n};\n\nint call_subcommand(struct subcommand* subcommand, int argc, char \n**argv, char* prefix)\n{\n         if (subcommand->has_ctx)\n                 return subcommand->ctx_fn(argc, argv, prefix, \nsubcommand->ctx);\n         else\n                 return subcommand->fn(argc, argv, prefix);\n}\n\n\nBest Wishes\n\nPhillip\n"},{"id":"466616","messageId":"221105.86sfixvxqk.gmgdl@evledraar.gmail.com","threadId":"58746","inReplyTo":"1b158749-44b1-34e0-5b52-1d3bfad9bc9a@dunelm.org.uk","subject":"Re: [PATCH 09/13] parse-options API: don't restrict OPT_SUBCOMMAND() to one *_fn type","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-05T21:59:07Z","receivedAt":"2022-11-05T22:32:26Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Sat, Nov 05 2022, Phillip Wood wrote:\n\n> On 05/11/2022 13:52, Ævar Arnfjörð Bjarmason wrote:\n>> On Sat, Nov 05 2022, René Scharfe wrote:\n>> \n>>> Am 04.11.22 um 14:22 schrieb Ævar Arnfjörð Bjarmason:\n>>>> diff --git a/parse-options.h b/parse-options.h\n>>>> index b6ef86e0d15..61e3016c3fc 100644\n>>>> --- a/parse-options.h\n>>>> +++ b/parse-options.h\n>>>> @@ -128,19 +128,24 @@ typedef int parse_opt_subcommand_fn(int argc, const char **argv,\n>>>>    *\t\t\t the option takes optional argument.\n>>>>    *\n>>>>    * `callback`::\n>>>> - *   pointer to the callback to use for OPTION_CALLBACK\n>>>> + *   pointer to the callback to use for OPTION_CALLBACK and OPTION_SUBCOMMAND.\n>>>>    *\n>>>>    * `defval`::\n>>>>    *   default value to fill (*->value) with for PARSE_OPT_OPTARG.\n>>>>    *   OPTION_{BIT,SET_INT} store the {mask,integer} to put in the value when met.\n>>>> + *   OPTION_SUBCOMMAND stores the pointer the function selected for\n>>>> + *   the subcommand.\n>>>> + *\n>>>>    *   CALLBACKS can use it like they want.\n>>>>    *\n>>>>    * `ll_callback`::\n>>>>    *   pointer to the callback to use for OPTION_LOWLEVEL_CALLBACK\n>>>>    *\n>>>>    * `subcommand_fn`::\n>>>> - *   pointer to a function to use for OPTION_SUBCOMMAND.\n>>>> - *   It will be put in value when the subcommand is given on the command line.\n>>>> + *   pointer to the callback used with OPT_SUBCOMMAND() and\n>>>> + *   OPT_SUBCOMMAND_F(). Internally we store the same value in\n>>>> + *   `defval`. This is only here to give the OPT_SUBCOMMAND{,_F}()\n>>>> + *   common case type safety.\n>>>>    */\n>>>>   struct option {\n>>>>   \tenum parse_opt_type type;\n>>>> @@ -217,12 +222,24 @@ struct option {\n>>>>   #define OPT_ALIAS(s, l, source_long_name) \\\n>>>>   \t{ OPTION_ALIAS, (s), (l), (source_long_name) }\n>>>>\n>>>> +static inline int parse_options_pick_subcommand_cb(const struct option *option,\n>>>> +\t\t\t\t\t\t   const char *arg UNUSED,\n>>>> +\t\t\t\t\t\t   int unset UNUSED)\n>>>> +{\n>>>> +\tparse_opt_subcommand_fn *fn = (parse_opt_subcommand_fn *)option->defval;\n>>>> +\t*(parse_opt_subcommand_fn **)option->value = fn;\n>>>\n>>> ->defval is of type intptr_t and ->value is a void pointer.  The result\n>>> of converting a void pointer value to an intptr_t and back is a void\n>>> pointer equal to the original pointer if I read 6.3.2.3 (Pointers,\n>>> paragraphs 5 and 6) and 7.18.1.4 (Integer types capable of holding\n>>> object pointers) in C99 correctly.\n>>>\n>>> 6.3.2.3 paragraph 8 says that casting between function pointers of\n>>> different type is OK and you can get your original function pointer\n>>> back and use it in a call if you convert it back to the right type.\n>>>\n>>> Casting between a function pointer and an object pointer is undefined,\n>>> though.  They don't have to be of the same size, so a function pointer\n>>> doesn't have to fit into an intptr_t.  I wouldn't be surprised if CHERI\n>>> (https://www.cl.cam.ac.uk/research/security/ctsrd/cheri/) was an actual\n>>> example of that.\n>> I should have called this out explicitly. I think you're right as\n>> far as\n>> what you're summarizing goes.\n>> To elaborate on it, paragraph 8 of 6.3.2.3 says:\n>> \tA pointer to a function of one type may be converted to a\n>> \tpointer to a function of another type and back again; the result\n>> \tshall compare equal to the original pointer. If a converted\n>> \tpointer is used to call a function whose type is not compatible\n>> \twith the pointed-to type, the behavior is undefined.\n>> And 7.18.1.4 says, when discussing (among other things) \"intptr_t\"\n>> (\"[such\" added for clarity:\n>> \t[...]any valid [such] pointer to void can be converted to this\n>> \ttype, then converted back to pointer to void, and the result\n>> \twill compare equal to the original pointer:\n>> But as you point out that doesn't say anything about whether a\n>> pointer\n>> to a function is a \"valid .. pointer to void\".\n>> I think that's an \"unportable\" extension covered in \"J.5 Common\n>> extensions\", specifically \"J.5.7 Function pointer casts\":\n>> \tA pointer to an object or to void may be cast to a pointer to\n>> a\n>> \tfunction, allowing data to be invoked as a function\n>\n> This is a common extension, it is _not_ guaranteed by the standard and\n> so still undefined behavior unless your compiler happens to have \n> implemented that extension.\n\n>> Thus, since the standard already establishes that valid \"void *\" and\n>> \"intptr_t\" pointers can be cast'd back & forth, the J.5.7 bridges the\n>> gap between the two saying a function pointer can be converted to\n>> either.\n>\n> How does J.5.7 bridge the gap when compilers are not required to\n> implement it?\n\nI'm saying it bridges the gap in that explanation, i.e. reinforces that\nthe main standard body isn't referring to function pointer casts to void\n* and intptr_t.\n\n>> Now, I may be missing something here, but I was under the impression\n>> that \"intptr_t\" wasn't special in any way here, and that any casting of\n>> a function pointer to either it or a \"void *\" was what was made portable\n>> by \"J.5.7\"\n>\n> How is it made portable by an \"unportable\" extension?\n\nI'm just repeating the terminology the standard uses: \"The following\nextensions are widely used in many systems, but are not portable to all\nimplementations\".\n\n>> So I think aside from other concerns this should be safe to use, as\n>> real-world data backing that up we've had a intptr_t converted to a\n>> function pointer since v2.35.0: 5cb28270a1f (pack-objects: lazily set up\n>> \"struct rev_info\", don't leak, 2022-03-28).\n>\n> Saying \"it works so it is fine\" is not a convincing argument that it\n> is compliant with the standard. \n\nI was saying, among other things, that it's standardized by POSIX, so\nit's in the same category as ssize_t, not some hypothetical \"happens to\nwork\" undefined behavior.\n\nBut we also make use of it already, so that gives us some real-world\ndata on potential issues.\n"},{"id":"466617","messageId":"221105.86o7tlvxh0.gmgdl@evledraar.gmail.com","threadId":"58746","inReplyTo":"25776063-a672-fc65-bed3-1bc8536ab8b3@web.de","subject":"Re: [PATCH 09/13] parse-options API: don't restrict OPT_SUBCOMMAND() to one *_fn type","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-05T22:33:32Z","receivedAt":"2022-11-05T22:38:11Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Sat, Nov 05 2022, René Scharfe wrote:\n\n> Am 05.11.22 um 14:52 schrieb Ævar Arnfjörð Bjarmason:\n>>\n>> I think that's an \"unportable\" extension covered in \"J.5 Common\n>> extensions\", specifically \"J.5.7 Function pointer casts\":\n>>\n>> \tA pointer to an object or to void may be cast to a pointer to a\n>> \tfunction, allowing data to be invoked as a function\n>>\n>> Thus, since the standard already establishes that valid \"void *\" and\n>> \"intptr_t\" pointers can be cast'd back & forth, the J.5.7 bridges the\n>> gap between the two saying a function pointer can be converted to\n>> either.\n>>\n>> Now, I may be missing something here, but I was under the impression\n>> that \"intptr_t\" wasn't special in any way here, and that any casting of\n>> a function pointer to either it or a \"void *\" was what was made portable\n>> by \"J.5.7\".\n>\n> Do you mean \"possible\" or \"workable\" instead of \"portable\" here?  As you\n> write above, J.5.7 is an extension, not (fully) portable.\n\nI think my just-sent in the side-thread should clarify this.\n\n>> Anyway, like ssize_t and a few other things this is extended upon and\n>> made standard by POSIX. I.e. we're basically talking about whether this\n>> passes:\n>>\n>> \tassert(sizeof(void (*)(void)) == sizeof(void*))\n>>\n>> And per POSIX\n>> (https://pubs.opengroup.org/onlinepubs/9699919799/functions/dlsym.html):\n>>\n>> \tNote that conversion from a void * pointer to a function pointer\n>> \tas in:\n>>\n>> \t\tfptr = (int (*)(int))dlsym(handle, \"my_function\");\n>>\n>> \tis not defined by the ISO C standard. This standard requires\n>> \tthis conversion to work correctly on conforming implementations.\n>\n> Conversion from object pointer to function pointer can still work if\n> function pointers are wider.\n>\n>> So I think aside from other concerns this should be safe to use, as\n>> real-world data backing that up we've had a intptr_t converted to a\n>> function pointer since v2.35.0: 5cb28270a1f (pack-objects: lazily set up\n>> \"struct rev_info\", don't leak, 2022-03-28).\n>\n> That may not have reached unusual architectures, yet.  Let's replace\n> that cast with something boring before someone gets hurt.  Something\n> like this?\n>\n>\n> diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c\n> index 573d0b20b7..9e6f1530c6 100644\n> --- a/builtin/pack-objects.c\n> +++ b/builtin/pack-objects.c\n> @@ -4154,14 +4154,15 @@ struct po_filter_data {\n>  \tstruct rev_info revs;\n>  };\n>\n> -static struct list_objects_filter_options *po_filter_revs_init(void *value)\n> +static int list_objects_filter_cb(const struct option *opt,\n> +\t\t\t\t  const char *arg, int unset)\n>  {\n> -\tstruct po_filter_data *data = value;\n> +\tstruct po_filter_data *data = opt->value;\n>\n>  \trepo_init_revisions(the_repository, &data->revs, NULL);\n>  \tdata->have_revs = 1;\n>\n> -\treturn &data->revs.filter;\n> +\treturn opt_parse_list_objects_filter(&data->revs.filter, arg, unset);\n>  }\n>\n>  int cmd_pack_objects(int argc, const char **argv, const char *prefix)\n> @@ -4265,7 +4266,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)\n>  \t\t\t      &write_bitmap_index,\n>  \t\t\t      N_(\"write a bitmap index if possible\"),\n>  \t\t\t      WRITE_BITMAP_QUIET, PARSE_OPT_HIDDEN),\n> -\t\tOPT_PARSE_LIST_OBJECTS_FILTER_INIT(&pfd, po_filter_revs_init),\n> +\t\tOPT_PARSE_LIST_OBJECTS_FILTER_F(&pfd, list_objects_filter_cb),\n>  \t\tOPT_CALLBACK_F(0, \"missing\", NULL, N_(\"action\"),\n>  \t\t  N_(\"handling for missing objects\"), PARSE_OPT_NONEG,\n>  \t\t  option_parse_missing_action),\n> diff --git a/list-objects-filter-options.c b/list-objects-filter-options.c\n> index 5339660238..2e560c2fdb 100644\n> --- a/list-objects-filter-options.c\n> +++ b/list-objects-filter-options.c\n> @@ -286,15 +286,9 @@ void parse_list_objects_filter(\n>  \t\tdie(\"%s\", errbuf.buf);\n>  }\n>\n> -int opt_parse_list_objects_filter(const struct option *opt,\n> +int opt_parse_list_objects_filter(struct list_objects_filter_options *filter_options,\n>  \t\t\t\t  const char *arg, int unset)\n>  {\n> -\tstruct list_objects_filter_options *filter_options = opt->value;\n> -\topt_lof_init init = (opt_lof_init)opt->defval;\n> -\n> -\tif (init)\n> -\t\tfilter_options = init(opt->value);\n> -\n>  \tif (unset || !arg)\n>  \t\tlist_objects_filter_set_no_filter(filter_options);\n>  \telse\n> @@ -302,6 +296,12 @@ int opt_parse_list_objects_filter(const struct option *opt,\n>  \treturn 0;\n>  }\n>\n> +int opt_parse_list_objects_filter_cb(const struct option *opt,\n> +\t\t\t\t     const char *arg, int unset)\n> +{\n> +\treturn opt_parse_list_objects_filter(opt->value, arg, unset);\n> +}\n> +\n>  const char *list_objects_filter_spec(struct list_objects_filter_options *filter)\n>  {\n>  \tif (!filter->filter_spec.len)\n> diff --git a/list-objects-filter-options.h b/list-objects-filter-options.h\n> index 7eeadab2dd..fc6b4da06d 100644\n> --- a/list-objects-filter-options.h\n> +++ b/list-objects-filter-options.h\n> @@ -107,31 +107,26 @@ void parse_list_objects_filter(\n>  \tstruct list_objects_filter_options *filter_options,\n>  \tconst char *arg);\n>\n> +int opt_parse_list_objects_filter(struct list_objects_filter_options *filter_options,\n> +\t\t\t\t  const char *arg, int unset);\n> +\n>  /**\n>   * The opt->value to opt_parse_list_objects_filter() is either a\n>   * \"struct list_objects_filter_option *\" when using\n>   * OPT_PARSE_LIST_OBJECTS_FILTER().\n>   *\n> - * Or, if using no \"struct option\" field is used by the callback,\n> - * except the \"defval\" which is expected to be an \"opt_lof_init\"\n> - * function, which is called with the \"opt->value\" and must return a\n> - * pointer to the \"\"struct list_objects_filter_option *\" to be used.\n> - *\n> - * The OPT_PARSE_LIST_OBJECTS_FILTER_INIT() can be used e.g. the\n> - * \"struct list_objects_filter_option\" is embedded in a \"struct\n> - * rev_info\", which the \"defval\" could be tasked with lazily\n> - * initializing. See cmd_pack_objects() for an example.\n> + * Or, OPT_PARSE_LIST_OBJECTS_FILTER_F() can be used to specify a\n> + * custom callback function that may expect a different type.\n>   */\n> -int opt_parse_list_objects_filter(const struct option *opt,\n> -\t\t\t\t  const char *arg, int unset);\n> +int opt_parse_list_objects_filter_cb(const struct option *opt,\n> +\t\t\t\t     const char *arg, int unset);\n>  typedef struct list_objects_filter_options *(*opt_lof_init)(void *);\n> -#define OPT_PARSE_LIST_OBJECTS_FILTER_INIT(fo, init) \\\n> +#define OPT_PARSE_LIST_OBJECTS_FILTER_F(fo, fn) \\\n>  \t{ OPTION_CALLBACK, 0, \"filter\", (fo), N_(\"args\"), \\\n> -\t  N_(\"object filtering\"), 0, opt_parse_list_objects_filter, \\\n> -\t  (intptr_t)(init) }\n> +\t  N_(\"object filtering\"), 0, (fn) }\n>\n>  #define OPT_PARSE_LIST_OBJECTS_FILTER(fo) \\\n> -\tOPT_PARSE_LIST_OBJECTS_FILTER_INIT((fo), NULL)\n> +\tOPT_PARSE_LIST_OBJECTS_FILTER_F((fo), opt_parse_list_objects_filter_cb)\n>\n>  /*\n>   * Translates abbreviated numbers in the filter's filter_spec into their\n\nI think \"just leave it, and see if anyone complains\".\n\nIf you look over config.mak.uname you can see what we're likely to be\nported to (and some of that's probably dead). The list of potential\ntargets that:\n\n 1) We know of ports to, or people would plausibly port git to\n 2) Are updated so slow that they're on a release that's getting close\n    to a year old.\n\nAre small, and it's usually easy to look up their memory model etc. are\nyou concerned about any specific one?\n\nI think if you're worried enough about it to push for the diff above:\nCan we just hide it behind an \"#ifdef\", then if we find that nobody's\nusing it, we can consider it safe to use.\n\nI don't think there's any great benefit to the extension in that\nspecific case, but there might be in the future (e.g. this topic would\nbe one small user), so since we already have an unintentional test\nballon, why not see if we can keep it safely?\n"},{"id":"466618","messageId":"Y2bvStmh9LBfgDVE@nand.local","threadId":"58746","inReplyTo":"cover.1667667058.git.congdanhqx@gmail.com","subject":"Re: [PATCH v2 0/3] Convert git-bisect--helper to OPT_SUBCOMMAND","fromName":"Taylor Blau","fromEmail":"me@ttaylorr.com","sentAt":"2022-11-05T23:18:34Z","receivedAt":"2022-11-05T23:18:47Z","isPatch":true,"sender":{"key":"me@ttaylorr.com","avatar":"https://avatars.githubusercontent.com/u/301000140?v=4"},"body":"On Sun, Nov 06, 2022 at 12:03:33AM +0700, Đoàn Trần Công Danh wrote:\n>  builtin/bisect--helper.c    | 229 ++++++++++++++++++++----------------\n>  git-bisect.sh               |  23 +---\n>  t/t6030-bisect-porcelain.sh |  10 ++\n>  3 files changed, 142 insertions(+), 120 deletions(-)\n\nThanks, this version looks good to me. Will queue.\n\nThanks,\nTaylor\n"},{"id":"466627","messageId":"46ee3f92-943f-10d5-7ec5-c68f1ced87ce@web.de","threadId":"58746","inReplyTo":"221105.86o7tlvxh0.gmgdl@evledraar.gmail.com","subject":"Re: [PATCH 09/13] parse-options API: don't restrict OPT_SUBCOMMAND() to one *_fn type","fromName":"René Scharfe","fromEmail":"l.s.r@web.de","sentAt":"2022-11-06T08:25:35Z","receivedAt":"2022-11-06T08:26:00Z","isPatch":true,"sender":{"key":"l.s.r@web.de","avatar":"https://avatars.githubusercontent.com/u/26122331?v=4"},"body":"Am 05.11.22 um 23:33 schrieb Ævar Arnfjörð Bjarmason:\n>\n> On Sat, Nov 05 2022, René Scharfe wrote:\n>\n>> Am 05.11.22 um 14:52 schrieb Ævar Arnfjörð Bjarmason:\n>>>\n>>> I think that's an \"unportable\" extension covered in \"J.5 Common\n>>> extensions\", specifically \"J.5.7 Function pointer casts\":\n>>>\n>>> \tA pointer to an object or to void may be cast to a pointer to a\n>>> \tfunction, allowing data to be invoked as a function\n>>>\n>>> Thus, since the standard already establishes that valid \"void *\" and\n>>> \"intptr_t\" pointers can be cast'd back & forth, the J.5.7 bridges the\n>>> gap between the two saying a function pointer can be converted to\n>>> either.\n>>>\n>>> Now, I may be missing something here, but I was under the impression\n>>> that \"intptr_t\" wasn't special in any way here, and that any casting of\n>>> a function pointer to either it or a \"void *\" was what was made portable\n>>> by \"J.5.7\".\n>>\n>> Do you mean \"possible\" or \"workable\" instead of \"portable\" here?  As you\n>> write above, J.5.7 is an extension, not (fully) portable.\n>\n> I think my just-sent in the side-thread should clarify this.\n\nAFAIU you think that J.5.7 plus POSIX make conversions between object\npointers and function pointers portable.\n\n>>> Anyway, like ssize_t and a few other things this is extended upon and\n>>> made standard by POSIX. I.e. we're basically talking about whether this\n>>> passes:\n>>>\n>>> \tassert(sizeof(void (*)(void)) == sizeof(void*))\n>>>\n>>> And per POSIX\n>>> (https://pubs.opengroup.org/onlinepubs/9699919799/functions/dlsym.html):\n>>>\n>>> \tNote that conversion from a void * pointer to a function pointer\n>>> \tas in:\n>>>\n>>> \t\tfptr = (int (*)(int))dlsym(handle, \"my_function\");\n>>>\n>>> \tis not defined by the ISO C standard. This standard requires\n>>> \tthis conversion to work correctly on conforming implementations.\n>>\n>> Conversion from object pointer to function pointer can still work if\n>> function pointers are wider.\n\nThis means that a compliant implementation could lose bits when going\nthe other way, i.e. converting a function pointer to an object pointer.\n\n>>> So I think aside from other concerns this should be safe to use, as\n>>> real-world data backing that up we've had a intptr_t converted to a\n>>> function pointer since v2.35.0: 5cb28270a1f (pack-objects: lazily set up\n>>> \"struct rev_info\", don't leak, 2022-03-28).\n>>\n>> That may not have reached unusual architectures, yet.  Let's replace\n>> that cast with something boring before someone gets hurt.  Something\n>> like this?\n\n[snip]\n\n> I think \"just leave it, and see if anyone complains\".\n>\n> If you look over config.mak.uname you can see what we're likely to be\n> ported to (and some of that's probably dead). The list of potential\n> targets that:\n>\n>  1) We know of ports to, or people would plausibly port git to\n>  2) Are updated so slow that they're on a release that's getting close\n>     to a year old.\n>\n> Are small, and it's usually easy to look up their memory model etc. are\n> you concerned about any specific one?\n\nUsing implementation-defined behavior and requiring extensions when\nstandard code would work just as well makes no sense to me.\n\n> I think if you're worried enough about it to push for the diff above:\n> Can we just hide it behind an \"#ifdef\", then if we find that nobody's\n> using it, we can consider it safe to use.\n>\n> I don't think there's any great benefit to the extension in that\n> specific case, but there might be in the future (e.g. this topic would\n> be one small user), so since we already have an unintentional test\n> ballon, why not see if we can keep it safely?\n\nYou can't certify safety with tests.  Undefined behavior may manifest\nitself in weird ways and only under certain circumstances.  Future\narchitectures may add new failure modes.  It's not like a syntax\nextension, to which nonsupporting compilers respond with an error,\ni.e. a clear signal.\n\nRené\n"},{"id":"466632","messageId":"221106.86k048w2f4.gmgdl@evledraar.gmail.com","threadId":"58746","inReplyTo":"46ee3f92-943f-10d5-7ec5-c68f1ced87ce@web.de","subject":"Re: [PATCH 09/13] parse-options API: don't restrict OPT_SUBCOMMAND() to one *_fn type","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-06T13:28:58Z","receivedAt":"2022-11-06T15:03:35Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Sun, Nov 06 2022, René Scharfe wrote:\n\n> Am 05.11.22 um 23:33 schrieb Ævar Arnfjörð Bjarmason:\n>>\n>> On Sat, Nov 05 2022, René Scharfe wrote:\n>>\n>>> Am 05.11.22 um 14:52 schrieb Ævar Arnfjörð Bjarmason:\n>>>>\n>>>> I think that's an \"unportable\" extension covered in \"J.5 Common\n>>>> extensions\", specifically \"J.5.7 Function pointer casts\":\n>>>>\n>>>> \tA pointer to an object or to void may be cast to a pointer to a\n>>>> \tfunction, allowing data to be invoked as a function\n>>>>\n>>>> Thus, since the standard already establishes that valid \"void *\" and\n>>>> \"intptr_t\" pointers can be cast'd back & forth, the J.5.7 bridges the\n>>>> gap between the two saying a function pointer can be converted to\n>>>> either.\n>>>>\n>>>> Now, I may be missing something here, but I was under the impression\n>>>> that \"intptr_t\" wasn't special in any way here, and that any casting of\n>>>> a function pointer to either it or a \"void *\" was what was made portable\n>>>> by \"J.5.7\".\n>>>\n>>> Do you mean \"possible\" or \"workable\" instead of \"portable\" here?  As you\n>>> write above, J.5.7 is an extension, not (fully) portable.\n>>\n>> I think my just-sent in the side-thread should clarify this.\n>\n> AFAIU you think that J.5.7 plus POSIX make conversions between object\n> pointers and function pointers portable.\n\nNo, I think that:\n\n1) J.5.7 does that on its own for C99\n2) POSIX has orthagonally mandated this, seperate from C99.\n\nIn practice I think it's always worked for dlsym(), but there's\ninteresting changes in wording between v6 and v7 of POSIX:\n\n   - https://pubs.opengroup.org/onlinepubs/009695399/functions/dlsym.html\n   - https://pubs.opengroup.org/onlinepubs/9699919799/functions/dlsym.html\n\nv6 claims that conforming C compilers are required to produce a warning\nif this isn't supported (I haven't found the part of the standard\nthey're referencing), and notes that the behavior may be deprecated in\nthe future.\n\nWhereas v7 says that POSIX \"requires this conversion to work correctly\non conforming implementations\".\n\nIs your reading of any of that different?\n\nIn addition to that: This is widely supported on systems that didn't\naquire such support via optional C99 extensions, or POSIX. E.g. Win32.\n\nI think this is one of those things that C has left deliberately\nundefined for the benefit of embedded implementations, and others with\nodd memory models.\n\n>> I think \"just leave it, and see if anyone complains\".\n>>\n>> If you look over config.mak.uname you can see what we're likely to be\n>> ported to (and some of that's probably dead). The list of potential\n>> targets that:\n>>\n>>  1) We know of ports to, or people would plausibly port git to\n>>  2) Are updated so slow that they're on a release that's getting close\n>>     to a year old.\n>>\n>> Are small, and it's usually easy to look up their memory model etc. are\n>> you concerned about any specific one?\n>\n> Using implementation-defined behavior and requiring extensions when\n> standard code would work just as well makes no sense to me.\n\nI think it's useful in itself to see what subset or superset of C we\nactually need to concern ourselves with.\n\nE.g. we have plenty of code that assumes ASCII, instead of catering to\nEBCDIC, and assuming NULL is (void *)0, not (void *)123456 or whatever.\n\nYes, in this case the alternative is trivial, but perhaps we'd find a\nuse-case in the future.\n\nAll I'm saying is let's leave the current one in place, as there's no\nindication that it's not supported by our targets.\n"},{"id":"466753","messageId":"221107.86sfiutpsh.gmgdl@evledraar.gmail.com","threadId":"58746","inReplyTo":"f212e6428855f0b0839bf6befd7c4703c505cc66.1667667460.git.congdanhqx@gmail.com","subject":"Re: [PATCH 07/13] bisect--helper: pretend we're real bisect when report error","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-07T21:29:00Z","receivedAt":"2022-11-07T21:31:34Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Sun, Nov 06 2022, Đoàn Trần Công Danh wrote:\n\n> In a later change, we will convert the bisect--helper to be builtin\n> bisect. Let's start by pretending it's the real bisect when reporting\n> error.\n\nIt's good to have this in here, FWIW I left this out of my version\nreasoning that it was broken before, so we could leave it with the\npsot-cleanups.\n\nI'm fine with having it in while we're at it, but just FWIW:\n\nI don't think we're \"pretending\". We *are* the bisect command, the fact\nthat we're implementing it via a \"helper\" is really quite irrelevant,\njust like we're not \"pretending\" if we say we're \"git bisect\" instead of\n\"git-bisect.sh\" or whatever.\n\nThe only cases where we should have these helpers report that they are\nthe helper is for messages that aren't user-visible, e.g. the \"-h\"\noutput emitted when you invoke a helper-specific command that no user\nshould be invoking (although arguably, we should just BUG() out\nthere...).\n"},{"id":"466754","messageId":"221107.86o7titppp.gmgdl@evledraar.gmail.com","threadId":"58746","inReplyTo":"5571bc36b84210e16ab8731fea8bf0ed8d62cca3.1667667460.git.congdanhqx@gmail.com","subject":"Re: [PATCH 01/13] bisect tests: test for v2.30.0 \"bisect run\" regressions","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-07T21:31:50Z","receivedAt":"2022-11-07T21:33:13Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Sun, Nov 06 2022, Đoàn Trần Công Danh wrote:\n\n> From: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n>\n> Add three failing tests which succeed on v2.29.0, but due to the topic\n> merged at [1] (specifically [2]) have been failing since then. We'll\n> address those regressions in subsequent commits.\n>\n> There was also a \"regression\" where:\n>\n> \tgit bisect run ./missing-script.sh\n>\n> Would count a non-existing script as \"good\", as the shell would exit\n> with 127. That edge case is a bit too insane to preserve, so let's not\n> add it to these regression tests.\n>\n> 1. 0a4cb1f1f2f (Merge branch 'mr/bisect-in-c-4', 2021-09-23)\n> 2. d1bbbe45df8 (bisect--helper: reimplement `bisect_run` shell\n>    function in C, 2021-09-13)\n>\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> Signed-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>\n> ---\n>  t/t6030-bisect-porcelain.sh | 79 +++++++++++++++++++++++++++++++++++++\n>  1 file changed, 79 insertions(+)\n\nLooks good, if I do say so myself :) (unchanged from my topic)\n\nBut I wonder why your \"fix the regression\" base topic isn't starting\nwith this. I.e. our intial report was about that \"--log\" issue, but now\nwe know we altered the output in ways we didn't intend.\n\nIt's fine if we say \"that's less important\", but then ... something\nshould say that .. :)\n"},{"id":"466755","messageId":"221107.86k046tp8p.gmgdl@evledraar.gmail.com","threadId":"58746","inReplyTo":"5ba3bafdd48b47320624d0db06f379bc0a4b8d4e.1667667460.git.congdanhqx@gmail.com","subject":"Re: [PATCH 05/13] bisect run: keep some of the post-v2.30.0 output","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-07T21:40:33Z","receivedAt":"2022-11-07T21:43:32Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Sun, Nov 06 2022, Đoàn Trần Công Danh wrote:\n\n> From: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n>\n> Preceding commits fixed output and behavior regressions in\n> d1bbbe45df8 (bisect--helper: reimplement `bisect_run` shell function\n> in C, 2021-09-13), which did not claim to be changing the output of\n> \"git bisect run\".\n>\n> But some of the output it emitted was subjectively better, so once\n> we've asserted that we're back on v2.29.0 behavior, let's change some\n> of it back:\n>\n> - We now quote the arguments again, but omit the first \" \" when\n>   printing the \"running\" line.\n> - Ditto for other cases where we emitted the argument\n> - We say \"found first bad commit\" again, not just \"run success\"\n\nSo, something you refactored here was that there's now a\ndo_bisect_run(), and:\n\n> -static int do_bisect_run(const char *command, int argc, const char **argv)\n> +static int do_bisect_run(const char *command, int argc UNUSED, const char **argv UNUSED)\n>  {\n>  \tstruct child_process cmd = CHILD_PROCESS_INIT;\n> -\tstruct strbuf buf = STRBUF_INIT;\n> +\tconst char *trimed = command;\n>  \n> -\tstrbuf_join_argv(&buf, argc, argv, ' ');\n> -\tprintf(_(\"running %s\\n\"), buf.buf);\n> -\tstrbuf_release(&buf);\n> +\twhile (*trimed && isspace(*trimed))\n> +\t\ttrimed++;\n> +\tprintf(_(\"running %s\\n\"), trimed);\n>  \tcmd.use_shell = 1;\n>  \tstrvec_push(&cmd.args, command);\n>  \treturn run_command(&cmd);\n\nInstead of trimming with strbuf_ltrim() we're now using this loop, but\nin any case, this has had the effect that you're only fixing one of many\nof the output changes. We're still adding this leading whitespace to the\nother messages we emit.\n\nAs note din the preceding commit you've carried here in 03/13 I didn't\nhave time to come up with tests for those.\n"},{"id":"466756","messageId":"221107.86fseutp3v.gmgdl@evledraar.gmail.com","threadId":"58746","inReplyTo":"8037667da0f3d9f91c8f2aa477e2e95fb7f0c24b.1667667460.git.congdanhqx@gmail.com","subject":"Re: [PATCH 11/13] bisect--helper: remove subcommand state","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-07T21:45:50Z","receivedAt":"2022-11-07T21:46:21Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Sun, Nov 06 2022, Đoàn Trần Công Danh wrote:\n\n> In previous change, we've made 'state' optional, and replaced all of its\n> usage.\n>\n> Let's remove it, now.\n\nLet's remove it then? I.e. let's squash this into 10/13. No reason not\nto...\n"},{"id":"466777","messageId":"Y2mtu701F5ZCxHXz@danh.dev","threadId":"58746","inReplyTo":"221107.86o7titppp.gmgdl@evledraar.gmail.com","subject":"Re: [PATCH 01/13] bisect tests: test for v2.30.0 \"bisect run\" regressions","fromName":"Đoàn Trần Công Danh","fromEmail":"congdanhqx@gmail.com","sentAt":"2022-11-08T01:17:32Z","receivedAt":"2022-11-08T01:17:40Z","isPatch":true,"sender":{"key":"congdanhqx@gmail.com","avatar":"https://avatars.githubusercontent.com/u/42673067?v=4"},"body":"On 2022-11-07 22:31:50+0100, Ævar Arnfjörð Bjarmason <avarab@gmail.com> wrote:\n> \n> On Sun, Nov 06 2022, Đoàn Trần Công Danh wrote:\n> \n> > From: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> >\n> > Add three failing tests which succeed on v2.29.0, but due to the topic\n> > merged at [1] (specifically [2]) have been failing since then. We'll\n> > address those regressions in subsequent commits.\n> >\n> > There was also a \"regression\" where:\n> >\n> > \tgit bisect run ./missing-script.sh\n> >\n> > Would count a non-existing script as \"good\", as the shell would exit\n> > with 127. That edge case is a bit too insane to preserve, so let's not\n> > add it to these regression tests.\n> >\n> > 1. 0a4cb1f1f2f (Merge branch 'mr/bisect-in-c-4', 2021-09-23)\n> > 2. d1bbbe45df8 (bisect--helper: reimplement `bisect_run` shell\n> >    function in C, 2021-09-13)\n> >\n> > Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> > Signed-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>\n> > ---\n> >  t/t6030-bisect-porcelain.sh | 79 +++++++++++++++++++++++++++++++++++++\n> >  1 file changed, 79 insertions(+)\n> \n> Looks good, if I do say so myself :) (unchanged from my topic)\n> \n> But I wonder why your \"fix the regression\" base topic isn't starting\n> with this. I.e. our intial report was about that \"--log\" issue, but now\n> we know we altered the output in ways we didn't intend.\n\nWell, I would like to keep that topic as much short as possible to\nhave a higher chance of fixing real regression first. Those changes is\nerror/warning/log are less important as you said below ...\n \n> It's fine if we say \"that's less important\", but then ... something\n> should say that .. :)\n\nSure, I will add it in the next revision.\n\n\n-- \nDanh\n"},{"id":"466778","messageId":"Y2mwN3bpaiN/7vJh@danh.dev","threadId":"58746","inReplyTo":"221107.86k046tp8p.gmgdl@evledraar.gmail.com","subject":"Re: [PATCH 05/13] bisect run: keep some of the post-v2.30.0 output","fromName":"Đoàn Trần Công Danh","fromEmail":"congdanhqx@gmail.com","sentAt":"2022-11-08T01:26:15Z","receivedAt":"2022-11-08T01:26:21Z","isPatch":true,"sender":{"key":"congdanhqx@gmail.com","avatar":"https://avatars.githubusercontent.com/u/42673067?v=4"},"body":"On 2022-11-07 22:40:33+0100, Ævar Arnfjörð Bjarmason <avarab@gmail.com> wrote:\n> \n> On Sun, Nov 06 2022, Đoàn Trần Công Danh wrote:\n> \n> > From: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> >\n> > Preceding commits fixed output and behavior regressions in\n> > d1bbbe45df8 (bisect--helper: reimplement `bisect_run` shell function\n> > in C, 2021-09-13), which did not claim to be changing the output of\n> > \"git bisect run\".\n> >\n> > But some of the output it emitted was subjectively better, so once\n> > we've asserted that we're back on v2.29.0 behavior, let's change some\n> > of it back:\n> >\n> > - We now quote the arguments again, but omit the first \" \" when\n> >   printing the \"running\" line.\n> > - Ditto for other cases where we emitted the argument\n> > - We say \"found first bad commit\" again, not just \"run success\"\n> \n> So, something you refactored here was that there's now a\n> do_bisect_run(), and:\n> \n> > -static int do_bisect_run(const char *command, int argc, const char **argv)\n> > +static int do_bisect_run(const char *command, int argc UNUSED, const char **argv UNUSED)\n> >  {\n> >  \tstruct child_process cmd = CHILD_PROCESS_INIT;\n> > -\tstruct strbuf buf = STRBUF_INIT;\n> > +\tconst char *trimed = command;\n> >  \n> > -\tstrbuf_join_argv(&buf, argc, argv, ' ');\n> > -\tprintf(_(\"running %s\\n\"), buf.buf);\n> > -\tstrbuf_release(&buf);\n> > +\twhile (*trimed && isspace(*trimed))\n> > +\t\ttrimed++;\n> > +\tprintf(_(\"running %s\\n\"), trimed);\n> >  \tcmd.use_shell = 1;\n> >  \tstrvec_push(&cmd.args, command);\n> >  \treturn run_command(&cmd);\n> \n> Instead of trimming with strbuf_ltrim() we're now using this loop, but\n> in any case, this has had the effect that you're only fixing one of many\n> of the output changes. We're still adding this leading whitespace to the\n> other messages we emit.\n\nSorry, I can't follow, we're fixing in do_bisect_run, which meant we\nfixed all of the output changes for leading whitespace, no?\n\n'do_bisect_run' will be called from normal 'git bisect run' iteration\nand also after receiving code 126/127 for the very first run.\n\nWhich is the other cases you're talking about?\n\n> \n> As note din the preceding commit you've carried here in 03/13 I didn't\n> have time to come up with tests for those.\n\n-- \nDanh\n"},{"id":"466779","messageId":"Y2mwgeXQh21e4wFf@danh.dev","threadId":"58746","inReplyTo":"221107.86fseutp3v.gmgdl@evledraar.gmail.com","subject":"Re: [PATCH 11/13] bisect--helper: remove subcommand state","fromName":"Đoàn Trần Công Danh","fromEmail":"congdanhqx@gmail.com","sentAt":"2022-11-08T01:27:29Z","receivedAt":"2022-11-08T01:27:36Z","isPatch":true,"sender":{"key":"congdanhqx@gmail.com","avatar":"https://avatars.githubusercontent.com/u/42673067?v=4"},"body":"On 2022-11-07 22:45:50+0100, Ævar Arnfjörð Bjarmason <avarab@gmail.com> wrote:\n> \n> On Sun, Nov 06 2022, Đoàn Trần Công Danh wrote:\n> \n> > In previous change, we've made 'state' optional, and replaced all of its\n> > usage.\n> >\n> > Let's remove it, now.\n> \n> Let's remove it then? I.e. let's squash this into 10/13. No reason not\n> to...\n\nI was following the existing (I think) practice of removing\na subcommand in a separated commit. Sure, I can meld it into 10/13\n\n-- \nDanh\n"},{"id":"466786","messageId":"221108.86y1smrube.gmgdl@evledraar.gmail.com","threadId":"58746","inReplyTo":"Y2mwN3bpaiN/7vJh@danh.dev","subject":"Re: [PATCH 05/13] bisect run: keep some of the post-v2.30.0 output","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-08T03:11:27Z","receivedAt":"2022-11-08T03:36:43Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Tue, Nov 08 2022, Đoàn Trần Công Danh wrote:\n\n> On 2022-11-07 22:40:33+0100, Ævar Arnfjörð Bjarmason <avarab@gmail.com> wrote:\n>> \n>> On Sun, Nov 06 2022, Đoàn Trần Công Danh wrote:\n>> \n>> > From: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n>> >\n>> > Preceding commits fixed output and behavior regressions in\n>> > d1bbbe45df8 (bisect--helper: reimplement `bisect_run` shell function\n>> > in C, 2021-09-13), which did not claim to be changing the output of\n>> > \"git bisect run\".\n>> >\n>> > But some of the output it emitted was subjectively better, so once\n>> > we've asserted that we're back on v2.29.0 behavior, let's change some\n>> > of it back:\n>> >\n>> > - We now quote the arguments again, but omit the first \" \" when\n>> >   printing the \"running\" line.\n>> > - Ditto for other cases where we emitted the argument\n>> > - We say \"found first bad commit\" again, not just \"run success\"\n>> \n>> So, something you refactored here was that there's now a\n>> do_bisect_run(), and:\n>> \n>> > -static int do_bisect_run(const char *command, int argc, const char **argv)\n>> > +static int do_bisect_run(const char *command, int argc UNUSED, const char **argv UNUSED)\n>> >  {\n>> >  \tstruct child_process cmd = CHILD_PROCESS_INIT;\n>> > -\tstruct strbuf buf = STRBUF_INIT;\n>> > +\tconst char *trimed = command;\n>> >  \n>> > -\tstrbuf_join_argv(&buf, argc, argv, ' ');\n>> > -\tprintf(_(\"running %s\\n\"), buf.buf);\n>> > -\tstrbuf_release(&buf);\n>> > +\twhile (*trimed && isspace(*trimed))\n>> > +\t\ttrimed++;\n>> > +\tprintf(_(\"running %s\\n\"), trimed);\n>> >  \tcmd.use_shell = 1;\n>> >  \tstrvec_push(&cmd.args, command);\n>> >  \treturn run_command(&cmd);\n>> \n>> Instead of trimming with strbuf_ltrim() we're now using this loop, but\n>> in any case, this has had the effect that you're only fixing one of many\n>> of the output changes. We're still adding this leading whitespace to the\n>> other messages we emit.\n>\n> Sorry, I can't follow, we're fixing in do_bisect_run, which meant we\n> fixed all of the output changes for leading whitespace, no?\n>\n> 'do_bisect_run' will be called from normal 'git bisect run' iteration\n> and also after receiving code 126/127 for the very first run.\n>\n> Which is the other cases you're talking about?\n\nThe other uses of command.buf in my initial version, i.e. I did:\n\t\n\t-       strbuf_reset(&command);\n\t-       strbuf_join_argv(&command, argc, argv, ' ');\n\t+       /* Quoted, but skip initial \" \" */\n\t+       strbuf_ltrim(&command);\n\nAnd the command.buf is then used by:\n\n\tprintf(_(\"running %s\\n\"), command.buf);\n\tres = run_command_v_opt(run_args.v, RUN_USING_SHELL);\n\nWhich your version covers, but also this, in bisect_run() just a few\nlines later:\n\n\terror(_(\"unable to verify '%s' on good\"\n\t      \" revision\"), command.buf);\n\nAnd, for:\n\n\terror(_(\"bisect run failed: exit code %d from\"\n\t      \" '%s' is < 0 or >= 128\"), res, command.buf);\n\nIn the original *.sh version of this it used the same variable.\n\nBut yours deals with the refactored do_bisect_run() from René's\ne8de018438e (bisect--helper: factor out do_bisect_run(), 2022-10-27).\n\nSo that first \"running\" takes place in its ownown do_bisect_run()\nfunction, and you only skip past the whitespace in the \"const char\n*command\" local to that function.\n\nThus you're only trimming the whitespace for 1/3 cases, the 2/3 being\nnoted in the 04/13 as the ones I didn't write a test for.\n\nI think this squashed in should be functionally equivalent:\n\t\n\tdiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\n\tindex f16b9df8fd6..493e062e76d 100644\n\t--- a/builtin/bisect--helper.c\n\t+++ b/builtin/bisect--helper.c\n\t@@ -1141,20 +1141,17 @@ static int get_first_good(const char *refname UNUSED,\n\t \treturn 1;\n\t }\n\t \n\t-static int do_bisect_run(const char *command, int argc UNUSED, const char **argv UNUSED)\n\t+static int do_bisect_run(const char *command, const char *trimmed)\n\t {\n\t \tstruct child_process cmd = CHILD_PROCESS_INIT;\n\t-\tconst char *trimed = command;\n\t \n\t-\twhile (*trimed && isspace(*trimed))\n\t-\t\ttrimed++;\n\t-\tprintf(_(\"running %s\\n\"), trimed);\n\t+\tprintf(_(\"running %s\\n\"), trimmed);\n\t \tcmd.use_shell = 1;\n\t \tstrvec_push(&cmd.args, command);\n\t \treturn run_command(&cmd);\n\t }\n\t \n\t-static int verify_good(const struct bisect_terms *terms, const char *command, int argc, const char **argv)\n\t+static int verify_good(const struct bisect_terms *terms, const char *command, const char *trimmed)\n\t {\n\t \tint rc;\n\t \tenum bisect_error res;\n\t@@ -1174,7 +1171,7 @@ static int verify_good(const struct bisect_terms *terms, const char *command, in\n\t \tif (res != BISECT_OK)\n\t \t\treturn -1;\n\t \n\t-\trc = do_bisect_run(command, argc, argv);\n\t+\trc = do_bisect_run(command, trimmed);\n\t \n\t \tres = bisect_checkout(&current_rev, no_checkout);\n\t \tif (res != BISECT_OK)\n\t@@ -1187,6 +1184,7 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n\t {\n\t \tint res = BISECT_OK;\n\t \tstruct strbuf command = STRBUF_INIT;\n\t+\tstruct strbuf trimmed = STRBUF_INIT;\n\t \tconst char *new_state;\n\t \tint temporary_stdout_fd, saved_stdout;\n\t \tint is_first_run = 1;\n\t@@ -1200,8 +1198,10 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n\t \t}\n\t \n\t \tsq_quote_argv(&command, argv);\n\t+\tstrbuf_addbuf(&trimmed, &command);\n\t+\tstrbuf_ltrim(&trimmed);\n\t \twhile (1) {\n\t-\t\tres = do_bisect_run(command.buf, argc, argv);\n\t+\t\tres = do_bisect_run(command.buf, trimmed.buf);\n\t \n\t \t\t/*\n\t \t\t * Exit code 126 and 127 can either come from the shell\n\t@@ -1211,7 +1211,7 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n\t \t\t * missing or non-executable script.\n\t \t\t */\n\t \t\tif (is_first_run && (res == 126 || res == 127)) {\n\t-\t\t\tint rc = verify_good(terms, command.buf, argc, argv);\n\t+\t\t\tint rc = verify_good(terms, command.buf, trimmed.buf);\n\t \t\t\tis_first_run = 0;\n\t \t\t\tif (rc < 0) {\n\t \t\t\t\terror(_(\"unable to verify '%s' on good\"\n\nSome of that's a bit of a hassle with e8de018438e, but this way we use\nthe whitespace-prefixed for run_command(), but not for the output. Maybe\nwe can just always use the trimmed version, I didn't check.\n\nThis approach would also mean that you can drop your 03/13 and 06/13\nsurrounding this commit, in 03/13 you added that argv/argc because:\n\n\t[...]\t\n\tIn a later change, we would like to restore the old behaviours,\n\twhich would need information regarding argc and argv.\n\nThat \"later change\" is your 04/13, then in 05/13 you're back to them\nbeing UNUSED, before 06/13 finally drops them.\n\nBut if we just pass both trimmed & non-trimmed into do_bisect_run() to\nbegin with we don't need to go through all of that...\n"},{"id":"467041","messageId":"2477861r-9363-75sn-q415-o19206q70p90@tzk.qr","threadId":"58746","inReplyTo":"cover-00.13-00000000000-20221104T132117Z-avarab@gmail.com","subject":"Re: [PATCH 00/13] bisect: v2.30.0 \"run\" regressions + make it built-in","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2022-11-10T12:50:15Z","receivedAt":"2022-11-10T12:50:37Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Ævar,\n\nI see you Cc:ed me on this, but I have to admit that I am not motivated to\nreview this patch series because it seems to be designed to interfere with\n`js/bisect-in-c` instead of being an honest effort to help me get that\npatch series over the finish line.\n\nI'd much rather see you assist me in the most efficient/minimal way\npossible to get `js/bisect-in-c` into a shape that can be integrated.\n\nCiao,\nJohannes\n\nOn Fri, 4 Nov 2022, Ævar Arnfjörð Bjarmason wrote:\n\n> This fixes the regression Lukáš Doktor reported in [1], and also gets\n> us the full way to a builtin/bisect.c and \"git rm git-bisect.sh\".\n>\n> Only 1-4/13 here are needed to fix the \"git bisect run <cmd> [...]\n> --log\" regression Lukáš reported, but as Jeff points out we'd still\n> conflate \"--bisect-*\" with the user arguments. That's fixed in 11/13\n> here.\n>\n> The 1-4/13 here also fixes other but probably more minor \"git bisect\n> run\" regressions in v2.30.0, we changed the output in a few ways\n> without intending it. 4/13 gets us mostly back to v2.29.0 behavior,\n> 5/13 keeps the best of it and the current output.\n>\n> I think for the v2.30.0 regressions we're better off with just\n> something like 1-4/13 here for now, and possibly 5/13 too.\n>\n> But getting to the point of fixing the root cause of \"--bisect-*\"\n> being conflated is going to take quite a bit of churn. In the\n> side-thread Đoàn's diffstat is on the order of 1/2 of the size of this\n> series, and this gives us built-in \"bisect\".\n>\n> The 6-13 here is something I had already for a couple of days, I was\n> seeing if I could distill Johannes's [2] down to something much\n> smaller, to just make a beeline towards a built-in bisect.\n>\n> Johannes's refactors the \"term\" passing in [3], and Đoàn ends up\n> needing to do much the same in [4].\n>\n> Here in 9/13 I instead just extend the OPT_SUBCOMMAND() API so it's\n> able to accept function callbacks with custom signatures, which\n> eliminates the need for most of that refactoring. 11/13 then makes use\n> of it.\n>\n> 1. https://lore.kernel.org/git/1cb1c033-0525-7e62-8c09-81019bf26060@redhat.com/\n> 2. https://lore.kernel.org/git/pull.1132.v6.git.1661885419.gitgitgadget@gmail.com/\n> 3. https://lore.kernel.org/git/92b3b116ef8f879192d9deb94d68b73e29d5dcd6.1661885419.git.gitgitgadget@gmail.com/\n> 4. https://lore.kernel.org/git/081f3f7f9501012404fb9e59ab6d94f632180b53.1667561761.git.congdanhqx@gmail.com/\n>\n> Johannes Schindelin (3):\n>   bisect--helper: remove dead --bisect-{next-check,autostart} code\n>   bisect--helper: make `state` optional\n>   Turn `git bisect` into a full built-in\n>\n> Ævar Arnfjörð Bjarmason (10):\n>   bisect tests: test for v2.30.0 \"bisect run\" regressions\n>   bisect: refactor bisect_run() to match CodingGuidelines\n>   bisect: fix output regressions in v2.30.0\n>   bisect run: fix \"--log\" eating regression in v2.30.0\n>   bisect run: keep some of the post-v2.30.0 output\n>   bisect test: test exit codes on bad usage\n>   bisect--helper: emit usage for \"git bisect\"\n>   bisect--helper: have all functions take state, argc, argv, prefix\n>   parse-options API: don't restrict OPT_SUBCOMMAND() to one *_fn  type\n>   bisect--helper: convert to OPT_SUBCOMMAND_CB()\n>\n>  Makefile                               |   3 +-\n>  builtin.h                              |   2 +-\n>  builtin/{bisect--helper.c => bisect.c} | 250 +++++++++++++------------\n>  git-bisect.sh                          |  84 ---------\n>  git.c                                  |   2 +-\n>  parse-options.c                        |   9 +-\n>  parse-options.h                        |  31 ++-\n>  t/t6030-bisect-porcelain.sh            | 109 +++++++++++\n>  8 files changed, 277 insertions(+), 213 deletions(-)\n>  rename builtin/{bisect--helper.c => bisect.c} (86%)\n>  delete mode 100755 git-bisect.sh\n>\n> --\n> 2.38.0.1452.g710f45c7951\n>\n>\n"},{"id":"467051","messageId":"cover.1668097286.git.congdanhqx@gmail.com","threadId":"58746","inReplyTo":"cover.1667561761.git.congdanhqx@gmail.com","subject":"[PATCH v3 0/3] Convert git-bisect--helper to OPT_SUBCOMMAND","fromName":"Đoàn Trần Công Danh","fromEmail":"congdanhqx@gmail.com","sentAt":"2022-11-10T16:36:19Z","receivedAt":"2022-11-10T16:36:34Z","isPatch":true,"sender":{"key":"congdanhqx@gmail.com","avatar":"https://avatars.githubusercontent.com/u/42673067?v=4"},"body":"Despite this series has been merged into next.\nI'm sending this because Taylor said he wanted a (combined) reroll?\n<Y2riRSL+NprJt278@nand.local>\n\nChange from v2 is only about cosmetic things, (structure zero-initialization)\n\nThis series aims to fix the problem that bisect--helper incorrectly consumes\n\"--log\" when running:\n\n\tgit bisect run cmd --log\n\nThis also clears a way for turning git-bisect into a built-in in a later day.\n\nThe series that convert git-bisect to builtin will be posted later as a reply\nto this series\n\nĐoàn Trần Công Danh (3):\n  bisect--helper: remove unused options\n  bisect--helper: move all subcommands into their own functions\n  bisect--helper: parse subcommand with OPT_SUBCOMMAND\n\n builtin/bisect--helper.c    | 229 ++++++++++++++++++++----------------\n git-bisect.sh               |  23 +---\n t/t6030-bisect-porcelain.sh |  10 ++\n 3 files changed, 142 insertions(+), 120 deletions(-)\n\nRange-diff against v2:\n-:  ---------- > 1:  6b80fd9398 bisect--helper: remove unused options\n1:  9d8a3cdd7a ! 2:  248ed392ea bisect--helper: move all subcommands into their own functions\n    @@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, cons\n     +static int cmd_bisect__terms(int argc, const char **argv, const char *prefix UNUSED)\n     +{\n     +\tint res;\n    -+\tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\n    ++\tstruct bisect_terms terms = { 0 };\n     +\n     +\tif (argc > 1)\n     +\t\treturn error(_(\"--bisect-terms requires 0 or 1 argument\"));\n    @@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, cons\n     +static int cmd_bisect__start(int argc, const char **argv, const char *prefix UNUSED)\n     +{\n     +\tint res;\n    -+\tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\n    ++\tstruct bisect_terms terms = { 0 };\n     +\n     +\tset_terms(&terms, \"bad\", \"good\");\n     +\tres = bisect_start(&terms, argv, argc);\n    @@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, cons\n     +static int cmd_bisect__next(int argc, const char **argv UNUSED, const char *prefix)\n     +{\n     +\tint res;\n    -+\tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\n    ++\tstruct bisect_terms terms = { 0 };\n     +\n     +\tif (argc)\n     +\t\treturn error(_(\"--bisect-next requires 0 arguments\"));\n    @@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, cons\n     +static int cmd_bisect__state(int argc, const char **argv, const char *prefix UNUSED)\n     +{\n     +\tint res;\n    -+\tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\n    ++\tstruct bisect_terms terms = { 0 };\n     +\n     +\tset_terms(&terms, \"bad\", \"good\");\n     +\tget_terms(&terms);\n    @@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, cons\n     +static int cmd_bisect__replay(int argc, const char **argv, const char *prefix UNUSED)\n     +{\n     +\tint res;\n    -+\tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\n    ++\tstruct bisect_terms terms = { 0 };\n     +\n     +\tif (argc != 1)\n     +\t\treturn error(_(\"no logfile given\"));\n    @@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, cons\n     +static int cmd_bisect__skip(int argc, const char **argv, const char *prefix UNUSED)\n     +{\n     +\tint res;\n    -+\tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\n    ++\tstruct bisect_terms terms = { 0 };\n     +\n     +\tset_terms(&terms, \"bad\", \"good\");\n     +\tget_terms(&terms);\n    @@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, cons\n     +static int cmd_bisect__visualize(int argc, const char **argv, const char *prefix UNUSED)\n     +{\n     +\tint res;\n    -+\tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\n    ++\tstruct bisect_terms terms = { 0 };\n     +\n     +\tget_terms(&terms);\n     +\tres = bisect_visualize(&terms, argv, argc);\n    @@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, cons\n     +static int cmd_bisect__run(int argc, const char **argv, const char *prefix UNUSED)\n     +{\n     +\tint res;\n    -+\tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\n    ++\tstruct bisect_terms terms = { 0 };\n     +\n     +\tif (!argc)\n     +\t\treturn error(_(\"bisect run failed: no command provided.\"));\n2:  a62ac72e24 = 3:  b67691f600 bisect--helper: parse subcommand with OPT_SUBCOMMAND\n-- \n2.38.1.157.gedabe22e0a\n\n"},{"id":"467052","messageId":"6b80fd93980ec5171fe0637cbd1a8173a5337da4.1668097286.git.congdanhqx@gmail.com","threadId":"58746","inReplyTo":"cover.1668097286.git.congdanhqx@gmail.com","subject":"[PATCH v3 1/3] bisect--helper: remove unused options","fromName":"Đoàn Trần Công Danh","fromEmail":"congdanhqx@gmail.com","sentAt":"2022-11-10T16:36:20Z","receivedAt":"2022-11-10T16:36:39Z","isPatch":true,"sender":{"key":"congdanhqx@gmail.com","avatar":"https://avatars.githubusercontent.com/u/42673067?v=4"},"body":"'git-bisect.sh' used to have a 'bisect_next_check' to check if we have\nboth good/bad, old/new terms set or not.  In commit 129a6cf344\n(bisect--helper: `bisect_next_check` shell function in C, 2019-01-02),\na subcommand for bisect--helper was introduced to port the check to C.\nSince d1bbbe45df (bisect--helper: reimplement `bisect_run` shell\nfunction in C, 2021-09-13), all users of 'bisect_next_check' was\nre-implemented in C, this subcommand was no longer used but we forgot\nto remove '--bisect-next-check'.\n\n'git-bisect.sh' also used to have a 'bisect_write' function, whose\nthird positional parameter was a \"nolog\" flag.  This flag was only used\nwhen 'bisect_start' invoked 'bisect_write' to write the starting good\nand bad revisions.  Then 0f30233a11 (bisect--helper: `bisect_write`\nshell function in C, 2019-01-02) ported it to C as a command mode of\n'bisect--helper', which (incorrectly) added the '--no-log' option,\nand convert the only place ('bisect_start') that call 'bisect_write'\nwith 'nolog' to 'git bisect--helper --bisect-write' with 'nolog'\ninstead of '--no-log', since 'bisect--helper' has command modes not\nsubcommands, all other command modes see and handle that option as well.\nThis bogus state didn't last long, however, because in the same patch\nseries 06f5608c14 (bisect--helper: `bisect_start` shell function\npartially in C, 2019-01-02) the C reimplementation of bisect_start()\nstarted calling the bisect_write() C function, this time with the\nright 'nolog' function parameter. From then on there was no need for\nthe '--no-log' option in 'bisect--helper'. Eventually all bisect\nsubcommands were ported to C as 'bisect--helper' command modes, each\ncalling the bisect_write() C function instead, but when the\n'--bisect-write' command mode was removed in 68efed8c8a\n(bisect--helper: retire `--bisect-write` subcommand, 2021-02-03) it\nforgot to remove that '--no-log' option.\n'--no-log' option had never been used and it's unused now.\n\nLet's remove --bisect-next-check and --no-log from option parsing.\n\nSigned-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>\n---\n builtin/bisect--helper.c | 7 +------\n 1 file changed, 1 insertion(+), 6 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 1d2ce8a0e1..5ec2e67f59 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1283,7 +1283,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n {\n \tenum {\n \t\tBISECT_RESET = 1,\n-\t\tBISECT_NEXT_CHECK,\n \t\tBISECT_TERMS,\n \t\tBISECT_START,\n \t\tBISECT_AUTOSTART,\n@@ -1295,12 +1294,10 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\tBISECT_VISUALIZE,\n \t\tBISECT_RUN,\n \t} cmdmode = 0;\n-\tint res = 0, nolog = 0;\n+\tint res = 0;\n \tstruct option options[] = {\n \t\tOPT_CMDMODE(0, \"bisect-reset\", &cmdmode,\n \t\t\t N_(\"reset the bisection state\"), BISECT_RESET),\n-\t\tOPT_CMDMODE(0, \"bisect-next-check\", &cmdmode,\n-\t\t\t N_(\"check whether bad or good terms exist\"), BISECT_NEXT_CHECK),\n \t\tOPT_CMDMODE(0, \"bisect-terms\", &cmdmode,\n \t\t\t N_(\"print out the bisect terms\"), BISECT_TERMS),\n \t\tOPT_CMDMODE(0, \"bisect-start\", &cmdmode,\n@@ -1319,8 +1316,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\t\t N_(\"visualize the bisection\"), BISECT_VISUALIZE),\n \t\tOPT_CMDMODE(0, \"bisect-run\", &cmdmode,\n \t\t\t N_(\"use <cmd>... to automatically bisect\"), BISECT_RUN),\n-\t\tOPT_BOOL(0, \"no-log\", &nolog,\n-\t\t\t N_(\"no log for BISECT_WRITE\")),\n \t\tOPT_END()\n \t};\n \tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\n-- \n2.38.1.157.gedabe22e0a\n\n"},{"id":"467053","messageId":"248ed392ea8bc7c812156276bd120bc9d5b8ba6e.1668097286.git.congdanhqx@gmail.com","threadId":"58746","inReplyTo":"cover.1668097286.git.congdanhqx@gmail.com","subject":"[PATCH v3 2/3] bisect--helper: move all subcommands into their own functions","fromName":"Đoàn Trần Công Danh","fromEmail":"congdanhqx@gmail.com","sentAt":"2022-11-10T16:36:21Z","receivedAt":"2022-11-10T16:36:41Z","isPatch":true,"sender":{"key":"congdanhqx@gmail.com","avatar":"https://avatars.githubusercontent.com/u/42673067?v=4"},"body":"In a later change, we will use OPT_SUBCOMMAND to parse sub-commands to\navoid consuming non-option opts.\n\nSince OPT_SUBCOMMAND needs a function pointer to operate,\nlet's move it now.\n\nSigned-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>\n---\n builtin/bisect--helper.c | 155 ++++++++++++++++++++++++++++++---------\n 1 file changed, 121 insertions(+), 34 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 5ec2e67f59..d425555d1f 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1279,6 +1279,117 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n \treturn res;\n }\n \n+static int cmd_bisect__reset(int argc, const char **argv, const char *prefix UNUSED)\n+{\n+\tif (argc > 1)\n+\t\treturn error(_(\"--bisect-reset requires either no argument or a commit\"));\n+\treturn bisect_reset(argc ? argv[0] : NULL);\n+}\n+\n+static int cmd_bisect__terms(int argc, const char **argv, const char *prefix UNUSED)\n+{\n+\tint res;\n+\tstruct bisect_terms terms = { 0 };\n+\n+\tif (argc > 1)\n+\t\treturn error(_(\"--bisect-terms requires 0 or 1 argument\"));\n+\tres = bisect_terms(&terms, argc == 1 ? argv[0] : NULL);\n+\tfree_terms(&terms);\n+\treturn res;\n+}\n+\n+static int cmd_bisect__start(int argc, const char **argv, const char *prefix UNUSED)\n+{\n+\tint res;\n+\tstruct bisect_terms terms = { 0 };\n+\n+\tset_terms(&terms, \"bad\", \"good\");\n+\tres = bisect_start(&terms, argv, argc);\n+\tfree_terms(&terms);\n+\treturn res;\n+}\n+\n+static int cmd_bisect__next(int argc, const char **argv UNUSED, const char *prefix)\n+{\n+\tint res;\n+\tstruct bisect_terms terms = { 0 };\n+\n+\tif (argc)\n+\t\treturn error(_(\"--bisect-next requires 0 arguments\"));\n+\tget_terms(&terms);\n+\tres = bisect_next(&terms, prefix);\n+\tfree_terms(&terms);\n+\treturn res;\n+}\n+\n+static int cmd_bisect__state(int argc, const char **argv, const char *prefix UNUSED)\n+{\n+\tint res;\n+\tstruct bisect_terms terms = { 0 };\n+\n+\tset_terms(&terms, \"bad\", \"good\");\n+\tget_terms(&terms);\n+\tres = bisect_state(&terms, argv, argc);\n+\tfree_terms(&terms);\n+\treturn res;\n+}\n+\n+static int cmd_bisect__log(int argc, const char **argv UNUSED, const char *prefix UNUSED)\n+{\n+\tif (argc)\n+\t\treturn error(_(\"--bisect-log requires 0 arguments\"));\n+\treturn bisect_log();\n+}\n+\n+static int cmd_bisect__replay(int argc, const char **argv, const char *prefix UNUSED)\n+{\n+\tint res;\n+\tstruct bisect_terms terms = { 0 };\n+\n+\tif (argc != 1)\n+\t\treturn error(_(\"no logfile given\"));\n+\tset_terms(&terms, \"bad\", \"good\");\n+\tres = bisect_replay(&terms, argv[0]);\n+\tfree_terms(&terms);\n+\treturn res;\n+}\n+\n+static int cmd_bisect__skip(int argc, const char **argv, const char *prefix UNUSED)\n+{\n+\tint res;\n+\tstruct bisect_terms terms = { 0 };\n+\n+\tset_terms(&terms, \"bad\", \"good\");\n+\tget_terms(&terms);\n+\tres = bisect_skip(&terms, argv, argc);\n+\tfree_terms(&terms);\n+\treturn res;\n+}\n+\n+static int cmd_bisect__visualize(int argc, const char **argv, const char *prefix UNUSED)\n+{\n+\tint res;\n+\tstruct bisect_terms terms = { 0 };\n+\n+\tget_terms(&terms);\n+\tres = bisect_visualize(&terms, argv, argc);\n+\tfree_terms(&terms);\n+\treturn res;\n+}\n+\n+static int cmd_bisect__run(int argc, const char **argv, const char *prefix UNUSED)\n+{\n+\tint res;\n+\tstruct bisect_terms terms = { 0 };\n+\n+\tif (!argc)\n+\t\treturn error(_(\"bisect run failed: no command provided.\"));\n+\tget_terms(&terms);\n+\tres = bisect_run(&terms, argv, argc);\n+\tfree_terms(&terms);\n+\treturn res;\n+}\n+\n int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n {\n \tenum {\n@@ -1318,8 +1429,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\t\t N_(\"use <cmd>... to automatically bisect\"), BISECT_RUN),\n \t\tOPT_END()\n \t};\n-\tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\n-\n \targc = parse_options(argc, argv, prefix, options,\n \t\t\t     git_bisect_helper_usage,\n \t\t\t     PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN_OPT);\n@@ -1329,60 +1438,38 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \n \tswitch (cmdmode) {\n \tcase BISECT_RESET:\n-\t\tif (argc > 1)\n-\t\t\treturn error(_(\"--bisect-reset requires either no argument or a commit\"));\n-\t\tres = bisect_reset(argc ? argv[0] : NULL);\n+\t\tres = cmd_bisect__reset(argc, argv, prefix);\n \t\tbreak;\n \tcase BISECT_TERMS:\n-\t\tif (argc > 1)\n-\t\t\treturn error(_(\"--bisect-terms requires 0 or 1 argument\"));\n-\t\tres = bisect_terms(&terms, argc == 1 ? argv[0] : NULL);\n+\t\tres = cmd_bisect__terms(argc, argv, prefix);\n \t\tbreak;\n \tcase BISECT_START:\n-\t\tset_terms(&terms, \"bad\", \"good\");\n-\t\tres = bisect_start(&terms, argv, argc);\n+\t\tres = cmd_bisect__start(argc, argv, prefix);\n \t\tbreak;\n \tcase BISECT_NEXT:\n-\t\tif (argc)\n-\t\t\treturn error(_(\"--bisect-next requires 0 arguments\"));\n-\t\tget_terms(&terms);\n-\t\tres = bisect_next(&terms, prefix);\n+\t\tres = cmd_bisect__next(argc, argv, prefix);\n \t\tbreak;\n \tcase BISECT_STATE:\n-\t\tset_terms(&terms, \"bad\", \"good\");\n-\t\tget_terms(&terms);\n-\t\tres = bisect_state(&terms, argv, argc);\n+\t\tres = cmd_bisect__state(argc, argv, prefix);\n \t\tbreak;\n \tcase BISECT_LOG:\n-\t\tif (argc)\n-\t\t\treturn error(_(\"--bisect-log requires 0 arguments\"));\n-\t\tres = bisect_log();\n+\t\tres = cmd_bisect__log(argc, argv, prefix);\n \t\tbreak;\n \tcase BISECT_REPLAY:\n-\t\tif (argc != 1)\n-\t\t\treturn error(_(\"no logfile given\"));\n-\t\tset_terms(&terms, \"bad\", \"good\");\n-\t\tres = bisect_replay(&terms, argv[0]);\n+\t\tres = cmd_bisect__replay(argc, argv, prefix);\n \t\tbreak;\n \tcase BISECT_SKIP:\n-\t\tset_terms(&terms, \"bad\", \"good\");\n-\t\tget_terms(&terms);\n-\t\tres = bisect_skip(&terms, argv, argc);\n+\t\tres = cmd_bisect__skip(argc, argv, prefix);\n \t\tbreak;\n \tcase BISECT_VISUALIZE:\n-\t\tget_terms(&terms);\n-\t\tres = bisect_visualize(&terms, argv, argc);\n+\t\tres = cmd_bisect__visualize(argc, argv, prefix);\n \t\tbreak;\n \tcase BISECT_RUN:\n-\t\tif (!argc)\n-\t\t\treturn error(_(\"bisect run failed: no command provided.\"));\n-\t\tget_terms(&terms);\n-\t\tres = bisect_run(&terms, argv, argc);\n+\t\tres = cmd_bisect__run(argc, argv, prefix);\n \t\tbreak;\n \tdefault:\n \t\tBUG(\"unknown subcommand %d\", cmdmode);\n \t}\n-\tfree_terms(&terms);\n \n \t/*\n \t * Handle early success\n-- \n2.38.1.157.gedabe22e0a\n\n"},{"id":"467054","messageId":"b67691f600d4a0bc800fda5c8d19e447c4a743e2.1668097286.git.congdanhqx@gmail.com","threadId":"58746","inReplyTo":"cover.1668097286.git.congdanhqx@gmail.com","subject":"[PATCH v3 3/3] bisect--helper: parse subcommand with OPT_SUBCOMMAND","fromName":"Đoàn Trần Công Danh","fromEmail":"congdanhqx@gmail.com","sentAt":"2022-11-10T16:36:22Z","receivedAt":"2022-11-10T16:36:52Z","isPatch":true,"sender":{"key":"congdanhqx@gmail.com","avatar":"https://avatars.githubusercontent.com/u/42673067?v=4"},"body":"As of it is, we're parsing subcommand with OPT_CMDMODE, which will\ncontinue to parse more options even if the command has been found.\n\nWhen we're running \"git bisect run\" with a command that expecting\na \"--log\" or \"--no-log\" arguments, or one of those \"--bisect-...\"\narguments, bisect--helper may mistakenly think those options are\nbisect--helper's option.\n\nWe may fix those problems by passing \"--\" when calling from\ngit-bisect.sh, and skip that \"--\" in bisect--helper. However, it may\ninterfere with user's \"--\".\n\nLet's parse subcommand with OPT_SUBCOMMAND since that API was born for\nthis specific use-case.\n\nReported-by: Lukáš Doktor <ldoktor@redhat.com>\nSigned-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>\n---\n builtin/bisect--helper.c    | 87 ++++++++-----------------------------\n git-bisect.sh               | 23 ++--------\n t/t6030-bisect-porcelain.sh | 10 +++++\n 3 files changed, 30 insertions(+), 90 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex d425555d1f..6e41cbdb2d 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1392,84 +1392,31 @@ static int cmd_bisect__run(int argc, const char **argv, const char *prefix UNUSE\n \n int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n {\n-\tenum {\n-\t\tBISECT_RESET = 1,\n-\t\tBISECT_TERMS,\n-\t\tBISECT_START,\n-\t\tBISECT_AUTOSTART,\n-\t\tBISECT_NEXT,\n-\t\tBISECT_STATE,\n-\t\tBISECT_LOG,\n-\t\tBISECT_REPLAY,\n-\t\tBISECT_SKIP,\n-\t\tBISECT_VISUALIZE,\n-\t\tBISECT_RUN,\n-\t} cmdmode = 0;\n \tint res = 0;\n+\tparse_opt_subcommand_fn *fn = NULL;\n \tstruct option options[] = {\n-\t\tOPT_CMDMODE(0, \"bisect-reset\", &cmdmode,\n-\t\t\t N_(\"reset the bisection state\"), BISECT_RESET),\n-\t\tOPT_CMDMODE(0, \"bisect-terms\", &cmdmode,\n-\t\t\t N_(\"print out the bisect terms\"), BISECT_TERMS),\n-\t\tOPT_CMDMODE(0, \"bisect-start\", &cmdmode,\n-\t\t\t N_(\"start the bisect session\"), BISECT_START),\n-\t\tOPT_CMDMODE(0, \"bisect-next\", &cmdmode,\n-\t\t\t N_(\"find the next bisection commit\"), BISECT_NEXT),\n-\t\tOPT_CMDMODE(0, \"bisect-state\", &cmdmode,\n-\t\t\t N_(\"mark the state of ref (or refs)\"), BISECT_STATE),\n-\t\tOPT_CMDMODE(0, \"bisect-log\", &cmdmode,\n-\t\t\t N_(\"list the bisection steps so far\"), BISECT_LOG),\n-\t\tOPT_CMDMODE(0, \"bisect-replay\", &cmdmode,\n-\t\t\t N_(\"replay the bisection process from the given file\"), BISECT_REPLAY),\n-\t\tOPT_CMDMODE(0, \"bisect-skip\", &cmdmode,\n-\t\t\t N_(\"skip some commits for checkout\"), BISECT_SKIP),\n-\t\tOPT_CMDMODE(0, \"bisect-visualize\", &cmdmode,\n-\t\t\t N_(\"visualize the bisection\"), BISECT_VISUALIZE),\n-\t\tOPT_CMDMODE(0, \"bisect-run\", &cmdmode,\n-\t\t\t N_(\"use <cmd>... to automatically bisect\"), BISECT_RUN),\n+\t\tOPT_SUBCOMMAND(\"reset\", &fn, cmd_bisect__reset),\n+\t\tOPT_SUBCOMMAND(\"terms\", &fn, cmd_bisect__terms),\n+\t\tOPT_SUBCOMMAND(\"start\", &fn, cmd_bisect__start),\n+\t\tOPT_SUBCOMMAND(\"next\", &fn, cmd_bisect__next),\n+\t\tOPT_SUBCOMMAND(\"state\", &fn, cmd_bisect__state),\n+\t\tOPT_SUBCOMMAND(\"log\", &fn, cmd_bisect__log),\n+\t\tOPT_SUBCOMMAND(\"replay\", &fn, cmd_bisect__replay),\n+\t\tOPT_SUBCOMMAND(\"skip\", &fn, cmd_bisect__skip),\n+\t\tOPT_SUBCOMMAND(\"visualize\", &fn, cmd_bisect__visualize),\n+\t\tOPT_SUBCOMMAND(\"view\", &fn, cmd_bisect__visualize),\n+\t\tOPT_SUBCOMMAND(\"run\", &fn, cmd_bisect__run),\n \t\tOPT_END()\n \t};\n \targc = parse_options(argc, argv, prefix, options,\n-\t\t\t     git_bisect_helper_usage,\n-\t\t\t     PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN_OPT);\n+\t\t\t     git_bisect_helper_usage, 0);\n \n-\tif (!cmdmode)\n+\tif (!fn)\n \t\tusage_with_options(git_bisect_helper_usage, options);\n+\targc--;\n+\targv++;\n \n-\tswitch (cmdmode) {\n-\tcase BISECT_RESET:\n-\t\tres = cmd_bisect__reset(argc, argv, prefix);\n-\t\tbreak;\n-\tcase BISECT_TERMS:\n-\t\tres = cmd_bisect__terms(argc, argv, prefix);\n-\t\tbreak;\n-\tcase BISECT_START:\n-\t\tres = cmd_bisect__start(argc, argv, prefix);\n-\t\tbreak;\n-\tcase BISECT_NEXT:\n-\t\tres = cmd_bisect__next(argc, argv, prefix);\n-\t\tbreak;\n-\tcase BISECT_STATE:\n-\t\tres = cmd_bisect__state(argc, argv, prefix);\n-\t\tbreak;\n-\tcase BISECT_LOG:\n-\t\tres = cmd_bisect__log(argc, argv, prefix);\n-\t\tbreak;\n-\tcase BISECT_REPLAY:\n-\t\tres = cmd_bisect__replay(argc, argv, prefix);\n-\t\tbreak;\n-\tcase BISECT_SKIP:\n-\t\tres = cmd_bisect__skip(argc, argv, prefix);\n-\t\tbreak;\n-\tcase BISECT_VISUALIZE:\n-\t\tres = cmd_bisect__visualize(argc, argv, prefix);\n-\t\tbreak;\n-\tcase BISECT_RUN:\n-\t\tres = cmd_bisect__run(argc, argv, prefix);\n-\t\tbreak;\n-\tdefault:\n-\t\tBUG(\"unknown subcommand %d\", cmdmode);\n-\t}\n+\tres = fn(argc, argv, prefix);\n \n \t/*\n \t * Handle early success\ndiff --git a/git-bisect.sh b/git-bisect.sh\nindex 405cf76f2a..dfce4b4f44 100755\n--- a/git-bisect.sh\n+++ b/git-bisect.sh\n@@ -57,28 +57,11 @@ case \"$#\" in\n \tcase \"$cmd\" in\n \thelp)\n \t\tgit bisect -h ;;\n-\tstart)\n-\t\tgit bisect--helper --bisect-start \"$@\" ;;\n \tbad|good|new|old|\"$TERM_BAD\"|\"$TERM_GOOD\")\n-\t\tgit bisect--helper --bisect-state \"$cmd\" \"$@\" ;;\n-\tskip)\n-\t\tgit bisect--helper --bisect-skip \"$@\" || exit;;\n-\tnext)\n-\t\t# Not sure we want \"next\" at the UI level anymore.\n-\t\tgit bisect--helper --bisect-next \"$@\" || exit ;;\n-\tvisualize|view)\n-\t\tgit bisect--helper --bisect-visualize \"$@\" || exit;;\n-\treset)\n-\t\tgit bisect--helper --bisect-reset \"$@\" ;;\n-\treplay)\n-\t\tgit bisect--helper --bisect-replay \"$@\" || exit;;\n+\t\tgit bisect--helper state \"$cmd\" \"$@\" ;;\n \tlog)\n-\t\tgit bisect--helper --bisect-log || exit ;;\n-\trun)\n-\t\tgit bisect--helper --bisect-run \"$@\" || exit;;\n-\tterms)\n-\t\tgit bisect--helper --bisect-terms \"$@\" || exit;;\n+\t\tgit bisect--helper log || exit ;;\n \t*)\n-\t\tusage ;;\n+\t\tgit bisect--helper \"$cmd\" \"$@\" ;;\n \tesac\n esac\ndiff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh\nindex 83931d482f..6dbbe62eb2 100755\n--- a/t/t6030-bisect-porcelain.sh\n+++ b/t/t6030-bisect-porcelain.sh\n@@ -266,6 +266,16 @@ test_expect_success '\"git bisect run\" simple case' '\n \tgit bisect reset\n '\n \n+# We want to make sure no arguments has been eaten\n+test_expect_success '\"git bisect run\" simple case' '\n+\tgit bisect start &&\n+\tgit bisect good $HASH1 &&\n+\tgit bisect bad $HASH4 &&\n+\tgit bisect run printf \"%s %s\\n\" reset --bisect-skip >my_bisect_log.txt &&\n+\tgrep -e \"reset --bisect-skip\" my_bisect_log.txt &&\n+\tgit bisect reset\n+'\n+\n # We want to automatically find the commit that\n # added \"Ciao\" into hello.\n test_expect_success '\"git bisect run\" with more complex \"git bisect start\"' '\n-- \n2.38.1.157.gedabe22e0a\n\n"},{"id":"467055","messageId":"d82c7eaabff114fab86459482ce1e5751a783497.1668097966.git.congdanhqx@gmail.com","threadId":"58746","inReplyTo":"cover.1668097962.git.congdanhqx@gmail.com","subject":"[PATCH v2 02/11] bisect: refactor bisect_run() to match CodingGuidelines","fromName":"Đoàn Trần Công Danh","fromEmail":"congdanhqx@gmail.com","sentAt":"2022-11-10T16:36:37Z","receivedAt":"2022-11-10T16:37:11Z","isPatch":true,"sender":{"key":"congdanhqx@gmail.com","avatar":"https://avatars.githubusercontent.com/u/42673067?v=4"},"body":"From: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n\nWe didn't add \"{}\" to all \"if/else\" branches, and one \"error\" was\nmis-indented. Let's fix that first, which makes subsequent commits\nsmaller. In the case of the \"if\" we can simply early return instead.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\nSigned-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>\n---\n builtin/bisect--helper.c | 7 +++----\n 1 file changed, 3 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 6e41cbdb2d..08d83e6867 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1191,13 +1191,12 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n \tif (bisect_next_check(terms, NULL))\n \t\treturn BISECT_FAILED;\n \n-\tif (argc)\n-\t\tsq_quote_argv(&command, argv);\n-\telse {\n+\tif (!argc) {\n \t\terror(_(\"bisect run failed: no command provided.\"));\n \t\treturn BISECT_FAILED;\n \t}\n \n+\tsq_quote_argv(&command, argv);\n \twhile (1) {\n \t\tres = do_bisect_run(command.buf);\n \n@@ -1268,7 +1267,7 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n \t\t\tres = BISECT_OK;\n \t\t} else if (res) {\n \t\t\terror(_(\"bisect run failed: 'git bisect--helper --bisect-state\"\n-\t\t\t\" %s' exited with error code %d\"), new_state, res);\n+\t\t\t\t\" %s' exited with error code %d\"), new_state, res);\n \t\t} else {\n \t\t\tcontinue;\n \t\t}\n-- \n2.38.1.157.gedabe22e0a\n\n"},{"id":"467056","messageId":"cover.1668097962.git.congdanhqx@gmail.com","threadId":"58746","inReplyTo":"cover.1668097286.git.congdanhqx@gmail.com","subject":"[PATCH v2 00/11] Turn git-bisect to be builtin","fromName":"Đoàn Trần Công Danh","fromEmail":"congdanhqx@gmail.com","sentAt":"2022-11-10T16:36:35Z","receivedAt":"2022-11-10T16:37:13Z","isPatch":true,"sender":{"key":"congdanhqx@gmail.com","avatar":"https://avatars.githubusercontent.com/u/42673067?v=4"},"body":"This series finish the git-bisect porting from shell script into a C builtin.\n\nThis series can't be applied cleaned on master, it needs to be applied on top\nof the series posted at:\nhttps://lore.kernel.org/git/cover.1668097286.git.congdanhqx@gmail.com/\nAND the series rs/no-more-run-command-v, which has been integrated to next.\n\nJohannes Schindelin (2):\n  bisect--helper: handle states directly\n  Turn `git bisect` into a full built-in\n\nÆvar Arnfjörð Bjarmason (4):\n  bisect tests: test for v2.30.0 \"bisect run\" regressions\n  bisect: refactor bisect_run() to match CodingGuidelines\n  bisect test: test exit codes on bad usage\n  bisect--helper: emit usage for \"git bisect\"\n\nĐoàn Trần Công Danh (5):\n  bisect: fix output regressions in v2.30.0\n  bisect run: keep some of the post-v2.30.0 output\n  bisect-run: verify_good: account for non-negative exit status\n  bisect--helper: identify as bisect when report error\n  bisect--helper: log: allow arbitrary number of arguments\n\n Makefile                               |   3 +-\n builtin.h                              |   2 +-\n builtin/{bisect--helper.c => bisect.c} | 126 ++++++++++++---------\n git-bisect.sh                          |   4 -\n git.c                                  |   2 +-\n t/t6030-bisect-porcelain.sh            | 148 +++++++++++++++++++++++++\n 6 files changed, 225 insertions(+), 60 deletions(-)\n rename builtin/{bisect--helper.c => bisect.c} (92%)\n\nRange-diff against v1:\n 1:  5571bc36b8 !  1:  b6fd4ecd66 bisect tests: test for v2.30.0 \"bisect run\" regressions\n    @@ Commit message\n         with 127. That edge case is a bit too insane to preserve, so let's not\n         add it to these regression tests.\n     \n    +    There was another regression that 'git bisect' consumed some options\n    +    that was meant to passed down to program run with 'git bisect run'.\n    +    Since that regression is breaking user's expectation, it has been fixed\n    +    earlier without this patch queued.\n    +\n         1. 0a4cb1f1f2f (Merge branch 'mr/bisect-in-c-4', 2021-09-23)\n         2. d1bbbe45df8 (bisect--helper: reimplement `bisect_run` shell\n            function in C, 2021-09-13)\n    @@ t/t6030-bisect-porcelain.sh: test_expect_success 'bisect skip: with commit both\n     +\ttest_cmp expect.args actual.args\n     +}\n     +\n    -+test_expect_failure 'git bisect run: args, stdout and stderr with no arguments' '\n    -+\ttest_bisect_run_args <<-\\EOF_ARGS 6<<-EOF_OUT 7<<-\\EOF_ERR\n    ++test_expect_failure 'git bisect run: args, stdout and stderr with no arguments' \"\n    ++\ttest_bisect_run_args <<-'EOF_ARGS' 6<<-EOF_OUT 7<<-'EOF_ERR'\n     +\tEOF_ARGS\n     +\trunning ./run.sh\n     +\t$HASH4 is the first bad commit\n     +\tbisect run success\n     +\tEOF_OUT\n     +\tEOF_ERR\n    -+'\n    ++\"\n     +\n    -+test_expect_failure 'git bisect run: args, stdout and stderr: \"--\" argument' '\n    -+\ttest_bisect_run_args -- <<-\\EOF_ARGS 6<<-EOF_OUT 7<<-\\EOF_ERR\n    ++test_expect_failure 'git bisect run: args, stdout and stderr: \"--\" argument' \"\n    ++\ttest_bisect_run_args -- <<-'EOF_ARGS' 6<<-EOF_OUT 7<<-'EOF_ERR'\n     +\t<-->\n     +\tEOF_ARGS\n     +\trunning ./run.sh --\n    @@ t/t6030-bisect-porcelain.sh: test_expect_success 'bisect skip: with commit both\n     +\tbisect run success\n     +\tEOF_OUT\n     +\tEOF_ERR\n    -+'\n    ++\"\n     +\n    -+test_expect_failure 'git bisect run: args, stdout and stderr: \"--log foo --no-log bar\" arguments' '\n    -+\ttest_bisect_run_args --log foo --no-log bar <<-\\EOF_ARGS 6<<-EOF_OUT 7<<-\\EOF_ERR\n    ++test_expect_failure 'git bisect run: args, stdout and stderr: \"--log foo --no-log bar\" arguments' \"\n    ++\ttest_bisect_run_args --log foo --no-log bar <<-'EOF_ARGS' 6<<-EOF_OUT 7<<-'EOF_ERR'\n     +\t<--log>\n     +\t<foo>\n     +\t<--no-log>\n    @@ t/t6030-bisect-porcelain.sh: test_expect_success 'bisect skip: with commit both\n     +\tbisect run success\n     +\tEOF_OUT\n     +\tEOF_ERR\n    -+'\n    ++\"\n     +\n    -+test_expect_failure 'git bisect run: args, stdout and stderr: \"--bisect-start\" argument' '\n    -+\ttest_bisect_run_args --bisect-start <<-\\EOF_ARGS 6<<-EOF_OUT 7<<-\\EOF_ERR\n    ++test_expect_failure 'git bisect run: args, stdout and stderr: \"--bisect-start\" argument' \"\n    ++\ttest_bisect_run_args --bisect-start <<-'EOF_ARGS' 6<<-EOF_OUT 7<<-'EOF_ERR'\n     +\t<--bisect-start>\n     +\tEOF_ARGS\n     +\trunning ./run.sh --bisect-start\n    @@ t/t6030-bisect-porcelain.sh: test_expect_success 'bisect skip: with commit both\n     +\tbisect run success\n     +\tEOF_OUT\n     +\tEOF_ERR\n    -+'\n    ++\"\n     +\n      # We want to automatically find the commit that\n      # added \"Another\" into hello.\n 2:  dc6ed4c453 =  2:  d82c7eaabf bisect: refactor bisect_run() to match CodingGuidelines\n 3:  8a815e2311 <  -:  ---------- bisect--helper: pass arg[cv] down to do_bisect_run\n 4:  31cd78f538 <  -:  ---------- bisect: fix output regressions in v2.30.0\n 5:  5ba3bafdd4 <  -:  ---------- bisect run: keep some of the post-v2.30.0 output\n 6:  32ad47ddc5 <  -:  ---------- bisect--helper: remove unused arguments from do_bisect_run\n -:  ---------- >  3:  912f32ceda bisect: fix output regressions in v2.30.0\n -:  ---------- >  4:  17bef3e951 bisect run: keep some of the post-v2.30.0 output\n -:  ---------- >  5:  d6c57af9cc bisect-run: verify_good: account for non-negative exit status\n 7:  f212e64288 !  6:  8039b010c8 bisect--helper: pretend we're real bisect when report error\n    @@ Metadata\n     Author: Đoàn Trần Công Danh <congdanhqx@gmail.com>\n     \n      ## Commit message ##\n    -    bisect--helper: pretend we're real bisect when report error\n    +    bisect--helper: identify as bisect when report error\n     \n         In a later change, we will convert the bisect--helper to be builtin\n    -    bisect. Let's start by pretending it's the real bisect when reporting\n    +    bisect. Let's start by self-identifying it's the real bisect when reporting\n         error.\n     \n    +    This change is safe since 'git bisect--helper' is an implementation\n    +    detail, users aren't expected to call 'git bisect--helper'.\n    +\n         Signed-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>\n     \n      ## builtin/bisect--helper.c ##\n    @@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, cons\n      }\n      \n     @@ builtin/bisect--helper.c: static int cmd_bisect__terms(int argc, const char **argv, const char *prefix UNU\n    - \tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\n    + \tstruct bisect_terms terms = { 0 };\n      \n      \tif (argc > 1)\n     -\t\treturn error(_(\"--bisect-terms requires 0 or 1 argument\"));\n    @@ builtin/bisect--helper.c: static int cmd_bisect__terms(int argc, const char **ar\n      \tfree_terms(&terms);\n      \treturn res;\n     @@ builtin/bisect--helper.c: static int cmd_bisect__next(int argc, const char **argv UNUSED, const char *pref\n    - \tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\n    + \tstruct bisect_terms terms = { 0 };\n      \n      \tif (argc)\n     -\t\treturn error(_(\"--bisect-next requires 0 arguments\"));\n    @@ builtin/bisect--helper.c: static int cmd_bisect__state(int argc, const char **ar\n      }\n      \n     @@ builtin/bisect--helper.c: static int cmd_bisect__run(int argc, const char **argv, const char *prefix UNUSE\n    - \tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\n    + \tstruct bisect_terms terms = { 0 };\n      \n      \tif (!argc)\n     -\t\treturn error(_(\"bisect run failed: no command provided.\"));\n 8:  4c1beb8bf8 =  7:  7c43abfcef bisect test: test exit codes on bad usage\n 9:  b494a4cf4e =  8:  4500867d56 bisect--helper: emit usage for \"git bisect\"\n10:  a53e0c61ca !  9:  3752c0348b bisect--helper: make `state` optional\n    @@ Metadata\n     Author: Johannes Schindelin <Johannes.Schindelin@gmx.de>\n     \n      ## Commit message ##\n    -    bisect--helper: make `state` optional\n    +    bisect--helper: handle states directly\n     \n         In preparation for making `git bisect` a real built-in, let's prepare\n         the `bisect--helper` built-in to handle `git bisect--helper good` and\n    -    `git bisect--helper bad`, i.e. do not require the `state` subcommand to\n    -    be passed explicitly.\n    +    `git bisect--helper bad`, i.e. eliminate the need of `state` subcommand.\n     \n         Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n      ## builtin/bisect--helper.c ##\n    +@@ builtin/bisect--helper.c: static int cmd_bisect__next(int argc, const char **argv UNUSED, const char *pref\n    + \treturn res;\n    + }\n    + \n    +-static int cmd_bisect__state(int argc, const char **argv, const char *prefix UNUSED)\n    +-{\n    +-\tint res;\n    +-\tstruct bisect_terms terms = { 0 };\n    +-\n    +-\tset_terms(&terms, \"bad\", \"good\");\n    +-\tget_terms(&terms);\n    +-\tres = bisect_state(&terms, argv, argc);\n    +-\tfree_terms(&terms);\n    +-\treturn res;\n    +-}\n    +-\n    + static int cmd_bisect__log(int argc, const char **argv UNUSED, const char *prefix UNUSED)\n    + {\n    + \tif (argc)\n    +@@ builtin/bisect--helper.c: int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n    + \t\tOPT_SUBCOMMAND(\"terms\", &fn, cmd_bisect__terms),\n    + \t\tOPT_SUBCOMMAND(\"start\", &fn, cmd_bisect__start),\n    + \t\tOPT_SUBCOMMAND(\"next\", &fn, cmd_bisect__next),\n    +-\t\tOPT_SUBCOMMAND(\"state\", &fn, cmd_bisect__state),\n    + \t\tOPT_SUBCOMMAND(\"log\", &fn, cmd_bisect__log),\n    + \t\tOPT_SUBCOMMAND(\"replay\", &fn, cmd_bisect__replay),\n    + \t\tOPT_SUBCOMMAND(\"skip\", &fn, cmd_bisect__skip),\n     @@ builtin/bisect--helper.c: int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n      \t\tOPT_SUBCOMMAND(\"run\", &fn, cmd_bisect__run),\n      \t\tOPT_END()\n11:  8037667da0 <  -:  ---------- bisect--helper: remove subcommand state\n12:  3b13350977 = 10:  de3075eff9 bisect--helper: log: allow arbitrary number of arguments\n13:  0441cf2554 = 11:  dadca7adbe Turn `git bisect` into a full built-in\n-- \n2.38.1.157.gedabe22e0a\n\n"},{"id":"467057","messageId":"b6fd4ecd66137710c76617aa05a16ad9cdd8ceb1.1668097965.git.congdanhqx@gmail.com","threadId":"58746","inReplyTo":"cover.1668097962.git.congdanhqx@gmail.com","subject":"[PATCH v2 01/11] bisect tests: test for v2.30.0 \"bisect run\" regressions","fromName":"Đoàn Trần Công Danh","fromEmail":"congdanhqx@gmail.com","sentAt":"2022-11-10T16:36:36Z","receivedAt":"2022-11-10T16:37:14Z","isPatch":true,"sender":{"key":"congdanhqx@gmail.com","avatar":"https://avatars.githubusercontent.com/u/42673067?v=4"},"body":"From: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n\nAdd three failing tests which succeed on v2.29.0, but due to the topic\nmerged at [1] (specifically [2]) have been failing since then. We'll\naddress those regressions in subsequent commits.\n\nThere was also a \"regression\" where:\n\n\tgit bisect run ./missing-script.sh\n\nWould count a non-existing script as \"good\", as the shell would exit\nwith 127. That edge case is a bit too insane to preserve, so let's not\nadd it to these regression tests.\n\nThere was another regression that 'git bisect' consumed some options\nthat was meant to passed down to program run with 'git bisect run'.\nSince that regression is breaking user's expectation, it has been fixed\nearlier without this patch queued.\n\n1. 0a4cb1f1f2f (Merge branch 'mr/bisect-in-c-4', 2021-09-23)\n2. d1bbbe45df8 (bisect--helper: reimplement `bisect_run` shell\n   function in C, 2021-09-13)\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\nSigned-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>\n---\n t/t6030-bisect-porcelain.sh | 79 +++++++++++++++++++++++++++++++++++++\n 1 file changed, 79 insertions(+)\n\ndiff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh\nindex 6dbbe62eb2..6c2c57cadf 100755\n--- a/t/t6030-bisect-porcelain.sh\n+++ b/t/t6030-bisect-porcelain.sh\n@@ -252,6 +252,85 @@ test_expect_success 'bisect skip: with commit both bad and skipped' '\n \tgrep $HASH4 my_bisect_log.txt\n '\n \n+test_bisect_run_args () {\n+\ttest_when_finished \"rm -f run.sh actual\" &&\n+\t>actual &&\n+\tcat >expect.args &&\n+\tcat <&6 >expect.out &&\n+\tcat <&7 >expect.err &&\n+\twrite_script run.sh <<-\\EOF &&\n+\twhile test $# != 0\n+\tdo\n+\t\techo \"<$1>\" &&\n+\t\tshift\n+\tdone >actual.args\n+\tEOF\n+\n+\ttest_when_finished \"git bisect reset\" &&\n+\tgit bisect start &&\n+\tgit bisect good $HASH1 &&\n+\tgit bisect bad $HASH4 &&\n+\tgit bisect run ./run.sh $@ >actual.out.raw 2>actual.err &&\n+\t# Prune just the log output\n+\tsed -n \\\n+\t\t-e '/^Author:/d' \\\n+\t\t-e '/^Date:/d' \\\n+\t\t-e '/^$/d' \\\n+\t\t-e '/^commit /d' \\\n+\t\t-e '/^ /d' \\\n+\t\t-e 'p' \\\n+\t\t<actual.out.raw >actual.out &&\n+\ttest_cmp expect.out actual.out &&\n+\ttest_cmp expect.err actual.err &&\n+\ttest_cmp expect.args actual.args\n+}\n+\n+test_expect_failure 'git bisect run: args, stdout and stderr with no arguments' \"\n+\ttest_bisect_run_args <<-'EOF_ARGS' 6<<-EOF_OUT 7<<-'EOF_ERR'\n+\tEOF_ARGS\n+\trunning ./run.sh\n+\t$HASH4 is the first bad commit\n+\tbisect run success\n+\tEOF_OUT\n+\tEOF_ERR\n+\"\n+\n+test_expect_failure 'git bisect run: args, stdout and stderr: \"--\" argument' \"\n+\ttest_bisect_run_args -- <<-'EOF_ARGS' 6<<-EOF_OUT 7<<-'EOF_ERR'\n+\t<-->\n+\tEOF_ARGS\n+\trunning ./run.sh --\n+\t$HASH4 is the first bad commit\n+\tbisect run success\n+\tEOF_OUT\n+\tEOF_ERR\n+\"\n+\n+test_expect_failure 'git bisect run: args, stdout and stderr: \"--log foo --no-log bar\" arguments' \"\n+\ttest_bisect_run_args --log foo --no-log bar <<-'EOF_ARGS' 6<<-EOF_OUT 7<<-'EOF_ERR'\n+\t<--log>\n+\t<foo>\n+\t<--no-log>\n+\t<bar>\n+\tEOF_ARGS\n+\trunning ./run.sh --log foo --no-log bar\n+\t$HASH4 is the first bad commit\n+\tbisect run success\n+\tEOF_OUT\n+\tEOF_ERR\n+\"\n+\n+test_expect_failure 'git bisect run: args, stdout and stderr: \"--bisect-start\" argument' \"\n+\ttest_bisect_run_args --bisect-start <<-'EOF_ARGS' 6<<-EOF_OUT 7<<-'EOF_ERR'\n+\t<--bisect-start>\n+\tEOF_ARGS\n+\trunning ./run.sh --bisect-start\n+\t$HASH4 is the first bad commit\n+\tbisect run success\n+\tEOF_OUT\n+\tEOF_ERR\n+\"\n+\n # We want to automatically find the commit that\n # added \"Another\" into hello.\n test_expect_success '\"git bisect run\" simple case' '\n-- \n2.38.1.157.gedabe22e0a\n\n"},{"id":"467058","messageId":"912f32cedaa7476fd83e306e075a2b63d41326c4.1668097966.git.congdanhqx@gmail.com","threadId":"58746","inReplyTo":"cover.1668097962.git.congdanhqx@gmail.com","subject":"[PATCH v2 03/11] bisect: fix output regressions in v2.30.0","fromName":"Đoàn Trần Công Danh","fromEmail":"congdanhqx@gmail.com","sentAt":"2022-11-10T16:36:38Z","receivedAt":"2022-11-10T16:37:17Z","isPatch":true,"sender":{"key":"congdanhqx@gmail.com","avatar":"https://avatars.githubusercontent.com/u/42673067?v=4"},"body":"When d1bbbe45df8 (bisect--helper: reimplement `bisect_run` shell\nfunction in C, 2021-09-13) reimplemented parts of \"git bisect run\" in\nC it changed the output we emitted so that:\n\n - The \"running ...\" line was now quoted\n - We lost the \\n after our output\n - We started saying \"bisect found ...\" instead of \"bisect run success\"\n\nArguably some of this is better now, but as d1bbbe45df8 did not\nadvocate for changing the output, let's revert this for now. It'll be\neasy to change it back if that's what we'd prefer.\n\nThis does not change the one remaining use of \"command.buf\" to emit\nthe quoted argument, as that's new in d1bbbe45df8.\n\nSome of these cases were not tested for in the tests added in the\npreceding commit, I didn't have time to fleshen those out, but a look\nat f1de981e8b6 will show that the other output being adjusted here is\nnow equivalent to what it was before d1bbbe45df8.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\nSigned-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>\n---\n builtin/bisect--helper.c    | 27 +++++++++++++++------------\n t/t6030-bisect-porcelain.sh |  8 ++++----\n 2 files changed, 19 insertions(+), 16 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 08d83e6867..05cab468e3 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1141,17 +1141,17 @@ static int get_first_good(const char *refname UNUSED,\n \treturn 1;\n }\n \n-static int do_bisect_run(const char *command)\n+static int do_bisect_run(const char *command, const char *unquoted_cmd)\n {\n \tstruct child_process cmd = CHILD_PROCESS_INIT;\n \n-\tprintf(_(\"running %s\\n\"), command);\n+\tprintf(_(\"running %s\\n\"), unquoted_cmd);\n \tcmd.use_shell = 1;\n \tstrvec_push(&cmd.args, command);\n \treturn run_command(&cmd);\n }\n \n-static int verify_good(const struct bisect_terms *terms, const char *command)\n+static int verify_good(const struct bisect_terms *terms, const char *command, const char *unquoted_cmd)\n {\n \tint rc;\n \tenum bisect_error res;\n@@ -1171,7 +1171,7 @@ static int verify_good(const struct bisect_terms *terms, const char *command)\n \tif (res != BISECT_OK)\n \t\treturn -1;\n \n-\trc = do_bisect_run(command);\n+\trc = do_bisect_run(command, unquoted_cmd);\n \n \tres = bisect_checkout(&current_rev, no_checkout);\n \tif (res != BISECT_OK)\n@@ -1184,6 +1184,7 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n {\n \tint res = BISECT_OK;\n \tstruct strbuf command = STRBUF_INIT;\n+\tstruct strbuf unquoted = STRBUF_INIT;\n \tconst char *new_state;\n \tint temporary_stdout_fd, saved_stdout;\n \tint is_first_run = 1;\n@@ -1197,8 +1198,9 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n \t}\n \n \tsq_quote_argv(&command, argv);\n+\tstrbuf_join_argv(&unquoted, argc, argv,' ');\n \twhile (1) {\n-\t\tres = do_bisect_run(command.buf);\n+\t\tres = do_bisect_run(command.buf, unquoted.buf);\n \n \t\t/*\n \t\t * Exit code 126 and 127 can either come from the shell\n@@ -1208,11 +1210,11 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n \t\t * missing or non-executable script.\n \t\t */\n \t\tif (is_first_run && (res == 126 || res == 127)) {\n-\t\t\tint rc = verify_good(terms, command.buf);\n+\t\t\tint rc = verify_good(terms, command.buf, unquoted.buf);\n \t\t\tis_first_run = 0;\n \t\t\tif (rc < 0) {\n \t\t\t\terror(_(\"unable to verify '%s' on good\"\n-\t\t\t\t\t\" revision\"), command.buf);\n+\t\t\t\t\t\" revision\"), unquoted.buf);\n \t\t\t\tres = BISECT_FAILED;\n \t\t\t\tbreak;\n \t\t\t}\n@@ -1226,7 +1228,7 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n \n \t\tif (res < 0 || 128 <= res) {\n \t\t\terror(_(\"bisect run failed: exit code %d from\"\n-\t\t\t\t\" '%s' is < 0 or >= 128\"), res, command.buf);\n+\t\t\t\t\" '%s' is < 0 or >= 128\"), res, unquoted.buf);\n \t\t\tbreak;\n \t\t}\n \n@@ -1260,20 +1262,21 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n \t\tif (res == BISECT_ONLY_SKIPPED_LEFT)\n \t\t\terror(_(\"bisect run cannot continue any more\"));\n \t\telse if (res == BISECT_INTERNAL_SUCCESS_MERGE_BASE) {\n-\t\t\tprintf(_(\"bisect run success\"));\n+\t\t\tputs(_(\"bisect run success\"));\n \t\t\tres = BISECT_OK;\n \t\t} else if (res == BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND) {\n-\t\t\tprintf(_(\"bisect found first bad commit\"));\n+\t\t\tputs(_(\"bisect run success\"));\n \t\t\tres = BISECT_OK;\n \t\t} else if (res) {\n-\t\t\terror(_(\"bisect run failed: 'git bisect--helper --bisect-state\"\n-\t\t\t\t\" %s' exited with error code %d\"), new_state, res);\n+\t\t\terror(_(\"bisect run failed: 'bisect-state %s'\"\n+\t\t\t\t\" exited with error code %d\"), new_state, res);\n \t\t} else {\n \t\t\tcontinue;\n \t\t}\n \t\tbreak;\n \t}\n \n+\tstrbuf_release(&unquoted);\n \tstrbuf_release(&command);\n \treturn res;\n }\ndiff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh\nindex 6c2c57cadf..a3dc5c8140 100755\n--- a/t/t6030-bisect-porcelain.sh\n+++ b/t/t6030-bisect-porcelain.sh\n@@ -285,7 +285,7 @@ test_bisect_run_args () {\n \ttest_cmp expect.args actual.args\n }\n \n-test_expect_failure 'git bisect run: args, stdout and stderr with no arguments' \"\n+test_expect_success 'git bisect run: args, stdout and stderr with no arguments' \"\n \ttest_bisect_run_args <<-'EOF_ARGS' 6<<-EOF_OUT 7<<-'EOF_ERR'\n \tEOF_ARGS\n \trunning ./run.sh\n@@ -295,7 +295,7 @@ test_expect_failure 'git bisect run: args, stdout and stderr with no arguments'\n \tEOF_ERR\n \"\n \n-test_expect_failure 'git bisect run: args, stdout and stderr: \"--\" argument' \"\n+test_expect_success 'git bisect run: args, stdout and stderr: \"--\" argument' \"\n \ttest_bisect_run_args -- <<-'EOF_ARGS' 6<<-EOF_OUT 7<<-'EOF_ERR'\n \t<-->\n \tEOF_ARGS\n@@ -306,7 +306,7 @@ test_expect_failure 'git bisect run: args, stdout and stderr: \"--\" argument' \"\n \tEOF_ERR\n \"\n \n-test_expect_failure 'git bisect run: args, stdout and stderr: \"--log foo --no-log bar\" arguments' \"\n+test_expect_success 'git bisect run: args, stdout and stderr: \"--log foo --no-log bar\" arguments' \"\n \ttest_bisect_run_args --log foo --no-log bar <<-'EOF_ARGS' 6<<-EOF_OUT 7<<-'EOF_ERR'\n \t<--log>\n \t<foo>\n@@ -320,7 +320,7 @@ test_expect_failure 'git bisect run: args, stdout and stderr: \"--log foo --no-lo\n \tEOF_ERR\n \"\n \n-test_expect_failure 'git bisect run: args, stdout and stderr: \"--bisect-start\" argument' \"\n+test_expect_success 'git bisect run: args, stdout and stderr: \"--bisect-start\" argument' \"\n \ttest_bisect_run_args --bisect-start <<-'EOF_ARGS' 6<<-EOF_OUT 7<<-'EOF_ERR'\n \t<--bisect-start>\n \tEOF_ARGS\n-- \n2.38.1.157.gedabe22e0a\n\n"},{"id":"467059","messageId":"17bef3e951cfe3c7cc226819abb3695887d6a686.1668097966.git.congdanhqx@gmail.com","threadId":"58746","inReplyTo":"cover.1668097962.git.congdanhqx@gmail.com","subject":"[PATCH v2 04/11] bisect run: keep some of the post-v2.30.0 output","fromName":"Đoàn Trần Công Danh","fromEmail":"congdanhqx@gmail.com","sentAt":"2022-11-10T16:36:39Z","receivedAt":"2022-11-10T16:37:23Z","isPatch":true,"sender":{"key":"congdanhqx@gmail.com","avatar":"https://avatars.githubusercontent.com/u/42673067?v=4"},"body":"Preceding commits fixed output and behavior regressions in\nd1bbbe45df8 (bisect--helper: reimplement `bisect_run` shell function\nin C, 2021-09-13), which did not claim to be changing the output of\n\"git bisect run\".\n\nBut some of the output it emitted was subjectively better, so once\nwe've asserted that we're back on v2.29.0 behavior, let's change some\nof it back:\n\n- We now quote the arguments again, but omit the first \" \" when\n  printing the \"running\" line.\n- Ditto for other cases where we emitted the argument\n- We say \"found first bad commit\" again, not just \"run success\"\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\nBased-on-patch-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\nSigned-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>\n---\n builtin/bisect--helper.c    | 24 ++++++++--------\n t/t6030-bisect-porcelain.sh | 55 +++++++++++++++++++++++++++++++------\n 2 files changed, 58 insertions(+), 21 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 05cab468e3..180c2faa7f 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1141,17 +1141,17 @@ static int get_first_good(const char *refname UNUSED,\n \treturn 1;\n }\n \n-static int do_bisect_run(const char *command, const char *unquoted_cmd)\n+static int do_bisect_run(const char *command)\n {\n \tstruct child_process cmd = CHILD_PROCESS_INIT;\n \n-\tprintf(_(\"running %s\\n\"), unquoted_cmd);\n+\tprintf(_(\"running %s\\n\"), command);\n \tcmd.use_shell = 1;\n \tstrvec_push(&cmd.args, command);\n \treturn run_command(&cmd);\n }\n \n-static int verify_good(const struct bisect_terms *terms, const char *command, const char *unquoted_cmd)\n+static int verify_good(const struct bisect_terms *terms, const char *command)\n {\n \tint rc;\n \tenum bisect_error res;\n@@ -1171,7 +1171,7 @@ static int verify_good(const struct bisect_terms *terms, const char *command, co\n \tif (res != BISECT_OK)\n \t\treturn -1;\n \n-\trc = do_bisect_run(command, unquoted_cmd);\n+\trc = do_bisect_run(command);\n \n \tres = bisect_checkout(&current_rev, no_checkout);\n \tif (res != BISECT_OK)\n@@ -1184,7 +1184,6 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n {\n \tint res = BISECT_OK;\n \tstruct strbuf command = STRBUF_INIT;\n-\tstruct strbuf unquoted = STRBUF_INIT;\n \tconst char *new_state;\n \tint temporary_stdout_fd, saved_stdout;\n \tint is_first_run = 1;\n@@ -1198,9 +1197,9 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n \t}\n \n \tsq_quote_argv(&command, argv);\n-\tstrbuf_join_argv(&unquoted, argc, argv,' ');\n+\tstrbuf_ltrim(&command);\n \twhile (1) {\n-\t\tres = do_bisect_run(command.buf, unquoted.buf);\n+\t\tres = do_bisect_run(command.buf);\n \n \t\t/*\n \t\t * Exit code 126 and 127 can either come from the shell\n@@ -1210,11 +1209,11 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n \t\t * missing or non-executable script.\n \t\t */\n \t\tif (is_first_run && (res == 126 || res == 127)) {\n-\t\t\tint rc = verify_good(terms, command.buf, unquoted.buf);\n+\t\t\tint rc = verify_good(terms, command.buf);\n \t\t\tis_first_run = 0;\n \t\t\tif (rc < 0) {\n-\t\t\t\terror(_(\"unable to verify '%s' on good\"\n-\t\t\t\t\t\" revision\"), unquoted.buf);\n+\t\t\t\terror(_(\"unable to verify %s on good\"\n+\t\t\t\t\t\" revision\"), command.buf);\n \t\t\t\tres = BISECT_FAILED;\n \t\t\t\tbreak;\n \t\t\t}\n@@ -1228,7 +1227,7 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n \n \t\tif (res < 0 || 128 <= res) {\n \t\t\terror(_(\"bisect run failed: exit code %d from\"\n-\t\t\t\t\" '%s' is < 0 or >= 128\"), res, unquoted.buf);\n+\t\t\t\t\" %s is < 0 or >= 128\"), res, command.buf);\n \t\t\tbreak;\n \t\t}\n \n@@ -1265,7 +1264,7 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n \t\t\tputs(_(\"bisect run success\"));\n \t\t\tres = BISECT_OK;\n \t\t} else if (res == BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND) {\n-\t\t\tputs(_(\"bisect run success\"));\n+\t\t\tputs(_(\"bisect found first bad commit\"));\n \t\t\tres = BISECT_OK;\n \t\t} else if (res) {\n \t\t\terror(_(\"bisect run failed: 'bisect-state %s'\"\n@@ -1276,7 +1275,6 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n \t\tbreak;\n \t}\n \n-\tstrbuf_release(&unquoted);\n \tstrbuf_release(&command);\n \treturn res;\n }\ndiff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh\nindex a3dc5c8140..34fd45a48e 100755\n--- a/t/t6030-bisect-porcelain.sh\n+++ b/t/t6030-bisect-porcelain.sh\n@@ -288,9 +288,9 @@ test_bisect_run_args () {\n test_expect_success 'git bisect run: args, stdout and stderr with no arguments' \"\n \ttest_bisect_run_args <<-'EOF_ARGS' 6<<-EOF_OUT 7<<-'EOF_ERR'\n \tEOF_ARGS\n-\trunning ./run.sh\n+\trunning './run.sh'\n \t$HASH4 is the first bad commit\n-\tbisect run success\n+\tbisect found first bad commit\n \tEOF_OUT\n \tEOF_ERR\n \"\n@@ -299,9 +299,9 @@ test_expect_success 'git bisect run: args, stdout and stderr: \"--\" argument' \"\n \ttest_bisect_run_args -- <<-'EOF_ARGS' 6<<-EOF_OUT 7<<-'EOF_ERR'\n \t<-->\n \tEOF_ARGS\n-\trunning ./run.sh --\n+\trunning './run.sh' '--'\n \t$HASH4 is the first bad commit\n-\tbisect run success\n+\tbisect found first bad commit\n \tEOF_OUT\n \tEOF_ERR\n \"\n@@ -313,9 +313,9 @@ test_expect_success 'git bisect run: args, stdout and stderr: \"--log foo --no-lo\n \t<--no-log>\n \t<bar>\n \tEOF_ARGS\n-\trunning ./run.sh --log foo --no-log bar\n+\trunning './run.sh' '--log' 'foo' '--no-log' 'bar'\n \t$HASH4 is the first bad commit\n-\tbisect run success\n+\tbisect found first bad commit\n \tEOF_OUT\n \tEOF_ERR\n \"\n@@ -324,13 +324,52 @@ test_expect_success 'git bisect run: args, stdout and stderr: \"--bisect-start\" a\n \ttest_bisect_run_args --bisect-start <<-'EOF_ARGS' 6<<-EOF_OUT 7<<-'EOF_ERR'\n \t<--bisect-start>\n \tEOF_ARGS\n-\trunning ./run.sh --bisect-start\n+\trunning './run.sh' '--bisect-start'\n \t$HASH4 is the first bad commit\n-\tbisect run success\n+\tbisect found first bad commit\n \tEOF_OUT\n \tEOF_ERR\n \"\n \n+test_expect_success 'git bisect run: negative exit code' \"\n+\twrite_script fail.sh <<-'EOF' &&\n+\texit 255\n+\tEOF\n+\tcat <<-'EOF' >expect &&\n+\tbisect run failed: exit code -1 from './fail.sh' is < 0 or >= 128\n+\tEOF\n+\ttest_when_finished 'git bisect reset' &&\n+\tgit bisect start &&\n+\tgit bisect good $HASH1 &&\n+\tgit bisect bad $HASH4 &&\n+\t! git bisect run ./fail.sh 2>err &&\n+\tsed -En 's/.*(bisect.*code) (-?[0-9]+) (from.*)/\\1 -1 \\3/p' err >actual &&\n+\ttest_cmp expect actual\n+\"\n+\n+test_expect_failure 'git bisect run: unable to verify on good' \"\n+\twrite_script fail.sh <<-'EOF' &&\n+\thead=\\$(git rev-parse --verify HEAD)\n+\tgood=\\$(git rev-parse --verify $HASH1)\n+\tif test \"\\$head\" = \"\\$good\"\n+\tthen\n+\t\texit 255\n+\telse\n+\t\texit 127\n+\tfi\n+\tEOF\n+\tcat <<-'EOF' >expect &&\n+\tunable to verify './fail.sh' on good revision\n+\tEOF\n+\ttest_when_finished 'git bisect reset' &&\n+\tgit bisect start &&\n+\tgit bisect good $HASH1 &&\n+\tgit bisect bad $HASH4 &&\n+\t! git bisect run ./fail.sh 2>err &&\n+\tsed -n 's/.*\\(unable to verify.*\\)/\\1/p' err >actual &&\n+\ttest_cmp expect actual\n+\"\n+\n # We want to automatically find the commit that\n # added \"Another\" into hello.\n test_expect_success '\"git bisect run\" simple case' '\n-- \n2.38.1.157.gedabe22e0a\n\n"},{"id":"467060","messageId":"d6c57af9cc12eb64a71e2effcdb4585952ccb3aa.1668097966.git.congdanhqx@gmail.com","threadId":"58746","inReplyTo":"cover.1668097962.git.congdanhqx@gmail.com","subject":"[PATCH v2 05/11] bisect-run: verify_good: account for non-negative exit status","fromName":"Đoàn Trần Công Danh","fromEmail":"congdanhqx@gmail.com","sentAt":"2022-11-10T16:36:40Z","receivedAt":"2022-11-10T16:37:37Z","isPatch":true,"sender":{"key":"congdanhqx@gmail.com","avatar":"https://avatars.githubusercontent.com/u/42673067?v=4"},"body":"Some system never reports negative exit code at all, they reports them\nas bigger-than-128 instead.  We take extra care for those systems in the\nlater check for normal 'do_bisect_run' loop.\n\nLet's check it here, too.\n\nSigned-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>\n---\n builtin/bisect--helper.c    | 2 +-\n t/t6030-bisect-porcelain.sh | 2 +-\n 2 files changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 180c2faa7f..e214190599 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1211,7 +1211,7 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n \t\tif (is_first_run && (res == 126 || res == 127)) {\n \t\t\tint rc = verify_good(terms, command.buf);\n \t\t\tis_first_run = 0;\n-\t\t\tif (rc < 0) {\n+\t\t\tif (rc < 0 || 128 <= rc) {\n \t\t\t\terror(_(\"unable to verify %s on good\"\n \t\t\t\t\t\" revision\"), command.buf);\n \t\t\t\tres = BISECT_FAILED;\ndiff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh\nindex 34fd45a48e..03d99b22f1 100755\n--- a/t/t6030-bisect-porcelain.sh\n+++ b/t/t6030-bisect-porcelain.sh\n@@ -347,7 +347,7 @@ test_expect_success 'git bisect run: negative exit code' \"\n \ttest_cmp expect actual\n \"\n \n-test_expect_failure 'git bisect run: unable to verify on good' \"\n+test_expect_success 'git bisect run: unable to verify on good' \"\n \twrite_script fail.sh <<-'EOF' &&\n \thead=\\$(git rev-parse --verify HEAD)\n \tgood=\\$(git rev-parse --verify $HASH1)\n-- \n2.38.1.157.gedabe22e0a\n\n"},{"id":"467061","messageId":"8039b010c88d35897b3e6eb6ac18672bc5a8f968.1668097966.git.congdanhqx@gmail.com","threadId":"58746","inReplyTo":"cover.1668097962.git.congdanhqx@gmail.com","subject":"[PATCH v2 06/11] bisect--helper: identify as bisect when report error","fromName":"Đoàn Trần Công Danh","fromEmail":"congdanhqx@gmail.com","sentAt":"2022-11-10T16:36:41Z","receivedAt":"2022-11-10T16:37:41Z","isPatch":true,"sender":{"key":"congdanhqx@gmail.com","avatar":"https://avatars.githubusercontent.com/u/42673067?v=4"},"body":"In a later change, we will convert the bisect--helper to be builtin\nbisect. Let's start by self-identifying it's the real bisect when reporting\nerror.\n\nThis change is safe since 'git bisect--helper' is an implementation\ndetail, users aren't expected to call 'git bisect--helper'.\n\nSigned-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>\n---\n builtin/bisect--helper.c | 13 ++++++++-----\n 1 file changed, 8 insertions(+), 5 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex e214190599..f28bedac6a 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1282,7 +1282,8 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n static int cmd_bisect__reset(int argc, const char **argv, const char *prefix UNUSED)\n {\n \tif (argc > 1)\n-\t\treturn error(_(\"--bisect-reset requires either no argument or a commit\"));\n+\t\treturn error(_(\"'%s' requires either no argument or a commit\"),\n+\t\t\t     \"git bisect reset\");\n \treturn bisect_reset(argc ? argv[0] : NULL);\n }\n \n@@ -1292,7 +1293,8 @@ static int cmd_bisect__terms(int argc, const char **argv, const char *prefix UNU\n \tstruct bisect_terms terms = { 0 };\n \n \tif (argc > 1)\n-\t\treturn error(_(\"--bisect-terms requires 0 or 1 argument\"));\n+\t\treturn error(_(\"'%s' requires 0 or 1 argument\"),\n+\t\t\t     \"git bisect terms\");\n \tres = bisect_terms(&terms, argc == 1 ? argv[0] : NULL);\n \tfree_terms(&terms);\n \treturn res;\n@@ -1315,7 +1317,8 @@ static int cmd_bisect__next(int argc, const char **argv UNUSED, const char *pref\n \tstruct bisect_terms terms = { 0 };\n \n \tif (argc)\n-\t\treturn error(_(\"--bisect-next requires 0 arguments\"));\n+\t\treturn error(_(\"'%s' requires 0 arguments\"),\n+\t\t\t     \"git bisect next\");\n \tget_terms(&terms);\n \tres = bisect_next(&terms, prefix);\n \tfree_terms(&terms);\n@@ -1337,7 +1340,7 @@ static int cmd_bisect__state(int argc, const char **argv, const char *prefix UNU\n static int cmd_bisect__log(int argc, const char **argv UNUSED, const char *prefix UNUSED)\n {\n \tif (argc)\n-\t\treturn error(_(\"--bisect-log requires 0 arguments\"));\n+\t\treturn error(_(\"'%s' requires 0 arguments\"), \"git bisect log\");\n \treturn bisect_log();\n }\n \n@@ -1383,7 +1386,7 @@ static int cmd_bisect__run(int argc, const char **argv, const char *prefix UNUSE\n \tstruct bisect_terms terms = { 0 };\n \n \tif (!argc)\n-\t\treturn error(_(\"bisect run failed: no command provided.\"));\n+\t\treturn error(_(\"'%s' failed: no command provided.\"), \"git bisect run\");\n \tget_terms(&terms);\n \tres = bisect_run(&terms, argv, argc);\n \tfree_terms(&terms);\n-- \n2.38.1.157.gedabe22e0a\n\n"},{"id":"467062","messageId":"7c43abfcefc6bf6e6e667ba86ef81a5bd1cb10a5.1668097966.git.congdanhqx@gmail.com","threadId":"58746","inReplyTo":"cover.1668097962.git.congdanhqx@gmail.com","subject":"[PATCH v2 07/11] bisect test: test exit codes on bad usage","fromName":"Đoàn Trần Công Danh","fromEmail":"congdanhqx@gmail.com","sentAt":"2022-11-10T16:36:42Z","receivedAt":"2022-11-10T16:37:48Z","isPatch":true,"sender":{"key":"congdanhqx@gmail.com","avatar":"https://avatars.githubusercontent.com/u/42673067?v=4"},"body":"From: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n\nAddress a test blindspot, the \"log\" command is the odd one out because\n\"git-bisect.sh\" ignores any arguments it receives. Let's test both the\nexit codes we expect, and the stderr and stdout we're emitting.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\nSigned-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>\n---\n t/t6030-bisect-porcelain.sh | 30 ++++++++++++++++++++++++++++++\n 1 file changed, 30 insertions(+)\n\ndiff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh\nindex 03d99b22f1..98a72ff78a 100755\n--- a/t/t6030-bisect-porcelain.sh\n+++ b/t/t6030-bisect-porcelain.sh\n@@ -34,6 +34,36 @@ HASH2=\n HASH3=\n HASH4=\n \n+test_bisect_usage () {\n+\tlocal code=\"$1\" &&\n+\tshift &&\n+\tcat >expect &&\n+\ttest_expect_code $code \"$@\" >out 2>actual &&\n+\ttest_must_be_empty out &&\n+\ttest_cmp expect actual\n+}\n+\n+test_expect_success 'bisect usage' \"\n+\ttest_bisect_usage 1 git bisect reset extra1 extra2 <<-\\EOF &&\n+\terror: 'git bisect reset' requires either no argument or a commit\n+\tEOF\n+\ttest_bisect_usage 1 git bisect terms extra1 extra2 <<-\\EOF &&\n+\terror: 'git bisect terms' requires 0 or 1 argument\n+\tEOF\n+\ttest_bisect_usage 1 git bisect next extra1 <<-\\EOF &&\n+\terror: 'git bisect next' requires 0 arguments\n+\tEOF\n+\ttest_bisect_usage 1 git bisect log extra1 <<-\\EOF &&\n+\terror: We are not bisecting.\n+\tEOF\n+\ttest_bisect_usage 1 git bisect replay <<-\\EOF &&\n+\terror: no logfile given\n+\tEOF\n+\ttest_bisect_usage 1 git bisect run <<-\\EOF\n+\terror: 'git bisect run' failed: no command provided.\n+\tEOF\n+\"\n+\n test_expect_success 'set up basic repo with 1 file (hello) and 4 commits' '\n      add_line_into_file \"1: Hello World\" hello &&\n      HASH1=$(git rev-parse --verify HEAD) &&\n-- \n2.38.1.157.gedabe22e0a\n\n"},{"id":"467063","messageId":"4500867d56d688a5b799ca25bb935bc3ec1f6c6d.1668097966.git.congdanhqx@gmail.com","threadId":"58746","inReplyTo":"cover.1668097962.git.congdanhqx@gmail.com","subject":"[PATCH v2 08/11] bisect--helper: emit usage for \"git bisect\"","fromName":"Đoàn Trần Công Danh","fromEmail":"congdanhqx@gmail.com","sentAt":"2022-11-10T16:36:43Z","receivedAt":"2022-11-10T16:37:51Z","isPatch":true,"sender":{"key":"congdanhqx@gmail.com","avatar":"https://avatars.githubusercontent.com/u/42673067?v=4"},"body":"From: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n\nIn subsequent commits we'll be removing \"git-bisect.sh\" in favor of\npromoting \"bisect--helper\" to a \"bisect\" built-in.\n\nIn doing that we'll first need to have it support \"git bisect--helper\n<cmd>\" rather than \"git bisect--helper --<cmd>\", and then finally have\nits \"-h\" output claim to be \"bisect\" rather than \"bisect--helper\".\n\nInstead of suffering that churn let's start claiming to be \"git\nbisect\" now. In just a few commits this will be true, and in the\nmeantime emitting the \"wrong\" usage information from the helper is a\nsmall price to pay to avoid the churn.\n\nLet's also declare \"BUILTIN_*\" macros, when we eventually migrate the\nsub-commands themselves to parse_options() we'll be able to re-use the\nstrings. See 0afd556b2e1 (worktree: define subcommand -h in terms of\ncommand -h, 2022-10-13) for a recent example.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\nSigned-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>\n---\n builtin/bisect--helper.c | 51 ++++++++++++++++++++++++++++------------\n 1 file changed, 36 insertions(+), 15 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex f28bedac6a..1ff2d4ea3f 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -20,18 +20,40 @@ static GIT_PATH_FUNC(git_path_bisect_names, \"BISECT_NAMES\")\n static GIT_PATH_FUNC(git_path_bisect_first_parent, \"BISECT_FIRST_PARENT\")\n static GIT_PATH_FUNC(git_path_bisect_run, \"BISECT_RUN\")\n \n-static const char * const git_bisect_helper_usage[] = {\n-\tN_(\"git bisect--helper --bisect-reset [<commit>]\"),\n-\t\"git bisect--helper --bisect-terms [--term-good | --term-old | --term-bad | --term-new]\",\n-\tN_(\"git bisect--helper --bisect-start [--term-{new,bad}=<term> --term-{old,good}=<term>]\"\n-\t\t\t\t\t    \" [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<paths>...]\"),\n-\t\"git bisect--helper --bisect-next\",\n-\tN_(\"git bisect--helper --bisect-state (bad|new) [<rev>]\"),\n-\tN_(\"git bisect--helper --bisect-state (good|old) [<rev>...]\"),\n-\tN_(\"git bisect--helper --bisect-replay <filename>\"),\n-\tN_(\"git bisect--helper --bisect-skip [(<rev>|<range>)...]\"),\n-\t\"git bisect--helper --bisect-visualize\",\n-\tN_(\"git bisect--helper --bisect-run <cmd>...\"),\n+#define BUILTIN_GIT_BISECT_START_USAGE \\\n+\tN_(\"git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>]\" \\\n+\t   \"    [--no-checkout] [--first-parent] [<bad> [<good>...]] [--]\" \\\n+\t   \"    [<pathspec>...]\")\n+#define BUILTIN_GIT_BISECT_STATE_USAGE \\\n+\tN_(\"git bisect (good|bad) [<rev>...]\")\n+#define BUILTIN_GIT_BISECT_TERMS_USAGE \\\n+\t\"git bisect terms [--term-good | --term-bad]\"\n+#define BUILTIN_GIT_BISECT_SKIP_USAGE \\\n+\tN_(\"git bisect skip [(<rev>|<range>)...]\")\n+#define BUILTIN_GIT_BISECT_NEXT_USAGE \\\n+\t\"git bisect next\"\n+#define BUILTIN_GIT_BISECT_RESET_USAGE \\\n+\tN_(\"git bisect reset [<commit>]\")\n+#define BUILTIN_GIT_BISECT_VISUALIZE_USAGE \\\n+\t\"git bisect visualize\"\n+#define BUILTIN_GIT_BISECT_REPLAY_USAGE \\\n+\tN_(\"git bisect replay <logfile>\")\n+#define BUILTIN_GIT_BISECT_LOG_USAGE \\\n+\t\"git bisect log\"\n+#define BUILTIN_GIT_BISECT_RUN_USAGE \\\n+\tN_(\"git bisect run <cmd>...\")\n+\n+static const char * const git_bisect_usage[] = {\n+\tBUILTIN_GIT_BISECT_START_USAGE,\n+\tBUILTIN_GIT_BISECT_STATE_USAGE,\n+\tBUILTIN_GIT_BISECT_TERMS_USAGE,\n+\tBUILTIN_GIT_BISECT_SKIP_USAGE,\n+\tBUILTIN_GIT_BISECT_NEXT_USAGE,\n+\tBUILTIN_GIT_BISECT_RESET_USAGE,\n+\tBUILTIN_GIT_BISECT_VISUALIZE_USAGE,\n+\tBUILTIN_GIT_BISECT_REPLAY_USAGE,\n+\tBUILTIN_GIT_BISECT_LOG_USAGE,\n+\tBUILTIN_GIT_BISECT_RUN_USAGE,\n \tNULL\n };\n \n@@ -1411,11 +1433,10 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\tOPT_SUBCOMMAND(\"run\", &fn, cmd_bisect__run),\n \t\tOPT_END()\n \t};\n-\targc = parse_options(argc, argv, prefix, options,\n-\t\t\t     git_bisect_helper_usage, 0);\n+\targc = parse_options(argc, argv, prefix, options, git_bisect_usage, 0);\n \n \tif (!fn)\n-\t\tusage_with_options(git_bisect_helper_usage, options);\n+\t\tusage_with_options(git_bisect_usage, options);\n \targc--;\n \targv++;\n \n-- \n2.38.1.157.gedabe22e0a\n\n"},{"id":"467064","messageId":"3752c0348b251e066729782729704c91486ed6c5.1668097966.git.congdanhqx@gmail.com","threadId":"58746","inReplyTo":"cover.1668097962.git.congdanhqx@gmail.com","subject":"[PATCH v2 09/11] bisect--helper: handle states directly","fromName":"Đoàn Trần Công Danh","fromEmail":"congdanhqx@gmail.com","sentAt":"2022-11-10T16:36:44Z","receivedAt":"2022-11-10T16:37:53Z","isPatch":true,"sender":{"key":"congdanhqx@gmail.com","avatar":"https://avatars.githubusercontent.com/u/42673067?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nIn preparation for making `git bisect` a real built-in, let's prepare\nthe `bisect--helper` built-in to handle `git bisect--helper good` and\n`git bisect--helper bad`, i.e. eliminate the need of `state` subcommand.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\nSigned-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>\n---\n builtin/bisect--helper.c | 42 ++++++++++++++++++++--------------------\n git-bisect.sh            |  2 --\n 2 files changed, 21 insertions(+), 23 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 1ff2d4ea3f..29d5a26c64 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1347,18 +1347,6 @@ static int cmd_bisect__next(int argc, const char **argv UNUSED, const char *pref\n \treturn res;\n }\n \n-static int cmd_bisect__state(int argc, const char **argv, const char *prefix UNUSED)\n-{\n-\tint res;\n-\tstruct bisect_terms terms = { 0 };\n-\n-\tset_terms(&terms, \"bad\", \"good\");\n-\tget_terms(&terms);\n-\tres = bisect_state(&terms, argv, argc);\n-\tfree_terms(&terms);\n-\treturn res;\n-}\n-\n static int cmd_bisect__log(int argc, const char **argv UNUSED, const char *prefix UNUSED)\n {\n \tif (argc)\n@@ -1424,7 +1412,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\tOPT_SUBCOMMAND(\"terms\", &fn, cmd_bisect__terms),\n \t\tOPT_SUBCOMMAND(\"start\", &fn, cmd_bisect__start),\n \t\tOPT_SUBCOMMAND(\"next\", &fn, cmd_bisect__next),\n-\t\tOPT_SUBCOMMAND(\"state\", &fn, cmd_bisect__state),\n \t\tOPT_SUBCOMMAND(\"log\", &fn, cmd_bisect__log),\n \t\tOPT_SUBCOMMAND(\"replay\", &fn, cmd_bisect__replay),\n \t\tOPT_SUBCOMMAND(\"skip\", &fn, cmd_bisect__skip),\n@@ -1433,14 +1420,27 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\tOPT_SUBCOMMAND(\"run\", &fn, cmd_bisect__run),\n \t\tOPT_END()\n \t};\n-\targc = parse_options(argc, argv, prefix, options, git_bisect_usage, 0);\n-\n-\tif (!fn)\n-\t\tusage_with_options(git_bisect_usage, options);\n-\targc--;\n-\targv++;\n-\n-\tres = fn(argc, argv, prefix);\n+\targc = parse_options(argc, argv, prefix, options, git_bisect_usage,\n+\t\t\t     PARSE_OPT_SUBCOMMAND_OPTIONAL);\n+\n+\tif (!fn) {\n+\t\tstruct bisect_terms terms = { 0 };\n+\n+\t\tif (!argc)\n+\t\t\tusage_msg_opt(_(\"need a command\"), git_bisect_usage, options);\n+\n+\t\tset_terms(&terms, \"bad\", \"good\");\n+\t\tget_terms(&terms);\n+\t\tif (check_and_set_terms(&terms, argv[0]))\n+\t\t\tusage_msg_optf(_(\"unknown command: '%s'\"), git_bisect_usage,\n+\t\t\t\t       options, argv[0]);\n+\t\tres = bisect_state(&terms, argv, argc);\n+\t\tfree_terms(&terms);\n+\t} else {\n+\t\targc--;\n+\t\targv++;\n+\t\tres = fn(argc, argv, prefix);\n+\t}\n \n \t/*\n \t * Handle early success\ndiff --git a/git-bisect.sh b/git-bisect.sh\nindex dfce4b4f44..9f6c8cc093 100755\n--- a/git-bisect.sh\n+++ b/git-bisect.sh\n@@ -57,8 +57,6 @@ case \"$#\" in\n \tcase \"$cmd\" in\n \thelp)\n \t\tgit bisect -h ;;\n-\tbad|good|new|old|\"$TERM_BAD\"|\"$TERM_GOOD\")\n-\t\tgit bisect--helper state \"$cmd\" \"$@\" ;;\n \tlog)\n \t\tgit bisect--helper log || exit ;;\n \t*)\n-- \n2.38.1.157.gedabe22e0a\n\n"},{"id":"467065","messageId":"de3075eff9ffffea27d19e749af897b72f83ef41.1668097966.git.congdanhqx@gmail.com","threadId":"58746","inReplyTo":"cover.1668097962.git.congdanhqx@gmail.com","subject":"[PATCH v2 10/11] bisect--helper: log: allow arbitrary number of arguments","fromName":"Đoàn Trần Công Danh","fromEmail":"congdanhqx@gmail.com","sentAt":"2022-11-10T16:36:45Z","receivedAt":"2022-11-10T16:37:57Z","isPatch":true,"sender":{"key":"congdanhqx@gmail.com","avatar":"https://avatars.githubusercontent.com/u/42673067?v=4"},"body":"In a later change, we would like to turn bisect into a builtin by\nrenaming bisect--helper.\n\nHowever, there's an oddity that \"git bisect log\" accepts any number of\narguments and it will just ignore them all.\n\nLet's prepare for the next step by ignoring any arguments passed to\n\"git bisect--helper log\"\n\nSigned-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>\n---\n builtin/bisect--helper.c | 4 +---\n git-bisect.sh            | 2 --\n 2 files changed, 1 insertion(+), 5 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 29d5a26c64..6066f553fd 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1347,10 +1347,8 @@ static int cmd_bisect__next(int argc, const char **argv UNUSED, const char *pref\n \treturn res;\n }\n \n-static int cmd_bisect__log(int argc, const char **argv UNUSED, const char *prefix UNUSED)\n+static int cmd_bisect__log(int argc UNUSED, const char **argv UNUSED, const char *prefix UNUSED)\n {\n-\tif (argc)\n-\t\treturn error(_(\"'%s' requires 0 arguments\"), \"git bisect log\");\n \treturn bisect_log();\n }\n \ndiff --git a/git-bisect.sh b/git-bisect.sh\nindex 9f6c8cc093..f95b8103a9 100755\n--- a/git-bisect.sh\n+++ b/git-bisect.sh\n@@ -57,8 +57,6 @@ case \"$#\" in\n \tcase \"$cmd\" in\n \thelp)\n \t\tgit bisect -h ;;\n-\tlog)\n-\t\tgit bisect--helper log || exit ;;\n \t*)\n \t\tgit bisect--helper \"$cmd\" \"$@\" ;;\n \tesac\n-- \n2.38.1.157.gedabe22e0a\n\n"},{"id":"467066","messageId":"dadca7adbe3e7984f60fd6de6c8d63edb6a1ad8f.1668097966.git.congdanhqx@gmail.com","threadId":"58746","inReplyTo":"cover.1668097962.git.congdanhqx@gmail.com","subject":"[PATCH v2 11/11] Turn `git bisect` into a full built-in","fromName":"Đoàn Trần Công Danh","fromEmail":"congdanhqx@gmail.com","sentAt":"2022-11-10T16:36:46Z","receivedAt":"2022-11-10T16:38:02Z","isPatch":true,"sender":{"key":"congdanhqx@gmail.com","avatar":"https://avatars.githubusercontent.com/u/42673067?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nNow that the shell script hands off to the `bisect--helper` to do\n_anything_ (except to show the help), it is but a tiny step to let the\nhelper implement the actual `git bisect` command instead.\n\nThis retires `git-bisect.sh`, concluding a multi-year journey that many\nhands helped with, in particular Pranit Bauna, Tanushree Tumane and\nMiriam Rubio.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>\n---\n Makefile                               | 3 +--\n builtin.h                              | 2 +-\n builtin/{bisect--helper.c => bisect.c} | 2 +-\n git.c                                  | 2 +-\n 4 files changed, 4 insertions(+), 5 deletions(-)\n rename builtin/{bisect--helper.c => bisect.c} (99%)\n\ndiff --git a/Makefile b/Makefile\nindex 4927379184..78785c6b84 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -627,7 +627,6 @@ THIRD_PARTY_SOURCES =\n # interactive shell sessions without exporting it.\n unexport CDPATH\n \n-SCRIPT_SH += git-bisect.sh\n SCRIPT_SH += git-difftool--helper.sh\n SCRIPT_SH += git-filter-branch.sh\n SCRIPT_SH += git-merge-octopus.sh\n@@ -1137,7 +1136,7 @@ BUILTIN_OBJS += builtin/am.o\n BUILTIN_OBJS += builtin/annotate.o\n BUILTIN_OBJS += builtin/apply.o\n BUILTIN_OBJS += builtin/archive.o\n-BUILTIN_OBJS += builtin/bisect--helper.o\n+BUILTIN_OBJS += builtin/bisect.o\n BUILTIN_OBJS += builtin/blame.o\n BUILTIN_OBJS += builtin/branch.o\n BUILTIN_OBJS += builtin/bugreport.o\ndiff --git a/builtin.h b/builtin.h\nindex 8901a34d6b..aa955466b4 100644\n--- a/builtin.h\n+++ b/builtin.h\n@@ -116,7 +116,7 @@ int cmd_am(int argc, const char **argv, const char *prefix);\n int cmd_annotate(int argc, const char **argv, const char *prefix);\n int cmd_apply(int argc, const char **argv, const char *prefix);\n int cmd_archive(int argc, const char **argv, const char *prefix);\n-int cmd_bisect__helper(int argc, const char **argv, const char *prefix);\n+int cmd_bisect(int argc, const char **argv, const char *prefix);\n int cmd_blame(int argc, const char **argv, const char *prefix);\n int cmd_branch(int argc, const char **argv, const char *prefix);\n int cmd_bugreport(int argc, const char **argv, const char *prefix);\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect.c\nsimilarity index 99%\nrename from builtin/bisect--helper.c\nrename to builtin/bisect.c\nindex 6066f553fd..cc9483e851 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect.c\n@@ -1401,7 +1401,7 @@ static int cmd_bisect__run(int argc, const char **argv, const char *prefix UNUSE\n \treturn res;\n }\n \n-int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n+int cmd_bisect(int argc, const char **argv, const char *prefix)\n {\n \tint res = 0;\n \tparse_opt_subcommand_fn *fn = NULL;\ndiff --git a/git.c b/git.c\nindex 6662548986..a2deb15e46 100644\n--- a/git.c\n+++ b/git.c\n@@ -492,7 +492,7 @@ static struct cmd_struct commands[] = {\n \t{ \"annotate\", cmd_annotate, RUN_SETUP },\n \t{ \"apply\", cmd_apply, RUN_SETUP_GENTLY },\n \t{ \"archive\", cmd_archive, RUN_SETUP_GENTLY },\n-\t{ \"bisect--helper\", cmd_bisect__helper, RUN_SETUP },\n+\t{ \"bisect\", cmd_bisect, RUN_SETUP },\n \t{ \"blame\", cmd_blame, RUN_SETUP },\n \t{ \"branch\", cmd_branch, RUN_SETUP | DELAY_PAGER_CONFIG },\n \t{ \"bugreport\", cmd_bugreport, RUN_SETUP_GENTLY },\n-- \n2.38.1.157.gedabe22e0a\n\n"},{"id":"467134","messageId":"221111.86v8nloeav.gmgdl@evledraar.gmail.com","threadId":"58746","inReplyTo":"cover.1668097286.git.congdanhqx@gmail.com","subject":"Re: [PATCH v3 0/3] Convert git-bisect--helper to OPT_SUBCOMMAND","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-11T12:32:54Z","receivedAt":"2022-11-11T12:40:06Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Thu, Nov 10 2022, Đoàn Trần Công Danh wrote:\n\n> Despite this series has been merged into next.\n> I'm sending this because Taylor said he wanted a (combined) reroll?\n> <Y2riRSL+NprJt278@nand.local>\n\nSince Taylor hasn't chimed in: I think that \"combined reroll\" was\nreferring to whether we could combine the version I sent out, and the\none you sent out.\n\nI think we should (obviously) go for your version, and thanks for\npicking this up and running with it. But at the time in that \"What's\nCooking\" the branch name was \"dd/git-bisect-builtin\" (i.e. your\nversion), but the note was still saying the source was\n\"<cover-00.13-00000000000-20221104T132117Z-avarab@gmail.com>\" (i.e. my\nversion).\n\nIn any case, the patches you're re-rolling in this 1-3 are already in\nnext, so a \"what it would have looked like\" isn't going to be useful to\napply at this point. So I think just...\n\n> Range-diff against v2:\n> -:  ---------- > 1:  6b80fd9398 bisect--helper: remove unused options\n> 1:  9d8a3cdd7a ! 2:  248ed392ea bisect--helper: move all subcommands into their own functions\n>     @@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, cons\n>      +static int cmd_bisect__terms(int argc, const char **argv, const char *prefix UNUSED)\n>      +{\n>      +\tint res;\n>     -+\tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\n>     ++\tstruct bisect_terms terms = { 0 };\n>      +\n>      +\tif (argc > 1)\n>      +\t\treturn error(_(\"--bisect-terms requires 0 or 1 argument\"));\n>     @@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, cons\n>      +static int cmd_bisect__start(int argc, const char **argv, const char *prefix UNUSED)\n>      +{\n>      +\tint res;\n>     -+\tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\n>     ++\tstruct bisect_terms terms = { 0 };\n>      +\n>      +\tset_terms(&terms, \"bad\", \"good\");\n>      +\tres = bisect_start(&terms, argv, argc);\n>     @@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, cons\n>      +static int cmd_bisect__next(int argc, const char **argv UNUSED, const char *prefix)\n>      +{\n>      +\tint res;\n>     -+\tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\n>     ++\tstruct bisect_terms terms = { 0 };\n>      +\n>      +\tif (argc)\n>      +\t\treturn error(_(\"--bisect-next requires 0 arguments\"));\n>     @@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, cons\n>      +static int cmd_bisect__state(int argc, const char **argv, const char *prefix UNUSED)\n>      +{\n>      +\tint res;\n>     -+\tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\n>     ++\tstruct bisect_terms terms = { 0 };\n>      +\n>      +\tset_terms(&terms, \"bad\", \"good\");\n>      +\tget_terms(&terms);\n>     @@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, cons\n>      +static int cmd_bisect__replay(int argc, const char **argv, const char *prefix UNUSED)\n>      +{\n>      +\tint res;\n>     -+\tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\n>     ++\tstruct bisect_terms terms = { 0 };\n>      +\n>      +\tif (argc != 1)\n>      +\t\treturn error(_(\"no logfile given\"));\n>     @@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, cons\n>      +static int cmd_bisect__skip(int argc, const char **argv, const char *prefix UNUSED)\n>      +{\n>      +\tint res;\n>     -+\tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\n>     ++\tstruct bisect_terms terms = { 0 };\n>      +\n>      +\tset_terms(&terms, \"bad\", \"good\");\n>      +\tget_terms(&terms);\n>     @@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, cons\n>      +static int cmd_bisect__visualize(int argc, const char **argv, const char *prefix UNUSED)\n>      +{\n>      +\tint res;\n>     -+\tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\n>     ++\tstruct bisect_terms terms = { 0 };\n>      +\n>      +\tget_terms(&terms);\n>      +\tres = bisect_visualize(&terms, argv, argc);\n>     @@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, cons\n>      +static int cmd_bisect__run(int argc, const char **argv, const char *prefix UNUSED)\n>      +{\n>      +\tint res;\n>     -+\tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\n>     ++\tstruct bisect_terms terms = { 0 };\n>      +\n>      +\tif (!argc)\n>      +\t\treturn error(_(\"bisect run failed: no command provided.\"));\n\n...a stand-alone two-patch series with these (and possibly tying any\nother loose ends) would be nice, I think (but haven't looked carefully)\nthat it could probably be done in such a way that it applies\nconcurrently with the migration to builtin/bisect.c, i.e. to the extent\nthat the hunks don't conflict textually or semantically.\n"},{"id":"467135","messageId":"221111.86r0y9odgk.gmgdl@evledraar.gmail.com","threadId":"58746","inReplyTo":"6b80fd93980ec5171fe0637cbd1a8173a5337da4.1668097286.git.congdanhqx@gmail.com","subject":"Re: [PATCH v3 1/3] bisect--helper: remove unused options","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-11T12:42:44Z","receivedAt":"2022-11-11T12:58:16Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Thu, Nov 10 2022, Đoàn Trần Công Danh wrote:\n\n> 'git-bisect.sh' used to have a 'bisect_next_check' to check if we have\n> both good/bad, old/new terms set or not.  In commit 129a6cf344\n> (bisect--helper: `bisect_next_check` shell function in C, 2019-01-02),\n> a subcommand for bisect--helper was introduced to port the check to C.\n> Since d1bbbe45df (bisect--helper: reimplement `bisect_run` shell\n> function in C, 2021-09-13), all users of 'bisect_next_check' was\n> re-implemented in C, this subcommand was no longer used but we forgot\n> to remove '--bisect-next-check'.\n\n\n\n> 'git-bisect.sh' also used to have a 'bisect_write' function, whose\n> third positional parameter was a \"nolog\" flag.  This flag was only used\n> when 'bisect_start' invoked 'bisect_write' to write the starting good\n> and bad revisions.  Then 0f30233a11 (bisect--helper: `bisect_write`\n> shell function in C, 2019-01-02) ported it to C as a command mode of\n> 'bisect--helper', which (incorrectly) added the '--no-log' option,\n> and convert the only place ('bisect_start') that call 'bisect_write'\n> with 'nolog' to 'git bisect--helper --bisect-write' with 'nolog'\n> instead of '--no-log', since 'bisect--helper' has command modes not\n> subcommands, all other command modes see and handle that option as well.\n> This bogus state didn't last long, however, because in the same patch\n> series 06f5608c14 (bisect--helper: `bisect_start` shell function\n> partially in C, 2019-01-02) the C reimplementation of bisect_start()\n> started calling the bisect_write() C function, this time with the\n> right 'nolog' function parameter. From then on there was no need for\n> the '--no-log' option in 'bisect--helper'. Eventually all bisect\n> subcommands were ported to C as 'bisect--helper' command modes, each\n> calling the bisect_write() C function instead, but when the\n> '--bisect-write' command mode was removed in 68efed8c8a\n> (bisect--helper: retire `--bisect-write` subcommand, 2021-02-03) it\n> forgot to remove that '--no-log' option.\n> '--no-log' option had never been used and it's unused now.\n\nFWIW I think this very long backstory can be condensed to just (mainly\ntrying to get some paragraph breaks in there):\n\n\tThe \"--no-log\" option has never been used. It was added in\n\t0f30233a11f (bisect--helper: `bisect_write` shell function in C,\n\t2019-01-02).\n\n        In that commit bisect_write() was also changed to take a\n\t\"no_log\" function parameter, with nothing providing the\n\t\"--no-log\" option, and \"bisect--helper --bisect-write\" being\n\tgiven an unused \"nolog\" parameter.\n\n        Then, later in the same series 06f5608c14e (bisect--helper:\n        `bisect_start` shell function partially in C, 2019-01-02) the\n        code passing the unused \"nolog\" parameter went away, while\n        leaving us with this unused \"--no-log\" code.\n\n> Signed-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>\n> ---\n>  builtin/bisect--helper.c | 7 +------\n>  1 file changed, 1 insertion(+), 6 deletions(-)\n>\n> diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\n> index 1d2ce8a0e1..5ec2e67f59 100644\n> --- a/builtin/bisect--helper.c\n> +++ b/builtin/bisect--helper.c\n> @@ -1283,7 +1283,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n>  {\n>  \tenum {\n>  \t\tBISECT_RESET = 1,\n> -\t\tBISECT_NEXT_CHECK,\n>  \t\tBISECT_TERMS,\n>  \t\tBISECT_START,\n>  \t\tBISECT_AUTOSTART,\n> @@ -1295,12 +1294,10 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n>  \t\tBISECT_VISUALIZE,\n>  \t\tBISECT_RUN,\n>  \t} cmdmode = 0;\n> -\tint res = 0, nolog = 0;\n> +\tint res = 0;\n>  \tstruct option options[] = {\n>  \t\tOPT_CMDMODE(0, \"bisect-reset\", &cmdmode,\n>  \t\t\t N_(\"reset the bisection state\"), BISECT_RESET),\n> -\t\tOPT_CMDMODE(0, \"bisect-next-check\", &cmdmode,\n> -\t\t\t N_(\"check whether bad or good terms exist\"), BISECT_NEXT_CHECK),\n>  \t\tOPT_CMDMODE(0, \"bisect-terms\", &cmdmode,\n>  \t\t\t N_(\"print out the bisect terms\"), BISECT_TERMS),\n>  \t\tOPT_CMDMODE(0, \"bisect-start\", &cmdmode,\n> @@ -1319,8 +1316,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n>  \t\t\t N_(\"visualize the bisection\"), BISECT_VISUALIZE),\n>  \t\tOPT_CMDMODE(0, \"bisect-run\", &cmdmode,\n>  \t\t\t N_(\"use <cmd>... to automatically bisect\"), BISECT_RUN),\n> -\t\tOPT_BOOL(0, \"no-log\", &nolog,\n> -\t\t\t N_(\"no log for BISECT_WRITE\")),\n>  \t\tOPT_END()\n>  \t};\n>  \tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\n\nThis looks good. Is it your original work, or did the signed-off-by's go\nmissing along the way? I.e. in the greater history of this topic this\ncomes from Johannes's:\n\n\thttps://lore.kernel.org/git/1e43148864a52ffe05b5075bd0e449c0e056f078.1661885419.git.gitgitgadget@gmail.com/\n\thttps://lore.kernel.org/git/05262b6a7d1b20a0d2f2ca2090be284ffb8c679c.1661885419.git.gitgitgadget@gmail.com/\n\nWhich, when I re-rolled it I carried forward as:\n\n\thttps://lore.kernel.org/git/patch-04.13-b10deee4827-20221104T132117Z-avarab@gmail.com/\n\nSo I assumed you went back and looked at the original topic...\n\nIn any case, if you are doing a \"misc little cleanups\" series, I think\nlifting some more from Johannes's original topic might be useful> I\ndropped some in my 13 patch re-roll to keep it more focused on just the\n\"bisect built-in\" goal, e.g. there's:\n\n\thttps://lore.kernel.org/git/f2132b61ff7d7959fd8efcd9d416736b154718f0.1661885419.git.gitgitgadget@gmail.com/\n\thttps://lore.kernel.org/git/4f93692e071cf316fd391344b5dbbc995c162232.1661885419.git.gitgitgadget@gmail.com/\n\nBut maybe those are better left out/or submitted as *another* topic,\njust pointing them out in case you missed them...\n"},{"id":"467136","messageId":"221111.86mt8xoaxh.gmgdl@evledraar.gmail.com","threadId":"58746","inReplyTo":"248ed392ea8bc7c812156276bd120bc9d5b8ba6e.1668097286.git.congdanhqx@gmail.com","subject":"Re: [PATCH v3 2/3] bisect--helper: move all subcommands into their own functions","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-11T13:51:44Z","receivedAt":"2022-11-11T13:52:54Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Thu, Nov 10 2022, Đoàn Trần Công Danh wrote:\n\n> In a later change, we will use OPT_SUBCOMMAND to parse sub-commands to\n> avoid consuming non-option opts.\n>\n> Since OPT_SUBCOMMAND needs a function pointer to operate,\n> let's move it now.\n>\n> Signed-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>\n> ---\n>  builtin/bisect--helper.c | 155 ++++++++++++++++++++++++++++++---------\n>  1 file changed, 121 insertions(+), 34 deletions(-)\n>\n> diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\n> index 5ec2e67f59..d425555d1f 100644\n> --- a/builtin/bisect--helper.c\n> +++ b/builtin/bisect--helper.c\n> @@ -1279,6 +1279,117 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n>  \treturn res;\n>  }\n>  \n> +static int cmd_bisect__reset(int argc, const char **argv, const char *prefix UNUSED)\n> +{\n> +\tif (argc > 1)\n> +\t\treturn error(_(\"--bisect-reset requires either no argument or a commit\"));\n> +\treturn bisect_reset(argc ? argv[0] : NULL);\n> +}\n> +\n> +static int cmd_bisect__terms(int argc, const char **argv, const char *prefix UNUSED)\n> +{\n> +\tint res;\n> +\tstruct bisect_terms terms = { 0 };\n> +\n> +\tif (argc > 1)\n> +\t\treturn error(_(\"--bisect-terms requires 0 or 1 argument\"));\n> +\tres = bisect_terms(&terms, argc == 1 ? argv[0] : NULL);\n> +\tfree_terms(&terms);\n> +\treturn res;\n> +}\n> +\n> +static int cmd_bisect__start(int argc, const char **argv, const char *prefix UNUSED)\n> +{\n> +\tint res;\n> +\tstruct bisect_terms terms = { 0 };\n> +\n> +\tset_terms(&terms, \"bad\", \"good\");\n> +\tres = bisect_start(&terms, argv, argc);\n> +\tfree_terms(&terms);\n> +\treturn res;\n> +}\n> +\n> +static int cmd_bisect__next(int argc, const char **argv UNUSED, const char *prefix)\n> +{\n> +\tint res;\n> +\tstruct bisect_terms terms = { 0 };\n> +\n> +\tif (argc)\n> +\t\treturn error(_(\"--bisect-next requires 0 arguments\"));\n> +\tget_terms(&terms);\n> +\tres = bisect_next(&terms, prefix);\n> +\tfree_terms(&terms);\n> +\treturn res;\n> +}\n> +\n> +static int cmd_bisect__state(int argc, const char **argv, const char *prefix UNUSED)\n> +{\n> +\tint res;\n> +\tstruct bisect_terms terms = { 0 };\n> +\n> +\tset_terms(&terms, \"bad\", \"good\");\n> +\tget_terms(&terms);\n> +\tres = bisect_state(&terms, argv, argc);\n> +\tfree_terms(&terms);\n> +\treturn res;\n> +}\n> +\n> +static int cmd_bisect__log(int argc, const char **argv UNUSED, const char *prefix UNUSED)\n> +{\n> +\tif (argc)\n> +\t\treturn error(_(\"--bisect-log requires 0 arguments\"));\n> +\treturn bisect_log();\n> +}\n> +\n> +static int cmd_bisect__replay(int argc, const char **argv, const char *prefix UNUSED)\n> +{\n> +\tint res;\n> +\tstruct bisect_terms terms = { 0 };\n> +\n> +\tif (argc != 1)\n> +\t\treturn error(_(\"no logfile given\"));\n> +\tset_terms(&terms, \"bad\", \"good\");\n> +\tres = bisect_replay(&terms, argv[0]);\n> +\tfree_terms(&terms);\n> +\treturn res;\n> +}\n> +\n> +static int cmd_bisect__skip(int argc, const char **argv, const char *prefix UNUSED)\n> +{\n> +\tint res;\n> +\tstruct bisect_terms terms = { 0 };\n> +\n> +\tset_terms(&terms, \"bad\", \"good\");\n> +\tget_terms(&terms);\n> +\tres = bisect_skip(&terms, argv, argc);\n> +\tfree_terms(&terms);\n> +\treturn res;\n> +}\n> +\n> +static int cmd_bisect__visualize(int argc, const char **argv, const char *prefix UNUSED)\n> +{\n> +\tint res;\n> +\tstruct bisect_terms terms = { 0 };\n> +\n> +\tget_terms(&terms);\n> +\tres = bisect_visualize(&terms, argv, argc);\n> +\tfree_terms(&terms);\n> +\treturn res;\n> +}\n> +\n> +static int cmd_bisect__run(int argc, const char **argv, const char *prefix UNUSED)\n> +{\n> +\tint res;\n> +\tstruct bisect_terms terms = { 0 };\n> +\n> +\tif (!argc)\n> +\t\treturn error(_(\"bisect run failed: no command provided.\"));\n> +\tget_terms(&terms);\n> +\tres = bisect_run(&terms, argv, argc);\n> +\tfree_terms(&terms);\n> +\treturn res;\n> +}\n> +\n>  int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n>  {\n>  \tenum {\n> @@ -1318,8 +1429,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n>  \t\t\t N_(\"use <cmd>... to automatically bisect\"), BISECT_RUN),\n>  \t\tOPT_END()\n>  \t};\n> -\tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\n> -\n>  \targc = parse_options(argc, argv, prefix, options,\n>  \t\t\t     git_bisect_helper_usage,\n>  \t\t\t     PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN_OPT);\n> @@ -1329,60 +1438,38 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n>  \n>  \tswitch (cmdmode) {\n>  \tcase BISECT_RESET:\n> -\t\tif (argc > 1)\n> -\t\t\treturn error(_(\"--bisect-reset requires either no argument or a commit\"));\n> -\t\tres = bisect_reset(argc ? argv[0] : NULL);\n> +\t\tres = cmd_bisect__reset(argc, argv, prefix);\n>  \t\tbreak;\n>  \tcase BISECT_TERMS:\n> -\t\tif (argc > 1)\n> -\t\t\treturn error(_(\"--bisect-terms requires 0 or 1 argument\"));\n> -\t\tres = bisect_terms(&terms, argc == 1 ? argv[0] : NULL);\n> +\t\tres = cmd_bisect__terms(argc, argv, prefix);\n>  \t\tbreak;\n>  \tcase BISECT_START:\n> -\t\tset_terms(&terms, \"bad\", \"good\");\n> -\t\tres = bisect_start(&terms, argv, argc);\n> +\t\tres = cmd_bisect__start(argc, argv, prefix);\n>  \t\tbreak;\n>  \tcase BISECT_NEXT:\n> -\t\tif (argc)\n> -\t\t\treturn error(_(\"--bisect-next requires 0 arguments\"));\n> -\t\tget_terms(&terms);\n> -\t\tres = bisect_next(&terms, prefix);\n> +\t\tres = cmd_bisect__next(argc, argv, prefix);\n>  \t\tbreak;\n>  \tcase BISECT_STATE:\n> -\t\tset_terms(&terms, \"bad\", \"good\");\n> -\t\tget_terms(&terms);\n> -\t\tres = bisect_state(&terms, argv, argc);\n> +\t\tres = cmd_bisect__state(argc, argv, prefix);\n>  \t\tbreak;\n>  \tcase BISECT_LOG:\n> -\t\tif (argc)\n> -\t\t\treturn error(_(\"--bisect-log requires 0 arguments\"));\n> -\t\tres = bisect_log();\n> +\t\tres = cmd_bisect__log(argc, argv, prefix);\n>  \t\tbreak;\n>  \tcase BISECT_REPLAY:\n> -\t\tif (argc != 1)\n> -\t\t\treturn error(_(\"no logfile given\"));\n> -\t\tset_terms(&terms, \"bad\", \"good\");\n> -\t\tres = bisect_replay(&terms, argv[0]);\n> +\t\tres = cmd_bisect__replay(argc, argv, prefix);\n>  \t\tbreak;\n>  \tcase BISECT_SKIP:\n> -\t\tset_terms(&terms, \"bad\", \"good\");\n> -\t\tget_terms(&terms);\n> -\t\tres = bisect_skip(&terms, argv, argc);\n> +\t\tres = cmd_bisect__skip(argc, argv, prefix);\n>  \t\tbreak;\n>  \tcase BISECT_VISUALIZE:\n> -\t\tget_terms(&terms);\n> -\t\tres = bisect_visualize(&terms, argv, argc);\n> +\t\tres = cmd_bisect__visualize(argc, argv, prefix);\n>  \t\tbreak;\n>  \tcase BISECT_RUN:\n> -\t\tif (!argc)\n> -\t\t\treturn error(_(\"bisect run failed: no command provided.\"));\n> -\t\tget_terms(&terms);\n> -\t\tres = bisect_run(&terms, argv, argc);\n> +\t\tres = cmd_bisect__run(argc, argv, prefix);\n>  \t\tbreak;\n>  \tdefault:\n>  \t\tBUG(\"unknown subcommand %d\", cmdmode);\n>  \t}\n> -\tfree_terms(&terms);\n>  \n>  \t/*\n>  \t * Handle early success\n\nFWIW I tried my suggestion in an earlier review of factoring this into a\nfunction, I don't know if it's worth it, but it is a net reduction in\nlines. Some of the error messages are changed as a result.\n\nIf you think the end result looks better, feel free to pick it up /\nadapt it etc with my Signed-off-by.\n\n builtin/bisect--helper.c | 109 +++++++++++++++++++----------------------------\n 1 file changed, 43 insertions(+), 66 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex d4d813ebfce..e5a5261f9f2 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -469,8 +469,11 @@ static int get_terms(struct bisect_terms *terms)\n \treturn res;\n }\n \n-static int bisect_terms(struct bisect_terms *terms, const char *option)\n+static int bisect_terms(struct bisect_terms *terms, const char **argv,\n+\t\t\tint argc)\n {\n+\tconst char *option = argc == 1 ? argv[0] : NULL;\n+\n \tif (get_terms(terms))\n \t\treturn error(_(\"no terms defined\"));\n \n@@ -1024,7 +1027,7 @@ static int process_replay_line(struct bisect_terms *terms, struct strbuf *line)\n \t\tstruct strvec argv = STRVEC_INIT;\n \t\tint res;\n \t\tsq_dequote_to_strvec(rev, &argv);\n-\t\tres = bisect_terms(terms, argv.nr == 1 ? argv.v[0] : NULL);\n+\t\tres = bisect_terms(terms, argv.v, argv.nr);\n \t\tstrvec_clear(&argv);\n \t\treturn res;\n \t}\n@@ -1033,8 +1036,10 @@ static int process_replay_line(struct bisect_terms *terms, struct strbuf *line)\n \treturn -1;\n }\n \n-static enum bisect_error bisect_replay(struct bisect_terms *terms, const char *filename)\n+static int bisect_replay(struct bisect_terms *terms, const char **argv,\n+\t\t\tint argc)\n {\n+\tconst char *filename = argv[0];\n \tFILE *fp = NULL;\n \tenum bisect_error res = BISECT_OK;\n \tstruct strbuf line = STRBUF_INIT;\n@@ -1279,6 +1284,24 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n \treturn res;\n }\n \n+typedef int (*cmd_bisect_fn_t)(struct bisect_terms *terms, const char **argv, int argc);\n+static int terms_cmd(int argc, const char **argv, const char *prefix UNUSED,\n+\t\t     cmd_bisect_fn_t fn, int set, int errcond,\n+\t\t     const char *errmsg, const char *errcmd)\n+{\n+\tint res;\n+\tstruct bisect_terms terms = { 0 };\n+\n+\tif (errcond)\n+\t\treturn error(_(errmsg), errcmd);\n+\tif (set)\n+\t\tset_terms(&terms, \"bad\", \"good\");\n+\tget_terms(&terms);\n+\tres = fn(&terms, argv, argc);\n+\tfree_terms(&terms);\n+\treturn res;\n+}\n+\n static int cmd_bisect__reset(int argc, const char **argv, const char *prefix UNUSED)\n {\n \tif (argc > 1)\n@@ -1286,27 +1309,15 @@ static int cmd_bisect__reset(int argc, const char **argv, const char *prefix UNU\n \treturn bisect_reset(argc ? argv[0] : NULL);\n }\n \n-static int cmd_bisect__terms(int argc, const char **argv, const char *prefix UNUSED)\n+static int cmd_bisect__terms(int argc, const char **argv, const char *prefix)\n {\n-\tint res;\n-\tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\n-\n-\tif (argc > 1)\n-\t\treturn error(_(\"--bisect-terms requires 0 or 1 argument\"));\n-\tres = bisect_terms(&terms, argc == 1 ? argv[0] : NULL);\n-\tfree_terms(&terms);\n-\treturn res;\n+\treturn terms_cmd(argc, argv, prefix, bisect_terms, 0, argc > 1,\n+\t\t\t N_(\"'bisect %s' requires 0 or 1 argument\"), \"terms\");\n }\n \n-static int cmd_bisect__start(int argc, const char **argv, const char *prefix UNUSED)\n+static int cmd_bisect__start(int argc, const char **argv, const char *prefix)\n {\n-\tint res;\n-\tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\n-\n-\tset_terms(&terms, \"bad\", \"good\");\n-\tres = bisect_start(&terms, argv, argc);\n-\tfree_terms(&terms);\n-\treturn res;\n+\treturn terms_cmd(argc, argv, prefix, bisect_start, 1, 0, NULL, NULL);\n }\n \n static int cmd_bisect__next(int argc, const char **argv UNUSED, const char *prefix)\n@@ -1322,16 +1333,9 @@ static int cmd_bisect__next(int argc, const char **argv UNUSED, const char *pref\n \treturn res;\n }\n \n-static int cmd_bisect__state(int argc, const char **argv, const char *prefix UNUSED)\n+static int cmd_bisect__state(int argc, const char **argv, const char *prefix)\n {\n-\tint res;\n-\tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\n-\n-\tset_terms(&terms, \"bad\", \"good\");\n-\tget_terms(&terms);\n-\tres = bisect_state(&terms, argv, argc);\n-\tfree_terms(&terms);\n-\treturn res;\n+\treturn terms_cmd(argc, argv, prefix, bisect_state, 1, 0, NULL, NULL);\n }\n \n static int cmd_bisect__log(int argc, const char **argv UNUSED, const char *prefix UNUSED)\n@@ -1341,53 +1345,26 @@ static int cmd_bisect__log(int argc, const char **argv UNUSED, const char *prefi\n \treturn bisect_log();\n }\n \n-static int cmd_bisect__replay(int argc, const char **argv, const char *prefix UNUSED)\n+static int cmd_bisect__replay(int argc, const char **argv, const char *prefix)\n {\n-\tint res;\n-\tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\n-\n-\tif (argc != 1)\n-\t\treturn error(_(\"no logfile given\"));\n-\tset_terms(&terms, \"bad\", \"good\");\n-\tres = bisect_replay(&terms, argv[0]);\n-\tfree_terms(&terms);\n-\treturn res;\n+\treturn terms_cmd(argc, argv, prefix, bisect_replay, 1, argc != 1,\n+\t\t\t N_(\"'bisect %s': no logfile given\"), \"replay\");\n }\n \n-static int cmd_bisect__skip(int argc, const char **argv, const char *prefix UNUSED)\n+static int cmd_bisect__skip(int argc, const char **argv, const char *prefix)\n {\n-\tint res;\n-\tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\n-\n-\tset_terms(&terms, \"bad\", \"good\");\n-\tget_terms(&terms);\n-\tres = bisect_skip(&terms, argv, argc);\n-\tfree_terms(&terms);\n-\treturn res;\n+\treturn terms_cmd(argc, argv, prefix, bisect_skip, 1, 0, NULL, NULL);\n }\n \n-static int cmd_bisect__visualize(int argc, const char **argv, const char *prefix UNUSED)\n+static int cmd_bisect__visualize(int argc, const char **argv, const char *prefix)\n {\n-\tint res;\n-\tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\n-\n-\tget_terms(&terms);\n-\tres = bisect_visualize(&terms, argv, argc);\n-\tfree_terms(&terms);\n-\treturn res;\n+\treturn terms_cmd(argc, argv, prefix, bisect_visualize, 0, 0, NULL, NULL);\n }\n \n-static int cmd_bisect__run(int argc, const char **argv, const char *prefix UNUSED)\n+static int cmd_bisect__run(int argc, const char **argv, const char *prefix)\n {\n-\tint res;\n-\tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\n-\n-\tif (!argc)\n-\t\treturn error(_(\"bisect run failed: no command provided.\"));\n-\tget_terms(&terms);\n-\tres = bisect_run(&terms, argv, argc);\n-\tfree_terms(&terms);\n-\treturn res;\n+\treturn terms_cmd(argc, argv, prefix, bisect_run, 0, !argc,\n+\t\t\t N_(\"bisect %s failed: no command provided.\"), \"run\");\n }\n \n int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n"},{"id":"467137","messageId":"221111.86iljload5.gmgdl@evledraar.gmail.com","threadId":"58746","inReplyTo":"de3075eff9ffffea27d19e749af897b72f83ef41.1668097966.git.congdanhqx@gmail.com","subject":"Re: [PATCH v2 10/11] bisect--helper: log: allow arbitrary number of arguments","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-11T14:01:38Z","receivedAt":"2022-11-11T14:14:57Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Thu, Nov 10 2022, Đoàn Trần Công Danh wrote:\n\n> In a later change, we would like to turn bisect into a builtin by\n> renaming bisect--helper.\n>\n> However, there's an oddity that \"git bisect log\" accepts any number of\n> arguments and it will just ignore them all.\n>\n> Let's prepare for the next step by ignoring any arguments passed to\n> \"git bisect--helper log\"\n>\n> Signed-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>\n> ---\n>  builtin/bisect--helper.c | 4 +---\n>  git-bisect.sh            | 2 --\n>  2 files changed, 1 insertion(+), 5 deletions(-)\n>\n> diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\n> index 29d5a26c64..6066f553fd 100644\n> --- a/builtin/bisect--helper.c\n> +++ b/builtin/bisect--helper.c\n> @@ -1347,10 +1347,8 @@ static int cmd_bisect__next(int argc, const char **argv UNUSED, const char *pref\n>  \treturn res;\n>  }\n>  \n> -static int cmd_bisect__log(int argc, const char **argv UNUSED, const char *prefix UNUSED)\n> +static int cmd_bisect__log(int argc UNUSED, const char **argv UNUSED, const char *prefix UNUSED)\n>  {\n> -\tif (argc)\n> -\t\treturn error(_(\"'%s' requires 0 arguments\"), \"git bisect log\");\n>  \treturn bisect_log();\n>  }\n>  \n> diff --git a/git-bisect.sh b/git-bisect.sh\n> index 9f6c8cc093..f95b8103a9 100755\n> --- a/git-bisect.sh\n> +++ b/git-bisect.sh\n> @@ -57,8 +57,6 @@ case \"$#\" in\n>  \tcase \"$cmd\" in\n>  \thelp)\n>  \t\tgit bisect -h ;;\n> -\tlog)\n> -\t\tgit bisect--helper log || exit ;;\n>  \t*)\n>  \t\tgit bisect--helper \"$cmd\" \"$@\" ;;\n>  \tesac\n\nI'm agnostic on whether we keep this oddity, or just say we're fixing it\nas we're converting things. We could also go for some in-between and\nissue a warning(), if we suspect users in the wild are relying on this\nfor whatever reason.\n\nI'd be fine with just making it error. E.g. in my upcoming (and already\naired on the list as an RFC) series to migrate git-submodule.sh to a\nbuilt-in I *do* change some behavior, because some of it's too insane to\ncarry forward in a bug-for-bug compatible way.\n\nBut I when doing so I add tests for it, explain why etc.\n\nSo, I think whatever we do here, we should be adding tests for this. If\nit's worth preserving it's worth testing.\n"},{"id":"467138","messageId":"221111.86edu9oa9d.gmgdl@evledraar.gmail.com","threadId":"58746","inReplyTo":"dadca7adbe3e7984f60fd6de6c8d63edb6a1ad8f.1668097966.git.congdanhqx@gmail.com","subject":"Re: [PATCH v2 11/11] Turn `git bisect` into a full built-in","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-11T13:53:19Z","receivedAt":"2022-11-11T14:16:52Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Thu, Nov 10 2022, Đoàn Trần Công Danh wrote:\n\n> From: Johannes Schindelin <johannes.schindelin@gmx.de>\n>\n> Now that the shell script hands off to the `bisect--helper` to do\n> _anything_ (except to show the help), it is but a tiny step to let the\n> helper implement the actual `git bisect` command instead.\n>\n> This retires `git-bisect.sh`, concluding a multi-year journey that many\n> hands helped with, in particular Pranit Bauna, Tanushree Tumane and\n> Miriam Rubio.\n>\n> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> Signed-off-by: Junio C Hamano <gitster@pobox.com>\n> Signed-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>\n> ---\n>  Makefile                               | 3 +--\n>  builtin.h                              | 2 +-\n>  builtin/{bisect--helper.c => bisect.c} | 2 +-\n>  git.c                                  | 2 +-\n>  4 files changed, 4 insertions(+), 5 deletions(-)\n>  rename builtin/{bisect--helper.c => bisect.c} (99%)\n>\n> diff --git a/Makefile b/Makefile\n> index 4927379184..78785c6b84 100644\n> --- a/Makefile\n> +++ b/Makefile\n> @@ -627,7 +627,6 @@ THIRD_PARTY_SOURCES =\n>  # interactive shell sessions without exporting it.\n>  unexport CDPATH\n>  \n> -SCRIPT_SH += git-bisect.sh\n>  SCRIPT_SH += git-difftool--helper.sh\n>  SCRIPT_SH += git-filter-branch.sh\n>  SCRIPT_SH += git-merge-octopus.sh\n\nThis is missing a \"git rm git-bisect.sh\", which should be part of this\ncommit.\n\nDo we have a test for at least the exit code of \"git bisect -h\"? I think\nnot, because before this it would have been (from skimming\ngit-sh-setup.sh) 1, but 129 after.\n\nThe new exit code is better, but let's test that. For some exitsing tests:\n\n\tgit grep 'test_expect_code 129 .*-h'\n"},{"id":"467147","messageId":"Y25sVYUAVvsfRiPK@coredump.intra.peff.net","threadId":"58746","inReplyTo":"221111.86edu9oa9d.gmgdl@evledraar.gmail.com","subject":"Re: [PATCH v2 11/11] Turn `git bisect` into a full built-in","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2022-11-11T15:37:57Z","receivedAt":"2022-11-11T15:38:02Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Fri, Nov 11, 2022 at 02:53:19PM +0100, Ævar Arnfjörð Bjarmason wrote:\n\n> Do we have a test for at least the exit code of \"git bisect -h\"? I think\n> not, because before this it would have been (from skimming\n> git-sh-setup.sh) 1, but 129 after.\n> \n> The new exit code is better, but let's test that. For some exitsing tests:\n> \n> \tgit grep 'test_expect_code 129 .*-h'\n\nIt should be covered by t0012 automatically once it becomes a builtin\n(and checking out the tip of dd/git-bisect-builtin, that seems to be the\ncase).\n\n-Peff\n"},{"id":"467160","messageId":"221111.86o7tdmc3f.gmgdl@evledraar.gmail.com","threadId":"58746","inReplyTo":"Y25sVYUAVvsfRiPK@coredump.intra.peff.net","subject":"Re: [PATCH v2 11/11] Turn `git bisect` into a full built-in","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-11T21:09:59Z","receivedAt":"2022-11-11T21:10:34Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Fri, Nov 11 2022, Jeff King wrote:\n\n> On Fri, Nov 11, 2022 at 02:53:19PM +0100, Ævar Arnfjörð Bjarmason wrote:\n>\n>> Do we have a test for at least the exit code of \"git bisect -h\"? I think\n>> not, because before this it would have been (from skimming\n>> git-sh-setup.sh) 1, but 129 after.\n>> \n>> The new exit code is better, but let's test that. For some exitsing tests:\n>> \n>> \tgit grep 'test_expect_code 129 .*-h'\n>\n> It should be covered by t0012 automatically once it becomes a builtin\n> (and checking out the tip of dd/git-bisect-builtin, that seems to be the\n> case).\n\nYes, you're right. I forgot about those. So, there's nothing to do here\nthen...\n"},{"id":"467164","messageId":"Y27Hrkruh6++7NkO@nand.local","threadId":"58746","inReplyTo":"cover.1668097962.git.congdanhqx@gmail.com","subject":"Re: [PATCH v2 00/11] Turn git-bisect to be builtin","fromName":"Taylor Blau","fromEmail":"me@ttaylorr.com","sentAt":"2022-11-11T22:07:42Z","receivedAt":"2022-11-11T22:08:56Z","isPatch":true,"sender":{"key":"me@ttaylorr.com","avatar":"https://avatars.githubusercontent.com/u/301000140?v=4"},"body":"On Thu, Nov 10, 2022 at 11:36:35PM +0700, Đoàn Trần Công Danh wrote:\n> This series finish the git-bisect porting from shell script into a C builtin.\n>\n> This series can't be applied cleaned on master, it needs to be applied on top\n> of the series posted at:\n> https://lore.kernel.org/git/cover.1668097286.git.congdanhqx@gmail.com/\n> AND the series rs/no-more-run-command-v, which has been integrated to next.\n\nThanks, having both was helpful. Note that 'rs/no-more-run-command-v' was\nmerged into 'master' via be4ac3b197 (Merge branch\n'rs/no-more-run-command-v', 2022-11-08), so picking up these new patches\nonly needed a merge of the other series.\n\n> Johannes Schindelin (2):\n>   bisect--helper: handle states directly\n>   Turn `git bisect` into a full built-in\n>\n> Ævar Arnfjörð Bjarmason (4):\n>   bisect tests: test for v2.30.0 \"bisect run\" regressions\n>   bisect: refactor bisect_run() to match CodingGuidelines\n>   bisect test: test exit codes on bad usage\n>   bisect--helper: emit usage for \"git bisect\"\n>\n> Đoàn Trần Công Danh (5):\n>   bisect: fix output regressions in v2.30.0\n>   bisect run: keep some of the post-v2.30.0 output\n>   bisect-run: verify_good: account for non-negative exit status\n>   bisect--helper: identify as bisect when report error\n>   bisect--helper: log: allow arbitrary number of arguments\n\nLooking good to me. Is everybody happy to start merging these two down?\n\nThanks,\nTaylor\n"},{"id":"467191","messageId":"36337a3f-6443-f272-09f0-7ddb3c20d7a4@web.de","threadId":"58746","inReplyTo":"221106.86k048w2f4.gmgdl@evledraar.gmail.com","subject":"Re: [PATCH 09/13] parse-options API: don't restrict OPT_SUBCOMMAND() to one *_fn type","fromName":"René Scharfe","fromEmail":"l.s.r@web.de","sentAt":"2022-11-12T10:42:09Z","receivedAt":"2022-11-12T10:42:33Z","isPatch":true,"sender":{"key":"l.s.r@web.de","avatar":"https://avatars.githubusercontent.com/u/26122331?v=4"},"body":"Am 06.11.22 um 14:28 schrieb Ævar Arnfjörð Bjarmason:\n>\n> No, I think that:\n>\n> 1) J.5.7 does that on its own for C99\n\nAn extension is not part of the standard, by definition.  Section J is\ninformative, not normative.  J.5.7 just says that there are systems out\nthere which allow casts from function pointers to object pointers and/or\nback, which is not portable.\n\n> 2) POSIX has orthagonally mandated this, seperate from C99.\n\nIt only requires dlsym(3) to work.  That's a narrow case.  A conforming\nimplementation could have function pointers wider than object pointers,\nmaking conversions in the other direction lossy.  Or have function\npointers narrower than object pointers and let dlopen(3) place symbols\nonly in the range addressable by those.\n\n> In practice I think it's always worked for dlsym(), but there's\n> interesting changes in wording between v6 and v7 of POSIX:\n>\n>    - https://pubs.opengroup.org/onlinepubs/009695399/functions/dlsym.html\n>    - https://pubs.opengroup.org/onlinepubs/9699919799/functions/dlsym.html\n>\n> v6 claims that conforming C compilers are required to produce a warning\n> if this isn't supported (I haven't found the part of the standard\n> they're referencing), and notes that the behavior may be deprecated in\n> the future.\n>\n> Whereas v7 says that POSIX \"requires this conversion to work correctly\n> on conforming implementations\".\n\nFrom the second link: \"The dlsym() function is moved from the XSI option\nto the Base.\"  So dynamic libraries are no longer optional on POSIX\nsystems.  That means you can use dlsym(3) on any compliant system.  You\ncan also safely store its return value in an intptr_t IIUC.  But that\ndoesn't generalize to all function pointers.\n\n> I think it's useful in itself to see what subset or superset of C we\n> actually need to concern ourselves with.\n>\n> E.g. we have plenty of code that assumes ASCII, instead of catering to\n> EBCDIC, and assuming NULL is (void *)0, not (void *)123456 or whatever.\n\nNULL is defined as \"0\" or \"(void *)0\" by C99 6.3.2.3 Pointers paragraph\n3 and 7.17 Common definitions <stddef.h> paragraph 3.\n\n> Yes, in this case the alternative is trivial, but perhaps we'd find a\n> use-case in the future.\n>\n> All I'm saying is let's leave the current one in place, as there's no\n> indication that it's not supported by our targets.\n\nLeaving undefined behavior in the code in the hope that we may come up\nwith a compelling use case for it later is a bad idea.  I really hope\nwe never find one.\n\nRené\n"},{"id":"467201","messageId":"Y2/LF/qiZI99YuxM@coredump.intra.peff.net","threadId":"58746","inReplyTo":"36337a3f-6443-f272-09f0-7ddb3c20d7a4@web.de","subject":"Re: [PATCH 09/13] parse-options API: don't restrict OPT_SUBCOMMAND() to one *_fn type","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2022-11-12T16:34:31Z","receivedAt":"2022-11-12T16:34:37Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Sat, Nov 12, 2022 at 11:42:09AM +0100, René Scharfe wrote:\n\n> > E.g. we have plenty of code that assumes ASCII, instead of catering to\n> > EBCDIC, and assuming NULL is (void *)0, not (void *)123456 or whatever.\n> \n> NULL is defined as \"0\" or \"(void *)0\" by C99 6.3.2.3 Pointers paragraph\n> 3 and 7.17 Common definitions <stddef.h> paragraph 3.\n\nI think he is alluding to the fact that while the standard requires that\na \"0\" constant refers to a NULL pointer, the representation does not\nhave to be all-bits-zero. So:\n\n  char *foo = 0;\n\nis fine, but:\n\n  char *foo;\n  memset(foo, 0, sizeof(&foo));\n\nis not. And we absolutely do the latter in our code base anyway, because\nit's convenient and unlikely to be a problem on practical platforms. And\nI think it has always been our attitude in this community to let\nengineering practicality trump strict adherence to the standard. But\n\"practicality\" there should be measuring the tradeoff of how useful\nsomething is versus how likely it is to bite us.\n\nIn the case under discussion, my gut feeling agrees with you, though.\nI'm skeptical that equivalence of object and function pointers is all\nthat useful in practice. And your mention of CHERI seems like a\nplausible way it could bite us.\n\n-Peff\n"},{"id":"467205","messageId":"221112.8635aom6p5.gmgdl@evledraar.gmail.com","threadId":"58746","inReplyTo":"Y2/LF/qiZI99YuxM@coredump.intra.peff.net","subject":"Re: [PATCH 09/13] parse-options API: don't restrict OPT_SUBCOMMAND() to one *_fn type","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-12T16:55:52Z","receivedAt":"2022-11-12T17:19:26Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Sat, Nov 12 2022, Jeff King wrote:\n\n> On Sat, Nov 12, 2022 at 11:42:09AM +0100, René Scharfe wrote:\n>\n>> > E.g. we have plenty of code that assumes ASCII, instead of catering to\n>> > EBCDIC, and assuming NULL is (void *)0, not (void *)123456 or whatever.\n>> \n>> NULL is defined as \"0\" or \"(void *)0\" by C99 6.3.2.3 Pointers paragraph\n>> 3 and 7.17 Common definitions <stddef.h> paragraph 3.\n>\n> I think he is alluding to the fact that while the standard requires that\n> a \"0\" constant refers to a NULL pointer, the representation does not\n> have to be all-bits-zero. So:\n>\n>   char *foo = 0;\n>\n> is fine, but:\n>\n>   char *foo;\n>   memset(foo, 0, sizeof(&foo));\n\nYes, to elaborate: the \"null pointer constant\" referred to in 6.3.2.3\ndeliberately leaves room for the representation being unequal to the\n\"all zero bits\". And as you point out the former example is portable,\nbut not the latter.\n\n> is not. And we absolutely do the latter in our code base anyway, because\n> it's convenient and unlikely to be a problem on practical platforms. And\n> I think it has always been our attitude in this community to let\n> engineering practicality trump strict adherence to the standard. But\n> \"practicality\" there should be measuring the tradeoff of how useful\n> something is versus how likely it is to bite us.\n\nAll I've been trying to get across in this sub-thread is that there's an\ninteresting empirical question here: Are we in fact targeting an\narchitecture where J.5.7 isn't implemented, or likely to have one sneak\nup on us?\n\nI don't think so, and timing-wise deciding to be paranoid about this\nparticular thing would leave that question unanswered, when all we have\nto do is wait a bit (some of the slower platforms tend to be a few\nreleases behind).\n\nThe argument for the change[1] (further articulated upthread) hasn't\nanswered the \"do we target such an arch?\", but seems to just fall back\nto general standards paranoia.\n\nWhich isn't an invalid argument in itself. But doesn't really address\nwhy we'd be worried about *this* particular thing, but not e.g. those\nsort of memsets, assuming ASCII ordering for 'A'..'z' etc.\n\n> In the case under discussion, my gut feeling agrees with you, though.\n> I'm skeptical that equivalence of object and function pointers is all\n> that useful in practice. And your mention of CHERI seems like a\n> plausible way it could bite us.\n\nI think the post-image of [1] looks nicer when reviewed stand-alone, so\nI'm not against the change per-se, I actually like it.\n\nAnd I don't have a use-case for using that feature further, in a way\nthat isn't easy to do differently.\n\nBut e.g. now we're having a parallel discussion about using some 3rd\nparty bitmap library. We might e.g. want to incorporate some 3rd party\nJIT or whatever in the future. If we run into this question again it\nwould be nice to have it answered already.\n\nAnd if we didn't have this J.5.7 reliance in that code already I don't\nthink it would be worth the effort to introduce one as a test\nballoon. I'm only saying this in the context that we already have one.\n\n1. https://lore.kernel.org/git/c64e4fa5-62c2-2a93-a4ef-bd84407ea570@web.de/\n"},{"id":"467223","messageId":"12542034-b5cc-bad0-5a60-2672bde35b78@web.de","threadId":"58746","inReplyTo":"221112.8635aom6p5.gmgdl@evledraar.gmail.com","subject":"Re: [PATCH 09/13] parse-options API: don't restrict OPT_SUBCOMMAND() to one *_fn type","fromName":"René Scharfe","fromEmail":"l.s.r@web.de","sentAt":"2022-11-13T17:31:06Z","receivedAt":"2022-11-13T17:31:39Z","isPatch":true,"sender":{"key":"l.s.r@web.de","avatar":"https://avatars.githubusercontent.com/u/26122331?v=4"},"body":"Am 12.11.22 um 17:55 schrieb Ævar Arnfjörð Bjarmason:\n>\n> On Sat, Nov 12 2022, Jeff King wrote:\n>\n>> On Sat, Nov 12, 2022 at 11:42:09AM +0100, René Scharfe wrote:\n>>\n>>>> E.g. we have plenty of code that assumes ASCII, instead of catering to\n>>>> EBCDIC, and assuming NULL is (void *)0, not (void *)123456 or whatever.\n>>>\n>>> NULL is defined as \"0\" or \"(void *)0\" by C99 6.3.2.3 Pointers paragraph\n>>> 3 and 7.17 Common definitions <stddef.h> paragraph 3.\n>>\n>> I think he is alluding to the fact that while the standard requires that\n>> a \"0\" constant refers to a NULL pointer, the representation does not\n>> have to be all-bits-zero. So:\n>>\n>>   char *foo = 0;\n>>\n>> is fine, but:\n>>\n>>   char *foo;\n>>   memset(foo, 0, sizeof(&foo));\n>\n> Yes, to elaborate: the \"null pointer constant\" referred to in 6.3.2.3\n> deliberately leaves room for the representation being unequal to the\n> \"all zero bits\". And as you point out the former example is portable,\n> but not the latter.\n>\n>> is not. And we absolutely do the latter in our code base anyway, because\n>> it's convenient and unlikely to be a problem on practical platforms. And\n>> I think it has always been our attitude in this community to let\n>> engineering practicality trump strict adherence to the standard. But\n>> \"practicality\" there should be measuring the tradeoff of how useful\n>> something is versus how likely it is to bite us.\n\nFor me the usefulness so far is negative: The code is more complicated\nthan necessary.  Adding a context pointer to the callback function\nsignature here and keeping the extra code outside the callback function\nin builtin/pack-objects.c is simpler.\n\n> All I've been trying to get across in this sub-thread is that there's an\n> interesting empirical question here: Are we in fact targeting an\n> architecture where J.5.7 isn't implemented, or likely to have one sneak\n> up on us?\n\nHow would you measure this?  Undefined behavior can manifest itself\ndifferently e.g. based on compiler version and options, or in this\ncase pointer value and perhaps even function calling convention.  And\nof course in the form of the famous nasal demons..\n\n> I don't think so, and timing-wise deciding to be paranoid about this\n> particular thing would leave that question unanswered, when all we have\n> to do is wait a bit (some of the slower platforms tend to be a few\n> releases behind).\n>\n> The argument for the change[1] (further articulated upthread) hasn't\n> answered the \"do we target such an arch?\", but seems to just fall back\n> to general standards paranoia.\n\nI mentioned CHERI (Arm Morello) as a candidate, but can't tell you for\nsure.\n\n> Which isn't an invalid argument in itself. But doesn't really address\n> why we'd be worried about *this* particular thing, but not e.g. those\n> sort of memsets, assuming ASCII ordering for 'A'..'z' etc.\n\nYou can keep worrying about them if you like.  Replacing memset calls\nwith _INIT macros has been going on for while already.  Using isalpha()\ninstead of character range comparisons etc. is probably a good idea\nanyway.\n\n>> In the case under discussion, my gut feeling agrees with you, though.\n>> I'm skeptical that equivalence of object and function pointers is all\n>> that useful in practice. And your mention of CHERI seems like a\n>> plausible way it could bite us.\n>\n> I think the post-image of [1] looks nicer when reviewed stand-alone, so\n> I'm not against the change per-se, I actually like it.\n>\n> And I don't have a use-case for using that feature further, in a way\n> that isn't easy to do differently.\n>\n> But e.g. now we're having a parallel discussion about using some 3rd\n> party bitmap library. We might e.g. want to incorporate some 3rd party\n> JIT or whatever in the future. If we run into this question again it\n> would be nice to have it answered already.\n\nWhy would a bitmap library require function pointer casts?\n\nA JIT library probably comes with a list of supported systems and\nrequires a fallback for anyone else.  I'd expect the system-specific\nparts to be encapsulated in that library.\n\n> And if we didn't have this J.5.7 reliance in that code already I don't\n> think it would be worth the effort to introduce one as a test\n> balloon. I'm only saying this in the context that we already have one.\n>\n> 1. https://lore.kernel.org/git/c64e4fa5-62c2-2a93-a4ef-bd84407ea570@web.de/\n\nIf it's not worth adding then it's probably not worth keeping.\n\nRené\n"},{"id":"467332","messageId":"Y3PmAP24GPAhXPOm@nand.local","threadId":"58746","inReplyTo":"Y27Hrkruh6++7NkO@nand.local","subject":"Re: [PATCH v2 00/11] Turn git-bisect to be builtin","fromName":"Taylor Blau","fromEmail":"me@ttaylorr.com","sentAt":"2022-11-15T19:18:24Z","receivedAt":"2022-11-15T19:18:29Z","isPatch":true,"sender":{"key":"me@ttaylorr.com","avatar":"https://avatars.githubusercontent.com/u/301000140?v=4"},"body":"On Fri, Nov 11, 2022 at 05:07:42PM -0500, Taylor Blau wrote:\n> On Thu, Nov 10, 2022 at 11:36:35PM +0700, Đoàn Trần Công Danh wrote:\n> > This series finish the git-bisect porting from shell script into a C builtin.\n> >\n> > This series can't be applied cleaned on master, it needs to be applied on top\n> > of the series posted at:\n> > https://lore.kernel.org/git/cover.1668097286.git.congdanhqx@gmail.com/\n> > AND the series rs/no-more-run-command-v, which has been integrated to next.\n>\n> Thanks, having both was helpful. Note that 'rs/no-more-run-command-v' was\n> merged into 'master' via be4ac3b197 (Merge branch\n> 'rs/no-more-run-command-v', 2022-11-08), so picking up these new patches\n> only needed a merge of the other series.\n>\n> > Johannes Schindelin (2):\n> >   bisect--helper: handle states directly\n> >   Turn `git bisect` into a full built-in\n> >\n> > Ævar Arnfjörð Bjarmason (4):\n> >   bisect tests: test for v2.30.0 \"bisect run\" regressions\n> >   bisect: refactor bisect_run() to match CodingGuidelines\n> >   bisect test: test exit codes on bad usage\n> >   bisect--helper: emit usage for \"git bisect\"\n> >\n> > Đoàn Trần Công Danh (5):\n> >   bisect: fix output regressions in v2.30.0\n> >   bisect run: keep some of the post-v2.30.0 output\n> >   bisect-run: verify_good: account for non-negative exit status\n> >   bisect--helper: identify as bisect when report error\n> >   bisect--helper: log: allow arbitrary number of arguments\n>\n> Looking good to me. Is everybody happy to start merging these two down?\n\nHmm. Looks like there is a small breakage in the last commit \"Turn `git\nbisect` into a full built-in\":\n\n    $ make check-builtins\n    ./check-builtins.sh\n    bisect is builtin but git-bisect.sh still exists\n    make: *** [Makefile:3561: check-builtins] Error 1\n\nSeeing that this is on 'next', it would be nice to see a fix in the near\nfuture, certainly before we graduate this down to 'master'. Am I correct\nin assuming that there is no reason to keep git-bisect.sh around after\nthat commit?\n\nThanks,\nTaylor\n"},{"id":"467333","messageId":"Y3PqLMzC8DBPjp10@coredump.intra.peff.net","threadId":"58746","inReplyTo":"Y3PmAP24GPAhXPOm@nand.local","subject":"Re: [PATCH v2 00/11] Turn git-bisect to be builtin","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2022-11-15T19:36:12Z","receivedAt":"2022-11-15T19:36:16Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Tue, Nov 15, 2022 at 02:18:24PM -0500, Taylor Blau wrote:\n\n> Hmm. Looks like there is a small breakage in the last commit \"Turn `git\n> bisect` into a full built-in\":\n> \n>     $ make check-builtins\n>     ./check-builtins.sh\n>     bisect is builtin but git-bisect.sh still exists\n>     make: *** [Makefile:3561: check-builtins] Error 1\n> \n> Seeing that this is on 'next', it would be nice to see a fix in the near\n> future, certainly before we graduate this down to 'master'. Am I correct\n> in assuming that there is no reason to keep git-bisect.sh around after\n> that commit?\n\nYeah, see:\n\n  https://lore.kernel.org/git/patch-1.1-7be23b6faa0-20221115T093130Z-avarab@gmail.com/\n\n-Peff\n"},{"id":"467335","messageId":"Y3PrIgynUYFtrqnB@nand.local","threadId":"58746","inReplyTo":"Y3PqLMzC8DBPjp10@coredump.intra.peff.net","subject":"Re: [PATCH v2 00/11] Turn git-bisect to be builtin","fromName":"Taylor Blau","fromEmail":"me@ttaylorr.com","sentAt":"2022-11-15T19:40:18Z","receivedAt":"2022-11-15T19:40:26Z","isPatch":true,"sender":{"key":"me@ttaylorr.com","avatar":"https://avatars.githubusercontent.com/u/301000140?v=4"},"body":"On Tue, Nov 15, 2022 at 02:36:12PM -0500, Jeff King wrote:\n> On Tue, Nov 15, 2022 at 02:18:24PM -0500, Taylor Blau wrote:\n>\n> > Hmm. Looks like there is a small breakage in the last commit \"Turn `git\n> > bisect` into a full built-in\":\n> >\n> >     $ make check-builtins\n> >     ./check-builtins.sh\n> >     bisect is builtin but git-bisect.sh still exists\n> >     make: *** [Makefile:3561: check-builtins] Error 1\n> >\n> > Seeing that this is on 'next', it would be nice to see a fix in the near\n> > future, certainly before we graduate this down to 'master'. Am I correct\n> > in assuming that there is no reason to keep git-bisect.sh around after\n> > that commit?\n>\n> Yeah, see:\n>\n>   https://lore.kernel.org/git/patch-1.1-7be23b6faa0-20221115T093130Z-avarab@gmail.com/\n\nAck, thanks.\n\nThanks,\nTaylor\n"}]}