{"thread":{"id":"57326","subject":"[PATCH 00/11] Finish converting git bisect into a built-in","startedAt":"2022-01-28T00:12:38Z","lastAt":"2022-09-13T18:26:52Z","messageCount":147,"participants":["Johannes Schindelin via GitGitGadget","Miriam R.","Johannes Schindelin","Ævar Arnfjörð Bjarmason","Elijah Newren","Junio C Hamano","Bagas Sanjaya"],"isPatch":true,"patchVersion":1,"patchTotal":11},"messages":[{"id":"447149","messageId":"pull.1132.git.1643328752.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":null,"subject":"[PATCH 00/11] Finish converting git bisect into a built-in","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-01-28T00:12:21Z","receivedAt":"2022-01-28T00:12:38Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"After three GSoC/Outreachy students spent an incredible effort on this, it\nis finally time to put a neat little bow on it.\n\nJohannes Schindelin (11):\n  bisect run: fix the error message\n  bisect--helper: retire the --no-log option\n  bisect--helper: really retire --bisect-next-check\n  bisect--helper: really retire `--bisect-autostart`\n  bisect--helper: align the sub-command order with git-bisect.sh\n  bisect--helper: make `--bisect-state` optional\n  bisect: move even the option parsing to `bisect--helper`\n  bisect--helper: using `--bisect-state` without an argument is a bug\n  Turn `git bisect` into a full built-in.\n  bisect: remove Cogito-related code\n  bisect: no longer try to clean up left-over `.git/head-name` files\n\n Makefile                               |   3 +-\n bisect.c                               |   3 -\n builtin.h                              |   2 +-\n builtin/{bisect--helper.c => bisect.c} | 201 ++++++++++---------------\n git-bisect.sh                          |  84 -----------\n git.c                                  |   2 +-\n t/t6030-bisect-porcelain.sh            |   1 -\n 7 files changed, 84 insertions(+), 212 deletions(-)\n rename builtin/{bisect--helper.c => bisect.c} (87%)\n delete mode 100755 git-bisect.sh\n\n\nbase-commit: 89bece5c8c96f0b962cfc89e63f82d603fd60bed\nPublished-As: https://github.com/gitgitgadget/git/releases/tag/pr-1132%2Fdscho%2Fbisect-in-c-v1\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1132/dscho/bisect-in-c-v1\nPull-Request: https://github.com/gitgitgadget/git/pull/1132\n-- \ngitgitgadget\n"},{"id":"447150","messageId":"93d19d85ee38f50019d5f05605ce7b5eca76cbd6.1643328752.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.git.1643328752.gitgitgadget@gmail.com","subject":"[PATCH 01/11] bisect run: fix the error message","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-01-28T00:12:22Z","receivedAt":"2022-01-28T00:12:40Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nIn d1bbbe45df8 (bisect--helper: reimplement `bisect_run` shell function\nin C, 2021-09-13), we ported the `bisect run` subcommand to C, including\nthe part that prints out an error message when the implicit `git bisect\nbad` or `git bisect good` failed.\n\nHowever, the error message was supposed to print out whether the state\nwas \"good\" or \"bad\", but used a bogus (because non-populated) `args`\nvariable for it.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/bisect--helper.c | 8 ++------\n 1 file changed, 2 insertions(+), 6 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 28a2e6a5750..4208206af07 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1093,7 +1093,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 strvec args = STRVEC_INIT;\n \tstruct strvec run_args = STRVEC_INIT;\n \tconst char *new_state;\n \tint temporary_stdout_fd, saved_stdout;\n@@ -1111,8 +1110,6 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n \tstrvec_push(&run_args, command.buf);\n \n \twhile (1) {\n-\t\tstrvec_clear(&args);\n-\n \t\tprintf(_(\"running %s\\n\"), command.buf);\n \t\tres = run_command_v_opt(run_args.v, RUN_USING_SHELL);\n \n@@ -1157,14 +1154,13 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n \t\t\tprintf(_(\"bisect found first bad commit\"));\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\"), args.v[0], res);\n+\t\t\terror(_(\"bisect run failed: 'git bisect\"\n+\t\t\t\" %s' exited with error code %d\"), new_state, res);\n \t\t} else {\n \t\t\tcontinue;\n \t\t}\n \n \t\tstrbuf_release(&command);\n-\t\tstrvec_clear(&args);\n \t\tstrvec_clear(&run_args);\n \t\treturn res;\n \t}\n-- \ngitgitgadget\n\n"},{"id":"447151","messageId":"8e0e555998007b2625f4a99f3b800e5f4cf89e19.1643328752.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.git.1643328752.gitgitgadget@gmail.com","subject":"[PATCH 02/11] bisect--helper: retire the --no-log option","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-01-28T00:12:23Z","receivedAt":"2022-01-28T00:12:41Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nTurns out we actually never used it, anyway...\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/bisect--helper.c | 4 +---\n 1 file changed, 1 insertion(+), 3 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 4208206af07..9c8ba61dac0 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1182,7 +1182,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@@ -1206,8 +1206,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-- \ngitgitgadget\n\n"},{"id":"447152","messageId":"996a7099bf8177ac018f9f534aec04921c4ef0e0.1643328752.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.git.1643328752.gitgitgadget@gmail.com","subject":"[PATCH 03/11] bisect--helper: really retire --bisect-next-check","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-01-28T00:12:24Z","receivedAt":"2022-01-28T00:12:42Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?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\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/bisect--helper.c | 3 ---\n 1 file changed, 3 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 9c8ba61dac0..dc840736cb5 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1170,7 +1170,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@@ -1186,8 +1185,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-- \ngitgitgadget\n\n"},{"id":"447153","messageId":"3de4c48b66dbab7c9bff486221cfd29212cee893.1643328752.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.git.1643328752.gitgitgadget@gmail.com","subject":"[PATCH 04/11] bisect--helper: really retire `--bisect-autostart`","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-01-28T00:12:25Z","receivedAt":"2022-01-28T00:12:43Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\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>\n---\n builtin/bisect--helper.c | 1 -\n 1 file changed, 1 deletion(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex dc840736cb5..7ba4be1947e 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1172,7 +1172,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\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-- \ngitgitgadget\n\n"},{"id":"447154","messageId":"6afc6e0eeced94d6d5b820cc0c77cbb74d175900.1643328752.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.git.1643328752.gitgitgadget@gmail.com","subject":"[PATCH 05/11] bisect--helper: align the sub-command order with git-bisect.sh","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-01-28T00:12:26Z","receivedAt":"2022-01-28T00:12:48Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nWe are about to retire the shell implementation of `git bisect`, or\nmaybe better put: the remainder of the shell implementation (a shell of\na script, if you want).\n\nIn preparation for that, align the order of the sub-commands with the\nway the outgoing implementation presents them to the user.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/bisect--helper.c | 76 ++++++++++++++++++++--------------------\n 1 file changed, 38 insertions(+), 38 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 7ba4be1947e..cc5a9ca41b9 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1169,37 +1169,37 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\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_START = 1,\n \t\tBISECT_STATE,\n-\t\tBISECT_LOG,\n-\t\tBISECT_REPLAY,\n+\t\tBISECT_TERMS,\n \t\tBISECT_SKIP,\n+\t\tBISECT_NEXT,\n+\t\tBISECT_RESET,\n \t\tBISECT_VISUALIZE,\n+\t\tBISECT_REPLAY,\n+\t\tBISECT_LOG,\n \t\tBISECT_RUN,\n \t} cmdmode = 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-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-terms\", &cmdmode,\n+\t\t\t N_(\"print out the bisect terms\"), BISECT_TERMS),\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-next\", &cmdmode,\n+\t\t\t N_(\"find the next bisection commit\"), BISECT_NEXT),\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-visualize\", &cmdmode,\n \t\t\t N_(\"visualize the bisection\"), BISECT_VISUALIZE),\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-log\", &cmdmode,\n+\t\t\t N_(\"list the bisection steps so far\"), BISECT_LOG),\n \t\tOPT_CMDMODE(0, \"bisect-run\", &cmdmode,\n \t\t\t N_(\"use <cmd>... to automatically bisect.\"), BISECT_RUN),\n \t\tOPT_END()\n@@ -1214,19 +1214,24 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\tusage_with_options(git_bisect_helper_usage, options);\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+\tcase BISECT_START:\n+\t\tset_terms(&terms, \"bad\", \"good\");\n+\t\tres = bisect_start(&terms, argv, argc);\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_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+\tcase BISECT_SKIP:\n \t\tset_terms(&terms, \"bad\", \"good\");\n-\t\tres = bisect_start(&terms, argv, argc);\n+\t\tget_terms(&terms);\n+\t\tres = bisect_skip(&terms, argv, argc);\n \t\tbreak;\n \tcase BISECT_NEXT:\n \t\tif (argc)\n@@ -1234,15 +1239,14 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\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+\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_LOG:\n-\t\tif (argc)\n-\t\t\treturn error(_(\"--bisect-log requires 0 arguments\"));\n-\t\tres = bisect_log();\n+\tcase BISECT_VISUALIZE:\n+\t\tget_terms(&terms);\n+\t\tres = bisect_visualize(&terms, argv, argc);\n \t\tbreak;\n \tcase BISECT_REPLAY:\n \t\tif (argc != 1)\n@@ -1250,14 +1254,10 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\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+\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_RUN:\n \t\tif (!argc)\n-- \ngitgitgadget\n\n"},{"id":"447155","messageId":"1b14ed3d7976b8fe4149822dcbb32343e0554a38.1643328752.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.git.1643328752.gitgitgadget@gmail.com","subject":"[PATCH 08/11] bisect--helper: using `--bisect-state` without an argument is a bug","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-01-28T00:12:29Z","receivedAt":"2022-01-28T00:12:48Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nThe `bisect--helper` command is not expected to be used directly by the\nuser. Therefore, it is a bug if it receives no argument to the\n`--bisect-state` command mode, not a user error. Which means that we\nneed to call `BUG()` instead of `die()`.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/bisect--helper.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 4450305c81c..009c919a989 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -872,7 +872,7 @@ static enum bisect_error bisect_state(struct bisect_terms *terms, const char **a\n \tstruct oid_array revs = OID_ARRAY_INIT;\n \n \tif (!argc)\n-\t\treturn error(_(\"Please call `--bisect-state` with at least one argument\"));\n+\t\tBUG(\"bisect_state() called without argument\");\n \n \tif (bisect_autostart(terms))\n \t\treturn BISECT_FAILED;\n-- \ngitgitgadget\n\n"},{"id":"447156","messageId":"eddbdde222a01113d8facdcb17d6ec85676edbe7.1643328752.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.git.1643328752.gitgitgadget@gmail.com","subject":"[PATCH 06/11] bisect--helper: make `--bisect-state` optional","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-01-28T00:12:27Z","receivedAt":"2022-01-28T00:12:48Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?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 `--bisect-state`\noption to be passed explicitly.\n\nTo prepare for converting `bisect--helper` to a full built-in\nimplementation of `git bisect` (which must not require the\n`--bisect-state` option to be specified at all), let's move the handling\ntoward the end of the `switch (cmdmode)` block.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/bisect--helper.c | 23 ++++++++++++++++-------\n 1 file changed, 16 insertions(+), 7 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex cc5a9ca41b9..219fa99cd0b 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -26,8 +26,8 @@ static const char * const git_bisect_helper_usage[] = {\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 \tN_(\"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-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 \tN_(\"git bisect--helper --bisect-visualize\"),\n@@ -1210,6 +1210,13 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\t\t     git_bisect_helper_usage,\n \t\t\t     PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN);\n \n+\tif (!cmdmode && argc > 0) {\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\tcmdmode = BISECT_STATE;\n+\t}\n+\n \tif (!cmdmode)\n \t\tusage_with_options(git_bisect_helper_usage, options);\n \n@@ -1218,11 +1225,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\tset_terms(&terms, \"bad\", \"good\");\n \t\tres = bisect_start(&terms, argv, argc);\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_TERMS:\n \t\tif (argc > 1)\n \t\t\treturn error(_(\"--bisect-terms requires 0 or 1 argument\"));\n@@ -1265,6 +1267,13 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\tget_terms(&terms);\n \t\tres = bisect_run(&terms, argv, argc);\n \t\tbreak;\n+\tcase BISECT_STATE:\n+\t\tif (!terms.term_good) {\n+\t\t\tset_terms(&terms, \"bad\", \"good\");\n+\t\t\tget_terms(&terms);\n+\t\t}\n+\t\tres = bisect_state(&terms, argv, argc);\n+\t\tbreak;\n \tdefault:\n \t\tBUG(\"unknown subcommand %d\", cmdmode);\n \t}\n-- \ngitgitgadget\n\n"},{"id":"447157","messageId":"1c0bd8a326f482d1a6c485b7f93f510268dade20.1643328752.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.git.1643328752.gitgitgadget@gmail.com","subject":"[PATCH 09/11] Turn `git bisect` into a full built-in.","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-01-28T00:12:30Z","receivedAt":"2022-01-28T00:12:50Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?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>\n---\n Makefile                               |  3 +--\n builtin.h                              |  2 +-\n builtin/{bisect--helper.c => bisect.c} |  2 +-\n git-bisect.sh                          | 37 --------------------------\n git.c                                  |  2 +-\n 5 files changed, 4 insertions(+), 42 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 5580859afdb..ce2eabeca58 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -595,7 +595,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@@ -1064,7 +1063,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 8a58743ed63..b5567ea3a9d 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 009c919a989..189aca9dd22 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect.c\n@@ -1182,7 +1182,7 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n \t}\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 \tstruct option options[] = {\ndiff --git a/git-bisect.sh b/git-bisect.sh\ndeleted file mode 100755\nindex 028d39cd9ce..00000000000\n--- a/git-bisect.sh\n+++ /dev/null\n@@ -1,37 +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-exec git bisect--helper \"$@\"\ndiff --git a/git.c b/git.c\nindex edda922ce6d..a8500132a28 100644\n--- a/git.c\n+++ b/git.c\n@@ -490,7 +490,7 @@ static struct cmd_struct commands[] = {\n \t{ \"annotate\", cmd_annotate, RUN_SETUP | NO_PARSEOPT },\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-- \ngitgitgadget\n\n"},{"id":"447158","messageId":"515e86e20758ed7f5b4a8ce8f38bfbbac27ec42a.1643328752.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.git.1643328752.gitgitgadget@gmail.com","subject":"[PATCH 07/11] bisect: move even the option parsing to `bisect--helper`","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-01-28T00:12:28Z","receivedAt":"2022-01-28T00:13:45Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nOn our journey to a fully built-in `git bisect`, this is the\nsecond-to-last step.\n\nSide note: The `if (!strcmp(...)) ... else if (!strcmp(...)) ... else if\n(!strcmp(...)) ...` chain seen in this patch was not actually the first\nidea how to convert the command modes to sub-commands. Since the\n`bisect--helper` command already used the `parse-opions` API with neatly\nset-up command modes, naturally the idea was to use `PARSE_OPT_NODASH`\nto support proper sub-commands instead. However, the `parse-options` API\nis not set up for that, and even after making that option work with long\noptions, it turned out that `STOP_AT_NON_OPTION` and `KEEP_UNKNOWN`\nwould have to be used but these options were not designed to work\ntogether. So it would appear as if a lot of work would have to be done\njust to be able to use `parse_options()` just to parse the sub-command,\ninstead of a simple `if...else if` chain, the latter being a\ndramatically simpler implementation. Therefore, we now keep the\n`parse_options()` call primarily to support `-h` and little else.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/bisect--helper.c | 172 ++++++++++++++++-----------------------\n git-bisect.sh            |  49 +----------\n 2 files changed, 72 insertions(+), 149 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 219fa99cd0b..4450305c81c 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -20,18 +20,34 @@ 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-\tN_(\"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-\tN_(\"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-\tN_(\"git bisect--helper --bisect-visualize\"),\n-\tN_(\"git bisect--helper --bisect-run <cmd>...\"),\n+static const char * const git_bisect_usage[] = {\n+\tN_(\"git bisect help\\n\"\n+\t   \"\\tprint this long help message.\"),\n+\tN_(\"git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>]\\n\"\n+\t   \"\\t\\t [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<pathspec>...]\\n\"\n+\t   \"\\treset bisect state and start bisection.\"),\n+\tN_(\"git bisect (bad|new) [<rev>]\\n\"\n+\t   \"\\tmark <rev> a known-bad revision/\\n\"\n+\t   \"\\t\\ta revision after change in a given property.\"),\n+\tN_(\"git bisect (good|old) [<rev>...]\\n\"\n+\t   \"\\tmark <rev>... known-good revisions/\\n\"\n+\t   \"\\t\\trevisions before change in a given property.\"),\n+\tN_(\"git bisect terms [--term-good | --term-bad]\\n\"\n+\t   \"\\tshow the terms used for old and new commits (default: bad, good)\"),\n+\tN_(\"git bisect skip [(<rev>|<range>)...]\\n\"\n+\t   \"\\tmark <rev>... untestable revisions.\"),\n+\tN_(\"git bisect next\\n\"\n+\t   \"\\tfind next bisection to test and check it out.\"),\n+\tN_(\"git bisect reset [<commit>]\\n\"\n+\t   \"\\tfinish bisection search and go back to commit.\"),\n+\tN_(\"git bisect (visualize|view)\\n\"\n+\t   \"\\tshow bisect status in gitk.\"),\n+\tN_(\"git bisect replay <logfile>\\n\"\n+\t   \"\\treplay bisection log.\"),\n+\tN_(\"git bisect log\\n\"\n+\t   \"\\tshow bisect log.\"),\n+\tN_(\"git bisect run <cmd>...\\n\"\n+\t   \"\\tuse <cmd>... to automatically bisect.\"),\n \tNULL\n };\n \n@@ -1168,115 +1184,69 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n \n int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n {\n-\tenum {\n-\t\tBISECT_START = 1,\n-\t\tBISECT_STATE,\n-\t\tBISECT_TERMS,\n-\t\tBISECT_SKIP,\n-\t\tBISECT_NEXT,\n-\t\tBISECT_RESET,\n-\t\tBISECT_VISUALIZE,\n-\t\tBISECT_REPLAY,\n-\t\tBISECT_LOG,\n-\t\tBISECT_RUN,\n-\t} cmdmode = 0;\n \tint res = 0;\n \tstruct option options[] = {\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-state\", &cmdmode,\n-\t\t\t N_(\"mark the state of ref (or refs)\"), BISECT_STATE),\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-skip\", &cmdmode,\n-\t\t\t N_(\"skip some commits for checkout\"), BISECT_SKIP),\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-reset\", &cmdmode,\n-\t\t\t N_(\"reset the bisection state\"), BISECT_RESET),\n-\t\tOPT_CMDMODE(0, \"bisect-visualize\", &cmdmode,\n-\t\t\t N_(\"visualize the bisection\"), BISECT_VISUALIZE),\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-log\", &cmdmode,\n-\t\t\t N_(\"list the bisection steps so far\"), BISECT_LOG),\n-\t\tOPT_CMDMODE(0, \"bisect-run\", &cmdmode,\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+\tconst char *command = argc > 1 ? argv[1] : \"help\";\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);\n+\t/* Handle -h and invalid options */\n+\tparse_options(argc - 1, argv + 1, prefix, options,\n+\t\t      git_bisect_usage,\n+\t\t      PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN |\n+\t\t      PARSE_OPT_ONE_SHOT | PARSE_OPT_STOP_AT_NON_OPTION);\n \n-\tif (!cmdmode && argc > 0) {\n+\tif (!strcmp(\"help\", command))\n+\t\tusage_with_options(git_bisect_usage, options);\n+\telse if (!strcmp(\"start\", command)) {\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\tcmdmode = BISECT_STATE;\n-\t}\n-\n-\tif (!cmdmode)\n-\t\tusage_with_options(git_bisect_helper_usage, options);\n-\n-\tswitch (cmdmode) {\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_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_SKIP:\n+\t\tres = bisect_start(&terms, argv + 2, argc - 2);\n+\t} else if (!strcmp(\"terms\", command)) {\n+\t\tif (argc > 3)\n+\t\t\treturn error(_(\"'terms' requires 0 or 1 argument\"));\n+\t\tres = bisect_terms(&terms, argc == 3 ? argv[2] : NULL);\n+\t} else if (!strcmp(\"skip\", command)) {\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_NEXT:\n-\t\tif (argc)\n-\t\t\treturn error(_(\"--bisect-next requires 0 arguments\"));\n+\t\tres = bisect_skip(&terms, argv + 2, argc - 2);\n+\t} else if (!strcmp(\"next\", command)) {\n+\t\tif (argc != 2)\n+\t\t\treturn error(_(\"'next' requires 0 arguments\"));\n \t\tget_terms(&terms);\n \t\tres = bisect_next(&terms, prefix);\n-\t\tbreak;\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_VISUALIZE:\n+\t} else if (!strcmp(\"reset\", command)) {\n+\t\tif (argc > 3)\n+\t\t\treturn error(_(\"'reset' requires either no argument or a commit\"));\n+\t\tres = bisect_reset(argc > 2 ? argv[2] : NULL);\n+\t} else if (one_of(command, \"visualize\", \"view\", NULL)) {\n \t\tget_terms(&terms);\n-\t\tres = bisect_visualize(&terms, argv, argc);\n-\t\tbreak;\n-\tcase BISECT_REPLAY:\n-\t\tif (argc != 1)\n+\t\tres = bisect_visualize(&terms, argv + 2, argc - 2);\n+\t} else if (!strcmp(\"replay\", command)) {\n+\t\tif (argc != 3)\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_LOG:\n-\t\tif (argc)\n-\t\t\treturn error(_(\"--bisect-log requires 0 arguments\"));\n+\t\tres = bisect_replay(&terms, argv[2]);\n+\t} else if (!strcmp(\"log\", command)) {\n+\t\tif (argc > 2)\n+\t\t\treturn error(_(\"'log' requires 0 arguments\"));\n \t\tres = bisect_log();\n-\t\tbreak;\n-\tcase BISECT_RUN:\n-\t\tif (!argc)\n+\t} else if (!strcmp(\"run\", command)) {\n+\t\tif (argc < 3)\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-\tcase BISECT_STATE:\n-\t\tif (!terms.term_good) {\n-\t\t\tset_terms(&terms, \"bad\", \"good\");\n-\t\t\tget_terms(&terms);\n+\t\tres = bisect_run(&terms, argv + 2, argc - 2);\n+\t} else {\n+\t\tset_terms(&terms, \"bad\", \"good\");\n+\t\tget_terms(&terms);\n+\t\tif (!check_and_set_terms(&terms, command))\n+\t\t\tres = bisect_state(&terms, argv + 1, argc - 1);\n+\t\telse {\n+\t\t\tchar *msg = xstrfmt(_(\"unknown command: '%s'\"), command);\n+\t\t\tusage_msg_opt(msg, git_bisect_usage, options);\n \t\t}\n-\t\tres = bisect_state(&terms, argv, argc);\n-\t\tbreak;\n-\tdefault:\n-\t\tBUG(\"unknown subcommand %d\", cmdmode);\n \t}\n+\n \tfree_terms(&terms);\n \n \t/*\ndiff --git a/git-bisect.sh b/git-bisect.sh\nindex 405cf76f2a3..028d39cd9ce 100755\n--- a/git-bisect.sh\n+++ b/git-bisect.sh\n@@ -34,51 +34,4 @@ 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 --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-\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*)\n-\t\tusage ;;\n-\tesac\n-esac\n+exec git bisect--helper \"$@\"\n-- \ngitgitgadget\n\n"},{"id":"447159","messageId":"dc77297c6760e630b7db678f8429face05b39773.1643328752.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.git.1643328752.gitgitgadget@gmail.com","subject":"[PATCH 11/11] bisect: no longer try to clean up left-over `.git/head-name` files","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-01-28T00:12:32Z","receivedAt":"2022-01-28T00:13:46Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nAs per the code comment, the `.git/head-name` files were cleaned up for\nbackwards-compatibility: an old version of `git bisect` could have left\nthem behind.\n\nNow, just how old would such a version be? As of 0f497e75f05 (Eliminate\nconfusing \"won't bisect on seeked tree\" failure, 2008-02-23), `git\nbisect` does not write that file anymore. Which corresponds to Git\nv1.5.4.4.\n\nEven if the likelihood is non-nil that there might still be users out\nthere who use such an old version to start a bisection, but then decide\nto continue bisecting with a current Git version, it is highly\nimprobable.\n\nSo let's remove that code, at long last.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n bisect.c                    | 3 ---\n t/t6030-bisect-porcelain.sh | 1 -\n 2 files changed, 4 deletions(-)\n\ndiff --git a/bisect.c b/bisect.c\nindex 888949fba6b..ebd4287c01c 100644\n--- a/bisect.c\n+++ b/bisect.c\n@@ -474,7 +474,6 @@ static GIT_PATH_FUNC(git_path_bisect_start, \"BISECT_START\")\n static GIT_PATH_FUNC(git_path_bisect_log, \"BISECT_LOG\")\n static GIT_PATH_FUNC(git_path_bisect_terms, \"BISECT_TERMS\")\n static GIT_PATH_FUNC(git_path_bisect_first_parent, \"BISECT_FIRST_PARENT\")\n-static GIT_PATH_FUNC(git_path_head_name, \"head-name\")\n \n static void read_bisect_paths(struct strvec *array)\n {\n@@ -1172,8 +1171,6 @@ int bisect_clean_state(void)\n \tunlink_or_warn(git_path_bisect_run());\n \tunlink_or_warn(git_path_bisect_terms());\n \tunlink_or_warn(git_path_bisect_first_parent());\n-\t/* Cleanup head-name if it got left by an old version of git-bisect */\n-\tunlink_or_warn(git_path_head_name());\n \t/*\n \t * Cleanup BISECT_START last to support the --no-checkout option\n \t * introduced in the commit 4796e823a.\ndiff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh\nindex 1be85d064e7..7f7ee42a7f4 100755\n--- a/t/t6030-bisect-porcelain.sh\n+++ b/t/t6030-bisect-porcelain.sh\n@@ -945,7 +945,6 @@ test_expect_success 'git bisect reset cleans bisection state properly' '\n \ttest_path_is_missing \".git/BISECT_LOG\" &&\n \ttest_path_is_missing \".git/BISECT_RUN\" &&\n \ttest_path_is_missing \".git/BISECT_TERMS\" &&\n-\ttest_path_is_missing \".git/head-name\" &&\n \ttest_path_is_missing \".git/BISECT_HEAD\" &&\n \ttest_path_is_missing \".git/BISECT_START\"\n '\n-- \ngitgitgadget\n"},{"id":"447160","messageId":"cce533486db27e0c906c91b37f30b2ef12b2ee7c.1643328752.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.git.1643328752.gitgitgadget@gmail.com","subject":"[PATCH 10/11] bisect: remove Cogito-related code","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-01-28T00:12:31Z","receivedAt":"2022-01-28T00:13:48Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nOnce upon a time, there was this idea that Git would not actually be a\nsingle coherent program, but rather a set of low-level programs that\nusers cobble together via shell scripts, or develop high-level user\ninterfaces for Git, or both.\n\nCogito was such a high-level user interface, incidentally implemented\nvia shell scripts that cobble together Git calls.\n\nIt did turn out relatively quickly that Git would much rather provide a\nuseful high-level user interface itself.\n\nAs of April 19th, 2007, Cogito was therefore discontinued (see\nhttps://lore.kernel.org/git/20070419124648.GL4489@pasky.or.cz/).\n\nNevertheless, for almost 15 years after that announcement, Git carried\nspecial code in `git bisect` to accommodate Cogito.\n\nSince it is beyond doubt that there are no more Cogito users, let's\nremove the last remnant of Cogito-accommodating code.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/bisect.c | 8 --------\n 1 file changed, 8 deletions(-)\n\ndiff --git a/builtin/bisect.c b/builtin/bisect.c\nindex 189aca9dd22..479d68dd3b5 100644\n--- a/builtin/bisect.c\n+++ b/builtin/bisect.c\n@@ -15,7 +15,6 @@ static GIT_PATH_FUNC(git_path_bisect_expected_rev, \"BISECT_EXPECTED_REV\")\n static GIT_PATH_FUNC(git_path_bisect_ancestors_ok, \"BISECT_ANCESTORS_OK\")\n static GIT_PATH_FUNC(git_path_bisect_start, \"BISECT_START\")\n static GIT_PATH_FUNC(git_path_bisect_log, \"BISECT_LOG\")\n-static GIT_PATH_FUNC(git_path_head_name, \"head-name\")\n 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@@ -756,13 +755,6 @@ static enum bisect_error bisect_start(struct bisect_terms *terms, const char **a\n \t\t\tstrbuf_addstr(&start_head, oid_to_hex(&head_oid));\n \t\t} else if (!get_oid(head, &head_oid) &&\n \t\t\t   skip_prefix(head, \"refs/heads/\", &head)) {\n-\t\t\t/*\n-\t\t\t * This error message should only be triggered by\n-\t\t\t * cogito usage, and cogito users should understand\n-\t\t\t * it relates to cg-seek.\n-\t\t\t */\n-\t\t\tif (!is_empty_or_missing_file(git_path_head_name()))\n-\t\t\t\treturn error(_(\"won't bisect on cg-seek'ed tree\"));\n \t\t\tstrbuf_addstr(&start_head, head);\n \t\t} else {\n \t\t\treturn error(_(\"bad HEAD - strange symbolic ref\"));\n-- \ngitgitgadget\n\n"},{"id":"447176","messageId":"CAN7CjDBSSCe9nyti8bF-cYW3LU+6E9brz91GY2=Db4NSmCpr9w@mail.gmail.com","threadId":"57326","inReplyTo":"CAN7CjDC+O883DB1iaJAXF5ZCis7FP2Z9z0y2qS2-JVAKfQA8aA@mail.gmail.com","subject":"Fwd: [PATCH 00/11] Finish converting git bisect into a built-in","fromName":"Miriam R.","fromEmail":"mirucam@gmail.com","sentAt":"2022-01-28T08:54:57Z","receivedAt":"2022-01-28T08:55:10Z","isPatch":true,"sender":{"key":"mirucam@gmail.com","avatar":"https://avatars.githubusercontent.com/u/56339109?v=4"},"body":"Hi Johannes,\n\nI had done the last commits to finish the porting of git bisect\ncommand since my Outreachy internship two years ago\n(https://gitlab.com/mirucam/git/-/commits/git-bisect-work-part5-v1),\nand I was planning to send them in the last patch series during this\nFebruary. I have a very very little availability and I can not send\nthe patch series frequently and I understand you are in hurry to\nfinish this.\n\nI am sure your patch series will be more complete and better and you\nwill do not need it, but if you want to use some of my commits(or\nparts) be my guest :).\nRegards,\nMiriam.\n\n\n\nEl vie, 28 ene 2022 a las 1:12, Johannes Schindelin via GitGitGadget\n(<gitgitgadget@gmail.com>) escribió:\n>\n> After three GSoC/Outreachy students spent an incredible effort on this, it\n> is finally time to put a neat little bow on it.\n>\n> Johannes Schindelin (11):\n>   bisect run: fix the error message\n>   bisect--helper: retire the --no-log option\n>   bisect--helper: really retire --bisect-next-check\n>   bisect--helper: really retire `--bisect-autostart`\n>   bisect--helper: align the sub-command order with git-bisect.sh\n>   bisect--helper: make `--bisect-state` optional\n>   bisect: move even the option parsing to `bisect--helper`\n>   bisect--helper: using `--bisect-state` without an argument is a bug\n>   Turn `git bisect` into a full built-in.\n>   bisect: remove Cogito-related code\n>   bisect: no longer try to clean up left-over `.git/head-name` files\n>\n>  Makefile                               |   3 +-\n>  bisect.c                               |   3 -\n>  builtin.h                              |   2 +-\n>  builtin/{bisect--helper.c => bisect.c} | 201 ++++++++++---------------\n>  git-bisect.sh                          |  84 -----------\n>  git.c                                  |   2 +-\n>  t/t6030-bisect-porcelain.sh            |   1 -\n>  7 files changed, 84 insertions(+), 212 deletions(-)\n>  rename builtin/{bisect--helper.c => bisect.c} (87%)\n>  delete mode 100755 git-bisect.sh\n>\n>\n> base-commit: 89bece5c8c96f0b962cfc89e63f82d603fd60bed\n> Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-1132%2Fdscho%2Fbisect-in-c-v1\n> Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1132/dscho/bisect-in-c-v1\n> Pull-Request: https://github.com/gitgitgadget/git/pull/1132\n> --\n> gitgitgadget\n"},{"id":"447202","messageId":"nycvar.QRO.7.76.6.2201281336410.347@tvgsbejvaqbjf.bet","threadId":"57326","inReplyTo":"CAN7CjDC+O883DB1iaJAXF5ZCis7FP2Z9z0y2qS2-JVAKfQA8aA@mail.gmail.com","subject":"Re: [PATCH 00/11] Finish converting git bisect into a built-in","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2022-01-28T12:42:11Z","receivedAt":"2022-01-28T12:42:21Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Miriam,\n\nOn Fri, 28 Jan 2022, Miriam R. wrote:\n\n> I had done the last commits to finish the porting of git bisect command\n> since my Outreachy internship two years ago (\n> https://gitlab.com/mirucam/git/-/commits/git-bisect-work-part5-v1), and I\n> was planning to send them in the last patch series during this February.\n\nOh sorry! I specifically went to look at your fork before starting to work\non the patch series, but had not seen that branch. Now I updated my\nremote-tracking branches and see it as a new branch, so I am not sure\nwhether I missed it or whether it simply wasn't there.\n\nAll in all, we did very similar things. I have a slight preference for the\nmore concise version that does not use any command modes (and therefore\nalso does not duplicate the commands in the output of `git bisect -h`).\n\nMaybe you could find time in February to review my patch series? Not a big\ndeal if you're too busy.\n\nCiao,\nDscho\n"},{"id":"447218","messageId":"CAN7CjDC+A08tq-6bfxMUH_VcEZHVOr=BpWEiuuinBj7ufnch3g@mail.gmail.com","threadId":"57326","inReplyTo":"nycvar.QRO.7.76.6.2201281336410.347@tvgsbejvaqbjf.bet","subject":"Re: [PATCH 00/11] Finish converting git bisect into a built-in","fromName":"Miriam R.","fromEmail":"mirucam@gmail.com","sentAt":"2022-01-28T15:11:16Z","receivedAt":"2022-01-28T15:11:31Z","isPatch":true,"sender":{"key":"mirucam@gmail.com","avatar":"https://avatars.githubusercontent.com/u/56339109?v=4"},"body":"El vie, 28 ene 2022 a las 13:42, Johannes Schindelin\n(<Johannes.Schindelin@gmx.de>) escribió:\n>\n> Hi Miriam,\n>\n> On Fri, 28 Jan 2022, Miriam R. wrote:\n>\n> > I had done the last commits to finish the porting of git bisect command\n> > since my Outreachy internship two years ago (\n> > https://gitlab.com/mirucam/git/-/commits/git-bisect-work-part5-v1), and I\n> > was planning to send them in the last patch series during this February.\n>\n> Oh sorry! I specifically went to look at your fork before starting to work\n> on the patch series, but had not seen that branch. Now I updated my\n> remote-tracking branches and see it as a new branch, so I am not sure\n> whether I missed it or whether it simply wasn't there.\n\nHi Johannes,\n\nthe branch  ..part5-v1, I think it is from the last month, but the\ncommits were done like two years ago during my internship and they\nwere also in this branch\n(https://gitlab.com/mirucam/git/-/commits/git-bisect-work4.7). But\ndon’t worry. Of course your patch series will be way better.\n\n>\n> All in all, we did very similar things. I have a slight preference for the\n> more concise version that does not use any command modes (and therefore\n> also does not duplicate the commands in the output of `git bisect -h`).\n>\n> Maybe you could find time in February to review my patch series? Not a big\n> deal if you're too busy.\n>\n\nHaha, I could review it, but I am sure they will be perfect.\nCiao,\nMiriam.\n\n> Ciao,\n> Dscho\n"},{"id":"447271","messageId":"220129.86pmobauyt.gmgdl@evledraar.gmail.com","threadId":"57326","inReplyTo":"515e86e20758ed7f5b4a8ce8f38bfbbac27ec42a.1643328752.git.gitgitgadget@gmail.com","subject":"Re: [PATCH 07/11] bisect: move even the option parsing to `bisect--helper`","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-01-29T06:47:52Z","receivedAt":"2022-01-29T06:59:15Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Fri, Jan 28 2022, Johannes Schindelin via GitGitGadget wrote:\n\n> From: Johannes Schindelin <johannes.schindelin@gmx.de>\n> [...]\n> Side note: The `if (!strcmp(...)) ... else if (!strcmp(...)) ... else if\n> (!strcmp(...)) ...` chain seen in this patch was not actually the first\n> idea how to convert the command modes to sub-commands. Since the\n> `bisect--helper` command already used the `parse-opions` API with neatly\n> set-up command modes, naturally the idea was to use `PARSE_OPT_NODASH`\n> to support proper sub-commands instead. However, the `parse-options` API\n> is not set up for that, and even after making that option work with long\n> options, it turned out that `STOP_AT_NON_OPTION` and `KEEP_UNKNOWN`\n> would have to be used but these options were not designed to work\n> together. So it would appear as if a lot of work would have to be done\n> just to be able to use `parse_options()` just to parse the sub-command,\n> instead of a simple `if...else if` chain, the latter being a\n> dramatically simpler implementation. Therefore, we now keep the\n> `parse_options()` call primarily to support `-h` and little else.\n\nYes, in this case we're hardly getting any use out of parse_options() as\nit is.\n\nAnd here the problem is that we're going from parsing a \"git <cmd>\n--bisect-FOO\" to \"git <cmd> FOO\", and parse_options() obviously is more\nset up to like the former form.\n\nFor your playing around with flags (the \"not set up for that\" for\nPARSE_OPT_NODASH is that it doesn't like \"long options\"?) I wonder if\nyou considered/tried just setting the argc you pass to it such that it\nonly looks at the \"FOO\" item.\n\nOr just parse_options_step(), which is the supported function equivalent\nof \"I set up my state, now parse this one item\".\n\nAnyway...\n\n> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> ---\n>  builtin/bisect--helper.c | 172 ++++++++++++++++-----------------------\n>  git-bisect.sh            |  49 +----------\n>  2 files changed, 72 insertions(+), 149 deletions(-)\n>\n> diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\n> index 219fa99cd0b..4450305c81c 100644\n> --- a/builtin/bisect--helper.c\n> +++ b/builtin/bisect--helper.c\n> @@ -20,18 +20,34 @@ 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> -\tN_(\"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> -\tN_(\"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> -\tN_(\"git bisect--helper --bisect-visualize\"),\n> -\tN_(\"git bisect--helper --bisect-run <cmd>...\"),\n> +static const char * const git_bisect_usage[] = {\n> +\tN_(\"git bisect help\\n\"\n> +\t   \"\\tprint this long help message.\"),\n> +\tN_(\"git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>]\\n\"\n> +\t   \"\\t\\t [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<pathspec>...]\\n\"\n> +\t   \"\\treset bisect state and start bisection.\"),\n> +\tN_(\"git bisect (bad|new) [<rev>]\\n\"\n> +\t   \"\\tmark <rev> a known-bad revision/\\n\"\n> +\t   \"\\t\\ta revision after change in a given property.\"),\n> +\tN_(\"git bisect (good|old) [<rev>...]\\n\"\n> +\t   \"\\tmark <rev>... known-good revisions/\\n\"\n> +\t   \"\\t\\trevisions before change in a given property.\"),\n> +\tN_(\"git bisect terms [--term-good | --term-bad]\\n\"\n> +\t   \"\\tshow the terms used for old and new commits (default: bad, good)\"),\n> +\tN_(\"git bisect skip [(<rev>|<range>)...]\\n\"\n> +\t   \"\\tmark <rev>... untestable revisions.\"),\n> +\tN_(\"git bisect next\\n\"\n> +\t   \"\\tfind next bisection to test and check it out.\"),\n> +\tN_(\"git bisect reset [<commit>]\\n\"\n> +\t   \"\\tfinish bisection search and go back to commit.\"),\n> +\tN_(\"git bisect (visualize|view)\\n\"\n> +\t   \"\\tshow bisect status in gitk.\"),\n> +\tN_(\"git bisect replay <logfile>\\n\"\n> +\t   \"\\treplay bisection log.\"),\n> +\tN_(\"git bisect log\\n\"\n> +\t   \"\\tshow bisect log.\"),\n> +\tN_(\"git bisect run <cmd>...\\n\"\n> +\t   \"\\tuse <cmd>... to automatically bisect.\"),\n>  \tNULL\n>  };\n\n...I think you're throwing the baby out with the bathwater here. The\nparse_options() version is much nicer to maintain, and will to\nauto-alignment of the help output.\n\nAs builtin/commit-graph.c, builtin/stash.c, builtin/bundle.c we can and\ndo have these manual if/else if chains in combination with\nparse_options(). There's no need to change this part (except for the\ns/bisect-helper/bisect/ etc. change.\n\n>  \n> @@ -1168,115 +1184,69 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n>  \n>  int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n>  {\n> -\tenum {\n> -\t\tBISECT_START = 1,\n> -\t\tBISECT_STATE,\n> -\t\tBISECT_TERMS,\n> -\t\tBISECT_SKIP,\n> -\t\tBISECT_NEXT,\n> -\t\tBISECT_RESET,\n> -\t\tBISECT_VISUALIZE,\n> -\t\tBISECT_REPLAY,\n> -\t\tBISECT_LOG,\n> -\t\tBISECT_RUN,\n> -\t} cmdmode = 0;\n>  \tint res = 0;\n>  \tstruct option options[] = {\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-state\", &cmdmode,\n> -\t\t\t N_(\"mark the state of ref (or refs)\"), BISECT_STATE),\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-skip\", &cmdmode,\n> -\t\t\t N_(\"skip some commits for checkout\"), BISECT_SKIP),\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-reset\", &cmdmode,\n> -\t\t\t N_(\"reset the bisection state\"), BISECT_RESET),\n> -\t\tOPT_CMDMODE(0, \"bisect-visualize\", &cmdmode,\n> -\t\t\t N_(\"visualize the bisection\"), BISECT_VISUALIZE),\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-log\", &cmdmode,\n> -\t\t\t N_(\"list the bisection steps so far\"), BISECT_LOG),\n> -\t\tOPT_CMDMODE(0, \"bisect-run\", &cmdmode,\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> +\tconst char *command = argc > 1 ? argv[1] : \"help\";\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);\n> +\t/* Handle -h and invalid options */\n> +\tparse_options(argc - 1, argv + 1, prefix, options,\n> +\t\t      git_bisect_usage,\n> +\t\t      PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN |\n> +\t\t      PARSE_OPT_ONE_SHOT | PARSE_OPT_STOP_AT_NON_OPTION);\n\nWhy isn't PARSE_OPT_STOP_AT_NON_OPTION sufficient here? That's pretty\nmuch our \"this is subcommand\" pattern flag. See:\n\n    git grep -W PARSE_OPT_STOP_AT_NON_OPTION -- builtin\n\nWhich lists the examples above.\n\nI think this should strive to just copy an existing pattern as-is. See\ne.g. 92f480909f7 (multi-pack-index: refactor \"goto usage\" pattern,\n2021-08-23) for one change to make them a bit more consistent (as they\nall solve the same problem)....\n\n> [...]\n> +\t\telse {\n> +\t\t\tchar *msg = xstrfmt(_(\"unknown command: '%s'\"), command);\n> +\t\t\tusage_msg_opt(msg, git_bisect_usage, options);\n\n...e.g. this part in cmd_commit_graph is nicer.\n"},{"id":"447273","messageId":"220129.86leyzaunr.gmgdl@evledraar.gmail.com","threadId":"57326","inReplyTo":"1b14ed3d7976b8fe4149822dcbb32343e0554a38.1643328752.git.gitgitgadget@gmail.com","subject":"Re: [PATCH 08/11] bisect--helper: using `--bisect-state` without an argument is a bug","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-01-29T07:04:17Z","receivedAt":"2022-01-29T07:05:58Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Fri, Jan 28 2022, Johannes Schindelin via GitGitGadget wrote:\n\n> From: Johannes Schindelin <johannes.schindelin@gmx.de>\n>\n> The `bisect--helper` command is not expected to be used directly by the\n> user. Therefore, it is a bug if it receives no argument to the\n> `--bisect-state` command mode, not a user error. Which means that we\n> need to call `BUG()` instead of `die()`.\n\nI found this commit message confusing with 07/11. I.e. won't this be\n\"git bisect\" directly make this BUG() a bug then?\n\nBut no, it won't, because this being a bug has nothing to do with it\nbeing a helper at all. after 07/11, but that it'll be called from an\nimplicit \"if (!argc)\" in cmd_bisect(), no?\n\nI think I've either misread that, or this commit message is very\nmisleading.\n"},{"id":"447274","messageId":"220129.86h79naueg.gmgdl@evledraar.gmail.com","threadId":"57326","inReplyTo":"1c0bd8a326f482d1a6c485b7f93f510268dade20.1643328752.git.gitgitgadget@gmail.com","subject":"Re: [PATCH 09/11] Turn `git bisect` into a full built-in.","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-01-29T07:09:28Z","receivedAt":"2022-01-29T07:11:26Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Fri, Jan 28 2022, Johannes Schindelin via GitGitGadget 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> ---\n>  Makefile                               |  3 +--\n>  builtin.h                              |  2 +-\n>  builtin/{bisect--helper.c => bisect.c} |  2 +-\n>  git-bisect.sh                          | 37 --------------------------\n>  git.c                                  |  2 +-\n>  5 files changed, 4 insertions(+), 42 deletions(-)\n>  rename builtin/{bisect--helper.c => bisect.c} (99%)\n>  delete mode 100755 git-bisect.sh\n>\n> diff --git a/Makefile b/Makefile\n> index 5580859afdb..ce2eabeca58 100644\n> --- a/Makefile\n> +++ b/Makefile\n> @@ -595,7 +595,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> @@ -1064,7 +1063,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\n> diff --git a/builtin.h b/builtin.h\n> index 8a58743ed63..b5567ea3a9d 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);\n> diff --git a/builtin/bisect--helper.c b/builtin/bisect.c\n> similarity index 99%\n> rename from builtin/bisect--helper.c\n> rename to builtin/bisect.c\n> index 009c919a989..189aca9dd22 100644\n> --- a/builtin/bisect--helper.c\n> +++ b/builtin/bisect.c\n> @@ -1182,7 +1182,7 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n>  \t}\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>  \tstruct option options[] = {\n> diff --git a/git-bisect.sh b/git-bisect.sh\n> deleted file mode 100755\n> index 028d39cd9ce..00000000000\n> --- a/git-bisect.sh\n> +++ /dev/null\n> @@ -1,37 +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> -exec git bisect--helper \"$@\"\n> diff --git a/git.c b/git.c\n> index edda922ce6d..a8500132a28 100644\n> --- a/git.c\n> +++ b/git.c\n> @@ -490,7 +490,7 @@ static struct cmd_struct commands[] = {\n>  \t{ \"annotate\", cmd_annotate, RUN_SETUP | NO_PARSEOPT },\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\nThis should really be squashed into 07/11, and I think shows an unstated\nreason for why you probably ditched parse_options.\n\nI.e. you've stuck the descriptions of the command into what we'd in\nparse_options() put after a \"\" item. See builtin/blame.c for such a use.\n\nSo having this squashed would really make it clear how the \"-h\" output\nis different after this series (which is OK), and what strings are\nre-used or not etc.\n"},{"id":"447306","messageId":"CABPp-BHtki3WupjbeyoQu9Li0S0kQV5rXWC0RN8_Pt524iUZOw@mail.gmail.com","threadId":"57326","inReplyTo":"pull.1132.git.1643328752.gitgitgadget@gmail.com","subject":"Re: [PATCH 00/11] Finish converting git bisect into a built-in","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2022-01-30T06:39:35Z","receivedAt":"2022-01-30T06:39:51Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Fri, Jan 28, 2022 at 3:08 PM Johannes Schindelin via GitGitGadget\n<gitgitgadget@gmail.com> wrote:\n>\n> After three GSoC/Outreachy students spent an incredible effort on this, it\n> is finally time to put a neat little bow on it.\n>\n> Johannes Schindelin (11):\n>   bisect run: fix the error message\n>   bisect--helper: retire the --no-log option\n>   bisect--helper: really retire --bisect-next-check\n>   bisect--helper: really retire `--bisect-autostart`\n>   bisect--helper: align the sub-command order with git-bisect.sh\n>   bisect--helper: make `--bisect-state` optional\n>   bisect: move even the option parsing to `bisect--helper`\n>   bisect--helper: using `--bisect-state` without an argument is a bug\n>   Turn `git bisect` into a full built-in.\n>   bisect: remove Cogito-related code\n>   bisect: no longer try to clean up left-over `.git/head-name` files\n>\n>  Makefile                               |   3 +-\n>  bisect.c                               |   3 -\n>  builtin.h                              |   2 +-\n>  builtin/{bisect--helper.c => bisect.c} | 201 ++++++++++---------------\n>  git-bisect.sh                          |  84 -----------\n>  git.c                                  |   2 +-\n>  t/t6030-bisect-porcelain.sh            |   1 -\n>  7 files changed, 84 insertions(+), 212 deletions(-)\n>  rename builtin/{bisect--helper.c => bisect.c} (87%)\n>  delete mode 100755 git-bisect.sh\n\nI read through the series and couldn't spot any problems.\n"},{"id":"448000","messageId":"CABPp-BGk7-yRZddOWBq6FpZDr=nOKSbL7eyMJQnOycP9CFtRng@mail.gmail.com","threadId":"57326","inReplyTo":"93d19d85ee38f50019d5f05605ce7b5eca76cbd6.1643328752.git.gitgitgadget@gmail.com","subject":"Re: [PATCH 01/11] bisect run: fix the error message","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2022-02-08T22:05:53Z","receivedAt":"2022-02-08T22:25:05Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Fri, Jan 28, 2022 at 3:27 PM Johannes Schindelin via GitGitGadget\n<gitgitgadget@gmail.com> wrote:\n>\n> From: Johannes Schindelin <johannes.schindelin@gmx.de>\n>\n> In d1bbbe45df8 (bisect--helper: reimplement `bisect_run` shell function\n> in C, 2021-09-13), we ported the `bisect run` subcommand to C, including\n> the part that prints out an error message when the implicit `git bisect\n> bad` or `git bisect good` failed.\n>\n> However, the error message was supposed to print out whether the state\n> was \"good\" or \"bad\", but used a bogus (because non-populated) `args`\n> variable for it.\n>\n> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> ---\n>  builtin/bisect--helper.c | 8 ++------\n>  1 file changed, 2 insertions(+), 6 deletions(-)\n>\n> diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\n> index 28a2e6a5750..4208206af07 100644\n> --- a/builtin/bisect--helper.c\n> +++ b/builtin/bisect--helper.c\n> @@ -1093,7 +1093,6 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n>  {\n>         int res = BISECT_OK;\n>         struct strbuf command = STRBUF_INIT;\n> -       struct strvec args = STRVEC_INIT;\n>         struct strvec run_args = STRVEC_INIT;\n>         const char *new_state;\n>         int temporary_stdout_fd, saved_stdout;\n> @@ -1111,8 +1110,6 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n>         strvec_push(&run_args, command.buf);\n>\n>         while (1) {\n> -               strvec_clear(&args);\n> -\n>                 printf(_(\"running %s\\n\"), command.buf);\n>                 res = run_command_v_opt(run_args.v, RUN_USING_SHELL);\n>\n> @@ -1157,14 +1154,13 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n>                         printf(_(\"bisect found first bad commit\"));\n>                         res = BISECT_OK;\n>                 } else if (res) {\n> -                       error(_(\"bisect run failed: 'git bisect--helper --bisect-state\"\n> -                       \" %s' exited with error code %d\"), args.v[0], res);\n> +                       error(_(\"bisect run failed: 'git bisect\"\n> +                       \" %s' exited with error code %d\"), new_state, res);\n>                 } else {\n>                         continue;\n>                 }\n>\n>                 strbuf_release(&command);\n> -               strvec_clear(&args);\n>                 strvec_clear(&run_args);\n>                 return res;\n>         }\n> --\n> gitgitgadget\n\nGood catch.  Looks like this printed \"(null)\" on glibc, and probably\ncrashed elsewhere.  Perhaps it'd help to add a test that would have\ncaught this with something like (I'm hoping gmail doesn't corrupt\nthis):\n\ndiff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh\nindex 1be85d064e..28b54ba41b 100755\n--- a/t/t6030-bisect-porcelain.sh\n+++ b/t/t6030-bisect-porcelain.sh\n@@ -980,4 +980,15 @@ test_expect_success 'bisect visualize with a\nfilename with dash and space' '\n        git bisect visualize -p -- \"-hello 2\"\n '\n\n+test_expect_success 'testing' '\n+       git bisect reset &&\n+       git bisect start $HASH4 $HASH1 &&\n+       write_script test_script.sh <<-\\EOF &&\n+       rm .git/BISECT*\n+       EOF\n+       test_must_fail git bisect run ./test_script.sh 2>error &&\n+       cat error &&\n+       grep git.bisect.good..exited.with.error.code error\n+'\n+\n test_done\n\n\nAlso, as a side note, it appears that another error message in this\nsame function has a suboptimal error message, which could be fixed\nwith\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 28a2e6a575..6187d9fbcb 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1118,7 +1118,7 @@ static int bisect_run(struct bisect_terms\n*terms, const char **argv, int argc)\n\n                if (res < 0 || 128 <= res) {\n                        error(_(\"bisect run failed: exit code %d from\"\n-                               \" '%s' is < 0 or >= 128\"), res, command.buf);\n+                               \" %s is < 0 or >= 128\"), res, command.buf);\n                        strbuf_release(&command);\n                        return res;\n                }\n\nIn particular, the line of code just above here:\n      sq_quote_argv(&command, argv);\nmeans that we get double single quotes without this fix, which looks\nugly.  Of course, this doesn't need to be included in your series, but\nsince you're cleaning up other error messages anyway, I thought I'd at\nleast mention it.\n"},{"id":"448011","messageId":"CABPp-BHvGOH5copWukeTy55dXDz1yq47VJcrZRj_b8cZgTy_VQ@mail.gmail.com","threadId":"57326","inReplyTo":"eddbdde222a01113d8facdcb17d6ec85676edbe7.1643328752.git.gitgitgadget@gmail.com","subject":"Re: [PATCH 06/11] bisect--helper: make `--bisect-state` optional","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2022-02-08T23:03:14Z","receivedAt":"2022-02-08T23:03:32Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Fri, Jan 28, 2022 at 3:52 PM Johannes Schindelin via GitGitGadget\n<gitgitgadget@gmail.com> wrote:\n>\n> From: Johannes Schindelin <johannes.schindelin@gmx.de>\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 `--bisect-state`\n> option to be passed explicitly.\n>\n> To prepare for converting `bisect--helper` to a full built-in\n> implementation of `git bisect` (which must not require the\n> `--bisect-state` option to be specified at all), let's move the handling\n> toward the end of the `switch (cmdmode)` block.\n>\n> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> ---\n>  builtin/bisect--helper.c | 23 ++++++++++++++++-------\n>  1 file changed, 16 insertions(+), 7 deletions(-)\n>\n> diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\n> index cc5a9ca41b9..219fa99cd0b 100644\n> --- a/builtin/bisect--helper.c\n> +++ b/builtin/bisect--helper.c\n> @@ -26,8 +26,8 @@ static const char * const git_bisect_helper_usage[] = {\n>         N_(\"git bisect--helper --bisect-start [--term-{new,bad}=<term> --term-{old,good}=<term>]\"\n>                                             \" [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<paths>...]\"),\n>         N_(\"git bisect--helper --bisect-next\"),\n> -       N_(\"git bisect--helper --bisect-state (bad|new) [<rev>]\"),\n> -       N_(\"git bisect--helper --bisect-state (good|old) [<rev>...]\"),\n> +       N_(\"git bisect--helper [--bisect-state] (bad|new) [<rev>]\"),\n> +       N_(\"git bisect--helper [--bisect-state] (good|old) [<rev>...]\"),\n>         N_(\"git bisect--helper --bisect-replay <filename>\"),\n>         N_(\"git bisect--helper --bisect-skip [(<rev>|<range>)...]\"),\n>         N_(\"git bisect--helper --bisect-visualize\"),\n> @@ -1210,6 +1210,13 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n>                              git_bisect_helper_usage,\n>                              PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN);\n>\n> +       if (!cmdmode && argc > 0) {\n> +               set_terms(&terms, \"bad\", \"good\");\n> +               get_terms(&terms);\n> +               if (!check_and_set_terms(&terms, argv[0]))\n> +                       cmdmode = BISECT_STATE;\n> +       }\n> +\n>         if (!cmdmode)\n>                 usage_with_options(git_bisect_helper_usage, options);\n>\n> @@ -1218,11 +1225,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n>                 set_terms(&terms, \"bad\", \"good\");\n>                 res = bisect_start(&terms, argv, argc);\n>                 break;\n> -       case BISECT_STATE:\n> -               set_terms(&terms, \"bad\", \"good\");\n> -               get_terms(&terms);\n> -               res = bisect_state(&terms, argv, argc);\n> -               break;\n>         case BISECT_TERMS:\n>                 if (argc > 1)\n>                         return error(_(\"--bisect-terms requires 0 or 1 argument\"));\n> @@ -1265,6 +1267,13 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n>                 get_terms(&terms);\n>                 res = bisect_run(&terms, argv, argc);\n>                 break;\n> +       case BISECT_STATE:\n> +               if (!terms.term_good) {\n> +                       set_terms(&terms, \"bad\", \"good\");\n> +                       get_terms(&terms);\n> +               }\n> +               res = bisect_state(&terms, argv, argc);\n> +               break;\n>         default:\n>                 BUG(\"unknown subcommand %d\", cmdmode);\n>         }\n> --\n> gitgitgadget\n\nDoes it make sense to also include something like this:\n\ndiff --git a/git-bisect.sh b/git-bisect.sh\nindex 405cf76f2a..fbf56649d7 100755\n--- a/git-bisect.sh\n+++ b/git-bisect.sh\n@@ -60,7 +60,7 @@ case \"$#\" in\n        start)\n                git bisect--helper --bisect-start \"$@\" ;;\n        bad|good|new|old|\"$TERM_BAD\"|\"$TERM_GOOD\")\n-               git bisect--helper --bisect-state \"$cmd\" \"$@\" ;;\n+               git bisect--helper \"$cmd\" \"$@\" ;;\n        skip)\n                git bisect--helper --bisect-skip \"$@\" || exit;;\n        next)\n\nto prove that you've made it optional?  (Well, assuming one has run\nthe tests with that change, but I did...)\n"},{"id":"448017","messageId":"CABPp-BG9-UWGLF-P5Cboj4JTv10gUXwO3NjAAgFo6215oo2WHw@mail.gmail.com","threadId":"57326","inReplyTo":"515e86e20758ed7f5b4a8ce8f38bfbbac27ec42a.1643328752.git.gitgitgadget@gmail.com","subject":"Re: [PATCH 07/11] bisect: move even the option parsing to `bisect--helper`","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2022-02-09T00:12:32Z","receivedAt":"2022-02-09T00:12:50Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Fri, Jan 28, 2022 at 3:27 PM Johannes Schindelin via GitGitGadget\n<gitgitgadget@gmail.com> wrote:\n>\n> From: Johannes Schindelin <johannes.schindelin@gmx.de>\n>\n> On our journey to a fully built-in `git bisect`, this is the\n> second-to-last step.\n>\n> Side note: The `if (!strcmp(...)) ... else if (!strcmp(...)) ... else if\n> (!strcmp(...)) ...` chain seen in this patch was not actually the first\n> idea how to convert the command modes to sub-commands. Since the\n> `bisect--helper` command already used the `parse-opions` API with neatly\n> set-up command modes, naturally the idea was to use `PARSE_OPT_NODASH`\n> to support proper sub-commands instead. However, the `parse-options` API\n> is not set up for that, and even after making that option work with long\n> options, it turned out that `STOP_AT_NON_OPTION` and `KEEP_UNKNOWN`\n> would have to be used but these options were not designed to work\n> together. So it would appear as if a lot of work would have to be done\n> just to be able to use `parse_options()` just to parse the sub-command,\n> instead of a simple `if...else if` chain, the latter being a\n> dramatically simpler implementation. Therefore, we now keep the\n> `parse_options()` call primarily to support `-h` and little else.\n>\n> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> ---\n>  builtin/bisect--helper.c | 172 ++++++++++++++++-----------------------\n>  git-bisect.sh            |  49 +----------\n>  2 files changed, 72 insertions(+), 149 deletions(-)\n>\n> diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\n> index 219fa99cd0b..4450305c81c 100644\n> --- a/builtin/bisect--helper.c\n> +++ b/builtin/bisect--helper.c\n> @@ -20,18 +20,34 @@ 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> -       N_(\"git bisect--helper --bisect-reset [<commit>]\"),\n> -       N_(\"git bisect--helper --bisect-terms [--term-good | --term-old | --term-bad | --term-new]\"),\n> -       N_(\"git bisect--helper --bisect-start [--term-{new,bad}=<term> --term-{old,good}=<term>]\"\n> -                                           \" [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<paths>...]\"),\n> -       N_(\"git bisect--helper --bisect-next\"),\n> -       N_(\"git bisect--helper [--bisect-state] (bad|new) [<rev>]\"),\n> -       N_(\"git bisect--helper [--bisect-state] (good|old) [<rev>...]\"),\n> -       N_(\"git bisect--helper --bisect-replay <filename>\"),\n> -       N_(\"git bisect--helper --bisect-skip [(<rev>|<range>)...]\"),\n> -       N_(\"git bisect--helper --bisect-visualize\"),\n> -       N_(\"git bisect--helper --bisect-run <cmd>...\"),\n> +static const char * const git_bisect_usage[] = {\n> +       N_(\"git bisect help\\n\"\n> +          \"\\tprint this long help message.\"),\n> +       N_(\"git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>]\\n\"\n> +          \"\\t\\t [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<pathspec>...]\\n\"\n> +          \"\\treset bisect state and start bisection.\"),\n> +       N_(\"git bisect (bad|new) [<rev>]\\n\"\n> +          \"\\tmark <rev> a known-bad revision/\\n\"\n> +          \"\\t\\ta revision after change in a given property.\"),\n> +       N_(\"git bisect (good|old) [<rev>...]\\n\"\n> +          \"\\tmark <rev>... known-good revisions/\\n\"\n> +          \"\\t\\trevisions before change in a given property.\"),\n> +       N_(\"git bisect terms [--term-good | --term-bad]\\n\"\n> +          \"\\tshow the terms used for old and new commits (default: bad, good)\"),\n> +       N_(\"git bisect skip [(<rev>|<range>)...]\\n\"\n> +          \"\\tmark <rev>... untestable revisions.\"),\n> +       N_(\"git bisect next\\n\"\n> +          \"\\tfind next bisection to test and check it out.\"),\n> +       N_(\"git bisect reset [<commit>]\\n\"\n> +          \"\\tfinish bisection search and go back to commit.\"),\n> +       N_(\"git bisect (visualize|view)\\n\"\n> +          \"\\tshow bisect status in gitk.\"),\n> +       N_(\"git bisect replay <logfile>\\n\"\n> +          \"\\treplay bisection log.\"),\n> +       N_(\"git bisect log\\n\"\n> +          \"\\tshow bisect log.\"),\n> +       N_(\"git bisect run <cmd>...\\n\"\n> +          \"\\tuse <cmd>... to automatically bisect.\"),\n>         NULL\n>  };\n\nHooray on getting rid of the \"--helper\" and \"--bisect-\" portions of\nthe strings.  The manual whitespace splitting/indentation is a bit\nunfortunate, but you did address that in the commit message.\n\n> @@ -1168,115 +1184,69 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n>\n>  int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n>  {\n> -       enum {\n> -               BISECT_START = 1,\n> -               BISECT_STATE,\n> -               BISECT_TERMS,\n> -               BISECT_SKIP,\n> -               BISECT_NEXT,\n> -               BISECT_RESET,\n> -               BISECT_VISUALIZE,\n> -               BISECT_REPLAY,\n> -               BISECT_LOG,\n> -               BISECT_RUN,\n> -       } cmdmode = 0;\n>         int res = 0;\n>         struct option options[] = {\n> -               OPT_CMDMODE(0, \"bisect-start\", &cmdmode,\n> -                        N_(\"start the bisect session\"), BISECT_START),\n> -               OPT_CMDMODE(0, \"bisect-state\", &cmdmode,\n> -                        N_(\"mark the state of ref (or refs)\"), BISECT_STATE),\n> -               OPT_CMDMODE(0, \"bisect-terms\", &cmdmode,\n> -                        N_(\"print out the bisect terms\"), BISECT_TERMS),\n> -               OPT_CMDMODE(0, \"bisect-skip\", &cmdmode,\n> -                        N_(\"skip some commits for checkout\"), BISECT_SKIP),\n> -               OPT_CMDMODE(0, \"bisect-next\", &cmdmode,\n> -                        N_(\"find the next bisection commit\"), BISECT_NEXT),\n> -               OPT_CMDMODE(0, \"bisect-reset\", &cmdmode,\n> -                        N_(\"reset the bisection state\"), BISECT_RESET),\n> -               OPT_CMDMODE(0, \"bisect-visualize\", &cmdmode,\n> -                        N_(\"visualize the bisection\"), BISECT_VISUALIZE),\n> -               OPT_CMDMODE(0, \"bisect-replay\", &cmdmode,\n> -                        N_(\"replay the bisection process from the given file\"), BISECT_REPLAY),\n> -               OPT_CMDMODE(0, \"bisect-log\", &cmdmode,\n> -                        N_(\"list the bisection steps so far\"), BISECT_LOG),\n> -               OPT_CMDMODE(0, \"bisect-run\", &cmdmode,\n> -                        N_(\"use <cmd>... to automatically bisect.\"), BISECT_RUN),\n>                 OPT_END()\n>         };\n>         struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\n> +       const char *command = argc > 1 ? argv[1] : \"help\";\n>\n> -       argc = parse_options(argc, argv, prefix, options,\n> -                            git_bisect_helper_usage,\n> -                            PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN);\n> +       /* Handle -h and invalid options */\n> +       parse_options(argc - 1, argv + 1, prefix, options,\n> +                     git_bisect_usage,\n> +                     PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN |\n> +                     PARSE_OPT_ONE_SHOT | PARSE_OPT_STOP_AT_NON_OPTION);\n>\n> -       if (!cmdmode && argc > 0) {\n> +       if (!strcmp(\"help\", command))\n> +               usage_with_options(git_bisect_usage, options);\n\nI think the rest of the changes in this file would be much easier to\nread if you did a\n   argc -= 2\n   argv += 2\nhere...\n\n> +       else if (!strcmp(\"start\", command)) {\n\n...and dropped the else here, just starting a new 'if' instead.\n\n>                 set_terms(&terms, \"bad\", \"good\");\n> -               get_terms(&terms);\n> -               if (!check_and_set_terms(&terms, argv[0]))\n> -                       cmdmode = BISECT_STATE;\n> -       }\n> -\n> -       if (!cmdmode)\n> -               usage_with_options(git_bisect_helper_usage, options);\n> -\n> -       switch (cmdmode) {\n> -       case BISECT_START:\n> -               set_terms(&terms, \"bad\", \"good\");\n> -               res = bisect_start(&terms, argv, argc);\n> -               break;\n> -       case BISECT_TERMS:\n> -               if (argc > 1)\n> -                       return error(_(\"--bisect-terms requires 0 or 1 argument\"));\n> -               res = bisect_terms(&terms, argc == 1 ? argv[0] : NULL);\n> -               break;\n> -       case BISECT_SKIP:\n> +               res = bisect_start(&terms, argv + 2, argc - 2);\n> +       } else if (!strcmp(\"terms\", command)) {\n> +               if (argc > 3)\n> +                       return error(_(\"'terms' requires 0 or 1 argument\"));\n> +               res = bisect_terms(&terms, argc == 3 ? argv[2] : NULL);\n> +       } else if (!strcmp(\"skip\", command)) {\n>                 set_terms(&terms, \"bad\", \"good\");\n>                 get_terms(&terms);\n> -               res = bisect_skip(&terms, argv, argc);\n> -               break;\n> -       case BISECT_NEXT:\n> -               if (argc)\n> -                       return error(_(\"--bisect-next requires 0 arguments\"));\n> +               res = bisect_skip(&terms, argv + 2, argc - 2);\n> +       } else if (!strcmp(\"next\", command)) {\n> +               if (argc != 2)\n> +                       return error(_(\"'next' requires 0 arguments\"));\n>                 get_terms(&terms);\n>                 res = bisect_next(&terms, prefix);\n> -               break;\n> -       case BISECT_RESET:\n> -               if (argc > 1)\n> -                       return error(_(\"--bisect-reset requires either no argument or a commit\"));\n> -               res = bisect_reset(argc ? argv[0] : NULL);\n> -               break;\n> -       case BISECT_VISUALIZE:\n> +       } else if (!strcmp(\"reset\", command)) {\n> +               if (argc > 3)\n> +                       return error(_(\"'reset' requires either no argument or a commit\"));\n> +               res = bisect_reset(argc > 2 ? argv[2] : NULL);\n> +       } else if (one_of(command, \"visualize\", \"view\", NULL)) {\n>                 get_terms(&terms);\n> -               res = bisect_visualize(&terms, argv, argc);\n> -               break;\n> -       case BISECT_REPLAY:\n> -               if (argc != 1)\n> +               res = bisect_visualize(&terms, argv + 2, argc - 2);\n> +       } else if (!strcmp(\"replay\", command)) {\n> +               if (argc != 3)\n>                         return error(_(\"no logfile given\"));\n>                 set_terms(&terms, \"bad\", \"good\");\n> -               res = bisect_replay(&terms, argv[0]);\n> -               break;\n> -       case BISECT_LOG:\n> -               if (argc)\n> -                       return error(_(\"--bisect-log requires 0 arguments\"));\n> +               res = bisect_replay(&terms, argv[2]);\n> +       } else if (!strcmp(\"log\", command)) {\n> +               if (argc > 2)\n> +                       return error(_(\"'log' requires 0 arguments\"));\n>                 res = bisect_log();\n> -               break;\n> -       case BISECT_RUN:\n> -               if (!argc)\n> +       } else if (!strcmp(\"run\", command)) {\n> +               if (argc < 3)\n>                         return error(_(\"bisect run failed: no command provided.\"));\n>                 get_terms(&terms);\n> -               res = bisect_run(&terms, argv, argc);\n> -               break;\n> -       case BISECT_STATE:\n> -               if (!terms.term_good) {\n> -                       set_terms(&terms, \"bad\", \"good\");\n> -                       get_terms(&terms);\n> +               res = bisect_run(&terms, argv + 2, argc - 2);\n> +       } else {\n> +               set_terms(&terms, \"bad\", \"good\");\n> +               get_terms(&terms);\n> +               if (!check_and_set_terms(&terms, command))\n> +                       res = bisect_state(&terms, argv + 1, argc - 1);\n\nOh, hmm... this one is +1,-1 while all others are +2,-2, because there\nis not a separate \"command\"; the command was implicit and so that\nreserved argument is actually part of the terms.  Still if we did the\noffset by two trick above, I guess we'd just add a comment here and do\nargv-1, argc+1?\n\n> +               else {\n> +                       char *msg = xstrfmt(_(\"unknown command: '%s'\"), command);\n> +                       usage_msg_opt(msg, git_bisect_usage, options);\n>                 }\n> -               res = bisect_state(&terms, argv, argc);\n> -               break;\n> -       default:\n> -               BUG(\"unknown subcommand %d\", cmdmode);\n>         }\n> +\n>         free_terms(&terms);\n>\n>         /*\n> diff --git a/git-bisect.sh b/git-bisect.sh\n> index 405cf76f2a3..028d39cd9ce 100755\n> --- a/git-bisect.sh\n> +++ b/git-bisect.sh\n> @@ -34,51 +34,4 @@ 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> -       if test -s \"$GIT_DIR/BISECT_TERMS\"\n> -       then\n> -               {\n> -               read TERM_BAD\n> -               read TERM_GOOD\n> -               } <\"$GIT_DIR/BISECT_TERMS\"\n> -       fi\n> -}\n> -\n> -case \"$#\" in\n> -0)\n> -       usage ;;\n> -*)\n> -       cmd=\"$1\"\n> -       get_terms\n> -       shift\n> -       case \"$cmd\" in\n> -       help)\n> -               git bisect -h ;;\n> -       start)\n> -               git bisect--helper --bisect-start \"$@\" ;;\n> -       bad|good|new|old|\"$TERM_BAD\"|\"$TERM_GOOD\")\n> -               git bisect--helper --bisect-state \"$cmd\" \"$@\" ;;\n> -       skip)\n> -               git bisect--helper --bisect-skip \"$@\" || exit;;\n> -       next)\n> -               # Not sure we want \"next\" at the UI level anymore.\n> -               git bisect--helper --bisect-next \"$@\" || exit ;;\n> -       visualize|view)\n> -               git bisect--helper --bisect-visualize \"$@\" || exit;;\n> -       reset)\n> -               git bisect--helper --bisect-reset \"$@\" ;;\n> -       replay)\n> -               git bisect--helper --bisect-replay \"$@\" || exit;;\n> -       log)\n> -               git bisect--helper --bisect-log || exit ;;\n> -       run)\n> -               git bisect--helper --bisect-run \"$@\" || exit;;\n> -       terms)\n> -               git bisect--helper --bisect-terms \"$@\" || exit;;\n> -       *)\n> -               usage ;;\n> -       esac\n> -esac\n> +exec git bisect--helper \"$@\"\n\nThis is a really nice cleanup to git-bisect.sh.  :-)\n"},{"id":"448018","messageId":"CABPp-BFfaOmmW6aX=3nyLQjKsK7Y7cNMKRUqGHTgSdGP3F1=-g@mail.gmail.com","threadId":"57326","inReplyTo":"1b14ed3d7976b8fe4149822dcbb32343e0554a38.1643328752.git.gitgitgadget@gmail.com","subject":"Re: [PATCH 08/11] bisect--helper: using `--bisect-state` without an argument is a bug","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2022-02-09T00:26:23Z","receivedAt":"2022-02-09T00:26:38Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Fri, Jan 28, 2022 at 3:30 PM Johannes Schindelin via GitGitGadget\n<gitgitgadget@gmail.com> wrote:\n>\n> From: Johannes Schindelin <johannes.schindelin@gmx.de>\n>\n> The `bisect--helper` command is not expected to be used directly by the\n> user. Therefore, it is a bug if it receives no argument to the\n> `--bisect-state` command mode, not a user error. Which means that we\n> need to call `BUG()` instead of `die()`.\n>\n> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> ---\n>  builtin/bisect--helper.c | 2 +-\n>  1 file changed, 1 insertion(+), 1 deletion(-)\n>\n> diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\n> index 4450305c81c..009c919a989 100644\n> --- a/builtin/bisect--helper.c\n> +++ b/builtin/bisect--helper.c\n> @@ -872,7 +872,7 @@ static enum bisect_error bisect_state(struct bisect_terms *terms, const char **a\n>         struct oid_array revs = OID_ARRAY_INIT;\n>\n>         if (!argc)\n> -               return error(_(\"Please call `--bisect-state` with at least one argument\"));\n> +               BUG(\"bisect_state() called without argument\");\n>\n>         if (bisect_autostart(terms))\n>                 return BISECT_FAILED;\n> --\n> gitgitgadget\n\nMakes sense.\n"},{"id":"448031","messageId":"CABPp-BEyFmsqQiO8+1JRw3R=XFVOFNXxmEMphPhu-OXVwUxAXw@mail.gmail.com","threadId":"57326","inReplyTo":"CABPp-BHtki3WupjbeyoQu9Li0S0kQV5rXWC0RN8_Pt524iUZOw@mail.gmail.com","subject":"Re: [PATCH 00/11] Finish converting git bisect into a built-in","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2022-02-09T04:41:23Z","receivedAt":"2022-02-09T05:14:41Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Sat, Jan 29, 2022 at 10:39 PM Elijah Newren <newren@gmail.com> wrote:\n>\n> On Fri, Jan 28, 2022 at 3:08 PM Johannes Schindelin via GitGitGadget\n> <gitgitgadget@gmail.com> wrote:\n> >\n> > After three GSoC/Outreachy students spent an incredible effort on this, it\n> > is finally time to put a neat little bow on it.\n> >\n> > Johannes Schindelin (11):\n> >   bisect run: fix the error message\n> >   bisect--helper: retire the --no-log option\n> >   bisect--helper: really retire --bisect-next-check\n> >   bisect--helper: really retire `--bisect-autostart`\n> >   bisect--helper: align the sub-command order with git-bisect.sh\n> >   bisect--helper: make `--bisect-state` optional\n> >   bisect: move even the option parsing to `bisect--helper`\n> >   bisect--helper: using `--bisect-state` without an argument is a bug\n> >   Turn `git bisect` into a full built-in.\n> >   bisect: remove Cogito-related code\n> >   bisect: no longer try to clean up left-over `.git/head-name` files\n> >\n> >  Makefile                               |   3 +-\n> >  bisect.c                               |   3 -\n> >  builtin.h                              |   2 +-\n> >  builtin/{bisect--helper.c => bisect.c} | 201 ++++++++++---------------\n> >  git-bisect.sh                          |  84 -----------\n> >  git.c                                  |   2 +-\n> >  t/t6030-bisect-porcelain.sh            |   1 -\n> >  7 files changed, 84 insertions(+), 212 deletions(-)\n> >  rename builtin/{bisect--helper.c => bisect.c} (87%)\n> >  delete mode 100755 git-bisect.sh\n>\n> I read through the series and couldn't spot any problems.\n\nI re-read the series, taking a closer look.  Spotted a few minor\nthings (and left some comments) but the series looks pretty good to\nme.  I think Dscho's on vacation, so we'll resume the discussion when\nhe gets back.\n"},{"id":"448071","messageId":"xmqqh7977rj8.fsf@gitster.g","threadId":"57326","inReplyTo":"eddbdde222a01113d8facdcb17d6ec85676edbe7.1643328752.git.gitgitgadget@gmail.com","subject":"Re: [PATCH 06/11] bisect--helper: make `--bisect-state` optional","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-02-09T19:45:31Z","receivedAt":"2022-02-09T19:45:42Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Johannes Schindelin via GitGitGadget\" <gitgitgadget@gmail.com>\nwrites:\n\n> @@ -1210,6 +1210,13 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n>  \t\t\t     git_bisect_helper_usage,\n>  \t\t\t     PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN);\n>  \n> +\tif (!cmdmode && argc > 0) {\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\tcmdmode = BISECT_STATE;\n> +\t}\n> +\n\nI do agree with \"if we want to reuse this function without changing\nit much, --bisect-state must become an optional and the default mode\nof operation\" as a goal, but I do not quite get this change.  From\nthe rephased description of the goal, what I would expect is more\nlike\n\n\tif (!cmdmode && possibly-other-conditions-like-argc-check)\n\t\tcmdmode = BISECT_STATE;\n\nand nothing else.  Between the case where --bisect-state was and was\nnot given explicitly, check-and-set-terms is or is not called.  I\ncan see that checking would be _nice_ when we try to decide if the\nfirst token makes sense as good/bad and the user wanted to do the\n\"state\" thing impolicitly, but if it is worth checking in implicit\ncase, shouldn't we be checking when the --bisect-state is explicitly\ngiven as well?\n\nAnd the actual execution of the BISECT_STATE command is even more\npuzzling, below.\n\n>  \tif (!cmdmode)\n>  \t\tusage_with_options(git_bisect_helper_usage, options);\n>  \n> @@ -1218,11 +1225,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n>  \t\tset_terms(&terms, \"bad\", \"good\");\n>  \t\tres = bisect_start(&terms, argv, argc);\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_TERMS:\n>  \t\tif (argc > 1)\n>  \t\t\treturn error(_(\"--bisect-terms requires 0 or 1 argument\"));\n> @@ -1265,6 +1267,13 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n>  \t\tget_terms(&terms);\n>  \t\tres = bisect_run(&terms, argv, argc);\n>  \t\tbreak;\n> +\tcase BISECT_STATE:\n> +\t\tif (!terms.term_good) {\n> +\t\t\tset_terms(&terms, \"bad\", \"good\");\n> +\t\t\tget_terms(&terms);\n> +\t\t}\n> +\t\tres = bisect_state(&terms, argv, argc);\n> +\t\tbreak;\n\nThis case arm has been moved but because there is no fall-through in\nthis switch statement, the movement is a no-op.  But the code has\nalso changed with this patch.  We used to do set_terms/get_terms\nunconditionally, but we do not even do so when terms_good (but not\nterms_bad) is already set.\n\nIs this an unrelated bugfix of some kind?  This does not look\nrelated to \"making --bisect-state optional and implicit default\" at\nall.  At least the proposed log message does not explain why.\n\nThanks.\n\n>  \tdefault:\n>  \t\tBUG(\"unknown subcommand %d\", cmdmode);\n>  \t}\n"},{"id":"449137","messageId":"nycvar.QRO.7.76.6.2202221537520.11118@tvgsbejvaqbjf.bet","threadId":"57326","inReplyTo":"CABPp-BGk7-yRZddOWBq6FpZDr=nOKSbL7eyMJQnOycP9CFtRng@mail.gmail.com","subject":"Re: [PATCH 01/11] bisect run: fix the error message","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2022-02-22T14:38:36Z","receivedAt":"2022-02-22T14:38:45Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Elijah,\n\nOn Tue, 8 Feb 2022, Elijah Newren wrote:\n\n> On Fri, Jan 28, 2022 at 3:27 PM Johannes Schindelin via GitGitGadget\n> <gitgitgadget@gmail.com> wrote:\n> >\n> > From: Johannes Schindelin <johannes.schindelin@gmx.de>\n> >\n> > In d1bbbe45df8 (bisect--helper: reimplement `bisect_run` shell function\n> > in C, 2021-09-13), we ported the `bisect run` subcommand to C, including\n> > the part that prints out an error message when the implicit `git bisect\n> > bad` or `git bisect good` failed.\n> >\n> > However, the error message was supposed to print out whether the state\n> > was \"good\" or \"bad\", but used a bogus (because non-populated) `args`\n> > variable for it.\n> >\n> > Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> > ---\n> >  builtin/bisect--helper.c | 8 ++------\n> >  1 file changed, 2 insertions(+), 6 deletions(-)\n> >\n> > diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\n> > index 28a2e6a5750..4208206af07 100644\n> > --- a/builtin/bisect--helper.c\n> > +++ b/builtin/bisect--helper.c\n> > @@ -1093,7 +1093,6 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n> >  {\n> >         int res = BISECT_OK;\n> >         struct strbuf command = STRBUF_INIT;\n> > -       struct strvec args = STRVEC_INIT;\n> >         struct strvec run_args = STRVEC_INIT;\n> >         const char *new_state;\n> >         int temporary_stdout_fd, saved_stdout;\n> > @@ -1111,8 +1110,6 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n> >         strvec_push(&run_args, command.buf);\n> >\n> >         while (1) {\n> > -               strvec_clear(&args);\n> > -\n> >                 printf(_(\"running %s\\n\"), command.buf);\n> >                 res = run_command_v_opt(run_args.v, RUN_USING_SHELL);\n> >\n> > @@ -1157,14 +1154,13 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n> >                         printf(_(\"bisect found first bad commit\"));\n> >                         res = BISECT_OK;\n> >                 } else if (res) {\n> > -                       error(_(\"bisect run failed: 'git bisect--helper --bisect-state\"\n> > -                       \" %s' exited with error code %d\"), args.v[0], res);\n> > +                       error(_(\"bisect run failed: 'git bisect\"\n> > +                       \" %s' exited with error code %d\"), new_state, res);\n> >                 } else {\n> >                         continue;\n> >                 }\n> >\n> >                 strbuf_release(&command);\n> > -               strvec_clear(&args);\n> >                 strvec_clear(&run_args);\n> >                 return res;\n> >         }\n> > --\n> > gitgitgadget\n>\n> Good catch.  Looks like this printed \"(null)\" on glibc, and probably\n> crashed elsewhere.  Perhaps it'd help to add a test that would have\n> caught this with something like (I'm hoping gmail doesn't corrupt\n> this):\n>\n> diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh\n> index 1be85d064e..28b54ba41b 100755\n> --- a/t/t6030-bisect-porcelain.sh\n> +++ b/t/t6030-bisect-porcelain.sh\n> @@ -980,4 +980,15 @@ test_expect_success 'bisect visualize with a\n> filename with dash and space' '\n>         git bisect visualize -p -- \"-hello 2\"\n>  '\n>\n> +test_expect_success 'testing' '\n> +       git bisect reset &&\n> +       git bisect start $HASH4 $HASH1 &&\n> +       write_script test_script.sh <<-\\EOF &&\n> +       rm .git/BISECT*\n> +       EOF\n> +       test_must_fail git bisect run ./test_script.sh 2>error &&\n> +       cat error &&\n> +       grep git.bisect.good..exited.with.error.code error\n> +'\n> +\n>  test_done\n\nExcellent, thank you!\n\n> Also, as a side note, it appears that another error message in this\n> same function has a suboptimal error message, which could be fixed\n> with\n>\n> diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\n> index 28a2e6a575..6187d9fbcb 100644\n> --- a/builtin/bisect--helper.c\n> +++ b/builtin/bisect--helper.c\n> @@ -1118,7 +1118,7 @@ static int bisect_run(struct bisect_terms\n> *terms, const char **argv, int argc)\n>\n>                 if (res < 0 || 128 <= res) {\n>                         error(_(\"bisect run failed: exit code %d from\"\n> -                               \" '%s' is < 0 or >= 128\"), res, command.buf);\n> +                               \" %s is < 0 or >= 128\"), res, command.buf);\n>                         strbuf_release(&command);\n>                         return res;\n>                 }\n>\n> In particular, the line of code just above here:\n>       sq_quote_argv(&command, argv);\n> means that we get double single quotes without this fix, which looks\n> ugly.  Of course, this doesn't need to be included in your series, but\n> since you're cleaning up other error messages anyway, I thought I'd at\n> least mention it.\n\nSure, and I think it is not _too_ much out of scope to fix it in the same\npatch series, too.\n\nThank you!\nDscho\n"},{"id":"449138","messageId":"nycvar.QRO.7.76.6.2202221612020.11118@tvgsbejvaqbjf.bet","threadId":"57326","inReplyTo":"CABPp-BHvGOH5copWukeTy55dXDz1yq47VJcrZRj_b8cZgTy_VQ@mail.gmail.com","subject":"Re: [PATCH 06/11] bisect--helper: make `--bisect-state` optional","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2022-02-22T15:12:43Z","receivedAt":"2022-02-22T15:12:58Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Elijah,\n\nOn Tue, 8 Feb 2022, Elijah Newren wrote:\n\n> On Fri, Jan 28, 2022 at 3:52 PM Johannes Schindelin via GitGitGadget\n> <gitgitgadget@gmail.com> wrote:\n> >\n> > From: Johannes Schindelin <johannes.schindelin@gmx.de>\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 `--bisect-state`\n> > option to be passed explicitly.\n> >\n> > To prepare for converting `bisect--helper` to a full built-in\n> > implementation of `git bisect` (which must not require the\n> > `--bisect-state` option to be specified at all), let's move the handling\n> > toward the end of the `switch (cmdmode)` block.\n> >\n> > Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> > ---\n> >  builtin/bisect--helper.c | 23 ++++++++++++++++-------\n> >  1 file changed, 16 insertions(+), 7 deletions(-)\n> >\n> > diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\n> > index cc5a9ca41b9..219fa99cd0b 100644\n> > --- a/builtin/bisect--helper.c\n> > +++ b/builtin/bisect--helper.c\n> > @@ -26,8 +26,8 @@ static const char * const git_bisect_helper_usage[] = {\n> >         N_(\"git bisect--helper --bisect-start [--term-{new,bad}=<term> --term-{old,good}=<term>]\"\n> >                                             \" [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<paths>...]\"),\n> >         N_(\"git bisect--helper --bisect-next\"),\n> > -       N_(\"git bisect--helper --bisect-state (bad|new) [<rev>]\"),\n> > -       N_(\"git bisect--helper --bisect-state (good|old) [<rev>...]\"),\n> > +       N_(\"git bisect--helper [--bisect-state] (bad|new) [<rev>]\"),\n> > +       N_(\"git bisect--helper [--bisect-state] (good|old) [<rev>...]\"),\n> >         N_(\"git bisect--helper --bisect-replay <filename>\"),\n> >         N_(\"git bisect--helper --bisect-skip [(<rev>|<range>)...]\"),\n> >         N_(\"git bisect--helper --bisect-visualize\"),\n> > @@ -1210,6 +1210,13 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n> >                              git_bisect_helper_usage,\n> >                              PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN);\n> >\n> > +       if (!cmdmode && argc > 0) {\n> > +               set_terms(&terms, \"bad\", \"good\");\n> > +               get_terms(&terms);\n> > +               if (!check_and_set_terms(&terms, argv[0]))\n> > +                       cmdmode = BISECT_STATE;\n> > +       }\n> > +\n> >         if (!cmdmode)\n> >                 usage_with_options(git_bisect_helper_usage, options);\n> >\n> > @@ -1218,11 +1225,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n> >                 set_terms(&terms, \"bad\", \"good\");\n> >                 res = bisect_start(&terms, argv, argc);\n> >                 break;\n> > -       case BISECT_STATE:\n> > -               set_terms(&terms, \"bad\", \"good\");\n> > -               get_terms(&terms);\n> > -               res = bisect_state(&terms, argv, argc);\n> > -               break;\n> >         case BISECT_TERMS:\n> >                 if (argc > 1)\n> >                         return error(_(\"--bisect-terms requires 0 or 1 argument\"));\n> > @@ -1265,6 +1267,13 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n> >                 get_terms(&terms);\n> >                 res = bisect_run(&terms, argv, argc);\n> >                 break;\n> > +       case BISECT_STATE:\n> > +               if (!terms.term_good) {\n> > +                       set_terms(&terms, \"bad\", \"good\");\n> > +                       get_terms(&terms);\n> > +               }\n> > +               res = bisect_state(&terms, argv, argc);\n> > +               break;\n> >         default:\n> >                 BUG(\"unknown subcommand %d\", cmdmode);\n> >         }\n> > --\n> > gitgitgadget\n>\n> Does it make sense to also include something like this:\n>\n> diff --git a/git-bisect.sh b/git-bisect.sh\n> index 405cf76f2a..fbf56649d7 100755\n> --- a/git-bisect.sh\n> +++ b/git-bisect.sh\n> @@ -60,7 +60,7 @@ case \"$#\" in\n>         start)\n>                 git bisect--helper --bisect-start \"$@\" ;;\n>         bad|good|new|old|\"$TERM_BAD\"|\"$TERM_GOOD\")\n> -               git bisect--helper --bisect-state \"$cmd\" \"$@\" ;;\n> +               git bisect--helper \"$cmd\" \"$@\" ;;\n>         skip)\n>                 git bisect--helper --bisect-skip \"$@\" || exit;;\n>         next)\n>\n> to prove that you've made it optional?  (Well, assuming one has run\n> the tests with that change, but I did...)\n\nGood point! That code will go away within the same patch series, of\ncourse, but it is good to keep this in an intermediate commit.\n\nThanks,\nDscho\n"},{"id":"449143","messageId":"nycvar.QRO.7.76.6.2202221648190.11118@tvgsbejvaqbjf.bet","threadId":"57326","inReplyTo":"CABPp-BG9-UWGLF-P5Cboj4JTv10gUXwO3NjAAgFo6215oo2WHw@mail.gmail.com","subject":"Re: [PATCH 07/11] bisect: move even the option parsing to `bisect--helper`","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2022-02-22T15:49:55Z","receivedAt":"2022-02-22T15:50:03Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Elijah,\n\nOn Tue, 8 Feb 2022, Elijah Newren wrote:\n\n> On Fri, Jan 28, 2022 at 3:27 PM Johannes Schindelin via GitGitGadget\n> <gitgitgadget@gmail.com> wrote:\n>\n> > [...]\n> > +       const char *command = argc > 1 ? argv[1] : \"help\";\n> >\n> > -       argc = parse_options(argc, argv, prefix, options,\n> > -                            git_bisect_helper_usage,\n> > -                            PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN);\n> > +       /* Handle -h and invalid options */\n> > +       parse_options(argc - 1, argv + 1, prefix, options,\n> > +                     git_bisect_usage,\n> > +                     PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN |\n> > +                     PARSE_OPT_ONE_SHOT | PARSE_OPT_STOP_AT_NON_OPTION);\n> >\n> > -       if (!cmdmode && argc > 0) {\n> > +       if (!strcmp(\"help\", command))\n> > +               usage_with_options(git_bisect_usage, options);\n>\n> I think the rest of the changes in this file would be much easier to\n> read if you did a\n>    argc -= 2\n>    argv += 2\n> here...\n>\n> > +       else if (!strcmp(\"start\", command)) {\n>\n> ...and dropped the else here, just starting a new 'if' instead.\n\nMakes sense.\n\nWhile at it, I also explicitly handle the `-h` case and no longer bother\nwith the `parse_options()` call at all anymore.\n\n>\n> >                 set_terms(&terms, \"bad\", \"good\");\n> > -               get_terms(&terms);\n> > -               if (!check_and_set_terms(&terms, argv[0]))\n> > -                       cmdmode = BISECT_STATE;\n> > -       }\n> > -\n> > -       if (!cmdmode)\n> > -               usage_with_options(git_bisect_helper_usage, options);\n> > -\n> > -       switch (cmdmode) {\n> > -       case BISECT_START:\n> > -               set_terms(&terms, \"bad\", \"good\");\n> > -               res = bisect_start(&terms, argv, argc);\n> > -               break;\n> > -       case BISECT_TERMS:\n> > -               if (argc > 1)\n> > -                       return error(_(\"--bisect-terms requires 0 or 1 argument\"));\n> > -               res = bisect_terms(&terms, argc == 1 ? argv[0] : NULL);\n> > -               break;\n> > -       case BISECT_SKIP:\n> > +               res = bisect_start(&terms, argv + 2, argc - 2);\n> > +       } else if (!strcmp(\"terms\", command)) {\n> > +               if (argc > 3)\n> > +                       return error(_(\"'terms' requires 0 or 1 argument\"));\n> > +               res = bisect_terms(&terms, argc == 3 ? argv[2] : NULL);\n> > +       } else if (!strcmp(\"skip\", command)) {\n> >                 set_terms(&terms, \"bad\", \"good\");\n> >                 get_terms(&terms);\n> > -               res = bisect_skip(&terms, argv, argc);\n> > -               break;\n> > -       case BISECT_NEXT:\n> > -               if (argc)\n> > -                       return error(_(\"--bisect-next requires 0 arguments\"));\n> > +               res = bisect_skip(&terms, argv + 2, argc - 2);\n> > +       } else if (!strcmp(\"next\", command)) {\n> > +               if (argc != 2)\n> > +                       return error(_(\"'next' requires 0 arguments\"));\n> >                 get_terms(&terms);\n> >                 res = bisect_next(&terms, prefix);\n> > -               break;\n> > -       case BISECT_RESET:\n> > -               if (argc > 1)\n> > -                       return error(_(\"--bisect-reset requires either no argument or a commit\"));\n> > -               res = bisect_reset(argc ? argv[0] : NULL);\n> > -               break;\n> > -       case BISECT_VISUALIZE:\n> > +       } else if (!strcmp(\"reset\", command)) {\n> > +               if (argc > 3)\n> > +                       return error(_(\"'reset' requires either no argument or a commit\"));\n> > +               res = bisect_reset(argc > 2 ? argv[2] : NULL);\n> > +       } else if (one_of(command, \"visualize\", \"view\", NULL)) {\n> >                 get_terms(&terms);\n> > -               res = bisect_visualize(&terms, argv, argc);\n> > -               break;\n> > -       case BISECT_REPLAY:\n> > -               if (argc != 1)\n> > +               res = bisect_visualize(&terms, argv + 2, argc - 2);\n> > +       } else if (!strcmp(\"replay\", command)) {\n> > +               if (argc != 3)\n> >                         return error(_(\"no logfile given\"));\n> >                 set_terms(&terms, \"bad\", \"good\");\n> > -               res = bisect_replay(&terms, argv[0]);\n> > -               break;\n> > -       case BISECT_LOG:\n> > -               if (argc)\n> > -                       return error(_(\"--bisect-log requires 0 arguments\"));\n> > +               res = bisect_replay(&terms, argv[2]);\n> > +       } else if (!strcmp(\"log\", command)) {\n> > +               if (argc > 2)\n> > +                       return error(_(\"'log' requires 0 arguments\"));\n> >                 res = bisect_log();\n> > -               break;\n> > -       case BISECT_RUN:\n> > -               if (!argc)\n> > +       } else if (!strcmp(\"run\", command)) {\n> > +               if (argc < 3)\n> >                         return error(_(\"bisect run failed: no command provided.\"));\n> >                 get_terms(&terms);\n> > -               res = bisect_run(&terms, argv, argc);\n> > -               break;\n> > -       case BISECT_STATE:\n> > -               if (!terms.term_good) {\n> > -                       set_terms(&terms, \"bad\", \"good\");\n> > -                       get_terms(&terms);\n> > +               res = bisect_run(&terms, argv + 2, argc - 2);\n> > +       } else {\n> > +               set_terms(&terms, \"bad\", \"good\");\n> > +               get_terms(&terms);\n> > +               if (!check_and_set_terms(&terms, command))\n> > +                       res = bisect_state(&terms, argv + 1, argc - 1);\n>\n> Oh, hmm... this one is +1,-1 while all others are +2,-2, because there\n> is not a separate \"command\"; the command was implicit and so that\n> reserved argument is actually part of the terms.  Still if we did the\n> offset by two trick above, I guess we'd just add a comment here and do\n> argv-1, argc+1?\n\nRight, we can just \"shift the command back in\".\n\nThank you,\nDscho\n"},{"id":"449144","messageId":"nycvar.QRO.7.76.6.2202221544300.11118@tvgsbejvaqbjf.bet","threadId":"57326","inReplyTo":"xmqqh7977rj8.fsf@gitster.g","subject":"Re: [PATCH 06/11] bisect--helper: make `--bisect-state` optional","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2022-02-22T15:53:08Z","receivedAt":"2022-02-22T15:53:26Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Wed, 9 Feb 2022, Junio C Hamano wrote:\n\n> \"Johannes Schindelin via GitGitGadget\" <gitgitgadget@gmail.com>\n> writes:\n>\n> > @@ -1210,6 +1210,13 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n> >  \t\t\t     git_bisect_helper_usage,\n> >  \t\t\t     PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN);\n> >\n> > +\tif (!cmdmode && argc > 0) {\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\tcmdmode = BISECT_STATE;\n> > +\t}\n> > +\n>\n> I do agree with \"if we want to reuse this function without changing\n> it much, --bisect-state must become an optional and the default mode\n> of operation\" as a goal, but I do not quite get this change.  From\n> the rephased description of the goal, what I would expect is more\n> like\n>\n> \tif (!cmdmode && possibly-other-conditions-like-argc-check)\n> \t\tcmdmode = BISECT_STATE;\n>\n> and nothing else.\n\nThat would not work, though: we must ensure that the `argv[0]` is a\nbad/good term (hence the need to call `set_terms()` and `get_terms()` to\nretrieve potentially overridden terms and then the call to\n`check_and_set_terms()` to verify that it was one of those terms).\n\n> Between the case where --bisect-state was and was not given explicitly,\n> check-and-set-terms is or is not called.  I\n> can see that checking would be _nice_ when we try to decide if the\n> first token makes sense as good/bad and the user wanted to do the\n> \"state\" thing impolicitly, but if it is worth checking in implicit\n> case, shouldn't we be checking when the --bisect-state is explicitly\n> given as well?\n\nI tried to keep the `if (!cmdmode) usage...` in place, and that's probably\nwhat caused your confusion. I replaced it with:\n\n-- snip --\n@@ -1210,10 +1210,7 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n                             git_bisect_helper_usage,\n                             PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN);\n\n-       if (!cmdmode)\n-               usage_with_options(git_bisect_helper_usage, options);\n-\n-       switch (cmdmode) {\n+       switch (cmdmode ? cmdmode : BISECT_STATE) {\n        case BISECT_START:\n                set_terms(&terms, \"bad\", \"good\");\n                res = bisect_start(&terms, argv, argc);\n@@ -1221,6 +1218,11 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n        case BISECT_STATE:\n                set_terms(&terms, \"bad\", \"good\");\n                get_terms(&terms);\n+               if (!cmdmode &&\n+                   (!argc || check_and_set_terms(&terms, argv[0]))) {\n+                       char *msg = xstrfmt(_(\"unknown command: '%s'\"), argv[0]);\n+                       usage_msg_opt(msg, git_bisect_helper_usage, options);\n+               }\n                res = bisect_state(&terms, argv, argc);\n                break;\n        case BISECT_TERMS:\n-- snap --\n\nI am not the best judge whether this is more obvious because I am so\nfamiliar with this code, but I hope that it is at least more concise.\n\n> And the actual execution of the BISECT_STATE command is even more\n> puzzling, below.\n>\n> >  \tif (!cmdmode)\n> >  \t\tusage_with_options(git_bisect_helper_usage, options);\n> >\n> > @@ -1218,11 +1225,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n> >  \t\tset_terms(&terms, \"bad\", \"good\");\n> >  \t\tres = bisect_start(&terms, argv, argc);\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_TERMS:\n> >  \t\tif (argc > 1)\n> >  \t\t\treturn error(_(\"--bisect-terms requires 0 or 1 argument\"));\n> > @@ -1265,6 +1267,13 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n> >  \t\tget_terms(&terms);\n> >  \t\tres = bisect_run(&terms, argv, argc);\n> >  \t\tbreak;\n> > +\tcase BISECT_STATE:\n> > +\t\tif (!terms.term_good) {\n> > +\t\t\tset_terms(&terms, \"bad\", \"good\");\n> > +\t\t\tget_terms(&terms);\n> > +\t\t}\n> > +\t\tres = bisect_state(&terms, argv, argc);\n> > +\t\tbreak;\n>\n> This case arm has been moved but because there is no fall-through in\n> this switch statement, the movement is a no-op.  But the code has\n> also changed with this patch.  We used to do set_terms/get_terms\n> unconditionally, but we do not even do so when terms_good (but not\n> terms_bad) is already set.\n>\n> Is this an unrelated bugfix of some kind?  This does not look\n> related to \"making --bisect-state optional and implicit default\" at\n> all.  At least the proposed log message does not explain why.\n\nI had hoped that this part of the commit message would be clear enough:\n\n\tTo prepare for converting `bisect--helper` to a full built-in\n\timplementation of `git bisect` (which must not require the\n\t`--bisect-state` option to be specified at all), let's move the\n\thandling toward the end of the `switch (cmdmode)` block.\n\nSince my hope did not turn into reality, I split out that move into its\nown commit (making the patch series even longer, but hopefully at least\nmaking it more readable, too).\n\nCiao,\nDscho\n"},{"id":"449145","messageId":"nycvar.QRO.7.76.6.2202221655000.11118@tvgsbejvaqbjf.bet","threadId":"57326","inReplyTo":"CABPp-BEyFmsqQiO8+1JRw3R=XFVOFNXxmEMphPhu-OXVwUxAXw@mail.gmail.com","subject":"Re: [PATCH 00/11] Finish converting git bisect into a built-in","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2022-02-22T15:55:41Z","receivedAt":"2022-02-22T15:55:53Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Elijah,\n\nOn Tue, 8 Feb 2022, Elijah Newren wrote:\n\n> On Sat, Jan 29, 2022 at 10:39 PM Elijah Newren <newren@gmail.com> wrote:\n> >\n> > On Fri, Jan 28, 2022 at 3:08 PM Johannes Schindelin via GitGitGadget\n> > <gitgitgadget@gmail.com> wrote:\n> > >\n> > > After three GSoC/Outreachy students spent an incredible effort on this, it\n> > > is finally time to put a neat little bow on it.\n> > >\n> > > Johannes Schindelin (11):\n> > >   bisect run: fix the error message\n> > >   bisect--helper: retire the --no-log option\n> > >   bisect--helper: really retire --bisect-next-check\n> > >   bisect--helper: really retire `--bisect-autostart`\n> > >   bisect--helper: align the sub-command order with git-bisect.sh\n> > >   bisect--helper: make `--bisect-state` optional\n> > >   bisect: move even the option parsing to `bisect--helper`\n> > >   bisect--helper: using `--bisect-state` without an argument is a bug\n> > >   Turn `git bisect` into a full built-in.\n> > >   bisect: remove Cogito-related code\n> > >   bisect: no longer try to clean up left-over `.git/head-name` files\n> > >\n> > >  Makefile                               |   3 +-\n> > >  bisect.c                               |   3 -\n> > >  builtin.h                              |   2 +-\n> > >  builtin/{bisect--helper.c => bisect.c} | 201 ++++++++++---------------\n> > >  git-bisect.sh                          |  84 -----------\n> > >  git.c                                  |   2 +-\n> > >  t/t6030-bisect-porcelain.sh            |   1 -\n> > >  7 files changed, 84 insertions(+), 212 deletions(-)\n> > >  rename builtin/{bisect--helper.c => bisect.c} (87%)\n> > >  delete mode 100755 git-bisect.sh\n> >\n> > I read through the series and couldn't spot any problems.\n>\n> I re-read the series, taking a closer look.  Spotted a few minor\n> things (and left some comments) but the series looks pretty good to\n> me.  I think Dscho's on vacation, so we'll resume the discussion when\n> he gets back.\n\nI took some time off, and then had to focus on other things, so I only got\nback to this patch series today.\n\nThank you so much for your helpful feedback!\n\nCiao,\nDscho\n"},{"id":"449152","messageId":"81ca0d68cde6c1cfcf439b8b43016fd2b8e64d10.1645547423.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v2.git.1645547423.gitgitgadget@gmail.com","subject":"[PATCH v2 01/14] bisect run: fix the error message","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-02-22T16:30:10Z","receivedAt":"2022-02-22T16:30:30Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nIn d1bbbe45df8 (bisect--helper: reimplement `bisect_run` shell function\nin C, 2021-09-13), we ported the `bisect run` subcommand to C, including\nthe part that prints out an error message when the implicit `git bisect\nbad` or `git bisect good` failed.\n\nHowever, the error message was supposed to print out whether the state\nwas \"good\" or \"bad\", but used a bogus (because non-populated) `args`\nvariable for it.\n\nHelped-by: Elijah Newren <newren@gmail.com>\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/bisect--helper.c    |  8 ++------\n t/t6030-bisect-porcelain.sh | 10 ++++++++++\n 2 files changed, 12 insertions(+), 6 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 28a2e6a5750..4208206af07 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1093,7 +1093,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 strvec args = STRVEC_INIT;\n \tstruct strvec run_args = STRVEC_INIT;\n \tconst char *new_state;\n \tint temporary_stdout_fd, saved_stdout;\n@@ -1111,8 +1110,6 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n \tstrvec_push(&run_args, command.buf);\n \n \twhile (1) {\n-\t\tstrvec_clear(&args);\n-\n \t\tprintf(_(\"running %s\\n\"), command.buf);\n \t\tres = run_command_v_opt(run_args.v, RUN_USING_SHELL);\n \n@@ -1157,14 +1154,13 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n \t\t\tprintf(_(\"bisect found first bad commit\"));\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\"), args.v[0], res);\n+\t\t\terror(_(\"bisect run failed: 'git bisect\"\n+\t\t\t\" %s' exited with error code %d\"), new_state, res);\n \t\t} else {\n \t\t\tcontinue;\n \t\t}\n \n \t\tstrbuf_release(&command);\n-\t\tstrvec_clear(&args);\n \t\tstrvec_clear(&run_args);\n \t\treturn res;\n \t}\ndiff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh\nindex 1be85d064e7..720442de2eb 100755\n--- a/t/t6030-bisect-porcelain.sh\n+++ b/t/t6030-bisect-porcelain.sh\n@@ -980,4 +980,14 @@ test_expect_success 'bisect visualize with a filename with dash and space' '\n \tgit bisect visualize -p -- \"-hello 2\"\n '\n \n+test_expect_success 'testing' '\n+\tgit bisect reset &&\n+\tgit bisect start $HASH4 $HASH1 &&\n+\twrite_script test_script.sh <<-\\EOF &&\n+\trm .git/BISECT*\n+\tEOF\n+\ttest_must_fail git bisect run ./test_script.sh 2>error &&\n+\tgrep \"git bisect good.*exited with error code\" error\n+'\n+\n test_done\n-- \ngitgitgadget\n\n"},{"id":"449153","messageId":"pull.1132.v2.git.1645547423.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.git.1643328752.gitgitgadget@gmail.com","subject":"[PATCH v2 00/14] Finish converting git bisect into a built-in","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-02-22T16:30:09Z","receivedAt":"2022-02-22T16:30:31Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"After three GSoC/Outreachy students spent an incredible effort on this, it\nis finally time to put a neat little bow on it.\n\nChanges since v1:\n\n * Added a regression test to \"bisect run: fix the error message\".\n * Added a patch to address an error message that double-single-quoted the\n   command.\n * Reworked the logic in \"bisect--helper: make --bisect-state optional\" to\n   delay showing the usage upon an unknown command, which should make the\n   code a lot less confusing.\n * Split out the change that moved the BISECT_STATE case to the end of the\n   switch block.\n * Added a patch that replaces the return error() calls in\n   cmd_bisect_helper() with die() calls, to avoid returning -1 as an exit\n   code.\n * Dropped the use of parse_options() for the single purpose of handling -h;\n   This is now done explicitly.\n * Simplified the diff of \"bisect: move even the option parsing to\n   bisect--helper\" by modifying argc and argv instead of modifying all the\n   function calls using those variables.\n * In the \"Turn git bisect into a full built-in\" patch, changed the name of\n   the variable holding the usage to use the builtin_ prefix used in other\n   built-ins, too.\n * Removed the trailing dot from the commit message of \"Turn git bisect into\n   a full built-in\".\n\nJohannes Schindelin (14):\n  bisect run: fix the error message\n  bisect: avoid double-quoting when printing the failed command\n  bisect--helper: retire the --no-log option\n  bisect--helper: really retire --bisect-next-check\n  bisect--helper: really retire `--bisect-autostart`\n  bisect--helper: using `--bisect-state` without an argument is a bug\n  bisect--helper: align the sub-command order with git-bisect.sh\n  bisect--helper: make `--bisect-state` optional\n  bisect--helper: move the `BISECT_STATE` case to the end\n  bisect--helper: return only correct exit codes in `cmd_*()`\n  bisect: move even the option parsing to `bisect--helper`\n  Turn `git bisect` into a full built-in\n  bisect: remove Cogito-related code\n  bisect: no longer try to clean up left-over `.git/head-name` files\n\n Makefile                               |   3 +-\n bisect.c                               |   3 -\n builtin.h                              |   2 +-\n builtin/{bisect--helper.c => bisect.c} | 189 ++++++++++---------------\n git-bisect.sh                          |  84 -----------\n git.c                                  |   2 +-\n t/t6030-bisect-porcelain.sh            |  11 +-\n 7 files changed, 88 insertions(+), 206 deletions(-)\n rename builtin/{bisect--helper.c => bisect.c} (88%)\n delete mode 100755 git-bisect.sh\n\n\nbase-commit: 89bece5c8c96f0b962cfc89e63f82d603fd60bed\nPublished-As: https://github.com/gitgitgadget/git/releases/tag/pr-1132%2Fdscho%2Fbisect-in-c-v2\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1132/dscho/bisect-in-c-v2\nPull-Request: https://github.com/gitgitgadget/git/pull/1132\n\nRange-diff vs v1:\n\n  1:  93d19d85ee3 !  1:  81ca0d68cde bisect run: fix the error message\n     @@ Commit message\n          was \"good\" or \"bad\", but used a bogus (because non-populated) `args`\n          variable for it.\n      \n     +    Helped-by: Elijah Newren <newren@gmail.com>\n          Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n      \n       ## builtin/bisect--helper.c ##\n     @@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, cons\n       \t\tstrvec_clear(&run_args);\n       \t\treturn res;\n       \t}\n     +\n     + ## t/t6030-bisect-porcelain.sh ##\n     +@@ t/t6030-bisect-porcelain.sh: test_expect_success 'bisect visualize with a filename with dash and space' '\n     + \tgit bisect visualize -p -- \"-hello 2\"\n     + '\n     + \n     ++test_expect_success 'testing' '\n     ++\tgit bisect reset &&\n     ++\tgit bisect start $HASH4 $HASH1 &&\n     ++\twrite_script test_script.sh <<-\\EOF &&\n     ++\trm .git/BISECT*\n     ++\tEOF\n     ++\ttest_must_fail git bisect run ./test_script.sh 2>error &&\n     ++\tgrep \"git bisect good.*exited with error code\" error\n     ++'\n     ++\n     + test_done\n  -:  ----------- >  2:  4320101f2e0 bisect: avoid double-quoting when printing the failed command\n  2:  8e0e5559980 =  3:  88d7173c86b bisect--helper: retire the --no-log option\n  3:  996a7099bf8 =  4:  b914fe64dda bisect--helper: really retire --bisect-next-check\n  4:  3de4c48b66d =  5:  0d3db63bda6 bisect--helper: really retire `--bisect-autostart`\n  8:  1b14ed3d797 =  6:  a345cf3e0e4 bisect--helper: using `--bisect-state` without an argument is a bug\n  5:  6afc6e0eece =  7:  0487701220b bisect--helper: align the sub-command order with git-bisect.sh\n  6:  eddbdde222a !  8:  d8b2767c148 bisect--helper: make `--bisect-state` optional\n     @@ Commit message\n          `git bisect--helper bad`, i.e. do not require the `--bisect-state`\n          option to be passed explicitly.\n      \n     -    To prepare for converting `bisect--helper` to a full built-in\n     -    implementation of `git bisect` (which must not require the\n     -    `--bisect-state` option to be specified at all), let's move the handling\n     -    toward the end of the `switch (cmdmode)` block.\n     -\n          Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n      \n       ## builtin/bisect--helper.c ##\n     @@ builtin/bisect--helper.c: int cmd_bisect__helper(int argc, const char **argv, co\n       \t\t\t     git_bisect_helper_usage,\n       \t\t\t     PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN);\n       \n     -+\tif (!cmdmode && argc > 0) {\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\tcmdmode = BISECT_STATE;\n     -+\t}\n     -+\n     - \tif (!cmdmode)\n     - \t\tusage_with_options(git_bisect_helper_usage, options);\n     - \n     -@@ builtin/bisect--helper.c: int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n     +-\tif (!cmdmode)\n     +-\t\tusage_with_options(git_bisect_helper_usage, options);\n     +-\n     +-\tswitch (cmdmode) {\n     ++\tswitch (cmdmode ? cmdmode : BISECT_STATE) {\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_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_TERMS:\n     - \t\tif (argc > 1)\n     - \t\t\treturn error(_(\"--bisect-terms requires 0 or 1 argument\"));\n      @@ builtin/bisect--helper.c: int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n     + \tcase BISECT_STATE:\n     + \t\tset_terms(&terms, \"bad\", \"good\");\n       \t\tget_terms(&terms);\n     - \t\tres = bisect_run(&terms, argv, argc);\n     - \t\tbreak;\n     -+\tcase BISECT_STATE:\n     -+\t\tif (!terms.term_good) {\n     -+\t\t\tset_terms(&terms, \"bad\", \"good\");\n     -+\t\t\tget_terms(&terms);\n     ++\t\tif (!cmdmode &&\n     ++\t\t    (!argc || check_and_set_terms(&terms, argv[0]))) {\n     ++\t\t\tchar *msg = xstrfmt(_(\"unknown command: '%s'\"), argv[0]);\n     ++\t\t\tusage_msg_opt(msg, git_bisect_helper_usage, options);\n      +\t\t}\n     -+\t\tres = bisect_state(&terms, argv, argc);\n     -+\t\tbreak;\n     - \tdefault:\n     - \t\tBUG(\"unknown subcommand %d\", cmdmode);\n     - \t}\n     + \t\tres = bisect_state(&terms, argv, argc);\n     + \t\tbreak;\n     + \tcase BISECT_TERMS:\n     +\n     + ## git-bisect.sh ##\n     +@@ git-bisect.sh: case \"$#\" in\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     ++\t\tgit bisect--helper \"$cmd\" \"$@\" ;;\n     + \tskip)\n     + \t\tgit bisect--helper --bisect-skip \"$@\" || exit;;\n     + \tnext)\n  -:  ----------- >  9:  e8904db81c5 bisect--helper: move the `BISECT_STATE` case to the end\n  -:  ----------- > 10:  208f8fa4851 bisect--helper: return only correct exit codes in `cmd_*()`\n  7:  515e86e2075 ! 11:  dc04b06206b bisect: move even the option parsing to `bisect--helper`\n     @@ Commit message\n          together. So it would appear as if a lot of work would have to be done\n          just to be able to use `parse_options()` just to parse the sub-command,\n          instead of a simple `if...else if` chain, the latter being a\n     -    dramatically simpler implementation. Therefore, we now keep the\n     -    `parse_options()` call primarily to support `-h` and little else.\n     +    dramatically simpler implementation.\n      \n          Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n      \n     @@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, cons\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);\n     -+\t/* Handle -h and invalid options */\n     -+\tparse_options(argc - 1, argv + 1, prefix, options,\n     -+\t\t      git_bisect_usage,\n     -+\t\t      PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN |\n     -+\t\t      PARSE_OPT_ONE_SHOT | PARSE_OPT_STOP_AT_NON_OPTION);\n     - \n     --\tif (!cmdmode && argc > 0) {\n     -+\tif (!strcmp(\"help\", command))\n     ++\tif (!strcmp(\"-h\", command) || !strcmp(\"help\", command))\n      +\t\tusage_with_options(git_bisect_usage, options);\n     -+\telse if (!strcmp(\"start\", command)) {\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\tcmdmode = BISECT_STATE;\n     --\t}\n     --\n     --\tif (!cmdmode)\n     --\t\tusage_with_options(git_bisect_helper_usage, options);\n     --\n     --\tswitch (cmdmode) {\n     + \n     +-\tswitch (cmdmode ? cmdmode : BISECT_STATE) {\n      -\tcase BISECT_START:\n     --\t\tset_terms(&terms, \"bad\", \"good\");\n     --\t\tres = bisect_start(&terms, argv, argc);\n     ++\targc -= 2;\n     ++\targv += 2;\n     ++\n     ++\tif (!strcmp(\"start\", command)) {\n     + \t\tset_terms(&terms, \"bad\", \"good\");\n     + \t\tres = bisect_start(&terms, argv, argc);\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} else if (!strcmp(\"terms\", command)) {\n     + \t\tif (argc > 1)\n     +-\t\t\tdie(_(\"--bisect-terms requires 0 or 1 argument\"));\n     ++\t\t\tdie(_(\"'terms' requires 0 or 1 argument\"));\n     + \t\tres = bisect_terms(&terms, argc == 1 ? argv[0] : NULL);\n      -\t\tbreak;\n      -\tcase BISECT_SKIP:\n     -+\t\tres = bisect_start(&terms, argv + 2, argc - 2);\n     -+\t} else if (!strcmp(\"terms\", command)) {\n     -+\t\tif (argc > 3)\n     -+\t\t\treturn error(_(\"'terms' requires 0 or 1 argument\"));\n     -+\t\tres = bisect_terms(&terms, argc == 3 ? argv[2] : NULL);\n      +\t} else if (!strcmp(\"skip\", command)) {\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, 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\tres = bisect_skip(&terms, argv + 2, argc - 2);\n      +\t} else if (!strcmp(\"next\", command)) {\n     -+\t\tif (argc != 2)\n     -+\t\t\treturn error(_(\"'next' requires 0 arguments\"));\n     + \t\tif (argc)\n     +-\t\t\tdie(_(\"--bisect-next requires 0 arguments\"));\n     ++\t\t\tdie(_(\"'next' requires 0 arguments\"));\n       \t\tget_terms(&terms);\n       \t\tres = bisect_next(&terms, prefix);\n      -\t\tbreak;\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} else if (!strcmp(\"reset\", command)) {\n     + \t\tif (argc > 1)\n     +-\t\t\tdie(_(\"--bisect-reset requires either no argument or a commit\"));\n     ++\t\t\tdie(_(\"'reset' requires either no argument or a commit\"));\n     + \t\tres = bisect_reset(argc ? argv[0] : NULL);\n      -\t\tbreak;\n      -\tcase BISECT_VISUALIZE:\n     -+\t} else if (!strcmp(\"reset\", command)) {\n     -+\t\tif (argc > 3)\n     -+\t\t\treturn error(_(\"'reset' requires either no argument or a commit\"));\n     -+\t\tres = bisect_reset(argc > 2 ? argv[2] : NULL);\n      +\t} else if (one_of(command, \"visualize\", \"view\", NULL)) {\n       \t\tget_terms(&terms);\n     --\t\tres = bisect_visualize(&terms, argv, argc);\n     + \t\tres = bisect_visualize(&terms, argv, argc);\n      -\t\tbreak;\n      -\tcase BISECT_REPLAY:\n     --\t\tif (argc != 1)\n     -+\t\tres = bisect_visualize(&terms, argv + 2, argc - 2);\n      +\t} else if (!strcmp(\"replay\", command)) {\n     -+\t\tif (argc != 3)\n     - \t\t\treturn error(_(\"no logfile given\"));\n     + \t\tif (argc != 1)\n     + \t\t\tdie(_(\"no logfile given\"));\n       \t\tset_terms(&terms, \"bad\", \"good\");\n     --\t\tres = bisect_replay(&terms, argv[0]);\n     + \t\tres = bisect_replay(&terms, argv[0]);\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_replay(&terms, argv[2]);\n      +\t} else if (!strcmp(\"log\", command)) {\n     -+\t\tif (argc > 2)\n     -+\t\t\treturn error(_(\"'log' requires 0 arguments\"));\n     + \t\tif (argc)\n     +-\t\t\tdie(_(\"--bisect-log requires 0 arguments\"));\n     ++\t\t\tdie(_(\"'log' requires 0 arguments\"));\n       \t\tres = bisect_log();\n      -\t\tbreak;\n      -\tcase BISECT_RUN:\n     --\t\tif (!argc)\n      +\t} else if (!strcmp(\"run\", command)) {\n     -+\t\tif (argc < 3)\n     - \t\t\treturn error(_(\"bisect run failed: no command provided.\"));\n     + \t\tif (!argc)\n     + \t\t\tdie(_(\"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, argv, argc);\n      -\t\tbreak;\n      -\tcase BISECT_STATE:\n     --\t\tif (!terms.term_good) {\n     --\t\t\tset_terms(&terms, \"bad\", \"good\");\n     --\t\t\tget_terms(&terms);\n     -+\t\tres = bisect_run(&terms, argv + 2, argc - 2);\n      +\t} else {\n     -+\t\tset_terms(&terms, \"bad\", \"good\");\n     -+\t\tget_terms(&terms);\n     -+\t\tif (!check_and_set_terms(&terms, command))\n     -+\t\t\tres = bisect_state(&terms, argv + 1, argc - 1);\n     -+\t\telse {\n     + \t\tset_terms(&terms, \"bad\", \"good\");\n     + \t\tget_terms(&terms);\n     +-\t\tif (!cmdmode &&\n     +-\t\t    (!argc || check_and_set_terms(&terms, argv[0]))) {\n     +-\t\t\tchar *msg = xstrfmt(_(\"unknown command: '%s'\"), argv[0]);\n     +-\t\t\tusage_msg_opt(msg, git_bisect_helper_usage, options);\n     ++\t\tif (check_and_set_terms(&terms, command)) {\n      +\t\t\tchar *msg = xstrfmt(_(\"unknown command: '%s'\"), command);\n      +\t\t\tusage_msg_opt(msg, git_bisect_usage, options);\n       \t\t}\n     --\t\tres = bisect_state(&terms, argv, argc);\n     ++\t\t/* shift the `command` back in */\n     ++\t\targc++;\n     ++\t\targv--;\n     + \t\tres = bisect_state(&terms, argv, argc);\n      -\t\tbreak;\n      -\tdefault:\n      -\t\tBUG(\"unknown subcommand %d\", cmdmode);\n     @@ git-bisect.sh: Please use \"git help bisect\" to get the full man page.'\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     +-\t\tgit bisect--helper \"$cmd\" \"$@\" ;;\n      -\tskip)\n      -\t\tgit bisect--helper --bisect-skip \"$@\" || exit;;\n      -\tnext)\n  9:  1c0bd8a326f ! 12:  7db4b03b668 Turn `git bisect` into a full built-in.\n     @@ Metadata\n      Author: Johannes Schindelin <Johannes.Schindelin@gmx.de>\n      \n       ## Commit message ##\n     -    Turn `git bisect` into a full built-in.\n     +    Turn `git bisect` into a full built-in\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     @@ builtin.h: int cmd_am(int argc, const char **argv, const char *prefix);\n       int cmd_bugreport(int argc, const char **argv, const char *prefix);\n      \n       ## builtin/bisect--helper.c => builtin/bisect.c ##\n     +@@ builtin/bisect.c: 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_usage[] = {\n     ++static const char * const builtin_bisect_usage[] = {\n     + \tN_(\"git bisect help\\n\"\n     + \t   \"\\tprint this long help message.\"),\n     + \tN_(\"git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>]\\n\"\n      @@ builtin/bisect.c: static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n       \t}\n       }\n     @@ builtin/bisect.c: static int bisect_run(struct bisect_terms *terms, const char *\n       {\n       \tint res = 0;\n       \tstruct option options[] = {\n     +@@ builtin/bisect.c: int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n     + \tconst char *command = argc > 1 ? argv[1] : \"help\";\n     + \n     + \tif (!strcmp(\"-h\", command) || !strcmp(\"help\", command))\n     +-\t\tusage_with_options(git_bisect_usage, options);\n     ++\t\tusage_with_options(builtin_bisect_usage, options);\n     + \n     + \targc -= 2;\n     + \targv += 2;\n     +@@ builtin/bisect.c: int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n     + \t\tget_terms(&terms);\n     + \t\tif (check_and_set_terms(&terms, command)) {\n     + \t\t\tchar *msg = xstrfmt(_(\"unknown command: '%s'\"), command);\n     +-\t\t\tusage_msg_opt(msg, git_bisect_usage, options);\n     ++\t\t\tusage_msg_opt(msg, builtin_bisect_usage, options);\n     + \t\t}\n     + \t\t/* shift the `command` back in */\n     + \t\targc++;\n      \n       ## git-bisect.sh (deleted) ##\n      @@\n 10:  cce533486db = 13:  0611d16f772 bisect: remove Cogito-related code\n 11:  dc77297c676 = 14:  e2fa11a819e bisect: no longer try to clean up left-over `.git/head-name` files\n\n-- \ngitgitgadget\n"},{"id":"449154","messageId":"4320101f2e01709ae33f7d81c9e4caa486fd9ad8.1645547423.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v2.git.1645547423.gitgitgadget@gmail.com","subject":"[PATCH v2 02/14] bisect: avoid double-quoting when printing the failed command","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-02-22T16:30:11Z","receivedAt":"2022-02-22T16:30:33Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nWe already quote the command via `sq_quote_argv()`, no need to enclose\nthe result in an extraneous pair of single-quotes.\n\nPointed out by Elijah Newren.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/bisect--helper.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 4208206af07..ba6d90635a5 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1115,7 +1115,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, command.buf);\n \t\t\tstrbuf_release(&command);\n \t\t\treturn res;\n \t\t}\n-- \ngitgitgadget\n\n"},{"id":"449155","messageId":"88d7173c86bbec7416cb43c408339c24ed015dce.1645547423.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v2.git.1645547423.gitgitgadget@gmail.com","subject":"[PATCH v2 03/14] bisect--helper: retire the --no-log option","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-02-22T16:30:12Z","receivedAt":"2022-02-22T16:30:33Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nTurns out we actually never used it, anyway...\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/bisect--helper.c | 4 +---\n 1 file changed, 1 insertion(+), 3 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex ba6d90635a5..71a6f8f5192 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1182,7 +1182,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@@ -1206,8 +1206,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-- \ngitgitgadget\n\n"},{"id":"449156","messageId":"b914fe64dda22697123446a4490379cb6511af71.1645547423.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v2.git.1645547423.gitgitgadget@gmail.com","subject":"[PATCH v2 04/14] bisect--helper: really retire --bisect-next-check","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-02-22T16:30:13Z","receivedAt":"2022-02-22T16:30:43Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?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\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/bisect--helper.c | 3 ---\n 1 file changed, 3 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 71a6f8f5192..4ee708e34c7 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1170,7 +1170,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@@ -1186,8 +1185,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-- \ngitgitgadget\n\n"},{"id":"449157","messageId":"0d3db63bda6d6fe1de5be4912534594571a0ee29.1645547423.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v2.git.1645547423.gitgitgadget@gmail.com","subject":"[PATCH v2 05/14] bisect--helper: really retire `--bisect-autostart`","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-02-22T16:30:14Z","receivedAt":"2022-02-22T16:30:44Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\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>\n---\n builtin/bisect--helper.c | 1 -\n 1 file changed, 1 deletion(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 4ee708e34c7..c7763be2c51 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1172,7 +1172,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\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-- \ngitgitgadget\n\n"},{"id":"449158","messageId":"a345cf3e0e4b92a2a8080ec245315fce6a8888d6.1645547423.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v2.git.1645547423.gitgitgadget@gmail.com","subject":"[PATCH v2 06/14] bisect--helper: using `--bisect-state` without an argument is a bug","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-02-22T16:30:15Z","receivedAt":"2022-02-22T16:30:46Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nThe `bisect--helper` command is not expected to be used directly by the\nuser. Therefore, it is a bug if it receives no argument to the\n`--bisect-state` command mode, not a user error. Which means that we\nneed to call `BUG()` instead of `die()`.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/bisect--helper.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex c7763be2c51..fcddd7444a4 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -856,7 +856,7 @@ static enum bisect_error bisect_state(struct bisect_terms *terms, const char **a\n \tstruct oid_array revs = OID_ARRAY_INIT;\n \n \tif (!argc)\n-\t\treturn error(_(\"Please call `--bisect-state` with at least one argument\"));\n+\t\tBUG(\"bisect_state() called without argument\");\n \n \tif (bisect_autostart(terms))\n \t\treturn BISECT_FAILED;\n-- \ngitgitgadget\n\n"},{"id":"449159","messageId":"0487701220b5b1e6c8212ed422ce4ebecca5fbe2.1645547423.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v2.git.1645547423.gitgitgadget@gmail.com","subject":"[PATCH v2 07/14] bisect--helper: align the sub-command order with git-bisect.sh","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-02-22T16:30:16Z","receivedAt":"2022-02-22T16:30:48Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nWe are about to retire the shell implementation of `git bisect`, or\nmaybe better put: the remainder of the shell implementation (a shell of\na script, if you want).\n\nIn preparation for that, align the order of the sub-commands with the\nway the outgoing implementation presents them to the user.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/bisect--helper.c | 76 ++++++++++++++++++++--------------------\n 1 file changed, 38 insertions(+), 38 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex fcddd7444a4..31243a88a02 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1169,37 +1169,37 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\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_START = 1,\n \t\tBISECT_STATE,\n-\t\tBISECT_LOG,\n-\t\tBISECT_REPLAY,\n+\t\tBISECT_TERMS,\n \t\tBISECT_SKIP,\n+\t\tBISECT_NEXT,\n+\t\tBISECT_RESET,\n \t\tBISECT_VISUALIZE,\n+\t\tBISECT_REPLAY,\n+\t\tBISECT_LOG,\n \t\tBISECT_RUN,\n \t} cmdmode = 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-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-terms\", &cmdmode,\n+\t\t\t N_(\"print out the bisect terms\"), BISECT_TERMS),\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-next\", &cmdmode,\n+\t\t\t N_(\"find the next bisection commit\"), BISECT_NEXT),\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-visualize\", &cmdmode,\n \t\t\t N_(\"visualize the bisection\"), BISECT_VISUALIZE),\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-log\", &cmdmode,\n+\t\t\t N_(\"list the bisection steps so far\"), BISECT_LOG),\n \t\tOPT_CMDMODE(0, \"bisect-run\", &cmdmode,\n \t\t\t N_(\"use <cmd>... to automatically bisect.\"), BISECT_RUN),\n \t\tOPT_END()\n@@ -1214,19 +1214,24 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\tusage_with_options(git_bisect_helper_usage, options);\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+\tcase BISECT_START:\n+\t\tset_terms(&terms, \"bad\", \"good\");\n+\t\tres = bisect_start(&terms, argv, argc);\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_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+\tcase BISECT_SKIP:\n \t\tset_terms(&terms, \"bad\", \"good\");\n-\t\tres = bisect_start(&terms, argv, argc);\n+\t\tget_terms(&terms);\n+\t\tres = bisect_skip(&terms, argv, argc);\n \t\tbreak;\n \tcase BISECT_NEXT:\n \t\tif (argc)\n@@ -1234,15 +1239,14 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\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+\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_LOG:\n-\t\tif (argc)\n-\t\t\treturn error(_(\"--bisect-log requires 0 arguments\"));\n-\t\tres = bisect_log();\n+\tcase BISECT_VISUALIZE:\n+\t\tget_terms(&terms);\n+\t\tres = bisect_visualize(&terms, argv, argc);\n \t\tbreak;\n \tcase BISECT_REPLAY:\n \t\tif (argc != 1)\n@@ -1250,14 +1254,10 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\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+\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_RUN:\n \t\tif (!argc)\n-- \ngitgitgadget\n\n"},{"id":"449160","messageId":"d8b2767c148e59eafd57b355605b90dd3d4e311e.1645547423.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v2.git.1645547423.gitgitgadget@gmail.com","subject":"[PATCH v2 08/14] bisect--helper: make `--bisect-state` optional","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-02-22T16:30:17Z","receivedAt":"2022-02-22T16:30:48Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?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 `--bisect-state`\noption to be passed explicitly.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/bisect--helper.c | 14 ++++++++------\n git-bisect.sh            |  2 +-\n 2 files changed, 9 insertions(+), 7 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 31243a88a02..39b3cd606f2 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -26,8 +26,8 @@ static const char * const git_bisect_helper_usage[] = {\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 \tN_(\"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-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 \tN_(\"git bisect--helper --bisect-visualize\"),\n@@ -1210,10 +1210,7 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\t\t     git_bisect_helper_usage,\n \t\t\t     PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN);\n \n-\tif (!cmdmode)\n-\t\tusage_with_options(git_bisect_helper_usage, options);\n-\n-\tswitch (cmdmode) {\n+\tswitch (cmdmode ? cmdmode : BISECT_STATE) {\n \tcase BISECT_START:\n \t\tset_terms(&terms, \"bad\", \"good\");\n \t\tres = bisect_start(&terms, argv, argc);\n@@ -1221,6 +1218,11 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \tcase BISECT_STATE:\n \t\tset_terms(&terms, \"bad\", \"good\");\n \t\tget_terms(&terms);\n+\t\tif (!cmdmode &&\n+\t\t    (!argc || check_and_set_terms(&terms, argv[0]))) {\n+\t\t\tchar *msg = xstrfmt(_(\"unknown command: '%s'\"), argv[0]);\n+\t\t\tusage_msg_opt(msg, git_bisect_helper_usage, options);\n+\t\t}\n \t\tres = bisect_state(&terms, argv, argc);\n \t\tbreak;\n \tcase BISECT_TERMS:\ndiff --git a/git-bisect.sh b/git-bisect.sh\nindex 405cf76f2a3..fbf56649d7d 100755\n--- a/git-bisect.sh\n+++ b/git-bisect.sh\n@@ -60,7 +60,7 @@ case \"$#\" in\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+\t\tgit bisect--helper \"$cmd\" \"$@\" ;;\n \tskip)\n \t\tgit bisect--helper --bisect-skip \"$@\" || exit;;\n \tnext)\n-- \ngitgitgadget\n\n"},{"id":"449161","messageId":"e8904db81c56e33f3f77b5040fff6b3ab7f2ec27.1645547423.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v2.git.1645547423.gitgitgadget@gmail.com","subject":"[PATCH v2 09/14] bisect--helper: move the `BISECT_STATE` case to the end","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-02-22T16:30:18Z","receivedAt":"2022-02-22T16:30:51Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nIn preparation for replacing the command-mode parsing in\n`bisect--helper` with an if/else if/else chain, let's move the one\ncommand that will be implicit (i.e. what will become the final `else`\nwithout any `if`) to the end.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/bisect--helper.c | 20 ++++++++++----------\n 1 file changed, 10 insertions(+), 10 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 39b3cd606f2..ba047ee0fc8 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1215,16 +1215,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\tset_terms(&terms, \"bad\", \"good\");\n \t\tres = bisect_start(&terms, argv, argc);\n \t\tbreak;\n-\tcase BISECT_STATE:\n-\t\tset_terms(&terms, \"bad\", \"good\");\n-\t\tget_terms(&terms);\n-\t\tif (!cmdmode &&\n-\t\t    (!argc || check_and_set_terms(&terms, argv[0]))) {\n-\t\t\tchar *msg = xstrfmt(_(\"unknown command: '%s'\"), argv[0]);\n-\t\t\tusage_msg_opt(msg, git_bisect_helper_usage, options);\n-\t\t}\n-\t\tres = bisect_state(&terms, argv, argc);\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@@ -1267,6 +1257,16 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\tget_terms(&terms);\n \t\tres = bisect_run(&terms, argv, argc);\n \t\tbreak;\n+\tcase BISECT_STATE:\n+\t\tset_terms(&terms, \"bad\", \"good\");\n+\t\tget_terms(&terms);\n+\t\tif (!cmdmode &&\n+\t\t    (!argc || check_and_set_terms(&terms, argv[0]))) {\n+\t\t\tchar *msg = xstrfmt(_(\"unknown command: '%s'\"), argv[0]);\n+\t\t\tusage_msg_opt(msg, git_bisect_helper_usage, options);\n+\t\t}\n+\t\tres = bisect_state(&terms, argv, argc);\n+\t\tbreak;\n \tdefault:\n \t\tBUG(\"unknown subcommand %d\", cmdmode);\n \t}\n-- \ngitgitgadget\n\n"},{"id":"449162","messageId":"208f8fa48512377e6d8f88c5c89f63692a792ccc.1645547423.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v2.git.1645547423.gitgitgadget@gmail.com","subject":"[PATCH v2 10/14] bisect--helper: return only correct exit codes in `cmd_*()`","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-02-22T16:30:19Z","receivedAt":"2022-02-22T16:30:54Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nExit codes cannot be negative, but `error()` returns -1.\n\nLet's just go with the common pattern and call `die()` in\n`cmd_bisect__helper()` when incorrect arguments were detected.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/bisect--helper.c | 12 ++++++------\n 1 file changed, 6 insertions(+), 6 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex ba047ee0fc8..5228964937d 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1217,7 +1217,7 @@ int cmd_bisect__helper(int argc, const char **argv, const char *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\t\tdie(_(\"--bisect-terms requires 0 or 1 argument\"));\n \t\tres = bisect_terms(&terms, argc == 1 ? argv[0] : NULL);\n \t\tbreak;\n \tcase BISECT_SKIP:\n@@ -1227,13 +1227,13 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\tbreak;\n \tcase BISECT_NEXT:\n \t\tif (argc)\n-\t\t\treturn error(_(\"--bisect-next requires 0 arguments\"));\n+\t\t\tdie(_(\"--bisect-next requires 0 arguments\"));\n \t\tget_terms(&terms);\n \t\tres = bisect_next(&terms, prefix);\n \t\tbreak;\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\t\tdie(_(\"--bisect-reset requires either no argument or a commit\"));\n \t\tres = bisect_reset(argc ? argv[0] : NULL);\n \t\tbreak;\n \tcase BISECT_VISUALIZE:\n@@ -1242,18 +1242,18 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\tbreak;\n \tcase BISECT_REPLAY:\n \t\tif (argc != 1)\n-\t\t\treturn error(_(\"no logfile given\"));\n+\t\t\tdie(_(\"no logfile given\"));\n \t\tset_terms(&terms, \"bad\", \"good\");\n \t\tres = bisect_replay(&terms, argv[0]);\n \t\tbreak;\n \tcase BISECT_LOG:\n \t\tif (argc)\n-\t\t\treturn error(_(\"--bisect-log requires 0 arguments\"));\n+\t\t\tdie(_(\"--bisect-log requires 0 arguments\"));\n \t\tres = bisect_log();\n \t\tbreak;\n \tcase BISECT_RUN:\n \t\tif (!argc)\n-\t\t\treturn error(_(\"bisect run failed: no command provided.\"));\n+\t\t\tdie(_(\"bisect run failed: no command provided.\"));\n \t\tget_terms(&terms);\n \t\tres = bisect_run(&terms, argv, argc);\n \t\tbreak;\n-- \ngitgitgadget\n\n"},{"id":"449163","messageId":"e2fa11a819e54ae30be1e18d66113cba24ddc163.1645547423.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v2.git.1645547423.gitgitgadget@gmail.com","subject":"[PATCH v2 14/14] bisect: no longer try to clean up left-over `.git/head-name` files","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-02-22T16:30:23Z","receivedAt":"2022-02-22T16:30:55Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nAs per the code comment, the `.git/head-name` files were cleaned up for\nbackwards-compatibility: an old version of `git bisect` could have left\nthem behind.\n\nNow, just how old would such a version be? As of 0f497e75f05 (Eliminate\nconfusing \"won't bisect on seeked tree\" failure, 2008-02-23), `git\nbisect` does not write that file anymore. Which corresponds to Git\nv1.5.4.4.\n\nEven if the likelihood is non-nil that there might still be users out\nthere who use such an old version to start a bisection, but then decide\nto continue bisecting with a current Git version, it is highly\nimprobable.\n\nSo let's remove that code, at long last.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n bisect.c                    | 3 ---\n t/t6030-bisect-porcelain.sh | 1 -\n 2 files changed, 4 deletions(-)\n\ndiff --git a/bisect.c b/bisect.c\nindex 888949fba6b..ebd4287c01c 100644\n--- a/bisect.c\n+++ b/bisect.c\n@@ -474,7 +474,6 @@ static GIT_PATH_FUNC(git_path_bisect_start, \"BISECT_START\")\n static GIT_PATH_FUNC(git_path_bisect_log, \"BISECT_LOG\")\n static GIT_PATH_FUNC(git_path_bisect_terms, \"BISECT_TERMS\")\n static GIT_PATH_FUNC(git_path_bisect_first_parent, \"BISECT_FIRST_PARENT\")\n-static GIT_PATH_FUNC(git_path_head_name, \"head-name\")\n \n static void read_bisect_paths(struct strvec *array)\n {\n@@ -1172,8 +1171,6 @@ int bisect_clean_state(void)\n \tunlink_or_warn(git_path_bisect_run());\n \tunlink_or_warn(git_path_bisect_terms());\n \tunlink_or_warn(git_path_bisect_first_parent());\n-\t/* Cleanup head-name if it got left by an old version of git-bisect */\n-\tunlink_or_warn(git_path_head_name());\n \t/*\n \t * Cleanup BISECT_START last to support the --no-checkout option\n \t * introduced in the commit 4796e823a.\ndiff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh\nindex 720442de2eb..4f17205c238 100755\n--- a/t/t6030-bisect-porcelain.sh\n+++ b/t/t6030-bisect-porcelain.sh\n@@ -945,7 +945,6 @@ test_expect_success 'git bisect reset cleans bisection state properly' '\n \ttest_path_is_missing \".git/BISECT_LOG\" &&\n \ttest_path_is_missing \".git/BISECT_RUN\" &&\n \ttest_path_is_missing \".git/BISECT_TERMS\" &&\n-\ttest_path_is_missing \".git/head-name\" &&\n \ttest_path_is_missing \".git/BISECT_HEAD\" &&\n \ttest_path_is_missing \".git/BISECT_START\"\n '\n-- \ngitgitgadget\n"},{"id":"449164","messageId":"0611d16f772597f160bbc32ad9275ddbaec251a0.1645547423.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v2.git.1645547423.gitgitgadget@gmail.com","subject":"[PATCH v2 13/14] bisect: remove Cogito-related code","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-02-22T16:30:22Z","receivedAt":"2022-02-22T16:30:56Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nOnce upon a time, there was this idea that Git would not actually be a\nsingle coherent program, but rather a set of low-level programs that\nusers cobble together via shell scripts, or develop high-level user\ninterfaces for Git, or both.\n\nCogito was such a high-level user interface, incidentally implemented\nvia shell scripts that cobble together Git calls.\n\nIt did turn out relatively quickly that Git would much rather provide a\nuseful high-level user interface itself.\n\nAs of April 19th, 2007, Cogito was therefore discontinued (see\nhttps://lore.kernel.org/git/20070419124648.GL4489@pasky.or.cz/).\n\nNevertheless, for almost 15 years after that announcement, Git carried\nspecial code in `git bisect` to accommodate Cogito.\n\nSince it is beyond doubt that there are no more Cogito users, let's\nremove the last remnant of Cogito-accommodating code.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/bisect.c | 8 --------\n 1 file changed, 8 deletions(-)\n\ndiff --git a/builtin/bisect.c b/builtin/bisect.c\nindex 1493d7d1d96..e8a346fa516 100644\n--- a/builtin/bisect.c\n+++ b/builtin/bisect.c\n@@ -15,7 +15,6 @@ static GIT_PATH_FUNC(git_path_bisect_expected_rev, \"BISECT_EXPECTED_REV\")\n static GIT_PATH_FUNC(git_path_bisect_ancestors_ok, \"BISECT_ANCESTORS_OK\")\n static GIT_PATH_FUNC(git_path_bisect_start, \"BISECT_START\")\n static GIT_PATH_FUNC(git_path_bisect_log, \"BISECT_LOG\")\n-static GIT_PATH_FUNC(git_path_head_name, \"head-name\")\n 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@@ -756,13 +755,6 @@ static enum bisect_error bisect_start(struct bisect_terms *terms, const char **a\n \t\t\tstrbuf_addstr(&start_head, oid_to_hex(&head_oid));\n \t\t} else if (!get_oid(head, &head_oid) &&\n \t\t\t   skip_prefix(head, \"refs/heads/\", &head)) {\n-\t\t\t/*\n-\t\t\t * This error message should only be triggered by\n-\t\t\t * cogito usage, and cogito users should understand\n-\t\t\t * it relates to cg-seek.\n-\t\t\t */\n-\t\t\tif (!is_empty_or_missing_file(git_path_head_name()))\n-\t\t\t\treturn error(_(\"won't bisect on cg-seek'ed tree\"));\n \t\t\tstrbuf_addstr(&start_head, head);\n \t\t} else {\n \t\t\treturn error(_(\"bad HEAD - strange symbolic ref\"));\n-- \ngitgitgadget\n\n"},{"id":"449165","messageId":"dc04b06206bbb833ce3a7fa893d724d00fe58a74.1645547423.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v2.git.1645547423.gitgitgadget@gmail.com","subject":"[PATCH v2 11/14] bisect: move even the option parsing to `bisect--helper`","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-02-22T16:30:20Z","receivedAt":"2022-02-22T16:30:56Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nOn our journey to a fully built-in `git bisect`, this is the\nsecond-to-last step.\n\nSide note: The `if (!strcmp(...)) ... else if (!strcmp(...)) ... else if\n(!strcmp(...)) ...` chain seen in this patch was not actually the first\nidea how to convert the command modes to sub-commands. Since the\n`bisect--helper` command already used the `parse-opions` API with neatly\nset-up command modes, naturally the idea was to use `PARSE_OPT_NODASH`\nto support proper sub-commands instead. However, the `parse-options` API\nis not set up for that, and even after making that option work with long\noptions, it turned out that `STOP_AT_NON_OPTION` and `KEEP_UNKNOWN`\nwould have to be used but these options were not designed to work\ntogether. So it would appear as if a lot of work would have to be done\njust to be able to use `parse_options()` just to parse the sub-command,\ninstead of a simple `if...else if` chain, the latter being a\ndramatically simpler implementation.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/bisect--helper.c | 133 ++++++++++++++++-----------------------\n git-bisect.sh            |  49 +--------------\n 2 files changed, 56 insertions(+), 126 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 5228964937d..ef0b06d594b 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -20,18 +20,34 @@ 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-\tN_(\"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-\tN_(\"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-\tN_(\"git bisect--helper --bisect-visualize\"),\n-\tN_(\"git bisect--helper --bisect-run <cmd>...\"),\n+static const char * const git_bisect_usage[] = {\n+\tN_(\"git bisect help\\n\"\n+\t   \"\\tprint this long help message.\"),\n+\tN_(\"git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>]\\n\"\n+\t   \"\\t\\t [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<pathspec>...]\\n\"\n+\t   \"\\treset bisect state and start bisection.\"),\n+\tN_(\"git bisect (bad|new) [<rev>]\\n\"\n+\t   \"\\tmark <rev> a known-bad revision/\\n\"\n+\t   \"\\t\\ta revision after change in a given property.\"),\n+\tN_(\"git bisect (good|old) [<rev>...]\\n\"\n+\t   \"\\tmark <rev>... known-good revisions/\\n\"\n+\t   \"\\t\\trevisions before change in a given property.\"),\n+\tN_(\"git bisect terms [--term-good | --term-bad]\\n\"\n+\t   \"\\tshow the terms used for old and new commits (default: bad, good)\"),\n+\tN_(\"git bisect skip [(<rev>|<range>)...]\\n\"\n+\t   \"\\tmark <rev>... untestable revisions.\"),\n+\tN_(\"git bisect next\\n\"\n+\t   \"\\tfind next bisection to test and check it out.\"),\n+\tN_(\"git bisect reset [<commit>]\\n\"\n+\t   \"\\tfinish bisection search and go back to commit.\"),\n+\tN_(\"git bisect (visualize|view)\\n\"\n+\t   \"\\tshow bisect status in gitk.\"),\n+\tN_(\"git bisect replay <logfile>\\n\"\n+\t   \"\\treplay bisection log.\"),\n+\tN_(\"git bisect log\\n\"\n+\t   \"\\tshow bisect log.\"),\n+\tN_(\"git bisect run <cmd>...\\n\"\n+\t   \"\\tuse <cmd>... to automatically bisect.\"),\n \tNULL\n };\n \n@@ -1168,108 +1184,69 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n \n int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n {\n-\tenum {\n-\t\tBISECT_START = 1,\n-\t\tBISECT_STATE,\n-\t\tBISECT_TERMS,\n-\t\tBISECT_SKIP,\n-\t\tBISECT_NEXT,\n-\t\tBISECT_RESET,\n-\t\tBISECT_VISUALIZE,\n-\t\tBISECT_REPLAY,\n-\t\tBISECT_LOG,\n-\t\tBISECT_RUN,\n-\t} cmdmode = 0;\n \tint res = 0;\n \tstruct option options[] = {\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-state\", &cmdmode,\n-\t\t\t N_(\"mark the state of ref (or refs)\"), BISECT_STATE),\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-skip\", &cmdmode,\n-\t\t\t N_(\"skip some commits for checkout\"), BISECT_SKIP),\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-reset\", &cmdmode,\n-\t\t\t N_(\"reset the bisection state\"), BISECT_RESET),\n-\t\tOPT_CMDMODE(0, \"bisect-visualize\", &cmdmode,\n-\t\t\t N_(\"visualize the bisection\"), BISECT_VISUALIZE),\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-log\", &cmdmode,\n-\t\t\t N_(\"list the bisection steps so far\"), BISECT_LOG),\n-\t\tOPT_CMDMODE(0, \"bisect-run\", &cmdmode,\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+\tconst char *command = argc > 1 ? argv[1] : \"help\";\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);\n+\tif (!strcmp(\"-h\", command) || !strcmp(\"help\", command))\n+\t\tusage_with_options(git_bisect_usage, options);\n \n-\tswitch (cmdmode ? cmdmode : BISECT_STATE) {\n-\tcase BISECT_START:\n+\targc -= 2;\n+\targv += 2;\n+\n+\tif (!strcmp(\"start\", command)) {\n \t\tset_terms(&terms, \"bad\", \"good\");\n \t\tres = bisect_start(&terms, argv, argc);\n-\t\tbreak;\n-\tcase BISECT_TERMS:\n+\t} else if (!strcmp(\"terms\", command)) {\n \t\tif (argc > 1)\n-\t\t\tdie(_(\"--bisect-terms requires 0 or 1 argument\"));\n+\t\t\tdie(_(\"'terms' requires 0 or 1 argument\"));\n \t\tres = bisect_terms(&terms, argc == 1 ? argv[0] : NULL);\n-\t\tbreak;\n-\tcase BISECT_SKIP:\n+\t} else if (!strcmp(\"skip\", command)) {\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_NEXT:\n+\t} else if (!strcmp(\"next\", command)) {\n \t\tif (argc)\n-\t\t\tdie(_(\"--bisect-next requires 0 arguments\"));\n+\t\t\tdie(_(\"'next' requires 0 arguments\"));\n \t\tget_terms(&terms);\n \t\tres = bisect_next(&terms, prefix);\n-\t\tbreak;\n-\tcase BISECT_RESET:\n+\t} else if (!strcmp(\"reset\", command)) {\n \t\tif (argc > 1)\n-\t\t\tdie(_(\"--bisect-reset requires either no argument or a commit\"));\n+\t\t\tdie(_(\"'reset' requires either no argument or a commit\"));\n \t\tres = bisect_reset(argc ? argv[0] : NULL);\n-\t\tbreak;\n-\tcase BISECT_VISUALIZE:\n+\t} else if (one_of(command, \"visualize\", \"view\", NULL)) {\n \t\tget_terms(&terms);\n \t\tres = bisect_visualize(&terms, argv, argc);\n-\t\tbreak;\n-\tcase BISECT_REPLAY:\n+\t} else if (!strcmp(\"replay\", command)) {\n \t\tif (argc != 1)\n \t\t\tdie(_(\"no logfile given\"));\n \t\tset_terms(&terms, \"bad\", \"good\");\n \t\tres = bisect_replay(&terms, argv[0]);\n-\t\tbreak;\n-\tcase BISECT_LOG:\n+\t} else if (!strcmp(\"log\", command)) {\n \t\tif (argc)\n-\t\t\tdie(_(\"--bisect-log requires 0 arguments\"));\n+\t\t\tdie(_(\"'log' requires 0 arguments\"));\n \t\tres = bisect_log();\n-\t\tbreak;\n-\tcase BISECT_RUN:\n+\t} else if (!strcmp(\"run\", command)) {\n \t\tif (!argc)\n \t\t\tdie(_(\"bisect run failed: no command provided.\"));\n \t\tget_terms(&terms);\n \t\tres = bisect_run(&terms, argv, argc);\n-\t\tbreak;\n-\tcase BISECT_STATE:\n+\t} else {\n \t\tset_terms(&terms, \"bad\", \"good\");\n \t\tget_terms(&terms);\n-\t\tif (!cmdmode &&\n-\t\t    (!argc || check_and_set_terms(&terms, argv[0]))) {\n-\t\t\tchar *msg = xstrfmt(_(\"unknown command: '%s'\"), argv[0]);\n-\t\t\tusage_msg_opt(msg, git_bisect_helper_usage, options);\n+\t\tif (check_and_set_terms(&terms, command)) {\n+\t\t\tchar *msg = xstrfmt(_(\"unknown command: '%s'\"), command);\n+\t\t\tusage_msg_opt(msg, git_bisect_usage, options);\n \t\t}\n+\t\t/* shift the `command` back in */\n+\t\targc++;\n+\t\targv--;\n \t\tres = bisect_state(&terms, argv, argc);\n-\t\tbreak;\n-\tdefault:\n-\t\tBUG(\"unknown subcommand %d\", cmdmode);\n \t}\n+\n \tfree_terms(&terms);\n \n \t/*\ndiff --git a/git-bisect.sh b/git-bisect.sh\nindex fbf56649d7d..028d39cd9ce 100755\n--- a/git-bisect.sh\n+++ b/git-bisect.sh\n@@ -34,51 +34,4 @@ 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 --bisect-start \"$@\" ;;\n-\tbad|good|new|old|\"$TERM_BAD\"|\"$TERM_GOOD\")\n-\t\tgit bisect--helper \"$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-\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*)\n-\t\tusage ;;\n-\tesac\n-esac\n+exec git bisect--helper \"$@\"\n-- \ngitgitgadget\n\n"},{"id":"449166","messageId":"7db4b03b66834ff78507303532af516206a22486.1645547423.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v2.git.1645547423.gitgitgadget@gmail.com","subject":"[PATCH v2 12/14] Turn `git bisect` into a full built-in","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-02-22T16:30:21Z","receivedAt":"2022-02-22T16:30:59Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?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>\n---\n Makefile                               |  3 +--\n builtin.h                              |  2 +-\n builtin/{bisect--helper.c => bisect.c} |  8 +++---\n git-bisect.sh                          | 37 --------------------------\n git.c                                  |  2 +-\n 5 files changed, 7 insertions(+), 45 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 5580859afdb..ce2eabeca58 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -595,7 +595,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@@ -1064,7 +1063,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 8a58743ed63..b5567ea3a9d 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 ef0b06d594b..1493d7d1d96 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect.c\n@@ -20,7 +20,7 @@ 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_usage[] = {\n+static const char * const builtin_bisect_usage[] = {\n \tN_(\"git bisect help\\n\"\n \t   \"\\tprint this long help message.\"),\n \tN_(\"git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>]\\n\"\n@@ -1182,7 +1182,7 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n \t}\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 \tstruct option options[] = {\n@@ -1192,7 +1192,7 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \tconst char *command = argc > 1 ? argv[1] : \"help\";\n \n \tif (!strcmp(\"-h\", command) || !strcmp(\"help\", command))\n-\t\tusage_with_options(git_bisect_usage, options);\n+\t\tusage_with_options(builtin_bisect_usage, options);\n \n \targc -= 2;\n \targv += 2;\n@@ -1239,7 +1239,7 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\tget_terms(&terms);\n \t\tif (check_and_set_terms(&terms, command)) {\n \t\t\tchar *msg = xstrfmt(_(\"unknown command: '%s'\"), command);\n-\t\t\tusage_msg_opt(msg, git_bisect_usage, options);\n+\t\t\tusage_msg_opt(msg, builtin_bisect_usage, options);\n \t\t}\n \t\t/* shift the `command` back in */\n \t\targc++;\ndiff --git a/git-bisect.sh b/git-bisect.sh\ndeleted file mode 100755\nindex 028d39cd9ce..00000000000\n--- a/git-bisect.sh\n+++ /dev/null\n@@ -1,37 +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-exec git bisect--helper \"$@\"\ndiff --git a/git.c b/git.c\nindex edda922ce6d..a8500132a28 100644\n--- a/git.c\n+++ b/git.c\n@@ -490,7 +490,7 @@ static struct cmd_struct commands[] = {\n \t{ \"annotate\", cmd_annotate, RUN_SETUP | NO_PARSEOPT },\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-- \ngitgitgadget\n\n"},{"id":"449204","messageId":"CABPp-BEOX+zxR9-yyx-EaiOV-Z9yD0YP_Kwvu4iGB8enz40XXQ@mail.gmail.com","threadId":"57326","inReplyTo":"pull.1132.v2.git.1645547423.gitgitgadget@gmail.com","subject":"Re: [PATCH v2 00/14] Finish converting git bisect into a built-in","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2022-02-23T01:41:41Z","receivedAt":"2022-02-23T01:41:58Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Tue, Feb 22, 2022 at 8:30 AM Johannes Schindelin via GitGitGadget\n<gitgitgadget@gmail.com> wrote:\n>\n> After three GSoC/Outreachy students spent an incredible effort on this, it\n> is finally time to put a neat little bow on it.\n>\n> Changes since v1:\n>\n>  * Added a regression test to \"bisect run: fix the error message\".\n>  * Added a patch to address an error message that double-single-quoted the\n>    command.\n>  * Reworked the logic in \"bisect--helper: make --bisect-state optional\" to\n>    delay showing the usage upon an unknown command, which should make the\n>    code a lot less confusing.\n>  * Split out the change that moved the BISECT_STATE case to the end of the\n>    switch block.\n>  * Added a patch that replaces the return error() calls in\n>    cmd_bisect_helper() with die() calls, to avoid returning -1 as an exit\n>    code.\n>  * Dropped the use of parse_options() for the single purpose of handling -h;\n>    This is now done explicitly.\n>  * Simplified the diff of \"bisect: move even the option parsing to\n>    bisect--helper\" by modifying argc and argv instead of modifying all the\n>    function calls using those variables.\n>  * In the \"Turn git bisect into a full built-in\" patch, changed the name of\n>    the variable holding the usage to use the builtin_ prefix used in other\n>    built-ins, too.\n>  * Removed the trailing dot from the commit message of \"Turn git bisect into\n>    a full built-in\".\n>\n> Johannes Schindelin (14):\n>   bisect run: fix the error message\n>   bisect: avoid double-quoting when printing the failed command\n>   bisect--helper: retire the --no-log option\n>   bisect--helper: really retire --bisect-next-check\n>   bisect--helper: really retire `--bisect-autostart`\n>   bisect--helper: using `--bisect-state` without an argument is a bug\n>   bisect--helper: align the sub-command order with git-bisect.sh\n>   bisect--helper: make `--bisect-state` optional\n>   bisect--helper: move the `BISECT_STATE` case to the end\n>   bisect--helper: return only correct exit codes in `cmd_*()`\n>   bisect: move even the option parsing to `bisect--helper`\n>   Turn `git bisect` into a full built-in\n>   bisect: remove Cogito-related code\n>   bisect: no longer try to clean up left-over `.git/head-name` files\n>\n>  Makefile                               |   3 +-\n>  bisect.c                               |   3 -\n>  builtin.h                              |   2 +-\n>  builtin/{bisect--helper.c => bisect.c} | 189 ++++++++++---------------\n>  git-bisect.sh                          |  84 -----------\n>  git.c                                  |   2 +-\n>  t/t6030-bisect-porcelain.sh            |  11 +-\n>  7 files changed, 88 insertions(+), 206 deletions(-)\n>  rename builtin/{bisect--helper.c => bisect.c} (88%)\n>  delete mode 100755 git-bisect.sh\n>\n>\n> base-commit: 89bece5c8c96f0b962cfc89e63f82d603fd60bed\n> Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-1132%2Fdscho%2Fbisect-in-c-v2\n> Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1132/dscho/bisect-in-c-v2\n> Pull-Request: https://github.com/gitgitgadget/git/pull/1132\n>\n> Range-diff vs v1:\n>\n>   1:  93d19d85ee3 !  1:  81ca0d68cde bisect run: fix the error message\n>      @@ Commit message\n>           was \"good\" or \"bad\", but used a bogus (because non-populated) `args`\n>           variable for it.\n>\n>      +    Helped-by: Elijah Newren <newren@gmail.com>\n>           Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n>\n>        ## builtin/bisect--helper.c ##\n>      @@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, cons\n>                 strvec_clear(&run_args);\n>                 return res;\n>         }\n>      +\n>      + ## t/t6030-bisect-porcelain.sh ##\n>      +@@ t/t6030-bisect-porcelain.sh: test_expect_success 'bisect visualize with a filename with dash and space' '\n>      +  git bisect visualize -p -- \"-hello 2\"\n>      + '\n>      +\n>      ++test_expect_success 'testing' '\n>      ++ git bisect reset &&\n>      ++ git bisect start $HASH4 $HASH1 &&\n>      ++ write_script test_script.sh <<-\\EOF &&\n>      ++ rm .git/BISECT*\n>      ++ EOF\n>      ++ test_must_fail git bisect run ./test_script.sh 2>error &&\n>      ++ grep \"git bisect good.*exited with error code\" error\n>      ++'\n>      ++\n>      + test_done\n>   -:  ----------- >  2:  4320101f2e0 bisect: avoid double-quoting when printing the failed command\n>   2:  8e0e5559980 =  3:  88d7173c86b bisect--helper: retire the --no-log option\n>   3:  996a7099bf8 =  4:  b914fe64dda bisect--helper: really retire --bisect-next-check\n>   4:  3de4c48b66d =  5:  0d3db63bda6 bisect--helper: really retire `--bisect-autostart`\n>   8:  1b14ed3d797 =  6:  a345cf3e0e4 bisect--helper: using `--bisect-state` without an argument is a bug\n>   5:  6afc6e0eece =  7:  0487701220b bisect--helper: align the sub-command order with git-bisect.sh\n>   6:  eddbdde222a !  8:  d8b2767c148 bisect--helper: make `--bisect-state` optional\n>      @@ Commit message\n>           `git bisect--helper bad`, i.e. do not require the `--bisect-state`\n>           option to be passed explicitly.\n>\n>      -    To prepare for converting `bisect--helper` to a full built-in\n>      -    implementation of `git bisect` (which must not require the\n>      -    `--bisect-state` option to be specified at all), let's move the handling\n>      -    toward the end of the `switch (cmdmode)` block.\n>      -\n>           Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n>\n>        ## builtin/bisect--helper.c ##\n>      @@ builtin/bisect--helper.c: int cmd_bisect__helper(int argc, const char **argv, co\n>                              git_bisect_helper_usage,\n>                              PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN);\n>\n>      -+ if (!cmdmode && argc > 0) {\n>      -+         set_terms(&terms, \"bad\", \"good\");\n>      -+         get_terms(&terms);\n>      -+         if (!check_and_set_terms(&terms, argv[0]))\n>      -+                 cmdmode = BISECT_STATE;\n>      -+ }\n>      -+\n>      -  if (!cmdmode)\n>      -          usage_with_options(git_bisect_helper_usage, options);\n>      -\n>      -@@ builtin/bisect--helper.c: int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n>      +- if (!cmdmode)\n>      +-         usage_with_options(git_bisect_helper_usage, options);\n>      +-\n>      +- switch (cmdmode) {\n>      ++ switch (cmdmode ? cmdmode : BISECT_STATE) {\n>      +  case BISECT_START:\n>                 set_terms(&terms, \"bad\", \"good\");\n>                 res = bisect_start(&terms, argv, argc);\n>      -          break;\n>      -- case BISECT_STATE:\n>      --         set_terms(&terms, \"bad\", \"good\");\n>      --         get_terms(&terms);\n>      --         res = bisect_state(&terms, argv, argc);\n>      --         break;\n>      -  case BISECT_TERMS:\n>      -          if (argc > 1)\n>      -                  return error(_(\"--bisect-terms requires 0 or 1 argument\"));\n>       @@ builtin/bisect--helper.c: int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n>      +  case BISECT_STATE:\n>      +          set_terms(&terms, \"bad\", \"good\");\n>                 get_terms(&terms);\n>      -          res = bisect_run(&terms, argv, argc);\n>      -          break;\n>      -+ case BISECT_STATE:\n>      -+         if (!terms.term_good) {\n>      -+                 set_terms(&terms, \"bad\", \"good\");\n>      -+                 get_terms(&terms);\n>      ++         if (!cmdmode &&\n>      ++             (!argc || check_and_set_terms(&terms, argv[0]))) {\n>      ++                 char *msg = xstrfmt(_(\"unknown command: '%s'\"), argv[0]);\n>      ++                 usage_msg_opt(msg, git_bisect_helper_usage, options);\n>       +         }\n>      -+         res = bisect_state(&terms, argv, argc);\n>      -+         break;\n>      -  default:\n>      -          BUG(\"unknown subcommand %d\", cmdmode);\n>      -  }\n>      +          res = bisect_state(&terms, argv, argc);\n>      +          break;\n>      +  case BISECT_TERMS:\n>      +\n>      + ## git-bisect.sh ##\n>      +@@ git-bisect.sh: case \"$#\" in\n>      +  start)\n>      +          git bisect--helper --bisect-start \"$@\" ;;\n>      +  bad|good|new|old|\"$TERM_BAD\"|\"$TERM_GOOD\")\n>      +-         git bisect--helper --bisect-state \"$cmd\" \"$@\" ;;\n>      ++         git bisect--helper \"$cmd\" \"$@\" ;;\n>      +  skip)\n>      +          git bisect--helper --bisect-skip \"$@\" || exit;;\n>      +  next)\n>   -:  ----------- >  9:  e8904db81c5 bisect--helper: move the `BISECT_STATE` case to the end\n>   -:  ----------- > 10:  208f8fa4851 bisect--helper: return only correct exit codes in `cmd_*()`\n>   7:  515e86e2075 ! 11:  dc04b06206b bisect: move even the option parsing to `bisect--helper`\n>      @@ Commit message\n>           together. So it would appear as if a lot of work would have to be done\n>           just to be able to use `parse_options()` just to parse the sub-command,\n>           instead of a simple `if...else if` chain, the latter being a\n>      -    dramatically simpler implementation. Therefore, we now keep the\n>      -    `parse_options()` call primarily to support `-h` and little else.\n>      +    dramatically simpler implementation.\n>\n>           Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n>\n>      @@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, cons\n>       - argc = parse_options(argc, argv, prefix, options,\n>       -                      git_bisect_helper_usage,\n>       -                      PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN);\n>      -+ /* Handle -h and invalid options */\n>      -+ parse_options(argc - 1, argv + 1, prefix, options,\n>      -+               git_bisect_usage,\n>      -+               PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN |\n>      -+               PARSE_OPT_ONE_SHOT | PARSE_OPT_STOP_AT_NON_OPTION);\n>      -\n>      -- if (!cmdmode && argc > 0) {\n>      -+ if (!strcmp(\"help\", command))\n>      ++ if (!strcmp(\"-h\", command) || !strcmp(\"help\", command))\n>       +         usage_with_options(git_bisect_usage, options);\n>      -+ else if (!strcmp(\"start\", command)) {\n>      -          set_terms(&terms, \"bad\", \"good\");\n>      --         get_terms(&terms);\n>      --         if (!check_and_set_terms(&terms, argv[0]))\n>      --                 cmdmode = BISECT_STATE;\n>      -- }\n>      --\n>      -- if (!cmdmode)\n>      --         usage_with_options(git_bisect_helper_usage, options);\n>      --\n>      -- switch (cmdmode) {\n>      +\n>      +- switch (cmdmode ? cmdmode : BISECT_STATE) {\n>       - case BISECT_START:\n>      --         set_terms(&terms, \"bad\", \"good\");\n>      --         res = bisect_start(&terms, argv, argc);\n>      ++ argc -= 2;\n>      ++ argv += 2;\n>      ++\n>      ++ if (!strcmp(\"start\", command)) {\n>      +          set_terms(&terms, \"bad\", \"good\");\n>      +          res = bisect_start(&terms, argv, argc);\n>       -         break;\n>       - case BISECT_TERMS:\n>      --         if (argc > 1)\n>      --                 return error(_(\"--bisect-terms requires 0 or 1 argument\"));\n>      --         res = bisect_terms(&terms, argc == 1 ? argv[0] : NULL);\n>      ++ } else if (!strcmp(\"terms\", command)) {\n>      +          if (argc > 1)\n>      +-                 die(_(\"--bisect-terms requires 0 or 1 argument\"));\n>      ++                 die(_(\"'terms' requires 0 or 1 argument\"));\n>      +          res = bisect_terms(&terms, argc == 1 ? argv[0] : NULL);\n>       -         break;\n>       - case BISECT_SKIP:\n>      -+         res = bisect_start(&terms, argv + 2, argc - 2);\n>      -+ } else if (!strcmp(\"terms\", command)) {\n>      -+         if (argc > 3)\n>      -+                 return error(_(\"'terms' requires 0 or 1 argument\"));\n>      -+         res = bisect_terms(&terms, argc == 3 ? argv[2] : NULL);\n>       + } else if (!strcmp(\"skip\", command)) {\n>                 set_terms(&terms, \"bad\", \"good\");\n>                 get_terms(&terms);\n>      --         res = bisect_skip(&terms, argv, argc);\n>      +          res = bisect_skip(&terms, argv, argc);\n>       -         break;\n>       - case BISECT_NEXT:\n>      --         if (argc)\n>      --                 return error(_(\"--bisect-next requires 0 arguments\"));\n>      -+         res = bisect_skip(&terms, argv + 2, argc - 2);\n>       + } else if (!strcmp(\"next\", command)) {\n>      -+         if (argc != 2)\n>      -+                 return error(_(\"'next' requires 0 arguments\"));\n>      +          if (argc)\n>      +-                 die(_(\"--bisect-next requires 0 arguments\"));\n>      ++                 die(_(\"'next' requires 0 arguments\"));\n>                 get_terms(&terms);\n>                 res = bisect_next(&terms, prefix);\n>       -         break;\n>       - case BISECT_RESET:\n>      --         if (argc > 1)\n>      --                 return error(_(\"--bisect-reset requires either no argument or a commit\"));\n>      --         res = bisect_reset(argc ? argv[0] : NULL);\n>      ++ } else if (!strcmp(\"reset\", command)) {\n>      +          if (argc > 1)\n>      +-                 die(_(\"--bisect-reset requires either no argument or a commit\"));\n>      ++                 die(_(\"'reset' requires either no argument or a commit\"));\n>      +          res = bisect_reset(argc ? argv[0] : NULL);\n>       -         break;\n>       - case BISECT_VISUALIZE:\n>      -+ } else if (!strcmp(\"reset\", command)) {\n>      -+         if (argc > 3)\n>      -+                 return error(_(\"'reset' requires either no argument or a commit\"));\n>      -+         res = bisect_reset(argc > 2 ? argv[2] : NULL);\n>       + } else if (one_of(command, \"visualize\", \"view\", NULL)) {\n>                 get_terms(&terms);\n>      --         res = bisect_visualize(&terms, argv, argc);\n>      +          res = bisect_visualize(&terms, argv, argc);\n>       -         break;\n>       - case BISECT_REPLAY:\n>      --         if (argc != 1)\n>      -+         res = bisect_visualize(&terms, argv + 2, argc - 2);\n>       + } else if (!strcmp(\"replay\", command)) {\n>      -+         if (argc != 3)\n>      -                  return error(_(\"no logfile given\"));\n>      +          if (argc != 1)\n>      +                  die(_(\"no logfile given\"));\n>                 set_terms(&terms, \"bad\", \"good\");\n>      --         res = bisect_replay(&terms, argv[0]);\n>      +          res = bisect_replay(&terms, argv[0]);\n>       -         break;\n>       - case BISECT_LOG:\n>      --         if (argc)\n>      --                 return error(_(\"--bisect-log requires 0 arguments\"));\n>      -+         res = bisect_replay(&terms, argv[2]);\n>       + } else if (!strcmp(\"log\", command)) {\n>      -+         if (argc > 2)\n>      -+                 return error(_(\"'log' requires 0 arguments\"));\n>      +          if (argc)\n>      +-                 die(_(\"--bisect-log requires 0 arguments\"));\n>      ++                 die(_(\"'log' requires 0 arguments\"));\n>                 res = bisect_log();\n>       -         break;\n>       - case BISECT_RUN:\n>      --         if (!argc)\n>       + } else if (!strcmp(\"run\", command)) {\n>      -+         if (argc < 3)\n>      -                  return error(_(\"bisect run failed: no command provided.\"));\n>      +          if (!argc)\n>      +                  die(_(\"bisect run failed: no command provided.\"));\n>                 get_terms(&terms);\n>      --         res = bisect_run(&terms, argv, argc);\n>      +          res = bisect_run(&terms, argv, argc);\n>       -         break;\n>       - case BISECT_STATE:\n>      --         if (!terms.term_good) {\n>      --                 set_terms(&terms, \"bad\", \"good\");\n>      --                 get_terms(&terms);\n>      -+         res = bisect_run(&terms, argv + 2, argc - 2);\n>       + } else {\n>      -+         set_terms(&terms, \"bad\", \"good\");\n>      -+         get_terms(&terms);\n>      -+         if (!check_and_set_terms(&terms, command))\n>      -+                 res = bisect_state(&terms, argv + 1, argc - 1);\n>      -+         else {\n>      +          set_terms(&terms, \"bad\", \"good\");\n>      +          get_terms(&terms);\n>      +-         if (!cmdmode &&\n>      +-             (!argc || check_and_set_terms(&terms, argv[0]))) {\n>      +-                 char *msg = xstrfmt(_(\"unknown command: '%s'\"), argv[0]);\n>      +-                 usage_msg_opt(msg, git_bisect_helper_usage, options);\n>      ++         if (check_and_set_terms(&terms, command)) {\n>       +                 char *msg = xstrfmt(_(\"unknown command: '%s'\"), command);\n>       +                 usage_msg_opt(msg, git_bisect_usage, options);\n>                 }\n>      --         res = bisect_state(&terms, argv, argc);\n>      ++         /* shift the `command` back in */\n>      ++         argc++;\n>      ++         argv--;\n>      +          res = bisect_state(&terms, argv, argc);\n>       -         break;\n>       - default:\n>       -         BUG(\"unknown subcommand %d\", cmdmode);\n>      @@ git-bisect.sh: Please use \"git help bisect\" to get the full man page.'\n>       - start)\n>       -         git bisect--helper --bisect-start \"$@\" ;;\n>       - bad|good|new|old|\"$TERM_BAD\"|\"$TERM_GOOD\")\n>      --         git bisect--helper --bisect-state \"$cmd\" \"$@\" ;;\n>      +-         git bisect--helper \"$cmd\" \"$@\" ;;\n>       - skip)\n>       -         git bisect--helper --bisect-skip \"$@\" || exit;;\n>       - next)\n>   9:  1c0bd8a326f ! 12:  7db4b03b668 Turn `git bisect` into a full built-in.\n>      @@ Metadata\n>       Author: Johannes Schindelin <Johannes.Schindelin@gmx.de>\n>\n>        ## Commit message ##\n>      -    Turn `git bisect` into a full built-in.\n>      +    Turn `git bisect` into a full built-in\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>      @@ builtin.h: int cmd_am(int argc, const char **argv, const char *prefix);\n>        int cmd_bugreport(int argc, const char **argv, const char *prefix);\n>\n>        ## builtin/bisect--helper.c => builtin/bisect.c ##\n>      +@@ builtin/bisect.c: 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_usage[] = {\n>      ++static const char * const builtin_bisect_usage[] = {\n>      +  N_(\"git bisect help\\n\"\n>      +     \"\\tprint this long help message.\"),\n>      +  N_(\"git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>]\\n\"\n>       @@ builtin/bisect.c: static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n>         }\n>        }\n>      @@ builtin/bisect.c: static int bisect_run(struct bisect_terms *terms, const char *\n>        {\n>         int res = 0;\n>         struct option options[] = {\n>      +@@ builtin/bisect.c: int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n>      +  const char *command = argc > 1 ? argv[1] : \"help\";\n>      +\n>      +  if (!strcmp(\"-h\", command) || !strcmp(\"help\", command))\n>      +-         usage_with_options(git_bisect_usage, options);\n>      ++         usage_with_options(builtin_bisect_usage, options);\n>      +\n>      +  argc -= 2;\n>      +  argv += 2;\n>      +@@ builtin/bisect.c: int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n>      +          get_terms(&terms);\n>      +          if (check_and_set_terms(&terms, command)) {\n>      +                  char *msg = xstrfmt(_(\"unknown command: '%s'\"), command);\n>      +-                 usage_msg_opt(msg, git_bisect_usage, options);\n>      ++                 usage_msg_opt(msg, builtin_bisect_usage, options);\n>      +          }\n>      +          /* shift the `command` back in */\n>      +          argc++;\n>\n>        ## git-bisect.sh (deleted) ##\n>       @@\n>  10:  cce533486db = 13:  0611d16f772 bisect: remove Cogito-related code\n>  11:  dc77297c676 = 14:  e2fa11a819e bisect: no longer try to clean up left-over `.git/head-name` files\n>\n> --\n> gitgitgadget\n\nYou've addressed all my feedback from v1, and I've looked over the\nchanges and they look good to me:\n\nReviewed-by: Elijah Newren <newren@gmail.com>\n"},{"id":"449231","messageId":"220223.86v8x56g7g.gmgdl@evledraar.gmail.com","threadId":"57326","inReplyTo":"dc04b06206bbb833ce3a7fa893d724d00fe58a74.1645547423.git.gitgitgadget@gmail.com","subject":"Re: [PATCH v2 11/14] bisect: move even the option parsing to `bisect--helper`","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-02-23T09:47:36Z","receivedAt":"2022-02-23T10:16:29Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Tue, Feb 22 2022, Johannes Schindelin via GitGitGadget wrote:\n\n> From: Johannes Schindelin <johannes.schindelin@gmx.de>\n>\n> On our journey to a fully built-in `git bisect`, this is the\n> second-to-last step.\n>\n> Side note: The `if (!strcmp(...)) ... else if (!strcmp(...)) ... else if\n> (!strcmp(...)) ...` chain seen in this patch was not actually the first\n> idea how to convert the command modes to sub-commands. Since the\n> `bisect--helper` command already used the `parse-opions` API with neatly\n> set-up command modes, naturally the idea was to use `PARSE_OPT_NODASH`\n> to support proper sub-commands instead. However, the `parse-options` API\n> is not set up for that, and even after making that option work with long\n> options, it turned out that `STOP_AT_NON_OPTION` and `KEEP_UNKNOWN`\n> would have to be used but these options were not designed to work\n> together. So it would appear as if a lot of work would have to be done\n> just to be able to use `parse_options()` just to parse the sub-command,\n> instead of a simple `if...else if` chain, the latter being a\n> dramatically simpler implementation.\n\nAs I noted in\nhttps://lore.kernel.org/git/220129.86pmobauyt.gmgdl@evledraar.gmail.com/:\n\n> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> ---\n>  builtin/bisect--helper.c | 133 ++++++++++++++++-----------------------\n>  git-bisect.sh            |  49 +--------------\n>  2 files changed, 56 insertions(+), 126 deletions(-)\n>\n> diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\n> index 5228964937d..ef0b06d594b 100644\n> --- a/builtin/bisect--helper.c\n> +++ b/builtin/bisect--helper.c\n> @@ -20,18 +20,34 @@ 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> -\tN_(\"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> -\tN_(\"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> -\tN_(\"git bisect--helper --bisect-visualize\"),\n> -\tN_(\"git bisect--helper --bisect-run <cmd>...\"),\n> +static const char * const git_bisect_usage[] = {\n> +\tN_(\"git bisect help\\n\"\n> +\t   \"\\tprint this long help message.\"),\n> +\tN_(\"git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>]\\n\"\n> +\t   \"\\t\\t [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<pathspec>...]\\n\"\n> +\t   \"\\treset bisect state and start bisection.\"),\n> +\tN_(\"git bisect (bad|new) [<rev>]\\n\"\n> +\t   \"\\tmark <rev> a known-bad revision/\\n\"\n> +\t   \"\\t\\ta revision after change in a given property.\"),\n> +\tN_(\"git bisect (good|old) [<rev>...]\\n\"\n> +\t   \"\\tmark <rev>... known-good revisions/\\n\"\n> +\t   \"\\t\\trevisions before change in a given property.\"),\n> +\tN_(\"git bisect terms [--term-good | --term-bad]\\n\"\n> +\t   \"\\tshow the terms used for old and new commits (default: bad, good)\"),\n> +\tN_(\"git bisect skip [(<rev>|<range>)...]\\n\"\n> +\t   \"\\tmark <rev>... untestable revisions.\"),\n> +\tN_(\"git bisect next\\n\"\n> +\t   \"\\tfind next bisection to test and check it out.\"),\n> +\tN_(\"git bisect reset [<commit>]\\n\"\n> +\t   \"\\tfinish bisection search and go back to commit.\"),\n> +\tN_(\"git bisect (visualize|view)\\n\"\n> +\t   \"\\tshow bisect status in gitk.\"),\n> +\tN_(\"git bisect replay <logfile>\\n\"\n> +\t   \"\\treplay bisection log.\"),\n> +\tN_(\"git bisect log\\n\"\n> +\t   \"\\tshow bisect log.\"),\n> +\tN_(\"git bisect run <cmd>...\\n\"\n> +\t   \"\\tuse <cmd>... to automatically bisect.\"),\n>  \tNULL\n>  };\n\nEven that doesn't explain why this needs to be changed as\nwell. I.e. this could just be:\n\t\n\tdiff --git a/builtin/bisect.c b/builtin/bisect.c\n\tindex e8a346fa516..d27b80ddaf3 100644\n\t--- a/builtin/bisect.c\n\t+++ b/builtin/bisect.c\n\t@@ -20,33 +20,18 @@ static GIT_PATH_FUNC(git_path_bisect_first_parent, \"BISECT_FIRST_PARENT\")\n\t static GIT_PATH_FUNC(git_path_bisect_run, \"BISECT_RUN\")\n\t \n\t static const char * const builtin_bisect_usage[] = {\n\t-\tN_(\"git bisect help\\n\"\n\t-\t   \"\\tprint this long help message.\"),\n\t+\tN_(\"git bisect reset [<commit>]\"),\n\t+\tN_(\"git bisect terms [--term-good | --term-old | --term-bad | --term-new]\"),\n\t \tN_(\"git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>]\\n\"\n\t-\t   \"\\t\\t [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<pathspec>...]\\n\"\n\t-\t   \"\\treset bisect state and start bisection.\"),\n\t-\tN_(\"git bisect (bad|new) [<rev>]\\n\"\n\t-\t   \"\\tmark <rev> a known-bad revision/\\n\"\n\t-\t   \"\\t\\ta revision after change in a given property.\"),\n\t-\tN_(\"git bisect (good|old) [<rev>...]\\n\"\n\t-\t   \"\\tmark <rev>... known-good revisions/\\n\"\n\t-\t   \"\\t\\trevisions before change in a given property.\"),\n\t-\tN_(\"git bisect terms [--term-good | --term-bad]\\n\"\n\t-\t   \"\\tshow the terms used for old and new commits (default: bad, good)\"),\n\t-\tN_(\"git bisect skip [(<rev>|<range>)...]\\n\"\n\t-\t   \"\\tmark <rev>... untestable revisions.\"),\n\t-\tN_(\"git bisect next\\n\"\n\t-\t   \"\\tfind next bisection to test and check it out.\"),\n\t-\tN_(\"git bisect reset [<commit>]\\n\"\n\t-\t   \"\\tfinish bisection search and go back to commit.\"),\n\t-\tN_(\"git bisect (visualize|view)\\n\"\n\t-\t   \"\\tshow bisect status in gitk.\"),\n\t-\tN_(\"git bisect replay <logfile>\\n\"\n\t-\t   \"\\treplay bisection log.\"),\n\t-\tN_(\"git bisect log\\n\"\n\t-\t   \"\\tshow bisect log.\"),\n\t-\tN_(\"git bisect run <cmd>...\\n\"\n\t-\t   \"\\tuse <cmd>... to automatically bisect.\"),\n\t+\t   \"                 [--no-checkout] [--first-parent] [<bad> [<good>...]]\\n\"\n\t+\t   \"                 [--] [<paths>...]\"),\n\t+\tN_(\"git bisect next\"),\n\t+\tN_(\"git bisect state (bad|new) [<rev>]\"),\n\t+\tN_(\"git bisect state (good|old) [<rev>...]\"),\n\t+\tN_(\"git bisect replay <filename>\"),\n\t+\tN_(\"git bisect skip [(<rev>|<range>)...]\"),\n\t+\tN_(\"git bisect visualize\"),\n\t+\tN_(\"git bisect run <cmd>...\"),\n\t \tNULL\n\t };\n\nWhich turns the help output into:\n    \n    $ ./git bisect -h\n    usage: git bisect reset [<commit>]\n       or: git bisect terms [--term-good | --term-old | --term-bad | --term-new]\n       or: git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>]\n                            [--no-checkout] [--first-parent] [<bad> [<good>...]]\n                            [--] [<paths>...]\n       or: git bisect next\n       or: git bisect state (bad|new) [<rev>]\n       or: git bisect state (good|old) [<rev>...]\n       or: git bisect replay <filename>\n       or: git bisect skip [(<rev>|<range>)...]\n       or: git bisect visualize\n       or: git bisect run <cmd>...\n\nInstead of:\n    \n    $ ./git bisect -h\n    usage: git bisect help\n            print this long help message.\n       or: git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>]\n                     [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<pathspec>...]\n            reset bisect state and start bisection.\n       or: git bisect (bad|new) [<rev>]\n            mark <rev> a known-bad revision/\n                    a revision after change in a given property.\n       or: git bisect (good|old) [<rev>...]\n            mark <rev>... known-good revisions/\n                    revisions before change in a given property.\n       or: git bisect terms [--term-good | --term-bad]\n            show the terms used for old and new commits (default: bad, good)\n       or: git bisect skip [(<rev>|<range>)...]\n            mark <rev>... untestable revisions.\n       or: git bisect next\n            find next bisection to test and check it out.\n       or: git bisect reset [<commit>]\n            finish bisection search and go back to commit.\n       or: git bisect (visualize|view)\n            show bisect status in gitk.\n       or: git bisect replay <logfile>\n            replay bisection log.\n       or: git bisect log\n            show bisect log.\n       or: git bisect run <cmd>...\n            use <cmd>... to automatically bisect.\n\nI.e. parse_options() != the usage_with_options() formatting function in\nparse-options.c. You can use one without using the other. The commit\nmessage only claims (wrongly I think, but let's leave that aside for the\nmoment) that we can't use parse_options(), but doesn't say why we *also*\nneed to move to doing our own formatting of the usage output, those are\ntwo different things.\n\nAs I noted in the previous round I think you were trying to retain the\nOPT_CMDMODE help messages. We could use the \"\" parse_options() usage\nfeature to emit output similar to \"git bisect--helper -h\", but I think\njust having it by the same as current built-ins is fine.\n\nI.e. for \"stash\" etc. we're not emitting human readable help\nexplanations along with every subcommand, and could just do the same for\n\"git bisect\".\n\nBut on to parse_options() usage:\n\n> @@ -1168,108 +1184,69 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n>  \n>  int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n>  {\n> -\tenum {\n> -\t\tBISECT_START = 1,\n> -\t\tBISECT_STATE,\n> -\t\tBISECT_TERMS,\n> -\t\tBISECT_SKIP,\n> -\t\tBISECT_NEXT,\n> -\t\tBISECT_RESET,\n> -\t\tBISECT_VISUALIZE,\n> -\t\tBISECT_REPLAY,\n> -\t\tBISECT_LOG,\n> -\t\tBISECT_RUN,\n> -\t} cmdmode = 0;\n>  \tint res = 0;\n>  \tstruct option options[] = {\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-state\", &cmdmode,\n> -\t\t\t N_(\"mark the state of ref (or refs)\"), BISECT_STATE),\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-skip\", &cmdmode,\n> -\t\t\t N_(\"skip some commits for checkout\"), BISECT_SKIP),\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-reset\", &cmdmode,\n> -\t\t\t N_(\"reset the bisection state\"), BISECT_RESET),\n> -\t\tOPT_CMDMODE(0, \"bisect-visualize\", &cmdmode,\n> -\t\t\t N_(\"visualize the bisection\"), BISECT_VISUALIZE),\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-log\", &cmdmode,\n> -\t\t\t N_(\"list the bisection steps so far\"), BISECT_LOG),\n> -\t\tOPT_CMDMODE(0, \"bisect-run\", &cmdmode,\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> +\tconst char *command = argc > 1 ? argv[1] : \"help\";\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);\n\nBecause of thinking that we need to get rid of parse_options() here\nwe...\n\n> +\tif (!strcmp(\"-h\", command) || !strcmp(\"help\", command))\n> +\t\tusage_with_options(git_bisect_usage, options);\n\n...end up duplicating some of its behavior here...\n\n>  \n> -\tswitch (cmdmode ? cmdmode : BISECT_STATE) {\n> -\tcase BISECT_START:\n> +\targc -= 2;\n> +\targv += 2;\n> +\n> +\tif (!strcmp(\"start\", command)) {\n>  \t\tset_terms(&terms, \"bad\", \"good\");\n>  \t\tres = bisect_start(&terms, argv, argc);\n> -\t\tbreak;\n> -\tcase BISECT_TERMS:\n> +\t} else if (!strcmp(\"terms\", command)) {\n>  \t\tif (argc > 1)\n> -\t\t\tdie(_(\"--bisect-terms requires 0 or 1 argument\"));\n> +\t\t\tdie(_(\"'terms' requires 0 or 1 argument\"));\n>  \t\tres = bisect_terms(&terms, argc == 1 ? argv[0] : NULL);\n> -\t\tbreak;\n> -\tcase BISECT_SKIP:\n> +\t} else if (!strcmp(\"skip\", command)) {\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_NEXT:\n> +\t} else if (!strcmp(\"next\", command)) {\n>  \t\tif (argc)\n> -\t\t\tdie(_(\"--bisect-next requires 0 arguments\"));\n> +\t\t\tdie(_(\"'next' requires 0 arguments\"));\n>  \t\tget_terms(&terms);\n>  \t\tres = bisect_next(&terms, prefix);\n> -\t\tbreak;\n> -\tcase BISECT_RESET:\n> +\t} else if (!strcmp(\"reset\", command)) {\n>  \t\tif (argc > 1)\n> -\t\t\tdie(_(\"--bisect-reset requires either no argument or a commit\"));\n> +\t\t\tdie(_(\"'reset' requires either no argument or a commit\"));\n>  \t\tres = bisect_reset(argc ? argv[0] : NULL);\n> -\t\tbreak;\n> -\tcase BISECT_VISUALIZE:\n> +\t} else if (one_of(command, \"visualize\", \"view\", NULL)) {\n>  \t\tget_terms(&terms);\n>  \t\tres = bisect_visualize(&terms, argv, argc);\n> -\t\tbreak;\n> -\tcase BISECT_REPLAY:\n> +\t} else if (!strcmp(\"replay\", command)) {\n>  \t\tif (argc != 1)\n>  \t\t\tdie(_(\"no logfile given\"));\n>  \t\tset_terms(&terms, \"bad\", \"good\");\n>  \t\tres = bisect_replay(&terms, argv[0]);\n> -\t\tbreak;\n> -\tcase BISECT_LOG:\n> +\t} else if (!strcmp(\"log\", command)) {\n>  \t\tif (argc)\n> -\t\t\tdie(_(\"--bisect-log requires 0 arguments\"));\n> +\t\t\tdie(_(\"'log' requires 0 arguments\"));\n>  \t\tres = bisect_log();\n> -\t\tbreak;\n> -\tcase BISECT_RUN:\n> +\t} else if (!strcmp(\"run\", command)) {\n>  \t\tif (!argc)\n>  \t\t\tdie(_(\"bisect run failed: no command provided.\"));\n>  \t\tget_terms(&terms);\n>  \t\tres = bisect_run(&terms, argv, argc);\n> -\t\tbreak;\n> -\tcase BISECT_STATE:\n> +\t} else {\n>  \t\tset_terms(&terms, \"bad\", \"good\");\n>  \t\tget_terms(&terms);\n> -\t\tif (!cmdmode &&\n> -\t\t    (!argc || check_and_set_terms(&terms, argv[0]))) {\n> -\t\t\tchar *msg = xstrfmt(_(\"unknown command: '%s'\"), argv[0]);\n> -\t\t\tusage_msg_opt(msg, git_bisect_helper_usage, options);\n> +\t\tif (check_and_set_terms(&terms, command)) {\n> +\t\t\tchar *msg = xstrfmt(_(\"unknown command: '%s'\"), command);\n> +\t\t\tusage_msg_opt(msg, git_bisect_usage, options);\n\n[Change this usage_msg_opt() to a usage_msg_optf() and drop the\nxstrfmt()]\n\n>  \t\t}\n> +\t\t/* shift the `command` back in */\n> +\t\targc++;\n> +\t\targv--;\n>  \t\tres = bisect_state(&terms, argv, argc);\n> -\t\tbreak;\n> -\tdefault:\n> -\t\tBUG(\"unknown subcommand %d\", cmdmode);\n>  \t}\n\n..and introducing bugs here, e.g. \"git bisect --blah\" is now a valid way\nto start a bisect\", we no longer understand \"git bisect <subcommand>\n-h\", but did before etc.\n\nIs the reason for further extending the custom command parser here\nbecause of e.g. the \"die(..requires N arguments\"? For all of those this\ncould follow the pattern that builtin/commit-graph.c etc. use.\n\nI.e. just define a usage for say \"log\", and empty options, then pass\nargc/argv to that subcommand, and have it call parse_options().\n\nThen not only will the user get an error, they'll get the subset of \"git\nbisect -h\" output appropriate for whatever \"git bisect subcommand <bad\nusage>\" they invoked.\n"},{"id":"449347","messageId":"xmqqo82xs1ue.fsf@gitster.g","threadId":"57326","inReplyTo":"pull.1132.v2.git.1645547423.gitgitgadget@gmail.com","subject":"Re: [PATCH v2 00/14] Finish converting git bisect into a built-in","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-02-23T21:35:37Z","receivedAt":"2022-02-23T21:35:46Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Johannes Schindelin via GitGitGadget\" <gitgitgadget@gmail.com>\nwrites:\n\n> After three GSoC/Outreachy students spent an incredible effort on this, it\n> is finally time to put a neat little bow on it.\n\nThanks for tying the loose ends.  I've read the previous one and\nalso this round, and except for the parse-options bit I am not sure\nabout (read: I do not have a strong objection, but I do have to\nwonder if there is a better way to achieve the goal), everything\nelse looks good.\n\nWill queue.\n\n"},{"id":"449590","messageId":"nycvar.QRO.7.76.6.2202251647370.11118@tvgsbejvaqbjf.bet","threadId":"57326","inReplyTo":"220223.86v8x56g7g.gmgdl@evledraar.gmail.com","subject":"Re: [PATCH v2 11/14] bisect: move even the option parsing to `bisect--helper`","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2022-02-25T15:59:13Z","receivedAt":"2022-02-25T15:59:23Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Ævar,\n\nOn Wed, 23 Feb 2022, Ævar Arnfjörð Bjarmason wrote:\n\n> On Tue, Feb 22 2022, Johannes Schindelin via GitGitGadget wrote:\n>\n> > From: Johannes Schindelin <johannes.schindelin@gmx.de>\n> >\n> > On our journey to a fully built-in `git bisect`, this is the\n> > second-to-last step.\n> >\n> > Side note: The `if (!strcmp(...)) ... else if (!strcmp(...)) ... else if\n> > (!strcmp(...)) ...` chain seen in this patch was not actually the first\n> > idea how to convert the command modes to sub-commands. Since the\n> > `bisect--helper` command already used the `parse-opions` API with neatly\n> > set-up command modes, naturally the idea was to use `PARSE_OPT_NODASH`\n> > to support proper sub-commands instead. However, the `parse-options` API\n> > is not set up for that, and even after making that option work with long\n> > options, it turned out that `STOP_AT_NON_OPTION` and `KEEP_UNKNOWN`\n> > would have to be used but these options were not designed to work\n> > together. So it would appear as if a lot of work would have to be done\n> > just to be able to use `parse_options()` just to parse the sub-command,\n> > instead of a simple `if...else if` chain, the latter being a\n> > dramatically simpler implementation.\n>\n> As I noted in\n> https://lore.kernel.org/git/220129.86pmobauyt.gmgdl@evledraar.gmail.com/:\n>\n> > Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> > ---\n> >  builtin/bisect--helper.c | 133 ++++++++++++++++-----------------------\n> >  git-bisect.sh            |  49 +--------------\n> >  2 files changed, 56 insertions(+), 126 deletions(-)\n> >\n> > diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\n> > index 5228964937d..ef0b06d594b 100644\n> > --- a/builtin/bisect--helper.c\n> > +++ b/builtin/bisect--helper.c\n> > @@ -20,18 +20,34 @@ 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> > -\tN_(\"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> > -\tN_(\"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> > -\tN_(\"git bisect--helper --bisect-visualize\"),\n> > -\tN_(\"git bisect--helper --bisect-run <cmd>...\"),\n> > +static const char * const git_bisect_usage[] = {\n> > +\tN_(\"git bisect help\\n\"\n> > +\t   \"\\tprint this long help message.\"),\n> > +\tN_(\"git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>]\\n\"\n> > +\t   \"\\t\\t [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<pathspec>...]\\n\"\n> > +\t   \"\\treset bisect state and start bisection.\"),\n> > +\tN_(\"git bisect (bad|new) [<rev>]\\n\"\n> > +\t   \"\\tmark <rev> a known-bad revision/\\n\"\n> > +\t   \"\\t\\ta revision after change in a given property.\"),\n> > +\tN_(\"git bisect (good|old) [<rev>...]\\n\"\n> > +\t   \"\\tmark <rev>... known-good revisions/\\n\"\n> > +\t   \"\\t\\trevisions before change in a given property.\"),\n> > +\tN_(\"git bisect terms [--term-good | --term-bad]\\n\"\n> > +\t   \"\\tshow the terms used for old and new commits (default: bad, good)\"),\n> > +\tN_(\"git bisect skip [(<rev>|<range>)...]\\n\"\n> > +\t   \"\\tmark <rev>... untestable revisions.\"),\n> > +\tN_(\"git bisect next\\n\"\n> > +\t   \"\\tfind next bisection to test and check it out.\"),\n> > +\tN_(\"git bisect reset [<commit>]\\n\"\n> > +\t   \"\\tfinish bisection search and go back to commit.\"),\n> > +\tN_(\"git bisect (visualize|view)\\n\"\n> > +\t   \"\\tshow bisect status in gitk.\"),\n> > +\tN_(\"git bisect replay <logfile>\\n\"\n> > +\t   \"\\treplay bisection log.\"),\n> > +\tN_(\"git bisect log\\n\"\n> > +\t   \"\\tshow bisect log.\"),\n> > +\tN_(\"git bisect run <cmd>...\\n\"\n> > +\t   \"\\tuse <cmd>... to automatically bisect.\"),\n> >  \tNULL\n> >  };\n>\n> Even that doesn't explain why this needs to be changed as\n> well.\n\nTrue. The explanation is easy: I am not in the business of changing the\nusage shown by `git bisect -h`.\n\n> we no longer understand \"git bisect <subcommand> -h\", but did before\n> etc.\n\n... for some definition of \"understand\" ;-) See for yourself:\n\n\t$ git bisect visualize -h\n\tusage: git bisect--helper --bisect-reset [<commit>]\n\t   or: git bisect--helper --bisect-terms [--term-good | --term-old | --term-bad | --term-new]\n\t   or: git bisect--helper --bisect-start [--term-{new,bad}=<term> --term-{old,good}=<term>] [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<paths>...]\n\t   or: git bisect--helper --bisect-next\n\t   or: git bisect--helper --bisect-state (bad|new) [<rev>]\n\t   or: git bisect--helper --bisect-state (good|old) [<rev>...]\n\t   or: git bisect--helper --bisect-replay <filename>\n\t   or: git bisect--helper --bisect-skip [(<rev>|<range>)...]\n\t   or: git bisect--helper --bisect-visualize\n\t   or: git bisect--helper --bisect-run <cmd>...\n\n\t    --bisect-reset        reset the bisection state\n\t    --bisect-next-check   check whether bad or good terms exist\n\t    --bisect-terms        print out the bisect terms\n\t    --bisect-start        start the bisect session\n\t    --bisect-next         find the next bisection commit\n\t    --bisect-state        mark the state of ref (or refs)\n\t    --bisect-log          list the bisection steps so far\n\t    --bisect-replay       replay the bisection process from the given file\n\t    --bisect-skip         skip some commits for checkout\n\t    --bisect-visualize    visualize the bisection\n\t    --bisect-run          use <cmd>... to automatically bisect.\n\t    --no-log              no log for BISECT_WRITE\n\nThat's not a helpful usage for `git bisect visualize`. It's better to\nleave it to a future patch for `bisect_visualize()` to handle `-h`.\n\nIn other words, what you point out as a bug is actually fixing one.\n\nI find the other comments on not using the `parse_options()` machinery\nsimilar, and your feedback seems to flatly dismiss the side note in the\ncommit message as irrelevant.\n\nTo be clear: I spent a substantial amount of time trying to extend the\n`parse_options()` machinery to support dash-less subcommands. The end\nresult was neither elegant nor particularly useful.\n\nSo, with all due respect, I disagree with your disagreeing.\n\nCiao,\nJohannes\n"},{"id":"449591","messageId":"nycvar.QRO.7.76.6.2202251659300.11118@tvgsbejvaqbjf.bet","threadId":"57326","inReplyTo":"CABPp-BEOX+zxR9-yyx-EaiOV-Z9yD0YP_Kwvu4iGB8enz40XXQ@mail.gmail.com","subject":"Re: [PATCH v2 00/14] Finish converting git bisect into a built-in","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2022-02-25T15:59:54Z","receivedAt":"2022-02-25T16:00:01Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Elijah,\n\nOn Tue, 22 Feb 2022, Elijah Newren wrote:\n\n> You've addressed all my feedback from v1, and I've looked over the\n> changes and they look good to me:\n>\n> Reviewed-by: Elijah Newren <newren@gmail.com>\n\nThank you for helping me improve the patch series!\nDscho\n"},{"id":"449593","messageId":"nycvar.QRO.7.76.6.2202251700110.11118@tvgsbejvaqbjf.bet","threadId":"57326","inReplyTo":"xmqqo82xs1ue.fsf@gitster.g","subject":"Re: [PATCH v2 00/14] Finish converting git bisect into a built-in","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2022-02-25T16:03:08Z","receivedAt":"2022-02-25T16:03:20Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Wed, 23 Feb 2022, Junio C Hamano wrote:\n\n> [...] the parse-options bit I am not sure about (read: I do not have a\n> strong objection, but I do have to wonder if there is a better way to\n> achieve the goal) [...]\n\nAfter spending a lot of time to try to make it work, I realized that it's\nin the name of `parse_options()` that it's not a `handle_subcommand()`\nAPI.\n\nSo yes, I agree there is probably a better way (and e.g. `git bundle`\nand `scalar` would benefit from it, too): designing a proper API for\nhandling subcommands.\n\nThat's safely outside the scope of the patch series, of course.\n\n> Will queue.\n\nThanks,\nDscho\n"},{"id":"449601","messageId":"220225.86mtie7v1k.gmgdl@evledraar.gmail.com","threadId":"57326","inReplyTo":"nycvar.QRO.7.76.6.2202251700110.11118@tvgsbejvaqbjf.bet","subject":"Re: [PATCH v2 00/14] Finish converting git bisect into a built-in","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-02-25T16:44:10Z","receivedAt":"2022-02-25T16:47:41Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Fri, Feb 25 2022, Johannes Schindelin wrote:\n\n> Hi Junio,\n>\n> On Wed, 23 Feb 2022, Junio C Hamano wrote:\n>\n>> [...] the parse-options bit I am not sure about (read: I do not have a\n>> strong objection, but I do have to wonder if there is a better way to\n>> achieve the goal) [...]\n>\n> After spending a lot of time to try to make it work, I realized that it's\n> in the name of `parse_options()` that it's not a `handle_subcommand()`\n> API.\n>\n> So yes, I agree there is probably a better way (and e.g. `git bundle`\n> and `scalar` would benefit from it, too): designing a proper API for\n> handling subcommands.\n>\n> That's safely outside the scope of the patch series, of course.\n\nI think SZEDER has some out-of-tree patches to do that, for what it's\nworth.\n\nBut it's not emit_usage_info() either (at least not directly), and we\nalso use it for that.\n\nSo this seems like a distraction from the feedback I provided on your\npatch.\n\nWhich for one is that due to bugs in the conversion things that emitted\nusage errors before are now silently accepted.\n\nAnd that whatever we do to make things *easier* for\nbundle/stash/commit-graph etc. when it comes to this, doesn't explain\nwhy you feel the need to introduce yet another pattern of doing this,\nwhen the existing \"handle subcommands\" built-ins do it rather uniformly,\nand AFAICT there's nothing in the \"git bisect\" case that's special\nenough that it wouldn't be served by pretty much copying that template.\n"},{"id":"449602","messageId":"220225.86ilt27uln.gmgdl@evledraar.gmail.com","threadId":"57326","inReplyTo":"nycvar.QRO.7.76.6.2202251647370.11118@tvgsbejvaqbjf.bet","subject":"Re: [PATCH v2 11/14] bisect: move even the option parsing to `bisect--helper`","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-02-25T16:49:26Z","receivedAt":"2022-02-25T16:57:04Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Fri, Feb 25 2022, Johannes Schindelin wrote:\n\n> Hi Ævar,\n>\n> On Wed, 23 Feb 2022, Ævar Arnfjörð Bjarmason wrote:\n>\n>> On Tue, Feb 22 2022, Johannes Schindelin via GitGitGadget wrote:\n>>\n>> > From: Johannes Schindelin <johannes.schindelin@gmx.de>\n>> >\n>> > On our journey to a fully built-in `git bisect`, this is the\n>> > second-to-last step.\n>> >\n>> > Side note: The `if (!strcmp(...)) ... else if (!strcmp(...)) ... else if\n>> > (!strcmp(...)) ...` chain seen in this patch was not actually the first\n>> > idea how to convert the command modes to sub-commands. Since the\n>> > `bisect--helper` command already used the `parse-opions` API with neatly\n>> > set-up command modes, naturally the idea was to use `PARSE_OPT_NODASH`\n>> > to support proper sub-commands instead. However, the `parse-options` API\n>> > is not set up for that, and even after making that option work with long\n>> > options, it turned out that `STOP_AT_NON_OPTION` and `KEEP_UNKNOWN`\n>> > would have to be used but these options were not designed to work\n>> > together. So it would appear as if a lot of work would have to be done\n>> > just to be able to use `parse_options()` just to parse the sub-command,\n>> > instead of a simple `if...else if` chain, the latter being a\n>> > dramatically simpler implementation.\n>>\n>> As I noted in\n>> https://lore.kernel.org/git/220129.86pmobauyt.gmgdl@evledraar.gmail.com/:\n>>\n>> > Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n>> > ---\n>> >  builtin/bisect--helper.c | 133 ++++++++++++++++-----------------------\n>> >  git-bisect.sh            |  49 +--------------\n>> >  2 files changed, 56 insertions(+), 126 deletions(-)\n>> >\n>> > diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\n>> > index 5228964937d..ef0b06d594b 100644\n>> > --- a/builtin/bisect--helper.c\n>> > +++ b/builtin/bisect--helper.c\n>> > @@ -20,18 +20,34 @@ 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>> > -\tN_(\"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>> > -\tN_(\"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>> > -\tN_(\"git bisect--helper --bisect-visualize\"),\n>> > -\tN_(\"git bisect--helper --bisect-run <cmd>...\"),\n>> > +static const char * const git_bisect_usage[] = {\n>> > +\tN_(\"git bisect help\\n\"\n>> > +\t   \"\\tprint this long help message.\"),\n>> > +\tN_(\"git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>]\\n\"\n>> > +\t   \"\\t\\t [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<pathspec>...]\\n\"\n>> > +\t   \"\\treset bisect state and start bisection.\"),\n>> > +\tN_(\"git bisect (bad|new) [<rev>]\\n\"\n>> > +\t   \"\\tmark <rev> a known-bad revision/\\n\"\n>> > +\t   \"\\t\\ta revision after change in a given property.\"),\n>> > +\tN_(\"git bisect (good|old) [<rev>...]\\n\"\n>> > +\t   \"\\tmark <rev>... known-good revisions/\\n\"\n>> > +\t   \"\\t\\trevisions before change in a given property.\"),\n>> > +\tN_(\"git bisect terms [--term-good | --term-bad]\\n\"\n>> > +\t   \"\\tshow the terms used for old and new commits (default: bad, good)\"),\n>> > +\tN_(\"git bisect skip [(<rev>|<range>)...]\\n\"\n>> > +\t   \"\\tmark <rev>... untestable revisions.\"),\n>> > +\tN_(\"git bisect next\\n\"\n>> > +\t   \"\\tfind next bisection to test and check it out.\"),\n>> > +\tN_(\"git bisect reset [<commit>]\\n\"\n>> > +\t   \"\\tfinish bisection search and go back to commit.\"),\n>> > +\tN_(\"git bisect (visualize|view)\\n\"\n>> > +\t   \"\\tshow bisect status in gitk.\"),\n>> > +\tN_(\"git bisect replay <logfile>\\n\"\n>> > +\t   \"\\treplay bisection log.\"),\n>> > +\tN_(\"git bisect log\\n\"\n>> > +\t   \"\\tshow bisect log.\"),\n>> > +\tN_(\"git bisect run <cmd>...\\n\"\n>> > +\t   \"\\tuse <cmd>... to automatically bisect.\"),\n>> >  \tNULL\n>> >  };\n>>\n>> Even that doesn't explain why this needs to be changed as\n>> well.\n>\n> True. The explanation is easy: I am not in the business of changing the\n> usage shown by `git bisect -h`.\n\nYou are changing it, here's the diff between \"master\" and \"seen\":\n\t\n\t--- b\t2022-02-25 17:49:07.264273673 +0100\n\t+++ a\t2022-02-25 17:48:46.076460197 +0100\n\t@@ -1,31 +1,28 @@\n\t-usage: git bisect [help|start|bad|good|new|old|terms|skip|next|reset|visualize|view|replay|log|run]\n\t+usage: git bisect help\n\t+       \tprint this long help message.\n\t+   or: git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>]\n\t+       \t\t [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<pathspec>...]\n\t+       \treset bisect state and start bisection.\n\t+   or: git bisect (bad|new) [<rev>]\n\t+       \tmark <rev> a known-bad revision/\n\t+       \t\ta revision after change in a given property.\n\t+   or: git bisect (good|old) [<rev>...]\n\t+       \tmark <rev>... known-good revisions/\n\t+       \t\trevisions before change in a given property.\n\t+   or: git bisect terms [--term-good | --term-bad]\n\t+       \tshow the terms used for old and new commits (default: bad, good)\n\t+   or: git bisect skip [(<rev>|<range>)...]\n\t+       \tmark <rev>... untestable revisions.\n\t+   or: git bisect next\n\t+       \tfind next bisection to test and check it out.\n\t+   or: git bisect reset [<commit>]\n\t+       \tfinish bisection search and go back to commit.\n\t+   or: git bisect (visualize|view)\n\t+       \tshow bisect status in gitk.\n\t+   or: git bisect replay <logfile>\n\t+       \treplay bisection log.\n\t+   or: git bisect log\n\t+       \tshow bisect log.\n\t+   or: git bisect run <cmd>...\n\t+       \tuse <cmd>... to automatically bisect.\n\t \n\t-git bisect help\n\t-\tprint this long help message.\n\t-git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>]\n\t-\t\t [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<pathspec>...]\n\t-\treset bisect state and start bisection.\n\t-git bisect (bad|new) [<rev>]\n\t-\tmark <rev> a known-bad revision/\n\t-\t\ta revision after change in a given property.\n\t-git bisect (good|old) [<rev>...]\n\t-\tmark <rev>... known-good revisions/\n\t-\t\trevisions before change in a given property.\n\t-git bisect terms [--term-good | --term-bad]\n\t-\tshow the terms used for old and new commits (default: bad, good)\n\t-git bisect skip [(<rev>|<range>)...]\n\t-\tmark <rev>... untestable revisions.\n\t-git bisect next\n\t-\tfind next bisection to test and check it out.\n\t-git bisect reset [<commit>]\n\t-\tfinish bisection search and go back to commit.\n\t-git bisect (visualize|view)\n\t-\tshow bisect status in gitk.\n\t-git bisect replay <logfile>\n\t-\treplay bisection log.\n\t-git bisect log\n\t-\tshow bisect log.\n\t-git bisect run <cmd>...\n\t-\tuse <cmd>... to automatically bisect.\n\t-\n\t-Please use \"git help bisect\" to get the full man page.\n\nI think such changes are fine, but if you don't then actually\nparse_options() would make that easier to emit with the \"\" delimiter,\ni.e. to mark up the rest as free-form text, as it is now.\n\nBut I don't see why you'd view that as a goal, for the rest of built-in\nmigrations we've changed this human-readable output in various ways\nwhile we were at it.\n\n>> we no longer understand \"git bisect <subcommand> -h\", but did before\n>> etc.\n>\n> ... for some definition of \"understand\" ;-) See for yourself:\n>\n> \t$ git bisect visualize -h\n> \tusage: git bisect--helper --bisect-reset [<commit>]\n> \t   or: git bisect--helper --bisect-terms [--term-good | --term-old | --term-bad | --term-new]\n> \t   or: git bisect--helper --bisect-start [--term-{new,bad}=<term> --term-{old,good}=<term>] [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<paths>...]\n> \t   or: git bisect--helper --bisect-next\n> \t   or: git bisect--helper --bisect-state (bad|new) [<rev>]\n> \t   or: git bisect--helper --bisect-state (good|old) [<rev>...]\n> \t   or: git bisect--helper --bisect-replay <filename>\n> \t   or: git bisect--helper --bisect-skip [(<rev>|<range>)...]\n> \t   or: git bisect--helper --bisect-visualize\n> \t   or: git bisect--helper --bisect-run <cmd>...\n>\n> \t    --bisect-reset        reset the bisection state\n> \t    --bisect-next-check   check whether bad or good terms exist\n> \t    --bisect-terms        print out the bisect terms\n> \t    --bisect-start        start the bisect session\n> \t    --bisect-next         find the next bisection commit\n> \t    --bisect-state        mark the state of ref (or refs)\n> \t    --bisect-log          list the bisection steps so far\n> \t    --bisect-replay       replay the bisection process from the given file\n> \t    --bisect-skip         skip some commits for checkout\n> \t    --bisect-visualize    visualize the bisection\n> \t    --bisect-run          use <cmd>... to automatically bisect.\n> \t    --no-log              no log for BISECT_WRITE\n>\n> That's not a helpful usage for `git bisect visualize`. It's better to\n> leave it to a future patch for `bisect_visualize()` to handle `-h`.\n\nYes, it could be better, but with your changes:\n\n    git bisect start -h\n\nOr whatever will start a bisection session.\n\n> In other words, what you point out as a bug is actually fixing one.\n\n...\n\n> I find the other comments on not using the `parse_options()` machinery\n> similar, and your feedback seems to flatly dismiss the side note in the\n> commit message as irrelevant.\n>\n> To be clear: I spent a substantial amount of time trying to extend the\n> `parse_options()` machinery to support dash-less subcommands. The end\n> result was neither elegant nor particularly useful.\n>\n> So, with all due respect, I disagree with your disagreeing.\n\nYes I agree that trying to get parse_option() to consider --bisect-reset\nimplicitly as \"reset\" is a dead-end.\n\nWhat I'm pointing out is that we could do it exactly as bisect/stash\netc. do it. I don't see how you ended up concluding that your conversion\nneeded to do anything different, and failing that that you couldn't use\nparse_options() at all. Just use it like those other commands use it.\n"},{"id":"455673","messageId":"pull.1132.v3.git.1653144546.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v2.git.1645547423.gitgitgadget@gmail.com","subject":"[PATCH v3 00/15] Finish converting git bisect into a built-in","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-05-21T14:48:51Z","receivedAt":"2022-05-21T14:49:20Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"After three GSoC/Outreachy students spent an incredible effort on this, it\nis finally time to put a neat little bow on it.\n\nChanges since v2:\n\n * We're now careful to provide identical usage strings upon git bisect -h\n   and git bisect bogus.\n * When a bogus command is provided, we now error out instead of trying to\n   start a git bisect run.\n * Rebased onto main to avoid plenty of merge conflicts with\n   rs/bisect-executable-not-found, ac/usage-string-fixups and with\n   cd/bisect-messages-from-pre-flight-states.\n\nChanges since v1:\n\n * Added a regression test to \"bisect run: fix the error message\".\n * Added a patch to address an error message that double-single-quoted the\n   command.\n * Reworked the logic in \"bisect--helper: make --bisect-state optional\" to\n   delay showing the usage upon an unknown command, which should make the\n   code a lot less confusing.\n * Split out the change that moved the BISECT_STATE case to the end of the\n   switch block.\n * Added a patch that replaces the return error() calls in\n   cmd_bisect_helper() with die() calls, to avoid returning -1 as an exit\n   code.\n * Dropped the use of parse_options() for the single purpose of handling -h;\n   This is now done explicitly.\n * Simplified the diff of \"bisect: move even the option parsing to\n   bisect--helper\" by modifying argc and argv instead of modifying all the\n   function calls using those variables.\n * In the \"Turn git bisect into a full built-in\" patch, changed the name of\n   the variable holding the usage to use the builtin_ prefix used in other\n   built-ins, too.\n * Removed the trailing dot from the commit message of \"Turn git bisect into\n   a full built-in\".\n\nJohannes Schindelin (15):\n  bisect run: fix the error message\n  bisect: avoid double-quoting when printing the failed command\n  bisect--helper: retire the --no-log option\n  bisect--helper: really retire --bisect-next-check\n  bisect--helper: really retire `--bisect-autostart`\n  bisect--helper: using `--bisect-state` without an argument is a bug\n  bisect--helper: align the sub-command order with git-bisect.sh\n  bisect--helper: make `--bisect-state` optional\n  bisect--helper: move the `BISECT_STATE` case to the end\n  bisect--helper: return only correct exit codes in `cmd_*()`\n  bisect: move even the command-line parsing to `bisect--helper`\n  bisect: teach the `bisect--helper` command to show the correct usage\n    strings\n  Turn `git bisect` into a full built-in\n  bisect: remove Cogito-related code\n  bisect: no longer try to clean up left-over `.git/head-name` files\n\n Makefile                               |   3 +-\n bisect.c                               |   3 -\n builtin.h                              |   2 +-\n builtin/{bisect--helper.c => bisect.c} | 202 +++++++++++--------------\n git-bisect.sh                          |  84 ----------\n git.c                                  |   2 +-\n t/t6030-bisect-porcelain.sh            |  11 +-\n 7 files changed, 100 insertions(+), 207 deletions(-)\n rename builtin/{bisect--helper.c => bisect.c} (89%)\n delete mode 100755 git-bisect.sh\n\n\nbase-commit: f9b95943b68b6b8ca5a6072f50a08411c6449b55\nPublished-As: https://github.com/gitgitgadget/git/releases/tag/pr-1132%2Fdscho%2Fbisect-in-c-v3\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1132/dscho/bisect-in-c-v3\nPull-Request: https://github.com/gitgitgadget/git/pull/1132\n\nRange-diff vs v2:\n\n  1:  81ca0d68cde !  1:  cf6034625dd bisect run: fix the error message\n     @@ Commit message\n          Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n      \n       ## builtin/bisect--helper.c ##\n     -@@ builtin/bisect--helper.c: 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 strvec args = STRVEC_INIT;\n     - \tstruct strvec run_args = STRVEC_INIT;\n     - \tconst char *new_state;\n     - \tint temporary_stdout_fd, saved_stdout;\n     -@@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n     - \tstrvec_push(&run_args, command.buf);\n     - \n     - \twhile (1) {\n     --\t\tstrvec_clear(&args);\n     --\n     - \t\tprintf(_(\"running %s\\n\"), command.buf);\n     - \t\tres = run_command_v_opt(run_args.v, RUN_USING_SHELL);\n     - \n      @@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n       \t\t\tprintf(_(\"bisect found first bad commit\"));\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\"), args.v[0], res);\n      +\t\t\terror(_(\"bisect run failed: 'git bisect\"\n     -+\t\t\t\" %s' exited with error code %d\"), new_state, res);\n     + \t\t\t\" %s' exited with error code %d\"), new_state, res);\n       \t\t} else {\n       \t\t\tcontinue;\n     - \t\t}\n     - \n     - \t\tstrbuf_release(&command);\n     --\t\tstrvec_clear(&args);\n     - \t\tstrvec_clear(&run_args);\n     - \t\treturn res;\n     - \t}\n      \n       ## t/t6030-bisect-porcelain.sh ##\n     -@@ t/t6030-bisect-porcelain.sh: test_expect_success 'bisect visualize with a filename with dash and space' '\n     - \tgit bisect visualize -p -- \"-hello 2\"\n     +@@ t/t6030-bisect-porcelain.sh: test_expect_success 'bisect state output with bad commit' '\n     + \tgrep -F \"waiting for good commit(s), bad commit known\" output\n       '\n       \n     -+test_expect_success 'testing' '\n     ++test_expect_success 'verify correct error message' '\n      +\tgit bisect reset &&\n      +\tgit bisect start $HASH4 $HASH1 &&\n      +\twrite_script test_script.sh <<-\\EOF &&\n  2:  4320101f2e0 !  2:  955ccd4d8c8 bisect: avoid double-quoting when printing the failed command\n     @@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, cons\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, command.buf);\n     - \t\t\tstrbuf_release(&command);\n     - \t\t\treturn res;\n     + \t\t\tbreak;\n       \t\t}\n     + \n  3:  88d7173c86b !  3:  abcbc25966c bisect--helper: retire the --no-log option\n     @@ builtin/bisect--helper.c: int cmd_bisect__helper(int argc, const char **argv, co\n      @@ builtin/bisect--helper.c: 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\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  4:  b914fe64dda =  4:  af60ef1b5a4 bisect--helper: really retire --bisect-next-check\n  5:  0d3db63bda6 =  5:  07a92c58f8e bisect--helper: really retire `--bisect-autostart`\n  6:  a345cf3e0e4 =  6:  04ba0950b85 bisect--helper: using `--bisect-state` without an argument is a bug\n  7:  0487701220b !  7:  6847af9d485 bisect--helper: align the sub-command order with git-bisect.sh\n     @@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, cons\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-run\", &cmdmode,\n     - \t\t\t N_(\"use <cmd>... to automatically bisect.\"), BISECT_RUN),\n     + \t\t\t N_(\"use <cmd>... to automatically bisect\"), BISECT_RUN),\n       \t\tOPT_END()\n      @@ builtin/bisect--helper.c: int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n       \t\tusage_with_options(git_bisect_helper_usage, options);\n  8:  d8b2767c148 !  8:  b7bc53b9cb6 bisect--helper: make `--bisect-state` optional\n     @@ builtin/bisect--helper.c\n      @@ builtin/bisect--helper.c: static const char * const git_bisect_helper_usage[] = {\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     - \tN_(\"git bisect--helper --bisect-next\"),\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-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     - \tN_(\"git bisect--helper --bisect-visualize\"),\n     + \t\"git bisect--helper --bisect-visualize\",\n      @@ builtin/bisect--helper.c: int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n       \t\t\t     git_bisect_helper_usage,\n       \t\t\t     PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN);\n  9:  e8904db81c5 =  9:  1919237a819 bisect--helper: move the `BISECT_STATE` case to the end\n 10:  208f8fa4851 = 10:  1236a731903 bisect--helper: return only correct exit codes in `cmd_*()`\n 11:  dc04b06206b ! 11:  4ae78d37d04 bisect: move even the option parsing to `bisect--helper`\n     @@ Metadata\n      Author: Johannes Schindelin <Johannes.Schindelin@gmx.de>\n      \n       ## Commit message ##\n     -    bisect: move even the option parsing to `bisect--helper`\n     +    bisect: move even the command-line parsing to `bisect--helper`\n      \n          On our journey to a fully built-in `git bisect`, this is the\n     -    second-to-last step.\n     +    one of the last steps.\n      \n     -    Side note: The `if (!strcmp(...)) ... else if (!strcmp(...)) ... else if\n     -    (!strcmp(...)) ...` chain seen in this patch was not actually the first\n     -    idea how to convert the command modes to sub-commands. Since the\n     -    `bisect--helper` command already used the `parse-opions` API with neatly\n     -    set-up command modes, naturally the idea was to use `PARSE_OPT_NODASH`\n     -    to support proper sub-commands instead. However, the `parse-options` API\n     -    is not set up for that, and even after making that option work with long\n     -    options, it turned out that `STOP_AT_NON_OPTION` and `KEEP_UNKNOWN`\n     -    would have to be used but these options were not designed to work\n     -    together. So it would appear as if a lot of work would have to be done\n     -    just to be able to use `parse_options()` just to parse the sub-command,\n     -    instead of a simple `if...else if` chain, the latter being a\n     -    dramatically simpler implementation.\n     +    Side note: The `parse-options` API is not at all set up to parse\n     +    subcommands such as `git bisect start`, `git bisect reset`, etc.\n     +    Instead of fighting an up-hill battle trying to \"fix\" that, we simply\n     +    roll the same type of manual subcommand parsing as we already do e.g.\n     +    in `builtin/bundle.c`.\n      \n          Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n      \n       ## builtin/bisect--helper.c ##\n     -@@ builtin/bisect--helper.c: 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     --\tN_(\"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     --\tN_(\"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     --\tN_(\"git bisect--helper --bisect-visualize\"),\n     --\tN_(\"git bisect--helper --bisect-run <cmd>...\"),\n     -+static const char * const git_bisect_usage[] = {\n     -+\tN_(\"git bisect help\\n\"\n     -+\t   \"\\tprint this long help message.\"),\n     -+\tN_(\"git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>]\\n\"\n     -+\t   \"\\t\\t [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<pathspec>...]\\n\"\n     -+\t   \"\\treset bisect state and start bisection.\"),\n     -+\tN_(\"git bisect (bad|new) [<rev>]\\n\"\n     -+\t   \"\\tmark <rev> a known-bad revision/\\n\"\n     -+\t   \"\\t\\ta revision after change in a given property.\"),\n     -+\tN_(\"git bisect (good|old) [<rev>...]\\n\"\n     -+\t   \"\\tmark <rev>... known-good revisions/\\n\"\n     -+\t   \"\\t\\trevisions before change in a given property.\"),\n     -+\tN_(\"git bisect terms [--term-good | --term-bad]\\n\"\n     -+\t   \"\\tshow the terms used for old and new commits (default: bad, good)\"),\n     -+\tN_(\"git bisect skip [(<rev>|<range>)...]\\n\"\n     -+\t   \"\\tmark <rev>... untestable revisions.\"),\n     -+\tN_(\"git bisect next\\n\"\n     -+\t   \"\\tfind next bisection to test and check it out.\"),\n     -+\tN_(\"git bisect reset [<commit>]\\n\"\n     -+\t   \"\\tfinish bisection search and go back to commit.\"),\n     -+\tN_(\"git bisect (visualize|view)\\n\"\n     -+\t   \"\\tshow bisect status in gitk.\"),\n     -+\tN_(\"git bisect replay <logfile>\\n\"\n     -+\t   \"\\treplay bisection log.\"),\n     -+\tN_(\"git bisect log\\n\"\n     -+\t   \"\\tshow bisect log.\"),\n     -+\tN_(\"git bisect run <cmd>...\\n\"\n     -+\t   \"\\tuse <cmd>... to automatically bisect.\"),\n     - \tNULL\n     - };\n     - \n      @@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n       \n       int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n     @@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, cons\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-run\", &cmdmode,\n     --\t\t\t N_(\"use <cmd>... to automatically bisect.\"), BISECT_RUN),\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     @@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, cons\n      -\t\t\t     git_bisect_helper_usage,\n      -\t\t\t     PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN);\n      +\tif (!strcmp(\"-h\", command) || !strcmp(\"help\", command))\n     -+\t\tusage_with_options(git_bisect_usage, options);\n     ++\t\tusage_with_options(git_bisect_helper_usage, options);\n       \n      -\tswitch (cmdmode ? cmdmode : BISECT_STATE) {\n      -\tcase BISECT_START:\n     @@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, cons\n      -\t\tif (!cmdmode &&\n      -\t\t    (!argc || check_and_set_terms(&terms, argv[0]))) {\n      -\t\t\tchar *msg = xstrfmt(_(\"unknown command: '%s'\"), argv[0]);\n     --\t\t\tusage_msg_opt(msg, git_bisect_helper_usage, options);\n      +\t\tif (check_and_set_terms(&terms, command)) {\n      +\t\t\tchar *msg = xstrfmt(_(\"unknown command: '%s'\"), command);\n     -+\t\t\tusage_msg_opt(msg, git_bisect_usage, options);\n     + \t\t\tusage_msg_opt(msg, git_bisect_helper_usage, options);\n       \t\t}\n      +\t\t/* shift the `command` back in */\n      +\t\targc++;\n  -:  ----------- > 12:  ac472aefb6a bisect: teach the `bisect--helper` command to show the correct usage strings\n 12:  7db4b03b668 ! 13:  85f5c256ae3 Turn `git bisect` into a full built-in\n     @@ builtin.h: int cmd_am(int argc, const char **argv, const char *prefix);\n       int cmd_bugreport(int argc, const char **argv, const char *prefix);\n      \n       ## builtin/bisect--helper.c => builtin/bisect.c ##\n     -@@ builtin/bisect.c: 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_usage[] = {\n     -+static const char * const builtin_bisect_usage[] = {\n     - \tN_(\"git bisect help\\n\"\n     - \t   \"\\tprint this long help message.\"),\n     - \tN_(\"git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>]\\n\"\n      @@ builtin/bisect.c: static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n     - \t}\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     - \tstruct option options[] = {\n     -@@ builtin/bisect.c: int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n     - \tconst char *command = argc > 1 ? argv[1] : \"help\";\n     - \n     - \tif (!strcmp(\"-h\", command) || !strcmp(\"help\", command))\n     --\t\tusage_with_options(git_bisect_usage, options);\n     -+\t\tusage_with_options(builtin_bisect_usage, options);\n     - \n     - \targc -= 2;\n     - \targv += 2;\n     -@@ builtin/bisect.c: int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n     - \t\tget_terms(&terms);\n     - \t\tif (check_and_set_terms(&terms, command)) {\n     - \t\t\tchar *msg = xstrfmt(_(\"unknown command: '%s'\"), command);\n     --\t\t\tusage_msg_opt(msg, git_bisect_usage, options);\n     -+\t\t\tusage_msg_opt(msg, builtin_bisect_usage, options);\n     - \t\t}\n     - \t\t/* shift the `command` back in */\n     - \t\targc++;\n     + \tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\n      \n       ## git-bisect.sh (deleted) ##\n      @@\n 13:  0611d16f772 = 14:  289917e96af bisect: remove Cogito-related code\n 14:  e2fa11a819e = 15:  8f8d2ba0fe4 bisect: no longer try to clean up left-over `.git/head-name` files\n\n-- \ngitgitgadget\n"},{"id":"455674","messageId":"cf6034625ddc7132c222152a62eb330d8f18fcbf.1653144546.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v3.git.1653144546.gitgitgadget@gmail.com","subject":"[PATCH v3 01/15] bisect run: fix the error message","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-05-21T14:48:52Z","receivedAt":"2022-05-21T14:49:22Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nIn d1bbbe45df8 (bisect--helper: reimplement `bisect_run` shell function\nin C, 2021-09-13), we ported the `bisect run` subcommand to C, including\nthe part that prints out an error message when the implicit `git bisect\nbad` or `git bisect good` failed.\n\nHowever, the error message was supposed to print out whether the state\nwas \"good\" or \"bad\", but used a bogus (because non-populated) `args`\nvariable for it.\n\nHelped-by: Elijah Newren <newren@gmail.com>\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/bisect--helper.c    |  2 +-\n t/t6030-bisect-porcelain.sh | 10 ++++++++++\n 2 files changed, 11 insertions(+), 1 deletion(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex d4eaaa345ee..207479ee9ff 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1261,7 +1261,7 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n \t\t\tprintf(_(\"bisect found first bad commit\"));\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: 'git bisect\"\n \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 83931d482fb..0cacbf1469a 100755\n--- a/t/t6030-bisect-porcelain.sh\n+++ b/t/t6030-bisect-porcelain.sh\n@@ -1053,4 +1053,14 @@ test_expect_success 'bisect state output with bad commit' '\n \tgrep -F \"waiting for good commit(s), bad commit known\" output\n '\n \n+test_expect_success 'verify correct error message' '\n+\tgit bisect reset &&\n+\tgit bisect start $HASH4 $HASH1 &&\n+\twrite_script test_script.sh <<-\\EOF &&\n+\trm .git/BISECT*\n+\tEOF\n+\ttest_must_fail git bisect run ./test_script.sh 2>error &&\n+\tgrep \"git bisect good.*exited with error code\" error\n+'\n+\n test_done\n-- \ngitgitgadget\n\n"},{"id":"455675","messageId":"955ccd4d8c895ec635b5937bec657c13e5c5e830.1653144546.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v3.git.1653144546.gitgitgadget@gmail.com","subject":"[PATCH v3 02/15] bisect: avoid double-quoting when printing the failed command","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-05-21T14:48:53Z","receivedAt":"2022-05-21T14:49:25Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nWe already quote the command via `sq_quote_argv()`, no need to enclose\nthe result in an extraneous pair of single-quotes.\n\nPointed out by Elijah Newren.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/bisect--helper.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 207479ee9ff..0f49f52ac10 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1221,7 +1221,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, command.buf);\n \t\t\tbreak;\n \t\t}\n \n-- \ngitgitgadget\n\n"},{"id":"455676","messageId":"abcbc25966ce101ca1d5085c8ed22abddb65ce5b.1653144546.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v3.git.1653144546.gitgitgadget@gmail.com","subject":"[PATCH v3 03/15] bisect--helper: retire the --no-log option","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-05-21T14:48:54Z","receivedAt":"2022-05-21T14:49:26Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nTurns out we actually never used it, anyway...\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/bisect--helper.c | 4 +---\n 1 file changed, 1 insertion(+), 3 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 0f49f52ac10..39556d60eab 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1290,7 +1290,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@@ -1314,8 +1314,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-- \ngitgitgadget\n\n"},{"id":"455677","messageId":"07a92c58f8e956d0906067131c5abdd990122698.1653144546.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v3.git.1653144546.gitgitgadget@gmail.com","subject":"[PATCH v3 05/15] bisect--helper: really retire `--bisect-autostart`","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-05-21T14:48:56Z","receivedAt":"2022-05-21T14:49:30Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\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>\n---\n builtin/bisect--helper.c | 1 -\n 1 file changed, 1 deletion(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 658390952b2..8f4dab48379 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1280,7 +1280,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\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-- \ngitgitgadget\n\n"},{"id":"455678","messageId":"04ba0950b858e0c5b2549d8be52c89f12d579e92.1653144546.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v3.git.1653144546.gitgitgadget@gmail.com","subject":"[PATCH v3 06/15] bisect--helper: using `--bisect-state` without an argument is a bug","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-05-21T14:48:57Z","receivedAt":"2022-05-21T14:49:32Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nThe `bisect--helper` command is not expected to be used directly by the\nuser. Therefore, it is a bug if it receives no argument to the\n`--bisect-state` command mode, not a user error. Which means that we\nneed to call `BUG()` instead of `die()`.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/bisect--helper.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 8f4dab48379..343aedbc545 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -899,7 +899,7 @@ static enum bisect_error bisect_state(struct bisect_terms *terms, const char **a\n \tstruct oid_array revs = OID_ARRAY_INIT;\n \n \tif (!argc)\n-\t\treturn error(_(\"Please call `--bisect-state` with at least one argument\"));\n+\t\tBUG(\"bisect_state() called without argument\");\n \n \tif (bisect_autostart(terms))\n \t\treturn BISECT_FAILED;\n-- \ngitgitgadget\n\n"},{"id":"455679","messageId":"af60ef1b5a40b97eed6b07248af6600ae4b77841.1653144546.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v3.git.1653144546.gitgitgadget@gmail.com","subject":"[PATCH v3 04/15] bisect--helper: really retire --bisect-next-check","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-05-21T14:48:55Z","receivedAt":"2022-05-21T14:49:33Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?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\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/bisect--helper.c | 3 ---\n 1 file changed, 3 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 39556d60eab..658390952b2 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1278,7 +1278,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@@ -1294,8 +1293,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-- \ngitgitgadget\n\n"},{"id":"455680","messageId":"6847af9d4859b3631cfec056f4c6e8d3120349ec.1653144546.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v3.git.1653144546.gitgitgadget@gmail.com","subject":"[PATCH v3 07/15] bisect--helper: align the sub-command order with git-bisect.sh","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-05-21T14:48:58Z","receivedAt":"2022-05-21T14:49:36Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nWe are about to retire the shell implementation of `git bisect`, or\nmaybe better put: the remainder of the shell implementation (a shell of\na script, if you want).\n\nIn preparation for that, align the order of the sub-commands with the\nway the outgoing implementation presents them to the user.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/bisect--helper.c | 76 ++++++++++++++++++++--------------------\n 1 file changed, 38 insertions(+), 38 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 343aedbc545..37a16c6ac1a 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1277,37 +1277,37 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\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_START = 1,\n \t\tBISECT_STATE,\n-\t\tBISECT_LOG,\n-\t\tBISECT_REPLAY,\n+\t\tBISECT_TERMS,\n \t\tBISECT_SKIP,\n+\t\tBISECT_NEXT,\n+\t\tBISECT_RESET,\n \t\tBISECT_VISUALIZE,\n+\t\tBISECT_REPLAY,\n+\t\tBISECT_LOG,\n \t\tBISECT_RUN,\n \t} cmdmode = 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-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-terms\", &cmdmode,\n+\t\t\t N_(\"print out the bisect terms\"), BISECT_TERMS),\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-next\", &cmdmode,\n+\t\t\t N_(\"find the next bisection commit\"), BISECT_NEXT),\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-visualize\", &cmdmode,\n \t\t\t N_(\"visualize the bisection\"), BISECT_VISUALIZE),\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-log\", &cmdmode,\n+\t\t\t N_(\"list the bisection steps so far\"), BISECT_LOG),\n \t\tOPT_CMDMODE(0, \"bisect-run\", &cmdmode,\n \t\t\t N_(\"use <cmd>... to automatically bisect\"), BISECT_RUN),\n \t\tOPT_END()\n@@ -1322,19 +1322,24 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\tusage_with_options(git_bisect_helper_usage, options);\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+\tcase BISECT_START:\n+\t\tset_terms(&terms, \"bad\", \"good\");\n+\t\tres = bisect_start(&terms, argv, argc);\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_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+\tcase BISECT_SKIP:\n \t\tset_terms(&terms, \"bad\", \"good\");\n-\t\tres = bisect_start(&terms, argv, argc);\n+\t\tget_terms(&terms);\n+\t\tres = bisect_skip(&terms, argv, argc);\n \t\tbreak;\n \tcase BISECT_NEXT:\n \t\tif (argc)\n@@ -1342,15 +1347,14 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\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+\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_LOG:\n-\t\tif (argc)\n-\t\t\treturn error(_(\"--bisect-log requires 0 arguments\"));\n-\t\tres = bisect_log();\n+\tcase BISECT_VISUALIZE:\n+\t\tget_terms(&terms);\n+\t\tres = bisect_visualize(&terms, argv, argc);\n \t\tbreak;\n \tcase BISECT_REPLAY:\n \t\tif (argc != 1)\n@@ -1358,14 +1362,10 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\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+\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_RUN:\n \t\tif (!argc)\n-- \ngitgitgadget\n\n"},{"id":"455681","messageId":"b7bc53b9cb6f0785341562d6e1a1190fc66dc5d3.1653144546.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v3.git.1653144546.gitgitgadget@gmail.com","subject":"[PATCH v3 08/15] bisect--helper: make `--bisect-state` optional","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-05-21T14:48:59Z","receivedAt":"2022-05-21T14:49:39Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?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 `--bisect-state`\noption to be passed explicitly.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/bisect--helper.c | 14 ++++++++------\n git-bisect.sh            |  2 +-\n 2 files changed, 9 insertions(+), 7 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 37a16c6ac1a..94293318619 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -26,8 +26,8 @@ static const char * const git_bisect_helper_usage[] = {\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-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@@ -1318,10 +1318,7 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\t\t     git_bisect_helper_usage,\n \t\t\t     PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN);\n \n-\tif (!cmdmode)\n-\t\tusage_with_options(git_bisect_helper_usage, options);\n-\n-\tswitch (cmdmode) {\n+\tswitch (cmdmode ? cmdmode : BISECT_STATE) {\n \tcase BISECT_START:\n \t\tset_terms(&terms, \"bad\", \"good\");\n \t\tres = bisect_start(&terms, argv, argc);\n@@ -1329,6 +1326,11 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \tcase BISECT_STATE:\n \t\tset_terms(&terms, \"bad\", \"good\");\n \t\tget_terms(&terms);\n+\t\tif (!cmdmode &&\n+\t\t    (!argc || check_and_set_terms(&terms, argv[0]))) {\n+\t\t\tchar *msg = xstrfmt(_(\"unknown command: '%s'\"), argv[0]);\n+\t\t\tusage_msg_opt(msg, git_bisect_helper_usage, options);\n+\t\t}\n \t\tres = bisect_state(&terms, argv, argc);\n \t\tbreak;\n \tcase BISECT_TERMS:\ndiff --git a/git-bisect.sh b/git-bisect.sh\nindex 405cf76f2a3..fbf56649d7d 100755\n--- a/git-bisect.sh\n+++ b/git-bisect.sh\n@@ -60,7 +60,7 @@ case \"$#\" in\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+\t\tgit bisect--helper \"$cmd\" \"$@\" ;;\n \tskip)\n \t\tgit bisect--helper --bisect-skip \"$@\" || exit;;\n \tnext)\n-- \ngitgitgadget\n\n"},{"id":"455682","messageId":"1236a7319033a67befe34ed892db0eb5200490fd.1653144546.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v3.git.1653144546.gitgitgadget@gmail.com","subject":"[PATCH v3 10/15] bisect--helper: return only correct exit codes in `cmd_*()`","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-05-21T14:49:01Z","receivedAt":"2022-05-21T14:49:42Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nExit codes cannot be negative, but `error()` returns -1.\n\nLet's just go with the common pattern and call `die()` in\n`cmd_bisect__helper()` when incorrect arguments were detected.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/bisect--helper.c | 12 ++++++------\n 1 file changed, 6 insertions(+), 6 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 21a3b913ed3..824f84ae76f 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1325,7 +1325,7 @@ int cmd_bisect__helper(int argc, const char **argv, const char *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\t\tdie(_(\"--bisect-terms requires 0 or 1 argument\"));\n \t\tres = bisect_terms(&terms, argc == 1 ? argv[0] : NULL);\n \t\tbreak;\n \tcase BISECT_SKIP:\n@@ -1335,13 +1335,13 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\tbreak;\n \tcase BISECT_NEXT:\n \t\tif (argc)\n-\t\t\treturn error(_(\"--bisect-next requires 0 arguments\"));\n+\t\t\tdie(_(\"--bisect-next requires 0 arguments\"));\n \t\tget_terms(&terms);\n \t\tres = bisect_next(&terms, prefix);\n \t\tbreak;\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\t\tdie(_(\"--bisect-reset requires either no argument or a commit\"));\n \t\tres = bisect_reset(argc ? argv[0] : NULL);\n \t\tbreak;\n \tcase BISECT_VISUALIZE:\n@@ -1350,18 +1350,18 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\tbreak;\n \tcase BISECT_REPLAY:\n \t\tif (argc != 1)\n-\t\t\treturn error(_(\"no logfile given\"));\n+\t\t\tdie(_(\"no logfile given\"));\n \t\tset_terms(&terms, \"bad\", \"good\");\n \t\tres = bisect_replay(&terms, argv[0]);\n \t\tbreak;\n \tcase BISECT_LOG:\n \t\tif (argc)\n-\t\t\treturn error(_(\"--bisect-log requires 0 arguments\"));\n+\t\t\tdie(_(\"--bisect-log requires 0 arguments\"));\n \t\tres = bisect_log();\n \t\tbreak;\n \tcase BISECT_RUN:\n \t\tif (!argc)\n-\t\t\treturn error(_(\"bisect run failed: no command provided.\"));\n+\t\t\tdie(_(\"bisect run failed: no command provided.\"));\n \t\tget_terms(&terms);\n \t\tres = bisect_run(&terms, argv, argc);\n \t\tbreak;\n-- \ngitgitgadget\n\n"},{"id":"455683","messageId":"1919237a8197d8ef08abe03bc3cda113f3422761.1653144546.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v3.git.1653144546.gitgitgadget@gmail.com","subject":"[PATCH v3 09/15] bisect--helper: move the `BISECT_STATE` case to the end","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-05-21T14:49:00Z","receivedAt":"2022-05-21T14:49:45Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nIn preparation for replacing the command-mode parsing in\n`bisect--helper` with an if/else if/else chain, let's move the one\ncommand that will be implicit (i.e. what will become the final `else`\nwithout any `if`) to the end.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/bisect--helper.c | 20 ++++++++++----------\n 1 file changed, 10 insertions(+), 10 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 94293318619..21a3b913ed3 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1323,16 +1323,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\tset_terms(&terms, \"bad\", \"good\");\n \t\tres = bisect_start(&terms, argv, argc);\n \t\tbreak;\n-\tcase BISECT_STATE:\n-\t\tset_terms(&terms, \"bad\", \"good\");\n-\t\tget_terms(&terms);\n-\t\tif (!cmdmode &&\n-\t\t    (!argc || check_and_set_terms(&terms, argv[0]))) {\n-\t\t\tchar *msg = xstrfmt(_(\"unknown command: '%s'\"), argv[0]);\n-\t\t\tusage_msg_opt(msg, git_bisect_helper_usage, options);\n-\t\t}\n-\t\tres = bisect_state(&terms, argv, argc);\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@@ -1375,6 +1365,16 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\tget_terms(&terms);\n \t\tres = bisect_run(&terms, argv, argc);\n \t\tbreak;\n+\tcase BISECT_STATE:\n+\t\tset_terms(&terms, \"bad\", \"good\");\n+\t\tget_terms(&terms);\n+\t\tif (!cmdmode &&\n+\t\t    (!argc || check_and_set_terms(&terms, argv[0]))) {\n+\t\t\tchar *msg = xstrfmt(_(\"unknown command: '%s'\"), argv[0]);\n+\t\t\tusage_msg_opt(msg, git_bisect_helper_usage, options);\n+\t\t}\n+\t\tres = bisect_state(&terms, argv, argc);\n+\t\tbreak;\n \tdefault:\n \t\tBUG(\"unknown subcommand %d\", cmdmode);\n \t}\n-- \ngitgitgadget\n\n"},{"id":"455684","messageId":"ac472aefb6af0670cc9fa498e57145aec9ae6c47.1653144546.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v3.git.1653144546.gitgitgadget@gmail.com","subject":"[PATCH v3 12/15] bisect: teach the `bisect--helper` command to show the correct usage strings","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-05-21T14:49:03Z","receivedAt":"2022-05-21T14:49:49Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nIn preparation for `bisect--helper` graduating to become the actual\n`bisect` command, we hereby teach it to print the very same usage\nstrings as the scripted `git-bisect.sh` does.\n\nWith this patch, the `bisect--helper` command is able to do everything\nthat the `git-bisect.sh` script could, leaving as last step only to\nretire that script at long last, which we will do in the next commit.\n\nNote: Since we cannot use the `parse-options` API to handle the\nsubcommands of `git bisect` anyway, we no longer use it even just to\nshow the usage string anymore, either.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/bisect--helper.c | 69 ++++++++++++++++++++++++++--------------\n 1 file changed, 46 insertions(+), 23 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 89ff688a4a2..a68f2c5a919 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1,6 +1,5 @@\n #include \"builtin.h\"\n #include \"cache.h\"\n-#include \"parse-options.h\"\n #include \"bisect.h\"\n #include \"refs.h\"\n #include \"dir.h\"\n@@ -20,20 +19,46 @@ 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-\tNULL\n-};\n+static const char *bisect_usage =\n+\tN_(\"git bisect [help|start|bad|good|new|old|terms|skip|next|reset|\"\n+\t   \"visualize|view|replay|log|run]\");\n+\n+static const char *bisect_long_usage =\n+\tN_(\"git bisect [help|start|bad|good|new|old|terms|skip|next|reset|\"\n+\t   \"visualize|view|replay|log|run]\\n\"\n+\t   \"\\n\"\n+\t   \"git bisect help\\n\"\n+\t   \"\\tprint this long help message.\\n\"\n+\t   \"git bisect start [--term-{new,bad}=<term> \"\n+\t\t\"--term-{old,good}=<term>]\\n\"\n+\t   \"\\t\t [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] \"\n+\t\t\"[<pathspec>...]\\n\"\n+\t   \"\\treset bisect state and start bisection.\\n\"\n+\t   \"git bisect (bad|new) [<rev>]\\n\"\n+\t   \"\\tmark <rev> a known-bad revision/\\n\"\n+\t   \"\\t\ta revision after change in a given property.\\n\"\n+\t   \"git bisect (good|old) [<rev>...]\\n\"\n+\t   \"\\tmark <rev>... known-good revisions/\\n\"\n+\t   \"\\t\trevisions before change in a given property.\\n\"\n+\t   \"git bisect terms [--term-good | --term-bad]\\n\"\n+\t   \"\\tshow the terms used for old and new commits \"\n+\t\t\"(default: bad, good)\\n\"\n+\t   \"git bisect skip [(<rev>|<range>)...]\\n\"\n+\t   \"\\tmark <rev>... untestable revisions.\\n\"\n+\t   \"git bisect next\\n\"\n+\t   \"\\tfind next bisection to test and check it out.\\n\"\n+\t   \"git bisect reset [<commit>]\\n\"\n+\t   \"\\tfinish bisection search and go back to commit.\\n\"\n+\t   \"git bisect (visualize|view)\\n\"\n+\t   \"\\tshow bisect status in gitk.\\n\"\n+\t   \"git bisect replay <logfile>\\n\"\n+\t   \"\\treplay bisection log.\\n\"\n+\t   \"git bisect log\\n\"\n+\t   \"\\tshow bisect log.\\n\"\n+\t   \"git bisect run <cmd>...\\n\"\n+\t   \"\\tuse <cmd>... to automatically bisect.\\n\"\n+\t   \"\\n\"\n+\t   \"Please use \\\"git help bisect\\\" to get the full man page.\");\n \n struct add_bisect_ref_data {\n \tstruct rev_info *revs;\n@@ -1277,14 +1302,11 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n {\n \tint res = 0;\n-\tstruct option options[] = {\n-\t\tOPT_END()\n-\t};\n \tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\n \tconst char *command = argc > 1 ? argv[1] : \"help\";\n \n \tif (!strcmp(\"-h\", command) || !strcmp(\"help\", command))\n-\t\tusage_with_options(git_bisect_helper_usage, options);\n+\t\tusage(bisect_long_usage);\n \n \targc -= 2;\n \targv += 2;\n@@ -1327,12 +1349,13 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\tget_terms(&terms);\n \t\tres = bisect_run(&terms, argv, argc);\n \t} else {\n+\t\tif (!file_is_not_empty(git_path_bisect_start()) &&\n+\t\t    !one_of(command, \"bad\", \"good\", \"new\", \"old\", NULL))\n+\t\t\tusage(bisect_usage);\n \t\tset_terms(&terms, \"bad\", \"good\");\n \t\tget_terms(&terms);\n-\t\tif (check_and_set_terms(&terms, command)) {\n-\t\t\tchar *msg = xstrfmt(_(\"unknown command: '%s'\"), command);\n-\t\t\tusage_msg_opt(msg, git_bisect_helper_usage, options);\n-\t\t}\n+\t\tif (check_and_set_terms(&terms, command))\n+\t\t\tusage(bisect_usage);\n \t\t/* shift the `command` back in */\n \t\targc++;\n \t\targv--;\n-- \ngitgitgadget\n\n"},{"id":"455685","messageId":"4ae78d37d04789b2cadb059088e59af80a850c15.1653144546.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v3.git.1653144546.gitgitgadget@gmail.com","subject":"[PATCH v3 11/15] bisect: move even the command-line parsing to `bisect--helper`","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-05-21T14:49:02Z","receivedAt":"2022-05-21T14:49:52Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nOn our journey to a fully built-in `git bisect`, this is the\none of the last steps.\n\nSide note: The `parse-options` API is not at all set up to parse\nsubcommands such as `git bisect start`, `git bisect reset`, etc.\nInstead of fighting an up-hill battle trying to \"fix\" that, we simply\nroll the same type of manual subcommand parsing as we already do e.g.\nin `builtin/bundle.c`.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/bisect--helper.c | 91 ++++++++++++----------------------------\n git-bisect.sh            | 49 +---------------------\n 2 files changed, 27 insertions(+), 113 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 824f84ae76f..89ff688a4a2 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1276,108 +1276,69 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n \n int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n {\n-\tenum {\n-\t\tBISECT_START = 1,\n-\t\tBISECT_STATE,\n-\t\tBISECT_TERMS,\n-\t\tBISECT_SKIP,\n-\t\tBISECT_NEXT,\n-\t\tBISECT_RESET,\n-\t\tBISECT_VISUALIZE,\n-\t\tBISECT_REPLAY,\n-\t\tBISECT_LOG,\n-\t\tBISECT_RUN,\n-\t} cmdmode = 0;\n \tint res = 0;\n \tstruct option options[] = {\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-state\", &cmdmode,\n-\t\t\t N_(\"mark the state of ref (or refs)\"), BISECT_STATE),\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-skip\", &cmdmode,\n-\t\t\t N_(\"skip some commits for checkout\"), BISECT_SKIP),\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-reset\", &cmdmode,\n-\t\t\t N_(\"reset the bisection state\"), BISECT_RESET),\n-\t\tOPT_CMDMODE(0, \"bisect-visualize\", &cmdmode,\n-\t\t\t N_(\"visualize the bisection\"), BISECT_VISUALIZE),\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-log\", &cmdmode,\n-\t\t\t N_(\"list the bisection steps so far\"), BISECT_LOG),\n-\t\tOPT_CMDMODE(0, \"bisect-run\", &cmdmode,\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+\tconst char *command = argc > 1 ? argv[1] : \"help\";\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);\n+\tif (!strcmp(\"-h\", command) || !strcmp(\"help\", command))\n+\t\tusage_with_options(git_bisect_helper_usage, options);\n \n-\tswitch (cmdmode ? cmdmode : BISECT_STATE) {\n-\tcase BISECT_START:\n+\targc -= 2;\n+\targv += 2;\n+\n+\tif (!strcmp(\"start\", command)) {\n \t\tset_terms(&terms, \"bad\", \"good\");\n \t\tres = bisect_start(&terms, argv, argc);\n-\t\tbreak;\n-\tcase BISECT_TERMS:\n+\t} else if (!strcmp(\"terms\", command)) {\n \t\tif (argc > 1)\n-\t\t\tdie(_(\"--bisect-terms requires 0 or 1 argument\"));\n+\t\t\tdie(_(\"'terms' requires 0 or 1 argument\"));\n \t\tres = bisect_terms(&terms, argc == 1 ? argv[0] : NULL);\n-\t\tbreak;\n-\tcase BISECT_SKIP:\n+\t} else if (!strcmp(\"skip\", command)) {\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_NEXT:\n+\t} else if (!strcmp(\"next\", command)) {\n \t\tif (argc)\n-\t\t\tdie(_(\"--bisect-next requires 0 arguments\"));\n+\t\t\tdie(_(\"'next' requires 0 arguments\"));\n \t\tget_terms(&terms);\n \t\tres = bisect_next(&terms, prefix);\n-\t\tbreak;\n-\tcase BISECT_RESET:\n+\t} else if (!strcmp(\"reset\", command)) {\n \t\tif (argc > 1)\n-\t\t\tdie(_(\"--bisect-reset requires either no argument or a commit\"));\n+\t\t\tdie(_(\"'reset' requires either no argument or a commit\"));\n \t\tres = bisect_reset(argc ? argv[0] : NULL);\n-\t\tbreak;\n-\tcase BISECT_VISUALIZE:\n+\t} else if (one_of(command, \"visualize\", \"view\", NULL)) {\n \t\tget_terms(&terms);\n \t\tres = bisect_visualize(&terms, argv, argc);\n-\t\tbreak;\n-\tcase BISECT_REPLAY:\n+\t} else if (!strcmp(\"replay\", command)) {\n \t\tif (argc != 1)\n \t\t\tdie(_(\"no logfile given\"));\n \t\tset_terms(&terms, \"bad\", \"good\");\n \t\tres = bisect_replay(&terms, argv[0]);\n-\t\tbreak;\n-\tcase BISECT_LOG:\n+\t} else if (!strcmp(\"log\", command)) {\n \t\tif (argc)\n-\t\t\tdie(_(\"--bisect-log requires 0 arguments\"));\n+\t\t\tdie(_(\"'log' requires 0 arguments\"));\n \t\tres = bisect_log();\n-\t\tbreak;\n-\tcase BISECT_RUN:\n+\t} else if (!strcmp(\"run\", command)) {\n \t\tif (!argc)\n \t\t\tdie(_(\"bisect run failed: no command provided.\"));\n \t\tget_terms(&terms);\n \t\tres = bisect_run(&terms, argv, argc);\n-\t\tbreak;\n-\tcase BISECT_STATE:\n+\t} else {\n \t\tset_terms(&terms, \"bad\", \"good\");\n \t\tget_terms(&terms);\n-\t\tif (!cmdmode &&\n-\t\t    (!argc || check_and_set_terms(&terms, argv[0]))) {\n-\t\t\tchar *msg = xstrfmt(_(\"unknown command: '%s'\"), argv[0]);\n+\t\tif (check_and_set_terms(&terms, command)) {\n+\t\t\tchar *msg = xstrfmt(_(\"unknown command: '%s'\"), command);\n \t\t\tusage_msg_opt(msg, git_bisect_helper_usage, options);\n \t\t}\n+\t\t/* shift the `command` back in */\n+\t\targc++;\n+\t\targv--;\n \t\tres = bisect_state(&terms, argv, argc);\n-\t\tbreak;\n-\tdefault:\n-\t\tBUG(\"unknown subcommand %d\", cmdmode);\n \t}\n+\n \tfree_terms(&terms);\n \n \t/*\ndiff --git a/git-bisect.sh b/git-bisect.sh\nindex fbf56649d7d..028d39cd9ce 100755\n--- a/git-bisect.sh\n+++ b/git-bisect.sh\n@@ -34,51 +34,4 @@ 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 --bisect-start \"$@\" ;;\n-\tbad|good|new|old|\"$TERM_BAD\"|\"$TERM_GOOD\")\n-\t\tgit bisect--helper \"$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-\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*)\n-\t\tusage ;;\n-\tesac\n-esac\n+exec git bisect--helper \"$@\"\n-- \ngitgitgadget\n\n"},{"id":"455686","messageId":"289917e96af373bceb0e11d1e33042e9d9225ce5.1653144546.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v3.git.1653144546.gitgitgadget@gmail.com","subject":"[PATCH v3 14/15] bisect: remove Cogito-related code","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-05-21T14:49:05Z","receivedAt":"2022-05-21T14:49:54Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nOnce upon a time, there was this idea that Git would not actually be a\nsingle coherent program, but rather a set of low-level programs that\nusers cobble together via shell scripts, or develop high-level user\ninterfaces for Git, or both.\n\nCogito was such a high-level user interface, incidentally implemented\nvia shell scripts that cobble together Git calls.\n\nIt did turn out relatively quickly that Git would much rather provide a\nuseful high-level user interface itself.\n\nAs of April 19th, 2007, Cogito was therefore discontinued (see\nhttps://lore.kernel.org/git/20070419124648.GL4489@pasky.or.cz/).\n\nNevertheless, for almost 15 years after that announcement, Git carried\nspecial code in `git bisect` to accommodate Cogito.\n\nSince it is beyond doubt that there are no more Cogito users, let's\nremove the last remnant of Cogito-accommodating code.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/bisect.c | 8 --------\n 1 file changed, 8 deletions(-)\n\ndiff --git a/builtin/bisect.c b/builtin/bisect.c\nindex d33de133c8c..8f32ccb47b7 100644\n--- a/builtin/bisect.c\n+++ b/builtin/bisect.c\n@@ -14,7 +14,6 @@ static GIT_PATH_FUNC(git_path_bisect_expected_rev, \"BISECT_EXPECTED_REV\")\n static GIT_PATH_FUNC(git_path_bisect_ancestors_ok, \"BISECT_ANCESTORS_OK\")\n static GIT_PATH_FUNC(git_path_bisect_start, \"BISECT_START\")\n static GIT_PATH_FUNC(git_path_bisect_log, \"BISECT_LOG\")\n-static GIT_PATH_FUNC(git_path_head_name, \"head-name\")\n 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@@ -808,13 +807,6 @@ static enum bisect_error bisect_start(struct bisect_terms *terms, const char **a\n \t\t\tstrbuf_addstr(&start_head, oid_to_hex(&head_oid));\n \t\t} else if (!get_oid(head, &head_oid) &&\n \t\t\t   skip_prefix(head, \"refs/heads/\", &head)) {\n-\t\t\t/*\n-\t\t\t * This error message should only be triggered by\n-\t\t\t * cogito usage, and cogito users should understand\n-\t\t\t * it relates to cg-seek.\n-\t\t\t */\n-\t\t\tif (!is_empty_or_missing_file(git_path_head_name()))\n-\t\t\t\treturn error(_(\"won't bisect on cg-seek'ed tree\"));\n \t\t\tstrbuf_addstr(&start_head, head);\n \t\t} else {\n \t\t\treturn error(_(\"bad HEAD - strange symbolic ref\"));\n-- \ngitgitgadget\n\n"},{"id":"455687","messageId":"85f5c256ae3e1014d42b3f76e16224a375f64360.1653144546.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v3.git.1653144546.gitgitgadget@gmail.com","subject":"[PATCH v3 13/15] Turn `git bisect` into a full built-in","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-05-21T14:49:04Z","receivedAt":"2022-05-21T14:49:56Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?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>\n---\n Makefile                               |  3 +--\n builtin.h                              |  2 +-\n builtin/{bisect--helper.c => bisect.c} |  2 +-\n git-bisect.sh                          | 37 --------------------------\n git.c                                  |  2 +-\n 5 files changed, 4 insertions(+), 42 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 61aadf3ce88..824b8a43576 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -611,7 +611,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@@ -1107,7 +1106,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 40e9ecc8485..b9470f8ab4f 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 a68f2c5a919..d33de133c8c 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect.c\n@@ -1299,7 +1299,7 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\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 \tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\ndiff --git a/git-bisect.sh b/git-bisect.sh\ndeleted file mode 100755\nindex 028d39cd9ce..00000000000\n--- a/git-bisect.sh\n+++ /dev/null\n@@ -1,37 +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-exec git bisect--helper \"$@\"\ndiff --git a/git.c b/git.c\nindex 5ff4f3e25b7..40ed082e621 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 | NO_PARSEOPT },\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-- \ngitgitgadget\n\n"},{"id":"455688","messageId":"8f8d2ba0fe41583716419645ed74c3ffb0f85d77.1653144546.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v3.git.1653144546.gitgitgadget@gmail.com","subject":"[PATCH v3 15/15] bisect: no longer try to clean up left-over `.git/head-name` files","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-05-21T14:49:06Z","receivedAt":"2022-05-21T14:49:59Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nAs per the code comment, the `.git/head-name` files were cleaned up for\nbackwards-compatibility: an old version of `git bisect` could have left\nthem behind.\n\nNow, just how old would such a version be? As of 0f497e75f05 (Eliminate\nconfusing \"won't bisect on seeked tree\" failure, 2008-02-23), `git\nbisect` does not write that file anymore. Which corresponds to Git\nv1.5.4.4.\n\nEven if the likelihood is non-nil that there might still be users out\nthere who use such an old version to start a bisection, but then decide\nto continue bisecting with a current Git version, it is highly\nimprobable.\n\nSo let's remove that code, at long last.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n bisect.c                    | 3 ---\n t/t6030-bisect-porcelain.sh | 1 -\n 2 files changed, 4 deletions(-)\n\ndiff --git a/bisect.c b/bisect.c\nindex 9e6a2b7f201..8f46c3813ce 100644\n--- a/bisect.c\n+++ b/bisect.c\n@@ -474,7 +474,6 @@ static GIT_PATH_FUNC(git_path_bisect_start, \"BISECT_START\")\n static GIT_PATH_FUNC(git_path_bisect_log, \"BISECT_LOG\")\n static GIT_PATH_FUNC(git_path_bisect_terms, \"BISECT_TERMS\")\n static GIT_PATH_FUNC(git_path_bisect_first_parent, \"BISECT_FIRST_PARENT\")\n-static GIT_PATH_FUNC(git_path_head_name, \"head-name\")\n \n static void read_bisect_paths(struct strvec *array)\n {\n@@ -1173,8 +1172,6 @@ int bisect_clean_state(void)\n \tunlink_or_warn(git_path_bisect_run());\n \tunlink_or_warn(git_path_bisect_terms());\n \tunlink_or_warn(git_path_bisect_first_parent());\n-\t/* Cleanup head-name if it got left by an old version of git-bisect */\n-\tunlink_or_warn(git_path_head_name());\n \t/*\n \t * Cleanup BISECT_START last to support the --no-checkout option\n \t * introduced in the commit 4796e823a.\ndiff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh\nindex 0cacbf1469a..d4846ca4de1 100755\n--- a/t/t6030-bisect-porcelain.sh\n+++ b/t/t6030-bisect-porcelain.sh\n@@ -990,7 +990,6 @@ test_expect_success 'git bisect reset cleans bisection state properly' '\n \ttest_path_is_missing \".git/BISECT_LOG\" &&\n \ttest_path_is_missing \".git/BISECT_RUN\" &&\n \ttest_path_is_missing \".git/BISECT_TERMS\" &&\n-\ttest_path_is_missing \".git/head-name\" &&\n \ttest_path_is_missing \".git/BISECT_HEAD\" &&\n \ttest_path_is_missing \".git/BISECT_START\"\n '\n-- \ngitgitgadget\n"},{"id":"455699","messageId":"220521.864k1i25jq.gmgdl@evledraar.gmail.com","threadId":"57326","inReplyTo":"1236a7319033a67befe34ed892db0eb5200490fd.1653144546.git.gitgitgadget@gmail.com","subject":"Re: [PATCH v3 10/15] bisect--helper: return only correct exit codes in `cmd_*()`","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-05-21T16:45:04Z","receivedAt":"2022-05-21T16:51:04Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Sat, May 21 2022, Johannes Schindelin via GitGitGadget wrote:\n\n> From: Johannes Schindelin <johannes.schindelin@gmx.de>\n>\n> Exit codes cannot be negative, but `error()` returns -1.\n>\n> Let's just go with the common pattern and call `die()` in\n> `cmd_bisect__helper()` when incorrect arguments were detected.\n\nThis is good in that before we'd return e.g. code 255 here:\n\n    $ ./git bisect--helper  --bisect-terms foo bar; echo $?\n    error: --bisect-terms requires 0 or 1 argument\n    255\n\nBut now say:\n    \n    $ ./git bisect--helper  --bisect-terms foo bar; echo $?\n    fatal: --bisect-terms requires 0 or 1 argument\n    128\n\nBut after this patch we emit e.g. this:\n\n    $ ./git bisect--helper  --bisect-terms ; echo $?\n    error: no terms defined\n    1\n\nWe should instead treat all these usage errors the same. A better fix\nwould be to either use usage_msg_opt[f]() consistently instead of die().\n\nOr just this, which would narrowly fix the inconsistency and the exit\ncode:\n\n    diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\n    index 21a3b913ed3..e44d894e2ec 100644\n    --- a/builtin/bisect--helper.c\n    +++ b/builtin/bisect--helper.c\n    @@ -1325,7 +1325,7 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n                    break;\n            case BISECT_TERMS:\n                    if (argc > 1)\n    -                       return error(_(\"--bisect-terms requires 0 or 1 argument\"));\n    +                       return -error(_(\"--bisect-terms requires 0 or 1 argument\"));\n                    res = bisect_terms(&terms, argc == 1 ? argv[0] : NULL);\n                    break;\n            case BISECT_SKIP:\n\nBut returning 129 instead of 1 or 128 is better here, as that's the exit\ncode we specifically use for bad usage messages.\n\nI'll read on, but changing \"error\" to \"fatal\" and the exit code from 255\nand 1 to 128 and 1 instead of either always 129 or always 1 in these\ncases seems odd, especially as the last part of the function has this\ncode:\n\n        return -res;\n\nI.e. it's expecting \"res\" to be e.g. -1 or 0, and to convert that to 1\nor 0.\n"},{"id":"455700","messageId":"220521.86zgjazuy4.gmgdl@evledraar.gmail.com","threadId":"57326","inReplyTo":"4ae78d37d04789b2cadb059088e59af80a850c15.1653144546.git.gitgitgadget@gmail.com","subject":"Re: [PATCH v3 11/15] bisect: move even the command-line parsing to `bisect--helper`","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-05-21T16:52:22Z","receivedAt":"2022-05-21T16:55:53Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Sat, May 21 2022, Johannes Schindelin via GitGitGadget wrote:\n\n> From: Johannes Schindelin <johannes.schindelin@gmx.de>\n>\n> On our journey to a fully built-in `git bisect`, this is the\n> one of the last steps.\n>\n> Side note: The `parse-options` API is not at all set up to parse\n> subcommands such as `git bisect start`, `git bisect reset`, etc.\n\n\nIt seems that since v2 you fixed the bug of \"-h\" starting a bisection\nsession, as noted in :\nhttps://lore.kernel.org/git/220225.86ilt27uln.gmgdl@evledraar.gmail.com/\n\n\nBut that problem seems to still be with us in other forms, e.g. just one\nthing I tried (the very first thing) was the command I was testing in\n10/15, and:\n    \n    ./git bisect--helper  --bisect-terms 1 2 ; echo $?\n    You need to start by \"git bisect start\"\n    \n    Do you want me to do it for you [Y/n]? ^C\n\nso that's buggy too.\n\n> Instead of fighting an up-hill battle trying to \"fix\" that, we simply\n> roll the same type of manual subcommand parsing as we already do e.g.\n> in `builtin/bundle.c`.\n\nThis is particularly confusing because that would be a good approach (as\nI pointed out in a previous round), but the end-state here isn't at all\nlike builtin/bundle.c. I.e. in that case we have a top-level strcmp()\nchain dispatching to parse_options() for the sub-command, which would\nsolve your problems here...\n"},{"id":"455727","messageId":"a6e77222-6a95-992a-892c-7361d5568784@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v3.git.1653144546.gitgitgadget@gmail.com","subject":"Re: [PATCH v3 00/15] Finish converting git bisect into a built-in","fromName":"Bagas Sanjaya","fromEmail":"bagasdotme@gmail.com","sentAt":"2022-05-22T03:07:21Z","receivedAt":"2022-05-22T03:14:06Z","isPatch":true,"sender":{"key":"bagasdotme@gmail.com","avatar":"https://avatars.githubusercontent.com/u/40219486?v=4"},"body":"On 5/21/22 21:48, Johannes Schindelin via GitGitGadget wrote:\n>  * When a bogus command is provided, we now error out instead of trying to\n>    start a git bisect run.\n\nAh! git bisect now behave like other shell commands where bogus\ncommand is given, instead of \"accidentally\" start the bisection.\n\nBTW, do the current version of git bisect exhibit that accidental\nbehavior?\n\n-- \nAn old man doll... just what I always wanted! - Clara\n"},{"id":"455762","messageId":"220523.865ylwzgji.gmgdl@evledraar.gmail.com","threadId":"57326","inReplyTo":"a6e77222-6a95-992a-892c-7361d5568784@gmail.com","subject":"Re: [PATCH v3 00/15] Finish converting git bisect into a built-in","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-05-23T10:22:52Z","receivedAt":"2022-05-23T10:31:42Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Sun, May 22 2022, Bagas Sanjaya wrote:\n\n> On 5/21/22 21:48, Johannes Schindelin via GitGitGadget wrote:\n>>  * When a bogus command is provided, we now error out instead of trying to\n>>    start a git bisect run.\n>\n> Ah! git bisect now behave like other shell commands where bogus\n> command is given, instead of \"accidentally\" start the bisection.\n>\n> BTW, do the current version of git bisect exhibit that accidental\n> behavior?\n\nNo, this is a fix for a bug introduced in an earlier version of this\ntopic, but the more general issue remains. See\nhttps://lore.kernel.org/git/220521.86zgjazuy4.gmgdl@evledraar.gmail.com/\n\nRather than a surgical fix for a specific issue I noted, with the\ninitial report being:\nhttps://lore.kernel.org/git/220223.86v8x56g7g.gmgdl@evledraar.gmail.com/\n\nThis topic could really use some confidence building by adding new \"git\nbisect\" tests. I.e. let's have tests for what exit codes etc. we emit on\nvarious valid and invalid \"git bisect\" usage.\n\nWe clearly don't have that since the proposed v2 would have introduced a\nregression, and this v3 would also have done that in other cases (while\nfixing the one specific case of \"-h\").\n"},{"id":"457931","messageId":"pull.1132.v4.git.1656354677.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v3.git.1653144546.gitgitgadget@gmail.com","subject":"[PATCH v4 00/16] Finish converting git bisect into a built-in","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-06-27T18:31:01Z","receivedAt":"2022-06-27T18:36:47Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"After three GSoC/Outreachy students spent an incredible effort on this, it\nis finally time to put a neat little bow on it.\n\nChanges since v3:\n\n * Rebased because of merge conflicts with ab/plug-leak-in-revisions.\n * Fixed the bug that git bisect --bisect-terms 1 2 wanted to auto-start a\n   bisection if running with a git executable built at the in-between state\n   at patch \"bisect: move even the command-line parsing to bisect--helper\".\n   Since this bug was \"fixed\" in v3 by the very next patch, \"bisect: teach\n   the bisect--helper command to show the correct usage strings\", v4 avoids\n   introducing this bug simply by letting these two patches trade places.\n   The range-diff admittedly looks quite awful because both patches overlap\n   quite a bit in the lines they modify. The end result is the same, though,\n   the diff between v3's and v4's builtin/bisect.c would be empty if I\n   hadn't been forced to rebase.\n * Added a test case to ensure that this bug won't be introduced again. This\n   test case is the only actual difference relative to v3 of this patch\n   series.\n\nChanges since v2:\n\n * We're now careful to provide identical usage strings upon git bisect -h\n   and git bisect bogus.\n * When a bogus command is provided, we now error out instead of trying to\n   start a git bisect run.\n * Rebased onto main to avoid plenty of merge conflicts with\n   rs/bisect-executable-not-found, ac/usage-string-fixups and with\n   cd/bisect-messages-from-pre-flight-states.\n\nChanges since v1:\n\n * Added a regression test to \"bisect run: fix the error message\".\n * Added a patch to address an error message that double-single-quoted the\n   command.\n * Reworked the logic in \"bisect--helper: make --bisect-state optional\" to\n   delay showing the usage upon an unknown command, which should make the\n   code a lot less confusing.\n * Split out the change that moved the BISECT_STATE case to the end of the\n   switch block.\n * Added a patch that replaces the return error() calls in\n   cmd_bisect_helper() with die() calls, to avoid returning -1 as an exit\n   code.\n * Dropped the use of parse_options() for the single purpose of handling -h;\n   This is now done explicitly.\n * Simplified the diff of \"bisect: move even the option parsing to\n   bisect--helper\" by modifying argc and argv instead of modifying all the\n   function calls using those variables.\n * In the \"Turn git bisect into a full built-in\" patch, changed the name of\n   the variable holding the usage to use the builtin_ prefix used in other\n   built-ins, too.\n * Removed the trailing dot from the commit message of \"Turn git bisect into\n   a full built-in\".\n\nJohannes Schindelin (16):\n  bisect: verify that a bogus option won't try to start a bisection\n  bisect run: fix the error message\n  bisect: avoid double-quoting when printing the failed command\n  bisect--helper: retire the --no-log option\n  bisect--helper: really retire --bisect-next-check\n  bisect--helper: really retire `--bisect-autostart`\n  bisect--helper: using `--bisect-state` without an argument is a bug\n  bisect--helper: align the sub-command order with git-bisect.sh\n  bisect--helper: make `--bisect-state` optional\n  bisect--helper: move the `BISECT_STATE` case to the end\n  bisect--helper: return only correct exit codes in `cmd_*()`\n  bisect: teach the `bisect--helper` command to show the correct usage\n    strings\n  bisect: move even the command-line parsing to `bisect--helper`\n  Turn `git bisect` into a full built-in\n  bisect: remove Cogito-related code\n  bisect: no longer try to clean up left-over `.git/head-name` files\n\n Makefile                               |   3 +-\n bisect.c                               |   3 -\n builtin.h                              |   2 +-\n builtin/{bisect--helper.c => bisect.c} | 202 +++++++++++--------------\n git-bisect.sh                          |  84 ----------\n git.c                                  |   2 +-\n t/t6030-bisect-porcelain.sh            |  21 ++-\n 7 files changed, 110 insertions(+), 207 deletions(-)\n rename builtin/{bisect--helper.c => bisect.c} (89%)\n delete mode 100755 git-bisect.sh\n\n\nbase-commit: 8168d5e9c23ed44ae3d604f392320d66556453c9\nPublished-As: https://github.com/gitgitgadget/git/releases/tag/pr-1132%2Fdscho%2Fbisect-in-c-v4\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1132/dscho/bisect-in-c-v4\nPull-Request: https://github.com/gitgitgadget/git/pull/1132\n\nRange-diff vs v3:\n\n  -:  ----------- >  1:  30ddbd7affc bisect: verify that a bogus option won't try to start a bisection\n  1:  cf6034625dd =  2:  97dd2da8f89 bisect run: fix the error message\n  2:  955ccd4d8c8 =  3:  5571e0f76ff bisect: avoid double-quoting when printing the failed command\n  3:  abcbc25966c =  4:  5bfaf0334c3 bisect--helper: retire the --no-log option\n  4:  af60ef1b5a4 =  5:  e85f236304b bisect--helper: really retire --bisect-next-check\n  5:  07a92c58f8e =  6:  b94b7bb4fd0 bisect--helper: really retire `--bisect-autostart`\n  6:  04ba0950b85 =  7:  aad3c9a0850 bisect--helper: using `--bisect-state` without an argument is a bug\n  7:  6847af9d485 =  8:  375a46dca9f bisect--helper: align the sub-command order with git-bisect.sh\n  8:  b7bc53b9cb6 =  9:  c57f63f6a61 bisect--helper: make `--bisect-state` optional\n  9:  1919237a819 = 10:  87f53469a72 bisect--helper: move the `BISECT_STATE` case to the end\n 10:  1236a731903 = 11:  ce508583e45 bisect--helper: return only correct exit codes in `cmd_*()`\n 12:  ac472aefb6a ! 12:  5dbe233e4ec bisect: teach the `bisect--helper` command to show the correct usage strings\n     @@ Commit message\n          `bisect` command, we hereby teach it to print the very same usage\n          strings as the scripted `git-bisect.sh` does.\n      \n     -    With this patch, the `bisect--helper` command is able to do everything\n     -    that the `git-bisect.sh` script could, leaving as last step only to\n     -    retire that script at long last, which we will do in the next commit.\n     -\n     -    Note: Since we cannot use the `parse-options` API to handle the\n     -    subcommands of `git bisect` anyway, we no longer use it even just to\n     -    show the usage string anymore, either.\n     -\n          Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n      \n       ## builtin/bisect--helper.c ##\n     @@ builtin/bisect--helper.c: static GIT_PATH_FUNC(git_path_bisect_names, \"BISECT_NA\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     --\tNULL\n     --};\n      +static const char *bisect_usage =\n      +\tN_(\"git bisect [help|start|bad|good|new|old|terms|skip|next|reset|\"\n      +\t   \"visualize|view|replay|log|run]\");\n      +\n     -+static const char *bisect_long_usage =\n     ++static const char * const bisect_long_usage[] = {\n      +\tN_(\"git bisect [help|start|bad|good|new|old|terms|skip|next|reset|\"\n      +\t   \"visualize|view|replay|log|run]\\n\"\n      +\t   \"\\n\"\n     @@ builtin/bisect--helper.c: static GIT_PATH_FUNC(git_path_bisect_names, \"BISECT_NA\n      +\t   \"git bisect run <cmd>...\\n\"\n      +\t   \"\\tuse <cmd>... to automatically bisect.\\n\"\n      +\t   \"\\n\"\n     -+\t   \"Please use \\\"git help bisect\\\" to get the full man page.\");\n     ++\t   \"Please use \\\"git help bisect\\\" to get the full man page.\"),\n     + \tNULL\n     + };\n       \n     - struct add_bisect_ref_data {\n     - \tstruct rev_info *revs;\n     -@@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n     - int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n     - {\n     - \tint res = 0;\n     --\tstruct option options[] = {\n     --\t\tOPT_END()\n     --\t};\n     +@@ builtin/bisect--helper.c: int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n       \tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\n     - \tconst char *command = argc > 1 ? argv[1] : \"help\";\n       \n     - \tif (!strcmp(\"-h\", command) || !strcmp(\"help\", command))\n     --\t\tusage_with_options(git_bisect_helper_usage, options);\n     -+\t\tusage(bisect_long_usage);\n     + \targc = parse_options(argc, argv, prefix, options,\n     +-\t\t\t     git_bisect_helper_usage,\n     ++\t\t\t     bisect_long_usage,\n     + \t\t\t     PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN);\n       \n     - \targc -= 2;\n     - \targv += 2;\n     + \tswitch (cmdmode ? cmdmode : BISECT_STATE) {\n      @@ builtin/bisect--helper.c: int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n     - \t\tget_terms(&terms);\n       \t\tres = bisect_run(&terms, argv, argc);\n     - \t} else {\n     -+\t\tif (!file_is_not_empty(git_path_bisect_start()) &&\n     -+\t\t    !one_of(command, \"bad\", \"good\", \"new\", \"old\", NULL))\n     + \t\tbreak;\n     + \tcase BISECT_STATE:\n     ++\t\tif (argc &&\n     ++\t\t    !file_is_not_empty(git_path_bisect_start()) &&\n     ++\t\t    !one_of(argv[0], \"bad\", \"good\", \"new\", \"old\", NULL))\n      +\t\t\tusage(bisect_usage);\n       \t\tset_terms(&terms, \"bad\", \"good\");\n       \t\tget_terms(&terms);\n     --\t\tif (check_and_set_terms(&terms, command)) {\n     --\t\t\tchar *msg = xstrfmt(_(\"unknown command: '%s'\"), command);\n     + \t\tif (!cmdmode &&\n     +-\t\t    (!argc || check_and_set_terms(&terms, argv[0]))) {\n     +-\t\t\tchar *msg = xstrfmt(_(\"unknown command: '%s'\"), argv[0]);\n      -\t\t\tusage_msg_opt(msg, git_bisect_helper_usage, options);\n      -\t\t}\n     -+\t\tif (check_and_set_terms(&terms, command))\n     ++\t\t    (!argc || check_and_set_terms(&terms, argv[0])))\n      +\t\t\tusage(bisect_usage);\n     - \t\t/* shift the `command` back in */\n     - \t\targc++;\n     - \t\targv--;\n     + \t\tres = bisect_state(&terms, argv, argc);\n     + \t\tbreak;\n     + \tdefault:\n 11:  4ae78d37d04 ! 13:  d56f2a14060 bisect: move even the command-line parsing to `bisect--helper`\n     @@ Commit message\n          bisect: move even the command-line parsing to `bisect--helper`\n      \n          On our journey to a fully built-in `git bisect`, this is the\n     -    one of the last steps.\n     +    last step.\n      \n          Side note: The `parse-options` API is not at all set up to parse\n          subcommands such as `git bisect start`, `git bisect reset`, etc.\n     @@ Commit message\n          Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n      \n       ## builtin/bisect--helper.c ##\n     +@@ builtin/bisect--helper.c: static const char *bisect_usage =\n     + \tN_(\"git bisect [help|start|bad|good|new|old|terms|skip|next|reset|\"\n     + \t   \"visualize|view|replay|log|run]\");\n     + \n     +-static const char * const bisect_long_usage[] = {\n     ++static const char *bisect_long_usage =\n     + \tN_(\"git bisect [help|start|bad|good|new|old|terms|skip|next|reset|\"\n     + \t   \"visualize|view|replay|log|run]\\n\"\n     + \t   \"\\n\"\n     +@@ builtin/bisect--helper.c: static const char * const bisect_long_usage[] = {\n     + \t   \"git bisect run <cmd>...\\n\"\n     + \t   \"\\tuse <cmd>... to automatically bisect.\\n\"\n     + \t   \"\\n\"\n     +-\t   \"Please use \\\"git help bisect\\\" to get the full man page.\"),\n     +-\tNULL\n     +-};\n     ++\t   \"Please use \\\"git help bisect\\\" to get the full man page.\");\n     + \n     + struct add_bisect_ref_data {\n     + \tstruct rev_info *revs;\n      @@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n       \n       int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n     @@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, cons\n      -\t\tBISECT_RUN,\n      -\t} cmdmode = 0;\n       \tint res = 0;\n     - \tstruct option options[] = {\n     +-\tstruct option options[] = {\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-state\", &cmdmode,\n     @@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, cons\n      -\t\t\t N_(\"list the bisection steps so far\"), BISECT_LOG),\n      -\t\tOPT_CMDMODE(0, \"bisect-run\", &cmdmode,\n      -\t\t\t N_(\"use <cmd>... to automatically bisect\"), BISECT_RUN),\n     - \t\tOPT_END()\n     - \t};\n     +-\t\tOPT_END()\n     +-\t};\n       \tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\n      +\tconst char *command = argc > 1 ? argv[1] : \"help\";\n     ++\n     ++\tif (!strcmp(\"-h\", command) || !strcmp(\"help\", command))\n     ++\t\tusage(bisect_long_usage);\n       \n      -\targc = parse_options(argc, argv, prefix, options,\n     --\t\t\t     git_bisect_helper_usage,\n     +-\t\t\t     bisect_long_usage,\n      -\t\t\t     PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN);\n     -+\tif (!strcmp(\"-h\", command) || !strcmp(\"help\", command))\n     -+\t\tusage_with_options(git_bisect_helper_usage, options);\n     ++\targc -= 2;\n     ++\targv += 2;\n       \n      -\tswitch (cmdmode ? cmdmode : BISECT_STATE) {\n      -\tcase BISECT_START:\n     -+\targc -= 2;\n     -+\targv += 2;\n     -+\n      +\tif (!strcmp(\"start\", command)) {\n       \t\tset_terms(&terms, \"bad\", \"good\");\n       \t\tres = bisect_start(&terms, argv, argc);\n     @@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, cons\n       \t\tres = bisect_run(&terms, argv, argc);\n      -\t\tbreak;\n      -\tcase BISECT_STATE:\n     +-\t\tif (argc &&\n     +-\t\t    !file_is_not_empty(git_path_bisect_start()) &&\n     +-\t\t    !one_of(argv[0], \"bad\", \"good\", \"new\", \"old\", NULL))\n      +\t} else {\n     ++\t\tif (!file_is_not_empty(git_path_bisect_start()) &&\n     ++\t\t    !one_of(command, \"bad\", \"good\", \"new\", \"old\", NULL))\n     + \t\t\tusage(bisect_usage);\n       \t\tset_terms(&terms, \"bad\", \"good\");\n       \t\tget_terms(&terms);\n      -\t\tif (!cmdmode &&\n     --\t\t    (!argc || check_and_set_terms(&terms, argv[0]))) {\n     --\t\t\tchar *msg = xstrfmt(_(\"unknown command: '%s'\"), argv[0]);\n     -+\t\tif (check_and_set_terms(&terms, command)) {\n     -+\t\t\tchar *msg = xstrfmt(_(\"unknown command: '%s'\"), command);\n     - \t\t\tusage_msg_opt(msg, git_bisect_helper_usage, options);\n     - \t\t}\n     +-\t\t    (!argc || check_and_set_terms(&terms, argv[0])))\n     ++\t\tif (check_and_set_terms(&terms, command))\n     + \t\t\tusage(bisect_usage);\n      +\t\t/* shift the `command` back in */\n      +\t\targc++;\n      +\t\targv--;\n 13:  85f5c256ae3 = 14:  378d6d22737 Turn `git bisect` into a full built-in\n 14:  289917e96af = 15:  33566b86d77 bisect: remove Cogito-related code\n 15:  8f8d2ba0fe4 = 16:  334664f23a8 bisect: no longer try to clean up left-over `.git/head-name` files\n\n-- \ngitgitgadget\n"},{"id":"457932","messageId":"97dd2da8f89fb918a49d4f70d8dcdad9652e5143.1656354677.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v4.git.1656354677.gitgitgadget@gmail.com","subject":"[PATCH v4 02/16] bisect run: fix the error message","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-06-27T18:31:03Z","receivedAt":"2022-06-27T18:36:48Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nIn d1bbbe45df8 (bisect--helper: reimplement `bisect_run` shell function\nin C, 2021-09-13), we ported the `bisect run` subcommand to C, including\nthe part that prints out an error message when the implicit `git bisect\nbad` or `git bisect good` failed.\n\nHowever, the error message was supposed to print out whether the state\nwas \"good\" or \"bad\", but used a bogus (because non-populated) `args`\nvariable for it.\n\nHelped-by: Elijah Newren <newren@gmail.com>\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/bisect--helper.c    |  2 +-\n t/t6030-bisect-porcelain.sh | 10 ++++++++++\n 2 files changed, 11 insertions(+), 1 deletion(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 8a052c7111f..cc38a009bdd 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1263,7 +1263,7 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n \t\t\tprintf(_(\"bisect found first bad commit\"));\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: 'git bisect\"\n \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 6d6e72276ae..7a76f204083 100755\n--- a/t/t6030-bisect-porcelain.sh\n+++ b/t/t6030-bisect-porcelain.sh\n@@ -1063,4 +1063,14 @@ test_expect_success 'bisect state output with bad commit' '\n \tgrep -F \"waiting for good commit(s), bad commit known\" output\n '\n \n+test_expect_success 'verify correct error message' '\n+\tgit bisect reset &&\n+\tgit bisect start $HASH4 $HASH1 &&\n+\twrite_script test_script.sh <<-\\EOF &&\n+\trm .git/BISECT*\n+\tEOF\n+\ttest_must_fail git bisect run ./test_script.sh 2>error &&\n+\tgrep \"git bisect good.*exited with error code\" error\n+'\n+\n test_done\n-- \ngitgitgadget\n\n"},{"id":"457933","messageId":"30ddbd7affc83e9b20ecdd66d941f1acc2cbc787.1656354677.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v4.git.1656354677.gitgitgadget@gmail.com","subject":"[PATCH v4 01/16] bisect: verify that a bogus option won't try to start a bisection","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-06-27T18:31:02Z","receivedAt":"2022-06-27T18:36:49Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nWe do not want `git bisect --bogus-option` to start a bisection. To\nverify that, we look for the tell-tale error message `You need to start\nby \"git bisect start\"` and fail if it was found.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n t/t6030-bisect-porcelain.sh | 10 ++++++++++\n 1 file changed, 10 insertions(+)\n\ndiff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh\nindex 83931d482fb..6d6e72276ae 100755\n--- a/t/t6030-bisect-porcelain.sh\n+++ b/t/t6030-bisect-porcelain.sh\n@@ -900,6 +900,16 @@ test_expect_success 'bisect start with one term1 and term2' '\n \tgit bisect reset\n '\n \n+test_expect_success 'bogus command does not start bisect' '\n+\tgit bisect reset &&\n+\ttest_must_fail git bisect --bisect-terms 1 2 2>out &&\n+\t! grep \"You need to start\" out &&\n+\ttest_must_fail git bisect --bisect-terms 2>out &&\n+\t! grep \"You need to start\" out &&\n+\tgrep \"git bisect.*visualize\" out &&\n+\tgit bisect reset\n+'\n+\n test_expect_success 'bisect replay with term1 and term2' '\n \tgit bisect replay log_to_replay.txt >bisect_result &&\n \tgrep \"$HASH2 is the first term1 commit\" bisect_result &&\n-- \ngitgitgadget\n\n"},{"id":"457934","messageId":"5bfaf0334c32a5cf71c19c72c7ca65253d460607.1656354677.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v4.git.1656354677.gitgitgadget@gmail.com","subject":"[PATCH v4 04/16] bisect--helper: retire the --no-log option","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-06-27T18:31:05Z","receivedAt":"2022-06-27T18:36:52Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nTurns out we actually never used it, anyway...\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/bisect--helper.c | 4 +---\n 1 file changed, 1 insertion(+), 3 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 2345c9f773e..8cfe3926dc7 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1292,7 +1292,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@@ -1316,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-- \ngitgitgadget\n\n"},{"id":"457935","messageId":"e85f236304b0de455713c45bbcb2248d25cd0f11.1656354677.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v4.git.1656354677.gitgitgadget@gmail.com","subject":"[PATCH v4 05/16] bisect--helper: really retire --bisect-next-check","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-06-27T18:31:06Z","receivedAt":"2022-06-27T18:36:54Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?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\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/bisect--helper.c | 3 ---\n 1 file changed, 3 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 8cfe3926dc7..75d008d7fa8 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1280,7 +1280,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@@ -1296,8 +1295,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-- \ngitgitgadget\n\n"},{"id":"457936","messageId":"5571e0f76ffd531986bf6c03b99bb34d00815fc3.1656354677.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v4.git.1656354677.gitgitgadget@gmail.com","subject":"[PATCH v4 03/16] bisect: avoid double-quoting when printing the failed command","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-06-27T18:31:04Z","receivedAt":"2022-06-27T18:36:55Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nWe already quote the command via `sq_quote_argv()`, no need to enclose\nthe result in an extraneous pair of single-quotes.\n\nPointed out by Elijah Newren.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/bisect--helper.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex cc38a009bdd..2345c9f773e 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1223,7 +1223,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, command.buf);\n \t\t\tbreak;\n \t\t}\n \n-- \ngitgitgadget\n\n"},{"id":"457937","messageId":"aad3c9a0850d302d6dbdb6ee583db0b61e58981a.1656354677.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v4.git.1656354677.gitgitgadget@gmail.com","subject":"[PATCH v4 07/16] bisect--helper: using `--bisect-state` without an argument is a bug","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-06-27T18:31:08Z","receivedAt":"2022-06-27T18:36:56Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nThe `bisect--helper` command is not expected to be used directly by the\nuser. Therefore, it is a bug if it receives no argument to the\n`--bisect-state` command mode, not a user error. Which means that we\nneed to call `BUG()` instead of `die()`.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/bisect--helper.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 477aba811f0..45983a0a1fc 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -900,7 +900,7 @@ static enum bisect_error bisect_state(struct bisect_terms *terms, const char **a\n \tstruct oid_array revs = OID_ARRAY_INIT;\n \n \tif (!argc)\n-\t\treturn error(_(\"Please call `--bisect-state` with at least one argument\"));\n+\t\tBUG(\"bisect_state() called without argument\");\n \n \tif (bisect_autostart(terms))\n \t\treturn BISECT_FAILED;\n-- \ngitgitgadget\n\n"},{"id":"457938","messageId":"b94b7bb4fd0ea19871683cfe2b9fad86cd189454.1656354677.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v4.git.1656354677.gitgitgadget@gmail.com","subject":"[PATCH v4 06/16] bisect--helper: really retire `--bisect-autostart`","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-06-27T18:31:07Z","receivedAt":"2022-06-27T18:37:00Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\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>\n---\n builtin/bisect--helper.c | 1 -\n 1 file changed, 1 deletion(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 75d008d7fa8..477aba811f0 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1282,7 +1282,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\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-- \ngitgitgadget\n\n"},{"id":"457939","messageId":"375a46dca9f82c91c8dcb873a5ca95b5fc11f79e.1656354677.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v4.git.1656354677.gitgitgadget@gmail.com","subject":"[PATCH v4 08/16] bisect--helper: align the sub-command order with git-bisect.sh","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-06-27T18:31:09Z","receivedAt":"2022-06-27T18:37:01Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nWe are about to retire the shell implementation of `git bisect`, or\nmaybe better put: the remainder of the shell implementation (a shell of\na script, if you want).\n\nIn preparation for that, align the order of the sub-commands with the\nway the outgoing implementation presents them to the user.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/bisect--helper.c | 76 ++++++++++++++++++++--------------------\n 1 file changed, 38 insertions(+), 38 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 45983a0a1fc..2d6eafa2abd 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1279,37 +1279,37 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\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_START = 1,\n \t\tBISECT_STATE,\n-\t\tBISECT_LOG,\n-\t\tBISECT_REPLAY,\n+\t\tBISECT_TERMS,\n \t\tBISECT_SKIP,\n+\t\tBISECT_NEXT,\n+\t\tBISECT_RESET,\n \t\tBISECT_VISUALIZE,\n+\t\tBISECT_REPLAY,\n+\t\tBISECT_LOG,\n \t\tBISECT_RUN,\n \t} cmdmode = 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-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-terms\", &cmdmode,\n+\t\t\t N_(\"print out the bisect terms\"), BISECT_TERMS),\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-next\", &cmdmode,\n+\t\t\t N_(\"find the next bisection commit\"), BISECT_NEXT),\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-visualize\", &cmdmode,\n \t\t\t N_(\"visualize the bisection\"), BISECT_VISUALIZE),\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-log\", &cmdmode,\n+\t\t\t N_(\"list the bisection steps so far\"), BISECT_LOG),\n \t\tOPT_CMDMODE(0, \"bisect-run\", &cmdmode,\n \t\t\t N_(\"use <cmd>... to automatically bisect\"), BISECT_RUN),\n \t\tOPT_END()\n@@ -1324,19 +1324,24 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\tusage_with_options(git_bisect_helper_usage, options);\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+\tcase BISECT_START:\n+\t\tset_terms(&terms, \"bad\", \"good\");\n+\t\tres = bisect_start(&terms, argv, argc);\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_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+\tcase BISECT_SKIP:\n \t\tset_terms(&terms, \"bad\", \"good\");\n-\t\tres = bisect_start(&terms, argv, argc);\n+\t\tget_terms(&terms);\n+\t\tres = bisect_skip(&terms, argv, argc);\n \t\tbreak;\n \tcase BISECT_NEXT:\n \t\tif (argc)\n@@ -1344,15 +1349,14 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\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+\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_LOG:\n-\t\tif (argc)\n-\t\t\treturn error(_(\"--bisect-log requires 0 arguments\"));\n-\t\tres = bisect_log();\n+\tcase BISECT_VISUALIZE:\n+\t\tget_terms(&terms);\n+\t\tres = bisect_visualize(&terms, argv, argc);\n \t\tbreak;\n \tcase BISECT_REPLAY:\n \t\tif (argc != 1)\n@@ -1360,14 +1364,10 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\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+\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_RUN:\n \t\tif (!argc)\n-- \ngitgitgadget\n\n"},{"id":"457940","messageId":"c57f63f6a6168b6da1e0cd786e0ec25013909d77.1656354677.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v4.git.1656354677.gitgitgadget@gmail.com","subject":"[PATCH v4 09/16] bisect--helper: make `--bisect-state` optional","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-06-27T18:31:10Z","receivedAt":"2022-06-27T18:37:02Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?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 `--bisect-state`\noption to be passed explicitly.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/bisect--helper.c | 14 ++++++++------\n git-bisect.sh            |  2 +-\n 2 files changed, 9 insertions(+), 7 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 2d6eafa2abd..1b1ce0941ff 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -26,8 +26,8 @@ static const char * const git_bisect_helper_usage[] = {\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-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@@ -1320,10 +1320,7 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\t\t     git_bisect_helper_usage,\n \t\t\t     PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN);\n \n-\tif (!cmdmode)\n-\t\tusage_with_options(git_bisect_helper_usage, options);\n-\n-\tswitch (cmdmode) {\n+\tswitch (cmdmode ? cmdmode : BISECT_STATE) {\n \tcase BISECT_START:\n \t\tset_terms(&terms, \"bad\", \"good\");\n \t\tres = bisect_start(&terms, argv, argc);\n@@ -1331,6 +1328,11 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \tcase BISECT_STATE:\n \t\tset_terms(&terms, \"bad\", \"good\");\n \t\tget_terms(&terms);\n+\t\tif (!cmdmode &&\n+\t\t    (!argc || check_and_set_terms(&terms, argv[0]))) {\n+\t\t\tchar *msg = xstrfmt(_(\"unknown command: '%s'\"), argv[0]);\n+\t\t\tusage_msg_opt(msg, git_bisect_helper_usage, options);\n+\t\t}\n \t\tres = bisect_state(&terms, argv, argc);\n \t\tbreak;\n \tcase BISECT_TERMS:\ndiff --git a/git-bisect.sh b/git-bisect.sh\nindex 405cf76f2a3..fbf56649d7d 100755\n--- a/git-bisect.sh\n+++ b/git-bisect.sh\n@@ -60,7 +60,7 @@ case \"$#\" in\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+\t\tgit bisect--helper \"$cmd\" \"$@\" ;;\n \tskip)\n \t\tgit bisect--helper --bisect-skip \"$@\" || exit;;\n \tnext)\n-- \ngitgitgadget\n\n"},{"id":"457941","messageId":"87f53469a721cefe1dbfb9f1b7906f189ddf3632.1656354677.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v4.git.1656354677.gitgitgadget@gmail.com","subject":"[PATCH v4 10/16] bisect--helper: move the `BISECT_STATE` case to the end","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-06-27T18:31:11Z","receivedAt":"2022-06-27T18:37:04Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nIn preparation for replacing the command-mode parsing in\n`bisect--helper` with an if/else if/else chain, let's move the one\ncommand that will be implicit (i.e. what will become the final `else`\nwithout any `if`) to the end.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/bisect--helper.c | 20 ++++++++++----------\n 1 file changed, 10 insertions(+), 10 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 1b1ce0941ff..22099b9ebe2 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1325,16 +1325,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\tset_terms(&terms, \"bad\", \"good\");\n \t\tres = bisect_start(&terms, argv, argc);\n \t\tbreak;\n-\tcase BISECT_STATE:\n-\t\tset_terms(&terms, \"bad\", \"good\");\n-\t\tget_terms(&terms);\n-\t\tif (!cmdmode &&\n-\t\t    (!argc || check_and_set_terms(&terms, argv[0]))) {\n-\t\t\tchar *msg = xstrfmt(_(\"unknown command: '%s'\"), argv[0]);\n-\t\t\tusage_msg_opt(msg, git_bisect_helper_usage, options);\n-\t\t}\n-\t\tres = bisect_state(&terms, argv, argc);\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@@ -1377,6 +1367,16 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\tget_terms(&terms);\n \t\tres = bisect_run(&terms, argv, argc);\n \t\tbreak;\n+\tcase BISECT_STATE:\n+\t\tset_terms(&terms, \"bad\", \"good\");\n+\t\tget_terms(&terms);\n+\t\tif (!cmdmode &&\n+\t\t    (!argc || check_and_set_terms(&terms, argv[0]))) {\n+\t\t\tchar *msg = xstrfmt(_(\"unknown command: '%s'\"), argv[0]);\n+\t\t\tusage_msg_opt(msg, git_bisect_helper_usage, options);\n+\t\t}\n+\t\tres = bisect_state(&terms, argv, argc);\n+\t\tbreak;\n \tdefault:\n \t\tBUG(\"unknown subcommand %d\", cmdmode);\n \t}\n-- \ngitgitgadget\n\n"},{"id":"457942","messageId":"ce508583e455a1dbb7620a238edb11dae195f00d.1656354677.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v4.git.1656354677.gitgitgadget@gmail.com","subject":"[PATCH v4 11/16] bisect--helper: return only correct exit codes in `cmd_*()`","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-06-27T18:31:12Z","receivedAt":"2022-06-27T18:37:05Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nExit codes cannot be negative, but `error()` returns -1.\n\nLet's just go with the common pattern and call `die()` in\n`cmd_bisect__helper()` when incorrect arguments were detected.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/bisect--helper.c | 12 ++++++------\n 1 file changed, 6 insertions(+), 6 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 22099b9ebe2..86195058cd5 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1327,7 +1327,7 @@ int cmd_bisect__helper(int argc, const char **argv, const char *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\t\tdie(_(\"--bisect-terms requires 0 or 1 argument\"));\n \t\tres = bisect_terms(&terms, argc == 1 ? argv[0] : NULL);\n \t\tbreak;\n \tcase BISECT_SKIP:\n@@ -1337,13 +1337,13 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\tbreak;\n \tcase BISECT_NEXT:\n \t\tif (argc)\n-\t\t\treturn error(_(\"--bisect-next requires 0 arguments\"));\n+\t\t\tdie(_(\"--bisect-next requires 0 arguments\"));\n \t\tget_terms(&terms);\n \t\tres = bisect_next(&terms, prefix);\n \t\tbreak;\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\t\tdie(_(\"--bisect-reset requires either no argument or a commit\"));\n \t\tres = bisect_reset(argc ? argv[0] : NULL);\n \t\tbreak;\n \tcase BISECT_VISUALIZE:\n@@ -1352,18 +1352,18 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\tbreak;\n \tcase BISECT_REPLAY:\n \t\tif (argc != 1)\n-\t\t\treturn error(_(\"no logfile given\"));\n+\t\t\tdie(_(\"no logfile given\"));\n \t\tset_terms(&terms, \"bad\", \"good\");\n \t\tres = bisect_replay(&terms, argv[0]);\n \t\tbreak;\n \tcase BISECT_LOG:\n \t\tif (argc)\n-\t\t\treturn error(_(\"--bisect-log requires 0 arguments\"));\n+\t\t\tdie(_(\"--bisect-log requires 0 arguments\"));\n \t\tres = bisect_log();\n \t\tbreak;\n \tcase BISECT_RUN:\n \t\tif (!argc)\n-\t\t\treturn error(_(\"bisect run failed: no command provided.\"));\n+\t\t\tdie(_(\"bisect run failed: no command provided.\"));\n \t\tget_terms(&terms);\n \t\tres = bisect_run(&terms, argv, argc);\n \t\tbreak;\n-- \ngitgitgadget\n\n"},{"id":"457943","messageId":"5dbe233e4ec2f404bb236a8ee71d24e8cb6a4387.1656354677.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v4.git.1656354677.gitgitgadget@gmail.com","subject":"[PATCH v4 12/16] bisect: teach the `bisect--helper` command to show the correct usage strings","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-06-27T18:31:13Z","receivedAt":"2022-06-27T18:37:09Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nIn preparation for `bisect--helper` graduating to become the actual\n`bisect` command, we hereby teach it to print the very same usage\nstrings as the scripted `git-bisect.sh` does.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/bisect--helper.c | 65 +++++++++++++++++++++++++++++-----------\n 1 file changed, 47 insertions(+), 18 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 86195058cd5..1914aa7c69f 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1,6 +1,5 @@\n #include \"builtin.h\"\n #include \"cache.h\"\n-#include \"parse-options.h\"\n #include \"bisect.h\"\n #include \"refs.h\"\n #include \"dir.h\"\n@@ -20,18 +19,46 @@ 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+static const char *bisect_usage =\n+\tN_(\"git bisect [help|start|bad|good|new|old|terms|skip|next|reset|\"\n+\t   \"visualize|view|replay|log|run]\");\n+\n+static const char * const bisect_long_usage[] = {\n+\tN_(\"git bisect [help|start|bad|good|new|old|terms|skip|next|reset|\"\n+\t   \"visualize|view|replay|log|run]\\n\"\n+\t   \"\\n\"\n+\t   \"git bisect help\\n\"\n+\t   \"\\tprint this long help message.\\n\"\n+\t   \"git bisect start [--term-{new,bad}=<term> \"\n+\t\t\"--term-{old,good}=<term>]\\n\"\n+\t   \"\\t\t [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] \"\n+\t\t\"[<pathspec>...]\\n\"\n+\t   \"\\treset bisect state and start bisection.\\n\"\n+\t   \"git bisect (bad|new) [<rev>]\\n\"\n+\t   \"\\tmark <rev> a known-bad revision/\\n\"\n+\t   \"\\t\ta revision after change in a given property.\\n\"\n+\t   \"git bisect (good|old) [<rev>...]\\n\"\n+\t   \"\\tmark <rev>... known-good revisions/\\n\"\n+\t   \"\\t\trevisions before change in a given property.\\n\"\n+\t   \"git bisect terms [--term-good | --term-bad]\\n\"\n+\t   \"\\tshow the terms used for old and new commits \"\n+\t\t\"(default: bad, good)\\n\"\n+\t   \"git bisect skip [(<rev>|<range>)...]\\n\"\n+\t   \"\\tmark <rev>... untestable revisions.\\n\"\n+\t   \"git bisect next\\n\"\n+\t   \"\\tfind next bisection to test and check it out.\\n\"\n+\t   \"git bisect reset [<commit>]\\n\"\n+\t   \"\\tfinish bisection search and go back to commit.\\n\"\n+\t   \"git bisect (visualize|view)\\n\"\n+\t   \"\\tshow bisect status in gitk.\\n\"\n+\t   \"git bisect replay <logfile>\\n\"\n+\t   \"\\treplay bisection log.\\n\"\n+\t   \"git bisect log\\n\"\n+\t   \"\\tshow bisect log.\\n\"\n+\t   \"git bisect run <cmd>...\\n\"\n+\t   \"\\tuse <cmd>... to automatically bisect.\\n\"\n+\t   \"\\n\"\n+\t   \"Please use \\\"git help bisect\\\" to get the full man page.\"),\n \tNULL\n };\n \n@@ -1317,7 +1344,7 @@ 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,\n-\t\t\t     git_bisect_helper_usage,\n+\t\t\t     bisect_long_usage,\n \t\t\t     PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN);\n \n \tswitch (cmdmode ? cmdmode : BISECT_STATE) {\n@@ -1368,13 +1395,15 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\tres = bisect_run(&terms, argv, argc);\n \t\tbreak;\n \tcase BISECT_STATE:\n+\t\tif (argc &&\n+\t\t    !file_is_not_empty(git_path_bisect_start()) &&\n+\t\t    !one_of(argv[0], \"bad\", \"good\", \"new\", \"old\", NULL))\n+\t\t\tusage(bisect_usage);\n \t\tset_terms(&terms, \"bad\", \"good\");\n \t\tget_terms(&terms);\n \t\tif (!cmdmode &&\n-\t\t    (!argc || check_and_set_terms(&terms, argv[0]))) {\n-\t\t\tchar *msg = xstrfmt(_(\"unknown command: '%s'\"), argv[0]);\n-\t\t\tusage_msg_opt(msg, git_bisect_helper_usage, options);\n-\t\t}\n+\t\t    (!argc || check_and_set_terms(&terms, argv[0])))\n+\t\t\tusage(bisect_usage);\n \t\tres = bisect_state(&terms, argv, argc);\n \t\tbreak;\n \tdefault:\n-- \ngitgitgadget\n\n"},{"id":"457944","messageId":"378d6d227372405326112fee03c377f1aff386fc.1656354677.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v4.git.1656354677.gitgitgadget@gmail.com","subject":"[PATCH v4 14/16] Turn `git bisect` into a full built-in","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-06-27T18:31:15Z","receivedAt":"2022-06-27T18:37:11Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?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>\n---\n Makefile                               |  3 +--\n builtin.h                              |  2 +-\n builtin/{bisect--helper.c => bisect.c} |  2 +-\n git-bisect.sh                          | 37 --------------------------\n git.c                                  |  2 +-\n 5 files changed, 4 insertions(+), 42 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 04d0fd1fe60..3462bad4f15 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -619,7 +619,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@@ -1119,7 +1118,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 40e9ecc8485..b9470f8ab4f 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 7232d650905..380fef852f3 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect.c\n@@ -1301,7 +1301,7 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\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 \tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\ndiff --git a/git-bisect.sh b/git-bisect.sh\ndeleted file mode 100755\nindex 028d39cd9ce..00000000000\n--- a/git-bisect.sh\n+++ /dev/null\n@@ -1,37 +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-exec git bisect--helper \"$@\"\ndiff --git a/git.c b/git.c\nindex d7a7a82008b..1ad501058a8 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 | NO_PARSEOPT },\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-- \ngitgitgadget\n\n"},{"id":"457945","messageId":"334664f23a8fa5d3b0df4a00ba9c7c96772ab93b.1656354677.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v4.git.1656354677.gitgitgadget@gmail.com","subject":"[PATCH v4 16/16] bisect: no longer try to clean up left-over `.git/head-name` files","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-06-27T18:31:17Z","receivedAt":"2022-06-27T18:37:14Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nAs per the code comment, the `.git/head-name` files were cleaned up for\nbackwards-compatibility: an old version of `git bisect` could have left\nthem behind.\n\nNow, just how old would such a version be? As of 0f497e75f05 (Eliminate\nconfusing \"won't bisect on seeked tree\" failure, 2008-02-23), `git\nbisect` does not write that file anymore. Which corresponds to Git\nv1.5.4.4.\n\nEven if the likelihood is non-nil that there might still be users out\nthere who use such an old version to start a bisection, but then decide\nto continue bisecting with a current Git version, it is highly\nimprobable.\n\nSo let's remove that code, at long last.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n bisect.c                    | 3 ---\n t/t6030-bisect-porcelain.sh | 1 -\n 2 files changed, 4 deletions(-)\n\ndiff --git a/bisect.c b/bisect.c\nindex b63669cc9d7..00bd4ba581c 100644\n--- a/bisect.c\n+++ b/bisect.c\n@@ -474,7 +474,6 @@ static GIT_PATH_FUNC(git_path_bisect_start, \"BISECT_START\")\n static GIT_PATH_FUNC(git_path_bisect_log, \"BISECT_LOG\")\n static GIT_PATH_FUNC(git_path_bisect_terms, \"BISECT_TERMS\")\n static GIT_PATH_FUNC(git_path_bisect_first_parent, \"BISECT_FIRST_PARENT\")\n-static GIT_PATH_FUNC(git_path_head_name, \"head-name\")\n \n static void read_bisect_paths(struct strvec *array)\n {\n@@ -1181,8 +1180,6 @@ int bisect_clean_state(void)\n \tunlink_or_warn(git_path_bisect_run());\n \tunlink_or_warn(git_path_bisect_terms());\n \tunlink_or_warn(git_path_bisect_first_parent());\n-\t/* Cleanup head-name if it got left by an old version of git-bisect */\n-\tunlink_or_warn(git_path_head_name());\n \t/*\n \t * Cleanup BISECT_START last to support the --no-checkout option\n \t * introduced in the commit 4796e823a.\ndiff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh\nindex 7a76f204083..1d9cbf229e2 100755\n--- a/t/t6030-bisect-porcelain.sh\n+++ b/t/t6030-bisect-porcelain.sh\n@@ -1000,7 +1000,6 @@ test_expect_success 'git bisect reset cleans bisection state properly' '\n \ttest_path_is_missing \".git/BISECT_LOG\" &&\n \ttest_path_is_missing \".git/BISECT_RUN\" &&\n \ttest_path_is_missing \".git/BISECT_TERMS\" &&\n-\ttest_path_is_missing \".git/head-name\" &&\n \ttest_path_is_missing \".git/BISECT_HEAD\" &&\n \ttest_path_is_missing \".git/BISECT_START\"\n '\n-- \ngitgitgadget\n"},{"id":"457946","messageId":"d56f2a140602d2029e1091c20172214045686ab9.1656354677.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v4.git.1656354677.gitgitgadget@gmail.com","subject":"[PATCH v4 13/16] bisect: move even the command-line parsing to `bisect--helper`","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-06-27T18:31:14Z","receivedAt":"2022-06-27T18:37:16Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nOn our journey to a fully built-in `git bisect`, this is the\nlast step.\n\nSide note: The `parse-options` API is not at all set up to parse\nsubcommands such as `git bisect start`, `git bisect reset`, etc.\nInstead of fighting an up-hill battle trying to \"fix\" that, we simply\nroll the same type of manual subcommand parsing as we already do e.g.\nin `builtin/bundle.c`.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/bisect--helper.c | 103 +++++++++++----------------------------\n git-bisect.sh            |  49 +------------------\n 2 files changed, 30 insertions(+), 122 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 1914aa7c69f..7232d650905 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -23,7 +23,7 @@ static const char *bisect_usage =\n \tN_(\"git bisect [help|start|bad|good|new|old|terms|skip|next|reset|\"\n \t   \"visualize|view|replay|log|run]\");\n \n-static const char * const bisect_long_usage[] = {\n+static const char *bisect_long_usage =\n \tN_(\"git bisect [help|start|bad|good|new|old|terms|skip|next|reset|\"\n \t   \"visualize|view|replay|log|run]\\n\"\n \t   \"\\n\"\n@@ -58,9 +58,7 @@ static const char * const bisect_long_usage[] = {\n \t   \"git bisect run <cmd>...\\n\"\n \t   \"\\tuse <cmd>... to automatically bisect.\\n\"\n \t   \"\\n\"\n-\t   \"Please use \\\"git help bisect\\\" to get the full man page.\"),\n-\tNULL\n-};\n+\t   \"Please use \\\"git help bisect\\\" to get the full man page.\");\n \n struct add_bisect_ref_data {\n \tstruct rev_info *revs;\n@@ -1305,110 +1303,67 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n \n int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n {\n-\tenum {\n-\t\tBISECT_START = 1,\n-\t\tBISECT_STATE,\n-\t\tBISECT_TERMS,\n-\t\tBISECT_SKIP,\n-\t\tBISECT_NEXT,\n-\t\tBISECT_RESET,\n-\t\tBISECT_VISUALIZE,\n-\t\tBISECT_REPLAY,\n-\t\tBISECT_LOG,\n-\t\tBISECT_RUN,\n-\t} cmdmode = 0;\n \tint res = 0;\n-\tstruct option options[] = {\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-state\", &cmdmode,\n-\t\t\t N_(\"mark the state of ref (or refs)\"), BISECT_STATE),\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-skip\", &cmdmode,\n-\t\t\t N_(\"skip some commits for checkout\"), BISECT_SKIP),\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-reset\", &cmdmode,\n-\t\t\t N_(\"reset the bisection state\"), BISECT_RESET),\n-\t\tOPT_CMDMODE(0, \"bisect-visualize\", &cmdmode,\n-\t\t\t N_(\"visualize the bisection\"), BISECT_VISUALIZE),\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-log\", &cmdmode,\n-\t\t\t N_(\"list the bisection steps so far\"), BISECT_LOG),\n-\t\tOPT_CMDMODE(0, \"bisect-run\", &cmdmode,\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+\tconst char *command = argc > 1 ? argv[1] : \"help\";\n+\n+\tif (!strcmp(\"-h\", command) || !strcmp(\"help\", command))\n+\t\tusage(bisect_long_usage);\n \n-\targc = parse_options(argc, argv, prefix, options,\n-\t\t\t     bisect_long_usage,\n-\t\t\t     PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN);\n+\targc -= 2;\n+\targv += 2;\n \n-\tswitch (cmdmode ? cmdmode : BISECT_STATE) {\n-\tcase BISECT_START:\n+\tif (!strcmp(\"start\", command)) {\n \t\tset_terms(&terms, \"bad\", \"good\");\n \t\tres = bisect_start(&terms, argv, argc);\n-\t\tbreak;\n-\tcase BISECT_TERMS:\n+\t} else if (!strcmp(\"terms\", command)) {\n \t\tif (argc > 1)\n-\t\t\tdie(_(\"--bisect-terms requires 0 or 1 argument\"));\n+\t\t\tdie(_(\"'terms' requires 0 or 1 argument\"));\n \t\tres = bisect_terms(&terms, argc == 1 ? argv[0] : NULL);\n-\t\tbreak;\n-\tcase BISECT_SKIP:\n+\t} else if (!strcmp(\"skip\", command)) {\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_NEXT:\n+\t} else if (!strcmp(\"next\", command)) {\n \t\tif (argc)\n-\t\t\tdie(_(\"--bisect-next requires 0 arguments\"));\n+\t\t\tdie(_(\"'next' requires 0 arguments\"));\n \t\tget_terms(&terms);\n \t\tres = bisect_next(&terms, prefix);\n-\t\tbreak;\n-\tcase BISECT_RESET:\n+\t} else if (!strcmp(\"reset\", command)) {\n \t\tif (argc > 1)\n-\t\t\tdie(_(\"--bisect-reset requires either no argument or a commit\"));\n+\t\t\tdie(_(\"'reset' requires either no argument or a commit\"));\n \t\tres = bisect_reset(argc ? argv[0] : NULL);\n-\t\tbreak;\n-\tcase BISECT_VISUALIZE:\n+\t} else if (one_of(command, \"visualize\", \"view\", NULL)) {\n \t\tget_terms(&terms);\n \t\tres = bisect_visualize(&terms, argv, argc);\n-\t\tbreak;\n-\tcase BISECT_REPLAY:\n+\t} else if (!strcmp(\"replay\", command)) {\n \t\tif (argc != 1)\n \t\t\tdie(_(\"no logfile given\"));\n \t\tset_terms(&terms, \"bad\", \"good\");\n \t\tres = bisect_replay(&terms, argv[0]);\n-\t\tbreak;\n-\tcase BISECT_LOG:\n+\t} else if (!strcmp(\"log\", command)) {\n \t\tif (argc)\n-\t\t\tdie(_(\"--bisect-log requires 0 arguments\"));\n+\t\t\tdie(_(\"'log' requires 0 arguments\"));\n \t\tres = bisect_log();\n-\t\tbreak;\n-\tcase BISECT_RUN:\n+\t} else if (!strcmp(\"run\", command)) {\n \t\tif (!argc)\n \t\t\tdie(_(\"bisect run failed: no command provided.\"));\n \t\tget_terms(&terms);\n \t\tres = bisect_run(&terms, argv, argc);\n-\t\tbreak;\n-\tcase BISECT_STATE:\n-\t\tif (argc &&\n-\t\t    !file_is_not_empty(git_path_bisect_start()) &&\n-\t\t    !one_of(argv[0], \"bad\", \"good\", \"new\", \"old\", NULL))\n+\t} else {\n+\t\tif (!file_is_not_empty(git_path_bisect_start()) &&\n+\t\t    !one_of(command, \"bad\", \"good\", \"new\", \"old\", NULL))\n \t\t\tusage(bisect_usage);\n \t\tset_terms(&terms, \"bad\", \"good\");\n \t\tget_terms(&terms);\n-\t\tif (!cmdmode &&\n-\t\t    (!argc || check_and_set_terms(&terms, argv[0])))\n+\t\tif (check_and_set_terms(&terms, command))\n \t\t\tusage(bisect_usage);\n+\t\t/* shift the `command` back in */\n+\t\targc++;\n+\t\targv--;\n \t\tres = bisect_state(&terms, argv, argc);\n-\t\tbreak;\n-\tdefault:\n-\t\tBUG(\"unknown subcommand %d\", cmdmode);\n \t}\n+\n \tfree_terms(&terms);\n \n \t/*\ndiff --git a/git-bisect.sh b/git-bisect.sh\nindex fbf56649d7d..028d39cd9ce 100755\n--- a/git-bisect.sh\n+++ b/git-bisect.sh\n@@ -34,51 +34,4 @@ 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 --bisect-start \"$@\" ;;\n-\tbad|good|new|old|\"$TERM_BAD\"|\"$TERM_GOOD\")\n-\t\tgit bisect--helper \"$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-\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*)\n-\t\tusage ;;\n-\tesac\n-esac\n+exec git bisect--helper \"$@\"\n-- \ngitgitgadget\n\n"},{"id":"457947","messageId":"33566b86d77dcc11d68b2aceec0b6c5218bf198e.1656354677.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v4.git.1656354677.gitgitgadget@gmail.com","subject":"[PATCH v4 15/16] bisect: remove Cogito-related code","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-06-27T18:31:16Z","receivedAt":"2022-06-27T18:37:18Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nOnce upon a time, there was this idea that Git would not actually be a\nsingle coherent program, but rather a set of low-level programs that\nusers cobble together via shell scripts, or develop high-level user\ninterfaces for Git, or both.\n\nCogito was such a high-level user interface, incidentally implemented\nvia shell scripts that cobble together Git calls.\n\nIt did turn out relatively quickly that Git would much rather provide a\nuseful high-level user interface itself.\n\nAs of April 19th, 2007, Cogito was therefore discontinued (see\nhttps://lore.kernel.org/git/20070419124648.GL4489@pasky.or.cz/).\n\nNevertheless, for almost 15 years after that announcement, Git carried\nspecial code in `git bisect` to accommodate Cogito.\n\nSince it is beyond doubt that there are no more Cogito users, let's\nremove the last remnant of Cogito-accommodating code.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/bisect.c | 8 --------\n 1 file changed, 8 deletions(-)\n\ndiff --git a/builtin/bisect.c b/builtin/bisect.c\nindex 380fef852f3..47103ebf3f2 100644\n--- a/builtin/bisect.c\n+++ b/builtin/bisect.c\n@@ -14,7 +14,6 @@ static GIT_PATH_FUNC(git_path_bisect_expected_rev, \"BISECT_EXPECTED_REV\")\n static GIT_PATH_FUNC(git_path_bisect_ancestors_ok, \"BISECT_ANCESTORS_OK\")\n static GIT_PATH_FUNC(git_path_bisect_start, \"BISECT_START\")\n static GIT_PATH_FUNC(git_path_bisect_log, \"BISECT_LOG\")\n-static GIT_PATH_FUNC(git_path_head_name, \"head-name\")\n 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@@ -809,13 +808,6 @@ static enum bisect_error bisect_start(struct bisect_terms *terms, const char **a\n \t\t\tstrbuf_addstr(&start_head, oid_to_hex(&head_oid));\n \t\t} else if (!get_oid(head, &head_oid) &&\n \t\t\t   skip_prefix(head, \"refs/heads/\", &head)) {\n-\t\t\t/*\n-\t\t\t * This error message should only be triggered by\n-\t\t\t * cogito usage, and cogito users should understand\n-\t\t\t * it relates to cg-seek.\n-\t\t\t */\n-\t\t\tif (!is_empty_or_missing_file(git_path_head_name()))\n-\t\t\t\treturn error(_(\"won't bisect on cg-seek'ed tree\"));\n \t\t\tstrbuf_addstr(&start_head, head);\n \t\t} else {\n \t\t\treturn error(_(\"bad HEAD - strange symbolic ref\"));\n-- \ngitgitgadget\n\n"},{"id":"457962","messageId":"220627.86mtdxhnwk.gmgdl@evledraar.gmail.com","threadId":"57326","inReplyTo":"pull.1132.v4.git.1656354677.gitgitgadget@gmail.com","subject":"Re: [PATCH v4 00/16] Finish converting git bisect into a built-in","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-06-27T19:45:04Z","receivedAt":"2022-06-27T20:06:28Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Mon, Jun 27 2022, Johannes Schindelin via GitGitGadget wrote:\n\n> After three GSoC/Outreachy students spent an incredible effort on this, it\n> is finally time to put a neat little bow on it.\n\nI probably just missed this in past iterations, but there's no\nGSOC/Outreachy students in SOB, or even Helped-by. Was their code not\nusable & this is the rewrite?\n\nIf that's the case it's not clear what that has to do with the current\nstate of this series...\n\n> Changes since v3:\n>\n>  * Rebased because of merge conflicts with ab/plug-leak-in-revisions.\n>  * Fixed the bug that git bisect --bisect-terms 1 2 wanted to auto-start a\n>    bisection if running with a git executable built at the in-between state\n>    at patch \"bisect: move even the command-line parsing to bisect--helper\".\n>    Since this bug was \"fixed\" in v3 by the very next patch, \"bisect: teach\n>    the bisect--helper command to show the correct usage strings\", v4 avoids\n>    introducing this bug simply by letting these two patches trade places.\n>    The range-diff admittedly looks quite awful because both patches overlap\n>    quite a bit in the lines they modify. The end result is the same, though,\n>    the diff between v3's and v4's builtin/bisect.c would be empty if I\n>    hadn't been forced to rebase.\n>  * Added a test case to ensure that this bug won't be introduced again. This\n>    test case is the only actual difference relative to v3 of this patch\n>    series.\n\nI think there's still a lot of unnecessary churn in this series related\nto migrating away from parse_options(). Your 13/16 still has a side-note\nthat I noted as not making sense in a past iteration.\n\nOn top of \"master\" I tried this trivial alternative to what you're doing\nhere in a *lot* more lines:\n\t\n\tdiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\n\tindex 8a052c7111f..38b23ee5fd4 100644\n\t--- a/builtin/bisect--helper.c\n\t+++ b/builtin/bisect--helper.c\n\t@@ -1321,6 +1321,29 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n\t \t\tOPT_END()\n\t \t};\n\t \tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\n\t+\tint i;\n\t+\tstruct strvec args = STRVEC_INIT;\n\t+\t\n\t+\tfor (i = 0; i < argc; i++) {\n\t+\t\tconst char *arg = argv[i];\n\t+\t\tint is_cmd = 0;\n\t+\t\tconst struct option *o = options;\n\t+\n\t+\t\tfor (; o->type != OPTION_END; o++)\n\t+\t\t\tif (o->flags & PARSE_OPT_CMDMODE &&\n\t+\t\t\t    !strcmp(o->long_name, arg)) {\n\t+\t\t\t\tis_cmd = 1;\n\t+\t\t\t\tbreak;\n\t+\t\t\t}\n\t+\n\t+\t\tif (is_cmd)\n\t+\t\t\tstrvec_pushf(&args, \"--%s\", arg);\n\t+\t\telse\n\t+\t\t\tstrvec_push(&args, argv[i]);\n\t+\n\t+\t}\n\t+\targc = args.nr;\n\t+\targv = args.v;\n\t \n\t \targc = parse_options(argc, argv, prefix, options,\n\t \t\t\t     git_bisect_helper_usage,\n\tdiff --git a/git-bisect.sh b/git-bisect.sh\n\tindex 405cf76f2a3..0fd63bf34db 100755\n\t--- a/git-bisect.sh\n\t+++ b/git-bisect.sh\n\t@@ -57,27 +57,10 @@ case \"$#\" in\n\t \tcase \"$cmd\" in\n\t \thelp)\n\t \t\tgit bisect -h ;;\n\t-\tstart)\n\t-\t\tgit bisect--helper --bisect-start \"$@\" ;;\n\t \tbad|good|new|old|\"$TERM_BAD\"|\"$TERM_GOOD\")\n\t \t\tgit bisect--helper --bisect-state \"$cmd\" \"$@\" ;;\n\t-\tskip)\n\t-\t\tgit bisect--helper --bisect-skip \"$@\" || exit;;\n\t-\tnext)\n\t-\t\t# Not sure we want \"next\" at the UI level anymore.\n\t-\t\tgit bisect--helper --bisect-next \"$@\" || exit ;;\n\t-\tvisualize|view)\n\t-\t\tgit bisect--helper --bisect-visualize \"$@\" || exit;;\n\t-\treset)\n\t-\t\tgit bisect--helper --bisect-reset \"$@\" ;;\n\t-\treplay)\n\t-\t\tgit bisect--helper --bisect-replay \"$@\" || exit;;\n\t-\tlog)\n\t-\t\tgit bisect--helper --bisect-log || exit ;;\n\t-\trun)\n\t-\t\tgit bisect--helper --bisect-run \"$@\" || exit;;\n\t-\tterms)\n\t-\t\tgit bisect--helper --bisect-terms \"$@\" || exit;;\n\t+\tstart|skip|next|visualize|view|reset|replay|log|run|terms)\n\t+\t\tgit bisect--helper \"--bisect-$cmd\" \"$@\" || exit;;\n\t \t*)\n\t \t\tusage ;;\n\t \tesac\n\nI.e. you're spending a lot of effort on working around the\nparse_options() API supporting \"--options-like-this\" but not\n\"options-like-this\". In this case it's much easier just to \"fake it\",\nisn't it?\n\nOf course near the end of this series we'd need to adjust that, but\ndoing so seems pretty easy, either just treat \"start\" as \"--start\", or\nperhaps patch the relevant bits of parse_options(), but just\nconstructing a new command-line as I'm doing here seemed easier.\n\nNow, there's a subtle bug in the above, I passed \"view\" as-is, but this\nwill error out. I don't think your topic introduces any bugs related to\nthat (that I've seen), but it goes to the \"confidence building\" part of [1].\n\nI.e. here we're converting a bunch of code that doesn't have tests, and\nas seen above v.s. the relevant parts of your series doing so in a way\nthat's not the least invasive path to that goal.\n\nIn particular I think all of 08/16, 09/16 and 13/16 (and maybe 10/16?)\nwould be easier & more straightforward to do with such one-pass argv\nconstruction. I.e. if we make \"start\" a \"--start\" and e.g. \"good\" a\n[\"--bisect-state\", \"good\"] shouldn't this all just work without\nmigrating bisect--helper away from parse_options()?\n\nIn that way this seems a bit like two steps forward & one step back,\ne.g. with the above patch we could drive 'git bisect' completion via the\nusual --git-completion-helper facility (with a trivial s/--//)\nworkaround.\n\nB.t.w. I think your tip is buggy with regards to that, i.e. don't you\nneed a NO_PARSEOPT flag in git.c when you s/bisect--helper/bisect/ so\nthat the completion doesn't try to use both --git-completion-helper and\nits own current 'bisect function' (but maybe it works by happy accident\nnow?). In any case if you're set on converting this away from\nparse_options() you should add that flag in git.c.\n\nI think as far as this conversion goes we could say \"we'll use\nparse_options() again later\", even though I think doing so is\nunfortunate, as I think you're going the long way around to migrate away\nfrom an API we're generally migrating to, when we can use it rather\neasily.\n\nI'm mainly concerned with the lack of testing. You have a new 01/16\nhere, but as noted in[1] and above that's really the tip of the iceberg.\n\nMaybe you're really confident that that was the last bug, even without\ntesting basic things like \"view\" working at all, but the CL here doesn't\nreally make for a convincing (to me) argument.\n\n1. https://lore.kernel.org/git/220523.865ylwzgji.gmgdl@evledraar.gmail.com/\n"},{"id":"457963","messageId":"220627.86ilolhnnn.gmgdl@evledraar.gmail.com","threadId":"57326","inReplyTo":"ce508583e455a1dbb7620a238edb11dae195f00d.1656354677.git.gitgitgadget@gmail.com","subject":"Re: [PATCH v4 11/16] bisect--helper: return only correct exit codes in `cmd_*()`","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-06-27T20:09:28Z","receivedAt":"2022-06-27T20:11:47Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Mon, Jun 27 2022, Johannes Schindelin via GitGitGadget wrote:\n\n> From: Johannes Schindelin <johannes.schindelin@gmx.de>\n>\n> Exit codes cannot be negative, but `error()` returns -1.\n\nThat's good, but...\n\n> Let's just go with the common pattern and call `die()` in\n> `cmd_bisect__helper()` when incorrect arguments were detected.\n\n...the common and correct pattern on bad options is to return 129, not\n128, which using use usage_msg_opt() instead of die() here would give\nyou for free. I think this should use that instead.\n"},{"id":"457971","messageId":"xmqqwnd1n4de.fsf@gitster.g","threadId":"57326","inReplyTo":"5dbe233e4ec2f404bb236a8ee71d24e8cb6a4387.1656354677.git.gitgitgadget@gmail.com","subject":"Re: [PATCH v4 12/16] bisect: teach the `bisect--helper` command to show the correct usage strings","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-06-27T22:11:41Z","receivedAt":"2022-06-27T22:11:46Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Johannes Schindelin via GitGitGadget\" <gitgitgadget@gmail.com>\nwrites:\n\n> From: Johannes Schindelin <johannes.schindelin@gmx.de>\n>\n> In preparation for `bisect--helper` graduating to become the actual\n> `bisect` command, we hereby teach it to print the very same usage\n> strings as the scripted `git-bisect.sh` does.\n\nSounds good.  If we stop the series at this stage, a misimplemented\ncaller might give us an awkweard output, but we are not expecting\nend-users to invoke \"git bisect--helper -h\" to begin with, so it is\nperfectly OK.  Somewhere during the journey to fully move it to\nbuiltin/bisect.c this needs to be done, and this step may probably\nbe the right spot in the series.\n"},{"id":"457972","messageId":"xmqqsfnpn49r.fsf@gitster.g","threadId":"57326","inReplyTo":"378d6d227372405326112fee03c377f1aff386fc.1656354677.git.gitgitgadget@gmail.com","subject":"Re: [PATCH v4 14/16] Turn `git bisect` into a full built-in","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-06-27T22:13:52Z","receivedAt":"2022-06-27T22:14:00Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Johannes Schindelin via GitGitGadget\" <gitgitgadget@gmail.com>\nwrites:\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> ---\n>  Makefile                               |  3 +--\n>  builtin.h                              |  2 +-\n>  builtin/{bisect--helper.c => bisect.c} |  2 +-\n>  git-bisect.sh                          | 37 --------------------------\n>  git.c                                  |  2 +-\n>  5 files changed, 4 insertions(+), 42 deletions(-)\n>  rename builtin/{bisect--helper.c => bisect.c} (99%)\n>  delete mode 100755 git-bisect.sh\n\nGood.\n\n"},{"id":"457973","messageId":"xmqqo7ydn42a.fsf@gitster.g","threadId":"57326","inReplyTo":"33566b86d77dcc11d68b2aceec0b6c5218bf198e.1656354677.git.gitgitgadget@gmail.com","subject":"Re: [PATCH v4 15/16] bisect: remove Cogito-related code","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-06-27T22:18:21Z","receivedAt":"2022-06-27T22:18:27Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Johannes Schindelin via GitGitGadget\" <gitgitgadget@gmail.com>\nwrites:\n\n> As of April 19th, 2007, Cogito was therefore discontinued (see\n> https://lore.kernel.org/git/20070419124648.GL4489@pasky.or.cz/).\n>\n> Nevertheless, for almost 15 years after that announcement, Git carried\n> special code in `git bisect` to accommodate Cogito.\n\nGood eyes.  Doesn't steps 15 & 16 cover the same theme, though?\nIOW, if surviving Cogito users appear after we take this 16-patch\nseries, would reverting this step the only thing needed if we decide\nto accomodate them again (and removal of head-name done in step 16\ncan still be kept without harming these Cogito users)?  I am wondering\nif these should be merged into one patch.\n\nThanks.\n\n\n>\n> Since it is beyond doubt that there are no more Cogito users, let's\n> remove the last remnant of Cogito-accommodating code.\n>\n> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> ---\n>  builtin/bisect.c | 8 --------\n>  1 file changed, 8 deletions(-)\n\n\n\n>\n> diff --git a/builtin/bisect.c b/builtin/bisect.c\n> index 380fef852f3..47103ebf3f2 100644\n> --- a/builtin/bisect.c\n> +++ b/builtin/bisect.c\n> @@ -14,7 +14,6 @@ static GIT_PATH_FUNC(git_path_bisect_expected_rev, \"BISECT_EXPECTED_REV\")\n>  static GIT_PATH_FUNC(git_path_bisect_ancestors_ok, \"BISECT_ANCESTORS_OK\")\n>  static GIT_PATH_FUNC(git_path_bisect_start, \"BISECT_START\")\n>  static GIT_PATH_FUNC(git_path_bisect_log, \"BISECT_LOG\")\n> -static GIT_PATH_FUNC(git_path_head_name, \"head-name\")\n>  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> @@ -809,13 +808,6 @@ static enum bisect_error bisect_start(struct bisect_terms *terms, const char **a\n>  \t\t\tstrbuf_addstr(&start_head, oid_to_hex(&head_oid));\n>  \t\t} else if (!get_oid(head, &head_oid) &&\n>  \t\t\t   skip_prefix(head, \"refs/heads/\", &head)) {\n> -\t\t\t/*\n> -\t\t\t * This error message should only be triggered by\n> -\t\t\t * cogito usage, and cogito users should understand\n> -\t\t\t * it relates to cg-seek.\n> -\t\t\t */\n> -\t\t\tif (!is_empty_or_missing_file(git_path_head_name()))\n> -\t\t\t\treturn error(_(\"won't bisect on cg-seek'ed tree\"));\n>  \t\t\tstrbuf_addstr(&start_head, head);\n>  \t\t} else {\n>  \t\t\treturn error(_(\"bad HEAD - strange symbolic ref\"));\n"},{"id":"457985","messageId":"xmqqilolmt8o.fsf@gitster.g","threadId":"57326","inReplyTo":"30ddbd7affc83e9b20ecdd66d941f1acc2cbc787.1656354677.git.gitgitgadget@gmail.com","subject":"Re: [PATCH v4 01/16] bisect: verify that a bogus option won't try to start a bisection","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-06-28T02:12:07Z","receivedAt":"2022-06-28T02:12:19Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Johannes Schindelin via GitGitGadget\" <gitgitgadget@gmail.com>\nwrites:\n\n> From: Johannes Schindelin <johannes.schindelin@gmx.de>\n>\n> We do not want `git bisect --bogus-option` to start a bisection. To\n> verify that, we look for the tell-tale error message `You need to start\n> by \"git bisect start\"` and fail if it was found.\n>\n> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> ---\n\nSorry, but this looks unclear to me.\n\nIn the test \"--bisect-terms\" is used, and from \"git grep\" it does\nseem to be one of the valid options \"git bisect--helper\" can take.\nIt is unclear if the patch wanted to literally use \"--bogus-option\"\ninsteaed of it but used \"--bisect-terms\" by mistake, or if that\nvalid option is \"bogus\" only in the sense that the option is not yet\nrelevant immediately after \"git bisect reset\" before a new \"git\nbisect start\" session has begun.  IOW, \"bogus\" both in the patch\ntitle and the test title needs to be clarified.\n\nTo put it another way, can we demonstrate the same correctness by\nseeing \"git bisect --no-such-option\" fail immediately after \"git\nbisect reset\"?\n\n\n\n>  t/t6030-bisect-porcelain.sh | 10 ++++++++++\n>  1 file changed, 10 insertions(+)\n>\n> diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh\n> index 83931d482fb..6d6e72276ae 100755\n> --- a/t/t6030-bisect-porcelain.sh\n> +++ b/t/t6030-bisect-porcelain.sh\n> @@ -900,6 +900,16 @@ test_expect_success 'bisect start with one term1 and term2' '\n>  \tgit bisect reset\n>  '\n>  \n> +test_expect_success 'bogus command does not start bisect' '\n> +\tgit bisect reset &&\n> +\ttest_must_fail git bisect --bisect-terms 1 2 2>out &&\n> +\t! grep \"You need to start\" out &&\n> +\ttest_must_fail git bisect --bisect-terms 2>out &&\n> +\t! grep \"You need to start\" out &&\n> +\tgrep \"git bisect.*visualize\" out &&\n> +\tgit bisect reset\n> +'\n> +\n>  test_expect_success 'bisect replay with term1 and term2' '\n>  \tgit bisect replay log_to_replay.txt >bisect_result &&\n>  \tgrep \"$HASH2 is the first term1 commit\" bisect_result &&\n"},{"id":"462026","messageId":"pull.1132.v5.git.1661604264.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v4.git.1656354677.gitgitgadget@gmail.com","subject":"[PATCH v5 00/16] Finish converting git bisect into a built-in","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-08-27T12:44:08Z","receivedAt":"2022-08-27T12:44:40Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"After three GSoC/Outreachy students spent an incredible effort on this, it\nis finally time to put a neat little bow on it, or maybe more like a big\nbow, maybe even a very large one, seeing as it takes quite a while to tie\n(half a year at the time of writing)...\n\nChanges since v4:\n\n * rebased onto sg/parse-options-subcommand\n * migrated to OPT_SUBCOMMAND().\n * As a consequence, this patch series is now unfortunately very large. And\n   the range-diff is much less useful than I'd like because of the extensive\n   changes that were de facto made a precondition to moving this patch\n   series further. Junio, I would have liked to keep the scope (and burden\n   for the reviewers) substantially smaller, maybe you can help with the\n   review?\n\nChanges since v3:\n\n * Rebased because of merge conflicts with ab/plug-leak-in-revisions.\n * Fixed the bug that git bisect --bisect-terms 1 2 wanted to auto-start a\n   bisection if running with a git executable built at the in-between state\n   at patch \"bisect: move even the command-line parsing to bisect--helper\".\n   Since this bug was \"fixed\" in v3 by the very next patch, \"bisect: teach\n   the bisect--helper command to show the correct usage strings\", v4 avoids\n   introducing this bug simply by letting these two patches trade places.\n   The range-diff admittedly looks quite awful because both patches overlap\n   quite a bit in the lines they modify. The end result is the same, though,\n   the diff between v3's and v4's builtin/bisect.c would be empty if I\n   hadn't been forced to rebase.\n * Added a test case to ensure that this bug won't be introduced again. This\n   test case is the only actual difference relative to v3 of this patch\n   series.\n\nChanges since v2:\n\n * We're now careful to provide identical usage strings upon git bisect -h\n   and git bisect bogus.\n * When a bogus command is provided, we now error out instead of trying to\n   start a git bisect run.\n * Rebased onto main to avoid plenty of merge conflicts with\n   rs/bisect-executable-not-found, ac/usage-string-fixups and with\n   cd/bisect-messages-from-pre-flight-states.\n\nChanges since v1:\n\n * Added a regression test to \"bisect run: fix the error message\".\n * Added a patch to address an error message that double-single-quoted the\n   command.\n * Reworked the logic in \"bisect--helper: make --bisect-state optional\" to\n   delay showing the usage upon an unknown command, which should make the\n   code a lot less confusing.\n * Split out the change that moved the BISECT_STATE case to the end of the\n   switch block.\n * Added a patch that replaces the return error() calls in\n   cmd_bisect_helper() with die() calls, to avoid returning -1 as an exit\n   code.\n * Dropped the use of parse_options() for the single purpose of handling -h;\n   This is now done explicitly.\n * Simplified the diff of \"bisect: move even the option parsing to\n   bisect--helper\" by modifying argc and argv instead of modifying all the\n   function calls using those variables.\n * In the \"Turn git bisect into a full built-in\" patch, changed the name of\n   the variable holding the usage to use the builtin_ prefix used in other\n   built-ins, too.\n * Removed the trailing dot from the commit message of \"Turn git bisect into\n   a full built-in\".\n\nJohannes Schindelin (16):\n  bisect--helper: retire the --no-log option\n  bisect--helper: really retire --bisect-next-check\n  bisect--helper: really retire `--bisect-autostart`\n  bisect--helper: simplify exit code computation\n  bisect--helper: make `terms` an explicit singleton\n  bisect--helper: make the order consistently `argc, argv`\n  bisect--helper: migrate to OPT_SUBCOMMAND()\n  bisect: verify that a bogus option won't try to start a bisection\n  bisect run: fix the error message\n  bisect: avoid double-quoting when printing the failed command\n  bisect--helper: calling `bisect_state()` without an argument is a bug\n  bisect--helper: make `state` optional\n  bisect: move even the command-line parsing to `bisect--helper`\n  Turn `git bisect` into a full built-in\n  bisect: remove Cogito-related code\n  bisect: no longer try to clean up left-over `.git/head-name` files\n\n Makefile                               |   3 +-\n bisect.c                               |   3 -\n builtin.h                              |   2 +-\n builtin/{bisect--helper.c => bisect.c} | 679 ++++++++++++++-----------\n git-bisect.sh                          |  84 ---\n git.c                                  |   2 +-\n t/t6030-bisect-porcelain.sh            |  21 +-\n 7 files changed, 406 insertions(+), 388 deletions(-)\n rename builtin/{bisect--helper.c => bisect.c} (67%)\n delete mode 100755 git-bisect.sh\n\n\nbase-commit: 8f9d80f6c06369b563c76ec46c462e740a1a2cf0\nPublished-As: https://github.com/gitgitgadget/git/releases/tag/pr-1132%2Fdscho%2Fbisect-in-c-v5\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1132/dscho/bisect-in-c-v5\nPull-Request: https://github.com/gitgitgadget/git/pull/1132\n\nRange-diff vs v4:\n\n  4:  5bfaf0334c3 =  1:  05262b6a7d1 bisect--helper: retire the --no-log option\n  5:  e85f236304b =  2:  1e43148864a bisect--helper: really retire --bisect-next-check\n  6:  b94b7bb4fd0 =  3:  1a1649d9d0d bisect--helper: really retire `--bisect-autostart`\n  -:  ----------- >  4:  9ab30552c6a bisect--helper: simplify exit code computation\n  -:  ----------- >  5:  92b3b116ef8 bisect--helper: make `terms` an explicit singleton\n 11:  ce508583e45 !  6:  c9dc0281e38 bisect--helper: return only correct exit codes in `cmd_*()`\n     @@ Metadata\n      Author: Johannes Schindelin <Johannes.Schindelin@gmx.de>\n      \n       ## Commit message ##\n     -    bisect--helper: return only correct exit codes in `cmd_*()`\n     +    bisect--helper: make the order consistently `argc, argv`\n      \n     -    Exit codes cannot be negative, but `error()` returns -1.\n     +    In C, the natural order is for `argc` to come before `argv` by virtue of\n     +    the `main()` function declaring the parameters in precisely that order.\n      \n     -    Let's just go with the common pattern and call `die()` in\n     -    `cmd_bisect__helper()` when incorrect arguments were detected.\n     +    It is confusing & distracting, then, when readers familiar with the C\n     +    language read code where that order is switched around.\n     +\n     +    Let's just change the order and avoid that type of developer friction.\n      \n          Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n      \n       ## builtin/bisect--helper.c ##\n     +@@ builtin/bisect--helper.c: static enum bisect_error bisect_auto_next(const char *prefix)\n     + \treturn bisect_next(prefix);\n     + }\n     + \n     +-static enum bisect_error bisect_start(const char **argv, int argc)\n     ++static enum bisect_error bisect_start(int argc, const char **argv)\n     + {\n     + \tint no_checkout = 0;\n     + \tint first_parent_only = 0;\n     +@@ builtin/bisect--helper.c: static int bisect_autostart(void)\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(empty_strvec, 0);\n     ++\t\t-1 : bisect_start(0, empty_strvec);\n     + \n     + \treturn res;\n     + }\n     + \n     +-static enum bisect_error bisect_state(const char **argv,\n     +-\t\t\t\t      int argc)\n     ++static enum bisect_error bisect_state(int argc, const char **argv)\n     + {\n     + \tconst char *state;\n     + \tint i, verify_expected = 1;\n     +@@ builtin/bisect--helper.c: static int process_replay_line(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(argv.v, argv.nr);\n     ++\t\tres = bisect_start(argv.nr, argv.v);\n     + \t\tstrvec_clear(&argv);\n     + \t\treturn res;\n     + \t}\n     +@@ builtin/bisect--helper.c: static enum bisect_error bisect_replay(const char *filename)\n     + \treturn bisect_auto_next(NULL);\n     + }\n     + \n     +-static enum bisect_error bisect_skip(const char **argv, int argc)\n     ++static enum bisect_error bisect_skip(int argc, const char **argv)\n     + {\n     + \tint i;\n     + \tenum bisect_error res;\n     +@@ builtin/bisect--helper.c: static enum bisect_error bisect_skip(const char **argv, int argc)\n     + \t\t\tstrvec_push(&argv_state, argv[i]);\n     + \t\t}\n     + \t}\n     +-\tres = bisect_state(argv_state.v, argv_state.nr);\n     ++\tres = bisect_state(argv_state.nr, argv_state.v);\n     + \n     + \tstrvec_clear(&argv_state);\n     + \treturn res;\n     + }\n     + \n     +-static int bisect_visualize(const char **argv, int argc)\n     ++static int bisect_visualize(int argc, const char **argv)\n     + {\n     + \tstruct strvec args = STRVEC_INIT;\n     + \tint flags = RUN_COMMAND_NO_STDIN, res = 0;\n     +@@ builtin/bisect--helper.c: static int verify_good(const char **quoted_argv)\n     + \treturn rc;\n     + }\n     + \n     +-static int bisect_run(const char **argv, int argc)\n     ++static int bisect_run(int argc, const char **argv)\n     + {\n     + \tint res = BISECT_OK;\n     + \tstruct strbuf command = STRBUF_INIT;\n     +@@ builtin/bisect--helper.c: static int bisect_run(const char **argv, int argc)\n     + \t\tsaved_stdout = dup(1);\n     + \t\tdup2(temporary_stdout_fd, 1);\n     + \n     +-\t\tres = bisect_state(&new_state, 1);\n     ++\t\tres = bisect_state(1, &new_state);\n     + \n     + \t\tfflush(stdout);\n     + \t\tdup2(saved_stdout, 1);\n      @@ builtin/bisect--helper.c: int cmd_bisect__helper(int argc, const char **argv, const char *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\t\tdie(_(\"--bisect-terms requires 0 or 1 argument\"));\n     - \t\tres = bisect_terms(&terms, argc == 1 ? argv[0] : NULL);\n     - \t\tbreak;\n     - \tcase BISECT_SKIP:\n     -@@ builtin/bisect--helper.c: int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n     + \tcase BISECT_START:\n     + \t\tset_terms(\"bad\", \"good\");\n     +-\t\tres = bisect_start(argv, argc);\n     ++\t\tres = bisect_start(argc, argv);\n       \t\tbreak;\n       \tcase BISECT_NEXT:\n       \t\tif (argc)\n     --\t\t\treturn error(_(\"--bisect-next requires 0 arguments\"));\n     -+\t\t\tdie(_(\"--bisect-next requires 0 arguments\"));\n     - \t\tget_terms(&terms);\n     - \t\tres = bisect_next(&terms, prefix);\n     - \t\tbreak;\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\t\tdie(_(\"--bisect-reset requires either no argument or a commit\"));\n     - \t\tres = bisect_reset(argc ? argv[0] : NULL);\n     - \t\tbreak;\n     - \tcase BISECT_VISUALIZE:\n      @@ builtin/bisect--helper.c: int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n     - \t\tbreak;\n     - \tcase BISECT_REPLAY:\n     - \t\tif (argc != 1)\n     --\t\t\treturn error(_(\"no logfile given\"));\n     -+\t\t\tdie(_(\"no logfile given\"));\n     - \t\tset_terms(&terms, \"bad\", \"good\");\n     - \t\tres = bisect_replay(&terms, argv[0]);\n     + \tcase BISECT_STATE:\n     + \t\tset_terms(\"bad\", \"good\");\n     + \t\tget_terms();\n     +-\t\tres = bisect_state(argv, argc);\n     ++\t\tres = bisect_state(argc, argv);\n       \t\tbreak;\n       \tcase BISECT_LOG:\n       \t\tif (argc)\n     --\t\t\treturn error(_(\"--bisect-log requires 0 arguments\"));\n     -+\t\t\tdie(_(\"--bisect-log requires 0 arguments\"));\n     - \t\tres = bisect_log();\n     +@@ builtin/bisect--helper.c: int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n     + \tcase BISECT_SKIP:\n     + \t\tset_terms(\"bad\", \"good\");\n     + \t\tget_terms();\n     +-\t\tres = bisect_skip(argv, argc);\n     ++\t\tres = bisect_skip(argc, argv);\n     + \t\tbreak;\n     + \tcase BISECT_VISUALIZE:\n     + \t\tget_terms();\n     +-\t\tres = bisect_visualize(argv, argc);\n     ++\t\tres = bisect_visualize(argc, argv);\n       \t\tbreak;\n       \tcase BISECT_RUN:\n       \t\tif (!argc)\n     --\t\t\treturn error(_(\"bisect run failed: no command provided.\"));\n     -+\t\t\tdie(_(\"bisect run failed: no command provided.\"));\n     - \t\tget_terms(&terms);\n     - \t\tres = bisect_run(&terms, argv, argc);\n     + \t\t\treturn error(_(\"bisect run failed: no command provided.\"));\n     + \t\tget_terms();\n     +-\t\tres = bisect_run(argv, argc);\n     ++\t\tres = bisect_run(argc, argv);\n       \t\tbreak;\n     + \tdefault:\n     + \t\tBUG(\"unknown subcommand %d\", cmdmode);\n  -:  ----------- >  7:  5b7a3d58b4f bisect--helper: migrate to OPT_SUBCOMMAND()\n  1:  30ddbd7affc =  8:  ba537af7066 bisect: verify that a bogus option won't try to start a bisection\n  2:  97dd2da8f89 !  9:  409492ad830 bisect run: fix the error message\n     @@ Commit message\n          Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n      \n       ## builtin/bisect--helper.c ##\n     -@@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n     +@@ builtin/bisect--helper.c: static int cmd_bisect_run(int argc, const char **argv, const char *prefix)\n       \t\t\tprintf(_(\"bisect found first bad commit\"));\n       \t\t\tres = BISECT_OK;\n       \t\t} else if (res) {\n  3:  5571e0f76ff ! 10:  bc5efc8fbfe bisect: avoid double-quoting when printing the failed command\n     @@ Commit message\n          Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n      \n       ## builtin/bisect--helper.c ##\n     -@@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n     +@@ builtin/bisect--helper.c: static int cmd_bisect_run(int argc, const char **argv, const char *prefix)\n       \n       \t\tif (res < 0 || 128 <= res) {\n       \t\t\terror(_(\"bisect run failed: exit code %d from\"\n  7:  aad3c9a0850 ! 11:  8a0adfe3867 bisect--helper: using `--bisect-state` without an argument is a bug\n     @@ Metadata\n      Author: Johannes Schindelin <Johannes.Schindelin@gmx.de>\n      \n       ## Commit message ##\n     -    bisect--helper: using `--bisect-state` without an argument is a bug\n     +    bisect--helper: calling `bisect_state()` without an argument is a bug\n      \n     -    The `bisect--helper` command is not expected to be used directly by the\n     -    user. Therefore, it is a bug if it receives no argument to the\n     -    `--bisect-state` command mode, not a user error. Which means that we\n     -    need to call `BUG()` instead of `die()`.\n     +    The `bisect_state()` function is now a purely internal function and must\n     +    be called with a valid state, everything else is a bug.\n      \n          Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n      \n       ## builtin/bisect--helper.c ##\n     -@@ builtin/bisect--helper.c: static enum bisect_error bisect_state(struct bisect_terms *terms, const char **a\n     +@@ builtin/bisect--helper.c: static enum bisect_error bisect_state(int argc, const char **argv,\n     + \tstruct strbuf buf = STRBUF_INIT;\n       \tstruct oid_array revs = OID_ARRAY_INIT;\n       \n     - \tif (!argc)\n     --\t\treturn error(_(\"Please call `--bisect-state` with at least one argument\"));\n     ++\tif (!argc)\n      +\t\tBUG(\"bisect_state() called without argument\");\n       \n     - \tif (bisect_autostart(terms))\n     + \tif (bisect_autostart(prefix))\n       \t\treturn BISECT_FAILED;\n  8:  375a46dca9f <  -:  ----------- bisect--helper: align the sub-command order with git-bisect.sh\n  9:  c57f63f6a61 ! 12:  189d2b3ba46 bisect--helper: make `--bisect-state` optional\n     @@ Metadata\n      Author: Johannes Schindelin <Johannes.Schindelin@gmx.de>\n      \n       ## Commit message ##\n     -    bisect--helper: make `--bisect-state` optional\n     +    bisect--helper: make `state` optional\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 `--bisect-state`\n     -    option to be passed explicitly.\n     +    `git bisect--helper bad`, i.e. do not require the `state` subcommand to\n     +    be passed explicitly.\n      \n          Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n      \n       ## builtin/bisect--helper.c ##\n     -@@ builtin/bisect--helper.c: static const char * const git_bisect_helper_usage[] = {\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-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     -@@ builtin/bisect--helper.c: int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n     - \t\t\t     git_bisect_helper_usage,\n     - \t\t\t     PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN);\n     +@@ builtin/bisect--helper.c: static int cmd_bisect_run(int argc, const char **argv, const char *prefix)\n       \n     --\tif (!cmdmode)\n     --\t\tusage_with_options(git_bisect_helper_usage, options);\n     --\n     --\tswitch (cmdmode) {\n     -+\tswitch (cmdmode ? cmdmode : BISECT_STATE) {\n     - \tcase BISECT_START:\n     - \t\tset_terms(&terms, \"bad\", \"good\");\n     - \t\tres = bisect_start(&terms, argv, argc);\n     + int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n     + {\n     ++\tstruct strvec args = STRVEC_INIT;\n     + \tparse_opt_subcommand_fn *fn = NULL;\n     + \tint res = 0;\n     + \tstruct option options[] = {\n      @@ builtin/bisect--helper.c: int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n     - \tcase BISECT_STATE:\n     - \t\tset_terms(&terms, \"bad\", \"good\");\n     - \t\tget_terms(&terms);\n     -+\t\tif (!cmdmode &&\n     -+\t\t    (!argc || check_and_set_terms(&terms, argv[0]))) {\n     -+\t\t\tchar *msg = xstrfmt(_(\"unknown command: '%s'\"), argv[0]);\n     -+\t\t\tusage_msg_opt(msg, git_bisect_helper_usage, options);\n     -+\t\t}\n     - \t\tres = bisect_state(&terms, argv, argc);\n     - \t\tbreak;\n     - \tcase BISECT_TERMS:\n     + \t};\n     + \n     + \targc = parse_options(argc, argv, prefix, options,\n     +-\t\t\t     bisect_usage, 0);\n     ++\t\t\t     bisect_usage, PARSE_OPT_SUBCOMMAND_OPTIONAL);\n     ++\n     ++\tif (!fn) {\n     ++\t\tif (!argc)\n     ++\t\t\tusage_msg_opt(_(\"need a command\"), bisect_usage,\n     ++\t\t\t\t      options);\n     ++\n     ++\t\tset_terms(\"bad\", \"good\");\n     ++\t\tget_terms();\n     ++\t\tif (check_and_set_terms(argv[0]))\n     ++\t\t\tusage_msg_optf(_(\"unknown command: '%s'\"), bisect_usage,\n     ++\t\t\t\t       options, argv[0]);\n     ++\n     ++\t\tstrvec_push(&args, \"state\");\n     ++\t\tstrvec_pushv(&args, argv);\n     ++\t\targc = args.nr;\n     ++\t\targv = args.v;\n     ++\t\tfn = cmd_bisect_state;\n     ++\t}\n     + \n     + \tres = fn(argc, argv, prefix);\n     + \tfree_terms();\n     ++\tstrvec_clear(&args);\n     + \n     + \treturn is_bisect_success(res) ? 0 : -res;\n     + }\n      \n       ## git-bisect.sh ##\n      @@ git-bisect.sh: case \"$#\" in\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      +\t\tgit bisect--helper \"$cmd\" \"$@\" ;;\n       \tskip)\n     - \t\tgit bisect--helper --bisect-skip \"$@\" || exit;;\n     + \t\tgit bisect--helper skip \"$@\" || exit;;\n       \tnext)\n 10:  87f53469a72 <  -:  ----------- bisect--helper: move the `BISECT_STATE` case to the end\n 12:  5dbe233e4ec <  -:  ----------- bisect: teach the `bisect--helper` command to show the correct usage strings\n 13:  d56f2a14060 ! 13:  32bf74e3050 bisect: move even the command-line parsing to `bisect--helper`\n     @@ Commit message\n          On our journey to a fully built-in `git bisect`, this is the\n          last step.\n      \n     -    Side note: The `parse-options` API is not at all set up to parse\n     -    subcommands such as `git bisect start`, `git bisect reset`, etc.\n     -    Instead of fighting an up-hill battle trying to \"fix\" that, we simply\n     -    roll the same type of manual subcommand parsing as we already do e.g.\n     -    in `builtin/bundle.c`.\n     -\n          Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n      \n       ## builtin/bisect--helper.c ##\n     -@@ builtin/bisect--helper.c: static const char *bisect_usage =\n     - \tN_(\"git bisect [help|start|bad|good|new|old|terms|skip|next|reset|\"\n     - \t   \"visualize|view|replay|log|run]\");\n     - \n     --static const char * const bisect_long_usage[] = {\n     -+static const char *bisect_long_usage =\n     - \tN_(\"git bisect [help|start|bad|good|new|old|terms|skip|next|reset|\"\n     - \t   \"visualize|view|replay|log|run]\\n\"\n     - \t   \"\\n\"\n     -@@ builtin/bisect--helper.c: static const char * const bisect_long_usage[] = {\n     - \t   \"git bisect run <cmd>...\\n\"\n     - \t   \"\\tuse <cmd>... to automatically bisect.\\n\"\n     - \t   \"\\n\"\n     --\t   \"Please use \\\"git help bisect\\\" to get the full man page.\"),\n     --\tNULL\n     --};\n     -+\t   \"Please use \\\"git help bisect\\\" to get the full man page.\");\n     - \n     - struct add_bisect_ref_data {\n     - \tstruct rev_info *revs;\n     -@@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n     - \n     - int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n     - {\n     --\tenum {\n     --\t\tBISECT_START = 1,\n     --\t\tBISECT_STATE,\n     --\t\tBISECT_TERMS,\n     --\t\tBISECT_SKIP,\n     --\t\tBISECT_NEXT,\n     --\t\tBISECT_RESET,\n     --\t\tBISECT_VISUALIZE,\n     --\t\tBISECT_REPLAY,\n     --\t\tBISECT_LOG,\n     --\t\tBISECT_RUN,\n     --\t} cmdmode = 0;\n     - \tint res = 0;\n     --\tstruct option options[] = {\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-state\", &cmdmode,\n     --\t\t\t N_(\"mark the state of ref (or refs)\"), BISECT_STATE),\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-skip\", &cmdmode,\n     --\t\t\t N_(\"skip some commits for checkout\"), BISECT_SKIP),\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-reset\", &cmdmode,\n     --\t\t\t N_(\"reset the bisection state\"), BISECT_RESET),\n     --\t\tOPT_CMDMODE(0, \"bisect-visualize\", &cmdmode,\n     --\t\t\t N_(\"visualize the bisection\"), BISECT_VISUALIZE),\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-log\", &cmdmode,\n     --\t\t\t N_(\"list the bisection steps so far\"), BISECT_LOG),\n     --\t\tOPT_CMDMODE(0, \"bisect-run\", &cmdmode,\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     -+\tconst char *command = argc > 1 ? argv[1] : \"help\";\n     -+\n     -+\tif (!strcmp(\"-h\", command) || !strcmp(\"help\", command))\n     -+\t\tusage(bisect_long_usage);\n     - \n     --\targc = parse_options(argc, argv, prefix, options,\n     --\t\t\t     bisect_long_usage,\n     --\t\t\t     PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN);\n     -+\targc -= 2;\n     -+\targv += 2;\n     - \n     --\tswitch (cmdmode ? cmdmode : BISECT_STATE) {\n     --\tcase BISECT_START:\n     -+\tif (!strcmp(\"start\", command)) {\n     - \t\tset_terms(&terms, \"bad\", \"good\");\n     - \t\tres = bisect_start(&terms, argv, argc);\n     --\t\tbreak;\n     --\tcase BISECT_TERMS:\n     -+\t} else if (!strcmp(\"terms\", command)) {\n     - \t\tif (argc > 1)\n     --\t\t\tdie(_(\"--bisect-terms requires 0 or 1 argument\"));\n     -+\t\t\tdie(_(\"'terms' requires 0 or 1 argument\"));\n     - \t\tres = bisect_terms(&terms, argc == 1 ? argv[0] : NULL);\n     --\t\tbreak;\n     --\tcase BISECT_SKIP:\n     -+\t} else if (!strcmp(\"skip\", command)) {\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_NEXT:\n     -+\t} else if (!strcmp(\"next\", command)) {\n     - \t\tif (argc)\n     --\t\t\tdie(_(\"--bisect-next requires 0 arguments\"));\n     -+\t\t\tdie(_(\"'next' requires 0 arguments\"));\n     - \t\tget_terms(&terms);\n     - \t\tres = bisect_next(&terms, prefix);\n     --\t\tbreak;\n     --\tcase BISECT_RESET:\n     -+\t} else if (!strcmp(\"reset\", command)) {\n     - \t\tif (argc > 1)\n     --\t\t\tdie(_(\"--bisect-reset requires either no argument or a commit\"));\n     -+\t\t\tdie(_(\"'reset' requires either no argument or a commit\"));\n     - \t\tres = bisect_reset(argc ? argv[0] : NULL);\n     --\t\tbreak;\n     --\tcase BISECT_VISUALIZE:\n     -+\t} else if (one_of(command, \"visualize\", \"view\", NULL)) {\n     - \t\tget_terms(&terms);\n     - \t\tres = bisect_visualize(&terms, argv, argc);\n     --\t\tbreak;\n     --\tcase BISECT_REPLAY:\n     -+\t} else if (!strcmp(\"replay\", command)) {\n     - \t\tif (argc != 1)\n     - \t\t\tdie(_(\"no logfile given\"));\n     - \t\tset_terms(&terms, \"bad\", \"good\");\n     - \t\tres = bisect_replay(&terms, argv[0]);\n     --\t\tbreak;\n     --\tcase BISECT_LOG:\n     -+\t} else if (!strcmp(\"log\", command)) {\n     - \t\tif (argc)\n     --\t\t\tdie(_(\"--bisect-log requires 0 arguments\"));\n     -+\t\t\tdie(_(\"'log' requires 0 arguments\"));\n     - \t\tres = bisect_log();\n     --\t\tbreak;\n     --\tcase BISECT_RUN:\n     -+\t} else if (!strcmp(\"run\", command)) {\n     - \t\tif (!argc)\n     - \t\t\tdie(_(\"bisect run failed: no command provided.\"));\n     - \t\tget_terms(&terms);\n     - \t\tres = bisect_run(&terms, argv, argc);\n     --\t\tbreak;\n     --\tcase BISECT_STATE:\n     --\t\tif (argc &&\n     --\t\t    !file_is_not_empty(git_path_bisect_start()) &&\n     --\t\t    !one_of(argv[0], \"bad\", \"good\", \"new\", \"old\", NULL))\n     -+\t} else {\n     -+\t\tif (!file_is_not_empty(git_path_bisect_start()) &&\n     -+\t\t    !one_of(command, \"bad\", \"good\", \"new\", \"old\", NULL))\n     - \t\t\tusage(bisect_usage);\n     - \t\tset_terms(&terms, \"bad\", \"good\");\n     - \t\tget_terms(&terms);\n     --\t\tif (!cmdmode &&\n     --\t\t    (!argc || check_and_set_terms(&terms, argv[0])))\n     -+\t\tif (check_and_set_terms(&terms, command))\n     - \t\t\tusage(bisect_usage);\n     -+\t\t/* shift the `command` back in */\n     -+\t\targc++;\n     -+\t\targv--;\n     - \t\tres = bisect_state(&terms, argv, argc);\n     --\t\tbreak;\n     --\tdefault:\n     --\t\tBUG(\"unknown subcommand %d\", cmdmode);\n     - \t}\n     -+\n     - \tfree_terms(&terms);\n     - \n     - \t/*\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      \n       ## git-bisect.sh ##\n      @@ git-bisect.sh: Please use \"git help bisect\" to get the full man page.'\n     @@ git-bisect.sh: Please use \"git help bisect\" to get the full man page.'\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 \"$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\n 14:  378d6d22737 ! 14:  a8f08f5e0cb Turn `git bisect` into a full built-in\n     @@ builtin.h: int cmd_am(int argc, const char **argv, const char *prefix);\n       int cmd_bugreport(int argc, const char **argv, const char *prefix);\n      \n       ## builtin/bisect--helper.c => builtin/bisect.c ##\n     -@@ builtin/bisect.c: static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n     +@@ builtin/bisect.c: static int cmd_bisect_run(int argc, const char **argv, const char *prefix)\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     - \tstruct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };\n     + \tstruct strvec args = STRVEC_INIT;\n     + \tparse_opt_subcommand_fn *fn = NULL;\n      \n       ## git-bisect.sh (deleted) ##\n      @@\n     @@ git-bisect.sh (deleted)\n      \n       ## git.c ##\n      @@ git.c: static struct cmd_struct commands[] = {\n     - \t{ \"annotate\", cmd_annotate, RUN_SETUP | NO_PARSEOPT },\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 15:  33566b86d77 ! 15:  a96489310d3 bisect: remove Cogito-related code\n     @@ builtin/bisect.c: static GIT_PATH_FUNC(git_path_bisect_expected_rev, \"BISECT_EXP\n       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     -@@ builtin/bisect.c: static enum bisect_error bisect_start(struct bisect_terms *terms, const char **a\n     +@@ builtin/bisect.c: static int cmd_bisect_start(int argc, const char **argv, const char *prefix)\n       \t\t\tstrbuf_addstr(&start_head, oid_to_hex(&head_oid));\n       \t\t} else if (!get_oid(head, &head_oid) &&\n       \t\t\t   skip_prefix(head, \"refs/heads/\", &head)) {\n 16:  334664f23a8 = 16:  bfa7aa19f03 bisect: no longer try to clean up left-over `.git/head-name` files\n\n-- \ngitgitgadget\n"},{"id":"462025","messageId":"05262b6a7d1b20a0d2f2ca2090be284ffb8c679c.1661604264.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v5.git.1661604264.gitgitgadget@gmail.com","subject":"[PATCH v5 01/16] bisect--helper: retire the --no-log option","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-08-27T12:44:09Z","receivedAt":"2022-08-27T12:44:41Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nTurns out we actually never used it, anyway...\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/bisect--helper.c | 4 +---\n 1 file changed, 1 insertion(+), 3 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 7097750fc6b..2cc69e1eee5 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1292,7 +1292,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@@ -1316,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-- \ngitgitgadget\n\n"},{"id":"462027","messageId":"1a1649d9d0d5739f76db82fdafae7e88374bc8a6.1661604264.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v5.git.1661604264.gitgitgadget@gmail.com","subject":"[PATCH v5 03/16] bisect--helper: really retire `--bisect-autostart`","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-08-27T12:44:11Z","receivedAt":"2022-08-27T12:44:46Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\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>\n---\n builtin/bisect--helper.c | 1 -\n 1 file changed, 1 deletion(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex bdf7ce18d7a..aa94c25ec73 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1282,7 +1282,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\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-- \ngitgitgadget\n\n"},{"id":"462028","messageId":"1e43148864a52ffe05b5075bd0e449c0e056f078.1661604264.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v5.git.1661604264.gitgitgadget@gmail.com","subject":"[PATCH v5 02/16] bisect--helper: really retire --bisect-next-check","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-08-27T12:44:10Z","receivedAt":"2022-08-27T12:44:46Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?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\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/bisect--helper.c | 3 ---\n 1 file changed, 3 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 2cc69e1eee5..bdf7ce18d7a 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1280,7 +1280,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@@ -1296,8 +1295,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-- \ngitgitgadget\n\n"},{"id":"462029","messageId":"9ab30552c6ae6a5d0a85d7a7bbdd10af4a4cf7ec.1661604264.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v5.git.1661604264.gitgitgadget@gmail.com","subject":"[PATCH v5 04/16] bisect--helper: simplify exit code computation","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-08-27T12:44:12Z","receivedAt":"2022-08-27T12:44:47Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nWe _already_ have a function to determine whether a given `enum\nbisect_error` value is non-zero but still _actually_ indicates success.\n\nLet's use it instead of duplicating the logic.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/bisect--helper.c | 9 +--------\n 1 file changed, 1 insertion(+), 8 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex aa94c25ec73..2f9c7f54f3f 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1380,12 +1380,5 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t}\n \tfree_terms(&terms);\n \n-\t/*\n-\t * Handle early success\n-\t * From check_merge_bases > check_good_are_ancestors_of_bad > bisect_next_all\n-\t */\n-\tif ((res == BISECT_INTERNAL_SUCCESS_MERGE_BASE) || (res == BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND))\n-\t\tres = BISECT_OK;\n-\n-\treturn -res;\n+\treturn is_bisect_success(res) ? 0 : -res;\n }\n-- \ngitgitgadget\n\n"},{"id":"462031","messageId":"92b3b116ef8f879192d9deb94d68b73e29d5dcd6.1661604264.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v5.git.1661604264.gitgitgadget@gmail.com","subject":"[PATCH v5 05/16] bisect--helper: make `terms` an explicit singleton","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-08-27T12:44:13Z","receivedAt":"2022-08-27T12:44:48Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nWe tried very hard to keep code in `builtin/bisect--helper.c` in as\nlibifyable a state as possible.\n\nHowever, we are about to migrate this built-in to the `OPT_SUBCOMMAND()`\nAPI, which does not allow for passing any context (e.g. via a `void\n*data` parameters as they are used in the config API).\n\nTherefore, we _have_ to move the `terms` variable outside of\n`cmd_bisect__helper()` and explicitly make it a singleton (as it\ncurrently is, anyway).\n\nLet's just make things consistent and stop passing around pointers to\nthat singleton; Use it directly instead.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/bisect--helper.c | 262 +++++++++++++++++++--------------------\n 1 file changed, 128 insertions(+), 134 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 2f9c7f54f3f..7f4e8e707c1 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -40,30 +40,30 @@ struct add_bisect_ref_data {\n \tunsigned int object_flags;\n };\n \n-struct bisect_terms {\n+static struct bisect_terms {\n \tchar *term_good;\n \tchar *term_bad;\n-};\n+} terms;\n \n-static void free_terms(struct bisect_terms *terms)\n+static void free_terms(void)\n {\n-\tFREE_AND_NULL(terms->term_good);\n-\tFREE_AND_NULL(terms->term_bad);\n+\tFREE_AND_NULL(terms.term_good);\n+\tFREE_AND_NULL(terms.term_bad);\n }\n \n-static void set_terms(struct bisect_terms *terms, const char *bad,\n+static void set_terms(const char *bad,\n \t\t      const char *good)\n {\n-\tfree((void *)terms->term_good);\n-\tterms->term_good = xstrdup(good);\n-\tfree((void *)terms->term_bad);\n-\tterms->term_bad = xstrdup(bad);\n+\tfree((void *)terms.term_good);\n+\tterms.term_good = xstrdup(good);\n+\tfree((void *)terms.term_bad);\n+\tterms.term_bad = xstrdup(bad);\n }\n \n static const char vocab_bad[] = \"bad|new\";\n static const char vocab_good[] = \"good|old\";\n \n-static int bisect_autostart(struct bisect_terms *terms);\n+static int bisect_autostart(void);\n \n /*\n  * Check whether the string `term` belongs to the set of strings\n@@ -254,8 +254,7 @@ static void log_commit(FILE *fp, char *fmt, const char *state,\n \tfree(label);\n }\n \n-static int bisect_write(const char *state, const char *rev,\n-\t\t\tconst struct bisect_terms *terms, int nolog)\n+static int bisect_write(const char *state, const char *rev, int nolog)\n {\n \tstruct strbuf tag = STRBUF_INIT;\n \tstruct object_id oid;\n@@ -263,9 +262,9 @@ static int bisect_write(const char *state, const char *rev,\n \tFILE *fp = NULL;\n \tint res = 0;\n \n-\tif (!strcmp(state, terms->term_bad)) {\n+\tif (!strcmp(state, terms.term_bad)) {\n \t\tstrbuf_addf(&tag, \"refs/bisect/%s\", state);\n-\t} else if (one_of(state, terms->term_good, \"skip\", NULL)) {\n+\t} else if (one_of(state, terms.term_good, \"skip\", NULL)) {\n \t\tstrbuf_addf(&tag, \"refs/bisect/%s-%s\", state, rev);\n \t} else {\n \t\tres = error(_(\"Bad bisect_write argument: %s\"), state);\n@@ -302,27 +301,27 @@ finish:\n \treturn res;\n }\n \n-static int check_and_set_terms(struct bisect_terms *terms, const char *cmd)\n+static int check_and_set_terms(const char *cmd)\n {\n \tint has_term_file = !is_empty_or_missing_file(git_path_bisect_terms());\n \n \tif (one_of(cmd, \"skip\", \"start\", \"terms\", NULL))\n \t\treturn 0;\n \n-\tif (has_term_file && strcmp(cmd, terms->term_bad) &&\n-\t    strcmp(cmd, terms->term_good))\n+\tif (has_term_file && strcmp(cmd, terms.term_bad) &&\n+\t    strcmp(cmd, terms.term_good))\n \t\treturn error(_(\"Invalid command: you're currently in a \"\n-\t\t\t\t\"%s/%s bisect\"), terms->term_bad,\n-\t\t\t\tterms->term_good);\n+\t\t\t\t\"%s/%s bisect\"), terms.term_bad,\n+\t\t\t\tterms.term_good);\n \n \tif (!has_term_file) {\n \t\tif (one_of(cmd, \"bad\", \"good\", NULL)) {\n-\t\t\tset_terms(terms, \"bad\", \"good\");\n-\t\t\treturn write_terms(terms->term_bad, terms->term_good);\n+\t\t\tset_terms(\"bad\", \"good\");\n+\t\t\treturn write_terms(terms.term_bad, terms.term_good);\n \t\t}\n \t\tif (one_of(cmd, \"new\", \"old\", NULL)) {\n-\t\t\tset_terms(terms, \"new\", \"old\");\n-\t\t\treturn write_terms(terms->term_bad, terms->term_good);\n+\t\t\tset_terms(\"new\", \"old\");\n+\t\t\treturn write_terms(terms.term_bad, terms.term_good);\n \t\t}\n \t}\n \n@@ -346,8 +345,7 @@ static const char need_bisect_start_warning[] =\n \t   \"You then need to give me at least one %s and %s revision.\\n\"\n \t   \"You can use \\\"git bisect %s\\\" and \\\"git bisect %s\\\" for that.\");\n \n-static int decide_next(const struct bisect_terms *terms,\n-\t\t       const char *current_term, int missing_good,\n+static int decide_next(const char *current_term, int missing_good,\n \t\t       int missing_bad)\n {\n \tif (!missing_good && !missing_bad)\n@@ -356,13 +354,13 @@ static int decide_next(const struct bisect_terms *terms,\n \t\treturn -1;\n \n \tif (missing_good && !missing_bad &&\n-\t    !strcmp(current_term, terms->term_good)) {\n+\t    !strcmp(current_term, terms.term_good)) {\n \t\tchar *yesno;\n \t\t/*\n \t\t * have bad (or new) but not good (or old). We could bisect\n \t\t * although this is less optimum.\n \t\t */\n-\t\twarning(_(\"bisecting only with a %s commit\"), terms->term_bad);\n+\t\twarning(_(\"bisecting only with a %s commit\"), terms.term_bad);\n \t\tif (!isatty(0))\n \t\t\treturn 0;\n \t\t/*\n@@ -384,11 +382,10 @@ static int decide_next(const struct bisect_terms *terms,\n \t\t\t     vocab_good, vocab_bad, vocab_good, vocab_bad);\n }\n \n-static void bisect_status(struct bisect_state *state,\n-\t\t\t  const struct bisect_terms *terms)\n+static void bisect_status(struct bisect_state *state)\n {\n-\tchar *bad_ref = xstrfmt(\"refs/bisect/%s\", terms->term_bad);\n-\tchar *good_glob = xstrfmt(\"%s-*\", terms->term_good);\n+\tchar *bad_ref = xstrfmt(\"refs/bisect/%s\", terms.term_bad);\n+\tchar *good_glob = xstrfmt(\"%s-*\", terms.term_good);\n \n \tif (ref_exists(bad_ref))\n \t\tstate->nr_bad = 1;\n@@ -416,11 +413,11 @@ static void bisect_log_printf(const char *fmt, ...)\n \tstrbuf_release(&buf);\n }\n \n-static void bisect_print_status(const struct bisect_terms *terms)\n+static void bisect_print_status(void)\n {\n \tstruct bisect_state state = { 0 };\n \n-\tbisect_status(&state, terms);\n+\tbisect_status(&state);\n \n \t/* If we had both, we'd already be started, and shouldn't get here. */\n \tif (state.nr_good && state.nr_bad)\n@@ -436,15 +433,14 @@ static void bisect_print_status(const struct bisect_terms *terms)\n \t\tbisect_log_printf(_(\"status: waiting for good commit(s), bad commit known\\n\"));\n }\n \n-static int bisect_next_check(const struct bisect_terms *terms,\n-\t\t\t     const char *current_term)\n+static int bisect_next_check(const char *current_term)\n {\n \tstruct bisect_state state = { 0 };\n-\tbisect_status(&state, terms);\n-\treturn decide_next(terms, current_term, !state.nr_good, !state.nr_bad);\n+\tbisect_status(&state);\n+\treturn decide_next(current_term, !state.nr_good, !state.nr_bad);\n }\n \n-static int get_terms(struct bisect_terms *terms)\n+static int get_terms(void)\n {\n \tstruct strbuf str = STRBUF_INIT;\n \tFILE *fp = NULL;\n@@ -456,11 +452,11 @@ static int get_terms(struct bisect_terms *terms)\n \t\tgoto finish;\n \t}\n \n-\tfree_terms(terms);\n+\tfree_terms();\n \tstrbuf_getline_lf(&str, fp);\n-\tterms->term_bad = strbuf_detach(&str, NULL);\n+\tterms.term_bad = strbuf_detach(&str, NULL);\n \tstrbuf_getline_lf(&str, fp);\n-\tterms->term_good = strbuf_detach(&str, NULL);\n+\tterms.term_good = strbuf_detach(&str, NULL);\n \n finish:\n \tif (fp)\n@@ -469,21 +465,21 @@ finish:\n \treturn res;\n }\n \n-static int bisect_terms(struct bisect_terms *terms, const char *option)\n+static int bisect_terms(const char *option)\n {\n-\tif (get_terms(terms))\n+\tif (get_terms())\n \t\treturn error(_(\"no terms defined\"));\n \n \tif (!option) {\n \t\tprintf(_(\"Your current terms are %s for the old state\\n\"\n \t\t\t \"and %s for the new state.\\n\"),\n-\t\t       terms->term_good, terms->term_bad);\n+\t\t       terms.term_good, terms.term_bad);\n \t\treturn 0;\n \t}\n \tif (one_of(option, \"--term-good\", \"--term-old\", NULL))\n-\t\tprintf(\"%s\\n\", terms->term_good);\n+\t\tprintf(\"%s\\n\", terms.term_good);\n \telse if (one_of(option, \"--term-bad\", \"--term-new\", NULL))\n-\t\tprintf(\"%s\\n\", terms->term_bad);\n+\t\tprintf(\"%s\\n\", terms.term_bad);\n \telse\n \t\treturn error(_(\"invalid argument %s for 'git bisect terms'.\\n\"\n \t\t\t       \"Supported options are: \"\n@@ -527,18 +523,18 @@ static int add_bisect_ref(const char *refname, const struct object_id *oid,\n \treturn 0;\n }\n \n-static int prepare_revs(struct bisect_terms *terms, struct rev_info *revs)\n+static int prepare_revs(struct rev_info *revs)\n {\n \tint res = 0;\n \tstruct add_bisect_ref_data cb = { revs };\n-\tchar *good = xstrfmt(\"%s-*\", terms->term_good);\n+\tchar *good = xstrfmt(\"%s-*\", terms.term_good);\n \n \t/*\n-\t * We cannot use terms->term_bad directly in\n+\t * We cannot use terms.term_bad directly in\n \t * for_each_glob_ref_in() and we have to append a '*' to it,\n \t * otherwise for_each_glob_ref_in() will append '/' and '*'.\n \t */\n-\tchar *bad = xstrfmt(\"%s*\", terms->term_bad);\n+\tchar *bad = xstrfmt(\"%s*\", terms.term_bad);\n \n \t/*\n \t * It is important to reset the flags used by revision walks\n@@ -559,7 +555,7 @@ static int prepare_revs(struct bisect_terms *terms, struct rev_info *revs)\n \treturn res;\n }\n \n-static int bisect_skipped_commits(struct bisect_terms *terms)\n+static int bisect_skipped_commits(void)\n {\n \tint res;\n \tFILE *fp = NULL;\n@@ -568,7 +564,7 @@ static int bisect_skipped_commits(struct bisect_terms *terms)\n \tstruct pretty_print_context pp = {0};\n \tstruct strbuf commit_name = STRBUF_INIT;\n \n-\tres = prepare_revs(terms, &revs);\n+\tres = prepare_revs(&revs);\n \tif (res)\n \t\treturn res;\n \n@@ -585,7 +581,7 @@ static int bisect_skipped_commits(struct bisect_terms *terms)\n \t\tformat_commit_message(commit, \"%s\",\n \t\t\t\t      &commit_name, &pp);\n \t\tfprintf(fp, \"# possible first %s commit: [%s] %s\\n\",\n-\t\t\tterms->term_bad, oid_to_hex(&commit->object.oid),\n+\t\t\tterms.term_bad, oid_to_hex(&commit->object.oid),\n \t\t\tcommit_name.buf);\n \t}\n \n@@ -601,13 +597,13 @@ static int bisect_skipped_commits(struct bisect_terms *terms)\n \treturn 0;\n }\n \n-static int bisect_successful(struct bisect_terms *terms)\n+static int bisect_successful(void)\n {\n \tstruct object_id oid;\n \tstruct commit *commit;\n \tstruct pretty_print_context pp = {0};\n \tstruct strbuf commit_name = STRBUF_INIT;\n-\tchar *bad_ref = xstrfmt(\"refs/bisect/%s\",terms->term_bad);\n+\tchar *bad_ref = xstrfmt(\"refs/bisect/%s\",terms.term_bad);\n \tint res;\n \n \tread_ref(bad_ref, &oid);\n@@ -615,7 +611,7 @@ static int bisect_successful(struct bisect_terms *terms)\n \tformat_commit_message(commit, \"%s\", &commit_name, &pp);\n \n \tres = append_to_file(git_path_bisect_log(), \"# first %s commit: [%s] %s\\n\",\n-\t\t\t    terms->term_bad, oid_to_hex(&commit->object.oid),\n+\t\t\t    terms.term_bad, oid_to_hex(&commit->object.oid),\n \t\t\t    commit_name.buf);\n \n \tstrbuf_release(&commit_name);\n@@ -623,40 +619,40 @@ 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 enum bisect_error bisect_next(const char *prefix)\n {\n \tenum bisect_error res;\n \n-\tif (bisect_autostart(terms))\n+\tif (bisect_autostart())\n \t\treturn BISECT_FAILED;\n \n-\tif (bisect_next_check(terms, terms->term_good))\n+\tif (bisect_next_check(terms.term_good))\n \t\treturn BISECT_FAILED;\n \n \t/* Perform all bisection computation */\n \tres = bisect_next_all(the_repository, prefix);\n \n \tif (res == BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND) {\n-\t\tres = bisect_successful(terms);\n+\t\tres = bisect_successful();\n \t\treturn res ? res : BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND;\n \t} else if (res == BISECT_ONLY_SKIPPED_LEFT) {\n-\t\tres = bisect_skipped_commits(terms);\n+\t\tres = bisect_skipped_commits();\n \t\treturn res ? res : BISECT_ONLY_SKIPPED_LEFT;\n \t}\n \treturn res;\n }\n \n-static enum bisect_error bisect_auto_next(struct bisect_terms *terms, const char *prefix)\n+static enum bisect_error bisect_auto_next(const char *prefix)\n {\n-\tif (bisect_next_check(terms, NULL)) {\n-\t\tbisect_print_status(terms);\n+\tif (bisect_next_check(NULL)) {\n+\t\tbisect_print_status();\n \t\treturn BISECT_OK;\n \t}\n \n-\treturn bisect_next(terms, prefix);\n+\treturn bisect_next(prefix);\n }\n \n-static enum bisect_error bisect_start(struct bisect_terms *terms, const char **argv, int argc)\n+static enum bisect_error bisect_start(const char **argv, int argc)\n {\n \tint no_checkout = 0;\n \tint first_parent_only = 0;\n@@ -698,26 +694,26 @@ static enum bisect_error bisect_start(struct bisect_terms *terms, const char **a\n \t\t\tif (argc <= i)\n \t\t\t\treturn error(_(\"'' is not a valid term\"));\n \t\t\tmust_write_terms = 1;\n-\t\t\tfree((void *) terms->term_good);\n-\t\t\tterms->term_good = xstrdup(argv[i]);\n+\t\t\tfree((void *) terms.term_good);\n+\t\t\tterms.term_good = xstrdup(argv[i]);\n \t\t} else if (skip_prefix(arg, \"--term-good=\", &arg) ||\n \t\t\t   skip_prefix(arg, \"--term-old=\", &arg)) {\n \t\t\tmust_write_terms = 1;\n-\t\t\tfree((void *) terms->term_good);\n-\t\t\tterms->term_good = xstrdup(arg);\n+\t\t\tfree((void *) terms.term_good);\n+\t\t\tterms.term_good = xstrdup(arg);\n \t\t} else if (!strcmp(arg, \"--term-bad\") ||\n \t\t\t !strcmp(arg, \"--term-new\")) {\n \t\t\ti++;\n \t\t\tif (argc <= i)\n \t\t\t\treturn error(_(\"'' is not a valid term\"));\n \t\t\tmust_write_terms = 1;\n-\t\t\tfree((void *) terms->term_bad);\n-\t\t\tterms->term_bad = xstrdup(argv[i]);\n+\t\t\tfree((void *) terms.term_bad);\n+\t\t\tterms.term_bad = xstrdup(argv[i]);\n \t\t} else if (skip_prefix(arg, \"--term-bad=\", &arg) ||\n \t\t\t   skip_prefix(arg, \"--term-new=\", &arg)) {\n \t\t\tmust_write_terms = 1;\n-\t\t\tfree((void *) terms->term_bad);\n-\t\t\tterms->term_bad = xstrdup(arg);\n+\t\t\tfree((void *) terms.term_bad);\n+\t\t\tterms.term_bad = xstrdup(arg);\n \t\t} else if (starts_with(arg, \"--\")) {\n \t\t\treturn error(_(\"unrecognized option: '%s'\"), arg);\n \t\t} else if (!get_oidf(&oid, \"%s^{commit}\", arg)) {\n@@ -741,10 +737,10 @@ static enum bisect_error bisect_start(struct bisect_terms *terms, const char **a\n \t\tmust_write_terms = 1;\n \tfor (i = 0; i < revs.nr; i++) {\n \t\tif (bad_seen) {\n-\t\t\tstring_list_append(&states, terms->term_good);\n+\t\t\tstring_list_append(&states, terms.term_good);\n \t\t} else {\n \t\t\tbad_seen = 1;\n-\t\t\tstring_list_append(&states, terms->term_bad);\n+\t\t\tstring_list_append(&states, terms.term_bad);\n \t\t}\n \t}\n \n@@ -829,13 +825,13 @@ static enum bisect_error bisect_start(struct bisect_terms *terms, const char **a\n \n \tfor (i = 0; i < states.nr; i++)\n \t\tif (bisect_write(states.items[i].string,\n-\t\t\t\t revs.items[i].string, terms, 1)) {\n+\t\t\t\t revs.items[i].string, 1)) {\n \t\t\tres = BISECT_FAILED;\n \t\t\tgoto finish;\n \t\t}\n \n-\tif (must_write_terms && write_terms(terms->term_bad,\n-\t\t\t\t\t    terms->term_good)) {\n+\tif (must_write_terms && write_terms(terms.term_bad,\n+\t\t\t\t\t    terms.term_good)) {\n \t\tres = BISECT_FAILED;\n \t\tgoto finish;\n \t}\n@@ -852,7 +848,7 @@ finish:\n \tif (res)\n \t\treturn res;\n \n-\tres = bisect_auto_next(terms, NULL);\n+\tres = bisect_auto_next(NULL);\n \tif (!is_bisect_success(res))\n \t\tbisect_clean_state();\n \treturn res;\n@@ -863,7 +859,7 @@ static inline int file_is_not_empty(const char *path)\n \treturn !is_empty_or_missing_file(path);\n }\n \n-static int bisect_autostart(struct bisect_terms *terms)\n+static int bisect_autostart(void)\n {\n \tint res;\n \tconst char *yesno;\n@@ -885,12 +881,12 @@ 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(empty_strvec, 0);\n \n \treturn res;\n }\n \n-static enum bisect_error bisect_state(struct bisect_terms *terms, const char **argv,\n+static enum bisect_error bisect_state(const char **argv,\n \t\t\t\t      int argc)\n {\n \tconst char *state;\n@@ -902,18 +898,18 @@ static enum bisect_error bisect_state(struct bisect_terms *terms, const char **a\n \tif (!argc)\n \t\treturn error(_(\"Please call `--bisect-state` with at least one argument\"));\n \n-\tif (bisect_autostart(terms))\n+\tif (bisect_autostart())\n \t\treturn BISECT_FAILED;\n \n \tstate = argv[0];\n-\tif (check_and_set_terms(terms, state) ||\n-\t    !one_of(state, terms->term_good, terms->term_bad, \"skip\", NULL))\n+\tif (check_and_set_terms(state) ||\n+\t    !one_of(state, terms.term_good, terms.term_bad, \"skip\", NULL))\n \t\treturn BISECT_FAILED;\n \n \targv++;\n \targc--;\n-\tif (argc > 1 && !strcmp(state, terms->term_bad))\n-\t\treturn error(_(\"'git bisect %s' can take only one argument.\"), terms->term_bad);\n+\tif (argc > 1 && !strcmp(state, terms.term_bad))\n+\t\treturn error(_(\"'git bisect %s' can take only one argument.\"), terms.term_bad);\n \n \tif (argc == 0) {\n \t\tconst char *head = \"BISECT_HEAD\";\n@@ -956,7 +952,7 @@ static enum bisect_error bisect_state(struct bisect_terms *terms, const char **a\n \tstrbuf_release(&buf);\n \n \tfor (i = 0; i < revs.nr; i++) {\n-\t\tif (bisect_write(state, oid_to_hex(&revs.oid[i]), terms, 0)) {\n+\t\tif (bisect_write(state, oid_to_hex(&revs.oid[i]), 0)) {\n \t\t\toid_array_clear(&revs);\n \t\t\treturn BISECT_FAILED;\n \t\t}\n@@ -968,7 +964,7 @@ static enum bisect_error bisect_state(struct bisect_terms *terms, const char **a\n \t}\n \n \toid_array_clear(&revs);\n-\treturn bisect_auto_next(terms, NULL);\n+\treturn bisect_auto_next(NULL);\n }\n \n static enum bisect_error bisect_log(void)\n@@ -988,7 +984,7 @@ static enum bisect_error bisect_log(void)\n \treturn status ? BISECT_FAILED : BISECT_OK;\n }\n \n-static int process_replay_line(struct bisect_terms *terms, struct strbuf *line)\n+static int process_replay_line(struct strbuf *line)\n {\n \tconst char *p = line->buf + strspn(line->buf, \" \\t\");\n \tchar *word_end, *rev;\n@@ -1002,28 +998,28 @@ static int process_replay_line(struct bisect_terms *terms, struct strbuf *line)\n \trev = word_end + strspn(word_end, \" \\t\");\n \t*word_end = '\\0'; /* NUL-terminate the word */\n \n-\tget_terms(terms);\n-\tif (check_and_set_terms(terms, p))\n+\tget_terms();\n+\tif (check_and_set_terms(p))\n \t\treturn -1;\n \n \tif (!strcmp(p, \"start\")) {\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(argv.v, argv.nr);\n \t\tstrvec_clear(&argv);\n \t\treturn res;\n \t}\n \n-\tif (one_of(p, terms->term_good,\n-\t   terms->term_bad, \"skip\", NULL))\n-\t\treturn bisect_write(p, rev, terms, 0);\n+\tif (one_of(p, terms.term_good,\n+\t   terms.term_bad, \"skip\", NULL))\n+\t\treturn bisect_write(p, rev, 0);\n \n \tif (!strcmp(p, \"terms\")) {\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(argv.nr == 1 ? argv.v[0] : NULL);\n \t\tstrvec_clear(&argv);\n \t\treturn res;\n \t}\n@@ -1032,7 +1028,7 @@ 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 enum bisect_error bisect_replay(const char *filename)\n {\n \tFILE *fp = NULL;\n \tenum bisect_error res = BISECT_OK;\n@@ -1049,7 +1045,7 @@ static enum bisect_error bisect_replay(struct bisect_terms *terms, const char *f\n \t\treturn BISECT_FAILED;\n \n \twhile ((strbuf_getline(&line, fp) != EOF) && !res)\n-\t\tres = process_replay_line(terms, &line);\n+\t\tres = process_replay_line(&line);\n \n \tstrbuf_release(&line);\n \tfclose(fp);\n@@ -1057,10 +1053,10 @@ static enum bisect_error bisect_replay(struct bisect_terms *terms, const char *f\n \tif (res)\n \t\treturn BISECT_FAILED;\n \n-\treturn bisect_auto_next(terms, NULL);\n+\treturn bisect_auto_next(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(const char **argv, int argc)\n {\n \tint i;\n \tenum bisect_error res;\n@@ -1090,19 +1086,19 @@ 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(argv_state.v, argv_state.nr);\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(const char **argv, int argc)\n {\n \tstruct strvec args = STRVEC_INIT;\n \tint flags = RUN_COMMAND_NO_STDIN, res = 0;\n \tstruct strbuf sb = STRBUF_INIT;\n \n-\tif (bisect_next_check(terms, NULL) != 0)\n+\tif (bisect_next_check(NULL) != 0)\n \t\treturn BISECT_FAILED;\n \n \tif (!argc) {\n@@ -1141,14 +1137,13 @@ static int get_first_good(const char *refname, const struct object_id *oid,\n \treturn 1;\n }\n \n-static int verify_good(const struct bisect_terms *terms,\n-\t\t       const char **quoted_argv)\n+static int verify_good(const char **quoted_argv)\n {\n \tint rc;\n \tenum bisect_error res;\n \tstruct object_id good_rev;\n \tstruct object_id current_rev;\n-\tchar *good_glob = xstrfmt(\"%s-*\", terms->term_good);\n+\tchar *good_glob = xstrfmt(\"%s-*\", terms.term_good);\n \tint no_checkout = ref_exists(\"BISECT_HEAD\");\n \n \tfor_each_glob_ref_in(get_first_good, good_glob, \"refs/bisect/\",\n@@ -1172,7 +1167,7 @@ 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(const char **argv, int argc)\n {\n \tint res = BISECT_OK;\n \tstruct strbuf command = STRBUF_INIT;\n@@ -1181,7 +1176,7 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n \tint temporary_stdout_fd, saved_stdout;\n \tint is_first_run = 1;\n \n-\tif (bisect_next_check(terms, NULL))\n+\tif (bisect_next_check(NULL))\n \t\treturn BISECT_FAILED;\n \n \tif (argc)\n@@ -1205,7 +1200,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, run_args.v);\n+\t\t\tint rc = verify_good(run_args.v);\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@@ -1230,9 +1225,9 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n \t\tif (res == 125)\n \t\t\tnew_state = \"skip\";\n \t\telse if (!res)\n-\t\t\tnew_state = terms->term_good;\n+\t\t\tnew_state = terms.term_good;\n \t\telse\n-\t\t\tnew_state = terms->term_bad;\n+\t\t\tnew_state = terms.term_bad;\n \n \t\ttemporary_stdout_fd = open(git_path_bisect_run(), O_CREAT | O_WRONLY | O_TRUNC, 0666);\n \n@@ -1245,7 +1240,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(&new_state, 1);\n \n \t\tfflush(stdout);\n \t\tdup2(saved_stdout, 1);\n@@ -1314,7 +1309,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@@ -1332,22 +1326,22 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\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(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\tset_terms(\"bad\", \"good\");\n+\t\tres = bisect_start(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\tget_terms();\n+\t\tres = bisect_next(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\tset_terms(\"bad\", \"good\");\n+\t\tget_terms();\n+\t\tres = bisect_state(argv, argc);\n \t\tbreak;\n \tcase BISECT_LOG:\n \t\tif (argc)\n@@ -1357,28 +1351,28 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\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\tset_terms(\"bad\", \"good\");\n+\t\tres = bisect_replay(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\tset_terms(\"bad\", \"good\");\n+\t\tget_terms();\n+\t\tres = bisect_skip(argv, argc);\n \t\tbreak;\n \tcase BISECT_VISUALIZE:\n-\t\tget_terms(&terms);\n-\t\tres = bisect_visualize(&terms, argv, argc);\n+\t\tget_terms();\n+\t\tres = bisect_visualize(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\tget_terms();\n+\t\tres = bisect_run(argv, argc);\n \t\tbreak;\n \tdefault:\n \t\tBUG(\"unknown subcommand %d\", cmdmode);\n \t}\n-\tfree_terms(&terms);\n+\tfree_terms();\n \n \treturn is_bisect_success(res) ? 0 : -res;\n }\n-- \ngitgitgadget\n\n"},{"id":"462030","messageId":"c9dc0281e38bf9bc0bce72de172b5dbadbcbb1f5.1661604264.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v5.git.1661604264.gitgitgadget@gmail.com","subject":"[PATCH v5 06/16] bisect--helper: make the order consistently `argc, argv`","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-08-27T12:44:14Z","receivedAt":"2022-08-27T12:44:49Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nIn C, the natural order is for `argc` to come before `argv` by virtue of\nthe `main()` function declaring the parameters in precisely that order.\n\nIt is confusing & distracting, then, when readers familiar with the C\nlanguage read code where that order is switched around.\n\nLet's just change the order and avoid that type of developer friction.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/bisect--helper.c | 29 ++++++++++++++---------------\n 1 file changed, 14 insertions(+), 15 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 7f4e8e707c1..0d7cc20f9c9 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -652,7 +652,7 @@ static enum bisect_error bisect_auto_next(const char *prefix)\n \treturn bisect_next(prefix);\n }\n \n-static enum bisect_error bisect_start(const char **argv, int argc)\n+static enum bisect_error bisect_start(int argc, const char **argv)\n {\n \tint no_checkout = 0;\n \tint first_parent_only = 0;\n@@ -881,13 +881,12 @@ static int bisect_autostart(void)\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(empty_strvec, 0);\n+\t\t-1 : bisect_start(0, empty_strvec);\n \n \treturn res;\n }\n \n-static enum bisect_error bisect_state(const char **argv,\n-\t\t\t\t      int argc)\n+static enum bisect_error bisect_state(int argc, const char **argv)\n {\n \tconst char *state;\n \tint i, verify_expected = 1;\n@@ -1006,7 +1005,7 @@ static int process_replay_line(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(argv.v, argv.nr);\n+\t\tres = bisect_start(argv.nr, argv.v);\n \t\tstrvec_clear(&argv);\n \t\treturn res;\n \t}\n@@ -1056,7 +1055,7 @@ static enum bisect_error bisect_replay(const char *filename)\n \treturn bisect_auto_next(NULL);\n }\n \n-static enum bisect_error bisect_skip(const char **argv, int argc)\n+static enum bisect_error bisect_skip(int argc, const char **argv)\n {\n \tint i;\n \tenum bisect_error res;\n@@ -1086,13 +1085,13 @@ static enum bisect_error bisect_skip(const char **argv, int argc)\n \t\t\tstrvec_push(&argv_state, argv[i]);\n \t\t}\n \t}\n-\tres = bisect_state(argv_state.v, argv_state.nr);\n+\tres = bisect_state(argv_state.nr, argv_state.v);\n \n \tstrvec_clear(&argv_state);\n \treturn res;\n }\n \n-static int bisect_visualize(const char **argv, int argc)\n+static int bisect_visualize(int argc, const char **argv)\n {\n \tstruct strvec args = STRVEC_INIT;\n \tint flags = RUN_COMMAND_NO_STDIN, res = 0;\n@@ -1167,7 +1166,7 @@ static int verify_good(const char **quoted_argv)\n \treturn rc;\n }\n \n-static int bisect_run(const char **argv, int argc)\n+static int bisect_run(int argc, const char **argv)\n {\n \tint res = BISECT_OK;\n \tstruct strbuf command = STRBUF_INIT;\n@@ -1240,7 +1239,7 @@ static int bisect_run(const char **argv, int argc)\n \t\tsaved_stdout = dup(1);\n \t\tdup2(temporary_stdout_fd, 1);\n \n-\t\tres = bisect_state(&new_state, 1);\n+\t\tres = bisect_state(1, &new_state);\n \n \t\tfflush(stdout);\n \t\tdup2(saved_stdout, 1);\n@@ -1330,7 +1329,7 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\tbreak;\n \tcase BISECT_START:\n \t\tset_terms(\"bad\", \"good\");\n-\t\tres = bisect_start(argv, argc);\n+\t\tres = bisect_start(argc, argv);\n \t\tbreak;\n \tcase BISECT_NEXT:\n \t\tif (argc)\n@@ -1341,7 +1340,7 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \tcase BISECT_STATE:\n \t\tset_terms(\"bad\", \"good\");\n \t\tget_terms();\n-\t\tres = bisect_state(argv, argc);\n+\t\tres = bisect_state(argc, argv);\n \t\tbreak;\n \tcase BISECT_LOG:\n \t\tif (argc)\n@@ -1357,17 +1356,17 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \tcase BISECT_SKIP:\n \t\tset_terms(\"bad\", \"good\");\n \t\tget_terms();\n-\t\tres = bisect_skip(argv, argc);\n+\t\tres = bisect_skip(argc, argv);\n \t\tbreak;\n \tcase BISECT_VISUALIZE:\n \t\tget_terms();\n-\t\tres = bisect_visualize(argv, argc);\n+\t\tres = bisect_visualize(argc, argv);\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();\n-\t\tres = bisect_run(argv, argc);\n+\t\tres = bisect_run(argc, argv);\n \t\tbreak;\n \tdefault:\n \t\tBUG(\"unknown subcommand %d\", cmdmode);\n-- \ngitgitgadget\n\n"},{"id":"462032","messageId":"5b7a3d58b4f84f72e1ae2196fa67c76b0a6302ad.1661604264.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v5.git.1661604264.gitgitgadget@gmail.com","subject":"[PATCH v5 07/16] bisect--helper: migrate to OPT_SUBCOMMAND()","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-08-27T12:44:15Z","receivedAt":"2022-08-27T12:44:51Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nWe just introduced a new way to process subcommands, and the\n`bisect--helper` learns about it in preparation for replacing the\n`git-bisect.sh` script altogether.\n\nNote that a couple of `bisect_*()` functions are not converted into\n`cmd_bisect_*()` functions directly, as they have callers other than the\n`OPT_SUBCOMMAND()` one (and the original functions did not expect\na subcommand name to be passed as `argv[0]`, unlike the convention for\nthe `cmd_*()` functions. In those cases, we introduce wrapper functions\n`cmd_*()` that also call the original function.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/bisect--helper.c | 462 +++++++++++++++++++++++----------------\n git-bisect.sh            |  20 +-\n 2 files changed, 288 insertions(+), 194 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 0d7cc20f9c9..d797cd1cef8 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -20,18 +20,71 @@ 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+static const char * const bisect_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+\tN_(\"git bisect (bad|new) [<rev>]\"),\n+\tN_(\"git bisect (good|old) [<rev>...]\"),\n+\tN_(\"git bisect terms [--term-good | --term-bad]\"),\n+\tN_(\"git bisect skip [(<rev>|<range>)...]\"),\n+\tN_(\"git bisect next\"),\n+\tN_(\"git bisect reset [<commit>]\"),\n+\tN_(\"git bisect (visualize|view)\"),\n+\tN_(\"git bisect replay <logfile>\"),\n+\tN_(\"git bisect log\"),\n+\tN_(\"git bisect run <cmd>...\"),\n+\tNULL\n+};\n+\n+static const char * const 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+\tNULL\n+};\n+static const char * const bisect_state_usage[] = {\n+\tN_(\"git bisect (good|bad) [<rev>...]\"),\n+\tNULL\n+};\n+\n+static const char * const bisect_terms_usage[] = {\n+\tN_(\"git bisect terms [--term-good | --term-bad]\"),\n+\tNULL\n+};\n+\n+static const char * const bisect_skip_usage[] = {\n+\tN_(\"git bisect skip [(<rev>|<range>)...]\"),\n+\tNULL\n+};\n+\n+static const char * const bisect_next_usage[] = {\n+\tN_(\"git bisect next\"),\n+\tNULL\n+};\n+\n+static const char * const bisect_reset_usage[] = {\n+\tN_(\"git bisect reset [<commit>]\"),\n+\tNULL\n+};\n+\n+static const char * const bisect_visualize_usage[] = {\n+\tN_(\"git bisect visualize\"),\n+\tNULL\n+};\n+\n+static const char * const bisect_replay_usage[] = {\n+\tN_(\"git bisect replay <logfile>\"),\n+\tNULL\n+};\n+\n+static const char * const bisect_log_usage[] = {\n+\tN_(\"git bisect log\"),\n+\tNULL\n+};\n+\n+static const char * const bisect_run_usage[] = {\n+\tN_(\"git bisect run <cmd>...\"),\n \tNULL\n };\n \n@@ -63,7 +116,7 @@ static void set_terms(const char *bad,\n static const char vocab_bad[] = \"bad|new\";\n static const char vocab_good[] = \"good|old\";\n \n-static int bisect_autostart(void);\n+static int bisect_autostart(const char *prefix);\n \n /*\n  * Check whether the string `term` belongs to the set of strings\n@@ -238,6 +291,21 @@ static int bisect_reset(const char *commit)\n \treturn bisect_clean_state();\n }\n \n+static int cmd_bisect_reset(int argc, const char **argv, const char *prefix)\n+{\n+\tstruct option options[] = {\n+\t\tOPT_END()\n+\t};\n+\targc = parse_options(argc, argv, prefix, options,\n+\t\t\t     bisect_reset_usage,  PARSE_OPT_STOP_AT_NON_OPTION);\n+\n+\tif (argc > 1)\n+\t\tusage_msg_opt(_(\"requires either no argument or a commit\"),\n+\t\t\t      bisect_reset_usage, options);\n+\n+\treturn bisect_reset(argc == 1 ? argv[0] : NULL);\n+}\n+\n static void log_commit(FILE *fp, char *fmt, const char *state,\n \t\t       struct commit *commit)\n {\n@@ -465,26 +533,41 @@ finish:\n \treturn res;\n }\n \n-static int bisect_terms(const char *option)\n+static int cmd_bisect_terms(int argc, const char **argv, const char *prefix)\n {\n+\tint mode = -1;\n+\tstruct option options[] = {\n+\t\tOPT_SET_INT(0, \"term-good\", &mode,\n+\t\t\t    N_(\"show term for good/old\"), 1),\n+\t\tOPT_SET_INT(0, \"term-old\", &mode,\n+\t\t\t    N_(\"show term for good/old\"), 1),\n+\t\tOPT_SET_INT(0, \"term-bad\", &mode,\n+\t\t\t    N_(\"show term for bad/new\"), 0),\n+\t\tOPT_SET_INT(0, \"term-new\", &mode,\n+\t\t\t    N_(\"show term for bad/new\"), 0),\n+\t\tOPT_END()\n+\t};\n+\n+\targc = parse_options(argc, argv, prefix, options,\n+\t\t\t     bisect_terms_usage,  PARSE_OPT_STOP_AT_NON_OPTION);\n+\n+\tif (argc > 1)\n+\t\tusage_msg_opt(_(\"terms: requires 0 or 1 argument\"),\n+\t\t\t      bisect_terms_usage, options);\n+\n \tif (get_terms())\n \t\treturn error(_(\"no terms defined\"));\n \n-\tif (!option) {\n+\tif (mode < 0) {\n \t\tprintf(_(\"Your current terms are %s for the old state\\n\"\n \t\t\t \"and %s for the new state.\\n\"),\n \t\t       terms.term_good, terms.term_bad);\n \t\treturn 0;\n \t}\n-\tif (one_of(option, \"--term-good\", \"--term-old\", NULL))\n+\tif (mode == 1)\n \t\tprintf(\"%s\\n\", terms.term_good);\n-\telse if (one_of(option, \"--term-bad\", \"--term-new\", NULL))\n-\t\tprintf(\"%s\\n\", terms.term_bad);\n \telse\n-\t\treturn error(_(\"invalid argument %s for 'git bisect terms'.\\n\"\n-\t\t\t       \"Supported options are: \"\n-\t\t\t       \"--term-good|--term-old and \"\n-\t\t\t       \"--term-bad|--term-new.\"), option);\n+\t\tprintf(\"%s\\n\", terms.term_bad);\n \n \treturn 0;\n }\n@@ -623,7 +706,7 @@ static enum bisect_error bisect_next(const char *prefix)\n {\n \tenum bisect_error res;\n \n-\tif (bisect_autostart())\n+\tif (bisect_autostart(prefix))\n \t\treturn BISECT_FAILED;\n \n \tif (bisect_next_check(terms.term_good))\n@@ -642,6 +725,24 @@ static enum bisect_error bisect_next(const char *prefix)\n \treturn res;\n }\n \n+static int cmd_bisect_next(int argc, const char **argv, const char *prefix)\n+{\n+\tstruct option options[] = {\n+\t\tOPT_END()\n+\t};\n+\n+\tget_terms();\n+\targc = parse_options(argc, argv, prefix, options,\n+\t\t\t\tbisect_next_usage,\n+\t\t\t\tPARSE_OPT_STOP_AT_NON_OPTION);\n+\n+\tif (argc > 0)\n+\t\tusage_msg_opt(_(\"requires 0 argument\"),\n+\t\t\t      bisect_next_usage, options);\n+\n+\treturn bisect_next(prefix);\n+}\n+\n static enum bisect_error bisect_auto_next(const char *prefix)\n {\n \tif (bisect_next_check(NULL)) {\n@@ -652,8 +753,9 @@ static enum bisect_error bisect_auto_next(const char *prefix)\n \treturn bisect_next(prefix);\n }\n \n-static enum bisect_error bisect_start(int argc, const char **argv)\n+static int cmd_bisect_start(int argc, const char **argv, const char *prefix)\n {\n+\tstruct strvec orig_argv = STRVEC_INIT;\n \tint no_checkout = 0;\n \tint first_parent_only = 0;\n \tint i, has_double_dash = 0, must_write_terms = 0, bad_seen = 0;\n@@ -665,66 +767,64 @@ static enum bisect_error bisect_start(int argc, const char **argv)\n \tstruct strbuf bisect_names = STRBUF_INIT;\n \tstruct object_id head_oid;\n \tstruct object_id oid;\n-\tconst char *head;\n+\tconst char *head, *term_good = NULL, *term_bad = NULL;\n+\tstruct option options[] = {\n+\t\tOPT_BOOL(0, \"no-checkout\", &no_checkout,\n+\t\t\t N_(\"do not update worktree\")),\n+\t\tOPT_BOOL(0, \"first-parent\", &first_parent_only,\n+\t\t\t N_(\"follow only first parent of merge commits\")),\n+\t\tOPT_STRING(0, \"term-good\", &term_good, N_(\"term\"),\n+\t\t\t   N_(\"use this term instead of 'good'\")),\n+\t\tOPT_STRING(0, \"term-bad\", &term_bad, N_(\"term\"),\n+\t\t\t   N_(\"use this term instead of 'bad'\")),\n+\t\tOPT_STRING(0, \"term-old\", &term_good, N_(\"term\"),\n+\t\t\t   N_(\"use this term instead of 'good'\")),\n+\t\tOPT_STRING(0, \"term-new\", &term_bad, N_(\"term\"),\n+\t\t\t   N_(\"use this term instead of 'bad'\")),\n+\t\tOPT_END()\n+\t};\n+\n+\tset_terms(\"bad\", \"good\");\n \n \tif (is_bare_repository())\n \t\tno_checkout = 1;\n \n-\t/*\n-\t * Check for one bad and then some good revisions\n-\t */\n-\tfor (i = 0; i < argc; i++) {\n+\tstrvec_pushv(&orig_argv, argv); /* save the command-line for logging */\n+\targc = parse_options(argc, argv, prefix, options, bisect_start_usage,\n+\t\t\t     PARSE_OPT_KEEP_DASHDASH);\n+\n+\tif (term_good) {\n+\t\tfree(terms.term_good);\n+\t\tterms.term_good = xstrdup(term_good);\n+\t\tmust_write_terms = 1;\n+\t}\n+\n+\tif (term_bad) {\n+\t\tfree(terms.term_bad);\n+\t\tterms.term_bad = xstrdup(term_bad);\n+\t\tmust_write_terms = 1;\n+\t}\n+\n+\tfor (i = 0; i < argc; i++)\n \t\tif (!strcmp(argv[i], \"--\")) {\n \t\t\thas_double_dash = 1;\n \t\t\tbreak;\n \t\t}\n-\t}\n \n-\tfor (i = 0; i < argc; i++) {\n-\t\tconst char *arg = argv[i];\n-\t\tif (!strcmp(argv[i], \"--\")) {\n-\t\t\tbreak;\n-\t\t} else if (!strcmp(arg, \"--no-checkout\")) {\n-\t\t\tno_checkout = 1;\n-\t\t} else if (!strcmp(arg, \"--first-parent\")) {\n-\t\t\tfirst_parent_only = 1;\n-\t\t} else if (!strcmp(arg, \"--term-good\") ||\n-\t\t\t !strcmp(arg, \"--term-old\")) {\n-\t\t\ti++;\n-\t\t\tif (argc <= i)\n-\t\t\t\treturn error(_(\"'' is not a valid term\"));\n-\t\t\tmust_write_terms = 1;\n-\t\t\tfree((void *) terms.term_good);\n-\t\t\tterms.term_good = xstrdup(argv[i]);\n-\t\t} else if (skip_prefix(arg, \"--term-good=\", &arg) ||\n-\t\t\t   skip_prefix(arg, \"--term-old=\", &arg)) {\n-\t\t\tmust_write_terms = 1;\n-\t\t\tfree((void *) terms.term_good);\n-\t\t\tterms.term_good = xstrdup(arg);\n-\t\t} else if (!strcmp(arg, \"--term-bad\") ||\n-\t\t\t !strcmp(arg, \"--term-new\")) {\n-\t\t\ti++;\n-\t\t\tif (argc <= i)\n-\t\t\t\treturn error(_(\"'' is not a valid term\"));\n-\t\t\tmust_write_terms = 1;\n-\t\t\tfree((void *) terms.term_bad);\n-\t\t\tterms.term_bad = xstrdup(argv[i]);\n-\t\t} else if (skip_prefix(arg, \"--term-bad=\", &arg) ||\n-\t\t\t   skip_prefix(arg, \"--term-new=\", &arg)) {\n-\t\t\tmust_write_terms = 1;\n-\t\t\tfree((void *) terms.term_bad);\n-\t\t\tterms.term_bad = xstrdup(arg);\n-\t\t} else if (starts_with(arg, \"--\")) {\n-\t\t\treturn error(_(\"unrecognized option: '%s'\"), arg);\n-\t\t} else if (!get_oidf(&oid, \"%s^{commit}\", arg)) {\n+\t/*\n+\t * Check for one bad and then some good revisions\n+\t */\n+\n+\tfor (i = 0; i < argc && strcmp(argv[i], \"--\"); i++)\n+\t\tif (!get_oidf(&oid, \"%s^{commit}\", argv[i])) {\n \t\t\tstring_list_append(&revs, oid_to_hex(&oid));\n \t\t} else if (has_double_dash) {\n \t\t\tdie(_(\"'%s' does not appear to be a valid \"\n-\t\t\t      \"revision\"), arg);\n+\t\t\t      \"revision\"), argv[i]);\n \t\t} else {\n \t\t\tbreak;\n \t\t}\n-\t}\n+\n \tpathspec_pos = i;\n \n \t/*\n@@ -836,11 +936,13 @@ static enum bisect_error bisect_start(int argc, const char **argv)\n \t\tgoto finish;\n \t}\n \n-\tres = bisect_append_log_quoted(argv);\n+\tres = bisect_append_log_quoted(orig_argv.v + 1);\n \tif (res)\n \t\tres = BISECT_FAILED;\n \n finish:\n+\tstrvec_clear(&orig_argv);\n+\n \tstring_list_clear(&revs, 0);\n \tstring_list_clear(&states, 0);\n \tstrbuf_release(&start_head);\n@@ -848,7 +950,7 @@ finish:\n \tif (res)\n \t\treturn res;\n \n-\tres = bisect_auto_next(NULL);\n+\tres = bisect_auto_next(prefix);\n \tif (!is_bisect_success(res))\n \t\tbisect_clean_state();\n \treturn res;\n@@ -859,7 +961,7 @@ static inline int file_is_not_empty(const char *path)\n \treturn !is_empty_or_missing_file(path);\n }\n \n-static int bisect_autostart(void)\n+static int bisect_autostart(const char *prefix)\n {\n \tint res;\n \tconst char *yesno;\n@@ -881,12 +983,13 @@ static int bisect_autostart(void)\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(0, empty_strvec);\n+\t\t-1 : cmd_bisect_start(1, &yesno, prefix);\n \n \treturn res;\n }\n \n-static enum bisect_error bisect_state(int argc, const char **argv)\n+static enum bisect_error bisect_state(int argc, const char **argv,\n+\t\t\t\t      const char *prefix)\n {\n \tconst char *state;\n \tint i, verify_expected = 1;\n@@ -894,10 +997,8 @@ static enum bisect_error bisect_state(int argc, const char **argv)\n \tstruct strbuf buf = STRBUF_INIT;\n \tstruct oid_array revs = OID_ARRAY_INIT;\n \n-\tif (!argc)\n-\t\treturn error(_(\"Please call `--bisect-state` with at least one argument\"));\n \n-\tif (bisect_autostart())\n+\tif (bisect_autostart(prefix))\n \t\treturn BISECT_FAILED;\n \n \tstate = argv[0];\n@@ -966,11 +1067,41 @@ static enum bisect_error bisect_state(int argc, const char **argv)\n \treturn bisect_auto_next(NULL);\n }\n \n-static enum bisect_error bisect_log(void)\n+static int cmd_bisect_state(int argc, const char **argv,\n+\t\t\t\tconst char *prefix)\n {\n+\tstruct option options[] = {\n+\t\tOPT_END()\n+\t};\n+\n+\tset_terms(\"bad\", \"good\");\n+\tget_terms();\n+\n+\targc = parse_options(argc, argv, prefix, options,\n+\t\t\t     bisect_state_usage,  PARSE_OPT_STOP_AT_NON_OPTION);\n+\n+\tif (!argc)\n+\t\tusage_msg_opt(_(\"need at least one argument\"),\n+\t\t\t      bisect_state_usage, options);\n+\n+\treturn bisect_state(argc, argv, prefix);\n+}\n+\n+static int cmd_bisect_log(int argc, const char **argv, const char *prefix)\n+{\n+\tstruct option options[] = {\n+\t\tOPT_END()\n+\t};\n \tint fd, status;\n \tconst char* filename = git_path_bisect_log();\n \n+\targc = parse_options(argc, argv, prefix, options,\n+\t\t\t     bisect_log_usage,  PARSE_OPT_STOP_AT_NON_OPTION);\n+\n+\tif (argc > 0)\n+\t\tusage_msg_opt(_(\"require 0 argument\"), bisect_log_usage,\n+\t\t\t      options);\n+\n \tif (is_empty_or_missing_file(filename))\n \t\treturn error(_(\"We are not bisecting.\"));\n \n@@ -983,7 +1114,7 @@ static enum bisect_error bisect_log(void)\n \treturn status ? BISECT_FAILED : BISECT_OK;\n }\n \n-static int process_replay_line(struct strbuf *line)\n+static int process_replay_line(struct strbuf *line, const char *prefix)\n {\n \tconst char *p = line->buf + strspn(line->buf, \" \\t\");\n \tchar *word_end, *rev;\n@@ -1004,8 +1135,10 @@ static int process_replay_line(struct strbuf *line)\n \tif (!strcmp(p, \"start\")) {\n \t\tstruct strvec argv = STRVEC_INIT;\n \t\tint res;\n+\n+\t\tstrvec_push(&argv, p);\n \t\tsq_dequote_to_strvec(rev, &argv);\n-\t\tres = bisect_start(argv.nr, argv.v);\n+\t\tres = cmd_bisect_start(argv.nr, argv.v, prefix);\n \t\tstrvec_clear(&argv);\n \t\treturn res;\n \t}\n@@ -1017,8 +1150,11 @@ static int process_replay_line(struct strbuf *line)\n \tif (!strcmp(p, \"terms\")) {\n \t\tstruct strvec argv = STRVEC_INIT;\n \t\tint res;\n+\n+\t\tstrvec_push(&argv, p);\n \t\tsq_dequote_to_strvec(rev, &argv);\n-\t\tres = bisect_terms(argv.nr == 1 ? argv.v[0] : NULL);\n+\t\tres = cmd_bisect_terms(argv.nr, argv.v, NULL);\n+\n \t\tstrvec_clear(&argv);\n \t\treturn res;\n \t}\n@@ -1027,12 +1163,25 @@ static int process_replay_line(struct strbuf *line)\n \treturn -1;\n }\n \n-static enum bisect_error bisect_replay(const char *filename)\n+static int cmd_bisect_replay(int argc, const char **argv, const char *prefix)\n {\n+\tstruct option options[] = {\n+\t\tOPT_END()\n+\t};\n+\tconst char *filename;\n \tFILE *fp = NULL;\n \tenum bisect_error res = BISECT_OK;\n \tstruct strbuf line = STRBUF_INIT;\n \n+\tset_terms(\"bad\", \"good\");\n+\targc = parse_options(argc, argv, prefix, options,\n+\t\t\t     bisect_reset_usage,  PARSE_OPT_STOP_AT_NON_OPTION);\n+\n+\tif (argc != 1)\n+\t\tusage_msg_opt(_(\"no logfile given\"), bisect_replay_usage,\n+\t\t\t      options);\n+\n+\tfilename = argv[0];\n \tif (is_empty_or_missing_file(filename))\n \t\treturn error(_(\"cannot read file '%s' for replaying\"), filename);\n \n@@ -1044,7 +1193,7 @@ static enum bisect_error bisect_replay(const char *filename)\n \t\treturn BISECT_FAILED;\n \n \twhile ((strbuf_getline(&line, fp) != EOF) && !res)\n-\t\tres = process_replay_line(&line);\n+\t\tres = process_replay_line(&line, prefix);\n \n \tstrbuf_release(&line);\n \tfclose(fp);\n@@ -1055,12 +1204,20 @@ static enum bisect_error bisect_replay(const char *filename)\n \treturn bisect_auto_next(NULL);\n }\n \n-static enum bisect_error bisect_skip(int argc, const char **argv)\n+static int cmd_bisect_skip(int argc, const char **argv, const char *prefix)\n {\n+\tstruct option options[] = {\n+\t\tOPT_END()\n+\t};\n \tint i;\n \tenum bisect_error res;\n \tstruct strvec argv_state = STRVEC_INIT;\n \n+\tset_terms(\"bad\", \"good\");\n+\tget_terms();\n+\targc = parse_options(argc, argv, prefix, options,\n+\t\t\t     bisect_skip_usage,  PARSE_OPT_STOP_AT_NON_OPTION);\n+\n \tstrvec_push(&argv_state, \"skip\");\n \n \tfor (i = 0; i < argc; i++) {\n@@ -1085,18 +1242,28 @@ static enum bisect_error bisect_skip(int argc, const char **argv)\n \t\t\tstrvec_push(&argv_state, argv[i]);\n \t\t}\n \t}\n-\tres = bisect_state(argv_state.nr, argv_state.v);\n+\tres = bisect_state(argv_state.nr, argv_state.v, prefix);\n \n \tstrvec_clear(&argv_state);\n \treturn res;\n }\n \n-static int bisect_visualize(int argc, const char **argv)\n+static int cmd_bisect_visualize(int argc, const char **argv, const char *prefix)\n {\n+\tstruct option options[] = {\n+\t\tOPT_END()\n+\t};\n \tstruct strvec args = STRVEC_INIT;\n \tint flags = RUN_COMMAND_NO_STDIN, res = 0;\n \tstruct strbuf sb = STRBUF_INIT;\n \n+\tset_terms(\"bad\", \"good\");\n+\tget_terms();\n+\targc = parse_options(argc, argv, prefix, options,\n+\t\t\t     bisect_visualize_usage,\n+\t\t\t     PARSE_OPT_KEEP_DASHDASH |\n+\t\t\t     PARSE_OPT_KEEP_UNKNOWN_OPT);\n+\n \tif (bisect_next_check(NULL) != 0)\n \t\treturn BISECT_FAILED;\n \n@@ -1166,8 +1333,11 @@ static int verify_good(const char **quoted_argv)\n \treturn rc;\n }\n \n-static int bisect_run(int argc, const char **argv)\n+static int cmd_bisect_run(int argc, const char **argv, const char *prefix)\n {\n+\tstruct option options[] = {\n+\t\tOPT_END()\n+\t};\n \tint res = BISECT_OK;\n \tstruct strbuf command = STRBUF_INIT;\n \tstruct strvec run_args = STRVEC_INIT;\n@@ -1175,15 +1345,18 @@ static int bisect_run(int argc, const char **argv)\n \tint temporary_stdout_fd, saved_stdout;\n \tint is_first_run = 1;\n \n+\tget_terms();\n+\targc = parse_options(argc, argv, prefix, options,\n+\t\t\t     bisect_run_usage,  PARSE_OPT_STOP_AT_NON_OPTION);\n+\n \tif (bisect_next_check(NULL))\n \t\treturn BISECT_FAILED;\n \n \tif (argc)\n \t\tsq_quote_argv(&command, argv);\n-\telse {\n-\t\terror(_(\"bisect run failed: no command provided.\"));\n-\t\treturn BISECT_FAILED;\n-\t}\n+\telse\n+\t\tusage_msg_opt(_(\"bisect run failed: no command provided.\"),\n+\t\t\t      bisect_run_usage, options);\n \n \tstrvec_push(&run_args, command.buf);\n \n@@ -1239,7 +1412,7 @@ static int bisect_run(int argc, const char **argv)\n \t\tsaved_stdout = dup(1);\n \t\tdup2(temporary_stdout_fd, 1);\n \n-\t\tres = bisect_state(1, &new_state);\n+\t\tres = bisect_state(1, &new_state, prefix);\n \n \t\tfflush(stdout);\n \t\tdup2(saved_stdout, 1);\n@@ -1272,105 +1445,26 @@ static int bisect_run(int argc, const char **argv)\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+\tparse_opt_subcommand_fn *fn = NULL;\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-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(\"run\", &fn, cmd_bisect_run),\n \t\tOPT_END()\n \t};\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-\n-\tif (!cmdmode)\n-\t\tusage_with_options(git_bisect_helper_usage, options);\n+\t\t\t     bisect_usage, 0);\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(argc == 1 ? argv[0] : NULL);\n-\t\tbreak;\n-\tcase BISECT_START:\n-\t\tset_terms(\"bad\", \"good\");\n-\t\tres = bisect_start(argc, argv);\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();\n-\t\tres = bisect_next(prefix);\n-\t\tbreak;\n-\tcase BISECT_STATE:\n-\t\tset_terms(\"bad\", \"good\");\n-\t\tget_terms();\n-\t\tres = bisect_state(argc, argv);\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(\"bad\", \"good\");\n-\t\tres = bisect_replay(argv[0]);\n-\t\tbreak;\n-\tcase BISECT_SKIP:\n-\t\tset_terms(\"bad\", \"good\");\n-\t\tget_terms();\n-\t\tres = bisect_skip(argc, argv);\n-\t\tbreak;\n-\tcase BISECT_VISUALIZE:\n-\t\tget_terms();\n-\t\tres = bisect_visualize(argc, argv);\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();\n-\t\tres = bisect_run(argc, argv);\n-\t\tbreak;\n-\tdefault:\n-\t\tBUG(\"unknown subcommand %d\", cmdmode);\n-\t}\n+\tres = fn(argc, argv, prefix);\n \tfree_terms();\n \n \treturn is_bisect_success(res) ? 0 : -res;\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\n-- \ngitgitgadget\n\n"},{"id":"462033","messageId":"ba537af706635b0246660ea1a459a33b9fc29376.1661604264.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v5.git.1661604264.gitgitgadget@gmail.com","subject":"[PATCH v5 08/16] bisect: verify that a bogus option won't try to start a bisection","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-08-27T12:44:16Z","receivedAt":"2022-08-27T12:44:53Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nWe do not want `git bisect --bogus-option` to start a bisection. To\nverify that, we look for the tell-tale error message `You need to start\nby \"git bisect start\"` and fail if it was found.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n t/t6030-bisect-porcelain.sh | 10 ++++++++++\n 1 file changed, 10 insertions(+)\n\ndiff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh\nindex 83931d482fb..6d6e72276ae 100755\n--- a/t/t6030-bisect-porcelain.sh\n+++ b/t/t6030-bisect-porcelain.sh\n@@ -900,6 +900,16 @@ test_expect_success 'bisect start with one term1 and term2' '\n \tgit bisect reset\n '\n \n+test_expect_success 'bogus command does not start bisect' '\n+\tgit bisect reset &&\n+\ttest_must_fail git bisect --bisect-terms 1 2 2>out &&\n+\t! grep \"You need to start\" out &&\n+\ttest_must_fail git bisect --bisect-terms 2>out &&\n+\t! grep \"You need to start\" out &&\n+\tgrep \"git bisect.*visualize\" out &&\n+\tgit bisect reset\n+'\n+\n test_expect_success 'bisect replay with term1 and term2' '\n \tgit bisect replay log_to_replay.txt >bisect_result &&\n \tgrep \"$HASH2 is the first term1 commit\" bisect_result &&\n-- \ngitgitgadget\n\n"},{"id":"462034","messageId":"409492ad830828f2b5f341706ad9ad1c64f66d6e.1661604264.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v5.git.1661604264.gitgitgadget@gmail.com","subject":"[PATCH v5 09/16] bisect run: fix the error message","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-08-27T12:44:17Z","receivedAt":"2022-08-27T12:44:54Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nIn d1bbbe45df8 (bisect--helper: reimplement `bisect_run` shell function\nin C, 2021-09-13), we ported the `bisect run` subcommand to C, including\nthe part that prints out an error message when the implicit `git bisect\nbad` or `git bisect good` failed.\n\nHowever, the error message was supposed to print out whether the state\nwas \"good\" or \"bad\", but used a bogus (because non-populated) `args`\nvariable for it.\n\nHelped-by: Elijah Newren <newren@gmail.com>\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/bisect--helper.c    |  2 +-\n t/t6030-bisect-porcelain.sh | 10 ++++++++++\n 2 files changed, 11 insertions(+), 1 deletion(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex d797cd1cef8..a00167f1373 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1430,7 +1430,7 @@ static int cmd_bisect_run(int argc, const char **argv, const char *prefix)\n \t\t\tprintf(_(\"bisect found first bad commit\"));\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: 'git bisect\"\n \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 6d6e72276ae..7a76f204083 100755\n--- a/t/t6030-bisect-porcelain.sh\n+++ b/t/t6030-bisect-porcelain.sh\n@@ -1063,4 +1063,14 @@ test_expect_success 'bisect state output with bad commit' '\n \tgrep -F \"waiting for good commit(s), bad commit known\" output\n '\n \n+test_expect_success 'verify correct error message' '\n+\tgit bisect reset &&\n+\tgit bisect start $HASH4 $HASH1 &&\n+\twrite_script test_script.sh <<-\\EOF &&\n+\trm .git/BISECT*\n+\tEOF\n+\ttest_must_fail git bisect run ./test_script.sh 2>error &&\n+\tgrep \"git bisect good.*exited with error code\" error\n+'\n+\n test_done\n-- \ngitgitgadget\n\n"},{"id":"462035","messageId":"bc5efc8fbfeac20073498d21fc6276c5c1a3870f.1661604264.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v5.git.1661604264.gitgitgadget@gmail.com","subject":"[PATCH v5 10/16] bisect: avoid double-quoting when printing the failed command","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-08-27T12:44:18Z","receivedAt":"2022-08-27T12:44:56Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nWe already quote the command via `sq_quote_argv()`, no need to enclose\nthe result in an extraneous pair of single-quotes.\n\nPointed out by Elijah Newren.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/bisect--helper.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex a00167f1373..5cf688c0dac 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1390,7 +1390,7 @@ static int cmd_bisect_run(int argc, const char **argv, const char *prefix)\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, command.buf);\n \t\t\tbreak;\n \t\t}\n \n-- \ngitgitgadget\n\n"},{"id":"462036","messageId":"8a0adfe3867157102e75d53ed928603ad634b904.1661604264.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v5.git.1661604264.gitgitgadget@gmail.com","subject":"[PATCH v5 11/16] bisect--helper: calling `bisect_state()` without an argument is a bug","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-08-27T12:44:19Z","receivedAt":"2022-08-27T12:44:58Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nThe `bisect_state()` function is now a purely internal function and must\nbe called with a valid state, everything else is a bug.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/bisect--helper.c | 2 ++\n 1 file changed, 2 insertions(+)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 5cf688c0dac..3f333cfae76 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -997,6 +997,8 @@ static enum bisect_error bisect_state(int argc, const char **argv,\n \tstruct strbuf buf = STRBUF_INIT;\n \tstruct oid_array revs = OID_ARRAY_INIT;\n \n+\tif (!argc)\n+\t\tBUG(\"bisect_state() called without argument\");\n \n \tif (bisect_autostart(prefix))\n \t\treturn BISECT_FAILED;\n-- \ngitgitgadget\n\n"},{"id":"462037","messageId":"a96489310d33f97e20380bdd4bcdac1d970e128f.1661604264.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v5.git.1661604264.gitgitgadget@gmail.com","subject":"[PATCH v5 15/16] bisect: remove Cogito-related code","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-08-27T12:44:23Z","receivedAt":"2022-08-27T12:45:47Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nOnce upon a time, there was this idea that Git would not actually be a\nsingle coherent program, but rather a set of low-level programs that\nusers cobble together via shell scripts, or develop high-level user\ninterfaces for Git, or both.\n\nCogito was such a high-level user interface, incidentally implemented\nvia shell scripts that cobble together Git calls.\n\nIt did turn out relatively quickly that Git would much rather provide a\nuseful high-level user interface itself.\n\nAs of April 19th, 2007, Cogito was therefore discontinued (see\nhttps://lore.kernel.org/git/20070419124648.GL4489@pasky.or.cz/).\n\nNevertheless, for almost 15 years after that announcement, Git carried\nspecial code in `git bisect` to accommodate Cogito.\n\nSince it is beyond doubt that there are no more Cogito users, let's\nremove the last remnant of Cogito-accommodating code.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/bisect.c | 8 --------\n 1 file changed, 8 deletions(-)\n\ndiff --git a/builtin/bisect.c b/builtin/bisect.c\nindex 16f5c92bb9e..cfd6b63214a 100644\n--- a/builtin/bisect.c\n+++ b/builtin/bisect.c\n@@ -15,7 +15,6 @@ static GIT_PATH_FUNC(git_path_bisect_expected_rev, \"BISECT_EXPECTED_REV\")\n static GIT_PATH_FUNC(git_path_bisect_ancestors_ok, \"BISECT_ANCESTORS_OK\")\n static GIT_PATH_FUNC(git_path_bisect_start, \"BISECT_START\")\n static GIT_PATH_FUNC(git_path_bisect_log, \"BISECT_LOG\")\n-static GIT_PATH_FUNC(git_path_head_name, \"head-name\")\n 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@@ -880,13 +879,6 @@ static int cmd_bisect_start(int argc, const char **argv, const char *prefix)\n \t\t\tstrbuf_addstr(&start_head, oid_to_hex(&head_oid));\n \t\t} else if (!get_oid(head, &head_oid) &&\n \t\t\t   skip_prefix(head, \"refs/heads/\", &head)) {\n-\t\t\t/*\n-\t\t\t * This error message should only be triggered by\n-\t\t\t * cogito usage, and cogito users should understand\n-\t\t\t * it relates to cg-seek.\n-\t\t\t */\n-\t\t\tif (!is_empty_or_missing_file(git_path_head_name()))\n-\t\t\t\treturn error(_(\"won't bisect on cg-seek'ed tree\"));\n \t\t\tstrbuf_addstr(&start_head, head);\n \t\t} else {\n \t\t\treturn error(_(\"bad HEAD - strange symbolic ref\"));\n-- \ngitgitgadget\n\n"},{"id":"462038","messageId":"a8f08f5e0cbfcfb74096d6c611de3d21eac1244f.1661604264.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v5.git.1661604264.gitgitgadget@gmail.com","subject":"[PATCH v5 14/16] Turn `git bisect` into a full built-in","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-08-27T12:44:22Z","receivedAt":"2022-08-27T12:47:18Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?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>\n---\n Makefile                               |  3 +--\n builtin.h                              |  2 +-\n builtin/{bisect--helper.c => bisect.c} |  2 +-\n git-bisect.sh                          | 37 --------------------------\n git.c                                  |  2 +-\n 5 files changed, 4 insertions(+), 42 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 1624471badc..4a79b2ba2fe 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@@ -1127,7 +1126,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 40e9ecc8485..b9470f8ab4f 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 d243a9132e2..16f5c92bb9e 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect.c\n@@ -1445,7 +1445,7 @@ static int cmd_bisect_run(int argc, const char **argv, const char *prefix)\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 \tstruct strvec args = STRVEC_INIT;\n \tparse_opt_subcommand_fn *fn = NULL;\ndiff --git a/git-bisect.sh b/git-bisect.sh\ndeleted file mode 100755\nindex 028d39cd9ce..00000000000\n--- a/git-bisect.sh\n+++ /dev/null\n@@ -1,37 +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-exec git bisect--helper \"$@\"\ndiff --git a/git.c b/git.c\nindex f52a9554103..9c11727e29d 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-- \ngitgitgadget\n\n"},{"id":"462039","messageId":"32bf74e3050a6e30e1e3fb1e77ce0d53f9054fd6.1661604264.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v5.git.1661604264.gitgitgadget@gmail.com","subject":"[PATCH v5 13/16] bisect: move even the command-line parsing to `bisect--helper`","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-08-27T12:44:21Z","receivedAt":"2022-08-27T12:47:21Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nOn our journey to a fully built-in `git bisect`, this is the\nlast step.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/bisect--helper.c |  1 -\n git-bisect.sh            | 49 +---------------------------------------\n 2 files changed, 1 insertion(+), 49 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 9f78bd45ca5..d243a9132e2 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1455,7 +1455,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),\ndiff --git a/git-bisect.sh b/git-bisect.sh\nindex f4df8709d84..028d39cd9ce 100755\n--- a/git-bisect.sh\n+++ b/git-bisect.sh\n@@ -34,51 +34,4 @@ 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 \"$cmd\" \"$@\" ;;\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\tusage ;;\n-\tesac\n-esac\n+exec git bisect--helper \"$@\"\n-- \ngitgitgadget\n\n"},{"id":"462040","messageId":"189d2b3ba46ce67ece7f8852d3ced4682ce8a645.1661604264.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v5.git.1661604264.gitgitgadget@gmail.com","subject":"[PATCH v5 12/16] bisect--helper: make `state` optional","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-08-27T12:44:20Z","receivedAt":"2022-08-27T12:47:23Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?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>\n---\n builtin/bisect--helper.c | 22 +++++++++++++++++++++-\n git-bisect.sh            |  2 +-\n 2 files changed, 22 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 3f333cfae76..9f78bd45ca5 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1447,6 +1447,7 @@ static int cmd_bisect_run(int argc, const char **argv, const char *prefix)\n \n int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n {\n+\tstruct strvec args = STRVEC_INIT;\n \tparse_opt_subcommand_fn *fn = NULL;\n \tint res = 0;\n \tstruct option options[] = {\n@@ -1464,10 +1465,29 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t};\n \n \targc = parse_options(argc, argv, prefix, options,\n-\t\t\t     bisect_usage, 0);\n+\t\t\t     bisect_usage, PARSE_OPT_SUBCOMMAND_OPTIONAL);\n+\n+\tif (!fn) {\n+\t\tif (!argc)\n+\t\t\tusage_msg_opt(_(\"need a command\"), bisect_usage,\n+\t\t\t\t      options);\n+\n+\t\tset_terms(\"bad\", \"good\");\n+\t\tget_terms();\n+\t\tif (check_and_set_terms(argv[0]))\n+\t\t\tusage_msg_optf(_(\"unknown command: '%s'\"), bisect_usage,\n+\t\t\t\t       options, argv[0]);\n+\n+\t\tstrvec_push(&args, \"state\");\n+\t\tstrvec_pushv(&args, argv);\n+\t\targc = args.nr;\n+\t\targv = args.v;\n+\t\tfn = cmd_bisect_state;\n+\t}\n \n \tres = fn(argc, argv, prefix);\n \tfree_terms();\n+\tstrvec_clear(&args);\n \n \treturn is_bisect_success(res) ? 0 : -res;\n }\ndiff --git a/git-bisect.sh b/git-bisect.sh\nindex e19847eba0d..f4df8709d84 100755\n--- a/git-bisect.sh\n+++ b/git-bisect.sh\n@@ -60,7 +60,7 @@ case \"$#\" in\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+\t\tgit bisect--helper \"$cmd\" \"$@\" ;;\n \tskip)\n \t\tgit bisect--helper skip \"$@\" || exit;;\n \tnext)\n-- \ngitgitgadget\n\n"},{"id":"462041","messageId":"bfa7aa19f0313cfee154b3e9157e63dc5ac8f2f6.1661604264.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v5.git.1661604264.gitgitgadget@gmail.com","subject":"[PATCH v5 16/16] bisect: no longer try to clean up left-over `.git/head-name` files","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-08-27T12:44:24Z","receivedAt":"2022-08-27T12:47:24Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nAs per the code comment, the `.git/head-name` files were cleaned up for\nbackwards-compatibility: an old version of `git bisect` could have left\nthem behind.\n\nNow, just how old would such a version be? As of 0f497e75f05 (Eliminate\nconfusing \"won't bisect on seeked tree\" failure, 2008-02-23), `git\nbisect` does not write that file anymore. Which corresponds to Git\nv1.5.4.4.\n\nEven if the likelihood is non-nil that there might still be users out\nthere who use such an old version to start a bisection, but then decide\nto continue bisecting with a current Git version, it is highly\nimprobable.\n\nSo let's remove that code, at long last.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n bisect.c                    | 3 ---\n t/t6030-bisect-porcelain.sh | 1 -\n 2 files changed, 4 deletions(-)\n\ndiff --git a/bisect.c b/bisect.c\nindex b63669cc9d7..00bd4ba581c 100644\n--- a/bisect.c\n+++ b/bisect.c\n@@ -474,7 +474,6 @@ static GIT_PATH_FUNC(git_path_bisect_start, \"BISECT_START\")\n static GIT_PATH_FUNC(git_path_bisect_log, \"BISECT_LOG\")\n static GIT_PATH_FUNC(git_path_bisect_terms, \"BISECT_TERMS\")\n static GIT_PATH_FUNC(git_path_bisect_first_parent, \"BISECT_FIRST_PARENT\")\n-static GIT_PATH_FUNC(git_path_head_name, \"head-name\")\n \n static void read_bisect_paths(struct strvec *array)\n {\n@@ -1181,8 +1180,6 @@ int bisect_clean_state(void)\n \tunlink_or_warn(git_path_bisect_run());\n \tunlink_or_warn(git_path_bisect_terms());\n \tunlink_or_warn(git_path_bisect_first_parent());\n-\t/* Cleanup head-name if it got left by an old version of git-bisect */\n-\tunlink_or_warn(git_path_head_name());\n \t/*\n \t * Cleanup BISECT_START last to support the --no-checkout option\n \t * introduced in the commit 4796e823a.\ndiff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh\nindex 7a76f204083..1d9cbf229e2 100755\n--- a/t/t6030-bisect-porcelain.sh\n+++ b/t/t6030-bisect-porcelain.sh\n@@ -1000,7 +1000,6 @@ test_expect_success 'git bisect reset cleans bisection state properly' '\n \ttest_path_is_missing \".git/BISECT_LOG\" &&\n \ttest_path_is_missing \".git/BISECT_RUN\" &&\n \ttest_path_is_missing \".git/BISECT_TERMS\" &&\n-\ttest_path_is_missing \".git/head-name\" &&\n \ttest_path_is_missing \".git/BISECT_HEAD\" &&\n \ttest_path_is_missing \".git/BISECT_START\"\n '\n-- \ngitgitgadget\n"},{"id":"462053","messageId":"xmqqpmgkvpee.fsf@gitster.g","threadId":"57326","inReplyTo":"9ab30552c6ae6a5d0a85d7a7bbdd10af4a4cf7ec.1661604264.git.gitgitgadget@gmail.com","subject":"Re: [PATCH v5 04/16] bisect--helper: simplify exit code computation","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-08-28T06:43:53Z","receivedAt":"2022-08-28T06:43:58Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Johannes Schindelin via GitGitGadget\" <gitgitgadget@gmail.com>\nwrites:\n\n> From: Johannes Schindelin <johannes.schindelin@gmx.de>\n>\n> We _already_ have a function to determine whether a given `enum\n> bisect_error` value is non-zero but still _actually_ indicates success.\n>\n> Let's use it instead of duplicating the logic.\n\nYeah, looking very good.\n\n\n>\n> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> ---\n>  builtin/bisect--helper.c | 9 +--------\n>  1 file changed, 1 insertion(+), 8 deletions(-)\n>\n> diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\n> index aa94c25ec73..2f9c7f54f3f 100644\n> --- a/builtin/bisect--helper.c\n> +++ b/builtin/bisect--helper.c\n> @@ -1380,12 +1380,5 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n>  \t}\n>  \tfree_terms(&terms);\n>  \n> -\t/*\n> -\t * Handle early success\n> -\t * From check_merge_bases > check_good_are_ancestors_of_bad > bisect_next_all\n> -\t */\n> -\tif ((res == BISECT_INTERNAL_SUCCESS_MERGE_BASE) || (res == BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND))\n> -\t\tres = BISECT_OK;\n> -\n> -\treturn -res;\n> +\treturn is_bisect_success(res) ? 0 : -res;\n>  }\n"},{"id":"462054","messageId":"xmqqk06svoxp.fsf@gitster.g","threadId":"57326","inReplyTo":"92b3b116ef8f879192d9deb94d68b73e29d5dcd6.1661604264.git.gitgitgadget@gmail.com","subject":"Re: [PATCH v5 05/16] bisect--helper: make `terms` an explicit singleton","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-08-28T06:53:54Z","receivedAt":"2022-08-28T06:54:01Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Johannes Schindelin via GitGitGadget\" <gitgitgadget@gmail.com>\nwrites:\n\n> -struct bisect_terms {\n> +static struct bisect_terms {\n>  \tchar *term_good;\n>  \tchar *term_bad;\n> -};\n> +} terms;\n\nOn the surface, more global state may feel sad, but I do not think\nwe want to run multiple bisection in one session anyway.  Overall\nthis may result in a simplicity win, hopefully.\n\nThe patch is noisy, but mostly from rewriting \"terms->member\" to\n\"terms.member\".  I am not sure if that was worth the effort, though.\nYou had a code that plumbed a parameter through the call graph, and\ninstead of destroying that arrangement, you could have just replaced\nthe reference at the beginning of the call chain to use the global\nstate instead of an on-stack variable that the caller used to have.\n\nI have no strong preference, but I do not think that it particularly\ncontributes to \"clarifying that we are using global state\" to make\ndirect accesses to the variable everywhere.  I dunno.\n\n"},{"id":"462055","messageId":"xmqqedx0voxp.fsf@gitster.g","threadId":"57326","inReplyTo":"c9dc0281e38bf9bc0bce72de172b5dbadbcbb1f5.1661604264.git.gitgitgadget@gmail.com","subject":"Re: [PATCH v5 06/16] bisect--helper: make the order consistently `argc, argv`","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-08-28T06:53:54Z","receivedAt":"2022-08-28T06:54:04Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Johannes Schindelin via GitGitGadget\" <gitgitgadget@gmail.com>\nwrites:\n\n> From: Johannes Schindelin <johannes.schindelin@gmx.de>\n>\n> In C, the natural order is for `argc` to come before `argv` by virtue of\n> the `main()` function declaring the parameters in precisely that order.\n>\n> It is confusing & distracting, then, when readers familiar with the C\n> language read code where that order is switched around.\n>\n> Let's just change the order and avoid that type of developer friction.\n\nThanks.  This did look disturbing to me every time I peeked into\nthis part of the code.  To some it may be insignificant detail, but\nthese things add up.  The result is much nicer.\n"},{"id":"462056","messageId":"xmqq8rn8voh2.fsf@gitster.g","threadId":"57326","inReplyTo":"409492ad830828f2b5f341706ad9ad1c64f66d6e.1661604264.git.gitgitgadget@gmail.com","subject":"Re: [PATCH v5 09/16] bisect run: fix the error message","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-08-28T07:03:53Z","receivedAt":"2022-08-28T07:03:59Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Johannes Schindelin via GitGitGadget\" <gitgitgadget@gmail.com>\nwrites:\n\n> From: Johannes Schindelin <johannes.schindelin@gmx.de>\n>\n> In d1bbbe45df8 (bisect--helper: reimplement `bisect_run` shell function\n> in C, 2021-09-13), we ported the `bisect run` subcommand to C, including\n> the part that prints out an error message when the implicit `git bisect\n> bad` or `git bisect good` failed.\n>\n> However, the error message was supposed to print out whether the state\n> was \"good\" or \"bad\", but used a bogus (because non-populated) `args`\n> variable for it.\n>\n> Helped-by: Elijah Newren <newren@gmail.com>\n> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> ---\n>  builtin/bisect--helper.c    |  2 +-\n>  t/t6030-bisect-porcelain.sh | 10 ++++++++++\n>  2 files changed, 11 insertions(+), 1 deletion(-)\n>\n> diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\n> index d797cd1cef8..a00167f1373 100644\n> --- a/builtin/bisect--helper.c\n> +++ b/builtin/bisect--helper.c\n> @@ -1430,7 +1430,7 @@ static int cmd_bisect_run(int argc, const char **argv, const char *prefix)\n>  \t\t\tprintf(_(\"bisect found first bad commit\"));\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: 'git bisect\"\n>  \t\t\t\" %s' exited with error code %d\"), new_state, res);\n>  \t\t} else {\n>  \t\t\tcontinue;\n\nThe change to retire \"bisect--helper\" from the end-user facing error\nmessage makes tons of sense, but I am not quite sure if the proposed\nlog message describes the change correctly.  Or is this a fallout of\nsome \"rebase -i\" gotcha that a log message meant for one commit was\napplied to a different commit, or something?\n"},{"id":"462075","messageId":"220829.86wnar2wus.gmgdl@evledraar.gmail.com","threadId":"57326","inReplyTo":"5b7a3d58b4f84f72e1ae2196fa67c76b0a6302ad.1661604264.git.gitgitgadget@gmail.com","subject":"Re: [PATCH v5 07/16] bisect--helper: migrate to OPT_SUBCOMMAND()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-29T09:38:13Z","receivedAt":"2022-08-29T10:00:24Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Sat, Aug 27 2022, Johannes Schindelin via GitGitGadget wrote:\n\n> From: Johannes Schindelin <johannes.schindelin@gmx.de>\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> +static const char * const bisect_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> +\tN_(\"git bisect (bad|new) [<rev>]\"),\n> +\tN_(\"git bisect (good|old) [<rev>...]\"),\n> +\tN_(\"git bisect terms [--term-good | --term-bad]\"),\n> +\tN_(\"git bisect skip [(<rev>|<range>)...]\"),\n> +\tN_(\"git bisect next\"),\n> +\tN_(\"git bisect reset [<commit>]\"),\n> +\tN_(\"git bisect (visualize|view)\"),\n> +\tN_(\"git bisect replay <logfile>\"),\n> +\tN_(\"git bisect log\"),\n> +\tN_(\"git bisect run <cmd>...\"),\n> +\tNULL\n> +};\n\nParts of this are erroneously reverting bits of 959d670d1a4 (i18n:\nremove from i18n strings that do not hold translatable parts,\n2022-01-31).\n\nI.e. the N_() should not be there in cases like \"git bisect next\", only\ncommands that have placeholders like \"<rev>\".\n\n> +static const char * const 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> +\tNULL\n> +};\n\nRather than copy/pasting these we can define them once & re-use that\ndefinition with a macro. See builtin/commit-graph.c and 8757b35d443\n(commit-graph: define common usage with a macro, 2021-08-23).\n\n(Ditto elided below)\n\n> +\targc = parse_options(argc, argv, prefix, options,\n> +\t\t\t     bisect_reset_usage,  PARSE_OPT_STOP_AT_NON_OPTION);\n\nNit: Stray \" \" (double space) here in the argument list.\n\n>  \t\tprintf(_(\"Your current terms are %s for the old state\\n\"\n>  \t\t\t \"and %s for the new state.\\n\"),\n>  \t\t       terms.term_good, terms.term_bad);\n>  \t\treturn 0;\n\nUsing '%s'-quoting here for the interpolated terms would help\ntranslators & normalize this with other bessages. It was (partially)\nlike this in the pre-image, but since we're changing the whole string\nanyway...\n\n> +\tif (argc > 0)\n> +\t\tusage_msg_opt(_(\"requires 0 argument\"),\n> +\t\t\t      bisect_next_usage, options);\n\nEarlier a message says \"requires either no argument[...]\", but here we\nsay \"requires 0 argument\", which sounds like it expects a literal \"0\" in\nthe argument list.\n\nBut what we actually mean is \"requires no arguments\", let's change the\nstring to that.\n\n> -\t}\n> +\n\nHere's a \"whitespace change while at it...\"...\n\n>  finish:\n> +\tstrvec_clear(&orig_argv);\n> +\n\nDitto here, why make this clear/release visually separate from the\ncleanup below?:\n\n>  \tstring_list_clear(&revs, 0);\n>  \tstring_list_clear(&states, 0);\n>  \tstrbuf_release(&start_head);\n\n^^^ i.e. this.\n\n> @@ -1004,8 +1135,10 @@ static int process_replay_line(struct strbuf *line)\n>  \tif (!strcmp(p, \"start\")) {\n>  \t\tstruct strvec argv = STRVEC_INIT;\n>  \t\tint res;\n> +\n\nDitto whitespace change here...\n\n> +\t\tstrvec_push(&argv, p);\n>  \t\tsq_dequote_to_strvec(rev, &argv);\n> [...]\n>  \t\tstruct strvec argv = STRVEC_INIT;\n>  \t\tint res;\n> +\n\n...and here.., I think these are good, but they add up, perhaps worth\nsplitting up various whitespace-prettification in this series for\nreadability into its own commit.\n\n> [...]\n> @@ -1272,105 +1445,26 @@ static int bisect_run(int argc, const char **argv)\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> +\tparse_opt_subcommand_fn *fn = NULL;\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-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(\"run\", &fn, cmd_bisect_run),\n>  \t\tOPT_END()\n>  \t};\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> -\n> -\tif (!cmdmode)\n> -\t\tusage_with_options(git_bisect_helper_usage, options);\n> +\t\t\t     bisect_usage, 0);\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(argc == 1 ? argv[0] : NULL);\n> -\t\tbreak;\n> -\tcase BISECT_START:\n> -\t\tset_terms(\"bad\", \"good\");\n> -\t\tres = bisect_start(argc, argv);\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();\n> -\t\tres = bisect_next(prefix);\n> -\t\tbreak;\n> -\tcase BISECT_STATE:\n> -\t\tset_terms(\"bad\", \"good\");\n> -\t\tget_terms();\n> -\t\tres = bisect_state(argc, argv);\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(\"bad\", \"good\");\n> -\t\tres = bisect_replay(argv[0]);\n> -\t\tbreak;\n> -\tcase BISECT_SKIP:\n> -\t\tset_terms(\"bad\", \"good\");\n> -\t\tget_terms();\n> -\t\tres = bisect_skip(argc, argv);\n> -\t\tbreak;\n> -\tcase BISECT_VISUALIZE:\n> -\t\tget_terms();\n> -\t\tres = bisect_visualize(argc, argv);\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();\n> -\t\tres = bisect_run(argc, argv);\n> -\t\tbreak;\n> -\tdefault:\n> -\t\tBUG(\"unknown subcommand %d\", cmdmode);\n> -\t}\n> +\tres = fn(argc, argv, prefix);\n>  \tfree_terms();\n\nThe real meat of this is here, and looks much better on top of SZEDER's\nseries in \"next\" ...\n\n>  \n>  \treturn is_bisect_success(res) ? 0 : -res;\n> diff --git a/git-bisect.sh b/git-bisect.sh\n> index 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\n\n...I did wonder if OPT_SUBCOMMAND() supported subcommands \"--like-this\"\nas opposed to \"this\", if so the renaming of all of these could be split\nup into its own change.\n\nMaybe not worth it, but it's a very large commit, which does at least:\n\n * Migration to that new API\n * Stray whitespace changes while at it\n * Migrating the sub-command functions themselves to parse_options()\n   (good!), but not strictly required for OPT_SUBCOMMAND() (an\n   orthagonal change).\n * Renaming the \"verbs\" for the internal helper from\n   e.g. \"--bisect-skip\" to \"skip\", which is what we want eventually, but\n   does inflate the almost 500-line change.\n\n"},{"id":"462076","messageId":"220829.86sflf2w57.gmgdl@evledraar.gmail.com","threadId":"57326","inReplyTo":"8a0adfe3867157102e75d53ed928603ad634b904.1661604264.git.gitgitgadget@gmail.com","subject":"Re: [PATCH v5 11/16] bisect--helper: calling `bisect_state()` without an argument is a bug","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-29T10:11:21Z","receivedAt":"2022-08-29T10:16:24Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Sat, Aug 27 2022, Johannes Schindelin via GitGitGadget wrote:\n\n> From: Johannes Schindelin <johannes.schindelin@gmx.de>\n>\n> The `bisect_state()` function is now a purely internal function and must\n> be called with a valid state, everything else is a bug.\n\nI'm confused by the \"is now purely an internal\", when did that happen\nexactly? That wording is new in this v5.\n\nBefore this series wasn't the only caller \"internal\" (git-bisect.sh) as\nwell? From the CL:\n\n     -    bisect--helper: using `--bisect-state` without an argument is a bug\n     +    bisect--helper: calling `bisect_state()` without an argument is a bug\n      \n     -    The `bisect--helper` command is not expected to be used directly by the\n     -    user. Therefore, it is a bug if it receives no argument to the\n     -    `--bisect-state` command mode, not a user error. Which means that we\n     -    need to call `BUG()` instead of `die()`.\n     +    The `bisect_state()` function is now a purely internal function and must\n     +    be called with a valid state, everything else is a bug.\n\nBefore the migration to OPT_SUBCOMMAND earlier in this series:\n\n\t$ ./git bisect--helper state\n\tusage: git bisect--helper --bisect-reset [<commit>]\n\t   or: git bisect--helper --bisect-terms [--term-good | --term-old | --term-bad | --term-new]\n\t   or: git bisect--helper --bisect-start [--term-{new,bad}=<term> --term-{old,good}=<term>] [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<paths>...]\n\t   or: git bisect--helper --bisect-next\n\t   or: git bisect--helper --bisect-state (bad|new) [<rev>]\n\t   or: git bisect--helper --bisect-state (good|old) [<rev>...]\n\t   or: git bisect--helper --bisect-replay <filename>\n\t   or: git bisect--helper --bisect-skip [(<rev>|<range>)...]\n\t   or: git bisect--helper --bisect-visualize\n\t   or: git bisect--helper --bisect-run <cmd>...\n\n\t    --bisect-reset        reset the bisection state\n\t    --bisect-terms        print out the bisect terms\n\t    --bisect-start        start the bisect session\n\t    --bisect-next         find the next bisection commit\n\t    --bisect-state        mark the state of ref (or refs)\n\t    --bisect-log          list the bisection steps so far\n\t    --bisect-replay       replay the bisection process from the given file\n\t    --bisect-skip         skip some commits for checkout\n\t    --bisect-visualize    visualize the bisection\n\t    --bisect-run          use <cmd>... to automatically bisect\n\nAfter that:\n\n\t$ ./git bisect--helper state \n\tfatal: need at least one argument\n\n\tusage: git bisect (good|bad) [<rev>...]\n\nSo intra-series we were showing the wrong SYNOPSIS for this\ninternal-only command. I don't think that matters per-se (and the\nend-state fixes it up), but doesn't it point to some ordering oddity\nhere?\n\nAFAICT we couldn't call \"state\" without an argument from git-bisect.sh\nbefore, and that's the only (and internal) caller, so shouldn't this\nBUG() come earlier?\n"},{"id":"462077","messageId":"220829.86o7w32vv2.gmgdl@evledraar.gmail.com","threadId":"57326","inReplyTo":"92b3b116ef8f879192d9deb94d68b73e29d5dcd6.1661604264.git.gitgitgadget@gmail.com","subject":"Re: [PATCH v5 05/16] bisect--helper: make `terms` an explicit singleton","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-29T10:20:13Z","receivedAt":"2022-08-29T10:21:43Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Sat, Aug 27 2022, Johannes Schindelin via GitGitGadget wrote:\n\n> From: Johannes Schindelin <johannes.schindelin@gmx.de>\n> [...]\n> -\tfree((void *)terms->term_good);\n> -\tterms->term_good = xstrdup(good);\n> -\tfree((void *)terms->term_bad);\n> -\tterms->term_bad = xstrdup(bad);\n> +\tfree((void *)terms.term_good);\n> +\tterms.term_good = xstrdup(good);\n> +\tfree((void *)terms.term_bad);\n> +\tterms.term_bad = xstrdup(bad);\n>  }\n\nThis is pre-existing, and dates back to 0f30233a11f (bisect--helper:\n`bisect_write` shell function in C, 2019-01-02), but it appears this\ncast to a \"void *\" was never needed. Perhaps some C++-ism that crept in\nhere?\n\nAs we're changing this all around perhaps it's worth droppping the cast,\nor it could be left for some other \"remove redundant casts\" series.\n"},{"id":"462084","messageId":"662758rn-942n-1n3s-25r9-o7qn071s0567@tzk.qr","threadId":"57326","inReplyTo":"xmqqk06svoxp.fsf@gitster.g","subject":"Re: [PATCH v5 05/16] bisect--helper: make `terms` an explicit singleton","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2022-08-29T12:13:48Z","receivedAt":"2022-08-29T12:31:10Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Sat, 27 Aug 2022, Junio C Hamano wrote:\n\n> \"Johannes Schindelin via GitGitGadget\" <gitgitgadget@gmail.com>\n> writes:\n>\n> > -struct bisect_terms {\n> > +static struct bisect_terms {\n> >  \tchar *term_good;\n> >  \tchar *term_bad;\n> > -};\n> > +} terms;\n>\n> On the surface, more global state may feel sad, but I do not think\n> we want to run multiple bisection in one session anyway.  Overall\n> this may result in a simplicity win, hopefully.\n>\n> The patch is noisy, but mostly from rewriting \"terms->member\" to\n> \"terms.member\".  I am not sure if that was worth the effort, though.\n> You had a code that plumbed a parameter through the call graph, and\n> instead of destroying that arrangement, you could have just replaced\n> the reference at the beginning of the call chain to use the global\n> state instead of an on-stack variable that the caller used to have.\n>\n> I have no strong preference, but I do not think that it particularly\n> contributes to \"clarifying that we are using global state\" to make\n> direct accesses to the variable everywhere.  I dunno.\n\nI do have a strong preference to avoid mixing and matching global\nvariables with functions that pretend not to use said global variables, as\nit is too easy to forget to pass through the corresponding parameter to a\nfunction at a lower layer when that function accesses the global variable\nanyway.\n\nCiao,\nDscho\n"},{"id":"462086","messageId":"06q285oq-np8q-qpo1-s470-74q5s3s3478o@tzk.qr","threadId":"57326","inReplyTo":"xmqq8rn8voh2.fsf@gitster.g","subject":"Re: [PATCH v5 09/16] bisect run: fix the error message","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2022-08-29T12:20:05Z","receivedAt":"2022-08-29T12:37:09Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Sun, 28 Aug 2022, Junio C Hamano wrote:\n\n> \"Johannes Schindelin via GitGitGadget\" <gitgitgadget@gmail.com>\n> writes:\n>\n> > From: Johannes Schindelin <johannes.schindelin@gmx.de>\n> >\n> > In d1bbbe45df8 (bisect--helper: reimplement `bisect_run` shell function\n> > in C, 2021-09-13), we ported the `bisect run` subcommand to C, including\n> > the part that prints out an error message when the implicit `git bisect\n> > bad` or `git bisect good` failed.\n> >\n> > However, the error message was supposed to print out whether the state\n> > was \"good\" or \"bad\", but used a bogus (because non-populated) `args`\n> > variable for it.\n> >\n> > Helped-by: Elijah Newren <newren@gmail.com>\n> > Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> > ---\n> >  builtin/bisect--helper.c    |  2 +-\n> >  t/t6030-bisect-porcelain.sh | 10 ++++++++++\n> >  2 files changed, 11 insertions(+), 1 deletion(-)\n> >\n> > diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\n> > index d797cd1cef8..a00167f1373 100644\n> > --- a/builtin/bisect--helper.c\n> > +++ b/builtin/bisect--helper.c\n> > @@ -1430,7 +1430,7 @@ static int cmd_bisect_run(int argc, const char **argv, const char *prefix)\n> >  \t\t\tprintf(_(\"bisect found first bad commit\"));\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: 'git bisect\"\n> >  \t\t\t\" %s' exited with error code %d\"), new_state, res);\n> >  \t\t} else {\n> >  \t\t\tcontinue;\n>\n> The change to retire \"bisect--helper\" from the end-user facing error\n> message makes tons of sense, but I am not quite sure if the proposed\n> log message describes the change correctly.  Or is this a fallout of\n> some \"rebase -i\" gotcha that a log message meant for one commit was\n> applied to a different commit, or something?\n\nThis is indeed a fall-out from some interactive rebase. Thank you for\ncatching it.\n\nYou can actually see it in the thread history: v2 still had a diff that\nwas aligned with the commit message, but\n<46fe0774-66e7-8947-cd79-d35229eec25a@web.de> graduated between v2 and v3\nand partially addressed the issue fixed by this here patch.\n\nI'm glad that we caught this in time for v6. This is the commit message I\nplan on using:\n\n-- snip --\n    bisect run: fix the error message\n\n    In d1bbbe45df8 (bisect--helper: reimplement `bisect_run` shell function\n    in C, 2021-09-13), we ported the `bisect run` subcommand to C, including\n    the part that prints out an error message when the implicit `git bisect\n    bad` or `git bisect good` failed.\n\n    However, the error message was supposed to print out whether the state\n    was \"good\" or \"bad\", but used a bogus (because non-populated) `args`\n    variable for it. This was fixed in 80c2e9657f2 (bisect--helper: report\n    actual bisect_state() argument on error, 2022-01-18), but the error\n    message still talks about `bisect--helper`, which is an implementation\n    detail that should not concern end users.\n\n    Fix that, and add a regression test to ensure that the intended form of\n    the error message.\n-- snap --\n\nCiao,\nDscho\n"},{"id":"462087","messageId":"s47684sr-p257-31n6-5qr7-0p29490rsp7q@tzk.qr","threadId":"57326","inReplyTo":"220829.86o7w32vv2.gmgdl@evledraar.gmail.com","subject":"Re: [PATCH v5 05/16] bisect--helper: make `terms` an explicit singleton","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2022-08-29T12:30:48Z","receivedAt":"2022-08-29T12:46:36Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Ævar,\n\nOn Mon, 29 Aug 2022, Ævar Arnfjörð Bjarmason wrote:\n\n>\n> On Sat, Aug 27 2022, Johannes Schindelin via GitGitGadget wrote:\n>\n> > From: Johannes Schindelin <johannes.schindelin@gmx.de>\n> > [...]\n> > -\tfree((void *)terms->term_good);\n> > -\tterms->term_good = xstrdup(good);\n> > -\tfree((void *)terms->term_bad);\n> > -\tterms->term_bad = xstrdup(bad);\n> > +\tfree((void *)terms.term_good);\n> > +\tterms.term_good = xstrdup(good);\n> > +\tfree((void *)terms.term_bad);\n> > +\tterms.term_bad = xstrdup(bad);\n> >  }\n>\n> This is pre-existing, and dates back to 0f30233a11f (bisect--helper:\n> `bisect_write` shell function in C, 2019-01-02), but it appears this\n> cast to a \"void *\" was never needed. Perhaps some C++-ism that crept in\n> here?\n\nWhile this is all true, this feedback is about code that is not changed by\nthis patch.\n\nI am afraid that this review therefore misses the intention of the patch.\n\nCiao,\nJohannes\n"},{"id":"462098","messageId":"xmqqy1v7ouav.fsf@gitster.g","threadId":"57326","inReplyTo":"662758rn-942n-1n3s-25r9-o7qn071s0567@tzk.qr","subject":"Re: [PATCH v5 05/16] bisect--helper: make `terms` an explicit singleton","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-08-29T17:04:24Z","receivedAt":"2022-08-29T17:05:18Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n>> I have no strong preference, but I do not think that it particularly\n>> contributes to \"clarifying that we are using global state\" to make\n>> direct accesses to the variable everywhere.  I dunno.\n>\n> I do have a strong preference to avoid mixing and matching global\n> variables with functions that pretend not to use said global variables, as\n> it is too easy to forget to pass through the corresponding parameter to a\n> function at a lower layer when that function accesses the global variable\n> anyway.\n\nWhen you have a truly well \"libified\" API and a program that needs\nto use global to communicate to other parts of the system, then the\napproach I suggested would follow a much better design taste.  For\nexample, if your program takes an argument --option=string, and you\nfor whatever reason have to use a global variable to store the value\ndue to limitation of your option parsing API, you'd create a global\nvariable to store the string.  But well libified API functions (say,\nthe ones from the C library) do not have to care if you are using a\nglobal or an on-stack variable.  I would not rewrite strlen(const\nchar *) to my_strlen(void) that only looks at the global variable\nand use it instead.\n\nBut it is quite possible that bisect--helper may not have such a\nclean interface, in which case it is pefectly OK for everybody to\nlook at the global directly.  My comment was mostly a reaction based\non the assumption that your earlier \"libifyable state\" comment meant\nthat these call graphs are nicely libified and pass everything they\nneed through via parameters, in which case, the ultimate callers of\nthese helper functions that take \"struct bisect_terms *\", like\nfree_terms(), may have the parameter they pass down to the callchain\non their stack, and now have to pass a pointer to a global, without\nthe callchain that is \"as libified as possible\" having to know.\n\n\n\n"},{"id":"462102","messageId":"xmqqedwzndqm.fsf@gitster.g","threadId":"57326","inReplyTo":"220829.86o7w32vv2.gmgdl@evledraar.gmail.com","subject":"Re: [PATCH v5 05/16] bisect--helper: make `terms` an explicit singleton","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-08-29T17:47:29Z","receivedAt":"2022-08-29T17:47:34Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n\n> On Sat, Aug 27 2022, Johannes Schindelin via GitGitGadget wrote:\n>\n>> From: Johannes Schindelin <johannes.schindelin@gmx.de>\n>> [...]\n>> -\tfree((void *)terms->term_good);\n>> -\tterms->term_good = xstrdup(good);\n>> -\tfree((void *)terms->term_bad);\n>> -\tterms->term_bad = xstrdup(bad);\n>> +\tfree((void *)terms.term_good);\n>> +\tterms.term_good = xstrdup(good);\n>> +\tfree((void *)terms.term_bad);\n>> +\tterms.term_bad = xstrdup(bad);\n>>  }\n>\n> This is pre-existing, and dates back to 0f30233a11f (bisect--helper:\n> `bisect_write` shell function in C, 2019-01-02), but it appears this\n> cast to a \"void *\" was never needed. Perhaps some C++-ism that crept in\n> here?\n>\n> As we're changing this all around perhaps it's worth droppping the cast,\n> or it could be left for some other \"remove redundant casts\" series.\n\nNice to notice it.  I suspect that at some point in the evolution of\nthe offending patch in 2019 the members were of type \"const char *\"\nand needed to cast the constness away, or something, perhaps?\n\nIn any case, such a change belongs to either preliminary clean-up\nbefore the series, or post clean-up after the dust settles, not\nsomething we'd want to see \"while we are at it\" to distract us.\n"},{"id":"462202","messageId":"5594qo11-716s-61qn-2rn9-q114199sp3p0@tzk.qr","threadId":"57326","inReplyTo":"220829.86sflf2w57.gmgdl@evledraar.gmail.com","subject":"Re: [PATCH v5 11/16] bisect--helper: calling `bisect_state()` without an argument is a bug","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2022-08-30T14:47:26Z","receivedAt":"2022-08-30T14:47:37Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Ævar,\n\nOn Mon, 29 Aug 2022, Ævar Arnfjörð Bjarmason wrote:\n\n>\n> On Sat, Aug 27 2022, Johannes Schindelin via GitGitGadget wrote:\n>\n> > From: Johannes Schindelin <johannes.schindelin@gmx.de>\n> >\n> > The `bisect_state()` function is now a purely internal function and must\n> > be called with a valid state, everything else is a bug.\n>\n> I'm confused by the \"is now purely an internal\", when did that happen\n> exactly? That wording is new in this v5.\n\nYes, it is new. It is part of that huge amount of work to not only convert\nthe script to a built-in but also \"while at it\" migrate the entire\n`bisect--helper` on top of the subcommand API, as you specifically asked\nfor, and it was that ask that blocked the patch series which would\nprobably otherwise have been accepted as-is, with the subcommand migration\nleft as a follow-up patch series with a much narrower scope than the\ncurrent iteration.\n\nAs to when it happened exactly? In 07/16 of this patch series iteration,\nas explained as part of the commit message:\n\n\tNote that a couple of `bisect_*()` functions are not converted into\n\t`cmd_bisect_*()` functions directly, as they have callers other than the\n\t`OPT_SUBCOMMAND()` one (and the original functions did not expect\n\ta subcommand name to be passed as `argv[0]`, unlike the convention for\n\tthe `cmd_*()` functions. In those cases, we introduce wrapper functions\n\t`cmd_*()` that also call the original function.\n\nI did not repeat in the commit message all details that the diff explains\nmuch more eloquently, such as `cmd_bisect_state()` now being a wrapper\naround `bisect_state()`.\n\n> Before this series wasn't the only caller \"internal\" (git-bisect.sh) as\n> well? From the CL:\n>\n>      -    bisect--helper: using `--bisect-state` without an argument is a bug\n>      +    bisect--helper: calling `bisect_state()` without an argument is a bug\n>\n>      -    The `bisect--helper` command is not expected to be used directly by the\n>      -    user. Therefore, it is a bug if it receives no argument to the\n>      -    `--bisect-state` command mode, not a user error. Which means that we\n>      -    need to call `BUG()` instead of `die()`.\n>      +    The `bisect_state()` function is now a purely internal function and must\n>      +    be called with a valid state, everything else is a bug.\n>\n> Before the migration to OPT_SUBCOMMAND earlier in this series:\n>\n> \t$ ./git bisect--helper state\n> \tusage: git bisect--helper --bisect-reset [<commit>]\n> \t   or: git bisect--helper --bisect-terms [--term-good | --term-old | --term-bad | --term-new]\n> \t   or: git bisect--helper --bisect-start [--term-{new,bad}=<term> --term-{old,good}=<term>] [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<paths>...]\n> \t   or: git bisect--helper --bisect-next\n> \t   or: git bisect--helper --bisect-state (bad|new) [<rev>]\n> \t   or: git bisect--helper --bisect-state (good|old) [<rev>...]\n> \t   or: git bisect--helper --bisect-replay <filename>\n> \t   or: git bisect--helper --bisect-skip [(<rev>|<range>)...]\n> \t   or: git bisect--helper --bisect-visualize\n> \t   or: git bisect--helper --bisect-run <cmd>...\n>\n> \t    --bisect-reset        reset the bisection state\n> \t    --bisect-terms        print out the bisect terms\n> \t    --bisect-start        start the bisect session\n> \t    --bisect-next         find the next bisection commit\n> \t    --bisect-state        mark the state of ref (or refs)\n> \t    --bisect-log          list the bisection steps so far\n> \t    --bisect-replay       replay the bisection process from the given file\n> \t    --bisect-skip         skip some commits for checkout\n> \t    --bisect-visualize    visualize the bisection\n> \t    --bisect-run          use <cmd>... to automatically bisect\n>\n> After that:\n>\n> \t$ ./git bisect--helper state\n> \tfatal: need at least one argument\n>\n> \tusage: git bisect (good|bad) [<rev>...]\n>\n> So intra-series we were showing the wrong SYNOPSIS for this\n> internal-only command. I don't think that matters per-se (and the\n> end-state fixes it up), but doesn't it point to some ordering oddity\n> here?\n>\n> AFAICT we couldn't call \"state\" without an argument from git-bisect.sh\n> before, and that's the only (and internal) caller, so shouldn't this\n> BUG() come earlier?\n\nYes, it could come earlier. Or later. It is part of some follow-up patches\nthat need to come after 07/16, in whatever order.\n\nI appreciate that you want to help.\n\nMy concern is that by having to focus on answering such questions that I\nconsider a thorough review of the iteration to answer handily, I cannot\nspend the same time and focus on preventing bugs I consider a lot more\ncritical. We saw some bug reports about the built-in `add -i` recently,\nfor example, that could have been prevented if the focus of the code\nreview was not so much on details that the end user won't ever see (such\nas the order of patches or whether to broaden the scope and size of a\npatch series instead of leaving follow-up work to subsequent patch\nseries), and more on unintentional changes that the users very much\nexperience, and not in a good way. I would appreciate it a lot if we could\nfocus first and foremost on preventing bugs cause problems to Git's users.\n\nThank you,\nJohannes\n"},{"id":"462208","messageId":"61rq5601-o016-3006-3p67-o56307109qq5@tzk.qr","threadId":"57326","inReplyTo":"220829.86wnar2wus.gmgdl@evledraar.gmail.com","subject":"Re: [PATCH v5 07/16] bisect--helper: migrate to OPT_SUBCOMMAND()","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2022-08-30T15:42:52Z","receivedAt":"2022-08-30T15:43:04Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Ævar,\n\nOn Mon, 29 Aug 2022, Ævar Arnfjörð Bjarmason wrote:\n\n> On Sat, Aug 27 2022, Johannes Schindelin via GitGitGadget wrote:\n>\n> > From: Johannes Schindelin <johannes.schindelin@gmx.de>\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> > +static const char * const bisect_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> > +\tN_(\"git bisect (bad|new) [<rev>]\"),\n> > +\tN_(\"git bisect (good|old) [<rev>...]\"),\n> > +\tN_(\"git bisect terms [--term-good | --term-bad]\"),\n> > +\tN_(\"git bisect skip [(<rev>|<range>)...]\"),\n> > +\tN_(\"git bisect next\"),\n> > +\tN_(\"git bisect reset [<commit>]\"),\n> > +\tN_(\"git bisect (visualize|view)\"),\n> > +\tN_(\"git bisect replay <logfile>\"),\n> > +\tN_(\"git bisect log\"),\n> > +\tN_(\"git bisect run <cmd>...\"),\n> > +\tNULL\n> > +};\n>\n> Parts of this are erroneously reverting bits of 959d670d1a4 (i18n:\n> remove from i18n strings that do not hold translatable parts,\n> 2022-01-31).\n\nThat is misreading what this patch does. I did not turn the pre-image into\nthe post-image.\n\nAs the commit message states, we now use the subcommand API with the\nintention to replace the `git-bisect.sh` script altogether (that's written\nin the first paragraph of the proposed commit message).\n\nThis means that the command modes are replaced by subcommands, and the\nusage of the subcommands is copied from the script.\n\nAnd that is the reason why you see a usage about `view` and `log`, as I\nassume you noticed.\n\nBy the way, this here distraction makes a really fine case why it would\nhave been better to leave the migration to the subcommand API to a\nfollow-up patch series. You will recall that I favored that, and I would\nhave loved for you to agree.\n\nHaving said that, it is a good point that we do not want to reintroduce\nthe problem that was fixed by 959d670d1a4 (i18n: remove from i18n strings\nthat do not hold translatable parts, 2022-01-31).\n\n> I.e. the N_() should not be there in cases like \"git bisect next\", only\n> commands that have placeholders like \"<rev>\".\n>\n> > +static const char * const 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> > +\tNULL\n> > +};\n>\n> Rather than copy/pasting these we can define them once & re-use that\n> definition with a macro. See builtin/commit-graph.c and 8757b35d443\n> (commit-graph: define common usage with a macro, 2021-08-23).\n\nI would do this if I found it elegant.\n\n> (Ditto elided below)\n>\n> > +\targc = parse_options(argc, argv, prefix, options,\n> > +\t\t\t     bisect_reset_usage,  PARSE_OPT_STOP_AT_NON_OPTION);\n>\n> Nit: Stray \" \" (double space) here in the argument list.\n\nGood find! Will fix. And obviously not only the `reset` case.\n\n>\n> >  \t\tprintf(_(\"Your current terms are %s for the old state\\n\"\n> >  \t\t\t \"and %s for the new state.\\n\"),\n> >  \t\t       terms.term_good, terms.term_bad);\n> >  \t\treturn 0;\n>\n> Using '%s'-quoting here for the interpolated terms would help\n> translators & normalize this with other bessages. It was (partially)\n> like this in the pre-image, but since we're changing the whole string\n> anyway...\n\nIt is a bad practice to draw out code contributions by asking contributors\nto add unrelated changes. This here mail thread presents a fine example\nwhy. Let's avoid doing that from now on.\n\n> > +\tif (argc > 0)\n> > +\t\tusage_msg_opt(_(\"requires 0 argument\"),\n> > +\t\t\t      bisect_next_usage, options);\n>\n> Earlier a message says \"requires either no argument[...]\", but here we\n> say \"requires 0 argument\", which sounds like it expects a literal \"0\" in\n> the argument list.\n\nAs you undoubtedly noticed, this message was moved from the\n`cmd_bisect__helper()` function, with its `--bisect-next` part deleted\n(because it is incorrect now that we no longer have command modes).\n\n> But what we actually mean is \"requires no arguments\", let's change the\n> string to that.\n\nNo, let's not. For the same reason as noted above.\n\n> > -\t}\n> > +\n>\n> Here's a \"whitespace change while at it...\"...\n\nThis removes a curly bracket and adds an empty line. You are referring to\nthe empty line?\n\nIt is a bit hard to understand what you mean, not only because of the lack\nof clarity but also because too much context was clipped to easily find\nthe part of the patch that you were referring to. Please be more\nconsiderate in the future.\n\nI have to assume that you are referring to a tiny part of one hunk that\ndescribes how `bisect_start()` became `cmd_bisect_start()`. If that is\nindeed what you were referring to, then you are talking about a hunk that\nseemingly replaces a `for (i = 0; i < argc; i++)` loop that parses the\ncommand-line with a loop that validates that only revision parameters are\nspecified before the double dash, if any. In other words, the \"introduced\"\nwhite-space is part of a completely new loop.\n\n>\n> >  finish:\n> > +\tstrvec_clear(&orig_argv);\n> > +\n>\n> Ditto here, why make this clear/release visually separate from the\n> cleanup below?:\n>\n> >  \tstring_list_clear(&revs, 0);\n> >  \tstring_list_clear(&states, 0);\n> >  \tstrbuf_release(&start_head);\n>\n> ^^^ i.e. this.\n\nBecause the latter statements clean up data structures that were used for\nthe core functionality of `bisect start`, while the `orig_argv` purely\nwere a copy for the sake of the bisect log. Therefore, they are logically\nseparate, and the empty line helps readers such as myself.\n\n>\n> > @@ -1004,8 +1135,10 @@ static int process_replay_line(struct strbuf *line)\n> >  \tif (!strcmp(p, \"start\")) {\n> >  \t\tstruct strvec argv = STRVEC_INIT;\n> >  \t\tint res;\n> > +\n>\n> Ditto whitespace change here...\n>\n> > +\t\tstrvec_push(&argv, p);\n> >  \t\tsq_dequote_to_strvec(rev, &argv);\n> > [...]\n> >  \t\tstruct strvec argv = STRVEC_INIT;\n> >  \t\tint res;\n> > +\n>\n> ...and here.., I think these are good, but they add up, perhaps worth\n> splitting up various whitespace-prettification in this series for\n> readability into its own commit.\n>\n> > [...]\n> > @@ -1272,105 +1445,26 @@ static int bisect_run(int argc, const char **argv)\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> > +\tparse_opt_subcommand_fn *fn = NULL;\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-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(\"run\", &fn, cmd_bisect_run),\n> >  \t\tOPT_END()\n> >  \t};\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> > -\n> > -\tif (!cmdmode)\n> > -\t\tusage_with_options(git_bisect_helper_usage, options);\n> > +\t\t\t     bisect_usage, 0);\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(argc == 1 ? argv[0] : NULL);\n> > -\t\tbreak;\n> > -\tcase BISECT_START:\n> > -\t\tset_terms(\"bad\", \"good\");\n> > -\t\tres = bisect_start(argc, argv);\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();\n> > -\t\tres = bisect_next(prefix);\n> > -\t\tbreak;\n> > -\tcase BISECT_STATE:\n> > -\t\tset_terms(\"bad\", \"good\");\n> > -\t\tget_terms();\n> > -\t\tres = bisect_state(argc, argv);\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(\"bad\", \"good\");\n> > -\t\tres = bisect_replay(argv[0]);\n> > -\t\tbreak;\n> > -\tcase BISECT_SKIP:\n> > -\t\tset_terms(\"bad\", \"good\");\n> > -\t\tget_terms();\n> > -\t\tres = bisect_skip(argc, argv);\n> > -\t\tbreak;\n> > -\tcase BISECT_VISUALIZE:\n> > -\t\tget_terms();\n> > -\t\tres = bisect_visualize(argc, argv);\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();\n> > -\t\tres = bisect_run(argc, argv);\n> > -\t\tbreak;\n> > -\tdefault:\n> > -\t\tBUG(\"unknown subcommand %d\", cmdmode);\n> > -\t}\n> > +\tres = fn(argc, argv, prefix);\n> >  \tfree_terms();\n>\n> The real meat of this is here, and looks much better on top of SZEDER's\n> series in \"next\" ...\n\nBeauty is no quality in things themselves: It exists merely in the mind\nwhich contemplates them; and each mind perceives a different beauty.\n\nPlus, this hunk cannot be taken out of context: It requires all the\nlengthy hunks that come before it, and that are relatively hard to parse\nas you found out.\n\n> >\n> >  \treturn is_bisect_success(res) ? 0 : -res;\n> > diff --git a/git-bisect.sh b/git-bisect.sh\n> > index 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\n>\n> ...I did wonder if OPT_SUBCOMMAND() supported subcommands \"--like-this\"\n> as opposed to \"this\", if so the renaming of all of these could be split\n> up into its own change.\n>\n> Maybe not worth it, but it's a very large commit, which does at least:\n>\n>  * Migration to that new API\n>  * Stray whitespace changes while at it\n>  * Migrating the sub-command functions themselves to parse_options()\n>    (good!), but not strictly required for OPT_SUBCOMMAND() (an\n>    orthagonal change).\n>  * Renaming the \"verbs\" for the internal helper from\n>    e.g. \"--bisect-skip\" to \"skip\", which is what we want eventually, but\n>    does inflate the almost 500-line change.\n\nThese suggestions could very easily be construed to be intentionally\ndrawing out a patch contribution that pretty much all other participants\nin the mail thread have expressed a desire to be done with.\n\nI do understand that you care a lot about these details and about\nwhite-space and the parse_options API.\n\nPlease do understand that I care about the correctness of the code, and\nwish I could see more suggestions between all those suggestions that would\nbe conducive to further that goal.\n\nThis is a complex patch, to be sure, and it is pretty much solely due to\nhaving had to include the move from the command-mode paradigm to the\nsubcommand paradigm in the patch series, which I would very much have\npreferred to do in a separate patch series.\n\nCould that move have been done more incrementally? Maybe. I tried to split\nit up as much as I could _without_ losing focus of the actual goal of this\npatch series: the conversion from a script that implemented the `bisect`\noperation to a pure built-in that is supposed to perform the same\noperation without introducing regressions. If it were a follow-up patch\nseries whose sole intention is to migrate `git bisect` to the subcommand\nAPI, I would have been eager to spent more time on making it more\nincremental. However, the goal of this patch series was, and is, to finish\nthe conversion of `git bisect` from a script to a built-in.\n\nThat goal was unfortuntely made a lot harder than I wanted to by the\nfeedback I received, and I really wish that it would have been easier to\nconvert `git-bisect.sh` to `builtin/bisect.c`. I would see the feedback in\nmore favorable light if I could see how that feedback furthered that goal,\nbut I have a hard time finding enough evidence that I could consider to\nmerit 5 iterations and 7 months of work.\n\nI want to be clear: any feedback you provide that helps me improve the\nquality and correctness of my patches is appreciated. Your feedback where\nyou pointed out that my v5 would regress on 959d670d1a4 (i18n: remove from\ni18n strings that do not hold translatable parts, 2022-01-31) is such a\nfeedback. I want to see more of that kind of feedback from you, and will\nnot hold it against you if you reduce tangential feedback in order to do\nthat.\n\nThank you,\nJohannes\n"},{"id":"462211","messageId":"pull.1132.v6.git.1661885419.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v5.git.1661604264.gitgitgadget@gmail.com","subject":"[PATCH v6 00/16] Finish converting git bisect into a built-in","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-08-30T18:50:03Z","receivedAt":"2022-08-30T18:50:29Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"After three GSoC/Outreachy students spent an incredible effort on this, it\nis finally time to put a neat little bow on it, or maybe more like a big\nbow, maybe even a very large one, seeing as it takes quite a while to tie\n(half a year at the time of writing)...\n\nChanges since v5:\n\n * Fixed the commit message of \"bisect run: fix the error message\" that had\n   become stale as of v3 due to 80c2e9657f2 \"overtaking\" it and doing half\n   of its job.\n * Skipped translation usage strings in \"bisect--helper: migrate to\n   OPT_SUBCOMMAND()\" that do not contain translatable parts.\n * Minor white-space clean-up in \"bisect--helper: migrate to\n   OPT_SUBCOMMAND()\".\n\nChanges since v4:\n\n * rebased onto sg/parse-options-subcommand\n * migrated to OPT_SUBCOMMAND().\n * As a consequence, this patch series is now unfortunately very large. And\n   the range-diff is much less useful than I'd like because of the extensive\n   changes that were de facto made a precondition to moving this patch\n   series further. Junio, I would have liked to keep the scope (and burden\n   for the reviewers) substantially smaller, maybe you can help with the\n   review?\n\nChanges since v3:\n\n * Rebased because of merge conflicts with ab/plug-leak-in-revisions.\n * Fixed the bug that git bisect --bisect-terms 1 2 wanted to auto-start a\n   bisection if running with a git executable built at the in-between state\n   at patch \"bisect: move even the command-line parsing to bisect--helper\".\n   Since this bug was \"fixed\" in v3 by the very next patch, \"bisect: teach\n   the bisect--helper command to show the correct usage strings\", v4 avoids\n   introducing this bug simply by letting these two patches trade places.\n   The range-diff admittedly looks quite awful because both patches overlap\n   quite a bit in the lines they modify. The end result is the same, though,\n   the diff between v3's and v4's builtin/bisect.c would be empty if I\n   hadn't been forced to rebase.\n * Added a test case to ensure that this bug won't be introduced again. This\n   test case is the only actual difference relative to v3 of this patch\n   series.\n\nChanges since v2:\n\n * We're now careful to provide identical usage strings upon git bisect -h\n   and git bisect bogus.\n * When a bogus command is provided, we now error out instead of trying to\n   start a git bisect run.\n * Rebased onto main to avoid plenty of merge conflicts with\n   rs/bisect-executable-not-found, ac/usage-string-fixups and with\n   cd/bisect-messages-from-pre-flight-states.\n\nChanges since v1:\n\n * Added a regression test to \"bisect run: fix the error message\".\n * Added a patch to address an error message that double-single-quoted the\n   command.\n * Reworked the logic in \"bisect--helper: make --bisect-state optional\" to\n   delay showing the usage upon an unknown command, which should make the\n   code a lot less confusing.\n * Split out the change that moved the BISECT_STATE case to the end of the\n   switch block.\n * Added a patch that replaces the return error() calls in\n   cmd_bisect_helper() with die() calls, to avoid returning -1 as an exit\n   code.\n * Dropped the use of parse_options() for the single purpose of handling -h;\n   This is now done explicitly.\n * Simplified the diff of \"bisect: move even the option parsing to\n   bisect--helper\" by modifying argc and argv instead of modifying all the\n   function calls using those variables.\n * In the \"Turn git bisect into a full built-in\" patch, changed the name of\n   the variable holding the usage to use the builtin_ prefix used in other\n   built-ins, too.\n * Removed the trailing dot from the commit message of \"Turn git bisect into\n   a full built-in\".\n\nJohannes Schindelin (16):\n  bisect--helper: retire the --no-log option\n  bisect--helper: really retire --bisect-next-check\n  bisect--helper: really retire `--bisect-autostart`\n  bisect--helper: simplify exit code computation\n  bisect--helper: make `terms` an explicit singleton\n  bisect--helper: make the order consistently `argc, argv`\n  bisect--helper: migrate to OPT_SUBCOMMAND()\n  bisect: verify that a bogus option won't try to start a bisection\n  bisect run: fix the error message\n  bisect: avoid double-quoting when printing the failed command\n  bisect--helper: calling `bisect_state()` without an argument is a bug\n  bisect--helper: make `state` optional\n  bisect: move even the command-line parsing to `bisect--helper`\n  Turn `git bisect` into a full built-in\n  bisect: remove Cogito-related code\n  bisect: no longer try to clean up left-over `.git/head-name` files\n\n Makefile                               |   3 +-\n bisect.c                               |   3 -\n builtin.h                              |   2 +-\n builtin/{bisect--helper.c => bisect.c} | 679 ++++++++++++++-----------\n git-bisect.sh                          |  84 ---\n git.c                                  |   2 +-\n t/t6030-bisect-porcelain.sh            |  21 +-\n 7 files changed, 406 insertions(+), 388 deletions(-)\n rename builtin/{bisect--helper.c => bisect.c} (67%)\n delete mode 100755 git-bisect.sh\n\n\nbase-commit: 8f9d80f6c06369b563c76ec46c462e740a1a2cf0\nPublished-As: https://github.com/gitgitgadget/git/releases/tag/pr-1132%2Fdscho%2Fbisect-in-c-v6\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1132/dscho/bisect-in-c-v6\nPull-Request: https://github.com/gitgitgadget/git/pull/1132\n\nRange-diff vs v5:\n\n  1:  05262b6a7d1 =  1:  05262b6a7d1 bisect--helper: retire the --no-log option\n  2:  1e43148864a =  2:  1e43148864a bisect--helper: really retire --bisect-next-check\n  3:  1a1649d9d0d =  3:  1a1649d9d0d bisect--helper: really retire `--bisect-autostart`\n  4:  9ab30552c6a =  4:  9ab30552c6a bisect--helper: simplify exit code computation\n  5:  92b3b116ef8 =  5:  92b3b116ef8 bisect--helper: make `terms` an explicit singleton\n  6:  c9dc0281e38 =  6:  c9dc0281e38 bisect--helper: make the order consistently `argc, argv`\n  7:  5b7a3d58b4f !  7:  e97e187bbec bisect--helper: migrate to OPT_SUBCOMMAND()\n     @@ Commit message\n          `bisect--helper` learns about it in preparation for replacing the\n          `git-bisect.sh` script altogether.\n      \n     +    As a consequence, the usage strings are copied over from the scripted\n     +    version of the `git bisect` command. To avoid regressing on 959d670d1a4\n     +    (i18n: remove from i18n strings that do not hold translatable parts,\n     +    2022-01-31), we specifically do not enclose usage strings in `N_(...)`\n     +    that do not contain any translatable parts.\n     +\n          Note that a couple of `bisect_*()` functions are not converted into\n          `cmd_bisect_*()` functions directly, as they have callers other than the\n          `OPT_SUBCOMMAND()` one (and the original functions did not expect\n     @@ builtin/bisect--helper.c: static GIT_PATH_FUNC(git_path_bisect_names, \"BISECT_NA\n      +\t   \"    [<pathspec>...]\"),\n      +\tN_(\"git bisect (bad|new) [<rev>]\"),\n      +\tN_(\"git bisect (good|old) [<rev>...]\"),\n     -+\tN_(\"git bisect terms [--term-good | --term-bad]\"),\n     ++\t\"git bisect terms [--term-good | --term-bad]\",\n      +\tN_(\"git bisect skip [(<rev>|<range>)...]\"),\n     -+\tN_(\"git bisect next\"),\n     ++\t\"git bisect next\",\n      +\tN_(\"git bisect reset [<commit>]\"),\n     -+\tN_(\"git bisect (visualize|view)\"),\n     ++\t\"git bisect (visualize|view)\",\n      +\tN_(\"git bisect replay <logfile>\"),\n     -+\tN_(\"git bisect log\"),\n     ++\t\"git bisect log\",\n      +\tN_(\"git bisect run <cmd>...\"),\n      +\tNULL\n      +};\n     @@ builtin/bisect--helper.c: static GIT_PATH_FUNC(git_path_bisect_names, \"BISECT_NA\n      +};\n      +\n      +static const char * const bisect_terms_usage[] = {\n     -+\tN_(\"git bisect terms [--term-good | --term-bad]\"),\n     ++\t\"git bisect terms [--term-good | --term-bad]\",\n      +\tNULL\n      +};\n      +\n     @@ builtin/bisect--helper.c: static GIT_PATH_FUNC(git_path_bisect_names, \"BISECT_NA\n      +};\n      +\n      +static const char * const bisect_next_usage[] = {\n     -+\tN_(\"git bisect next\"),\n     ++\t\"git bisect next\",\n      +\tNULL\n      +};\n      +\n     @@ builtin/bisect--helper.c: static GIT_PATH_FUNC(git_path_bisect_names, \"BISECT_NA\n      +};\n      +\n      +static const char * const bisect_visualize_usage[] = {\n     -+\tN_(\"git bisect visualize\"),\n     ++\t\"git bisect visualize\",\n      +\tNULL\n      +};\n      +\n     @@ builtin/bisect--helper.c: static GIT_PATH_FUNC(git_path_bisect_names, \"BISECT_NA\n      +};\n      +\n      +static const char * const bisect_log_usage[] = {\n     -+\tN_(\"git bisect log\"),\n     ++\t\"git bisect log\",\n      +\tNULL\n      +};\n      +\n     @@ builtin/bisect--helper.c: static int bisect_reset(const char *commit)\n      +\t\tOPT_END()\n      +\t};\n      +\targc = parse_options(argc, argv, prefix, options,\n     -+\t\t\t     bisect_reset_usage,  PARSE_OPT_STOP_AT_NON_OPTION);\n     ++\t\t\t     bisect_reset_usage, PARSE_OPT_STOP_AT_NON_OPTION);\n      +\n      +\tif (argc > 1)\n      +\t\tusage_msg_opt(_(\"requires either no argument or a commit\"),\n     @@ builtin/bisect--helper.c: finish:\n      +\t};\n      +\n      +\targc = parse_options(argc, argv, prefix, options,\n     -+\t\t\t     bisect_terms_usage,  PARSE_OPT_STOP_AT_NON_OPTION);\n     ++\t\t\t     bisect_terms_usage, PARSE_OPT_STOP_AT_NON_OPTION);\n      +\n      +\tif (argc > 1)\n      +\t\tusage_msg_opt(_(\"terms: requires 0 or 1 argument\"),\n     @@ builtin/bisect--helper.c: static enum bisect_error bisect_state(int argc, const\n      +\tget_terms();\n      +\n      +\targc = parse_options(argc, argv, prefix, options,\n     -+\t\t\t     bisect_state_usage,  PARSE_OPT_STOP_AT_NON_OPTION);\n     ++\t\t\t     bisect_state_usage, PARSE_OPT_STOP_AT_NON_OPTION);\n      +\n      +\tif (!argc)\n      +\t\tusage_msg_opt(_(\"need at least one argument\"),\n     @@ builtin/bisect--helper.c: static enum bisect_error bisect_state(int argc, const\n       \tconst char* filename = git_path_bisect_log();\n       \n      +\targc = parse_options(argc, argv, prefix, options,\n     -+\t\t\t     bisect_log_usage,  PARSE_OPT_STOP_AT_NON_OPTION);\n     ++\t\t\t     bisect_log_usage, PARSE_OPT_STOP_AT_NON_OPTION);\n      +\n      +\tif (argc > 0)\n      +\t\tusage_msg_opt(_(\"require 0 argument\"), bisect_log_usage,\n     @@ builtin/bisect--helper.c: static int process_replay_line(struct strbuf *line)\n       \n      +\tset_terms(\"bad\", \"good\");\n      +\targc = parse_options(argc, argv, prefix, options,\n     -+\t\t\t     bisect_reset_usage,  PARSE_OPT_STOP_AT_NON_OPTION);\n     ++\t\t\t     bisect_reset_usage, PARSE_OPT_STOP_AT_NON_OPTION);\n      +\n      +\tif (argc != 1)\n      +\t\tusage_msg_opt(_(\"no logfile given\"), bisect_replay_usage,\n     @@ builtin/bisect--helper.c: static enum bisect_error bisect_replay(const char *fil\n      +\tset_terms(\"bad\", \"good\");\n      +\tget_terms();\n      +\targc = parse_options(argc, argv, prefix, options,\n     -+\t\t\t     bisect_skip_usage,  PARSE_OPT_STOP_AT_NON_OPTION);\n     ++\t\t\t     bisect_skip_usage, PARSE_OPT_STOP_AT_NON_OPTION);\n      +\n       \tstrvec_push(&argv_state, \"skip\");\n       \n     @@ builtin/bisect--helper.c: static int bisect_run(int argc, const char **argv)\n       \n      +\tget_terms();\n      +\targc = parse_options(argc, argv, prefix, options,\n     -+\t\t\t     bisect_run_usage,  PARSE_OPT_STOP_AT_NON_OPTION);\n     ++\t\t\t     bisect_run_usage, PARSE_OPT_STOP_AT_NON_OPTION);\n      +\n       \tif (bisect_next_check(NULL))\n       \t\treturn BISECT_FAILED;\n  8:  ba537af7066 =  8:  30c87f2e92e bisect: verify that a bogus option won't try to start a bisection\n  9:  409492ad830 !  9:  4696652b99c bisect run: fix the error message\n     @@ Commit message\n      \n          However, the error message was supposed to print out whether the state\n          was \"good\" or \"bad\", but used a bogus (because non-populated) `args`\n     -    variable for it.\n     +    variable for it. This was fixed in 80c2e9657f2 (bisect--helper: report\n     +    actual bisect_state() argument on error, 2022-01-18), but the error\n     +    message still talks about `bisect--helper`, which is an implementation\n     +    detail that should not concern end users.\n     +\n     +    Fix that, and add a regression test to ensure that the intended form of\n     +    the error message.\n      \n          Helped-by: Elijah Newren <newren@gmail.com>\n          Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n 10:  bc5efc8fbfe = 10:  b202a0e386c bisect: avoid double-quoting when printing the failed command\n 11:  8a0adfe3867 = 11:  3376b450867 bisect--helper: calling `bisect_state()` without an argument is a bug\n 12:  189d2b3ba46 = 12:  e7623508f90 bisect--helper: make `state` optional\n 13:  32bf74e3050 = 13:  3f052580c95 bisect: move even the command-line parsing to `bisect--helper`\n 14:  a8f08f5e0cb = 14:  a83fe3dc3c2 Turn `git bisect` into a full built-in\n 15:  a96489310d3 = 15:  f2132b61ff7 bisect: remove Cogito-related code\n 16:  bfa7aa19f03 = 16:  4f93692e071 bisect: no longer try to clean up left-over `.git/head-name` files\n\n-- \ngitgitgadget\n"},{"id":"462212","messageId":"05262b6a7d1b20a0d2f2ca2090be284ffb8c679c.1661885419.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v6.git.1661885419.gitgitgadget@gmail.com","subject":"[PATCH v6 01/16] bisect--helper: retire the --no-log option","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-08-30T18:50:04Z","receivedAt":"2022-08-30T18:50:31Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nTurns out we actually never used it, anyway...\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/bisect--helper.c | 4 +---\n 1 file changed, 1 insertion(+), 3 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 7097750fc6b..2cc69e1eee5 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1292,7 +1292,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@@ -1316,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-- \ngitgitgadget\n\n"},{"id":"462213","messageId":"1e43148864a52ffe05b5075bd0e449c0e056f078.1661885419.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v6.git.1661885419.gitgitgadget@gmail.com","subject":"[PATCH v6 02/16] bisect--helper: really retire --bisect-next-check","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-08-30T18:50:05Z","receivedAt":"2022-08-30T18:50:34Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?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\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/bisect--helper.c | 3 ---\n 1 file changed, 3 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 2cc69e1eee5..bdf7ce18d7a 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1280,7 +1280,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@@ -1296,8 +1295,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-- \ngitgitgadget\n\n"},{"id":"462214","messageId":"1a1649d9d0d5739f76db82fdafae7e88374bc8a6.1661885419.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v6.git.1661885419.gitgitgadget@gmail.com","subject":"[PATCH v6 03/16] bisect--helper: really retire `--bisect-autostart`","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-08-30T18:50:06Z","receivedAt":"2022-08-30T18:50:36Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\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>\n---\n builtin/bisect--helper.c | 1 -\n 1 file changed, 1 deletion(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex bdf7ce18d7a..aa94c25ec73 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1282,7 +1282,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\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-- \ngitgitgadget\n\n"},{"id":"462215","messageId":"9ab30552c6ae6a5d0a85d7a7bbdd10af4a4cf7ec.1661885419.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v6.git.1661885419.gitgitgadget@gmail.com","subject":"[PATCH v6 04/16] bisect--helper: simplify exit code computation","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-08-30T18:50:07Z","receivedAt":"2022-08-30T18:50:40Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nWe _already_ have a function to determine whether a given `enum\nbisect_error` value is non-zero but still _actually_ indicates success.\n\nLet's use it instead of duplicating the logic.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/bisect--helper.c | 9 +--------\n 1 file changed, 1 insertion(+), 8 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex aa94c25ec73..2f9c7f54f3f 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1380,12 +1380,5 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t}\n \tfree_terms(&terms);\n \n-\t/*\n-\t * Handle early success\n-\t * From check_merge_bases > check_good_are_ancestors_of_bad > bisect_next_all\n-\t */\n-\tif ((res == BISECT_INTERNAL_SUCCESS_MERGE_BASE) || (res == BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND))\n-\t\tres = BISECT_OK;\n-\n-\treturn -res;\n+\treturn is_bisect_success(res) ? 0 : -res;\n }\n-- \ngitgitgadget\n\n"},{"id":"462216","messageId":"c9dc0281e38bf9bc0bce72de172b5dbadbcbb1f5.1661885419.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v6.git.1661885419.gitgitgadget@gmail.com","subject":"[PATCH v6 06/16] bisect--helper: make the order consistently `argc, argv`","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-08-30T18:50:09Z","receivedAt":"2022-08-30T18:50:42Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nIn C, the natural order is for `argc` to come before `argv` by virtue of\nthe `main()` function declaring the parameters in precisely that order.\n\nIt is confusing & distracting, then, when readers familiar with the C\nlanguage read code where that order is switched around.\n\nLet's just change the order and avoid that type of developer friction.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/bisect--helper.c | 29 ++++++++++++++---------------\n 1 file changed, 14 insertions(+), 15 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 7f4e8e707c1..0d7cc20f9c9 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -652,7 +652,7 @@ static enum bisect_error bisect_auto_next(const char *prefix)\n \treturn bisect_next(prefix);\n }\n \n-static enum bisect_error bisect_start(const char **argv, int argc)\n+static enum bisect_error bisect_start(int argc, const char **argv)\n {\n \tint no_checkout = 0;\n \tint first_parent_only = 0;\n@@ -881,13 +881,12 @@ static int bisect_autostart(void)\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(empty_strvec, 0);\n+\t\t-1 : bisect_start(0, empty_strvec);\n \n \treturn res;\n }\n \n-static enum bisect_error bisect_state(const char **argv,\n-\t\t\t\t      int argc)\n+static enum bisect_error bisect_state(int argc, const char **argv)\n {\n \tconst char *state;\n \tint i, verify_expected = 1;\n@@ -1006,7 +1005,7 @@ static int process_replay_line(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(argv.v, argv.nr);\n+\t\tres = bisect_start(argv.nr, argv.v);\n \t\tstrvec_clear(&argv);\n \t\treturn res;\n \t}\n@@ -1056,7 +1055,7 @@ static enum bisect_error bisect_replay(const char *filename)\n \treturn bisect_auto_next(NULL);\n }\n \n-static enum bisect_error bisect_skip(const char **argv, int argc)\n+static enum bisect_error bisect_skip(int argc, const char **argv)\n {\n \tint i;\n \tenum bisect_error res;\n@@ -1086,13 +1085,13 @@ static enum bisect_error bisect_skip(const char **argv, int argc)\n \t\t\tstrvec_push(&argv_state, argv[i]);\n \t\t}\n \t}\n-\tres = bisect_state(argv_state.v, argv_state.nr);\n+\tres = bisect_state(argv_state.nr, argv_state.v);\n \n \tstrvec_clear(&argv_state);\n \treturn res;\n }\n \n-static int bisect_visualize(const char **argv, int argc)\n+static int bisect_visualize(int argc, const char **argv)\n {\n \tstruct strvec args = STRVEC_INIT;\n \tint flags = RUN_COMMAND_NO_STDIN, res = 0;\n@@ -1167,7 +1166,7 @@ static int verify_good(const char **quoted_argv)\n \treturn rc;\n }\n \n-static int bisect_run(const char **argv, int argc)\n+static int bisect_run(int argc, const char **argv)\n {\n \tint res = BISECT_OK;\n \tstruct strbuf command = STRBUF_INIT;\n@@ -1240,7 +1239,7 @@ static int bisect_run(const char **argv, int argc)\n \t\tsaved_stdout = dup(1);\n \t\tdup2(temporary_stdout_fd, 1);\n \n-\t\tres = bisect_state(&new_state, 1);\n+\t\tres = bisect_state(1, &new_state);\n \n \t\tfflush(stdout);\n \t\tdup2(saved_stdout, 1);\n@@ -1330,7 +1329,7 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\tbreak;\n \tcase BISECT_START:\n \t\tset_terms(\"bad\", \"good\");\n-\t\tres = bisect_start(argv, argc);\n+\t\tres = bisect_start(argc, argv);\n \t\tbreak;\n \tcase BISECT_NEXT:\n \t\tif (argc)\n@@ -1341,7 +1340,7 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \tcase BISECT_STATE:\n \t\tset_terms(\"bad\", \"good\");\n \t\tget_terms();\n-\t\tres = bisect_state(argv, argc);\n+\t\tres = bisect_state(argc, argv);\n \t\tbreak;\n \tcase BISECT_LOG:\n \t\tif (argc)\n@@ -1357,17 +1356,17 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \tcase BISECT_SKIP:\n \t\tset_terms(\"bad\", \"good\");\n \t\tget_terms();\n-\t\tres = bisect_skip(argv, argc);\n+\t\tres = bisect_skip(argc, argv);\n \t\tbreak;\n \tcase BISECT_VISUALIZE:\n \t\tget_terms();\n-\t\tres = bisect_visualize(argv, argc);\n+\t\tres = bisect_visualize(argc, argv);\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();\n-\t\tres = bisect_run(argv, argc);\n+\t\tres = bisect_run(argc, argv);\n \t\tbreak;\n \tdefault:\n \t\tBUG(\"unknown subcommand %d\", cmdmode);\n-- \ngitgitgadget\n\n"},{"id":"462217","messageId":"92b3b116ef8f879192d9deb94d68b73e29d5dcd6.1661885419.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v6.git.1661885419.gitgitgadget@gmail.com","subject":"[PATCH v6 05/16] bisect--helper: make `terms` an explicit singleton","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-08-30T18:50:08Z","receivedAt":"2022-08-30T18:50:53Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nWe tried very hard to keep code in `builtin/bisect--helper.c` in as\nlibifyable a state as possible.\n\nHowever, we are about to migrate this built-in to the `OPT_SUBCOMMAND()`\nAPI, which does not allow for passing any context (e.g. via a `void\n*data` parameters as they are used in the config API).\n\nTherefore, we _have_ to move the `terms` variable outside of\n`cmd_bisect__helper()` and explicitly make it a singleton (as it\ncurrently is, anyway).\n\nLet's just make things consistent and stop passing around pointers to\nthat singleton; Use it directly instead.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/bisect--helper.c | 262 +++++++++++++++++++--------------------\n 1 file changed, 128 insertions(+), 134 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 2f9c7f54f3f..7f4e8e707c1 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -40,30 +40,30 @@ struct add_bisect_ref_data {\n \tunsigned int object_flags;\n };\n \n-struct bisect_terms {\n+static struct bisect_terms {\n \tchar *term_good;\n \tchar *term_bad;\n-};\n+} terms;\n \n-static void free_terms(struct bisect_terms *terms)\n+static void free_terms(void)\n {\n-\tFREE_AND_NULL(terms->term_good);\n-\tFREE_AND_NULL(terms->term_bad);\n+\tFREE_AND_NULL(terms.term_good);\n+\tFREE_AND_NULL(terms.term_bad);\n }\n \n-static void set_terms(struct bisect_terms *terms, const char *bad,\n+static void set_terms(const char *bad,\n \t\t      const char *good)\n {\n-\tfree((void *)terms->term_good);\n-\tterms->term_good = xstrdup(good);\n-\tfree((void *)terms->term_bad);\n-\tterms->term_bad = xstrdup(bad);\n+\tfree((void *)terms.term_good);\n+\tterms.term_good = xstrdup(good);\n+\tfree((void *)terms.term_bad);\n+\tterms.term_bad = xstrdup(bad);\n }\n \n static const char vocab_bad[] = \"bad|new\";\n static const char vocab_good[] = \"good|old\";\n \n-static int bisect_autostart(struct bisect_terms *terms);\n+static int bisect_autostart(void);\n \n /*\n  * Check whether the string `term` belongs to the set of strings\n@@ -254,8 +254,7 @@ static void log_commit(FILE *fp, char *fmt, const char *state,\n \tfree(label);\n }\n \n-static int bisect_write(const char *state, const char *rev,\n-\t\t\tconst struct bisect_terms *terms, int nolog)\n+static int bisect_write(const char *state, const char *rev, int nolog)\n {\n \tstruct strbuf tag = STRBUF_INIT;\n \tstruct object_id oid;\n@@ -263,9 +262,9 @@ static int bisect_write(const char *state, const char *rev,\n \tFILE *fp = NULL;\n \tint res = 0;\n \n-\tif (!strcmp(state, terms->term_bad)) {\n+\tif (!strcmp(state, terms.term_bad)) {\n \t\tstrbuf_addf(&tag, \"refs/bisect/%s\", state);\n-\t} else if (one_of(state, terms->term_good, \"skip\", NULL)) {\n+\t} else if (one_of(state, terms.term_good, \"skip\", NULL)) {\n \t\tstrbuf_addf(&tag, \"refs/bisect/%s-%s\", state, rev);\n \t} else {\n \t\tres = error(_(\"Bad bisect_write argument: %s\"), state);\n@@ -302,27 +301,27 @@ finish:\n \treturn res;\n }\n \n-static int check_and_set_terms(struct bisect_terms *terms, const char *cmd)\n+static int check_and_set_terms(const char *cmd)\n {\n \tint has_term_file = !is_empty_or_missing_file(git_path_bisect_terms());\n \n \tif (one_of(cmd, \"skip\", \"start\", \"terms\", NULL))\n \t\treturn 0;\n \n-\tif (has_term_file && strcmp(cmd, terms->term_bad) &&\n-\t    strcmp(cmd, terms->term_good))\n+\tif (has_term_file && strcmp(cmd, terms.term_bad) &&\n+\t    strcmp(cmd, terms.term_good))\n \t\treturn error(_(\"Invalid command: you're currently in a \"\n-\t\t\t\t\"%s/%s bisect\"), terms->term_bad,\n-\t\t\t\tterms->term_good);\n+\t\t\t\t\"%s/%s bisect\"), terms.term_bad,\n+\t\t\t\tterms.term_good);\n \n \tif (!has_term_file) {\n \t\tif (one_of(cmd, \"bad\", \"good\", NULL)) {\n-\t\t\tset_terms(terms, \"bad\", \"good\");\n-\t\t\treturn write_terms(terms->term_bad, terms->term_good);\n+\t\t\tset_terms(\"bad\", \"good\");\n+\t\t\treturn write_terms(terms.term_bad, terms.term_good);\n \t\t}\n \t\tif (one_of(cmd, \"new\", \"old\", NULL)) {\n-\t\t\tset_terms(terms, \"new\", \"old\");\n-\t\t\treturn write_terms(terms->term_bad, terms->term_good);\n+\t\t\tset_terms(\"new\", \"old\");\n+\t\t\treturn write_terms(terms.term_bad, terms.term_good);\n \t\t}\n \t}\n \n@@ -346,8 +345,7 @@ static const char need_bisect_start_warning[] =\n \t   \"You then need to give me at least one %s and %s revision.\\n\"\n \t   \"You can use \\\"git bisect %s\\\" and \\\"git bisect %s\\\" for that.\");\n \n-static int decide_next(const struct bisect_terms *terms,\n-\t\t       const char *current_term, int missing_good,\n+static int decide_next(const char *current_term, int missing_good,\n \t\t       int missing_bad)\n {\n \tif (!missing_good && !missing_bad)\n@@ -356,13 +354,13 @@ static int decide_next(const struct bisect_terms *terms,\n \t\treturn -1;\n \n \tif (missing_good && !missing_bad &&\n-\t    !strcmp(current_term, terms->term_good)) {\n+\t    !strcmp(current_term, terms.term_good)) {\n \t\tchar *yesno;\n \t\t/*\n \t\t * have bad (or new) but not good (or old). We could bisect\n \t\t * although this is less optimum.\n \t\t */\n-\t\twarning(_(\"bisecting only with a %s commit\"), terms->term_bad);\n+\t\twarning(_(\"bisecting only with a %s commit\"), terms.term_bad);\n \t\tif (!isatty(0))\n \t\t\treturn 0;\n \t\t/*\n@@ -384,11 +382,10 @@ static int decide_next(const struct bisect_terms *terms,\n \t\t\t     vocab_good, vocab_bad, vocab_good, vocab_bad);\n }\n \n-static void bisect_status(struct bisect_state *state,\n-\t\t\t  const struct bisect_terms *terms)\n+static void bisect_status(struct bisect_state *state)\n {\n-\tchar *bad_ref = xstrfmt(\"refs/bisect/%s\", terms->term_bad);\n-\tchar *good_glob = xstrfmt(\"%s-*\", terms->term_good);\n+\tchar *bad_ref = xstrfmt(\"refs/bisect/%s\", terms.term_bad);\n+\tchar *good_glob = xstrfmt(\"%s-*\", terms.term_good);\n \n \tif (ref_exists(bad_ref))\n \t\tstate->nr_bad = 1;\n@@ -416,11 +413,11 @@ static void bisect_log_printf(const char *fmt, ...)\n \tstrbuf_release(&buf);\n }\n \n-static void bisect_print_status(const struct bisect_terms *terms)\n+static void bisect_print_status(void)\n {\n \tstruct bisect_state state = { 0 };\n \n-\tbisect_status(&state, terms);\n+\tbisect_status(&state);\n \n \t/* If we had both, we'd already be started, and shouldn't get here. */\n \tif (state.nr_good && state.nr_bad)\n@@ -436,15 +433,14 @@ static void bisect_print_status(const struct bisect_terms *terms)\n \t\tbisect_log_printf(_(\"status: waiting for good commit(s), bad commit known\\n\"));\n }\n \n-static int bisect_next_check(const struct bisect_terms *terms,\n-\t\t\t     const char *current_term)\n+static int bisect_next_check(const char *current_term)\n {\n \tstruct bisect_state state = { 0 };\n-\tbisect_status(&state, terms);\n-\treturn decide_next(terms, current_term, !state.nr_good, !state.nr_bad);\n+\tbisect_status(&state);\n+\treturn decide_next(current_term, !state.nr_good, !state.nr_bad);\n }\n \n-static int get_terms(struct bisect_terms *terms)\n+static int get_terms(void)\n {\n \tstruct strbuf str = STRBUF_INIT;\n \tFILE *fp = NULL;\n@@ -456,11 +452,11 @@ static int get_terms(struct bisect_terms *terms)\n \t\tgoto finish;\n \t}\n \n-\tfree_terms(terms);\n+\tfree_terms();\n \tstrbuf_getline_lf(&str, fp);\n-\tterms->term_bad = strbuf_detach(&str, NULL);\n+\tterms.term_bad = strbuf_detach(&str, NULL);\n \tstrbuf_getline_lf(&str, fp);\n-\tterms->term_good = strbuf_detach(&str, NULL);\n+\tterms.term_good = strbuf_detach(&str, NULL);\n \n finish:\n \tif (fp)\n@@ -469,21 +465,21 @@ finish:\n \treturn res;\n }\n \n-static int bisect_terms(struct bisect_terms *terms, const char *option)\n+static int bisect_terms(const char *option)\n {\n-\tif (get_terms(terms))\n+\tif (get_terms())\n \t\treturn error(_(\"no terms defined\"));\n \n \tif (!option) {\n \t\tprintf(_(\"Your current terms are %s for the old state\\n\"\n \t\t\t \"and %s for the new state.\\n\"),\n-\t\t       terms->term_good, terms->term_bad);\n+\t\t       terms.term_good, terms.term_bad);\n \t\treturn 0;\n \t}\n \tif (one_of(option, \"--term-good\", \"--term-old\", NULL))\n-\t\tprintf(\"%s\\n\", terms->term_good);\n+\t\tprintf(\"%s\\n\", terms.term_good);\n \telse if (one_of(option, \"--term-bad\", \"--term-new\", NULL))\n-\t\tprintf(\"%s\\n\", terms->term_bad);\n+\t\tprintf(\"%s\\n\", terms.term_bad);\n \telse\n \t\treturn error(_(\"invalid argument %s for 'git bisect terms'.\\n\"\n \t\t\t       \"Supported options are: \"\n@@ -527,18 +523,18 @@ static int add_bisect_ref(const char *refname, const struct object_id *oid,\n \treturn 0;\n }\n \n-static int prepare_revs(struct bisect_terms *terms, struct rev_info *revs)\n+static int prepare_revs(struct rev_info *revs)\n {\n \tint res = 0;\n \tstruct add_bisect_ref_data cb = { revs };\n-\tchar *good = xstrfmt(\"%s-*\", terms->term_good);\n+\tchar *good = xstrfmt(\"%s-*\", terms.term_good);\n \n \t/*\n-\t * We cannot use terms->term_bad directly in\n+\t * We cannot use terms.term_bad directly in\n \t * for_each_glob_ref_in() and we have to append a '*' to it,\n \t * otherwise for_each_glob_ref_in() will append '/' and '*'.\n \t */\n-\tchar *bad = xstrfmt(\"%s*\", terms->term_bad);\n+\tchar *bad = xstrfmt(\"%s*\", terms.term_bad);\n \n \t/*\n \t * It is important to reset the flags used by revision walks\n@@ -559,7 +555,7 @@ static int prepare_revs(struct bisect_terms *terms, struct rev_info *revs)\n \treturn res;\n }\n \n-static int bisect_skipped_commits(struct bisect_terms *terms)\n+static int bisect_skipped_commits(void)\n {\n \tint res;\n \tFILE *fp = NULL;\n@@ -568,7 +564,7 @@ static int bisect_skipped_commits(struct bisect_terms *terms)\n \tstruct pretty_print_context pp = {0};\n \tstruct strbuf commit_name = STRBUF_INIT;\n \n-\tres = prepare_revs(terms, &revs);\n+\tres = prepare_revs(&revs);\n \tif (res)\n \t\treturn res;\n \n@@ -585,7 +581,7 @@ static int bisect_skipped_commits(struct bisect_terms *terms)\n \t\tformat_commit_message(commit, \"%s\",\n \t\t\t\t      &commit_name, &pp);\n \t\tfprintf(fp, \"# possible first %s commit: [%s] %s\\n\",\n-\t\t\tterms->term_bad, oid_to_hex(&commit->object.oid),\n+\t\t\tterms.term_bad, oid_to_hex(&commit->object.oid),\n \t\t\tcommit_name.buf);\n \t}\n \n@@ -601,13 +597,13 @@ static int bisect_skipped_commits(struct bisect_terms *terms)\n \treturn 0;\n }\n \n-static int bisect_successful(struct bisect_terms *terms)\n+static int bisect_successful(void)\n {\n \tstruct object_id oid;\n \tstruct commit *commit;\n \tstruct pretty_print_context pp = {0};\n \tstruct strbuf commit_name = STRBUF_INIT;\n-\tchar *bad_ref = xstrfmt(\"refs/bisect/%s\",terms->term_bad);\n+\tchar *bad_ref = xstrfmt(\"refs/bisect/%s\",terms.term_bad);\n \tint res;\n \n \tread_ref(bad_ref, &oid);\n@@ -615,7 +611,7 @@ static int bisect_successful(struct bisect_terms *terms)\n \tformat_commit_message(commit, \"%s\", &commit_name, &pp);\n \n \tres = append_to_file(git_path_bisect_log(), \"# first %s commit: [%s] %s\\n\",\n-\t\t\t    terms->term_bad, oid_to_hex(&commit->object.oid),\n+\t\t\t    terms.term_bad, oid_to_hex(&commit->object.oid),\n \t\t\t    commit_name.buf);\n \n \tstrbuf_release(&commit_name);\n@@ -623,40 +619,40 @@ 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 enum bisect_error bisect_next(const char *prefix)\n {\n \tenum bisect_error res;\n \n-\tif (bisect_autostart(terms))\n+\tif (bisect_autostart())\n \t\treturn BISECT_FAILED;\n \n-\tif (bisect_next_check(terms, terms->term_good))\n+\tif (bisect_next_check(terms.term_good))\n \t\treturn BISECT_FAILED;\n \n \t/* Perform all bisection computation */\n \tres = bisect_next_all(the_repository, prefix);\n \n \tif (res == BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND) {\n-\t\tres = bisect_successful(terms);\n+\t\tres = bisect_successful();\n \t\treturn res ? res : BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND;\n \t} else if (res == BISECT_ONLY_SKIPPED_LEFT) {\n-\t\tres = bisect_skipped_commits(terms);\n+\t\tres = bisect_skipped_commits();\n \t\treturn res ? res : BISECT_ONLY_SKIPPED_LEFT;\n \t}\n \treturn res;\n }\n \n-static enum bisect_error bisect_auto_next(struct bisect_terms *terms, const char *prefix)\n+static enum bisect_error bisect_auto_next(const char *prefix)\n {\n-\tif (bisect_next_check(terms, NULL)) {\n-\t\tbisect_print_status(terms);\n+\tif (bisect_next_check(NULL)) {\n+\t\tbisect_print_status();\n \t\treturn BISECT_OK;\n \t}\n \n-\treturn bisect_next(terms, prefix);\n+\treturn bisect_next(prefix);\n }\n \n-static enum bisect_error bisect_start(struct bisect_terms *terms, const char **argv, int argc)\n+static enum bisect_error bisect_start(const char **argv, int argc)\n {\n \tint no_checkout = 0;\n \tint first_parent_only = 0;\n@@ -698,26 +694,26 @@ static enum bisect_error bisect_start(struct bisect_terms *terms, const char **a\n \t\t\tif (argc <= i)\n \t\t\t\treturn error(_(\"'' is not a valid term\"));\n \t\t\tmust_write_terms = 1;\n-\t\t\tfree((void *) terms->term_good);\n-\t\t\tterms->term_good = xstrdup(argv[i]);\n+\t\t\tfree((void *) terms.term_good);\n+\t\t\tterms.term_good = xstrdup(argv[i]);\n \t\t} else if (skip_prefix(arg, \"--term-good=\", &arg) ||\n \t\t\t   skip_prefix(arg, \"--term-old=\", &arg)) {\n \t\t\tmust_write_terms = 1;\n-\t\t\tfree((void *) terms->term_good);\n-\t\t\tterms->term_good = xstrdup(arg);\n+\t\t\tfree((void *) terms.term_good);\n+\t\t\tterms.term_good = xstrdup(arg);\n \t\t} else if (!strcmp(arg, \"--term-bad\") ||\n \t\t\t !strcmp(arg, \"--term-new\")) {\n \t\t\ti++;\n \t\t\tif (argc <= i)\n \t\t\t\treturn error(_(\"'' is not a valid term\"));\n \t\t\tmust_write_terms = 1;\n-\t\t\tfree((void *) terms->term_bad);\n-\t\t\tterms->term_bad = xstrdup(argv[i]);\n+\t\t\tfree((void *) terms.term_bad);\n+\t\t\tterms.term_bad = xstrdup(argv[i]);\n \t\t} else if (skip_prefix(arg, \"--term-bad=\", &arg) ||\n \t\t\t   skip_prefix(arg, \"--term-new=\", &arg)) {\n \t\t\tmust_write_terms = 1;\n-\t\t\tfree((void *) terms->term_bad);\n-\t\t\tterms->term_bad = xstrdup(arg);\n+\t\t\tfree((void *) terms.term_bad);\n+\t\t\tterms.term_bad = xstrdup(arg);\n \t\t} else if (starts_with(arg, \"--\")) {\n \t\t\treturn error(_(\"unrecognized option: '%s'\"), arg);\n \t\t} else if (!get_oidf(&oid, \"%s^{commit}\", arg)) {\n@@ -741,10 +737,10 @@ static enum bisect_error bisect_start(struct bisect_terms *terms, const char **a\n \t\tmust_write_terms = 1;\n \tfor (i = 0; i < revs.nr; i++) {\n \t\tif (bad_seen) {\n-\t\t\tstring_list_append(&states, terms->term_good);\n+\t\t\tstring_list_append(&states, terms.term_good);\n \t\t} else {\n \t\t\tbad_seen = 1;\n-\t\t\tstring_list_append(&states, terms->term_bad);\n+\t\t\tstring_list_append(&states, terms.term_bad);\n \t\t}\n \t}\n \n@@ -829,13 +825,13 @@ static enum bisect_error bisect_start(struct bisect_terms *terms, const char **a\n \n \tfor (i = 0; i < states.nr; i++)\n \t\tif (bisect_write(states.items[i].string,\n-\t\t\t\t revs.items[i].string, terms, 1)) {\n+\t\t\t\t revs.items[i].string, 1)) {\n \t\t\tres = BISECT_FAILED;\n \t\t\tgoto finish;\n \t\t}\n \n-\tif (must_write_terms && write_terms(terms->term_bad,\n-\t\t\t\t\t    terms->term_good)) {\n+\tif (must_write_terms && write_terms(terms.term_bad,\n+\t\t\t\t\t    terms.term_good)) {\n \t\tres = BISECT_FAILED;\n \t\tgoto finish;\n \t}\n@@ -852,7 +848,7 @@ finish:\n \tif (res)\n \t\treturn res;\n \n-\tres = bisect_auto_next(terms, NULL);\n+\tres = bisect_auto_next(NULL);\n \tif (!is_bisect_success(res))\n \t\tbisect_clean_state();\n \treturn res;\n@@ -863,7 +859,7 @@ static inline int file_is_not_empty(const char *path)\n \treturn !is_empty_or_missing_file(path);\n }\n \n-static int bisect_autostart(struct bisect_terms *terms)\n+static int bisect_autostart(void)\n {\n \tint res;\n \tconst char *yesno;\n@@ -885,12 +881,12 @@ 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(empty_strvec, 0);\n \n \treturn res;\n }\n \n-static enum bisect_error bisect_state(struct bisect_terms *terms, const char **argv,\n+static enum bisect_error bisect_state(const char **argv,\n \t\t\t\t      int argc)\n {\n \tconst char *state;\n@@ -902,18 +898,18 @@ static enum bisect_error bisect_state(struct bisect_terms *terms, const char **a\n \tif (!argc)\n \t\treturn error(_(\"Please call `--bisect-state` with at least one argument\"));\n \n-\tif (bisect_autostart(terms))\n+\tif (bisect_autostart())\n \t\treturn BISECT_FAILED;\n \n \tstate = argv[0];\n-\tif (check_and_set_terms(terms, state) ||\n-\t    !one_of(state, terms->term_good, terms->term_bad, \"skip\", NULL))\n+\tif (check_and_set_terms(state) ||\n+\t    !one_of(state, terms.term_good, terms.term_bad, \"skip\", NULL))\n \t\treturn BISECT_FAILED;\n \n \targv++;\n \targc--;\n-\tif (argc > 1 && !strcmp(state, terms->term_bad))\n-\t\treturn error(_(\"'git bisect %s' can take only one argument.\"), terms->term_bad);\n+\tif (argc > 1 && !strcmp(state, terms.term_bad))\n+\t\treturn error(_(\"'git bisect %s' can take only one argument.\"), terms.term_bad);\n \n \tif (argc == 0) {\n \t\tconst char *head = \"BISECT_HEAD\";\n@@ -956,7 +952,7 @@ static enum bisect_error bisect_state(struct bisect_terms *terms, const char **a\n \tstrbuf_release(&buf);\n \n \tfor (i = 0; i < revs.nr; i++) {\n-\t\tif (bisect_write(state, oid_to_hex(&revs.oid[i]), terms, 0)) {\n+\t\tif (bisect_write(state, oid_to_hex(&revs.oid[i]), 0)) {\n \t\t\toid_array_clear(&revs);\n \t\t\treturn BISECT_FAILED;\n \t\t}\n@@ -968,7 +964,7 @@ static enum bisect_error bisect_state(struct bisect_terms *terms, const char **a\n \t}\n \n \toid_array_clear(&revs);\n-\treturn bisect_auto_next(terms, NULL);\n+\treturn bisect_auto_next(NULL);\n }\n \n static enum bisect_error bisect_log(void)\n@@ -988,7 +984,7 @@ static enum bisect_error bisect_log(void)\n \treturn status ? BISECT_FAILED : BISECT_OK;\n }\n \n-static int process_replay_line(struct bisect_terms *terms, struct strbuf *line)\n+static int process_replay_line(struct strbuf *line)\n {\n \tconst char *p = line->buf + strspn(line->buf, \" \\t\");\n \tchar *word_end, *rev;\n@@ -1002,28 +998,28 @@ static int process_replay_line(struct bisect_terms *terms, struct strbuf *line)\n \trev = word_end + strspn(word_end, \" \\t\");\n \t*word_end = '\\0'; /* NUL-terminate the word */\n \n-\tget_terms(terms);\n-\tif (check_and_set_terms(terms, p))\n+\tget_terms();\n+\tif (check_and_set_terms(p))\n \t\treturn -1;\n \n \tif (!strcmp(p, \"start\")) {\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(argv.v, argv.nr);\n \t\tstrvec_clear(&argv);\n \t\treturn res;\n \t}\n \n-\tif (one_of(p, terms->term_good,\n-\t   terms->term_bad, \"skip\", NULL))\n-\t\treturn bisect_write(p, rev, terms, 0);\n+\tif (one_of(p, terms.term_good,\n+\t   terms.term_bad, \"skip\", NULL))\n+\t\treturn bisect_write(p, rev, 0);\n \n \tif (!strcmp(p, \"terms\")) {\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(argv.nr == 1 ? argv.v[0] : NULL);\n \t\tstrvec_clear(&argv);\n \t\treturn res;\n \t}\n@@ -1032,7 +1028,7 @@ 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 enum bisect_error bisect_replay(const char *filename)\n {\n \tFILE *fp = NULL;\n \tenum bisect_error res = BISECT_OK;\n@@ -1049,7 +1045,7 @@ static enum bisect_error bisect_replay(struct bisect_terms *terms, const char *f\n \t\treturn BISECT_FAILED;\n \n \twhile ((strbuf_getline(&line, fp) != EOF) && !res)\n-\t\tres = process_replay_line(terms, &line);\n+\t\tres = process_replay_line(&line);\n \n \tstrbuf_release(&line);\n \tfclose(fp);\n@@ -1057,10 +1053,10 @@ static enum bisect_error bisect_replay(struct bisect_terms *terms, const char *f\n \tif (res)\n \t\treturn BISECT_FAILED;\n \n-\treturn bisect_auto_next(terms, NULL);\n+\treturn bisect_auto_next(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(const char **argv, int argc)\n {\n \tint i;\n \tenum bisect_error res;\n@@ -1090,19 +1086,19 @@ 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(argv_state.v, argv_state.nr);\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(const char **argv, int argc)\n {\n \tstruct strvec args = STRVEC_INIT;\n \tint flags = RUN_COMMAND_NO_STDIN, res = 0;\n \tstruct strbuf sb = STRBUF_INIT;\n \n-\tif (bisect_next_check(terms, NULL) != 0)\n+\tif (bisect_next_check(NULL) != 0)\n \t\treturn BISECT_FAILED;\n \n \tif (!argc) {\n@@ -1141,14 +1137,13 @@ static int get_first_good(const char *refname, const struct object_id *oid,\n \treturn 1;\n }\n \n-static int verify_good(const struct bisect_terms *terms,\n-\t\t       const char **quoted_argv)\n+static int verify_good(const char **quoted_argv)\n {\n \tint rc;\n \tenum bisect_error res;\n \tstruct object_id good_rev;\n \tstruct object_id current_rev;\n-\tchar *good_glob = xstrfmt(\"%s-*\", terms->term_good);\n+\tchar *good_glob = xstrfmt(\"%s-*\", terms.term_good);\n \tint no_checkout = ref_exists(\"BISECT_HEAD\");\n \n \tfor_each_glob_ref_in(get_first_good, good_glob, \"refs/bisect/\",\n@@ -1172,7 +1167,7 @@ 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(const char **argv, int argc)\n {\n \tint res = BISECT_OK;\n \tstruct strbuf command = STRBUF_INIT;\n@@ -1181,7 +1176,7 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n \tint temporary_stdout_fd, saved_stdout;\n \tint is_first_run = 1;\n \n-\tif (bisect_next_check(terms, NULL))\n+\tif (bisect_next_check(NULL))\n \t\treturn BISECT_FAILED;\n \n \tif (argc)\n@@ -1205,7 +1200,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, run_args.v);\n+\t\t\tint rc = verify_good(run_args.v);\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@@ -1230,9 +1225,9 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n \t\tif (res == 125)\n \t\t\tnew_state = \"skip\";\n \t\telse if (!res)\n-\t\t\tnew_state = terms->term_good;\n+\t\t\tnew_state = terms.term_good;\n \t\telse\n-\t\t\tnew_state = terms->term_bad;\n+\t\t\tnew_state = terms.term_bad;\n \n \t\ttemporary_stdout_fd = open(git_path_bisect_run(), O_CREAT | O_WRONLY | O_TRUNC, 0666);\n \n@@ -1245,7 +1240,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(&new_state, 1);\n \n \t\tfflush(stdout);\n \t\tdup2(saved_stdout, 1);\n@@ -1314,7 +1309,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@@ -1332,22 +1326,22 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\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(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\tset_terms(\"bad\", \"good\");\n+\t\tres = bisect_start(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\tget_terms();\n+\t\tres = bisect_next(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\tset_terms(\"bad\", \"good\");\n+\t\tget_terms();\n+\t\tres = bisect_state(argv, argc);\n \t\tbreak;\n \tcase BISECT_LOG:\n \t\tif (argc)\n@@ -1357,28 +1351,28 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\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\tset_terms(\"bad\", \"good\");\n+\t\tres = bisect_replay(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\tset_terms(\"bad\", \"good\");\n+\t\tget_terms();\n+\t\tres = bisect_skip(argv, argc);\n \t\tbreak;\n \tcase BISECT_VISUALIZE:\n-\t\tget_terms(&terms);\n-\t\tres = bisect_visualize(&terms, argv, argc);\n+\t\tget_terms();\n+\t\tres = bisect_visualize(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\tget_terms();\n+\t\tres = bisect_run(argv, argc);\n \t\tbreak;\n \tdefault:\n \t\tBUG(\"unknown subcommand %d\", cmdmode);\n \t}\n-\tfree_terms(&terms);\n+\tfree_terms();\n \n \treturn is_bisect_success(res) ? 0 : -res;\n }\n-- \ngitgitgadget\n\n"},{"id":"462218","messageId":"e97e187bbec93b47f35e3dd42b4831f1c1d8658d.1661885419.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v6.git.1661885419.gitgitgadget@gmail.com","subject":"[PATCH v6 07/16] bisect--helper: migrate to OPT_SUBCOMMAND()","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-08-30T18:50:10Z","receivedAt":"2022-08-30T18:50:59Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nWe just introduced a new way to process subcommands, and the\n`bisect--helper` learns about it in preparation for replacing the\n`git-bisect.sh` script altogether.\n\nAs a consequence, the usage strings are copied over from the scripted\nversion of the `git bisect` command. To avoid regressing on 959d670d1a4\n(i18n: remove from i18n strings that do not hold translatable parts,\n2022-01-31), we specifically do not enclose usage strings in `N_(...)`\nthat do not contain any translatable parts.\n\nNote that a couple of `bisect_*()` functions are not converted into\n`cmd_bisect_*()` functions directly, as they have callers other than the\n`OPT_SUBCOMMAND()` one (and the original functions did not expect\na subcommand name to be passed as `argv[0]`, unlike the convention for\nthe `cmd_*()` functions. In those cases, we introduce wrapper functions\n`cmd_*()` that also call the original function.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/bisect--helper.c | 462 +++++++++++++++++++++++----------------\n git-bisect.sh            |  20 +-\n 2 files changed, 288 insertions(+), 194 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 0d7cc20f9c9..56d900c3d3c 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -20,18 +20,71 @@ 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+static const char * const bisect_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+\tN_(\"git bisect (bad|new) [<rev>]\"),\n+\tN_(\"git bisect (good|old) [<rev>...]\"),\n+\t\"git bisect terms [--term-good | --term-bad]\",\n+\tN_(\"git bisect skip [(<rev>|<range>)...]\"),\n+\t\"git bisect next\",\n+\tN_(\"git bisect reset [<commit>]\"),\n+\t\"git bisect (visualize|view)\",\n+\tN_(\"git bisect replay <logfile>\"),\n+\t\"git bisect log\",\n+\tN_(\"git bisect run <cmd>...\"),\n+\tNULL\n+};\n+\n+static const char * const 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+\tNULL\n+};\n+static const char * const bisect_state_usage[] = {\n+\tN_(\"git bisect (good|bad) [<rev>...]\"),\n+\tNULL\n+};\n+\n+static const char * const bisect_terms_usage[] = {\n+\t\"git bisect terms [--term-good | --term-bad]\",\n+\tNULL\n+};\n+\n+static const char * const bisect_skip_usage[] = {\n+\tN_(\"git bisect skip [(<rev>|<range>)...]\"),\n+\tNULL\n+};\n+\n+static const char * const bisect_next_usage[] = {\n+\t\"git bisect next\",\n+\tNULL\n+};\n+\n+static const char * const bisect_reset_usage[] = {\n+\tN_(\"git bisect reset [<commit>]\"),\n+\tNULL\n+};\n+\n+static const char * const bisect_visualize_usage[] = {\n+\t\"git bisect visualize\",\n+\tNULL\n+};\n+\n+static const char * const bisect_replay_usage[] = {\n+\tN_(\"git bisect replay <logfile>\"),\n+\tNULL\n+};\n+\n+static const char * const bisect_log_usage[] = {\n+\t\"git bisect log\",\n+\tNULL\n+};\n+\n+static const char * const bisect_run_usage[] = {\n+\tN_(\"git bisect run <cmd>...\"),\n \tNULL\n };\n \n@@ -63,7 +116,7 @@ static void set_terms(const char *bad,\n static const char vocab_bad[] = \"bad|new\";\n static const char vocab_good[] = \"good|old\";\n \n-static int bisect_autostart(void);\n+static int bisect_autostart(const char *prefix);\n \n /*\n  * Check whether the string `term` belongs to the set of strings\n@@ -238,6 +291,21 @@ static int bisect_reset(const char *commit)\n \treturn bisect_clean_state();\n }\n \n+static int cmd_bisect_reset(int argc, const char **argv, const char *prefix)\n+{\n+\tstruct option options[] = {\n+\t\tOPT_END()\n+\t};\n+\targc = parse_options(argc, argv, prefix, options,\n+\t\t\t     bisect_reset_usage, PARSE_OPT_STOP_AT_NON_OPTION);\n+\n+\tif (argc > 1)\n+\t\tusage_msg_opt(_(\"requires either no argument or a commit\"),\n+\t\t\t      bisect_reset_usage, options);\n+\n+\treturn bisect_reset(argc == 1 ? argv[0] : NULL);\n+}\n+\n static void log_commit(FILE *fp, char *fmt, const char *state,\n \t\t       struct commit *commit)\n {\n@@ -465,26 +533,41 @@ finish:\n \treturn res;\n }\n \n-static int bisect_terms(const char *option)\n+static int cmd_bisect_terms(int argc, const char **argv, const char *prefix)\n {\n+\tint mode = -1;\n+\tstruct option options[] = {\n+\t\tOPT_SET_INT(0, \"term-good\", &mode,\n+\t\t\t    N_(\"show term for good/old\"), 1),\n+\t\tOPT_SET_INT(0, \"term-old\", &mode,\n+\t\t\t    N_(\"show term for good/old\"), 1),\n+\t\tOPT_SET_INT(0, \"term-bad\", &mode,\n+\t\t\t    N_(\"show term for bad/new\"), 0),\n+\t\tOPT_SET_INT(0, \"term-new\", &mode,\n+\t\t\t    N_(\"show term for bad/new\"), 0),\n+\t\tOPT_END()\n+\t};\n+\n+\targc = parse_options(argc, argv, prefix, options,\n+\t\t\t     bisect_terms_usage, PARSE_OPT_STOP_AT_NON_OPTION);\n+\n+\tif (argc > 1)\n+\t\tusage_msg_opt(_(\"terms: requires 0 or 1 argument\"),\n+\t\t\t      bisect_terms_usage, options);\n+\n \tif (get_terms())\n \t\treturn error(_(\"no terms defined\"));\n \n-\tif (!option) {\n+\tif (mode < 0) {\n \t\tprintf(_(\"Your current terms are %s for the old state\\n\"\n \t\t\t \"and %s for the new state.\\n\"),\n \t\t       terms.term_good, terms.term_bad);\n \t\treturn 0;\n \t}\n-\tif (one_of(option, \"--term-good\", \"--term-old\", NULL))\n+\tif (mode == 1)\n \t\tprintf(\"%s\\n\", terms.term_good);\n-\telse if (one_of(option, \"--term-bad\", \"--term-new\", NULL))\n-\t\tprintf(\"%s\\n\", terms.term_bad);\n \telse\n-\t\treturn error(_(\"invalid argument %s for 'git bisect terms'.\\n\"\n-\t\t\t       \"Supported options are: \"\n-\t\t\t       \"--term-good|--term-old and \"\n-\t\t\t       \"--term-bad|--term-new.\"), option);\n+\t\tprintf(\"%s\\n\", terms.term_bad);\n \n \treturn 0;\n }\n@@ -623,7 +706,7 @@ static enum bisect_error bisect_next(const char *prefix)\n {\n \tenum bisect_error res;\n \n-\tif (bisect_autostart())\n+\tif (bisect_autostart(prefix))\n \t\treturn BISECT_FAILED;\n \n \tif (bisect_next_check(terms.term_good))\n@@ -642,6 +725,24 @@ static enum bisect_error bisect_next(const char *prefix)\n \treturn res;\n }\n \n+static int cmd_bisect_next(int argc, const char **argv, const char *prefix)\n+{\n+\tstruct option options[] = {\n+\t\tOPT_END()\n+\t};\n+\n+\tget_terms();\n+\targc = parse_options(argc, argv, prefix, options,\n+\t\t\t\tbisect_next_usage,\n+\t\t\t\tPARSE_OPT_STOP_AT_NON_OPTION);\n+\n+\tif (argc > 0)\n+\t\tusage_msg_opt(_(\"requires 0 argument\"),\n+\t\t\t      bisect_next_usage, options);\n+\n+\treturn bisect_next(prefix);\n+}\n+\n static enum bisect_error bisect_auto_next(const char *prefix)\n {\n \tif (bisect_next_check(NULL)) {\n@@ -652,8 +753,9 @@ static enum bisect_error bisect_auto_next(const char *prefix)\n \treturn bisect_next(prefix);\n }\n \n-static enum bisect_error bisect_start(int argc, const char **argv)\n+static int cmd_bisect_start(int argc, const char **argv, const char *prefix)\n {\n+\tstruct strvec orig_argv = STRVEC_INIT;\n \tint no_checkout = 0;\n \tint first_parent_only = 0;\n \tint i, has_double_dash = 0, must_write_terms = 0, bad_seen = 0;\n@@ -665,66 +767,64 @@ static enum bisect_error bisect_start(int argc, const char **argv)\n \tstruct strbuf bisect_names = STRBUF_INIT;\n \tstruct object_id head_oid;\n \tstruct object_id oid;\n-\tconst char *head;\n+\tconst char *head, *term_good = NULL, *term_bad = NULL;\n+\tstruct option options[] = {\n+\t\tOPT_BOOL(0, \"no-checkout\", &no_checkout,\n+\t\t\t N_(\"do not update worktree\")),\n+\t\tOPT_BOOL(0, \"first-parent\", &first_parent_only,\n+\t\t\t N_(\"follow only first parent of merge commits\")),\n+\t\tOPT_STRING(0, \"term-good\", &term_good, N_(\"term\"),\n+\t\t\t   N_(\"use this term instead of 'good'\")),\n+\t\tOPT_STRING(0, \"term-bad\", &term_bad, N_(\"term\"),\n+\t\t\t   N_(\"use this term instead of 'bad'\")),\n+\t\tOPT_STRING(0, \"term-old\", &term_good, N_(\"term\"),\n+\t\t\t   N_(\"use this term instead of 'good'\")),\n+\t\tOPT_STRING(0, \"term-new\", &term_bad, N_(\"term\"),\n+\t\t\t   N_(\"use this term instead of 'bad'\")),\n+\t\tOPT_END()\n+\t};\n+\n+\tset_terms(\"bad\", \"good\");\n \n \tif (is_bare_repository())\n \t\tno_checkout = 1;\n \n-\t/*\n-\t * Check for one bad and then some good revisions\n-\t */\n-\tfor (i = 0; i < argc; i++) {\n+\tstrvec_pushv(&orig_argv, argv); /* save the command-line for logging */\n+\targc = parse_options(argc, argv, prefix, options, bisect_start_usage,\n+\t\t\t     PARSE_OPT_KEEP_DASHDASH);\n+\n+\tif (term_good) {\n+\t\tfree(terms.term_good);\n+\t\tterms.term_good = xstrdup(term_good);\n+\t\tmust_write_terms = 1;\n+\t}\n+\n+\tif (term_bad) {\n+\t\tfree(terms.term_bad);\n+\t\tterms.term_bad = xstrdup(term_bad);\n+\t\tmust_write_terms = 1;\n+\t}\n+\n+\tfor (i = 0; i < argc; i++)\n \t\tif (!strcmp(argv[i], \"--\")) {\n \t\t\thas_double_dash = 1;\n \t\t\tbreak;\n \t\t}\n-\t}\n \n-\tfor (i = 0; i < argc; i++) {\n-\t\tconst char *arg = argv[i];\n-\t\tif (!strcmp(argv[i], \"--\")) {\n-\t\t\tbreak;\n-\t\t} else if (!strcmp(arg, \"--no-checkout\")) {\n-\t\t\tno_checkout = 1;\n-\t\t} else if (!strcmp(arg, \"--first-parent\")) {\n-\t\t\tfirst_parent_only = 1;\n-\t\t} else if (!strcmp(arg, \"--term-good\") ||\n-\t\t\t !strcmp(arg, \"--term-old\")) {\n-\t\t\ti++;\n-\t\t\tif (argc <= i)\n-\t\t\t\treturn error(_(\"'' is not a valid term\"));\n-\t\t\tmust_write_terms = 1;\n-\t\t\tfree((void *) terms.term_good);\n-\t\t\tterms.term_good = xstrdup(argv[i]);\n-\t\t} else if (skip_prefix(arg, \"--term-good=\", &arg) ||\n-\t\t\t   skip_prefix(arg, \"--term-old=\", &arg)) {\n-\t\t\tmust_write_terms = 1;\n-\t\t\tfree((void *) terms.term_good);\n-\t\t\tterms.term_good = xstrdup(arg);\n-\t\t} else if (!strcmp(arg, \"--term-bad\") ||\n-\t\t\t !strcmp(arg, \"--term-new\")) {\n-\t\t\ti++;\n-\t\t\tif (argc <= i)\n-\t\t\t\treturn error(_(\"'' is not a valid term\"));\n-\t\t\tmust_write_terms = 1;\n-\t\t\tfree((void *) terms.term_bad);\n-\t\t\tterms.term_bad = xstrdup(argv[i]);\n-\t\t} else if (skip_prefix(arg, \"--term-bad=\", &arg) ||\n-\t\t\t   skip_prefix(arg, \"--term-new=\", &arg)) {\n-\t\t\tmust_write_terms = 1;\n-\t\t\tfree((void *) terms.term_bad);\n-\t\t\tterms.term_bad = xstrdup(arg);\n-\t\t} else if (starts_with(arg, \"--\")) {\n-\t\t\treturn error(_(\"unrecognized option: '%s'\"), arg);\n-\t\t} else if (!get_oidf(&oid, \"%s^{commit}\", arg)) {\n+\t/*\n+\t * Check for one bad and then some good revisions\n+\t */\n+\n+\tfor (i = 0; i < argc && strcmp(argv[i], \"--\"); i++)\n+\t\tif (!get_oidf(&oid, \"%s^{commit}\", argv[i])) {\n \t\t\tstring_list_append(&revs, oid_to_hex(&oid));\n \t\t} else if (has_double_dash) {\n \t\t\tdie(_(\"'%s' does not appear to be a valid \"\n-\t\t\t      \"revision\"), arg);\n+\t\t\t      \"revision\"), argv[i]);\n \t\t} else {\n \t\t\tbreak;\n \t\t}\n-\t}\n+\n \tpathspec_pos = i;\n \n \t/*\n@@ -836,11 +936,13 @@ static enum bisect_error bisect_start(int argc, const char **argv)\n \t\tgoto finish;\n \t}\n \n-\tres = bisect_append_log_quoted(argv);\n+\tres = bisect_append_log_quoted(orig_argv.v + 1);\n \tif (res)\n \t\tres = BISECT_FAILED;\n \n finish:\n+\tstrvec_clear(&orig_argv);\n+\n \tstring_list_clear(&revs, 0);\n \tstring_list_clear(&states, 0);\n \tstrbuf_release(&start_head);\n@@ -848,7 +950,7 @@ finish:\n \tif (res)\n \t\treturn res;\n \n-\tres = bisect_auto_next(NULL);\n+\tres = bisect_auto_next(prefix);\n \tif (!is_bisect_success(res))\n \t\tbisect_clean_state();\n \treturn res;\n@@ -859,7 +961,7 @@ static inline int file_is_not_empty(const char *path)\n \treturn !is_empty_or_missing_file(path);\n }\n \n-static int bisect_autostart(void)\n+static int bisect_autostart(const char *prefix)\n {\n \tint res;\n \tconst char *yesno;\n@@ -881,12 +983,13 @@ static int bisect_autostart(void)\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(0, empty_strvec);\n+\t\t-1 : cmd_bisect_start(1, &yesno, prefix);\n \n \treturn res;\n }\n \n-static enum bisect_error bisect_state(int argc, const char **argv)\n+static enum bisect_error bisect_state(int argc, const char **argv,\n+\t\t\t\t      const char *prefix)\n {\n \tconst char *state;\n \tint i, verify_expected = 1;\n@@ -894,10 +997,8 @@ static enum bisect_error bisect_state(int argc, const char **argv)\n \tstruct strbuf buf = STRBUF_INIT;\n \tstruct oid_array revs = OID_ARRAY_INIT;\n \n-\tif (!argc)\n-\t\treturn error(_(\"Please call `--bisect-state` with at least one argument\"));\n \n-\tif (bisect_autostart())\n+\tif (bisect_autostart(prefix))\n \t\treturn BISECT_FAILED;\n \n \tstate = argv[0];\n@@ -966,11 +1067,41 @@ static enum bisect_error bisect_state(int argc, const char **argv)\n \treturn bisect_auto_next(NULL);\n }\n \n-static enum bisect_error bisect_log(void)\n+static int cmd_bisect_state(int argc, const char **argv,\n+\t\t\t\tconst char *prefix)\n {\n+\tstruct option options[] = {\n+\t\tOPT_END()\n+\t};\n+\n+\tset_terms(\"bad\", \"good\");\n+\tget_terms();\n+\n+\targc = parse_options(argc, argv, prefix, options,\n+\t\t\t     bisect_state_usage, PARSE_OPT_STOP_AT_NON_OPTION);\n+\n+\tif (!argc)\n+\t\tusage_msg_opt(_(\"need at least one argument\"),\n+\t\t\t      bisect_state_usage, options);\n+\n+\treturn bisect_state(argc, argv, prefix);\n+}\n+\n+static int cmd_bisect_log(int argc, const char **argv, const char *prefix)\n+{\n+\tstruct option options[] = {\n+\t\tOPT_END()\n+\t};\n \tint fd, status;\n \tconst char* filename = git_path_bisect_log();\n \n+\targc = parse_options(argc, argv, prefix, options,\n+\t\t\t     bisect_log_usage, PARSE_OPT_STOP_AT_NON_OPTION);\n+\n+\tif (argc > 0)\n+\t\tusage_msg_opt(_(\"require 0 argument\"), bisect_log_usage,\n+\t\t\t      options);\n+\n \tif (is_empty_or_missing_file(filename))\n \t\treturn error(_(\"We are not bisecting.\"));\n \n@@ -983,7 +1114,7 @@ static enum bisect_error bisect_log(void)\n \treturn status ? BISECT_FAILED : BISECT_OK;\n }\n \n-static int process_replay_line(struct strbuf *line)\n+static int process_replay_line(struct strbuf *line, const char *prefix)\n {\n \tconst char *p = line->buf + strspn(line->buf, \" \\t\");\n \tchar *word_end, *rev;\n@@ -1004,8 +1135,10 @@ static int process_replay_line(struct strbuf *line)\n \tif (!strcmp(p, \"start\")) {\n \t\tstruct strvec argv = STRVEC_INIT;\n \t\tint res;\n+\n+\t\tstrvec_push(&argv, p);\n \t\tsq_dequote_to_strvec(rev, &argv);\n-\t\tres = bisect_start(argv.nr, argv.v);\n+\t\tres = cmd_bisect_start(argv.nr, argv.v, prefix);\n \t\tstrvec_clear(&argv);\n \t\treturn res;\n \t}\n@@ -1017,8 +1150,11 @@ static int process_replay_line(struct strbuf *line)\n \tif (!strcmp(p, \"terms\")) {\n \t\tstruct strvec argv = STRVEC_INIT;\n \t\tint res;\n+\n+\t\tstrvec_push(&argv, p);\n \t\tsq_dequote_to_strvec(rev, &argv);\n-\t\tres = bisect_terms(argv.nr == 1 ? argv.v[0] : NULL);\n+\t\tres = cmd_bisect_terms(argv.nr, argv.v, NULL);\n+\n \t\tstrvec_clear(&argv);\n \t\treturn res;\n \t}\n@@ -1027,12 +1163,25 @@ static int process_replay_line(struct strbuf *line)\n \treturn -1;\n }\n \n-static enum bisect_error bisect_replay(const char *filename)\n+static int cmd_bisect_replay(int argc, const char **argv, const char *prefix)\n {\n+\tstruct option options[] = {\n+\t\tOPT_END()\n+\t};\n+\tconst char *filename;\n \tFILE *fp = NULL;\n \tenum bisect_error res = BISECT_OK;\n \tstruct strbuf line = STRBUF_INIT;\n \n+\tset_terms(\"bad\", \"good\");\n+\targc = parse_options(argc, argv, prefix, options,\n+\t\t\t     bisect_reset_usage, PARSE_OPT_STOP_AT_NON_OPTION);\n+\n+\tif (argc != 1)\n+\t\tusage_msg_opt(_(\"no logfile given\"), bisect_replay_usage,\n+\t\t\t      options);\n+\n+\tfilename = argv[0];\n \tif (is_empty_or_missing_file(filename))\n \t\treturn error(_(\"cannot read file '%s' for replaying\"), filename);\n \n@@ -1044,7 +1193,7 @@ static enum bisect_error bisect_replay(const char *filename)\n \t\treturn BISECT_FAILED;\n \n \twhile ((strbuf_getline(&line, fp) != EOF) && !res)\n-\t\tres = process_replay_line(&line);\n+\t\tres = process_replay_line(&line, prefix);\n \n \tstrbuf_release(&line);\n \tfclose(fp);\n@@ -1055,12 +1204,20 @@ static enum bisect_error bisect_replay(const char *filename)\n \treturn bisect_auto_next(NULL);\n }\n \n-static enum bisect_error bisect_skip(int argc, const char **argv)\n+static int cmd_bisect_skip(int argc, const char **argv, const char *prefix)\n {\n+\tstruct option options[] = {\n+\t\tOPT_END()\n+\t};\n \tint i;\n \tenum bisect_error res;\n \tstruct strvec argv_state = STRVEC_INIT;\n \n+\tset_terms(\"bad\", \"good\");\n+\tget_terms();\n+\targc = parse_options(argc, argv, prefix, options,\n+\t\t\t     bisect_skip_usage, PARSE_OPT_STOP_AT_NON_OPTION);\n+\n \tstrvec_push(&argv_state, \"skip\");\n \n \tfor (i = 0; i < argc; i++) {\n@@ -1085,18 +1242,28 @@ static enum bisect_error bisect_skip(int argc, const char **argv)\n \t\t\tstrvec_push(&argv_state, argv[i]);\n \t\t}\n \t}\n-\tres = bisect_state(argv_state.nr, argv_state.v);\n+\tres = bisect_state(argv_state.nr, argv_state.v, prefix);\n \n \tstrvec_clear(&argv_state);\n \treturn res;\n }\n \n-static int bisect_visualize(int argc, const char **argv)\n+static int cmd_bisect_visualize(int argc, const char **argv, const char *prefix)\n {\n+\tstruct option options[] = {\n+\t\tOPT_END()\n+\t};\n \tstruct strvec args = STRVEC_INIT;\n \tint flags = RUN_COMMAND_NO_STDIN, res = 0;\n \tstruct strbuf sb = STRBUF_INIT;\n \n+\tset_terms(\"bad\", \"good\");\n+\tget_terms();\n+\targc = parse_options(argc, argv, prefix, options,\n+\t\t\t     bisect_visualize_usage,\n+\t\t\t     PARSE_OPT_KEEP_DASHDASH |\n+\t\t\t     PARSE_OPT_KEEP_UNKNOWN_OPT);\n+\n \tif (bisect_next_check(NULL) != 0)\n \t\treturn BISECT_FAILED;\n \n@@ -1166,8 +1333,11 @@ static int verify_good(const char **quoted_argv)\n \treturn rc;\n }\n \n-static int bisect_run(int argc, const char **argv)\n+static int cmd_bisect_run(int argc, const char **argv, const char *prefix)\n {\n+\tstruct option options[] = {\n+\t\tOPT_END()\n+\t};\n \tint res = BISECT_OK;\n \tstruct strbuf command = STRBUF_INIT;\n \tstruct strvec run_args = STRVEC_INIT;\n@@ -1175,15 +1345,18 @@ static int bisect_run(int argc, const char **argv)\n \tint temporary_stdout_fd, saved_stdout;\n \tint is_first_run = 1;\n \n+\tget_terms();\n+\targc = parse_options(argc, argv, prefix, options,\n+\t\t\t     bisect_run_usage, PARSE_OPT_STOP_AT_NON_OPTION);\n+\n \tif (bisect_next_check(NULL))\n \t\treturn BISECT_FAILED;\n \n \tif (argc)\n \t\tsq_quote_argv(&command, argv);\n-\telse {\n-\t\terror(_(\"bisect run failed: no command provided.\"));\n-\t\treturn BISECT_FAILED;\n-\t}\n+\telse\n+\t\tusage_msg_opt(_(\"bisect run failed: no command provided.\"),\n+\t\t\t      bisect_run_usage, options);\n \n \tstrvec_push(&run_args, command.buf);\n \n@@ -1239,7 +1412,7 @@ static int bisect_run(int argc, const char **argv)\n \t\tsaved_stdout = dup(1);\n \t\tdup2(temporary_stdout_fd, 1);\n \n-\t\tres = bisect_state(1, &new_state);\n+\t\tres = bisect_state(1, &new_state, prefix);\n \n \t\tfflush(stdout);\n \t\tdup2(saved_stdout, 1);\n@@ -1272,105 +1445,26 @@ static int bisect_run(int argc, const char **argv)\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+\tparse_opt_subcommand_fn *fn = NULL;\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-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(\"run\", &fn, cmd_bisect_run),\n \t\tOPT_END()\n \t};\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-\n-\tif (!cmdmode)\n-\t\tusage_with_options(git_bisect_helper_usage, options);\n+\t\t\t     bisect_usage, 0);\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(argc == 1 ? argv[0] : NULL);\n-\t\tbreak;\n-\tcase BISECT_START:\n-\t\tset_terms(\"bad\", \"good\");\n-\t\tres = bisect_start(argc, argv);\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();\n-\t\tres = bisect_next(prefix);\n-\t\tbreak;\n-\tcase BISECT_STATE:\n-\t\tset_terms(\"bad\", \"good\");\n-\t\tget_terms();\n-\t\tres = bisect_state(argc, argv);\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(\"bad\", \"good\");\n-\t\tres = bisect_replay(argv[0]);\n-\t\tbreak;\n-\tcase BISECT_SKIP:\n-\t\tset_terms(\"bad\", \"good\");\n-\t\tget_terms();\n-\t\tres = bisect_skip(argc, argv);\n-\t\tbreak;\n-\tcase BISECT_VISUALIZE:\n-\t\tget_terms();\n-\t\tres = bisect_visualize(argc, argv);\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();\n-\t\tres = bisect_run(argc, argv);\n-\t\tbreak;\n-\tdefault:\n-\t\tBUG(\"unknown subcommand %d\", cmdmode);\n-\t}\n+\tres = fn(argc, argv, prefix);\n \tfree_terms();\n \n \treturn is_bisect_success(res) ? 0 : -res;\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\n-- \ngitgitgadget\n\n"},{"id":"462219","messageId":"30c87f2e92eacd315cf2ade6d704cdb03ef17a84.1661885419.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v6.git.1661885419.gitgitgadget@gmail.com","subject":"[PATCH v6 08/16] bisect: verify that a bogus option won't try to start a bisection","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-08-30T18:50:11Z","receivedAt":"2022-08-30T18:51:01Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nWe do not want `git bisect --bogus-option` to start a bisection. To\nverify that, we look for the tell-tale error message `You need to start\nby \"git bisect start\"` and fail if it was found.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n t/t6030-bisect-porcelain.sh | 10 ++++++++++\n 1 file changed, 10 insertions(+)\n\ndiff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh\nindex 83931d482fb..6d6e72276ae 100755\n--- a/t/t6030-bisect-porcelain.sh\n+++ b/t/t6030-bisect-porcelain.sh\n@@ -900,6 +900,16 @@ test_expect_success 'bisect start with one term1 and term2' '\n \tgit bisect reset\n '\n \n+test_expect_success 'bogus command does not start bisect' '\n+\tgit bisect reset &&\n+\ttest_must_fail git bisect --bisect-terms 1 2 2>out &&\n+\t! grep \"You need to start\" out &&\n+\ttest_must_fail git bisect --bisect-terms 2>out &&\n+\t! grep \"You need to start\" out &&\n+\tgrep \"git bisect.*visualize\" out &&\n+\tgit bisect reset\n+'\n+\n test_expect_success 'bisect replay with term1 and term2' '\n \tgit bisect replay log_to_replay.txt >bisect_result &&\n \tgrep \"$HASH2 is the first term1 commit\" bisect_result &&\n-- \ngitgitgadget\n\n"},{"id":"462220","messageId":"4696652b99ce05bece8e3abd10620aa4e4bba7c5.1661885419.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v6.git.1661885419.gitgitgadget@gmail.com","subject":"[PATCH v6 09/16] bisect run: fix the error message","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-08-30T18:50:12Z","receivedAt":"2022-08-30T18:51:05Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nIn d1bbbe45df8 (bisect--helper: reimplement `bisect_run` shell function\nin C, 2021-09-13), we ported the `bisect run` subcommand to C, including\nthe part that prints out an error message when the implicit `git bisect\nbad` or `git bisect good` failed.\n\nHowever, the error message was supposed to print out whether the state\nwas \"good\" or \"bad\", but used a bogus (because non-populated) `args`\nvariable for it. This was fixed in 80c2e9657f2 (bisect--helper: report\nactual bisect_state() argument on error, 2022-01-18), but the error\nmessage still talks about `bisect--helper`, which is an implementation\ndetail that should not concern end users.\n\nFix that, and add a regression test to ensure that the intended form of\nthe error message.\n\nHelped-by: Elijah Newren <newren@gmail.com>\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/bisect--helper.c    |  2 +-\n t/t6030-bisect-porcelain.sh | 10 ++++++++++\n 2 files changed, 11 insertions(+), 1 deletion(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 56d900c3d3c..ba4aa8059cb 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1430,7 +1430,7 @@ static int cmd_bisect_run(int argc, const char **argv, const char *prefix)\n \t\t\tprintf(_(\"bisect found first bad commit\"));\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: 'git bisect\"\n \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 6d6e72276ae..7a76f204083 100755\n--- a/t/t6030-bisect-porcelain.sh\n+++ b/t/t6030-bisect-porcelain.sh\n@@ -1063,4 +1063,14 @@ test_expect_success 'bisect state output with bad commit' '\n \tgrep -F \"waiting for good commit(s), bad commit known\" output\n '\n \n+test_expect_success 'verify correct error message' '\n+\tgit bisect reset &&\n+\tgit bisect start $HASH4 $HASH1 &&\n+\twrite_script test_script.sh <<-\\EOF &&\n+\trm .git/BISECT*\n+\tEOF\n+\ttest_must_fail git bisect run ./test_script.sh 2>error &&\n+\tgrep \"git bisect good.*exited with error code\" error\n+'\n+\n test_done\n-- \ngitgitgadget\n\n"},{"id":"462221","messageId":"b202a0e386c91b0dbe4b1d27d55276e6e1d76587.1661885419.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v6.git.1661885419.gitgitgadget@gmail.com","subject":"[PATCH v6 10/16] bisect: avoid double-quoting when printing the failed command","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-08-30T18:50:13Z","receivedAt":"2022-08-30T18:51:09Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nWe already quote the command via `sq_quote_argv()`, no need to enclose\nthe result in an extraneous pair of single-quotes.\n\nPointed out by Elijah Newren.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/bisect--helper.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex ba4aa8059cb..05fe619c47c 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1390,7 +1390,7 @@ static int cmd_bisect_run(int argc, const char **argv, const char *prefix)\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, command.buf);\n \t\t\tbreak;\n \t\t}\n \n-- \ngitgitgadget\n\n"},{"id":"462222","messageId":"3376b4508671491ff5c3e770ad3cd17203208bac.1661885419.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v6.git.1661885419.gitgitgadget@gmail.com","subject":"[PATCH v6 11/16] bisect--helper: calling `bisect_state()` without an argument is a bug","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-08-30T18:50:14Z","receivedAt":"2022-08-30T18:51:10Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nThe `bisect_state()` function is now a purely internal function and must\nbe called with a valid state, everything else is a bug.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/bisect--helper.c | 2 ++\n 1 file changed, 2 insertions(+)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 05fe619c47c..ac3b2e5b61c 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -997,6 +997,8 @@ static enum bisect_error bisect_state(int argc, const char **argv,\n \tstruct strbuf buf = STRBUF_INIT;\n \tstruct oid_array revs = OID_ARRAY_INIT;\n \n+\tif (!argc)\n+\t\tBUG(\"bisect_state() called without argument\");\n \n \tif (bisect_autostart(prefix))\n \t\treturn BISECT_FAILED;\n-- \ngitgitgadget\n\n"},{"id":"462223","messageId":"e7623508f90916d494915637342cd2327c7eea5e.1661885419.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v6.git.1661885419.gitgitgadget@gmail.com","subject":"[PATCH v6 12/16] bisect--helper: make `state` optional","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-08-30T18:50:15Z","receivedAt":"2022-08-30T18:51:12Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?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>\n---\n builtin/bisect--helper.c | 22 +++++++++++++++++++++-\n git-bisect.sh            |  2 +-\n 2 files changed, 22 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex ac3b2e5b61c..61e819e4efc 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1447,6 +1447,7 @@ static int cmd_bisect_run(int argc, const char **argv, const char *prefix)\n \n int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n {\n+\tstruct strvec args = STRVEC_INIT;\n \tparse_opt_subcommand_fn *fn = NULL;\n \tint res = 0;\n \tstruct option options[] = {\n@@ -1464,10 +1465,29 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t};\n \n \targc = parse_options(argc, argv, prefix, options,\n-\t\t\t     bisect_usage, 0);\n+\t\t\t     bisect_usage, PARSE_OPT_SUBCOMMAND_OPTIONAL);\n+\n+\tif (!fn) {\n+\t\tif (!argc)\n+\t\t\tusage_msg_opt(_(\"need a command\"), bisect_usage,\n+\t\t\t\t      options);\n+\n+\t\tset_terms(\"bad\", \"good\");\n+\t\tget_terms();\n+\t\tif (check_and_set_terms(argv[0]))\n+\t\t\tusage_msg_optf(_(\"unknown command: '%s'\"), bisect_usage,\n+\t\t\t\t       options, argv[0]);\n+\n+\t\tstrvec_push(&args, \"state\");\n+\t\tstrvec_pushv(&args, argv);\n+\t\targc = args.nr;\n+\t\targv = args.v;\n+\t\tfn = cmd_bisect_state;\n+\t}\n \n \tres = fn(argc, argv, prefix);\n \tfree_terms();\n+\tstrvec_clear(&args);\n \n \treturn is_bisect_success(res) ? 0 : -res;\n }\ndiff --git a/git-bisect.sh b/git-bisect.sh\nindex e19847eba0d..f4df8709d84 100755\n--- a/git-bisect.sh\n+++ b/git-bisect.sh\n@@ -60,7 +60,7 @@ case \"$#\" in\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+\t\tgit bisect--helper \"$cmd\" \"$@\" ;;\n \tskip)\n \t\tgit bisect--helper skip \"$@\" || exit;;\n \tnext)\n-- \ngitgitgadget\n\n"},{"id":"462224","messageId":"3f052580c95ff5a570374d17391de1592aa34047.1661885419.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v6.git.1661885419.gitgitgadget@gmail.com","subject":"[PATCH v6 13/16] bisect: move even the command-line parsing to `bisect--helper`","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-08-30T18:50:16Z","receivedAt":"2022-08-30T18:51:26Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nOn our journey to a fully built-in `git bisect`, this is the\nlast step.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/bisect--helper.c |  1 -\n git-bisect.sh            | 49 +---------------------------------------\n 2 files changed, 1 insertion(+), 49 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 61e819e4efc..6bcf16d9f62 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -1455,7 +1455,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),\ndiff --git a/git-bisect.sh b/git-bisect.sh\nindex f4df8709d84..028d39cd9ce 100755\n--- a/git-bisect.sh\n+++ b/git-bisect.sh\n@@ -34,51 +34,4 @@ 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 \"$cmd\" \"$@\" ;;\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\tusage ;;\n-\tesac\n-esac\n+exec git bisect--helper \"$@\"\n-- \ngitgitgadget\n\n"},{"id":"462225","messageId":"a83fe3dc3c2de664c8d0596564d4ac10dd79331f.1661885419.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v6.git.1661885419.gitgitgadget@gmail.com","subject":"[PATCH v6 14/16] Turn `git bisect` into a full built-in","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-08-30T18:50:17Z","receivedAt":"2022-08-30T18:51:29Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?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>\n---\n Makefile                               |  3 +--\n builtin.h                              |  2 +-\n builtin/{bisect--helper.c => bisect.c} |  2 +-\n git-bisect.sh                          | 37 --------------------------\n git.c                                  |  2 +-\n 5 files changed, 4 insertions(+), 42 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 1624471badc..4a79b2ba2fe 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@@ -1127,7 +1126,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 40e9ecc8485..b9470f8ab4f 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 6bcf16d9f62..46b65c91738 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect.c\n@@ -1445,7 +1445,7 @@ static int cmd_bisect_run(int argc, const char **argv, const char *prefix)\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 \tstruct strvec args = STRVEC_INIT;\n \tparse_opt_subcommand_fn *fn = NULL;\ndiff --git a/git-bisect.sh b/git-bisect.sh\ndeleted file mode 100755\nindex 028d39cd9ce..00000000000\n--- a/git-bisect.sh\n+++ /dev/null\n@@ -1,37 +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-exec git bisect--helper \"$@\"\ndiff --git a/git.c b/git.c\nindex f52a9554103..9c11727e29d 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-- \ngitgitgadget\n\n"},{"id":"462226","messageId":"f2132b61ff7d7959fd8efcd9d416736b154718f0.1661885419.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v6.git.1661885419.gitgitgadget@gmail.com","subject":"[PATCH v6 15/16] bisect: remove Cogito-related code","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-08-30T18:50:18Z","receivedAt":"2022-08-30T18:51:34Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nOnce upon a time, there was this idea that Git would not actually be a\nsingle coherent program, but rather a set of low-level programs that\nusers cobble together via shell scripts, or develop high-level user\ninterfaces for Git, or both.\n\nCogito was such a high-level user interface, incidentally implemented\nvia shell scripts that cobble together Git calls.\n\nIt did turn out relatively quickly that Git would much rather provide a\nuseful high-level user interface itself.\n\nAs of April 19th, 2007, Cogito was therefore discontinued (see\nhttps://lore.kernel.org/git/20070419124648.GL4489@pasky.or.cz/).\n\nNevertheless, for almost 15 years after that announcement, Git carried\nspecial code in `git bisect` to accommodate Cogito.\n\nSince it is beyond doubt that there are no more Cogito users, let's\nremove the last remnant of Cogito-accommodating code.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/bisect.c | 8 --------\n 1 file changed, 8 deletions(-)\n\ndiff --git a/builtin/bisect.c b/builtin/bisect.c\nindex 46b65c91738..a8deabf9eb1 100644\n--- a/builtin/bisect.c\n+++ b/builtin/bisect.c\n@@ -15,7 +15,6 @@ static GIT_PATH_FUNC(git_path_bisect_expected_rev, \"BISECT_EXPECTED_REV\")\n static GIT_PATH_FUNC(git_path_bisect_ancestors_ok, \"BISECT_ANCESTORS_OK\")\n static GIT_PATH_FUNC(git_path_bisect_start, \"BISECT_START\")\n static GIT_PATH_FUNC(git_path_bisect_log, \"BISECT_LOG\")\n-static GIT_PATH_FUNC(git_path_head_name, \"head-name\")\n 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@@ -880,13 +879,6 @@ static int cmd_bisect_start(int argc, const char **argv, const char *prefix)\n \t\t\tstrbuf_addstr(&start_head, oid_to_hex(&head_oid));\n \t\t} else if (!get_oid(head, &head_oid) &&\n \t\t\t   skip_prefix(head, \"refs/heads/\", &head)) {\n-\t\t\t/*\n-\t\t\t * This error message should only be triggered by\n-\t\t\t * cogito usage, and cogito users should understand\n-\t\t\t * it relates to cg-seek.\n-\t\t\t */\n-\t\t\tif (!is_empty_or_missing_file(git_path_head_name()))\n-\t\t\t\treturn error(_(\"won't bisect on cg-seek'ed tree\"));\n \t\t\tstrbuf_addstr(&start_head, head);\n \t\t} else {\n \t\t\treturn error(_(\"bad HEAD - strange symbolic ref\"));\n-- \ngitgitgadget\n\n"},{"id":"462227","messageId":"4f93692e071cf316fd391344b5dbbc995c162232.1661885419.git.gitgitgadget@gmail.com","threadId":"57326","inReplyTo":"pull.1132.v6.git.1661885419.gitgitgadget@gmail.com","subject":"[PATCH v6 16/16] bisect: no longer try to clean up left-over `.git/head-name` files","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-08-30T18:50:19Z","receivedAt":"2022-08-30T18:51:36Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nAs per the code comment, the `.git/head-name` files were cleaned up for\nbackwards-compatibility: an old version of `git bisect` could have left\nthem behind.\n\nNow, just how old would such a version be? As of 0f497e75f05 (Eliminate\nconfusing \"won't bisect on seeked tree\" failure, 2008-02-23), `git\nbisect` does not write that file anymore. Which corresponds to Git\nv1.5.4.4.\n\nEven if the likelihood is non-nil that there might still be users out\nthere who use such an old version to start a bisection, but then decide\nto continue bisecting with a current Git version, it is highly\nimprobable.\n\nSo let's remove that code, at long last.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n bisect.c                    | 3 ---\n t/t6030-bisect-porcelain.sh | 1 -\n 2 files changed, 4 deletions(-)\n\ndiff --git a/bisect.c b/bisect.c\nindex b63669cc9d7..00bd4ba581c 100644\n--- a/bisect.c\n+++ b/bisect.c\n@@ -474,7 +474,6 @@ static GIT_PATH_FUNC(git_path_bisect_start, \"BISECT_START\")\n static GIT_PATH_FUNC(git_path_bisect_log, \"BISECT_LOG\")\n static GIT_PATH_FUNC(git_path_bisect_terms, \"BISECT_TERMS\")\n static GIT_PATH_FUNC(git_path_bisect_first_parent, \"BISECT_FIRST_PARENT\")\n-static GIT_PATH_FUNC(git_path_head_name, \"head-name\")\n \n static void read_bisect_paths(struct strvec *array)\n {\n@@ -1181,8 +1180,6 @@ int bisect_clean_state(void)\n \tunlink_or_warn(git_path_bisect_run());\n \tunlink_or_warn(git_path_bisect_terms());\n \tunlink_or_warn(git_path_bisect_first_parent());\n-\t/* Cleanup head-name if it got left by an old version of git-bisect */\n-\tunlink_or_warn(git_path_head_name());\n \t/*\n \t * Cleanup BISECT_START last to support the --no-checkout option\n \t * introduced in the commit 4796e823a.\ndiff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh\nindex 7a76f204083..1d9cbf229e2 100755\n--- a/t/t6030-bisect-porcelain.sh\n+++ b/t/t6030-bisect-porcelain.sh\n@@ -1000,7 +1000,6 @@ test_expect_success 'git bisect reset cleans bisection state properly' '\n \ttest_path_is_missing \".git/BISECT_LOG\" &&\n \ttest_path_is_missing \".git/BISECT_RUN\" &&\n \ttest_path_is_missing \".git/BISECT_TERMS\" &&\n-\ttest_path_is_missing \".git/head-name\" &&\n \ttest_path_is_missing \".git/BISECT_HEAD\" &&\n \ttest_path_is_missing \".git/BISECT_START\"\n '\n-- \ngitgitgadget\n"},{"id":"462241","messageId":"xmqqmtblighr.fsf@gitster.g","threadId":"57326","inReplyTo":"92b3b116ef8f879192d9deb94d68b73e29d5dcd6.1661885419.git.gitgitgadget@gmail.com","subject":"Re: [PATCH v6 05/16] bisect--helper: make `terms` an explicit singleton","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-08-30T21:11:28Z","receivedAt":"2022-08-30T21:11:33Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Johannes Schindelin via GitGitGadget\" <gitgitgadget@gmail.com>\nwrites:\n\n> From: Johannes Schindelin <johannes.schindelin@gmx.de>\n>\n> We tried very hard to keep code in `builtin/bisect--helper.c` in as\n> libifyable a state as possible.\n>\n> However, we are about to migrate this built-in to the `OPT_SUBCOMMAND()`\n> API, which does not allow for passing any context (e.g. via a `void\n> *data` parameters as they are used in the config API).\n>\n> Therefore, we _have_ to move the `terms` variable outside of\n> `cmd_bisect__helper()` and explicitly make it a singleton (as it\n> currently is, anyway).\n\nWell, I do not find the above all that convincing.\n\nI can see that the top-level functions that are called from\nOPT_SUBCOMMAND(), because the only thing they get may be argc, argv,\nand prefix, may need to access a global variable to keep track of\nother states.  But all the helper functions that are called by them,\nwhich are already \"kept as libifyable as possible\", can be called\nwith a pointer to that global variable by these subcommand functions\nlike cmd_bisect_{terms,start,...}().  As long as the libification\nboundary is left relatively clean, I do not see the need to churn\nthis much code to change even the lowest level of helpers to access\nthe global.\n\nI was actually imagining that these functions that (used to) take a\npointer to \"struct bisect_terms\" can be moved to the top-level\n\"bisect.c\", together with the code already libified that drive the\n\"git bisect\" program, as part of the \"libified part of bisect\nengine\".\n\n> -static void free_terms(struct bisect_terms *terms)\n> +static void free_terms(void)\n>  {\n> -\tFREE_AND_NULL(terms->term_good);\n> -\tFREE_AND_NULL(terms->term_bad);\n> +\tFREE_AND_NULL(terms.term_good);\n> +\tFREE_AND_NULL(terms.term_bad);\n>  }\n\nFor example, at the tip of 'seen', free_term() are called by\nget_terms() and cmd_bisect() and nothing else.  get_terms(), before\nthis patch deliberately made it less libifiable, used to take a\npointer to \"struct bisect_terms\", so it is just the matter of\npassing what it got from its callers down to free_terms().\n\nget_terms() in turn are called from many places, but as far as I can\nsee, all the callers are either\n\n - functions that are OPT_SUBCOMMAND() handler, which should take\n   the pointer to the global &global_terms and pass it down to the\n   callchain that are \"kept libifiable\" until this step, or\n\n - functions that used to take a pointer to \"struct bisect_terms\"\n   before this step, and can just pass it down the callchain.\n\nThat is the impression after I tentatively modified the file at the\ntip of 'seen' to\n\n    static struct bisect_terms {\n            char *term_good;\n            char *term_bad;\n    } global_terms;\n\nand tried resurrect the \"as libified as possible\" state for some\ncall graphs.\n\nIs there a function I missed that MUST access the global *and* also\naccess pointer given as a parameter?  If there is such a codepath,\nthat would indeed cause a confusion for future developers and leave\na maintenance burden because developers do not have a clear guidance\nwhich one to use, but I do not think the current (i.e. the state\nbefore this step) \"as libifiable as possible\" state is not that bad.\n\nThanks.\n"},{"id":"462243","messageId":"xmqqfshdifq5.fsf@gitster.g","threadId":"57326","inReplyTo":"xmqqmtblighr.fsf@gitster.g","subject":"Re: [PATCH v6 05/16] bisect--helper: make `terms` an explicit singleton","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-08-30T21:28:02Z","receivedAt":"2022-08-30T21:28:07Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Well, I do not find the above all that convincing.\n\nHaving said all that, quite honestly, I do not care all that deeply.\n\nIt just looked suboptimal, even if we were to take the \"as long as\nthe end result 'works', we do not care\" attitude, to deliberately\nmake the code worse with a larger-than-necessary patch, and then\ncomplain that use of OPT_SUBCOMMAND() made you write unnecessary\ncode.\n\nWill push out another round of integration result sometime today and\nthis series will be part of 'seen'.\n\nThanks.\n"},{"id":"462980","messageId":"xmqqv8pr8903.fsf@gitster.g","threadId":"57326","inReplyTo":"pull.1132.v6.git.1661885419.gitgitgadget@gmail.com","subject":"Re: [PATCH v6 00/16] Finish converting git bisect into a built-in","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-09-13T17:44:12Z","receivedAt":"2022-09-13T18:26:52Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Johannes Schindelin via GitGitGadget\" <gitgitgadget@gmail.com>\nwrites:\n\n> Changes since v5:\n>\n>  * Fixed the commit message of \"bisect run: fix the error message\" that had\n>    become stale as of v3 due to 80c2e9657f2 \"overtaking\" it and doing half\n>    of its job.\n>  * Skipped translation usage strings in \"bisect--helper: migrate to\n>    OPT_SUBCOMMAND()\" that do not contain translatable parts.\n>  * Minor white-space clean-up in \"bisect--helper: migrate to\n>    OPT_SUBCOMMAND()\".\n\nOther than \"deliberately breaking the first steps that tried a nice\nlibification that passed 'terms' pair through the codepath could not\nbe a good idea\" thing, we did not see any comments on this round.\n\nDo people not care about this topic, are people all silently happy,\nor what?\n\n"}]}