All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/11] Finish converting git bisect into a built-in
@ 2022-01-28  0:12 Johannes Schindelin via GitGitGadget
  2022-01-28  0:12 ` [PATCH 01/11] bisect run: fix the error message Johannes Schindelin via GitGitGadget
                   ` (13 more replies)
  0 siblings, 14 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-01-28  0:12 UTC (permalink / raw)
  To: git; +Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio, Johannes Schindelin

After three GSoC/Outreachy students spent an incredible effort on this, it
is finally time to put a neat little bow on it.

Johannes Schindelin (11):
  bisect run: fix the error message
  bisect--helper: retire the --no-log option
  bisect--helper: really retire --bisect-next-check
  bisect--helper: really retire `--bisect-autostart`
  bisect--helper: align the sub-command order with git-bisect.sh
  bisect--helper: make `--bisect-state` optional
  bisect: move even the option parsing to `bisect--helper`
  bisect--helper: using `--bisect-state` without an argument is a bug
  Turn `git bisect` into a full built-in.
  bisect: remove Cogito-related code
  bisect: no longer try to clean up left-over `.git/head-name` files

 Makefile                               |   3 +-
 bisect.c                               |   3 -
 builtin.h                              |   2 +-
 builtin/{bisect--helper.c => bisect.c} | 201 ++++++++++---------------
 git-bisect.sh                          |  84 -----------
 git.c                                  |   2 +-
 t/t6030-bisect-porcelain.sh            |   1 -
 7 files changed, 84 insertions(+), 212 deletions(-)
 rename builtin/{bisect--helper.c => bisect.c} (87%)
 delete mode 100755 git-bisect.sh


base-commit: 89bece5c8c96f0b962cfc89e63f82d603fd60bed
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-1132%2Fdscho%2Fbisect-in-c-v1
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1132/dscho/bisect-in-c-v1
Pull-Request: https://github.com/gitgitgadget/git/pull/1132
-- 
gitgitgadget

^ permalink raw reply	[flat|nested] 147+ messages in thread

* [PATCH 01/11] bisect run: fix the error message
  2022-01-28  0:12 [PATCH 00/11] Finish converting git bisect into a built-in Johannes Schindelin via GitGitGadget
@ 2022-01-28  0:12 ` Johannes Schindelin via GitGitGadget
  2022-02-08 22:05   ` Elijah Newren
  2022-01-28  0:12 ` [PATCH 02/11] bisect--helper: retire the --no-log option Johannes Schindelin via GitGitGadget
                   ` (12 subsequent siblings)
  13 siblings, 1 reply; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-01-28  0:12 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Johannes Schindelin, Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

In d1bbbe45df8 (bisect--helper: reimplement `bisect_run` shell function
in C, 2021-09-13), we ported the `bisect run` subcommand to C, including
the part that prints out an error message when the implicit `git bisect
bad` or `git bisect good` failed.

However, the error message was supposed to print out whether the state
was "good" or "bad", but used a bogus (because non-populated) `args`
variable for it.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/bisect--helper.c | 8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 28a2e6a5750..4208206af07 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1093,7 +1093,6 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
 {
 	int res = BISECT_OK;
 	struct strbuf command = STRBUF_INIT;
-	struct strvec args = STRVEC_INIT;
 	struct strvec run_args = STRVEC_INIT;
 	const char *new_state;
 	int temporary_stdout_fd, saved_stdout;
@@ -1111,8 +1110,6 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
 	strvec_push(&run_args, command.buf);
 
 	while (1) {
-		strvec_clear(&args);
-
 		printf(_("running %s\n"), command.buf);
 		res = run_command_v_opt(run_args.v, RUN_USING_SHELL);
 
@@ -1157,14 +1154,13 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
 			printf(_("bisect found first bad commit"));
 			res = BISECT_OK;
 		} else if (res) {
-			error(_("bisect run failed: 'git bisect--helper --bisect-state"
-			" %s' exited with error code %d"), args.v[0], res);
+			error(_("bisect run failed: 'git bisect"
+			" %s' exited with error code %d"), new_state, res);
 		} else {
 			continue;
 		}
 
 		strbuf_release(&command);
-		strvec_clear(&args);
 		strvec_clear(&run_args);
 		return res;
 	}
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH 02/11] bisect--helper: retire the --no-log option
  2022-01-28  0:12 [PATCH 00/11] Finish converting git bisect into a built-in Johannes Schindelin via GitGitGadget
  2022-01-28  0:12 ` [PATCH 01/11] bisect run: fix the error message Johannes Schindelin via GitGitGadget
@ 2022-01-28  0:12 ` Johannes Schindelin via GitGitGadget
  2022-01-28  0:12 ` [PATCH 03/11] bisect--helper: really retire --bisect-next-check Johannes Schindelin via GitGitGadget
                   ` (11 subsequent siblings)
  13 siblings, 0 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-01-28  0:12 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Johannes Schindelin, Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

Turns out we actually never used it, anyway...

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/bisect--helper.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 4208206af07..9c8ba61dac0 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1182,7 +1182,7 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 		BISECT_VISUALIZE,
 		BISECT_RUN,
 	} cmdmode = 0;
-	int res = 0, nolog = 0;
+	int res = 0;
 	struct option options[] = {
 		OPT_CMDMODE(0, "bisect-reset", &cmdmode,
 			 N_("reset the bisection state"), BISECT_RESET),
@@ -1206,8 +1206,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 			 N_("visualize the bisection"), BISECT_VISUALIZE),
 		OPT_CMDMODE(0, "bisect-run", &cmdmode,
 			 N_("use <cmd>... to automatically bisect."), BISECT_RUN),
-		OPT_BOOL(0, "no-log", &nolog,
-			 N_("no log for BISECT_WRITE")),
 		OPT_END()
 	};
 	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH 03/11] bisect--helper: really retire --bisect-next-check
  2022-01-28  0:12 [PATCH 00/11] Finish converting git bisect into a built-in Johannes Schindelin via GitGitGadget
  2022-01-28  0:12 ` [PATCH 01/11] bisect run: fix the error message Johannes Schindelin via GitGitGadget
  2022-01-28  0:12 ` [PATCH 02/11] bisect--helper: retire the --no-log option Johannes Schindelin via GitGitGadget
@ 2022-01-28  0:12 ` Johannes Schindelin via GitGitGadget
  2022-01-28  0:12 ` [PATCH 04/11] bisect--helper: really retire `--bisect-autostart` Johannes Schindelin via GitGitGadget
                   ` (10 subsequent siblings)
  13 siblings, 0 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-01-28  0:12 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Johannes Schindelin, Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

In 911aba14205 (bisect--helper: retire `--bisect-next-check` subcommand,
2021-09-13), we removed the usage string and the implementation, but not
actually the option.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/bisect--helper.c | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 9c8ba61dac0..dc840736cb5 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1170,7 +1170,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 {
 	enum {
 		BISECT_RESET = 1,
-		BISECT_NEXT_CHECK,
 		BISECT_TERMS,
 		BISECT_START,
 		BISECT_AUTOSTART,
@@ -1186,8 +1185,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 	struct option options[] = {
 		OPT_CMDMODE(0, "bisect-reset", &cmdmode,
 			 N_("reset the bisection state"), BISECT_RESET),
-		OPT_CMDMODE(0, "bisect-next-check", &cmdmode,
-			 N_("check whether bad or good terms exist"), BISECT_NEXT_CHECK),
 		OPT_CMDMODE(0, "bisect-terms", &cmdmode,
 			 N_("print out the bisect terms"), BISECT_TERMS),
 		OPT_CMDMODE(0, "bisect-start", &cmdmode,
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH 04/11] bisect--helper: really retire `--bisect-autostart`
  2022-01-28  0:12 [PATCH 00/11] Finish converting git bisect into a built-in Johannes Schindelin via GitGitGadget
                   ` (2 preceding siblings ...)
  2022-01-28  0:12 ` [PATCH 03/11] bisect--helper: really retire --bisect-next-check Johannes Schindelin via GitGitGadget
@ 2022-01-28  0:12 ` Johannes Schindelin via GitGitGadget
  2022-01-28  0:12 ` [PATCH 05/11] bisect--helper: align the sub-command order with git-bisect.sh Johannes Schindelin via GitGitGadget
                   ` (9 subsequent siblings)
  13 siblings, 0 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-01-28  0:12 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Johannes Schindelin, Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

Since b0f6494f70f (bisect--helper: retire `--bisect-autostart`
subcommand, 2020-10-15), the `--bisect-autostart` option is no more. But
we kept the `enum` value of the command mode around. Let's drop it, too.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/bisect--helper.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index dc840736cb5..7ba4be1947e 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1172,7 +1172,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 		BISECT_RESET = 1,
 		BISECT_TERMS,
 		BISECT_START,
-		BISECT_AUTOSTART,
 		BISECT_NEXT,
 		BISECT_STATE,
 		BISECT_LOG,
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH 05/11] bisect--helper: align the sub-command order with git-bisect.sh
  2022-01-28  0:12 [PATCH 00/11] Finish converting git bisect into a built-in Johannes Schindelin via GitGitGadget
                   ` (3 preceding siblings ...)
  2022-01-28  0:12 ` [PATCH 04/11] bisect--helper: really retire `--bisect-autostart` Johannes Schindelin via GitGitGadget
@ 2022-01-28  0:12 ` Johannes Schindelin via GitGitGadget
  2022-01-28  0:12 ` [PATCH 06/11] bisect--helper: make `--bisect-state` optional Johannes Schindelin via GitGitGadget
                   ` (8 subsequent siblings)
  13 siblings, 0 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-01-28  0:12 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Johannes Schindelin, Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

We are about to retire the shell implementation of `git bisect`, or
maybe better put: the remainder of the shell implementation (a shell of
a script, if you want).

In preparation for that, align the order of the sub-commands with the
way the outgoing implementation presents them to the user.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/bisect--helper.c | 76 ++++++++++++++++++++--------------------
 1 file changed, 38 insertions(+), 38 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 7ba4be1947e..cc5a9ca41b9 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1169,37 +1169,37 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
 int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 {
 	enum {
-		BISECT_RESET = 1,
-		BISECT_TERMS,
-		BISECT_START,
-		BISECT_NEXT,
+		BISECT_START = 1,
 		BISECT_STATE,
-		BISECT_LOG,
-		BISECT_REPLAY,
+		BISECT_TERMS,
 		BISECT_SKIP,
+		BISECT_NEXT,
+		BISECT_RESET,
 		BISECT_VISUALIZE,
+		BISECT_REPLAY,
+		BISECT_LOG,
 		BISECT_RUN,
 	} cmdmode = 0;
 	int res = 0;
 	struct option options[] = {
-		OPT_CMDMODE(0, "bisect-reset", &cmdmode,
-			 N_("reset the bisection state"), BISECT_RESET),
-		OPT_CMDMODE(0, "bisect-terms", &cmdmode,
-			 N_("print out the bisect terms"), BISECT_TERMS),
 		OPT_CMDMODE(0, "bisect-start", &cmdmode,
 			 N_("start the bisect session"), BISECT_START),
-		OPT_CMDMODE(0, "bisect-next", &cmdmode,
-			 N_("find the next bisection commit"), BISECT_NEXT),
 		OPT_CMDMODE(0, "bisect-state", &cmdmode,
 			 N_("mark the state of ref (or refs)"), BISECT_STATE),
-		OPT_CMDMODE(0, "bisect-log", &cmdmode,
-			 N_("list the bisection steps so far"), BISECT_LOG),
-		OPT_CMDMODE(0, "bisect-replay", &cmdmode,
-			 N_("replay the bisection process from the given file"), BISECT_REPLAY),
+		OPT_CMDMODE(0, "bisect-terms", &cmdmode,
+			 N_("print out the bisect terms"), BISECT_TERMS),
 		OPT_CMDMODE(0, "bisect-skip", &cmdmode,
 			 N_("skip some commits for checkout"), BISECT_SKIP),
+		OPT_CMDMODE(0, "bisect-next", &cmdmode,
+			 N_("find the next bisection commit"), BISECT_NEXT),
+		OPT_CMDMODE(0, "bisect-reset", &cmdmode,
+			 N_("reset the bisection state"), BISECT_RESET),
 		OPT_CMDMODE(0, "bisect-visualize", &cmdmode,
 			 N_("visualize the bisection"), BISECT_VISUALIZE),
+		OPT_CMDMODE(0, "bisect-replay", &cmdmode,
+			 N_("replay the bisection process from the given file"), BISECT_REPLAY),
+		OPT_CMDMODE(0, "bisect-log", &cmdmode,
+			 N_("list the bisection steps so far"), BISECT_LOG),
 		OPT_CMDMODE(0, "bisect-run", &cmdmode,
 			 N_("use <cmd>... to automatically bisect."), BISECT_RUN),
 		OPT_END()
@@ -1214,19 +1214,24 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 		usage_with_options(git_bisect_helper_usage, options);
 
 	switch (cmdmode) {
-	case BISECT_RESET:
-		if (argc > 1)
-			return error(_("--bisect-reset requires either no argument or a commit"));
-		res = bisect_reset(argc ? argv[0] : NULL);
+	case BISECT_START:
+		set_terms(&terms, "bad", "good");
+		res = bisect_start(&terms, argv, argc);
+		break;
+	case BISECT_STATE:
+		set_terms(&terms, "bad", "good");
+		get_terms(&terms);
+		res = bisect_state(&terms, argv, argc);
 		break;
 	case BISECT_TERMS:
 		if (argc > 1)
 			return error(_("--bisect-terms requires 0 or 1 argument"));
 		res = bisect_terms(&terms, argc == 1 ? argv[0] : NULL);
 		break;
-	case BISECT_START:
+	case BISECT_SKIP:
 		set_terms(&terms, "bad", "good");
-		res = bisect_start(&terms, argv, argc);
+		get_terms(&terms);
+		res = bisect_skip(&terms, argv, argc);
 		break;
 	case BISECT_NEXT:
 		if (argc)
@@ -1234,15 +1239,14 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 		get_terms(&terms);
 		res = bisect_next(&terms, prefix);
 		break;
-	case BISECT_STATE:
-		set_terms(&terms, "bad", "good");
-		get_terms(&terms);
-		res = bisect_state(&terms, argv, argc);
+	case BISECT_RESET:
+		if (argc > 1)
+			return error(_("--bisect-reset requires either no argument or a commit"));
+		res = bisect_reset(argc ? argv[0] : NULL);
 		break;
-	case BISECT_LOG:
-		if (argc)
-			return error(_("--bisect-log requires 0 arguments"));
-		res = bisect_log();
+	case BISECT_VISUALIZE:
+		get_terms(&terms);
+		res = bisect_visualize(&terms, argv, argc);
 		break;
 	case BISECT_REPLAY:
 		if (argc != 1)
@@ -1250,14 +1254,10 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 		set_terms(&terms, "bad", "good");
 		res = bisect_replay(&terms, argv[0]);
 		break;
-	case BISECT_SKIP:
-		set_terms(&terms, "bad", "good");
-		get_terms(&terms);
-		res = bisect_skip(&terms, argv, argc);
-		break;
-	case BISECT_VISUALIZE:
-		get_terms(&terms);
-		res = bisect_visualize(&terms, argv, argc);
+	case BISECT_LOG:
+		if (argc)
+			return error(_("--bisect-log requires 0 arguments"));
+		res = bisect_log();
 		break;
 	case BISECT_RUN:
 		if (!argc)
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH 06/11] bisect--helper: make `--bisect-state` optional
  2022-01-28  0:12 [PATCH 00/11] Finish converting git bisect into a built-in Johannes Schindelin via GitGitGadget
                   ` (4 preceding siblings ...)
  2022-01-28  0:12 ` [PATCH 05/11] bisect--helper: align the sub-command order with git-bisect.sh Johannes Schindelin via GitGitGadget
@ 2022-01-28  0:12 ` Johannes Schindelin via GitGitGadget
  2022-02-08 23:03   ` Elijah Newren
  2022-02-09 19:45   ` Junio C Hamano
  2022-01-28  0:12 ` [PATCH 07/11] bisect: move even the option parsing to `bisect--helper` Johannes Schindelin via GitGitGadget
                   ` (7 subsequent siblings)
  13 siblings, 2 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-01-28  0:12 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Johannes Schindelin, Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

In preparation for making `git bisect` a real built-in, let's prepare
the `bisect--helper` built-in to handle `git bisect--helper good` and
`git bisect--helper bad`, i.e. do not require the `--bisect-state`
option to be passed explicitly.

To prepare for converting `bisect--helper` to a full built-in
implementation of `git bisect` (which must not require the
`--bisect-state` option to be specified at all), let's move the handling
toward the end of the `switch (cmdmode)` block.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/bisect--helper.c | 23 ++++++++++++++++-------
 1 file changed, 16 insertions(+), 7 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index cc5a9ca41b9..219fa99cd0b 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -26,8 +26,8 @@ static const char * const git_bisect_helper_usage[] = {
 	N_("git bisect--helper --bisect-start [--term-{new,bad}=<term> --term-{old,good}=<term>]"
 					    " [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<paths>...]"),
 	N_("git bisect--helper --bisect-next"),
-	N_("git bisect--helper --bisect-state (bad|new) [<rev>]"),
-	N_("git bisect--helper --bisect-state (good|old) [<rev>...]"),
+	N_("git bisect--helper [--bisect-state] (bad|new) [<rev>]"),
+	N_("git bisect--helper [--bisect-state] (good|old) [<rev>...]"),
 	N_("git bisect--helper --bisect-replay <filename>"),
 	N_("git bisect--helper --bisect-skip [(<rev>|<range>)...]"),
 	N_("git bisect--helper --bisect-visualize"),
@@ -1210,6 +1210,13 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 			     git_bisect_helper_usage,
 			     PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN);
 
+	if (!cmdmode && argc > 0) {
+		set_terms(&terms, "bad", "good");
+		get_terms(&terms);
+		if (!check_and_set_terms(&terms, argv[0]))
+			cmdmode = BISECT_STATE;
+	}
+
 	if (!cmdmode)
 		usage_with_options(git_bisect_helper_usage, options);
 
@@ -1218,11 +1225,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 		set_terms(&terms, "bad", "good");
 		res = bisect_start(&terms, argv, argc);
 		break;
-	case BISECT_STATE:
-		set_terms(&terms, "bad", "good");
-		get_terms(&terms);
-		res = bisect_state(&terms, argv, argc);
-		break;
 	case BISECT_TERMS:
 		if (argc > 1)
 			return error(_("--bisect-terms requires 0 or 1 argument"));
@@ -1265,6 +1267,13 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 		get_terms(&terms);
 		res = bisect_run(&terms, argv, argc);
 		break;
+	case BISECT_STATE:
+		if (!terms.term_good) {
+			set_terms(&terms, "bad", "good");
+			get_terms(&terms);
+		}
+		res = bisect_state(&terms, argv, argc);
+		break;
 	default:
 		BUG("unknown subcommand %d", cmdmode);
 	}
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH 07/11] bisect: move even the option parsing to `bisect--helper`
  2022-01-28  0:12 [PATCH 00/11] Finish converting git bisect into a built-in Johannes Schindelin via GitGitGadget
                   ` (5 preceding siblings ...)
  2022-01-28  0:12 ` [PATCH 06/11] bisect--helper: make `--bisect-state` optional Johannes Schindelin via GitGitGadget
@ 2022-01-28  0:12 ` Johannes Schindelin via GitGitGadget
  2022-01-29  6:47   ` Ævar Arnfjörð Bjarmason
  2022-02-09  0:12   ` Elijah Newren
  2022-01-28  0:12 ` [PATCH 08/11] bisect--helper: using `--bisect-state` without an argument is a bug Johannes Schindelin via GitGitGadget
                   ` (6 subsequent siblings)
  13 siblings, 2 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-01-28  0:12 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Johannes Schindelin, Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

On our journey to a fully built-in `git bisect`, this is the
second-to-last step.

Side note: The `if (!strcmp(...)) ... else if (!strcmp(...)) ... else if
(!strcmp(...)) ...` chain seen in this patch was not actually the first
idea how to convert the command modes to sub-commands. Since the
`bisect--helper` command already used the `parse-opions` API with neatly
set-up command modes, naturally the idea was to use `PARSE_OPT_NODASH`
to support proper sub-commands instead. However, the `parse-options` API
is not set up for that, and even after making that option work with long
options, it turned out that `STOP_AT_NON_OPTION` and `KEEP_UNKNOWN`
would have to be used but these options were not designed to work
together. So it would appear as if a lot of work would have to be done
just to be able to use `parse_options()` just to parse the sub-command,
instead of a simple `if...else if` chain, the latter being a
dramatically simpler implementation. Therefore, we now keep the
`parse_options()` call primarily to support `-h` and little else.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/bisect--helper.c | 172 ++++++++++++++++-----------------------
 git-bisect.sh            |  49 +----------
 2 files changed, 72 insertions(+), 149 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 219fa99cd0b..4450305c81c 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -20,18 +20,34 @@ static GIT_PATH_FUNC(git_path_bisect_names, "BISECT_NAMES")
 static GIT_PATH_FUNC(git_path_bisect_first_parent, "BISECT_FIRST_PARENT")
 static GIT_PATH_FUNC(git_path_bisect_run, "BISECT_RUN")
 
-static const char * const git_bisect_helper_usage[] = {
-	N_("git bisect--helper --bisect-reset [<commit>]"),
-	N_("git bisect--helper --bisect-terms [--term-good | --term-old | --term-bad | --term-new]"),
-	N_("git bisect--helper --bisect-start [--term-{new,bad}=<term> --term-{old,good}=<term>]"
-					    " [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<paths>...]"),
-	N_("git bisect--helper --bisect-next"),
-	N_("git bisect--helper [--bisect-state] (bad|new) [<rev>]"),
-	N_("git bisect--helper [--bisect-state] (good|old) [<rev>...]"),
-	N_("git bisect--helper --bisect-replay <filename>"),
-	N_("git bisect--helper --bisect-skip [(<rev>|<range>)...]"),
-	N_("git bisect--helper --bisect-visualize"),
-	N_("git bisect--helper --bisect-run <cmd>..."),
+static const char * const git_bisect_usage[] = {
+	N_("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."),
 	NULL
 };
 
@@ -1168,115 +1184,69 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
 
 int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 {
-	enum {
-		BISECT_START = 1,
-		BISECT_STATE,
-		BISECT_TERMS,
-		BISECT_SKIP,
-		BISECT_NEXT,
-		BISECT_RESET,
-		BISECT_VISUALIZE,
-		BISECT_REPLAY,
-		BISECT_LOG,
-		BISECT_RUN,
-	} cmdmode = 0;
 	int res = 0;
 	struct option options[] = {
-		OPT_CMDMODE(0, "bisect-start", &cmdmode,
-			 N_("start the bisect session"), BISECT_START),
-		OPT_CMDMODE(0, "bisect-state", &cmdmode,
-			 N_("mark the state of ref (or refs)"), BISECT_STATE),
-		OPT_CMDMODE(0, "bisect-terms", &cmdmode,
-			 N_("print out the bisect terms"), BISECT_TERMS),
-		OPT_CMDMODE(0, "bisect-skip", &cmdmode,
-			 N_("skip some commits for checkout"), BISECT_SKIP),
-		OPT_CMDMODE(0, "bisect-next", &cmdmode,
-			 N_("find the next bisection commit"), BISECT_NEXT),
-		OPT_CMDMODE(0, "bisect-reset", &cmdmode,
-			 N_("reset the bisection state"), BISECT_RESET),
-		OPT_CMDMODE(0, "bisect-visualize", &cmdmode,
-			 N_("visualize the bisection"), BISECT_VISUALIZE),
-		OPT_CMDMODE(0, "bisect-replay", &cmdmode,
-			 N_("replay the bisection process from the given file"), BISECT_REPLAY),
-		OPT_CMDMODE(0, "bisect-log", &cmdmode,
-			 N_("list the bisection steps so far"), BISECT_LOG),
-		OPT_CMDMODE(0, "bisect-run", &cmdmode,
-			 N_("use <cmd>... to automatically bisect."), BISECT_RUN),
 		OPT_END()
 	};
 	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
+	const char *command = argc > 1 ? argv[1] : "help";
 
-	argc = parse_options(argc, argv, prefix, options,
-			     git_bisect_helper_usage,
-			     PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN);
+	/* Handle -h and invalid options */
+	parse_options(argc - 1, argv + 1, prefix, options,
+		      git_bisect_usage,
+		      PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN |
+		      PARSE_OPT_ONE_SHOT | PARSE_OPT_STOP_AT_NON_OPTION);
 
-	if (!cmdmode && argc > 0) {
+	if (!strcmp("help", command))
+		usage_with_options(git_bisect_usage, options);
+	else if (!strcmp("start", command)) {
 		set_terms(&terms, "bad", "good");
-		get_terms(&terms);
-		if (!check_and_set_terms(&terms, argv[0]))
-			cmdmode = BISECT_STATE;
-	}
-
-	if (!cmdmode)
-		usage_with_options(git_bisect_helper_usage, options);
-
-	switch (cmdmode) {
-	case BISECT_START:
-		set_terms(&terms, "bad", "good");
-		res = bisect_start(&terms, argv, argc);
-		break;
-	case BISECT_TERMS:
-		if (argc > 1)
-			return error(_("--bisect-terms requires 0 or 1 argument"));
-		res = bisect_terms(&terms, argc == 1 ? argv[0] : NULL);
-		break;
-	case BISECT_SKIP:
+		res = bisect_start(&terms, argv + 2, argc - 2);
+	} else if (!strcmp("terms", command)) {
+		if (argc > 3)
+			return error(_("'terms' requires 0 or 1 argument"));
+		res = bisect_terms(&terms, argc == 3 ? argv[2] : NULL);
+	} else if (!strcmp("skip", command)) {
 		set_terms(&terms, "bad", "good");
 		get_terms(&terms);
-		res = bisect_skip(&terms, argv, argc);
-		break;
-	case BISECT_NEXT:
-		if (argc)
-			return error(_("--bisect-next requires 0 arguments"));
+		res = bisect_skip(&terms, argv + 2, argc - 2);
+	} else if (!strcmp("next", command)) {
+		if (argc != 2)
+			return error(_("'next' requires 0 arguments"));
 		get_terms(&terms);
 		res = bisect_next(&terms, prefix);
-		break;
-	case BISECT_RESET:
-		if (argc > 1)
-			return error(_("--bisect-reset requires either no argument or a commit"));
-		res = bisect_reset(argc ? argv[0] : NULL);
-		break;
-	case BISECT_VISUALIZE:
+	} else if (!strcmp("reset", command)) {
+		if (argc > 3)
+			return error(_("'reset' requires either no argument or a commit"));
+		res = bisect_reset(argc > 2 ? argv[2] : NULL);
+	} else if (one_of(command, "visualize", "view", NULL)) {
 		get_terms(&terms);
-		res = bisect_visualize(&terms, argv, argc);
-		break;
-	case BISECT_REPLAY:
-		if (argc != 1)
+		res = bisect_visualize(&terms, argv + 2, argc - 2);
+	} else if (!strcmp("replay", command)) {
+		if (argc != 3)
 			return error(_("no logfile given"));
 		set_terms(&terms, "bad", "good");
-		res = bisect_replay(&terms, argv[0]);
-		break;
-	case BISECT_LOG:
-		if (argc)
-			return error(_("--bisect-log requires 0 arguments"));
+		res = bisect_replay(&terms, argv[2]);
+	} else if (!strcmp("log", command)) {
+		if (argc > 2)
+			return error(_("'log' requires 0 arguments"));
 		res = bisect_log();
-		break;
-	case BISECT_RUN:
-		if (!argc)
+	} else if (!strcmp("run", command)) {
+		if (argc < 3)
 			return error(_("bisect run failed: no command provided."));
 		get_terms(&terms);
-		res = bisect_run(&terms, argv, argc);
-		break;
-	case BISECT_STATE:
-		if (!terms.term_good) {
-			set_terms(&terms, "bad", "good");
-			get_terms(&terms);
+		res = bisect_run(&terms, argv + 2, argc - 2);
+	} else {
+		set_terms(&terms, "bad", "good");
+		get_terms(&terms);
+		if (!check_and_set_terms(&terms, command))
+			res = bisect_state(&terms, argv + 1, argc - 1);
+		else {
+			char *msg = xstrfmt(_("unknown command: '%s'"), command);
+			usage_msg_opt(msg, git_bisect_usage, options);
 		}
-		res = bisect_state(&terms, argv, argc);
-		break;
-	default:
-		BUG("unknown subcommand %d", cmdmode);
 	}
+
 	free_terms(&terms);
 
 	/*
diff --git a/git-bisect.sh b/git-bisect.sh
index 405cf76f2a3..028d39cd9ce 100755
--- a/git-bisect.sh
+++ b/git-bisect.sh
@@ -34,51 +34,4 @@ Please use "git help bisect" to get the full man page.'
 OPTIONS_SPEC=
 . git-sh-setup
 
-TERM_BAD=bad
-TERM_GOOD=good
-
-get_terms () {
-	if test -s "$GIT_DIR/BISECT_TERMS"
-	then
-		{
-		read TERM_BAD
-		read TERM_GOOD
-		} <"$GIT_DIR/BISECT_TERMS"
-	fi
-}
-
-case "$#" in
-0)
-	usage ;;
-*)
-	cmd="$1"
-	get_terms
-	shift
-	case "$cmd" in
-	help)
-		git bisect -h ;;
-	start)
-		git bisect--helper --bisect-start "$@" ;;
-	bad|good|new|old|"$TERM_BAD"|"$TERM_GOOD")
-		git bisect--helper --bisect-state "$cmd" "$@" ;;
-	skip)
-		git bisect--helper --bisect-skip "$@" || exit;;
-	next)
-		# Not sure we want "next" at the UI level anymore.
-		git bisect--helper --bisect-next "$@" || exit ;;
-	visualize|view)
-		git bisect--helper --bisect-visualize "$@" || exit;;
-	reset)
-		git bisect--helper --bisect-reset "$@" ;;
-	replay)
-		git bisect--helper --bisect-replay "$@" || exit;;
-	log)
-		git bisect--helper --bisect-log || exit ;;
-	run)
-		git bisect--helper --bisect-run "$@" || exit;;
-	terms)
-		git bisect--helper --bisect-terms "$@" || exit;;
-	*)
-		usage ;;
-	esac
-esac
+exec git bisect--helper "$@"
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH 08/11] bisect--helper: using `--bisect-state` without an argument is a bug
  2022-01-28  0:12 [PATCH 00/11] Finish converting git bisect into a built-in Johannes Schindelin via GitGitGadget
                   ` (6 preceding siblings ...)
  2022-01-28  0:12 ` [PATCH 07/11] bisect: move even the option parsing to `bisect--helper` Johannes Schindelin via GitGitGadget
@ 2022-01-28  0:12 ` Johannes Schindelin via GitGitGadget
  2022-01-29  7:04   ` Ævar Arnfjörð Bjarmason
  2022-02-09  0:26   ` Elijah Newren
  2022-01-28  0:12 ` [PATCH 09/11] Turn `git bisect` into a full built-in Johannes Schindelin via GitGitGadget
                   ` (5 subsequent siblings)
  13 siblings, 2 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-01-28  0:12 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Johannes Schindelin, Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

The `bisect--helper` command is not expected to be used directly by the
user. Therefore, it is a bug if it receives no argument to the
`--bisect-state` command mode, not a user error. Which means that we
need to call `BUG()` instead of `die()`.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/bisect--helper.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 4450305c81c..009c919a989 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -872,7 +872,7 @@ static enum bisect_error bisect_state(struct bisect_terms *terms, const char **a
 	struct oid_array revs = OID_ARRAY_INIT;
 
 	if (!argc)
-		return error(_("Please call `--bisect-state` with at least one argument"));
+		BUG("bisect_state() called without argument");
 
 	if (bisect_autostart(terms))
 		return BISECT_FAILED;
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH 09/11] Turn `git bisect` into a full built-in.
  2022-01-28  0:12 [PATCH 00/11] Finish converting git bisect into a built-in Johannes Schindelin via GitGitGadget
                   ` (7 preceding siblings ...)
  2022-01-28  0:12 ` [PATCH 08/11] bisect--helper: using `--bisect-state` without an argument is a bug Johannes Schindelin via GitGitGadget
@ 2022-01-28  0:12 ` Johannes Schindelin via GitGitGadget
  2022-01-29  7:09   ` Ævar Arnfjörð Bjarmason
  2022-01-28  0:12 ` [PATCH 10/11] bisect: remove Cogito-related code Johannes Schindelin via GitGitGadget
                   ` (4 subsequent siblings)
  13 siblings, 1 reply; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-01-28  0:12 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Johannes Schindelin, Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

Now that the shell script hands off to the `bisect--helper` to do
_anything_ (except to show the help), it is but a tiny step to let the
helper implement the actual `git bisect` command instead.

This retires `git-bisect.sh`, concluding a multi-year journey that many
hands helped with, in particular Pranit Bauna, Tanushree Tumane and
Miriam Rubio.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 Makefile                               |  3 +--
 builtin.h                              |  2 +-
 builtin/{bisect--helper.c => bisect.c} |  2 +-
 git-bisect.sh                          | 37 --------------------------
 git.c                                  |  2 +-
 5 files changed, 4 insertions(+), 42 deletions(-)
 rename builtin/{bisect--helper.c => bisect.c} (99%)
 delete mode 100755 git-bisect.sh

diff --git a/Makefile b/Makefile
index 5580859afdb..ce2eabeca58 100644
--- a/Makefile
+++ b/Makefile
@@ -595,7 +595,6 @@ THIRD_PARTY_SOURCES =
 # interactive shell sessions without exporting it.
 unexport CDPATH
 
-SCRIPT_SH += git-bisect.sh
 SCRIPT_SH += git-difftool--helper.sh
 SCRIPT_SH += git-filter-branch.sh
 SCRIPT_SH += git-merge-octopus.sh
@@ -1064,7 +1063,7 @@ BUILTIN_OBJS += builtin/am.o
 BUILTIN_OBJS += builtin/annotate.o
 BUILTIN_OBJS += builtin/apply.o
 BUILTIN_OBJS += builtin/archive.o
-BUILTIN_OBJS += builtin/bisect--helper.o
+BUILTIN_OBJS += builtin/bisect.o
 BUILTIN_OBJS += builtin/blame.o
 BUILTIN_OBJS += builtin/branch.o
 BUILTIN_OBJS += builtin/bugreport.o
diff --git a/builtin.h b/builtin.h
index 8a58743ed63..b5567ea3a9d 100644
--- a/builtin.h
+++ b/builtin.h
@@ -116,7 +116,7 @@ int cmd_am(int argc, const char **argv, const char *prefix);
 int cmd_annotate(int argc, const char **argv, const char *prefix);
 int cmd_apply(int argc, const char **argv, const char *prefix);
 int cmd_archive(int argc, const char **argv, const char *prefix);
-int cmd_bisect__helper(int argc, const char **argv, const char *prefix);
+int cmd_bisect(int argc, const char **argv, const char *prefix);
 int cmd_blame(int argc, const char **argv, const char *prefix);
 int cmd_branch(int argc, const char **argv, const char *prefix);
 int cmd_bugreport(int argc, const char **argv, const char *prefix);
diff --git a/builtin/bisect--helper.c b/builtin/bisect.c
similarity index 99%
rename from builtin/bisect--helper.c
rename to builtin/bisect.c
index 009c919a989..189aca9dd22 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect.c
@@ -1182,7 +1182,7 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
 	}
 }
 
-int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
+int cmd_bisect(int argc, const char **argv, const char *prefix)
 {
 	int res = 0;
 	struct option options[] = {
diff --git a/git-bisect.sh b/git-bisect.sh
deleted file mode 100755
index 028d39cd9ce..00000000000
--- a/git-bisect.sh
+++ /dev/null
@@ -1,37 +0,0 @@
-#!/bin/sh
-
-USAGE='[help|start|bad|good|new|old|terms|skip|next|reset|visualize|view|replay|log|run]'
-LONG_USAGE='git bisect help
-	print this long help message.
-git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>]
-		 [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<pathspec>...]
-	reset bisect state and start bisection.
-git bisect (bad|new) [<rev>]
-	mark <rev> a known-bad revision/
-		a revision after change in a given property.
-git bisect (good|old) [<rev>...]
-	mark <rev>... known-good revisions/
-		revisions before change in a given property.
-git bisect terms [--term-good | --term-bad]
-	show the terms used for old and new commits (default: bad, good)
-git bisect skip [(<rev>|<range>)...]
-	mark <rev>... untestable revisions.
-git bisect next
-	find next bisection to test and check it out.
-git bisect reset [<commit>]
-	finish bisection search and go back to commit.
-git bisect (visualize|view)
-	show bisect status in gitk.
-git bisect replay <logfile>
-	replay bisection log.
-git bisect log
-	show bisect log.
-git bisect run <cmd>...
-	use <cmd>... to automatically bisect.
-
-Please use "git help bisect" to get the full man page.'
-
-OPTIONS_SPEC=
-. git-sh-setup
-
-exec git bisect--helper "$@"
diff --git a/git.c b/git.c
index edda922ce6d..a8500132a28 100644
--- a/git.c
+++ b/git.c
@@ -490,7 +490,7 @@ static struct cmd_struct commands[] = {
 	{ "annotate", cmd_annotate, RUN_SETUP | NO_PARSEOPT },
 	{ "apply", cmd_apply, RUN_SETUP_GENTLY },
 	{ "archive", cmd_archive, RUN_SETUP_GENTLY },
-	{ "bisect--helper", cmd_bisect__helper, RUN_SETUP },
+	{ "bisect", cmd_bisect, RUN_SETUP },
 	{ "blame", cmd_blame, RUN_SETUP },
 	{ "branch", cmd_branch, RUN_SETUP | DELAY_PAGER_CONFIG },
 	{ "bugreport", cmd_bugreport, RUN_SETUP_GENTLY },
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH 10/11] bisect: remove Cogito-related code
  2022-01-28  0:12 [PATCH 00/11] Finish converting git bisect into a built-in Johannes Schindelin via GitGitGadget
                   ` (8 preceding siblings ...)
  2022-01-28  0:12 ` [PATCH 09/11] Turn `git bisect` into a full built-in Johannes Schindelin via GitGitGadget
@ 2022-01-28  0:12 ` Johannes Schindelin via GitGitGadget
  2022-01-28  0:12 ` [PATCH 11/11] bisect: no longer try to clean up left-over `.git/head-name` files Johannes Schindelin via GitGitGadget
                   ` (3 subsequent siblings)
  13 siblings, 0 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-01-28  0:12 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Johannes Schindelin, Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

Once upon a time, there was this idea that Git would not actually be a
single coherent program, but rather a set of low-level programs that
users cobble together via shell scripts, or develop high-level user
interfaces for Git, or both.

Cogito was such a high-level user interface, incidentally implemented
via shell scripts that cobble together Git calls.

It did turn out relatively quickly that Git would much rather provide a
useful high-level user interface itself.

As of April 19th, 2007, Cogito was therefore discontinued (see
https://lore.kernel.org/git/20070419124648.GL4489@pasky.or.cz/).

Nevertheless, for almost 15 years after that announcement, Git carried
special code in `git bisect` to accommodate Cogito.

Since it is beyond doubt that there are no more Cogito users, let's
remove the last remnant of Cogito-accommodating code.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/bisect.c | 8 --------
 1 file changed, 8 deletions(-)

diff --git a/builtin/bisect.c b/builtin/bisect.c
index 189aca9dd22..479d68dd3b5 100644
--- a/builtin/bisect.c
+++ b/builtin/bisect.c
@@ -15,7 +15,6 @@ static GIT_PATH_FUNC(git_path_bisect_expected_rev, "BISECT_EXPECTED_REV")
 static GIT_PATH_FUNC(git_path_bisect_ancestors_ok, "BISECT_ANCESTORS_OK")
 static GIT_PATH_FUNC(git_path_bisect_start, "BISECT_START")
 static GIT_PATH_FUNC(git_path_bisect_log, "BISECT_LOG")
-static GIT_PATH_FUNC(git_path_head_name, "head-name")
 static GIT_PATH_FUNC(git_path_bisect_names, "BISECT_NAMES")
 static GIT_PATH_FUNC(git_path_bisect_first_parent, "BISECT_FIRST_PARENT")
 static GIT_PATH_FUNC(git_path_bisect_run, "BISECT_RUN")
@@ -756,13 +755,6 @@ static enum bisect_error bisect_start(struct bisect_terms *terms, const char **a
 			strbuf_addstr(&start_head, oid_to_hex(&head_oid));
 		} else if (!get_oid(head, &head_oid) &&
 			   skip_prefix(head, "refs/heads/", &head)) {
-			/*
-			 * This error message should only be triggered by
-			 * cogito usage, and cogito users should understand
-			 * it relates to cg-seek.
-			 */
-			if (!is_empty_or_missing_file(git_path_head_name()))
-				return error(_("won't bisect on cg-seek'ed tree"));
 			strbuf_addstr(&start_head, head);
 		} else {
 			return error(_("bad HEAD - strange symbolic ref"));
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH 11/11] bisect: no longer try to clean up left-over `.git/head-name` files
  2022-01-28  0:12 [PATCH 00/11] Finish converting git bisect into a built-in Johannes Schindelin via GitGitGadget
                   ` (9 preceding siblings ...)
  2022-01-28  0:12 ` [PATCH 10/11] bisect: remove Cogito-related code Johannes Schindelin via GitGitGadget
@ 2022-01-28  0:12 ` Johannes Schindelin via GitGitGadget
       [not found] ` <CAN7CjDC+O883DB1iaJAXF5ZCis7FP2Z9z0y2qS2-JVAKfQA8aA@mail.gmail.com>
                   ` (2 subsequent siblings)
  13 siblings, 0 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-01-28  0:12 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Johannes Schindelin, Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

As per the code comment, the `.git/head-name` files were cleaned up for
backwards-compatibility: an old version of `git bisect` could have left
them behind.

Now, just how old would such a version be? As of 0f497e75f05 (Eliminate
confusing "won't bisect on seeked tree" failure, 2008-02-23), `git
bisect` does not write that file anymore. Which corresponds to Git
v1.5.4.4.

Even if the likelihood is non-nil that there might still be users out
there who use such an old version to start a bisection, but then decide
to continue bisecting with a current Git version, it is highly
improbable.

So let's remove that code, at long last.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 bisect.c                    | 3 ---
 t/t6030-bisect-porcelain.sh | 1 -
 2 files changed, 4 deletions(-)

diff --git a/bisect.c b/bisect.c
index 888949fba6b..ebd4287c01c 100644
--- a/bisect.c
+++ b/bisect.c
@@ -474,7 +474,6 @@ static GIT_PATH_FUNC(git_path_bisect_start, "BISECT_START")
 static GIT_PATH_FUNC(git_path_bisect_log, "BISECT_LOG")
 static GIT_PATH_FUNC(git_path_bisect_terms, "BISECT_TERMS")
 static GIT_PATH_FUNC(git_path_bisect_first_parent, "BISECT_FIRST_PARENT")
-static GIT_PATH_FUNC(git_path_head_name, "head-name")
 
 static void read_bisect_paths(struct strvec *array)
 {
@@ -1172,8 +1171,6 @@ int bisect_clean_state(void)
 	unlink_or_warn(git_path_bisect_run());
 	unlink_or_warn(git_path_bisect_terms());
 	unlink_or_warn(git_path_bisect_first_parent());
-	/* Cleanup head-name if it got left by an old version of git-bisect */
-	unlink_or_warn(git_path_head_name());
 	/*
 	 * Cleanup BISECT_START last to support the --no-checkout option
 	 * introduced in the commit 4796e823a.
diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh
index 1be85d064e7..7f7ee42a7f4 100755
--- a/t/t6030-bisect-porcelain.sh
+++ b/t/t6030-bisect-porcelain.sh
@@ -945,7 +945,6 @@ test_expect_success 'git bisect reset cleans bisection state properly' '
 	test_path_is_missing ".git/BISECT_LOG" &&
 	test_path_is_missing ".git/BISECT_RUN" &&
 	test_path_is_missing ".git/BISECT_TERMS" &&
-	test_path_is_missing ".git/head-name" &&
 	test_path_is_missing ".git/BISECT_HEAD" &&
 	test_path_is_missing ".git/BISECT_START"
 '
-- 
gitgitgadget

^ permalink raw reply related	[flat|nested] 147+ messages in thread

* Fwd: [PATCH 00/11] Finish converting git bisect into a built-in
       [not found] ` <CAN7CjDC+O883DB1iaJAXF5ZCis7FP2Z9z0y2qS2-JVAKfQA8aA@mail.gmail.com>
@ 2022-01-28  8:54   ` Miriam R.
  2022-01-28 12:42   ` Johannes Schindelin
  1 sibling, 0 replies; 147+ messages in thread
From: Miriam R. @ 2022-01-28  8:54 UTC (permalink / raw)
  To: git

Hi Johannes,

I had done the last commits to finish the porting of git bisect
command since my Outreachy internship two years ago
(https://gitlab.com/mirucam/git/-/commits/git-bisect-work-part5-v1),
and I was planning to send them in the last patch series during this
February. I have a very very little availability and I can not send
the patch series frequently and I understand you are in hurry to
finish this.

I am sure your patch series will be more complete and better and you
will do not need it, but if you want to use some of my commits(or
parts) be my guest :).
Regards,
Miriam.



El vie, 28 ene 2022 a las 1:12, Johannes Schindelin via GitGitGadget
(<gitgitgadget@gmail.com>) escribió:
>
> After three GSoC/Outreachy students spent an incredible effort on this, it
> is finally time to put a neat little bow on it.
>
> Johannes Schindelin (11):
>   bisect run: fix the error message
>   bisect--helper: retire the --no-log option
>   bisect--helper: really retire --bisect-next-check
>   bisect--helper: really retire `--bisect-autostart`
>   bisect--helper: align the sub-command order with git-bisect.sh
>   bisect--helper: make `--bisect-state` optional
>   bisect: move even the option parsing to `bisect--helper`
>   bisect--helper: using `--bisect-state` without an argument is a bug
>   Turn `git bisect` into a full built-in.
>   bisect: remove Cogito-related code
>   bisect: no longer try to clean up left-over `.git/head-name` files
>
>  Makefile                               |   3 +-
>  bisect.c                               |   3 -
>  builtin.h                              |   2 +-
>  builtin/{bisect--helper.c => bisect.c} | 201 ++++++++++---------------
>  git-bisect.sh                          |  84 -----------
>  git.c                                  |   2 +-
>  t/t6030-bisect-porcelain.sh            |   1 -
>  7 files changed, 84 insertions(+), 212 deletions(-)
>  rename builtin/{bisect--helper.c => bisect.c} (87%)
>  delete mode 100755 git-bisect.sh
>
>
> base-commit: 89bece5c8c96f0b962cfc89e63f82d603fd60bed
> Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-1132%2Fdscho%2Fbisect-in-c-v1
> Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1132/dscho/bisect-in-c-v1
> Pull-Request: https://github.com/gitgitgadget/git/pull/1132
> --
> gitgitgadget

^ permalink raw reply	[flat|nested] 147+ messages in thread

* Re: [PATCH 00/11] Finish converting git bisect into a built-in
       [not found] ` <CAN7CjDC+O883DB1iaJAXF5ZCis7FP2Z9z0y2qS2-JVAKfQA8aA@mail.gmail.com>
  2022-01-28  8:54   ` Fwd: [PATCH 00/11] Finish converting git bisect into a built-in Miriam R.
@ 2022-01-28 12:42   ` Johannes Schindelin
  2022-01-28 15:11     ` Miriam R.
  1 sibling, 1 reply; 147+ messages in thread
From: Johannes Schindelin @ 2022-01-28 12:42 UTC (permalink / raw)
  To: Miriam R.
  Cc: Johannes Schindelin via GitGitGadget, git, Pranit Bauva,
	Tanushree Tumane, Christian Couder

Hi Miriam,

On Fri, 28 Jan 2022, Miriam R. wrote:

> I had done the last commits to finish the porting of git bisect command
> since my Outreachy internship two years ago (
> https://gitlab.com/mirucam/git/-/commits/git-bisect-work-part5-v1), and I
> was planning to send them in the last patch series during this February.

Oh sorry! I specifically went to look at your fork before starting to work
on the patch series, but had not seen that branch. Now I updated my
remote-tracking branches and see it as a new branch, so I am not sure
whether I missed it or whether it simply wasn't there.

All in all, we did very similar things. I have a slight preference for the
more concise version that does not use any command modes (and therefore
also does not duplicate the commands in the output of `git bisect -h`).

Maybe you could find time in February to review my patch series? Not a big
deal if you're too busy.

Ciao,
Dscho

^ permalink raw reply	[flat|nested] 147+ messages in thread

* Re: [PATCH 00/11] Finish converting git bisect into a built-in
  2022-01-28 12:42   ` Johannes Schindelin
@ 2022-01-28 15:11     ` Miriam R.
  0 siblings, 0 replies; 147+ messages in thread
From: Miriam R. @ 2022-01-28 15:11 UTC (permalink / raw)
  To: Johannes Schindelin
  Cc: Johannes Schindelin via GitGitGadget, git, Pranit Bauva,
	Tanushree Tumane, Christian Couder

El vie, 28 ene 2022 a las 13:42, Johannes Schindelin
(<Johannes.Schindelin@gmx.de>) escribió:
>
> Hi Miriam,
>
> On Fri, 28 Jan 2022, Miriam R. wrote:
>
> > I had done the last commits to finish the porting of git bisect command
> > since my Outreachy internship two years ago (
> > https://gitlab.com/mirucam/git/-/commits/git-bisect-work-part5-v1), and I
> > was planning to send them in the last patch series during this February.
>
> Oh sorry! I specifically went to look at your fork before starting to work
> on the patch series, but had not seen that branch. Now I updated my
> remote-tracking branches and see it as a new branch, so I am not sure
> whether I missed it or whether it simply wasn't there.

Hi Johannes,

the branch  ..part5-v1, I think it is from the last month, but the
commits were done like two years ago during my internship and they
were also in this branch
(https://gitlab.com/mirucam/git/-/commits/git-bisect-work4.7). But
don’t worry. Of course your patch series will be way better.

>
> All in all, we did very similar things. I have a slight preference for the
> more concise version that does not use any command modes (and therefore
> also does not duplicate the commands in the output of `git bisect -h`).
>
> Maybe you could find time in February to review my patch series? Not a big
> deal if you're too busy.
>

Haha, I could review it, but I am sure they will be perfect.
Ciao,
Miriam.

> Ciao,
> Dscho

^ permalink raw reply	[flat|nested] 147+ messages in thread

* Re: [PATCH 07/11] bisect: move even the option parsing to `bisect--helper`
  2022-01-28  0:12 ` [PATCH 07/11] bisect: move even the option parsing to `bisect--helper` Johannes Schindelin via GitGitGadget
@ 2022-01-29  6:47   ` Ævar Arnfjörð Bjarmason
  2022-02-09  0:12   ` Elijah Newren
  1 sibling, 0 replies; 147+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-01-29  6:47 UTC (permalink / raw)
  To: Johannes Schindelin via GitGitGadget
  Cc: git, Pranit Bauva, Tanushree Tumane, Miriam Rubio, Johannes Schindelin


On Fri, Jan 28 2022, Johannes Schindelin via GitGitGadget wrote:

> From: Johannes Schindelin <johannes.schindelin@gmx.de>
> [...]
> Side note: The `if (!strcmp(...)) ... else if (!strcmp(...)) ... else if
> (!strcmp(...)) ...` chain seen in this patch was not actually the first
> idea how to convert the command modes to sub-commands. Since the
> `bisect--helper` command already used the `parse-opions` API with neatly
> set-up command modes, naturally the idea was to use `PARSE_OPT_NODASH`
> to support proper sub-commands instead. However, the `parse-options` API
> is not set up for that, and even after making that option work with long
> options, it turned out that `STOP_AT_NON_OPTION` and `KEEP_UNKNOWN`
> would have to be used but these options were not designed to work
> together. So it would appear as if a lot of work would have to be done
> just to be able to use `parse_options()` just to parse the sub-command,
> instead of a simple `if...else if` chain, the latter being a
> dramatically simpler implementation. Therefore, we now keep the
> `parse_options()` call primarily to support `-h` and little else.

Yes, in this case we're hardly getting any use out of parse_options() as
it is.

And here the problem is that we're going from parsing a "git <cmd>
--bisect-FOO" to "git <cmd> FOO", and parse_options() obviously is more
set up to like the former form.

For your playing around with flags (the "not set up for that" for
PARSE_OPT_NODASH is that it doesn't like "long options"?) I wonder if
you considered/tried just setting the argc you pass to it such that it
only looks at the "FOO" item.

Or just parse_options_step(), which is the supported function equivalent
of "I set up my state, now parse this one item".

Anyway...

> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> ---
>  builtin/bisect--helper.c | 172 ++++++++++++++++-----------------------
>  git-bisect.sh            |  49 +----------
>  2 files changed, 72 insertions(+), 149 deletions(-)
>
> diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
> index 219fa99cd0b..4450305c81c 100644
> --- a/builtin/bisect--helper.c
> +++ b/builtin/bisect--helper.c
> @@ -20,18 +20,34 @@ static GIT_PATH_FUNC(git_path_bisect_names, "BISECT_NAMES")
>  static GIT_PATH_FUNC(git_path_bisect_first_parent, "BISECT_FIRST_PARENT")
>  static GIT_PATH_FUNC(git_path_bisect_run, "BISECT_RUN")
>  
> -static const char * const git_bisect_helper_usage[] = {
> -	N_("git bisect--helper --bisect-reset [<commit>]"),
> -	N_("git bisect--helper --bisect-terms [--term-good | --term-old | --term-bad | --term-new]"),
> -	N_("git bisect--helper --bisect-start [--term-{new,bad}=<term> --term-{old,good}=<term>]"
> -					    " [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<paths>...]"),
> -	N_("git bisect--helper --bisect-next"),
> -	N_("git bisect--helper [--bisect-state] (bad|new) [<rev>]"),
> -	N_("git bisect--helper [--bisect-state] (good|old) [<rev>...]"),
> -	N_("git bisect--helper --bisect-replay <filename>"),
> -	N_("git bisect--helper --bisect-skip [(<rev>|<range>)...]"),
> -	N_("git bisect--helper --bisect-visualize"),
> -	N_("git bisect--helper --bisect-run <cmd>..."),
> +static const char * const git_bisect_usage[] = {
> +	N_("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."),
>  	NULL
>  };

...I think you're throwing the baby out with the bathwater here. The
parse_options() version is much nicer to maintain, and will to
auto-alignment of the help output.

As builtin/commit-graph.c, builtin/stash.c, builtin/bundle.c we can and
do have these manual if/else if chains in combination with
parse_options(). There's no need to change this part (except for the
s/bisect-helper/bisect/ etc. change.

>  
> @@ -1168,115 +1184,69 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
>  
>  int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
>  {
> -	enum {
> -		BISECT_START = 1,
> -		BISECT_STATE,
> -		BISECT_TERMS,
> -		BISECT_SKIP,
> -		BISECT_NEXT,
> -		BISECT_RESET,
> -		BISECT_VISUALIZE,
> -		BISECT_REPLAY,
> -		BISECT_LOG,
> -		BISECT_RUN,
> -	} cmdmode = 0;
>  	int res = 0;
>  	struct option options[] = {
> -		OPT_CMDMODE(0, "bisect-start", &cmdmode,
> -			 N_("start the bisect session"), BISECT_START),
> -		OPT_CMDMODE(0, "bisect-state", &cmdmode,
> -			 N_("mark the state of ref (or refs)"), BISECT_STATE),
> -		OPT_CMDMODE(0, "bisect-terms", &cmdmode,
> -			 N_("print out the bisect terms"), BISECT_TERMS),
> -		OPT_CMDMODE(0, "bisect-skip", &cmdmode,
> -			 N_("skip some commits for checkout"), BISECT_SKIP),
> -		OPT_CMDMODE(0, "bisect-next", &cmdmode,
> -			 N_("find the next bisection commit"), BISECT_NEXT),
> -		OPT_CMDMODE(0, "bisect-reset", &cmdmode,
> -			 N_("reset the bisection state"), BISECT_RESET),
> -		OPT_CMDMODE(0, "bisect-visualize", &cmdmode,
> -			 N_("visualize the bisection"), BISECT_VISUALIZE),
> -		OPT_CMDMODE(0, "bisect-replay", &cmdmode,
> -			 N_("replay the bisection process from the given file"), BISECT_REPLAY),
> -		OPT_CMDMODE(0, "bisect-log", &cmdmode,
> -			 N_("list the bisection steps so far"), BISECT_LOG),
> -		OPT_CMDMODE(0, "bisect-run", &cmdmode,
> -			 N_("use <cmd>... to automatically bisect."), BISECT_RUN),
>  		OPT_END()
>  	};
>  	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
> +	const char *command = argc > 1 ? argv[1] : "help";
>  
> -	argc = parse_options(argc, argv, prefix, options,
> -			     git_bisect_helper_usage,
> -			     PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN);
> +	/* Handle -h and invalid options */
> +	parse_options(argc - 1, argv + 1, prefix, options,
> +		      git_bisect_usage,
> +		      PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN |
> +		      PARSE_OPT_ONE_SHOT | PARSE_OPT_STOP_AT_NON_OPTION);

Why isn't PARSE_OPT_STOP_AT_NON_OPTION sufficient here? That's pretty
much our "this is subcommand" pattern flag. See:

    git grep -W PARSE_OPT_STOP_AT_NON_OPTION -- builtin

Which lists the examples above.

I think this should strive to just copy an existing pattern as-is. See
e.g. 92f480909f7 (multi-pack-index: refactor "goto usage" pattern,
2021-08-23) for one change to make them a bit more consistent (as they
all solve the same problem)....

> [...]
> +		else {
> +			char *msg = xstrfmt(_("unknown command: '%s'"), command);
> +			usage_msg_opt(msg, git_bisect_usage, options);

...e.g. this part in cmd_commit_graph is nicer.

^ permalink raw reply	[flat|nested] 147+ messages in thread

* Re: [PATCH 08/11] bisect--helper: using `--bisect-state` without an argument is a bug
  2022-01-28  0:12 ` [PATCH 08/11] bisect--helper: using `--bisect-state` without an argument is a bug Johannes Schindelin via GitGitGadget
@ 2022-01-29  7:04   ` Ævar Arnfjörð Bjarmason
  2022-02-09  0:26   ` Elijah Newren
  1 sibling, 0 replies; 147+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-01-29  7:04 UTC (permalink / raw)
  To: Johannes Schindelin via GitGitGadget
  Cc: git, Pranit Bauva, Tanushree Tumane, Miriam Rubio, Johannes Schindelin


On Fri, Jan 28 2022, Johannes Schindelin via GitGitGadget wrote:

> From: Johannes Schindelin <johannes.schindelin@gmx.de>
>
> The `bisect--helper` command is not expected to be used directly by the
> user. Therefore, it is a bug if it receives no argument to the
> `--bisect-state` command mode, not a user error. Which means that we
> need to call `BUG()` instead of `die()`.

I found this commit message confusing with 07/11. I.e. won't this be
"git bisect" directly make this BUG() a bug then?

But no, it won't, because this being a bug has nothing to do with it
being a helper at all. after 07/11, but that it'll be called from an
implicit "if (!argc)" in cmd_bisect(), no?

I think I've either misread that, or this commit message is very
misleading.

^ permalink raw reply	[flat|nested] 147+ messages in thread

* Re: [PATCH 09/11] Turn `git bisect` into a full built-in.
  2022-01-28  0:12 ` [PATCH 09/11] Turn `git bisect` into a full built-in Johannes Schindelin via GitGitGadget
@ 2022-01-29  7:09   ` Ævar Arnfjörð Bjarmason
  0 siblings, 0 replies; 147+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-01-29  7:09 UTC (permalink / raw)
  To: Johannes Schindelin via GitGitGadget
  Cc: git, Pranit Bauva, Tanushree Tumane, Miriam Rubio, Johannes Schindelin


On Fri, Jan 28 2022, Johannes Schindelin via GitGitGadget wrote:

> From: Johannes Schindelin <johannes.schindelin@gmx.de>
>
> Now that the shell script hands off to the `bisect--helper` to do
> _anything_ (except to show the help), it is but a tiny step to let the
> helper implement the actual `git bisect` command instead.
>
> This retires `git-bisect.sh`, concluding a multi-year journey that many
> hands helped with, in particular Pranit Bauna, Tanushree Tumane and
> Miriam Rubio.
>
> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> ---
>  Makefile                               |  3 +--
>  builtin.h                              |  2 +-
>  builtin/{bisect--helper.c => bisect.c} |  2 +-
>  git-bisect.sh                          | 37 --------------------------
>  git.c                                  |  2 +-
>  5 files changed, 4 insertions(+), 42 deletions(-)
>  rename builtin/{bisect--helper.c => bisect.c} (99%)
>  delete mode 100755 git-bisect.sh
>
> diff --git a/Makefile b/Makefile
> index 5580859afdb..ce2eabeca58 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -595,7 +595,6 @@ THIRD_PARTY_SOURCES =
>  # interactive shell sessions without exporting it.
>  unexport CDPATH
>  
> -SCRIPT_SH += git-bisect.sh
>  SCRIPT_SH += git-difftool--helper.sh
>  SCRIPT_SH += git-filter-branch.sh
>  SCRIPT_SH += git-merge-octopus.sh
> @@ -1064,7 +1063,7 @@ BUILTIN_OBJS += builtin/am.o
>  BUILTIN_OBJS += builtin/annotate.o
>  BUILTIN_OBJS += builtin/apply.o
>  BUILTIN_OBJS += builtin/archive.o
> -BUILTIN_OBJS += builtin/bisect--helper.o
> +BUILTIN_OBJS += builtin/bisect.o
>  BUILTIN_OBJS += builtin/blame.o
>  BUILTIN_OBJS += builtin/branch.o
>  BUILTIN_OBJS += builtin/bugreport.o
> diff --git a/builtin.h b/builtin.h
> index 8a58743ed63..b5567ea3a9d 100644
> --- a/builtin.h
> +++ b/builtin.h
> @@ -116,7 +116,7 @@ int cmd_am(int argc, const char **argv, const char *prefix);
>  int cmd_annotate(int argc, const char **argv, const char *prefix);
>  int cmd_apply(int argc, const char **argv, const char *prefix);
>  int cmd_archive(int argc, const char **argv, const char *prefix);
> -int cmd_bisect__helper(int argc, const char **argv, const char *prefix);
> +int cmd_bisect(int argc, const char **argv, const char *prefix);
>  int cmd_blame(int argc, const char **argv, const char *prefix);
>  int cmd_branch(int argc, const char **argv, const char *prefix);
>  int cmd_bugreport(int argc, const char **argv, const char *prefix);
> diff --git a/builtin/bisect--helper.c b/builtin/bisect.c
> similarity index 99%
> rename from builtin/bisect--helper.c
> rename to builtin/bisect.c
> index 009c919a989..189aca9dd22 100644
> --- a/builtin/bisect--helper.c
> +++ b/builtin/bisect.c
> @@ -1182,7 +1182,7 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
>  	}
>  }
>  
> -int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
> +int cmd_bisect(int argc, const char **argv, const char *prefix)
>  {
>  	int res = 0;
>  	struct option options[] = {
> diff --git a/git-bisect.sh b/git-bisect.sh
> deleted file mode 100755
> index 028d39cd9ce..00000000000
> --- a/git-bisect.sh
> +++ /dev/null
> @@ -1,37 +0,0 @@
> -#!/bin/sh
> -
> -USAGE='[help|start|bad|good|new|old|terms|skip|next|reset|visualize|view|replay|log|run]'
> -LONG_USAGE='git bisect help
> -	print this long help message.
> -git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>]
> -		 [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<pathspec>...]
> -	reset bisect state and start bisection.
> -git bisect (bad|new) [<rev>]
> -	mark <rev> a known-bad revision/
> -		a revision after change in a given property.
> -git bisect (good|old) [<rev>...]
> -	mark <rev>... known-good revisions/
> -		revisions before change in a given property.
> -git bisect terms [--term-good | --term-bad]
> -	show the terms used for old and new commits (default: bad, good)
> -git bisect skip [(<rev>|<range>)...]
> -	mark <rev>... untestable revisions.
> -git bisect next
> -	find next bisection to test and check it out.
> -git bisect reset [<commit>]
> -	finish bisection search and go back to commit.
> -git bisect (visualize|view)
> -	show bisect status in gitk.
> -git bisect replay <logfile>
> -	replay bisection log.
> -git bisect log
> -	show bisect log.
> -git bisect run <cmd>...
> -	use <cmd>... to automatically bisect.
> -
> -Please use "git help bisect" to get the full man page.'
> -
> -OPTIONS_SPEC=
> -. git-sh-setup
> -
> -exec git bisect--helper "$@"
> diff --git a/git.c b/git.c
> index edda922ce6d..a8500132a28 100644
> --- a/git.c
> +++ b/git.c
> @@ -490,7 +490,7 @@ static struct cmd_struct commands[] = {
>  	{ "annotate", cmd_annotate, RUN_SETUP | NO_PARSEOPT },
>  	{ "apply", cmd_apply, RUN_SETUP_GENTLY },
>  	{ "archive", cmd_archive, RUN_SETUP_GENTLY },
> -	{ "bisect--helper", cmd_bisect__helper, RUN_SETUP },
> +	{ "bisect", cmd_bisect, RUN_SETUP },
>  	{ "blame", cmd_blame, RUN_SETUP },
>  	{ "branch", cmd_branch, RUN_SETUP | DELAY_PAGER_CONFIG },
>  	{ "bugreport", cmd_bugreport, RUN_SETUP_GENTLY },

This should really be squashed into 07/11, and I think shows an unstated
reason for why you probably ditched parse_options.

I.e. you've stuck the descriptions of the command into what we'd in
parse_options() put after a "" item. See builtin/blame.c for such a use.

So having this squashed would really make it clear how the "-h" output
is different after this series (which is OK), and what strings are
re-used or not etc.

^ permalink raw reply	[flat|nested] 147+ messages in thread

* Re: [PATCH 00/11] Finish converting git bisect into a built-in
  2022-01-28  0:12 [PATCH 00/11] Finish converting git bisect into a built-in Johannes Schindelin via GitGitGadget
                   ` (11 preceding siblings ...)
       [not found] ` <CAN7CjDC+O883DB1iaJAXF5ZCis7FP2Z9z0y2qS2-JVAKfQA8aA@mail.gmail.com>
@ 2022-01-30  6:39 ` Elijah Newren
  2022-02-09  4:41   ` Elijah Newren
  2022-02-22 16:30 ` [PATCH v2 00/14] " Johannes Schindelin via GitGitGadget
  13 siblings, 1 reply; 147+ messages in thread
From: Elijah Newren @ 2022-01-30  6:39 UTC (permalink / raw)
  To: Johannes Schindelin via GitGitGadget
  Cc: Git Mailing List, Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Johannes Schindelin

On Fri, Jan 28, 2022 at 3:08 PM Johannes Schindelin via GitGitGadget
<gitgitgadget@gmail.com> wrote:
>
> After three GSoC/Outreachy students spent an incredible effort on this, it
> is finally time to put a neat little bow on it.
>
> Johannes Schindelin (11):
>   bisect run: fix the error message
>   bisect--helper: retire the --no-log option
>   bisect--helper: really retire --bisect-next-check
>   bisect--helper: really retire `--bisect-autostart`
>   bisect--helper: align the sub-command order with git-bisect.sh
>   bisect--helper: make `--bisect-state` optional
>   bisect: move even the option parsing to `bisect--helper`
>   bisect--helper: using `--bisect-state` without an argument is a bug
>   Turn `git bisect` into a full built-in.
>   bisect: remove Cogito-related code
>   bisect: no longer try to clean up left-over `.git/head-name` files
>
>  Makefile                               |   3 +-
>  bisect.c                               |   3 -
>  builtin.h                              |   2 +-
>  builtin/{bisect--helper.c => bisect.c} | 201 ++++++++++---------------
>  git-bisect.sh                          |  84 -----------
>  git.c                                  |   2 +-
>  t/t6030-bisect-porcelain.sh            |   1 -
>  7 files changed, 84 insertions(+), 212 deletions(-)
>  rename builtin/{bisect--helper.c => bisect.c} (87%)
>  delete mode 100755 git-bisect.sh

I read through the series and couldn't spot any problems.

^ permalink raw reply	[flat|nested] 147+ messages in thread

* Re: [PATCH 01/11] bisect run: fix the error message
  2022-01-28  0:12 ` [PATCH 01/11] bisect run: fix the error message Johannes Schindelin via GitGitGadget
@ 2022-02-08 22:05   ` Elijah Newren
  2022-02-22 14:38     ` Johannes Schindelin
  0 siblings, 1 reply; 147+ messages in thread
From: Elijah Newren @ 2022-02-08 22:05 UTC (permalink / raw)
  To: Johannes Schindelin via GitGitGadget
  Cc: Git Mailing List, Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Johannes Schindelin

On Fri, Jan 28, 2022 at 3:27 PM Johannes Schindelin via GitGitGadget
<gitgitgadget@gmail.com> wrote:
>
> From: Johannes Schindelin <johannes.schindelin@gmx.de>
>
> In d1bbbe45df8 (bisect--helper: reimplement `bisect_run` shell function
> in C, 2021-09-13), we ported the `bisect run` subcommand to C, including
> the part that prints out an error message when the implicit `git bisect
> bad` or `git bisect good` failed.
>
> However, the error message was supposed to print out whether the state
> was "good" or "bad", but used a bogus (because non-populated) `args`
> variable for it.
>
> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> ---
>  builtin/bisect--helper.c | 8 ++------
>  1 file changed, 2 insertions(+), 6 deletions(-)
>
> diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
> index 28a2e6a5750..4208206af07 100644
> --- a/builtin/bisect--helper.c
> +++ b/builtin/bisect--helper.c
> @@ -1093,7 +1093,6 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
>  {
>         int res = BISECT_OK;
>         struct strbuf command = STRBUF_INIT;
> -       struct strvec args = STRVEC_INIT;
>         struct strvec run_args = STRVEC_INIT;
>         const char *new_state;
>         int temporary_stdout_fd, saved_stdout;
> @@ -1111,8 +1110,6 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
>         strvec_push(&run_args, command.buf);
>
>         while (1) {
> -               strvec_clear(&args);
> -
>                 printf(_("running %s\n"), command.buf);
>                 res = run_command_v_opt(run_args.v, RUN_USING_SHELL);
>
> @@ -1157,14 +1154,13 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
>                         printf(_("bisect found first bad commit"));
>                         res = BISECT_OK;
>                 } else if (res) {
> -                       error(_("bisect run failed: 'git bisect--helper --bisect-state"
> -                       " %s' exited with error code %d"), args.v[0], res);
> +                       error(_("bisect run failed: 'git bisect"
> +                       " %s' exited with error code %d"), new_state, res);
>                 } else {
>                         continue;
>                 }
>
>                 strbuf_release(&command);
> -               strvec_clear(&args);
>                 strvec_clear(&run_args);
>                 return res;
>         }
> --
> gitgitgadget

Good catch.  Looks like this printed "(null)" on glibc, and probably
crashed elsewhere.  Perhaps it'd help to add a test that would have
caught this with something like (I'm hoping gmail doesn't corrupt
this):

diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh
index 1be85d064e..28b54ba41b 100755
--- a/t/t6030-bisect-porcelain.sh
+++ b/t/t6030-bisect-porcelain.sh
@@ -980,4 +980,15 @@ test_expect_success 'bisect visualize with a
filename with dash and space' '
        git bisect visualize -p -- "-hello 2"
 '

+test_expect_success 'testing' '
+       git bisect reset &&
+       git bisect start $HASH4 $HASH1 &&
+       write_script test_script.sh <<-\EOF &&
+       rm .git/BISECT*
+       EOF
+       test_must_fail git bisect run ./test_script.sh 2>error &&
+       cat error &&
+       grep git.bisect.good..exited.with.error.code error
+'
+
 test_done


Also, as a side note, it appears that another error message in this
same function has a suboptimal error message, which could be fixed
with

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 28a2e6a575..6187d9fbcb 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1118,7 +1118,7 @@ static int bisect_run(struct bisect_terms
*terms, const char **argv, int argc)

                if (res < 0 || 128 <= res) {
                        error(_("bisect run failed: exit code %d from"
-                               " '%s' is < 0 or >= 128"), res, command.buf);
+                               " %s is < 0 or >= 128"), res, command.buf);
                        strbuf_release(&command);
                        return res;
                }

In particular, the line of code just above here:
      sq_quote_argv(&command, argv);
means that we get double single quotes without this fix, which looks
ugly.  Of course, this doesn't need to be included in your series, but
since you're cleaning up other error messages anyway, I thought I'd at
least mention it.

^ permalink raw reply related	[flat|nested] 147+ messages in thread

* Re: [PATCH 06/11] bisect--helper: make `--bisect-state` optional
  2022-01-28  0:12 ` [PATCH 06/11] bisect--helper: make `--bisect-state` optional Johannes Schindelin via GitGitGadget
@ 2022-02-08 23:03   ` Elijah Newren
  2022-02-22 15:12     ` Johannes Schindelin
  2022-02-09 19:45   ` Junio C Hamano
  1 sibling, 1 reply; 147+ messages in thread
From: Elijah Newren @ 2022-02-08 23:03 UTC (permalink / raw)
  To: Johannes Schindelin via GitGitGadget
  Cc: Git Mailing List, Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Johannes Schindelin

On Fri, Jan 28, 2022 at 3:52 PM Johannes Schindelin via GitGitGadget
<gitgitgadget@gmail.com> wrote:
>
> From: Johannes Schindelin <johannes.schindelin@gmx.de>
>
> In preparation for making `git bisect` a real built-in, let's prepare
> the `bisect--helper` built-in to handle `git bisect--helper good` and
> `git bisect--helper bad`, i.e. do not require the `--bisect-state`
> option to be passed explicitly.
>
> To prepare for converting `bisect--helper` to a full built-in
> implementation of `git bisect` (which must not require the
> `--bisect-state` option to be specified at all), let's move the handling
> toward the end of the `switch (cmdmode)` block.
>
> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> ---
>  builtin/bisect--helper.c | 23 ++++++++++++++++-------
>  1 file changed, 16 insertions(+), 7 deletions(-)
>
> diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
> index cc5a9ca41b9..219fa99cd0b 100644
> --- a/builtin/bisect--helper.c
> +++ b/builtin/bisect--helper.c
> @@ -26,8 +26,8 @@ static const char * const git_bisect_helper_usage[] = {
>         N_("git bisect--helper --bisect-start [--term-{new,bad}=<term> --term-{old,good}=<term>]"
>                                             " [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<paths>...]"),
>         N_("git bisect--helper --bisect-next"),
> -       N_("git bisect--helper --bisect-state (bad|new) [<rev>]"),
> -       N_("git bisect--helper --bisect-state (good|old) [<rev>...]"),
> +       N_("git bisect--helper [--bisect-state] (bad|new) [<rev>]"),
> +       N_("git bisect--helper [--bisect-state] (good|old) [<rev>...]"),
>         N_("git bisect--helper --bisect-replay <filename>"),
>         N_("git bisect--helper --bisect-skip [(<rev>|<range>)...]"),
>         N_("git bisect--helper --bisect-visualize"),
> @@ -1210,6 +1210,13 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
>                              git_bisect_helper_usage,
>                              PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN);
>
> +       if (!cmdmode && argc > 0) {
> +               set_terms(&terms, "bad", "good");
> +               get_terms(&terms);
> +               if (!check_and_set_terms(&terms, argv[0]))
> +                       cmdmode = BISECT_STATE;
> +       }
> +
>         if (!cmdmode)
>                 usage_with_options(git_bisect_helper_usage, options);
>
> @@ -1218,11 +1225,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
>                 set_terms(&terms, "bad", "good");
>                 res = bisect_start(&terms, argv, argc);
>                 break;
> -       case BISECT_STATE:
> -               set_terms(&terms, "bad", "good");
> -               get_terms(&terms);
> -               res = bisect_state(&terms, argv, argc);
> -               break;
>         case BISECT_TERMS:
>                 if (argc > 1)
>                         return error(_("--bisect-terms requires 0 or 1 argument"));
> @@ -1265,6 +1267,13 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
>                 get_terms(&terms);
>                 res = bisect_run(&terms, argv, argc);
>                 break;
> +       case BISECT_STATE:
> +               if (!terms.term_good) {
> +                       set_terms(&terms, "bad", "good");
> +                       get_terms(&terms);
> +               }
> +               res = bisect_state(&terms, argv, argc);
> +               break;
>         default:
>                 BUG("unknown subcommand %d", cmdmode);
>         }
> --
> gitgitgadget

Does it make sense to also include something like this:

diff --git a/git-bisect.sh b/git-bisect.sh
index 405cf76f2a..fbf56649d7 100755
--- a/git-bisect.sh
+++ b/git-bisect.sh
@@ -60,7 +60,7 @@ case "$#" in
        start)
                git bisect--helper --bisect-start "$@" ;;
        bad|good|new|old|"$TERM_BAD"|"$TERM_GOOD")
-               git bisect--helper --bisect-state "$cmd" "$@" ;;
+               git bisect--helper "$cmd" "$@" ;;
        skip)
                git bisect--helper --bisect-skip "$@" || exit;;
        next)

to prove that you've made it optional?  (Well, assuming one has run
the tests with that change, but I did...)

^ permalink raw reply related	[flat|nested] 147+ messages in thread

* Re: [PATCH 07/11] bisect: move even the option parsing to `bisect--helper`
  2022-01-28  0:12 ` [PATCH 07/11] bisect: move even the option parsing to `bisect--helper` Johannes Schindelin via GitGitGadget
  2022-01-29  6:47   ` Ævar Arnfjörð Bjarmason
@ 2022-02-09  0:12   ` Elijah Newren
  2022-02-22 15:49     ` Johannes Schindelin
  1 sibling, 1 reply; 147+ messages in thread
From: Elijah Newren @ 2022-02-09  0:12 UTC (permalink / raw)
  To: Johannes Schindelin via GitGitGadget
  Cc: Git Mailing List, Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Johannes Schindelin

On Fri, Jan 28, 2022 at 3:27 PM Johannes Schindelin via GitGitGadget
<gitgitgadget@gmail.com> wrote:
>
> From: Johannes Schindelin <johannes.schindelin@gmx.de>
>
> On our journey to a fully built-in `git bisect`, this is the
> second-to-last step.
>
> Side note: The `if (!strcmp(...)) ... else if (!strcmp(...)) ... else if
> (!strcmp(...)) ...` chain seen in this patch was not actually the first
> idea how to convert the command modes to sub-commands. Since the
> `bisect--helper` command already used the `parse-opions` API with neatly
> set-up command modes, naturally the idea was to use `PARSE_OPT_NODASH`
> to support proper sub-commands instead. However, the `parse-options` API
> is not set up for that, and even after making that option work with long
> options, it turned out that `STOP_AT_NON_OPTION` and `KEEP_UNKNOWN`
> would have to be used but these options were not designed to work
> together. So it would appear as if a lot of work would have to be done
> just to be able to use `parse_options()` just to parse the sub-command,
> instead of a simple `if...else if` chain, the latter being a
> dramatically simpler implementation. Therefore, we now keep the
> `parse_options()` call primarily to support `-h` and little else.
>
> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> ---
>  builtin/bisect--helper.c | 172 ++++++++++++++++-----------------------
>  git-bisect.sh            |  49 +----------
>  2 files changed, 72 insertions(+), 149 deletions(-)
>
> diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
> index 219fa99cd0b..4450305c81c 100644
> --- a/builtin/bisect--helper.c
> +++ b/builtin/bisect--helper.c
> @@ -20,18 +20,34 @@ static GIT_PATH_FUNC(git_path_bisect_names, "BISECT_NAMES")
>  static GIT_PATH_FUNC(git_path_bisect_first_parent, "BISECT_FIRST_PARENT")
>  static GIT_PATH_FUNC(git_path_bisect_run, "BISECT_RUN")
>
> -static const char * const git_bisect_helper_usage[] = {
> -       N_("git bisect--helper --bisect-reset [<commit>]"),
> -       N_("git bisect--helper --bisect-terms [--term-good | --term-old | --term-bad | --term-new]"),
> -       N_("git bisect--helper --bisect-start [--term-{new,bad}=<term> --term-{old,good}=<term>]"
> -                                           " [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<paths>...]"),
> -       N_("git bisect--helper --bisect-next"),
> -       N_("git bisect--helper [--bisect-state] (bad|new) [<rev>]"),
> -       N_("git bisect--helper [--bisect-state] (good|old) [<rev>...]"),
> -       N_("git bisect--helper --bisect-replay <filename>"),
> -       N_("git bisect--helper --bisect-skip [(<rev>|<range>)...]"),
> -       N_("git bisect--helper --bisect-visualize"),
> -       N_("git bisect--helper --bisect-run <cmd>..."),
> +static const char * const git_bisect_usage[] = {
> +       N_("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."),
>         NULL
>  };

Hooray on getting rid of the "--helper" and "--bisect-" portions of
the strings.  The manual whitespace splitting/indentation is a bit
unfortunate, but you did address that in the commit message.

> @@ -1168,115 +1184,69 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
>
>  int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
>  {
> -       enum {
> -               BISECT_START = 1,
> -               BISECT_STATE,
> -               BISECT_TERMS,
> -               BISECT_SKIP,
> -               BISECT_NEXT,
> -               BISECT_RESET,
> -               BISECT_VISUALIZE,
> -               BISECT_REPLAY,
> -               BISECT_LOG,
> -               BISECT_RUN,
> -       } cmdmode = 0;
>         int res = 0;
>         struct option options[] = {
> -               OPT_CMDMODE(0, "bisect-start", &cmdmode,
> -                        N_("start the bisect session"), BISECT_START),
> -               OPT_CMDMODE(0, "bisect-state", &cmdmode,
> -                        N_("mark the state of ref (or refs)"), BISECT_STATE),
> -               OPT_CMDMODE(0, "bisect-terms", &cmdmode,
> -                        N_("print out the bisect terms"), BISECT_TERMS),
> -               OPT_CMDMODE(0, "bisect-skip", &cmdmode,
> -                        N_("skip some commits for checkout"), BISECT_SKIP),
> -               OPT_CMDMODE(0, "bisect-next", &cmdmode,
> -                        N_("find the next bisection commit"), BISECT_NEXT),
> -               OPT_CMDMODE(0, "bisect-reset", &cmdmode,
> -                        N_("reset the bisection state"), BISECT_RESET),
> -               OPT_CMDMODE(0, "bisect-visualize", &cmdmode,
> -                        N_("visualize the bisection"), BISECT_VISUALIZE),
> -               OPT_CMDMODE(0, "bisect-replay", &cmdmode,
> -                        N_("replay the bisection process from the given file"), BISECT_REPLAY),
> -               OPT_CMDMODE(0, "bisect-log", &cmdmode,
> -                        N_("list the bisection steps so far"), BISECT_LOG),
> -               OPT_CMDMODE(0, "bisect-run", &cmdmode,
> -                        N_("use <cmd>... to automatically bisect."), BISECT_RUN),
>                 OPT_END()
>         };
>         struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
> +       const char *command = argc > 1 ? argv[1] : "help";
>
> -       argc = parse_options(argc, argv, prefix, options,
> -                            git_bisect_helper_usage,
> -                            PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN);
> +       /* Handle -h and invalid options */
> +       parse_options(argc - 1, argv + 1, prefix, options,
> +                     git_bisect_usage,
> +                     PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN |
> +                     PARSE_OPT_ONE_SHOT | PARSE_OPT_STOP_AT_NON_OPTION);
>
> -       if (!cmdmode && argc > 0) {
> +       if (!strcmp("help", command))
> +               usage_with_options(git_bisect_usage, options);

I think the rest of the changes in this file would be much easier to
read if you did a
   argc -= 2
   argv += 2
here...

> +       else if (!strcmp("start", command)) {

...and dropped the else here, just starting a new 'if' instead.

>                 set_terms(&terms, "bad", "good");
> -               get_terms(&terms);
> -               if (!check_and_set_terms(&terms, argv[0]))
> -                       cmdmode = BISECT_STATE;
> -       }
> -
> -       if (!cmdmode)
> -               usage_with_options(git_bisect_helper_usage, options);
> -
> -       switch (cmdmode) {
> -       case BISECT_START:
> -               set_terms(&terms, "bad", "good");
> -               res = bisect_start(&terms, argv, argc);
> -               break;
> -       case BISECT_TERMS:
> -               if (argc > 1)
> -                       return error(_("--bisect-terms requires 0 or 1 argument"));
> -               res = bisect_terms(&terms, argc == 1 ? argv[0] : NULL);
> -               break;
> -       case BISECT_SKIP:
> +               res = bisect_start(&terms, argv + 2, argc - 2);
> +       } else if (!strcmp("terms", command)) {
> +               if (argc > 3)
> +                       return error(_("'terms' requires 0 or 1 argument"));
> +               res = bisect_terms(&terms, argc == 3 ? argv[2] : NULL);
> +       } else if (!strcmp("skip", command)) {
>                 set_terms(&terms, "bad", "good");
>                 get_terms(&terms);
> -               res = bisect_skip(&terms, argv, argc);
> -               break;
> -       case BISECT_NEXT:
> -               if (argc)
> -                       return error(_("--bisect-next requires 0 arguments"));
> +               res = bisect_skip(&terms, argv + 2, argc - 2);
> +       } else if (!strcmp("next", command)) {
> +               if (argc != 2)
> +                       return error(_("'next' requires 0 arguments"));
>                 get_terms(&terms);
>                 res = bisect_next(&terms, prefix);
> -               break;
> -       case BISECT_RESET:
> -               if (argc > 1)
> -                       return error(_("--bisect-reset requires either no argument or a commit"));
> -               res = bisect_reset(argc ? argv[0] : NULL);
> -               break;
> -       case BISECT_VISUALIZE:
> +       } else if (!strcmp("reset", command)) {
> +               if (argc > 3)
> +                       return error(_("'reset' requires either no argument or a commit"));
> +               res = bisect_reset(argc > 2 ? argv[2] : NULL);
> +       } else if (one_of(command, "visualize", "view", NULL)) {
>                 get_terms(&terms);
> -               res = bisect_visualize(&terms, argv, argc);
> -               break;
> -       case BISECT_REPLAY:
> -               if (argc != 1)
> +               res = bisect_visualize(&terms, argv + 2, argc - 2);
> +       } else if (!strcmp("replay", command)) {
> +               if (argc != 3)
>                         return error(_("no logfile given"));
>                 set_terms(&terms, "bad", "good");
> -               res = bisect_replay(&terms, argv[0]);
> -               break;
> -       case BISECT_LOG:
> -               if (argc)
> -                       return error(_("--bisect-log requires 0 arguments"));
> +               res = bisect_replay(&terms, argv[2]);
> +       } else if (!strcmp("log", command)) {
> +               if (argc > 2)
> +                       return error(_("'log' requires 0 arguments"));
>                 res = bisect_log();
> -               break;
> -       case BISECT_RUN:
> -               if (!argc)
> +       } else if (!strcmp("run", command)) {
> +               if (argc < 3)
>                         return error(_("bisect run failed: no command provided."));
>                 get_terms(&terms);
> -               res = bisect_run(&terms, argv, argc);
> -               break;
> -       case BISECT_STATE:
> -               if (!terms.term_good) {
> -                       set_terms(&terms, "bad", "good");
> -                       get_terms(&terms);
> +               res = bisect_run(&terms, argv + 2, argc - 2);
> +       } else {
> +               set_terms(&terms, "bad", "good");
> +               get_terms(&terms);
> +               if (!check_and_set_terms(&terms, command))
> +                       res = bisect_state(&terms, argv + 1, argc - 1);

Oh, hmm... this one is +1,-1 while all others are +2,-2, because there
is not a separate "command"; the command was implicit and so that
reserved argument is actually part of the terms.  Still if we did the
offset by two trick above, I guess we'd just add a comment here and do
argv-1, argc+1?

> +               else {
> +                       char *msg = xstrfmt(_("unknown command: '%s'"), command);
> +                       usage_msg_opt(msg, git_bisect_usage, options);
>                 }
> -               res = bisect_state(&terms, argv, argc);
> -               break;
> -       default:
> -               BUG("unknown subcommand %d", cmdmode);
>         }
> +
>         free_terms(&terms);
>
>         /*
> diff --git a/git-bisect.sh b/git-bisect.sh
> index 405cf76f2a3..028d39cd9ce 100755
> --- a/git-bisect.sh
> +++ b/git-bisect.sh
> @@ -34,51 +34,4 @@ Please use "git help bisect" to get the full man page.'
>  OPTIONS_SPEC=
>  . git-sh-setup
>
> -TERM_BAD=bad
> -TERM_GOOD=good
> -
> -get_terms () {
> -       if test -s "$GIT_DIR/BISECT_TERMS"
> -       then
> -               {
> -               read TERM_BAD
> -               read TERM_GOOD
> -               } <"$GIT_DIR/BISECT_TERMS"
> -       fi
> -}
> -
> -case "$#" in
> -0)
> -       usage ;;
> -*)
> -       cmd="$1"
> -       get_terms
> -       shift
> -       case "$cmd" in
> -       help)
> -               git bisect -h ;;
> -       start)
> -               git bisect--helper --bisect-start "$@" ;;
> -       bad|good|new|old|"$TERM_BAD"|"$TERM_GOOD")
> -               git bisect--helper --bisect-state "$cmd" "$@" ;;
> -       skip)
> -               git bisect--helper --bisect-skip "$@" || exit;;
> -       next)
> -               # Not sure we want "next" at the UI level anymore.
> -               git bisect--helper --bisect-next "$@" || exit ;;
> -       visualize|view)
> -               git bisect--helper --bisect-visualize "$@" || exit;;
> -       reset)
> -               git bisect--helper --bisect-reset "$@" ;;
> -       replay)
> -               git bisect--helper --bisect-replay "$@" || exit;;
> -       log)
> -               git bisect--helper --bisect-log || exit ;;
> -       run)
> -               git bisect--helper --bisect-run "$@" || exit;;
> -       terms)
> -               git bisect--helper --bisect-terms "$@" || exit;;
> -       *)
> -               usage ;;
> -       esac
> -esac
> +exec git bisect--helper "$@"

This is a really nice cleanup to git-bisect.sh.  :-)

^ permalink raw reply	[flat|nested] 147+ messages in thread

* Re: [PATCH 08/11] bisect--helper: using `--bisect-state` without an argument is a bug
  2022-01-28  0:12 ` [PATCH 08/11] bisect--helper: using `--bisect-state` without an argument is a bug Johannes Schindelin via GitGitGadget
  2022-01-29  7:04   ` Ævar Arnfjörð Bjarmason
@ 2022-02-09  0:26   ` Elijah Newren
  1 sibling, 0 replies; 147+ messages in thread
From: Elijah Newren @ 2022-02-09  0:26 UTC (permalink / raw)
  To: Johannes Schindelin via GitGitGadget
  Cc: Git Mailing List, Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Johannes Schindelin

On Fri, Jan 28, 2022 at 3:30 PM Johannes Schindelin via GitGitGadget
<gitgitgadget@gmail.com> wrote:
>
> From: Johannes Schindelin <johannes.schindelin@gmx.de>
>
> The `bisect--helper` command is not expected to be used directly by the
> user. Therefore, it is a bug if it receives no argument to the
> `--bisect-state` command mode, not a user error. Which means that we
> need to call `BUG()` instead of `die()`.
>
> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> ---
>  builtin/bisect--helper.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
> index 4450305c81c..009c919a989 100644
> --- a/builtin/bisect--helper.c
> +++ b/builtin/bisect--helper.c
> @@ -872,7 +872,7 @@ static enum bisect_error bisect_state(struct bisect_terms *terms, const char **a
>         struct oid_array revs = OID_ARRAY_INIT;
>
>         if (!argc)
> -               return error(_("Please call `--bisect-state` with at least one argument"));
> +               BUG("bisect_state() called without argument");
>
>         if (bisect_autostart(terms))
>                 return BISECT_FAILED;
> --
> gitgitgadget

Makes sense.

^ permalink raw reply	[flat|nested] 147+ messages in thread

* Re: [PATCH 00/11] Finish converting git bisect into a built-in
  2022-01-30  6:39 ` Elijah Newren
@ 2022-02-09  4:41   ` Elijah Newren
  2022-02-22 15:55     ` Johannes Schindelin
  0 siblings, 1 reply; 147+ messages in thread
From: Elijah Newren @ 2022-02-09  4:41 UTC (permalink / raw)
  To: Johannes Schindelin via GitGitGadget
  Cc: Git Mailing List, Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Johannes Schindelin

On Sat, Jan 29, 2022 at 10:39 PM Elijah Newren <newren@gmail.com> wrote:
>
> On Fri, Jan 28, 2022 at 3:08 PM Johannes Schindelin via GitGitGadget
> <gitgitgadget@gmail.com> wrote:
> >
> > After three GSoC/Outreachy students spent an incredible effort on this, it
> > is finally time to put a neat little bow on it.
> >
> > Johannes Schindelin (11):
> >   bisect run: fix the error message
> >   bisect--helper: retire the --no-log option
> >   bisect--helper: really retire --bisect-next-check
> >   bisect--helper: really retire `--bisect-autostart`
> >   bisect--helper: align the sub-command order with git-bisect.sh
> >   bisect--helper: make `--bisect-state` optional
> >   bisect: move even the option parsing to `bisect--helper`
> >   bisect--helper: using `--bisect-state` without an argument is a bug
> >   Turn `git bisect` into a full built-in.
> >   bisect: remove Cogito-related code
> >   bisect: no longer try to clean up left-over `.git/head-name` files
> >
> >  Makefile                               |   3 +-
> >  bisect.c                               |   3 -
> >  builtin.h                              |   2 +-
> >  builtin/{bisect--helper.c => bisect.c} | 201 ++++++++++---------------
> >  git-bisect.sh                          |  84 -----------
> >  git.c                                  |   2 +-
> >  t/t6030-bisect-porcelain.sh            |   1 -
> >  7 files changed, 84 insertions(+), 212 deletions(-)
> >  rename builtin/{bisect--helper.c => bisect.c} (87%)
> >  delete mode 100755 git-bisect.sh
>
> I read through the series and couldn't spot any problems.

I re-read the series, taking a closer look.  Spotted a few minor
things (and left some comments) but the series looks pretty good to
me.  I think Dscho's on vacation, so we'll resume the discussion when
he gets back.

^ permalink raw reply	[flat|nested] 147+ messages in thread

* Re: [PATCH 06/11] bisect--helper: make `--bisect-state` optional
  2022-01-28  0:12 ` [PATCH 06/11] bisect--helper: make `--bisect-state` optional Johannes Schindelin via GitGitGadget
  2022-02-08 23:03   ` Elijah Newren
@ 2022-02-09 19:45   ` Junio C Hamano
  2022-02-22 15:53     ` Johannes Schindelin
  1 sibling, 1 reply; 147+ messages in thread
From: Junio C Hamano @ 2022-02-09 19:45 UTC (permalink / raw)
  To: Johannes Schindelin via GitGitGadget
  Cc: git, Pranit Bauva, Tanushree Tumane, Miriam Rubio, Johannes Schindelin

"Johannes Schindelin via GitGitGadget" <gitgitgadget@gmail.com>
writes:

> @@ -1210,6 +1210,13 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
>  			     git_bisect_helper_usage,
>  			     PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN);
>  
> +	if (!cmdmode && argc > 0) {
> +		set_terms(&terms, "bad", "good");
> +		get_terms(&terms);
> +		if (!check_and_set_terms(&terms, argv[0]))
> +			cmdmode = BISECT_STATE;
> +	}
> +

I do agree with "if we want to reuse this function without changing
it much, --bisect-state must become an optional and the default mode
of operation" as a goal, but I do not quite get this change.  From
the rephased description of the goal, what I would expect is more
like

	if (!cmdmode && possibly-other-conditions-like-argc-check)
		cmdmode = BISECT_STATE;

and nothing else.  Between the case where --bisect-state was and was
not given explicitly, check-and-set-terms is or is not called.  I
can see that checking would be _nice_ when we try to decide if the
first token makes sense as good/bad and the user wanted to do the
"state" thing impolicitly, but if it is worth checking in implicit
case, shouldn't we be checking when the --bisect-state is explicitly
given as well?

And the actual execution of the BISECT_STATE command is even more
puzzling, below.

>  	if (!cmdmode)
>  		usage_with_options(git_bisect_helper_usage, options);
>  
> @@ -1218,11 +1225,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
>  		set_terms(&terms, "bad", "good");
>  		res = bisect_start(&terms, argv, argc);
>  		break;
> -	case BISECT_STATE:
> -		set_terms(&terms, "bad", "good");
> -		get_terms(&terms);
> -		res = bisect_state(&terms, argv, argc);
> -		break;
>  	case BISECT_TERMS:
>  		if (argc > 1)
>  			return error(_("--bisect-terms requires 0 or 1 argument"));
> @@ -1265,6 +1267,13 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
>  		get_terms(&terms);
>  		res = bisect_run(&terms, argv, argc);
>  		break;
> +	case BISECT_STATE:
> +		if (!terms.term_good) {
> +			set_terms(&terms, "bad", "good");
> +			get_terms(&terms);
> +		}
> +		res = bisect_state(&terms, argv, argc);
> +		break;

This case arm has been moved but because there is no fall-through in
this switch statement, the movement is a no-op.  But the code has
also changed with this patch.  We used to do set_terms/get_terms
unconditionally, but we do not even do so when terms_good (but not
terms_bad) is already set.

Is this an unrelated bugfix of some kind?  This does not look
related to "making --bisect-state optional and implicit default" at
all.  At least the proposed log message does not explain why.

Thanks.

>  	default:
>  		BUG("unknown subcommand %d", cmdmode);
>  	}

^ permalink raw reply	[flat|nested] 147+ messages in thread

* Re: [PATCH 01/11] bisect run: fix the error message
  2022-02-08 22:05   ` Elijah Newren
@ 2022-02-22 14:38     ` Johannes Schindelin
  0 siblings, 0 replies; 147+ messages in thread
From: Johannes Schindelin @ 2022-02-22 14:38 UTC (permalink / raw)
  To: Elijah Newren
  Cc: Johannes Schindelin via GitGitGadget, Git Mailing List,
	Pranit Bauva, Tanushree Tumane, Miriam Rubio

Hi Elijah,

On Tue, 8 Feb 2022, Elijah Newren wrote:

> On Fri, Jan 28, 2022 at 3:27 PM Johannes Schindelin via GitGitGadget
> <gitgitgadget@gmail.com> wrote:
> >
> > From: Johannes Schindelin <johannes.schindelin@gmx.de>
> >
> > In d1bbbe45df8 (bisect--helper: reimplement `bisect_run` shell function
> > in C, 2021-09-13), we ported the `bisect run` subcommand to C, including
> > the part that prints out an error message when the implicit `git bisect
> > bad` or `git bisect good` failed.
> >
> > However, the error message was supposed to print out whether the state
> > was "good" or "bad", but used a bogus (because non-populated) `args`
> > variable for it.
> >
> > Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> > ---
> >  builtin/bisect--helper.c | 8 ++------
> >  1 file changed, 2 insertions(+), 6 deletions(-)
> >
> > diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
> > index 28a2e6a5750..4208206af07 100644
> > --- a/builtin/bisect--helper.c
> > +++ b/builtin/bisect--helper.c
> > @@ -1093,7 +1093,6 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
> >  {
> >         int res = BISECT_OK;
> >         struct strbuf command = STRBUF_INIT;
> > -       struct strvec args = STRVEC_INIT;
> >         struct strvec run_args = STRVEC_INIT;
> >         const char *new_state;
> >         int temporary_stdout_fd, saved_stdout;
> > @@ -1111,8 +1110,6 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
> >         strvec_push(&run_args, command.buf);
> >
> >         while (1) {
> > -               strvec_clear(&args);
> > -
> >                 printf(_("running %s\n"), command.buf);
> >                 res = run_command_v_opt(run_args.v, RUN_USING_SHELL);
> >
> > @@ -1157,14 +1154,13 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
> >                         printf(_("bisect found first bad commit"));
> >                         res = BISECT_OK;
> >                 } else if (res) {
> > -                       error(_("bisect run failed: 'git bisect--helper --bisect-state"
> > -                       " %s' exited with error code %d"), args.v[0], res);
> > +                       error(_("bisect run failed: 'git bisect"
> > +                       " %s' exited with error code %d"), new_state, res);
> >                 } else {
> >                         continue;
> >                 }
> >
> >                 strbuf_release(&command);
> > -               strvec_clear(&args);
> >                 strvec_clear(&run_args);
> >                 return res;
> >         }
> > --
> > gitgitgadget
>
> Good catch.  Looks like this printed "(null)" on glibc, and probably
> crashed elsewhere.  Perhaps it'd help to add a test that would have
> caught this with something like (I'm hoping gmail doesn't corrupt
> this):
>
> diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh
> index 1be85d064e..28b54ba41b 100755
> --- a/t/t6030-bisect-porcelain.sh
> +++ b/t/t6030-bisect-porcelain.sh
> @@ -980,4 +980,15 @@ test_expect_success 'bisect visualize with a
> filename with dash and space' '
>         git bisect visualize -p -- "-hello 2"
>  '
>
> +test_expect_success 'testing' '
> +       git bisect reset &&
> +       git bisect start $HASH4 $HASH1 &&
> +       write_script test_script.sh <<-\EOF &&
> +       rm .git/BISECT*
> +       EOF
> +       test_must_fail git bisect run ./test_script.sh 2>error &&
> +       cat error &&
> +       grep git.bisect.good..exited.with.error.code error
> +'
> +
>  test_done

Excellent, thank you!

> Also, as a side note, it appears that another error message in this
> same function has a suboptimal error message, which could be fixed
> with
>
> diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
> index 28a2e6a575..6187d9fbcb 100644
> --- a/builtin/bisect--helper.c
> +++ b/builtin/bisect--helper.c
> @@ -1118,7 +1118,7 @@ static int bisect_run(struct bisect_terms
> *terms, const char **argv, int argc)
>
>                 if (res < 0 || 128 <= res) {
>                         error(_("bisect run failed: exit code %d from"
> -                               " '%s' is < 0 or >= 128"), res, command.buf);
> +                               " %s is < 0 or >= 128"), res, command.buf);
>                         strbuf_release(&command);
>                         return res;
>                 }
>
> In particular, the line of code just above here:
>       sq_quote_argv(&command, argv);
> means that we get double single quotes without this fix, which looks
> ugly.  Of course, this doesn't need to be included in your series, but
> since you're cleaning up other error messages anyway, I thought I'd at
> least mention it.

Sure, and I think it is not _too_ much out of scope to fix it in the same
patch series, too.

Thank you!
Dscho

^ permalink raw reply	[flat|nested] 147+ messages in thread

* Re: [PATCH 06/11] bisect--helper: make `--bisect-state` optional
  2022-02-08 23:03   ` Elijah Newren
@ 2022-02-22 15:12     ` Johannes Schindelin
  0 siblings, 0 replies; 147+ messages in thread
From: Johannes Schindelin @ 2022-02-22 15:12 UTC (permalink / raw)
  To: Elijah Newren
  Cc: Johannes Schindelin via GitGitGadget, Git Mailing List,
	Pranit Bauva, Tanushree Tumane, Miriam Rubio

Hi Elijah,

On Tue, 8 Feb 2022, Elijah Newren wrote:

> On Fri, Jan 28, 2022 at 3:52 PM Johannes Schindelin via GitGitGadget
> <gitgitgadget@gmail.com> wrote:
> >
> > From: Johannes Schindelin <johannes.schindelin@gmx.de>
> >
> > In preparation for making `git bisect` a real built-in, let's prepare
> > the `bisect--helper` built-in to handle `git bisect--helper good` and
> > `git bisect--helper bad`, i.e. do not require the `--bisect-state`
> > option to be passed explicitly.
> >
> > To prepare for converting `bisect--helper` to a full built-in
> > implementation of `git bisect` (which must not require the
> > `--bisect-state` option to be specified at all), let's move the handling
> > toward the end of the `switch (cmdmode)` block.
> >
> > Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> > ---
> >  builtin/bisect--helper.c | 23 ++++++++++++++++-------
> >  1 file changed, 16 insertions(+), 7 deletions(-)
> >
> > diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
> > index cc5a9ca41b9..219fa99cd0b 100644
> > --- a/builtin/bisect--helper.c
> > +++ b/builtin/bisect--helper.c
> > @@ -26,8 +26,8 @@ static const char * const git_bisect_helper_usage[] = {
> >         N_("git bisect--helper --bisect-start [--term-{new,bad}=<term> --term-{old,good}=<term>]"
> >                                             " [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<paths>...]"),
> >         N_("git bisect--helper --bisect-next"),
> > -       N_("git bisect--helper --bisect-state (bad|new) [<rev>]"),
> > -       N_("git bisect--helper --bisect-state (good|old) [<rev>...]"),
> > +       N_("git bisect--helper [--bisect-state] (bad|new) [<rev>]"),
> > +       N_("git bisect--helper [--bisect-state] (good|old) [<rev>...]"),
> >         N_("git bisect--helper --bisect-replay <filename>"),
> >         N_("git bisect--helper --bisect-skip [(<rev>|<range>)...]"),
> >         N_("git bisect--helper --bisect-visualize"),
> > @@ -1210,6 +1210,13 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
> >                              git_bisect_helper_usage,
> >                              PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN);
> >
> > +       if (!cmdmode && argc > 0) {
> > +               set_terms(&terms, "bad", "good");
> > +               get_terms(&terms);
> > +               if (!check_and_set_terms(&terms, argv[0]))
> > +                       cmdmode = BISECT_STATE;
> > +       }
> > +
> >         if (!cmdmode)
> >                 usage_with_options(git_bisect_helper_usage, options);
> >
> > @@ -1218,11 +1225,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
> >                 set_terms(&terms, "bad", "good");
> >                 res = bisect_start(&terms, argv, argc);
> >                 break;
> > -       case BISECT_STATE:
> > -               set_terms(&terms, "bad", "good");
> > -               get_terms(&terms);
> > -               res = bisect_state(&terms, argv, argc);
> > -               break;
> >         case BISECT_TERMS:
> >                 if (argc > 1)
> >                         return error(_("--bisect-terms requires 0 or 1 argument"));
> > @@ -1265,6 +1267,13 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
> >                 get_terms(&terms);
> >                 res = bisect_run(&terms, argv, argc);
> >                 break;
> > +       case BISECT_STATE:
> > +               if (!terms.term_good) {
> > +                       set_terms(&terms, "bad", "good");
> > +                       get_terms(&terms);
> > +               }
> > +               res = bisect_state(&terms, argv, argc);
> > +               break;
> >         default:
> >                 BUG("unknown subcommand %d", cmdmode);
> >         }
> > --
> > gitgitgadget
>
> Does it make sense to also include something like this:
>
> diff --git a/git-bisect.sh b/git-bisect.sh
> index 405cf76f2a..fbf56649d7 100755
> --- a/git-bisect.sh
> +++ b/git-bisect.sh
> @@ -60,7 +60,7 @@ case "$#" in
>         start)
>                 git bisect--helper --bisect-start "$@" ;;
>         bad|good|new|old|"$TERM_BAD"|"$TERM_GOOD")
> -               git bisect--helper --bisect-state "$cmd" "$@" ;;
> +               git bisect--helper "$cmd" "$@" ;;
>         skip)
>                 git bisect--helper --bisect-skip "$@" || exit;;
>         next)
>
> to prove that you've made it optional?  (Well, assuming one has run
> the tests with that change, but I did...)

Good point! That code will go away within the same patch series, of
course, but it is good to keep this in an intermediate commit.

Thanks,
Dscho

^ permalink raw reply	[flat|nested] 147+ messages in thread

* Re: [PATCH 07/11] bisect: move even the option parsing to `bisect--helper`
  2022-02-09  0:12   ` Elijah Newren
@ 2022-02-22 15:49     ` Johannes Schindelin
  0 siblings, 0 replies; 147+ messages in thread
From: Johannes Schindelin @ 2022-02-22 15:49 UTC (permalink / raw)
  To: Elijah Newren
  Cc: Johannes Schindelin via GitGitGadget, Git Mailing List,
	Pranit Bauva, Tanushree Tumane, Miriam Rubio

Hi Elijah,

On Tue, 8 Feb 2022, Elijah Newren wrote:

> On Fri, Jan 28, 2022 at 3:27 PM Johannes Schindelin via GitGitGadget
> <gitgitgadget@gmail.com> wrote:
>
> > [...]
> > +       const char *command = argc > 1 ? argv[1] : "help";
> >
> > -       argc = parse_options(argc, argv, prefix, options,
> > -                            git_bisect_helper_usage,
> > -                            PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN);
> > +       /* Handle -h and invalid options */
> > +       parse_options(argc - 1, argv + 1, prefix, options,
> > +                     git_bisect_usage,
> > +                     PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN |
> > +                     PARSE_OPT_ONE_SHOT | PARSE_OPT_STOP_AT_NON_OPTION);
> >
> > -       if (!cmdmode && argc > 0) {
> > +       if (!strcmp("help", command))
> > +               usage_with_options(git_bisect_usage, options);
>
> I think the rest of the changes in this file would be much easier to
> read if you did a
>    argc -= 2
>    argv += 2
> here...
>
> > +       else if (!strcmp("start", command)) {
>
> ...and dropped the else here, just starting a new 'if' instead.

Makes sense.

While at it, I also explicitly handle the `-h` case and no longer bother
with the `parse_options()` call at all anymore.

>
> >                 set_terms(&terms, "bad", "good");
> > -               get_terms(&terms);
> > -               if (!check_and_set_terms(&terms, argv[0]))
> > -                       cmdmode = BISECT_STATE;
> > -       }
> > -
> > -       if (!cmdmode)
> > -               usage_with_options(git_bisect_helper_usage, options);
> > -
> > -       switch (cmdmode) {
> > -       case BISECT_START:
> > -               set_terms(&terms, "bad", "good");
> > -               res = bisect_start(&terms, argv, argc);
> > -               break;
> > -       case BISECT_TERMS:
> > -               if (argc > 1)
> > -                       return error(_("--bisect-terms requires 0 or 1 argument"));
> > -               res = bisect_terms(&terms, argc == 1 ? argv[0] : NULL);
> > -               break;
> > -       case BISECT_SKIP:
> > +               res = bisect_start(&terms, argv + 2, argc - 2);
> > +       } else if (!strcmp("terms", command)) {
> > +               if (argc > 3)
> > +                       return error(_("'terms' requires 0 or 1 argument"));
> > +               res = bisect_terms(&terms, argc == 3 ? argv[2] : NULL);
> > +       } else if (!strcmp("skip", command)) {
> >                 set_terms(&terms, "bad", "good");
> >                 get_terms(&terms);
> > -               res = bisect_skip(&terms, argv, argc);
> > -               break;
> > -       case BISECT_NEXT:
> > -               if (argc)
> > -                       return error(_("--bisect-next requires 0 arguments"));
> > +               res = bisect_skip(&terms, argv + 2, argc - 2);
> > +       } else if (!strcmp("next", command)) {
> > +               if (argc != 2)
> > +                       return error(_("'next' requires 0 arguments"));
> >                 get_terms(&terms);
> >                 res = bisect_next(&terms, prefix);
> > -               break;
> > -       case BISECT_RESET:
> > -               if (argc > 1)
> > -                       return error(_("--bisect-reset requires either no argument or a commit"));
> > -               res = bisect_reset(argc ? argv[0] : NULL);
> > -               break;
> > -       case BISECT_VISUALIZE:
> > +       } else if (!strcmp("reset", command)) {
> > +               if (argc > 3)
> > +                       return error(_("'reset' requires either no argument or a commit"));
> > +               res = bisect_reset(argc > 2 ? argv[2] : NULL);
> > +       } else if (one_of(command, "visualize", "view", NULL)) {
> >                 get_terms(&terms);
> > -               res = bisect_visualize(&terms, argv, argc);
> > -               break;
> > -       case BISECT_REPLAY:
> > -               if (argc != 1)
> > +               res = bisect_visualize(&terms, argv + 2, argc - 2);
> > +       } else if (!strcmp("replay", command)) {
> > +               if (argc != 3)
> >                         return error(_("no logfile given"));
> >                 set_terms(&terms, "bad", "good");
> > -               res = bisect_replay(&terms, argv[0]);
> > -               break;
> > -       case BISECT_LOG:
> > -               if (argc)
> > -                       return error(_("--bisect-log requires 0 arguments"));
> > +               res = bisect_replay(&terms, argv[2]);
> > +       } else if (!strcmp("log", command)) {
> > +               if (argc > 2)
> > +                       return error(_("'log' requires 0 arguments"));
> >                 res = bisect_log();
> > -               break;
> > -       case BISECT_RUN:
> > -               if (!argc)
> > +       } else if (!strcmp("run", command)) {
> > +               if (argc < 3)
> >                         return error(_("bisect run failed: no command provided."));
> >                 get_terms(&terms);
> > -               res = bisect_run(&terms, argv, argc);
> > -               break;
> > -       case BISECT_STATE:
> > -               if (!terms.term_good) {
> > -                       set_terms(&terms, "bad", "good");
> > -                       get_terms(&terms);
> > +               res = bisect_run(&terms, argv + 2, argc - 2);
> > +       } else {
> > +               set_terms(&terms, "bad", "good");
> > +               get_terms(&terms);
> > +               if (!check_and_set_terms(&terms, command))
> > +                       res = bisect_state(&terms, argv + 1, argc - 1);
>
> Oh, hmm... this one is +1,-1 while all others are +2,-2, because there
> is not a separate "command"; the command was implicit and so that
> reserved argument is actually part of the terms.  Still if we did the
> offset by two trick above, I guess we'd just add a comment here and do
> argv-1, argc+1?

Right, we can just "shift the command back in".

Thank you,
Dscho

^ permalink raw reply	[flat|nested] 147+ messages in thread

* Re: [PATCH 06/11] bisect--helper: make `--bisect-state` optional
  2022-02-09 19:45   ` Junio C Hamano
@ 2022-02-22 15:53     ` Johannes Schindelin
  0 siblings, 0 replies; 147+ messages in thread
From: Johannes Schindelin @ 2022-02-22 15:53 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Johannes Schindelin via GitGitGadget, git, Pranit Bauva,
	Tanushree Tumane, Miriam Rubio

Hi Junio,

On Wed, 9 Feb 2022, Junio C Hamano wrote:

> "Johannes Schindelin via GitGitGadget" <gitgitgadget@gmail.com>
> writes:
>
> > @@ -1210,6 +1210,13 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
> >  			     git_bisect_helper_usage,
> >  			     PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN);
> >
> > +	if (!cmdmode && argc > 0) {
> > +		set_terms(&terms, "bad", "good");
> > +		get_terms(&terms);
> > +		if (!check_and_set_terms(&terms, argv[0]))
> > +			cmdmode = BISECT_STATE;
> > +	}
> > +
>
> I do agree with "if we want to reuse this function without changing
> it much, --bisect-state must become an optional and the default mode
> of operation" as a goal, but I do not quite get this change.  From
> the rephased description of the goal, what I would expect is more
> like
>
> 	if (!cmdmode && possibly-other-conditions-like-argc-check)
> 		cmdmode = BISECT_STATE;
>
> and nothing else.

That would not work, though: we must ensure that the `argv[0]` is a
bad/good term (hence the need to call `set_terms()` and `get_terms()` to
retrieve potentially overridden terms and then the call to
`check_and_set_terms()` to verify that it was one of those terms).

> Between the case where --bisect-state was and was not given explicitly,
> check-and-set-terms is or is not called.  I
> can see that checking would be _nice_ when we try to decide if the
> first token makes sense as good/bad and the user wanted to do the
> "state" thing impolicitly, but if it is worth checking in implicit
> case, shouldn't we be checking when the --bisect-state is explicitly
> given as well?

I tried to keep the `if (!cmdmode) usage...` in place, and that's probably
what caused your confusion. I replaced it with:

-- snip --
@@ -1210,10 +1210,7 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
                             git_bisect_helper_usage,
                             PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN);

-       if (!cmdmode)
-               usage_with_options(git_bisect_helper_usage, options);
-
-       switch (cmdmode) {
+       switch (cmdmode ? cmdmode : BISECT_STATE) {
        case BISECT_START:
                set_terms(&terms, "bad", "good");
                res = bisect_start(&terms, argv, argc);
@@ -1221,6 +1218,11 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
        case BISECT_STATE:
                set_terms(&terms, "bad", "good");
                get_terms(&terms);
+               if (!cmdmode &&
+                   (!argc || check_and_set_terms(&terms, argv[0]))) {
+                       char *msg = xstrfmt(_("unknown command: '%s'"), argv[0]);
+                       usage_msg_opt(msg, git_bisect_helper_usage, options);
+               }
                res = bisect_state(&terms, argv, argc);
                break;
        case BISECT_TERMS:
-- snap --

I am not the best judge whether this is more obvious because I am so
familiar with this code, but I hope that it is at least more concise.

> And the actual execution of the BISECT_STATE command is even more
> puzzling, below.
>
> >  	if (!cmdmode)
> >  		usage_with_options(git_bisect_helper_usage, options);
> >
> > @@ -1218,11 +1225,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
> >  		set_terms(&terms, "bad", "good");
> >  		res = bisect_start(&terms, argv, argc);
> >  		break;
> > -	case BISECT_STATE:
> > -		set_terms(&terms, "bad", "good");
> > -		get_terms(&terms);
> > -		res = bisect_state(&terms, argv, argc);
> > -		break;
> >  	case BISECT_TERMS:
> >  		if (argc > 1)
> >  			return error(_("--bisect-terms requires 0 or 1 argument"));
> > @@ -1265,6 +1267,13 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
> >  		get_terms(&terms);
> >  		res = bisect_run(&terms, argv, argc);
> >  		break;
> > +	case BISECT_STATE:
> > +		if (!terms.term_good) {
> > +			set_terms(&terms, "bad", "good");
> > +			get_terms(&terms);
> > +		}
> > +		res = bisect_state(&terms, argv, argc);
> > +		break;
>
> This case arm has been moved but because there is no fall-through in
> this switch statement, the movement is a no-op.  But the code has
> also changed with this patch.  We used to do set_terms/get_terms
> unconditionally, but we do not even do so when terms_good (but not
> terms_bad) is already set.
>
> Is this an unrelated bugfix of some kind?  This does not look
> related to "making --bisect-state optional and implicit default" at
> all.  At least the proposed log message does not explain why.

I had hoped that this part of the commit message would be clear enough:

	To prepare for converting `bisect--helper` to a full built-in
	implementation of `git bisect` (which must not require the
	`--bisect-state` option to be specified at all), let's move the
	handling toward the end of the `switch (cmdmode)` block.

Since my hope did not turn into reality, I split out that move into its
own commit (making the patch series even longer, but hopefully at least
making it more readable, too).

Ciao,
Dscho

^ permalink raw reply	[flat|nested] 147+ messages in thread

* Re: [PATCH 00/11] Finish converting git bisect into a built-in
  2022-02-09  4:41   ` Elijah Newren
@ 2022-02-22 15:55     ` Johannes Schindelin
  0 siblings, 0 replies; 147+ messages in thread
From: Johannes Schindelin @ 2022-02-22 15:55 UTC (permalink / raw)
  To: Elijah Newren
  Cc: Johannes Schindelin via GitGitGadget, Git Mailing List,
	Pranit Bauva, Tanushree Tumane, Miriam Rubio

Hi Elijah,

On Tue, 8 Feb 2022, Elijah Newren wrote:

> On Sat, Jan 29, 2022 at 10:39 PM Elijah Newren <newren@gmail.com> wrote:
> >
> > On Fri, Jan 28, 2022 at 3:08 PM Johannes Schindelin via GitGitGadget
> > <gitgitgadget@gmail.com> wrote:
> > >
> > > After three GSoC/Outreachy students spent an incredible effort on this, it
> > > is finally time to put a neat little bow on it.
> > >
> > > Johannes Schindelin (11):
> > >   bisect run: fix the error message
> > >   bisect--helper: retire the --no-log option
> > >   bisect--helper: really retire --bisect-next-check
> > >   bisect--helper: really retire `--bisect-autostart`
> > >   bisect--helper: align the sub-command order with git-bisect.sh
> > >   bisect--helper: make `--bisect-state` optional
> > >   bisect: move even the option parsing to `bisect--helper`
> > >   bisect--helper: using `--bisect-state` without an argument is a bug
> > >   Turn `git bisect` into a full built-in.
> > >   bisect: remove Cogito-related code
> > >   bisect: no longer try to clean up left-over `.git/head-name` files
> > >
> > >  Makefile                               |   3 +-
> > >  bisect.c                               |   3 -
> > >  builtin.h                              |   2 +-
> > >  builtin/{bisect--helper.c => bisect.c} | 201 ++++++++++---------------
> > >  git-bisect.sh                          |  84 -----------
> > >  git.c                                  |   2 +-
> > >  t/t6030-bisect-porcelain.sh            |   1 -
> > >  7 files changed, 84 insertions(+), 212 deletions(-)
> > >  rename builtin/{bisect--helper.c => bisect.c} (87%)
> > >  delete mode 100755 git-bisect.sh
> >
> > I read through the series and couldn't spot any problems.
>
> I re-read the series, taking a closer look.  Spotted a few minor
> things (and left some comments) but the series looks pretty good to
> me.  I think Dscho's on vacation, so we'll resume the discussion when
> he gets back.

I took some time off, and then had to focus on other things, so I only got
back to this patch series today.

Thank you so much for your helpful feedback!

Ciao,
Dscho

^ permalink raw reply	[flat|nested] 147+ messages in thread

* [PATCH v2 00/14] Finish converting git bisect into a built-in
  2022-01-28  0:12 [PATCH 00/11] Finish converting git bisect into a built-in Johannes Schindelin via GitGitGadget
                   ` (12 preceding siblings ...)
  2022-01-30  6:39 ` Elijah Newren
@ 2022-02-22 16:30 ` Johannes Schindelin via GitGitGadget
  2022-02-22 16:30   ` [PATCH v2 01/14] bisect run: fix the error message Johannes Schindelin via GitGitGadget
                     ` (16 more replies)
  13 siblings, 17 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-02-22 16:30 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Johannes Schindelin

After three GSoC/Outreachy students spent an incredible effort on this, it
is finally time to put a neat little bow on it.

Changes since v1:

 * Added a regression test to "bisect run: fix the error message".
 * Added a patch to address an error message that double-single-quoted the
   command.
 * Reworked the logic in "bisect--helper: make --bisect-state optional" to
   delay showing the usage upon an unknown command, which should make the
   code a lot less confusing.
 * Split out the change that moved the BISECT_STATE case to the end of the
   switch block.
 * Added a patch that replaces the return error() calls in
   cmd_bisect_helper() with die() calls, to avoid returning -1 as an exit
   code.
 * Dropped the use of parse_options() for the single purpose of handling -h;
   This is now done explicitly.
 * Simplified the diff of "bisect: move even the option parsing to
   bisect--helper" by modifying argc and argv instead of modifying all the
   function calls using those variables.
 * In the "Turn git bisect into a full built-in" patch, changed the name of
   the variable holding the usage to use the builtin_ prefix used in other
   built-ins, too.
 * Removed the trailing dot from the commit message of "Turn git bisect into
   a full built-in".

Johannes Schindelin (14):
  bisect run: fix the error message
  bisect: avoid double-quoting when printing the failed command
  bisect--helper: retire the --no-log option
  bisect--helper: really retire --bisect-next-check
  bisect--helper: really retire `--bisect-autostart`
  bisect--helper: using `--bisect-state` without an argument is a bug
  bisect--helper: align the sub-command order with git-bisect.sh
  bisect--helper: make `--bisect-state` optional
  bisect--helper: move the `BISECT_STATE` case to the end
  bisect--helper: return only correct exit codes in `cmd_*()`
  bisect: move even the option parsing to `bisect--helper`
  Turn `git bisect` into a full built-in
  bisect: remove Cogito-related code
  bisect: no longer try to clean up left-over `.git/head-name` files

 Makefile                               |   3 +-
 bisect.c                               |   3 -
 builtin.h                              |   2 +-
 builtin/{bisect--helper.c => bisect.c} | 189 ++++++++++---------------
 git-bisect.sh                          |  84 -----------
 git.c                                  |   2 +-
 t/t6030-bisect-porcelain.sh            |  11 +-
 7 files changed, 88 insertions(+), 206 deletions(-)
 rename builtin/{bisect--helper.c => bisect.c} (88%)
 delete mode 100755 git-bisect.sh


base-commit: 89bece5c8c96f0b962cfc89e63f82d603fd60bed
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-1132%2Fdscho%2Fbisect-in-c-v2
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1132/dscho/bisect-in-c-v2
Pull-Request: https://github.com/gitgitgadget/git/pull/1132

Range-diff vs v1:

  1:  93d19d85ee3 !  1:  81ca0d68cde bisect run: fix the error message
     @@ Commit message
          was "good" or "bad", but used a bogus (because non-populated) `args`
          variable for it.
      
     +    Helped-by: Elijah Newren <newren@gmail.com>
          Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
      
       ## builtin/bisect--helper.c ##
     @@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, cons
       		strvec_clear(&run_args);
       		return res;
       	}
     +
     + ## t/t6030-bisect-porcelain.sh ##
     +@@ t/t6030-bisect-porcelain.sh: test_expect_success 'bisect visualize with a filename with dash and space' '
     + 	git bisect visualize -p -- "-hello 2"
     + '
     + 
     ++test_expect_success 'testing' '
     ++	git bisect reset &&
     ++	git bisect start $HASH4 $HASH1 &&
     ++	write_script test_script.sh <<-\EOF &&
     ++	rm .git/BISECT*
     ++	EOF
     ++	test_must_fail git bisect run ./test_script.sh 2>error &&
     ++	grep "git bisect good.*exited with error code" error
     ++'
     ++
     + test_done
  -:  ----------- >  2:  4320101f2e0 bisect: avoid double-quoting when printing the failed command
  2:  8e0e5559980 =  3:  88d7173c86b bisect--helper: retire the --no-log option
  3:  996a7099bf8 =  4:  b914fe64dda bisect--helper: really retire --bisect-next-check
  4:  3de4c48b66d =  5:  0d3db63bda6 bisect--helper: really retire `--bisect-autostart`
  8:  1b14ed3d797 =  6:  a345cf3e0e4 bisect--helper: using `--bisect-state` without an argument is a bug
  5:  6afc6e0eece =  7:  0487701220b bisect--helper: align the sub-command order with git-bisect.sh
  6:  eddbdde222a !  8:  d8b2767c148 bisect--helper: make `--bisect-state` optional
     @@ Commit message
          `git bisect--helper bad`, i.e. do not require the `--bisect-state`
          option to be passed explicitly.
      
     -    To prepare for converting `bisect--helper` to a full built-in
     -    implementation of `git bisect` (which must not require the
     -    `--bisect-state` option to be specified at all), let's move the handling
     -    toward the end of the `switch (cmdmode)` block.
     -
          Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
      
       ## builtin/bisect--helper.c ##
     @@ builtin/bisect--helper.c: int cmd_bisect__helper(int argc, const char **argv, co
       			     git_bisect_helper_usage,
       			     PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN);
       
     -+	if (!cmdmode && argc > 0) {
     -+		set_terms(&terms, "bad", "good");
     -+		get_terms(&terms);
     -+		if (!check_and_set_terms(&terms, argv[0]))
     -+			cmdmode = BISECT_STATE;
     -+	}
     -+
     - 	if (!cmdmode)
     - 		usage_with_options(git_bisect_helper_usage, options);
     - 
     -@@ builtin/bisect--helper.c: int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
     +-	if (!cmdmode)
     +-		usage_with_options(git_bisect_helper_usage, options);
     +-
     +-	switch (cmdmode) {
     ++	switch (cmdmode ? cmdmode : BISECT_STATE) {
     + 	case BISECT_START:
       		set_terms(&terms, "bad", "good");
       		res = bisect_start(&terms, argv, argc);
     - 		break;
     --	case BISECT_STATE:
     --		set_terms(&terms, "bad", "good");
     --		get_terms(&terms);
     --		res = bisect_state(&terms, argv, argc);
     --		break;
     - 	case BISECT_TERMS:
     - 		if (argc > 1)
     - 			return error(_("--bisect-terms requires 0 or 1 argument"));
      @@ builtin/bisect--helper.c: int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
     + 	case BISECT_STATE:
     + 		set_terms(&terms, "bad", "good");
       		get_terms(&terms);
     - 		res = bisect_run(&terms, argv, argc);
     - 		break;
     -+	case BISECT_STATE:
     -+		if (!terms.term_good) {
     -+			set_terms(&terms, "bad", "good");
     -+			get_terms(&terms);
     ++		if (!cmdmode &&
     ++		    (!argc || check_and_set_terms(&terms, argv[0]))) {
     ++			char *msg = xstrfmt(_("unknown command: '%s'"), argv[0]);
     ++			usage_msg_opt(msg, git_bisect_helper_usage, options);
      +		}
     -+		res = bisect_state(&terms, argv, argc);
     -+		break;
     - 	default:
     - 		BUG("unknown subcommand %d", cmdmode);
     - 	}
     + 		res = bisect_state(&terms, argv, argc);
     + 		break;
     + 	case BISECT_TERMS:
     +
     + ## git-bisect.sh ##
     +@@ git-bisect.sh: case "$#" in
     + 	start)
     + 		git bisect--helper --bisect-start "$@" ;;
     + 	bad|good|new|old|"$TERM_BAD"|"$TERM_GOOD")
     +-		git bisect--helper --bisect-state "$cmd" "$@" ;;
     ++		git bisect--helper "$cmd" "$@" ;;
     + 	skip)
     + 		git bisect--helper --bisect-skip "$@" || exit;;
     + 	next)
  -:  ----------- >  9:  e8904db81c5 bisect--helper: move the `BISECT_STATE` case to the end
  -:  ----------- > 10:  208f8fa4851 bisect--helper: return only correct exit codes in `cmd_*()`
  7:  515e86e2075 ! 11:  dc04b06206b bisect: move even the option parsing to `bisect--helper`
     @@ Commit message
          together. So it would appear as if a lot of work would have to be done
          just to be able to use `parse_options()` just to parse the sub-command,
          instead of a simple `if...else if` chain, the latter being a
     -    dramatically simpler implementation. Therefore, we now keep the
     -    `parse_options()` call primarily to support `-h` and little else.
     +    dramatically simpler implementation.
      
          Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
      
     @@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, cons
      -	argc = parse_options(argc, argv, prefix, options,
      -			     git_bisect_helper_usage,
      -			     PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN);
     -+	/* Handle -h and invalid options */
     -+	parse_options(argc - 1, argv + 1, prefix, options,
     -+		      git_bisect_usage,
     -+		      PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN |
     -+		      PARSE_OPT_ONE_SHOT | PARSE_OPT_STOP_AT_NON_OPTION);
     - 
     --	if (!cmdmode && argc > 0) {
     -+	if (!strcmp("help", command))
     ++	if (!strcmp("-h", command) || !strcmp("help", command))
      +		usage_with_options(git_bisect_usage, options);
     -+	else if (!strcmp("start", command)) {
     - 		set_terms(&terms, "bad", "good");
     --		get_terms(&terms);
     --		if (!check_and_set_terms(&terms, argv[0]))
     --			cmdmode = BISECT_STATE;
     --	}
     --
     --	if (!cmdmode)
     --		usage_with_options(git_bisect_helper_usage, options);
     --
     --	switch (cmdmode) {
     + 
     +-	switch (cmdmode ? cmdmode : BISECT_STATE) {
      -	case BISECT_START:
     --		set_terms(&terms, "bad", "good");
     --		res = bisect_start(&terms, argv, argc);
     ++	argc -= 2;
     ++	argv += 2;
     ++
     ++	if (!strcmp("start", command)) {
     + 		set_terms(&terms, "bad", "good");
     + 		res = bisect_start(&terms, argv, argc);
      -		break;
      -	case BISECT_TERMS:
     --		if (argc > 1)
     --			return error(_("--bisect-terms requires 0 or 1 argument"));
     --		res = bisect_terms(&terms, argc == 1 ? argv[0] : NULL);
     ++	} else if (!strcmp("terms", command)) {
     + 		if (argc > 1)
     +-			die(_("--bisect-terms requires 0 or 1 argument"));
     ++			die(_("'terms' requires 0 or 1 argument"));
     + 		res = bisect_terms(&terms, argc == 1 ? argv[0] : NULL);
      -		break;
      -	case BISECT_SKIP:
     -+		res = bisect_start(&terms, argv + 2, argc - 2);
     -+	} else if (!strcmp("terms", command)) {
     -+		if (argc > 3)
     -+			return error(_("'terms' requires 0 or 1 argument"));
     -+		res = bisect_terms(&terms, argc == 3 ? argv[2] : NULL);
      +	} else if (!strcmp("skip", command)) {
       		set_terms(&terms, "bad", "good");
       		get_terms(&terms);
     --		res = bisect_skip(&terms, argv, argc);
     + 		res = bisect_skip(&terms, argv, argc);
      -		break;
      -	case BISECT_NEXT:
     --		if (argc)
     --			return error(_("--bisect-next requires 0 arguments"));
     -+		res = bisect_skip(&terms, argv + 2, argc - 2);
      +	} else if (!strcmp("next", command)) {
     -+		if (argc != 2)
     -+			return error(_("'next' requires 0 arguments"));
     + 		if (argc)
     +-			die(_("--bisect-next requires 0 arguments"));
     ++			die(_("'next' requires 0 arguments"));
       		get_terms(&terms);
       		res = bisect_next(&terms, prefix);
      -		break;
      -	case BISECT_RESET:
     --		if (argc > 1)
     --			return error(_("--bisect-reset requires either no argument or a commit"));
     --		res = bisect_reset(argc ? argv[0] : NULL);
     ++	} else if (!strcmp("reset", command)) {
     + 		if (argc > 1)
     +-			die(_("--bisect-reset requires either no argument or a commit"));
     ++			die(_("'reset' requires either no argument or a commit"));
     + 		res = bisect_reset(argc ? argv[0] : NULL);
      -		break;
      -	case BISECT_VISUALIZE:
     -+	} else if (!strcmp("reset", command)) {
     -+		if (argc > 3)
     -+			return error(_("'reset' requires either no argument or a commit"));
     -+		res = bisect_reset(argc > 2 ? argv[2] : NULL);
      +	} else if (one_of(command, "visualize", "view", NULL)) {
       		get_terms(&terms);
     --		res = bisect_visualize(&terms, argv, argc);
     + 		res = bisect_visualize(&terms, argv, argc);
      -		break;
      -	case BISECT_REPLAY:
     --		if (argc != 1)
     -+		res = bisect_visualize(&terms, argv + 2, argc - 2);
      +	} else if (!strcmp("replay", command)) {
     -+		if (argc != 3)
     - 			return error(_("no logfile given"));
     + 		if (argc != 1)
     + 			die(_("no logfile given"));
       		set_terms(&terms, "bad", "good");
     --		res = bisect_replay(&terms, argv[0]);
     + 		res = bisect_replay(&terms, argv[0]);
      -		break;
      -	case BISECT_LOG:
     --		if (argc)
     --			return error(_("--bisect-log requires 0 arguments"));
     -+		res = bisect_replay(&terms, argv[2]);
      +	} else if (!strcmp("log", command)) {
     -+		if (argc > 2)
     -+			return error(_("'log' requires 0 arguments"));
     + 		if (argc)
     +-			die(_("--bisect-log requires 0 arguments"));
     ++			die(_("'log' requires 0 arguments"));
       		res = bisect_log();
      -		break;
      -	case BISECT_RUN:
     --		if (!argc)
      +	} else if (!strcmp("run", command)) {
     -+		if (argc < 3)
     - 			return error(_("bisect run failed: no command provided."));
     + 		if (!argc)
     + 			die(_("bisect run failed: no command provided."));
       		get_terms(&terms);
     --		res = bisect_run(&terms, argv, argc);
     + 		res = bisect_run(&terms, argv, argc);
      -		break;
      -	case BISECT_STATE:
     --		if (!terms.term_good) {
     --			set_terms(&terms, "bad", "good");
     --			get_terms(&terms);
     -+		res = bisect_run(&terms, argv + 2, argc - 2);
      +	} else {
     -+		set_terms(&terms, "bad", "good");
     -+		get_terms(&terms);
     -+		if (!check_and_set_terms(&terms, command))
     -+			res = bisect_state(&terms, argv + 1, argc - 1);
     -+		else {
     + 		set_terms(&terms, "bad", "good");
     + 		get_terms(&terms);
     +-		if (!cmdmode &&
     +-		    (!argc || check_and_set_terms(&terms, argv[0]))) {
     +-			char *msg = xstrfmt(_("unknown command: '%s'"), argv[0]);
     +-			usage_msg_opt(msg, git_bisect_helper_usage, options);
     ++		if (check_and_set_terms(&terms, command)) {
      +			char *msg = xstrfmt(_("unknown command: '%s'"), command);
      +			usage_msg_opt(msg, git_bisect_usage, options);
       		}
     --		res = bisect_state(&terms, argv, argc);
     ++		/* shift the `command` back in */
     ++		argc++;
     ++		argv--;
     + 		res = bisect_state(&terms, argv, argc);
      -		break;
      -	default:
      -		BUG("unknown subcommand %d", cmdmode);
     @@ git-bisect.sh: Please use "git help bisect" to get the full man page.'
      -	start)
      -		git bisect--helper --bisect-start "$@" ;;
      -	bad|good|new|old|"$TERM_BAD"|"$TERM_GOOD")
     --		git bisect--helper --bisect-state "$cmd" "$@" ;;
     +-		git bisect--helper "$cmd" "$@" ;;
      -	skip)
      -		git bisect--helper --bisect-skip "$@" || exit;;
      -	next)
  9:  1c0bd8a326f ! 12:  7db4b03b668 Turn `git bisect` into a full built-in.
     @@ Metadata
      Author: Johannes Schindelin <Johannes.Schindelin@gmx.de>
      
       ## Commit message ##
     -    Turn `git bisect` into a full built-in.
     +    Turn `git bisect` into a full built-in
      
          Now that the shell script hands off to the `bisect--helper` to do
          _anything_ (except to show the help), it is but a tiny step to let the
     @@ builtin.h: int cmd_am(int argc, const char **argv, const char *prefix);
       int cmd_bugreport(int argc, const char **argv, const char *prefix);
      
       ## builtin/bisect--helper.c => builtin/bisect.c ##
     +@@ builtin/bisect.c: static GIT_PATH_FUNC(git_path_bisect_names, "BISECT_NAMES")
     + static GIT_PATH_FUNC(git_path_bisect_first_parent, "BISECT_FIRST_PARENT")
     + static GIT_PATH_FUNC(git_path_bisect_run, "BISECT_RUN")
     + 
     +-static const char * const git_bisect_usage[] = {
     ++static const char * const builtin_bisect_usage[] = {
     + 	N_("git bisect help\n"
     + 	   "\tprint this long help message."),
     + 	N_("git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>]\n"
      @@ builtin/bisect.c: static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
       	}
       }
     @@ builtin/bisect.c: static int bisect_run(struct bisect_terms *terms, const char *
       {
       	int res = 0;
       	struct option options[] = {
     +@@ builtin/bisect.c: int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
     + 	const char *command = argc > 1 ? argv[1] : "help";
     + 
     + 	if (!strcmp("-h", command) || !strcmp("help", command))
     +-		usage_with_options(git_bisect_usage, options);
     ++		usage_with_options(builtin_bisect_usage, options);
     + 
     + 	argc -= 2;
     + 	argv += 2;
     +@@ builtin/bisect.c: int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
     + 		get_terms(&terms);
     + 		if (check_and_set_terms(&terms, command)) {
     + 			char *msg = xstrfmt(_("unknown command: '%s'"), command);
     +-			usage_msg_opt(msg, git_bisect_usage, options);
     ++			usage_msg_opt(msg, builtin_bisect_usage, options);
     + 		}
     + 		/* shift the `command` back in */
     + 		argc++;
      
       ## git-bisect.sh (deleted) ##
      @@
 10:  cce533486db = 13:  0611d16f772 bisect: remove Cogito-related code
 11:  dc77297c676 = 14:  e2fa11a819e bisect: no longer try to clean up left-over `.git/head-name` files

-- 
gitgitgadget

^ permalink raw reply	[flat|nested] 147+ messages in thread

* [PATCH v2 01/14] bisect run: fix the error message
  2022-02-22 16:30 ` [PATCH v2 00/14] " Johannes Schindelin via GitGitGadget
@ 2022-02-22 16:30   ` Johannes Schindelin via GitGitGadget
  2022-02-22 16:30   ` [PATCH v2 02/14] bisect: avoid double-quoting when printing the failed command Johannes Schindelin via GitGitGadget
                     ` (15 subsequent siblings)
  16 siblings, 0 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-02-22 16:30 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Johannes Schindelin, Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

In d1bbbe45df8 (bisect--helper: reimplement `bisect_run` shell function
in C, 2021-09-13), we ported the `bisect run` subcommand to C, including
the part that prints out an error message when the implicit `git bisect
bad` or `git bisect good` failed.

However, the error message was supposed to print out whether the state
was "good" or "bad", but used a bogus (because non-populated) `args`
variable for it.

Helped-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/bisect--helper.c    |  8 ++------
 t/t6030-bisect-porcelain.sh | 10 ++++++++++
 2 files changed, 12 insertions(+), 6 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 28a2e6a5750..4208206af07 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1093,7 +1093,6 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
 {
 	int res = BISECT_OK;
 	struct strbuf command = STRBUF_INIT;
-	struct strvec args = STRVEC_INIT;
 	struct strvec run_args = STRVEC_INIT;
 	const char *new_state;
 	int temporary_stdout_fd, saved_stdout;
@@ -1111,8 +1110,6 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
 	strvec_push(&run_args, command.buf);
 
 	while (1) {
-		strvec_clear(&args);
-
 		printf(_("running %s\n"), command.buf);
 		res = run_command_v_opt(run_args.v, RUN_USING_SHELL);
 
@@ -1157,14 +1154,13 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
 			printf(_("bisect found first bad commit"));
 			res = BISECT_OK;
 		} else if (res) {
-			error(_("bisect run failed: 'git bisect--helper --bisect-state"
-			" %s' exited with error code %d"), args.v[0], res);
+			error(_("bisect run failed: 'git bisect"
+			" %s' exited with error code %d"), new_state, res);
 		} else {
 			continue;
 		}
 
 		strbuf_release(&command);
-		strvec_clear(&args);
 		strvec_clear(&run_args);
 		return res;
 	}
diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh
index 1be85d064e7..720442de2eb 100755
--- a/t/t6030-bisect-porcelain.sh
+++ b/t/t6030-bisect-porcelain.sh
@@ -980,4 +980,14 @@ test_expect_success 'bisect visualize with a filename with dash and space' '
 	git bisect visualize -p -- "-hello 2"
 '
 
+test_expect_success 'testing' '
+	git bisect reset &&
+	git bisect start $HASH4 $HASH1 &&
+	write_script test_script.sh <<-\EOF &&
+	rm .git/BISECT*
+	EOF
+	test_must_fail git bisect run ./test_script.sh 2>error &&
+	grep "git bisect good.*exited with error code" error
+'
+
 test_done
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH v2 02/14] bisect: avoid double-quoting when printing the failed command
  2022-02-22 16:30 ` [PATCH v2 00/14] " Johannes Schindelin via GitGitGadget
  2022-02-22 16:30   ` [PATCH v2 01/14] bisect run: fix the error message Johannes Schindelin via GitGitGadget
@ 2022-02-22 16:30   ` Johannes Schindelin via GitGitGadget
  2022-02-22 16:30   ` [PATCH v2 03/14] bisect--helper: retire the --no-log option Johannes Schindelin via GitGitGadget
                     ` (14 subsequent siblings)
  16 siblings, 0 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-02-22 16:30 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Johannes Schindelin, Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

We already quote the command via `sq_quote_argv()`, no need to enclose
the result in an extraneous pair of single-quotes.

Pointed out by Elijah Newren.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/bisect--helper.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 4208206af07..ba6d90635a5 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1115,7 +1115,7 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
 
 		if (res < 0 || 128 <= res) {
 			error(_("bisect run failed: exit code %d from"
-				" '%s' is < 0 or >= 128"), res, command.buf);
+				" %s is < 0 or >= 128"), res, command.buf);
 			strbuf_release(&command);
 			return res;
 		}
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH v2 03/14] bisect--helper: retire the --no-log option
  2022-02-22 16:30 ` [PATCH v2 00/14] " Johannes Schindelin via GitGitGadget
  2022-02-22 16:30   ` [PATCH v2 01/14] bisect run: fix the error message Johannes Schindelin via GitGitGadget
  2022-02-22 16:30   ` [PATCH v2 02/14] bisect: avoid double-quoting when printing the failed command Johannes Schindelin via GitGitGadget
@ 2022-02-22 16:30   ` Johannes Schindelin via GitGitGadget
  2022-02-22 16:30   ` [PATCH v2 04/14] bisect--helper: really retire --bisect-next-check Johannes Schindelin via GitGitGadget
                     ` (13 subsequent siblings)
  16 siblings, 0 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-02-22 16:30 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Johannes Schindelin, Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

Turns out we actually never used it, anyway...

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/bisect--helper.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index ba6d90635a5..71a6f8f5192 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1182,7 +1182,7 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 		BISECT_VISUALIZE,
 		BISECT_RUN,
 	} cmdmode = 0;
-	int res = 0, nolog = 0;
+	int res = 0;
 	struct option options[] = {
 		OPT_CMDMODE(0, "bisect-reset", &cmdmode,
 			 N_("reset the bisection state"), BISECT_RESET),
@@ -1206,8 +1206,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 			 N_("visualize the bisection"), BISECT_VISUALIZE),
 		OPT_CMDMODE(0, "bisect-run", &cmdmode,
 			 N_("use <cmd>... to automatically bisect."), BISECT_RUN),
-		OPT_BOOL(0, "no-log", &nolog,
-			 N_("no log for BISECT_WRITE")),
 		OPT_END()
 	};
 	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH v2 04/14] bisect--helper: really retire --bisect-next-check
  2022-02-22 16:30 ` [PATCH v2 00/14] " Johannes Schindelin via GitGitGadget
                     ` (2 preceding siblings ...)
  2022-02-22 16:30   ` [PATCH v2 03/14] bisect--helper: retire the --no-log option Johannes Schindelin via GitGitGadget
@ 2022-02-22 16:30   ` Johannes Schindelin via GitGitGadget
  2022-02-22 16:30   ` [PATCH v2 05/14] bisect--helper: really retire `--bisect-autostart` Johannes Schindelin via GitGitGadget
                     ` (12 subsequent siblings)
  16 siblings, 0 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-02-22 16:30 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Johannes Schindelin, Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

In 911aba14205 (bisect--helper: retire `--bisect-next-check` subcommand,
2021-09-13), we removed the usage string and the implementation, but not
actually the option.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/bisect--helper.c | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 71a6f8f5192..4ee708e34c7 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1170,7 +1170,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 {
 	enum {
 		BISECT_RESET = 1,
-		BISECT_NEXT_CHECK,
 		BISECT_TERMS,
 		BISECT_START,
 		BISECT_AUTOSTART,
@@ -1186,8 +1185,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 	struct option options[] = {
 		OPT_CMDMODE(0, "bisect-reset", &cmdmode,
 			 N_("reset the bisection state"), BISECT_RESET),
-		OPT_CMDMODE(0, "bisect-next-check", &cmdmode,
-			 N_("check whether bad or good terms exist"), BISECT_NEXT_CHECK),
 		OPT_CMDMODE(0, "bisect-terms", &cmdmode,
 			 N_("print out the bisect terms"), BISECT_TERMS),
 		OPT_CMDMODE(0, "bisect-start", &cmdmode,
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH v2 05/14] bisect--helper: really retire `--bisect-autostart`
  2022-02-22 16:30 ` [PATCH v2 00/14] " Johannes Schindelin via GitGitGadget
                     ` (3 preceding siblings ...)
  2022-02-22 16:30   ` [PATCH v2 04/14] bisect--helper: really retire --bisect-next-check Johannes Schindelin via GitGitGadget
@ 2022-02-22 16:30   ` Johannes Schindelin via GitGitGadget
  2022-02-22 16:30   ` [PATCH v2 06/14] bisect--helper: using `--bisect-state` without an argument is a bug Johannes Schindelin via GitGitGadget
                     ` (11 subsequent siblings)
  16 siblings, 0 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-02-22 16:30 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Johannes Schindelin, Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

Since b0f6494f70f (bisect--helper: retire `--bisect-autostart`
subcommand, 2020-10-15), the `--bisect-autostart` option is no more. But
we kept the `enum` value of the command mode around. Let's drop it, too.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/bisect--helper.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 4ee708e34c7..c7763be2c51 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1172,7 +1172,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 		BISECT_RESET = 1,
 		BISECT_TERMS,
 		BISECT_START,
-		BISECT_AUTOSTART,
 		BISECT_NEXT,
 		BISECT_STATE,
 		BISECT_LOG,
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH v2 06/14] bisect--helper: using `--bisect-state` without an argument is a bug
  2022-02-22 16:30 ` [PATCH v2 00/14] " Johannes Schindelin via GitGitGadget
                     ` (4 preceding siblings ...)
  2022-02-22 16:30   ` [PATCH v2 05/14] bisect--helper: really retire `--bisect-autostart` Johannes Schindelin via GitGitGadget
@ 2022-02-22 16:30   ` Johannes Schindelin via GitGitGadget
  2022-02-22 16:30   ` [PATCH v2 07/14] bisect--helper: align the sub-command order with git-bisect.sh Johannes Schindelin via GitGitGadget
                     ` (10 subsequent siblings)
  16 siblings, 0 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-02-22 16:30 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Johannes Schindelin, Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

The `bisect--helper` command is not expected to be used directly by the
user. Therefore, it is a bug if it receives no argument to the
`--bisect-state` command mode, not a user error. Which means that we
need to call `BUG()` instead of `die()`.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/bisect--helper.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index c7763be2c51..fcddd7444a4 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -856,7 +856,7 @@ static enum bisect_error bisect_state(struct bisect_terms *terms, const char **a
 	struct oid_array revs = OID_ARRAY_INIT;
 
 	if (!argc)
-		return error(_("Please call `--bisect-state` with at least one argument"));
+		BUG("bisect_state() called without argument");
 
 	if (bisect_autostart(terms))
 		return BISECT_FAILED;
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH v2 07/14] bisect--helper: align the sub-command order with git-bisect.sh
  2022-02-22 16:30 ` [PATCH v2 00/14] " Johannes Schindelin via GitGitGadget
                     ` (5 preceding siblings ...)
  2022-02-22 16:30   ` [PATCH v2 06/14] bisect--helper: using `--bisect-state` without an argument is a bug Johannes Schindelin via GitGitGadget
@ 2022-02-22 16:30   ` Johannes Schindelin via GitGitGadget
  2022-02-22 16:30   ` [PATCH v2 08/14] bisect--helper: make `--bisect-state` optional Johannes Schindelin via GitGitGadget
                     ` (9 subsequent siblings)
  16 siblings, 0 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-02-22 16:30 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Johannes Schindelin, Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

We are about to retire the shell implementation of `git bisect`, or
maybe better put: the remainder of the shell implementation (a shell of
a script, if you want).

In preparation for that, align the order of the sub-commands with the
way the outgoing implementation presents them to the user.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/bisect--helper.c | 76 ++++++++++++++++++++--------------------
 1 file changed, 38 insertions(+), 38 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index fcddd7444a4..31243a88a02 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1169,37 +1169,37 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
 int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 {
 	enum {
-		BISECT_RESET = 1,
-		BISECT_TERMS,
-		BISECT_START,
-		BISECT_NEXT,
+		BISECT_START = 1,
 		BISECT_STATE,
-		BISECT_LOG,
-		BISECT_REPLAY,
+		BISECT_TERMS,
 		BISECT_SKIP,
+		BISECT_NEXT,
+		BISECT_RESET,
 		BISECT_VISUALIZE,
+		BISECT_REPLAY,
+		BISECT_LOG,
 		BISECT_RUN,
 	} cmdmode = 0;
 	int res = 0;
 	struct option options[] = {
-		OPT_CMDMODE(0, "bisect-reset", &cmdmode,
-			 N_("reset the bisection state"), BISECT_RESET),
-		OPT_CMDMODE(0, "bisect-terms", &cmdmode,
-			 N_("print out the bisect terms"), BISECT_TERMS),
 		OPT_CMDMODE(0, "bisect-start", &cmdmode,
 			 N_("start the bisect session"), BISECT_START),
-		OPT_CMDMODE(0, "bisect-next", &cmdmode,
-			 N_("find the next bisection commit"), BISECT_NEXT),
 		OPT_CMDMODE(0, "bisect-state", &cmdmode,
 			 N_("mark the state of ref (or refs)"), BISECT_STATE),
-		OPT_CMDMODE(0, "bisect-log", &cmdmode,
-			 N_("list the bisection steps so far"), BISECT_LOG),
-		OPT_CMDMODE(0, "bisect-replay", &cmdmode,
-			 N_("replay the bisection process from the given file"), BISECT_REPLAY),
+		OPT_CMDMODE(0, "bisect-terms", &cmdmode,
+			 N_("print out the bisect terms"), BISECT_TERMS),
 		OPT_CMDMODE(0, "bisect-skip", &cmdmode,
 			 N_("skip some commits for checkout"), BISECT_SKIP),
+		OPT_CMDMODE(0, "bisect-next", &cmdmode,
+			 N_("find the next bisection commit"), BISECT_NEXT),
+		OPT_CMDMODE(0, "bisect-reset", &cmdmode,
+			 N_("reset the bisection state"), BISECT_RESET),
 		OPT_CMDMODE(0, "bisect-visualize", &cmdmode,
 			 N_("visualize the bisection"), BISECT_VISUALIZE),
+		OPT_CMDMODE(0, "bisect-replay", &cmdmode,
+			 N_("replay the bisection process from the given file"), BISECT_REPLAY),
+		OPT_CMDMODE(0, "bisect-log", &cmdmode,
+			 N_("list the bisection steps so far"), BISECT_LOG),
 		OPT_CMDMODE(0, "bisect-run", &cmdmode,
 			 N_("use <cmd>... to automatically bisect."), BISECT_RUN),
 		OPT_END()
@@ -1214,19 +1214,24 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 		usage_with_options(git_bisect_helper_usage, options);
 
 	switch (cmdmode) {
-	case BISECT_RESET:
-		if (argc > 1)
-			return error(_("--bisect-reset requires either no argument or a commit"));
-		res = bisect_reset(argc ? argv[0] : NULL);
+	case BISECT_START:
+		set_terms(&terms, "bad", "good");
+		res = bisect_start(&terms, argv, argc);
+		break;
+	case BISECT_STATE:
+		set_terms(&terms, "bad", "good");
+		get_terms(&terms);
+		res = bisect_state(&terms, argv, argc);
 		break;
 	case BISECT_TERMS:
 		if (argc > 1)
 			return error(_("--bisect-terms requires 0 or 1 argument"));
 		res = bisect_terms(&terms, argc == 1 ? argv[0] : NULL);
 		break;
-	case BISECT_START:
+	case BISECT_SKIP:
 		set_terms(&terms, "bad", "good");
-		res = bisect_start(&terms, argv, argc);
+		get_terms(&terms);
+		res = bisect_skip(&terms, argv, argc);
 		break;
 	case BISECT_NEXT:
 		if (argc)
@@ -1234,15 +1239,14 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 		get_terms(&terms);
 		res = bisect_next(&terms, prefix);
 		break;
-	case BISECT_STATE:
-		set_terms(&terms, "bad", "good");
-		get_terms(&terms);
-		res = bisect_state(&terms, argv, argc);
+	case BISECT_RESET:
+		if (argc > 1)
+			return error(_("--bisect-reset requires either no argument or a commit"));
+		res = bisect_reset(argc ? argv[0] : NULL);
 		break;
-	case BISECT_LOG:
-		if (argc)
-			return error(_("--bisect-log requires 0 arguments"));
-		res = bisect_log();
+	case BISECT_VISUALIZE:
+		get_terms(&terms);
+		res = bisect_visualize(&terms, argv, argc);
 		break;
 	case BISECT_REPLAY:
 		if (argc != 1)
@@ -1250,14 +1254,10 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 		set_terms(&terms, "bad", "good");
 		res = bisect_replay(&terms, argv[0]);
 		break;
-	case BISECT_SKIP:
-		set_terms(&terms, "bad", "good");
-		get_terms(&terms);
-		res = bisect_skip(&terms, argv, argc);
-		break;
-	case BISECT_VISUALIZE:
-		get_terms(&terms);
-		res = bisect_visualize(&terms, argv, argc);
+	case BISECT_LOG:
+		if (argc)
+			return error(_("--bisect-log requires 0 arguments"));
+		res = bisect_log();
 		break;
 	case BISECT_RUN:
 		if (!argc)
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH v2 08/14] bisect--helper: make `--bisect-state` optional
  2022-02-22 16:30 ` [PATCH v2 00/14] " Johannes Schindelin via GitGitGadget
                     ` (6 preceding siblings ...)
  2022-02-22 16:30   ` [PATCH v2 07/14] bisect--helper: align the sub-command order with git-bisect.sh Johannes Schindelin via GitGitGadget
@ 2022-02-22 16:30   ` Johannes Schindelin via GitGitGadget
  2022-02-22 16:30   ` [PATCH v2 09/14] bisect--helper: move the `BISECT_STATE` case to the end Johannes Schindelin via GitGitGadget
                     ` (8 subsequent siblings)
  16 siblings, 0 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-02-22 16:30 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Johannes Schindelin, Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

In preparation for making `git bisect` a real built-in, let's prepare
the `bisect--helper` built-in to handle `git bisect--helper good` and
`git bisect--helper bad`, i.e. do not require the `--bisect-state`
option to be passed explicitly.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/bisect--helper.c | 14 ++++++++------
 git-bisect.sh            |  2 +-
 2 files changed, 9 insertions(+), 7 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 31243a88a02..39b3cd606f2 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -26,8 +26,8 @@ static const char * const git_bisect_helper_usage[] = {
 	N_("git bisect--helper --bisect-start [--term-{new,bad}=<term> --term-{old,good}=<term>]"
 					    " [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<paths>...]"),
 	N_("git bisect--helper --bisect-next"),
-	N_("git bisect--helper --bisect-state (bad|new) [<rev>]"),
-	N_("git bisect--helper --bisect-state (good|old) [<rev>...]"),
+	N_("git bisect--helper [--bisect-state] (bad|new) [<rev>]"),
+	N_("git bisect--helper [--bisect-state] (good|old) [<rev>...]"),
 	N_("git bisect--helper --bisect-replay <filename>"),
 	N_("git bisect--helper --bisect-skip [(<rev>|<range>)...]"),
 	N_("git bisect--helper --bisect-visualize"),
@@ -1210,10 +1210,7 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 			     git_bisect_helper_usage,
 			     PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN);
 
-	if (!cmdmode)
-		usage_with_options(git_bisect_helper_usage, options);
-
-	switch (cmdmode) {
+	switch (cmdmode ? cmdmode : BISECT_STATE) {
 	case BISECT_START:
 		set_terms(&terms, "bad", "good");
 		res = bisect_start(&terms, argv, argc);
@@ -1221,6 +1218,11 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 	case BISECT_STATE:
 		set_terms(&terms, "bad", "good");
 		get_terms(&terms);
+		if (!cmdmode &&
+		    (!argc || check_and_set_terms(&terms, argv[0]))) {
+			char *msg = xstrfmt(_("unknown command: '%s'"), argv[0]);
+			usage_msg_opt(msg, git_bisect_helper_usage, options);
+		}
 		res = bisect_state(&terms, argv, argc);
 		break;
 	case BISECT_TERMS:
diff --git a/git-bisect.sh b/git-bisect.sh
index 405cf76f2a3..fbf56649d7d 100755
--- a/git-bisect.sh
+++ b/git-bisect.sh
@@ -60,7 +60,7 @@ case "$#" in
 	start)
 		git bisect--helper --bisect-start "$@" ;;
 	bad|good|new|old|"$TERM_BAD"|"$TERM_GOOD")
-		git bisect--helper --bisect-state "$cmd" "$@" ;;
+		git bisect--helper "$cmd" "$@" ;;
 	skip)
 		git bisect--helper --bisect-skip "$@" || exit;;
 	next)
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH v2 09/14] bisect--helper: move the `BISECT_STATE` case to the end
  2022-02-22 16:30 ` [PATCH v2 00/14] " Johannes Schindelin via GitGitGadget
                     ` (7 preceding siblings ...)
  2022-02-22 16:30   ` [PATCH v2 08/14] bisect--helper: make `--bisect-state` optional Johannes Schindelin via GitGitGadget
@ 2022-02-22 16:30   ` Johannes Schindelin via GitGitGadget
  2022-02-22 16:30   ` [PATCH v2 10/14] bisect--helper: return only correct exit codes in `cmd_*()` Johannes Schindelin via GitGitGadget
                     ` (7 subsequent siblings)
  16 siblings, 0 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-02-22 16:30 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Johannes Schindelin, Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

In preparation for replacing the command-mode parsing in
`bisect--helper` with an if/else if/else chain, let's move the one
command that will be implicit (i.e. what will become the final `else`
without any `if`) to the end.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/bisect--helper.c | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 39b3cd606f2..ba047ee0fc8 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1215,16 +1215,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 		set_terms(&terms, "bad", "good");
 		res = bisect_start(&terms, argv, argc);
 		break;
-	case BISECT_STATE:
-		set_terms(&terms, "bad", "good");
-		get_terms(&terms);
-		if (!cmdmode &&
-		    (!argc || check_and_set_terms(&terms, argv[0]))) {
-			char *msg = xstrfmt(_("unknown command: '%s'"), argv[0]);
-			usage_msg_opt(msg, git_bisect_helper_usage, options);
-		}
-		res = bisect_state(&terms, argv, argc);
-		break;
 	case BISECT_TERMS:
 		if (argc > 1)
 			return error(_("--bisect-terms requires 0 or 1 argument"));
@@ -1267,6 +1257,16 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 		get_terms(&terms);
 		res = bisect_run(&terms, argv, argc);
 		break;
+	case BISECT_STATE:
+		set_terms(&terms, "bad", "good");
+		get_terms(&terms);
+		if (!cmdmode &&
+		    (!argc || check_and_set_terms(&terms, argv[0]))) {
+			char *msg = xstrfmt(_("unknown command: '%s'"), argv[0]);
+			usage_msg_opt(msg, git_bisect_helper_usage, options);
+		}
+		res = bisect_state(&terms, argv, argc);
+		break;
 	default:
 		BUG("unknown subcommand %d", cmdmode);
 	}
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH v2 10/14] bisect--helper: return only correct exit codes in `cmd_*()`
  2022-02-22 16:30 ` [PATCH v2 00/14] " Johannes Schindelin via GitGitGadget
                     ` (8 preceding siblings ...)
  2022-02-22 16:30   ` [PATCH v2 09/14] bisect--helper: move the `BISECT_STATE` case to the end Johannes Schindelin via GitGitGadget
@ 2022-02-22 16:30   ` Johannes Schindelin via GitGitGadget
  2022-02-22 16:30   ` [PATCH v2 11/14] bisect: move even the option parsing to `bisect--helper` Johannes Schindelin via GitGitGadget
                     ` (6 subsequent siblings)
  16 siblings, 0 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-02-22 16:30 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Johannes Schindelin, Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

Exit codes cannot be negative, but `error()` returns -1.

Let's just go with the common pattern and call `die()` in
`cmd_bisect__helper()` when incorrect arguments were detected.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/bisect--helper.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index ba047ee0fc8..5228964937d 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1217,7 +1217,7 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 		break;
 	case BISECT_TERMS:
 		if (argc > 1)
-			return error(_("--bisect-terms requires 0 or 1 argument"));
+			die(_("--bisect-terms requires 0 or 1 argument"));
 		res = bisect_terms(&terms, argc == 1 ? argv[0] : NULL);
 		break;
 	case BISECT_SKIP:
@@ -1227,13 +1227,13 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 		break;
 	case BISECT_NEXT:
 		if (argc)
-			return error(_("--bisect-next requires 0 arguments"));
+			die(_("--bisect-next requires 0 arguments"));
 		get_terms(&terms);
 		res = bisect_next(&terms, prefix);
 		break;
 	case BISECT_RESET:
 		if (argc > 1)
-			return error(_("--bisect-reset requires either no argument or a commit"));
+			die(_("--bisect-reset requires either no argument or a commit"));
 		res = bisect_reset(argc ? argv[0] : NULL);
 		break;
 	case BISECT_VISUALIZE:
@@ -1242,18 +1242,18 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 		break;
 	case BISECT_REPLAY:
 		if (argc != 1)
-			return error(_("no logfile given"));
+			die(_("no logfile given"));
 		set_terms(&terms, "bad", "good");
 		res = bisect_replay(&terms, argv[0]);
 		break;
 	case BISECT_LOG:
 		if (argc)
-			return error(_("--bisect-log requires 0 arguments"));
+			die(_("--bisect-log requires 0 arguments"));
 		res = bisect_log();
 		break;
 	case BISECT_RUN:
 		if (!argc)
-			return error(_("bisect run failed: no command provided."));
+			die(_("bisect run failed: no command provided."));
 		get_terms(&terms);
 		res = bisect_run(&terms, argv, argc);
 		break;
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH v2 11/14] bisect: move even the option parsing to `bisect--helper`
  2022-02-22 16:30 ` [PATCH v2 00/14] " Johannes Schindelin via GitGitGadget
                     ` (9 preceding siblings ...)
  2022-02-22 16:30   ` [PATCH v2 10/14] bisect--helper: return only correct exit codes in `cmd_*()` Johannes Schindelin via GitGitGadget
@ 2022-02-22 16:30   ` Johannes Schindelin via GitGitGadget
  2022-02-23  9:47     ` Ævar Arnfjörð Bjarmason
  2022-02-22 16:30   ` [PATCH v2 12/14] Turn `git bisect` into a full built-in Johannes Schindelin via GitGitGadget
                     ` (5 subsequent siblings)
  16 siblings, 1 reply; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-02-22 16:30 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Johannes Schindelin, Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

On our journey to a fully built-in `git bisect`, this is the
second-to-last step.

Side note: The `if (!strcmp(...)) ... else if (!strcmp(...)) ... else if
(!strcmp(...)) ...` chain seen in this patch was not actually the first
idea how to convert the command modes to sub-commands. Since the
`bisect--helper` command already used the `parse-opions` API with neatly
set-up command modes, naturally the idea was to use `PARSE_OPT_NODASH`
to support proper sub-commands instead. However, the `parse-options` API
is not set up for that, and even after making that option work with long
options, it turned out that `STOP_AT_NON_OPTION` and `KEEP_UNKNOWN`
would have to be used but these options were not designed to work
together. So it would appear as if a lot of work would have to be done
just to be able to use `parse_options()` just to parse the sub-command,
instead of a simple `if...else if` chain, the latter being a
dramatically simpler implementation.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/bisect--helper.c | 133 ++++++++++++++++-----------------------
 git-bisect.sh            |  49 +--------------
 2 files changed, 56 insertions(+), 126 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 5228964937d..ef0b06d594b 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -20,18 +20,34 @@ static GIT_PATH_FUNC(git_path_bisect_names, "BISECT_NAMES")
 static GIT_PATH_FUNC(git_path_bisect_first_parent, "BISECT_FIRST_PARENT")
 static GIT_PATH_FUNC(git_path_bisect_run, "BISECT_RUN")
 
-static const char * const git_bisect_helper_usage[] = {
-	N_("git bisect--helper --bisect-reset [<commit>]"),
-	N_("git bisect--helper --bisect-terms [--term-good | --term-old | --term-bad | --term-new]"),
-	N_("git bisect--helper --bisect-start [--term-{new,bad}=<term> --term-{old,good}=<term>]"
-					    " [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<paths>...]"),
-	N_("git bisect--helper --bisect-next"),
-	N_("git bisect--helper [--bisect-state] (bad|new) [<rev>]"),
-	N_("git bisect--helper [--bisect-state] (good|old) [<rev>...]"),
-	N_("git bisect--helper --bisect-replay <filename>"),
-	N_("git bisect--helper --bisect-skip [(<rev>|<range>)...]"),
-	N_("git bisect--helper --bisect-visualize"),
-	N_("git bisect--helper --bisect-run <cmd>..."),
+static const char * const git_bisect_usage[] = {
+	N_("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."),
 	NULL
 };
 
@@ -1168,108 +1184,69 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
 
 int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 {
-	enum {
-		BISECT_START = 1,
-		BISECT_STATE,
-		BISECT_TERMS,
-		BISECT_SKIP,
-		BISECT_NEXT,
-		BISECT_RESET,
-		BISECT_VISUALIZE,
-		BISECT_REPLAY,
-		BISECT_LOG,
-		BISECT_RUN,
-	} cmdmode = 0;
 	int res = 0;
 	struct option options[] = {
-		OPT_CMDMODE(0, "bisect-start", &cmdmode,
-			 N_("start the bisect session"), BISECT_START),
-		OPT_CMDMODE(0, "bisect-state", &cmdmode,
-			 N_("mark the state of ref (or refs)"), BISECT_STATE),
-		OPT_CMDMODE(0, "bisect-terms", &cmdmode,
-			 N_("print out the bisect terms"), BISECT_TERMS),
-		OPT_CMDMODE(0, "bisect-skip", &cmdmode,
-			 N_("skip some commits for checkout"), BISECT_SKIP),
-		OPT_CMDMODE(0, "bisect-next", &cmdmode,
-			 N_("find the next bisection commit"), BISECT_NEXT),
-		OPT_CMDMODE(0, "bisect-reset", &cmdmode,
-			 N_("reset the bisection state"), BISECT_RESET),
-		OPT_CMDMODE(0, "bisect-visualize", &cmdmode,
-			 N_("visualize the bisection"), BISECT_VISUALIZE),
-		OPT_CMDMODE(0, "bisect-replay", &cmdmode,
-			 N_("replay the bisection process from the given file"), BISECT_REPLAY),
-		OPT_CMDMODE(0, "bisect-log", &cmdmode,
-			 N_("list the bisection steps so far"), BISECT_LOG),
-		OPT_CMDMODE(0, "bisect-run", &cmdmode,
-			 N_("use <cmd>... to automatically bisect."), BISECT_RUN),
 		OPT_END()
 	};
 	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
+	const char *command = argc > 1 ? argv[1] : "help";
 
-	argc = parse_options(argc, argv, prefix, options,
-			     git_bisect_helper_usage,
-			     PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN);
+	if (!strcmp("-h", command) || !strcmp("help", command))
+		usage_with_options(git_bisect_usage, options);
 
-	switch (cmdmode ? cmdmode : BISECT_STATE) {
-	case BISECT_START:
+	argc -= 2;
+	argv += 2;
+
+	if (!strcmp("start", command)) {
 		set_terms(&terms, "bad", "good");
 		res = bisect_start(&terms, argv, argc);
-		break;
-	case BISECT_TERMS:
+	} else if (!strcmp("terms", command)) {
 		if (argc > 1)
-			die(_("--bisect-terms requires 0 or 1 argument"));
+			die(_("'terms' requires 0 or 1 argument"));
 		res = bisect_terms(&terms, argc == 1 ? argv[0] : NULL);
-		break;
-	case BISECT_SKIP:
+	} else if (!strcmp("skip", command)) {
 		set_terms(&terms, "bad", "good");
 		get_terms(&terms);
 		res = bisect_skip(&terms, argv, argc);
-		break;
-	case BISECT_NEXT:
+	} else if (!strcmp("next", command)) {
 		if (argc)
-			die(_("--bisect-next requires 0 arguments"));
+			die(_("'next' requires 0 arguments"));
 		get_terms(&terms);
 		res = bisect_next(&terms, prefix);
-		break;
-	case BISECT_RESET:
+	} else if (!strcmp("reset", command)) {
 		if (argc > 1)
-			die(_("--bisect-reset requires either no argument or a commit"));
+			die(_("'reset' requires either no argument or a commit"));
 		res = bisect_reset(argc ? argv[0] : NULL);
-		break;
-	case BISECT_VISUALIZE:
+	} else if (one_of(command, "visualize", "view", NULL)) {
 		get_terms(&terms);
 		res = bisect_visualize(&terms, argv, argc);
-		break;
-	case BISECT_REPLAY:
+	} else if (!strcmp("replay", command)) {
 		if (argc != 1)
 			die(_("no logfile given"));
 		set_terms(&terms, "bad", "good");
 		res = bisect_replay(&terms, argv[0]);
-		break;
-	case BISECT_LOG:
+	} else if (!strcmp("log", command)) {
 		if (argc)
-			die(_("--bisect-log requires 0 arguments"));
+			die(_("'log' requires 0 arguments"));
 		res = bisect_log();
-		break;
-	case BISECT_RUN:
+	} else if (!strcmp("run", command)) {
 		if (!argc)
 			die(_("bisect run failed: no command provided."));
 		get_terms(&terms);
 		res = bisect_run(&terms, argv, argc);
-		break;
-	case BISECT_STATE:
+	} else {
 		set_terms(&terms, "bad", "good");
 		get_terms(&terms);
-		if (!cmdmode &&
-		    (!argc || check_and_set_terms(&terms, argv[0]))) {
-			char *msg = xstrfmt(_("unknown command: '%s'"), argv[0]);
-			usage_msg_opt(msg, git_bisect_helper_usage, options);
+		if (check_and_set_terms(&terms, command)) {
+			char *msg = xstrfmt(_("unknown command: '%s'"), command);
+			usage_msg_opt(msg, git_bisect_usage, options);
 		}
+		/* shift the `command` back in */
+		argc++;
+		argv--;
 		res = bisect_state(&terms, argv, argc);
-		break;
-	default:
-		BUG("unknown subcommand %d", cmdmode);
 	}
+
 	free_terms(&terms);
 
 	/*
diff --git a/git-bisect.sh b/git-bisect.sh
index fbf56649d7d..028d39cd9ce 100755
--- a/git-bisect.sh
+++ b/git-bisect.sh
@@ -34,51 +34,4 @@ Please use "git help bisect" to get the full man page.'
 OPTIONS_SPEC=
 . git-sh-setup
 
-TERM_BAD=bad
-TERM_GOOD=good
-
-get_terms () {
-	if test -s "$GIT_DIR/BISECT_TERMS"
-	then
-		{
-		read TERM_BAD
-		read TERM_GOOD
-		} <"$GIT_DIR/BISECT_TERMS"
-	fi
-}
-
-case "$#" in
-0)
-	usage ;;
-*)
-	cmd="$1"
-	get_terms
-	shift
-	case "$cmd" in
-	help)
-		git bisect -h ;;
-	start)
-		git bisect--helper --bisect-start "$@" ;;
-	bad|good|new|old|"$TERM_BAD"|"$TERM_GOOD")
-		git bisect--helper "$cmd" "$@" ;;
-	skip)
-		git bisect--helper --bisect-skip "$@" || exit;;
-	next)
-		# Not sure we want "next" at the UI level anymore.
-		git bisect--helper --bisect-next "$@" || exit ;;
-	visualize|view)
-		git bisect--helper --bisect-visualize "$@" || exit;;
-	reset)
-		git bisect--helper --bisect-reset "$@" ;;
-	replay)
-		git bisect--helper --bisect-replay "$@" || exit;;
-	log)
-		git bisect--helper --bisect-log || exit ;;
-	run)
-		git bisect--helper --bisect-run "$@" || exit;;
-	terms)
-		git bisect--helper --bisect-terms "$@" || exit;;
-	*)
-		usage ;;
-	esac
-esac
+exec git bisect--helper "$@"
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH v2 12/14] Turn `git bisect` into a full built-in
  2022-02-22 16:30 ` [PATCH v2 00/14] " Johannes Schindelin via GitGitGadget
                     ` (10 preceding siblings ...)
  2022-02-22 16:30   ` [PATCH v2 11/14] bisect: move even the option parsing to `bisect--helper` Johannes Schindelin via GitGitGadget
@ 2022-02-22 16:30   ` Johannes Schindelin via GitGitGadget
  2022-02-22 16:30   ` [PATCH v2 13/14] bisect: remove Cogito-related code Johannes Schindelin via GitGitGadget
                     ` (4 subsequent siblings)
  16 siblings, 0 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-02-22 16:30 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Johannes Schindelin, Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

Now that the shell script hands off to the `bisect--helper` to do
_anything_ (except to show the help), it is but a tiny step to let the
helper implement the actual `git bisect` command instead.

This retires `git-bisect.sh`, concluding a multi-year journey that many
hands helped with, in particular Pranit Bauna, Tanushree Tumane and
Miriam Rubio.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 Makefile                               |  3 +--
 builtin.h                              |  2 +-
 builtin/{bisect--helper.c => bisect.c} |  8 +++---
 git-bisect.sh                          | 37 --------------------------
 git.c                                  |  2 +-
 5 files changed, 7 insertions(+), 45 deletions(-)
 rename builtin/{bisect--helper.c => bisect.c} (99%)
 delete mode 100755 git-bisect.sh

diff --git a/Makefile b/Makefile
index 5580859afdb..ce2eabeca58 100644
--- a/Makefile
+++ b/Makefile
@@ -595,7 +595,6 @@ THIRD_PARTY_SOURCES =
 # interactive shell sessions without exporting it.
 unexport CDPATH
 
-SCRIPT_SH += git-bisect.sh
 SCRIPT_SH += git-difftool--helper.sh
 SCRIPT_SH += git-filter-branch.sh
 SCRIPT_SH += git-merge-octopus.sh
@@ -1064,7 +1063,7 @@ BUILTIN_OBJS += builtin/am.o
 BUILTIN_OBJS += builtin/annotate.o
 BUILTIN_OBJS += builtin/apply.o
 BUILTIN_OBJS += builtin/archive.o
-BUILTIN_OBJS += builtin/bisect--helper.o
+BUILTIN_OBJS += builtin/bisect.o
 BUILTIN_OBJS += builtin/blame.o
 BUILTIN_OBJS += builtin/branch.o
 BUILTIN_OBJS += builtin/bugreport.o
diff --git a/builtin.h b/builtin.h
index 8a58743ed63..b5567ea3a9d 100644
--- a/builtin.h
+++ b/builtin.h
@@ -116,7 +116,7 @@ int cmd_am(int argc, const char **argv, const char *prefix);
 int cmd_annotate(int argc, const char **argv, const char *prefix);
 int cmd_apply(int argc, const char **argv, const char *prefix);
 int cmd_archive(int argc, const char **argv, const char *prefix);
-int cmd_bisect__helper(int argc, const char **argv, const char *prefix);
+int cmd_bisect(int argc, const char **argv, const char *prefix);
 int cmd_blame(int argc, const char **argv, const char *prefix);
 int cmd_branch(int argc, const char **argv, const char *prefix);
 int cmd_bugreport(int argc, const char **argv, const char *prefix);
diff --git a/builtin/bisect--helper.c b/builtin/bisect.c
similarity index 99%
rename from builtin/bisect--helper.c
rename to builtin/bisect.c
index ef0b06d594b..1493d7d1d96 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect.c
@@ -20,7 +20,7 @@ static GIT_PATH_FUNC(git_path_bisect_names, "BISECT_NAMES")
 static GIT_PATH_FUNC(git_path_bisect_first_parent, "BISECT_FIRST_PARENT")
 static GIT_PATH_FUNC(git_path_bisect_run, "BISECT_RUN")
 
-static const char * const git_bisect_usage[] = {
+static const char * const builtin_bisect_usage[] = {
 	N_("git bisect help\n"
 	   "\tprint this long help message."),
 	N_("git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>]\n"
@@ -1182,7 +1182,7 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
 	}
 }
 
-int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
+int cmd_bisect(int argc, const char **argv, const char *prefix)
 {
 	int res = 0;
 	struct option options[] = {
@@ -1192,7 +1192,7 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 	const char *command = argc > 1 ? argv[1] : "help";
 
 	if (!strcmp("-h", command) || !strcmp("help", command))
-		usage_with_options(git_bisect_usage, options);
+		usage_with_options(builtin_bisect_usage, options);
 
 	argc -= 2;
 	argv += 2;
@@ -1239,7 +1239,7 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 		get_terms(&terms);
 		if (check_and_set_terms(&terms, command)) {
 			char *msg = xstrfmt(_("unknown command: '%s'"), command);
-			usage_msg_opt(msg, git_bisect_usage, options);
+			usage_msg_opt(msg, builtin_bisect_usage, options);
 		}
 		/* shift the `command` back in */
 		argc++;
diff --git a/git-bisect.sh b/git-bisect.sh
deleted file mode 100755
index 028d39cd9ce..00000000000
--- a/git-bisect.sh
+++ /dev/null
@@ -1,37 +0,0 @@
-#!/bin/sh
-
-USAGE='[help|start|bad|good|new|old|terms|skip|next|reset|visualize|view|replay|log|run]'
-LONG_USAGE='git bisect help
-	print this long help message.
-git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>]
-		 [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<pathspec>...]
-	reset bisect state and start bisection.
-git bisect (bad|new) [<rev>]
-	mark <rev> a known-bad revision/
-		a revision after change in a given property.
-git bisect (good|old) [<rev>...]
-	mark <rev>... known-good revisions/
-		revisions before change in a given property.
-git bisect terms [--term-good | --term-bad]
-	show the terms used for old and new commits (default: bad, good)
-git bisect skip [(<rev>|<range>)...]
-	mark <rev>... untestable revisions.
-git bisect next
-	find next bisection to test and check it out.
-git bisect reset [<commit>]
-	finish bisection search and go back to commit.
-git bisect (visualize|view)
-	show bisect status in gitk.
-git bisect replay <logfile>
-	replay bisection log.
-git bisect log
-	show bisect log.
-git bisect run <cmd>...
-	use <cmd>... to automatically bisect.
-
-Please use "git help bisect" to get the full man page.'
-
-OPTIONS_SPEC=
-. git-sh-setup
-
-exec git bisect--helper "$@"
diff --git a/git.c b/git.c
index edda922ce6d..a8500132a28 100644
--- a/git.c
+++ b/git.c
@@ -490,7 +490,7 @@ static struct cmd_struct commands[] = {
 	{ "annotate", cmd_annotate, RUN_SETUP | NO_PARSEOPT },
 	{ "apply", cmd_apply, RUN_SETUP_GENTLY },
 	{ "archive", cmd_archive, RUN_SETUP_GENTLY },
-	{ "bisect--helper", cmd_bisect__helper, RUN_SETUP },
+	{ "bisect", cmd_bisect, RUN_SETUP },
 	{ "blame", cmd_blame, RUN_SETUP },
 	{ "branch", cmd_branch, RUN_SETUP | DELAY_PAGER_CONFIG },
 	{ "bugreport", cmd_bugreport, RUN_SETUP_GENTLY },
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH v2 13/14] bisect: remove Cogito-related code
  2022-02-22 16:30 ` [PATCH v2 00/14] " Johannes Schindelin via GitGitGadget
                     ` (11 preceding siblings ...)
  2022-02-22 16:30   ` [PATCH v2 12/14] Turn `git bisect` into a full built-in Johannes Schindelin via GitGitGadget
@ 2022-02-22 16:30   ` Johannes Schindelin via GitGitGadget
  2022-02-22 16:30   ` [PATCH v2 14/14] bisect: no longer try to clean up left-over `.git/head-name` files Johannes Schindelin via GitGitGadget
                     ` (3 subsequent siblings)
  16 siblings, 0 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-02-22 16:30 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Johannes Schindelin, Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

Once upon a time, there was this idea that Git would not actually be a
single coherent program, but rather a set of low-level programs that
users cobble together via shell scripts, or develop high-level user
interfaces for Git, or both.

Cogito was such a high-level user interface, incidentally implemented
via shell scripts that cobble together Git calls.

It did turn out relatively quickly that Git would much rather provide a
useful high-level user interface itself.

As of April 19th, 2007, Cogito was therefore discontinued (see
https://lore.kernel.org/git/20070419124648.GL4489@pasky.or.cz/).

Nevertheless, for almost 15 years after that announcement, Git carried
special code in `git bisect` to accommodate Cogito.

Since it is beyond doubt that there are no more Cogito users, let's
remove the last remnant of Cogito-accommodating code.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/bisect.c | 8 --------
 1 file changed, 8 deletions(-)

diff --git a/builtin/bisect.c b/builtin/bisect.c
index 1493d7d1d96..e8a346fa516 100644
--- a/builtin/bisect.c
+++ b/builtin/bisect.c
@@ -15,7 +15,6 @@ static GIT_PATH_FUNC(git_path_bisect_expected_rev, "BISECT_EXPECTED_REV")
 static GIT_PATH_FUNC(git_path_bisect_ancestors_ok, "BISECT_ANCESTORS_OK")
 static GIT_PATH_FUNC(git_path_bisect_start, "BISECT_START")
 static GIT_PATH_FUNC(git_path_bisect_log, "BISECT_LOG")
-static GIT_PATH_FUNC(git_path_head_name, "head-name")
 static GIT_PATH_FUNC(git_path_bisect_names, "BISECT_NAMES")
 static GIT_PATH_FUNC(git_path_bisect_first_parent, "BISECT_FIRST_PARENT")
 static GIT_PATH_FUNC(git_path_bisect_run, "BISECT_RUN")
@@ -756,13 +755,6 @@ static enum bisect_error bisect_start(struct bisect_terms *terms, const char **a
 			strbuf_addstr(&start_head, oid_to_hex(&head_oid));
 		} else if (!get_oid(head, &head_oid) &&
 			   skip_prefix(head, "refs/heads/", &head)) {
-			/*
-			 * This error message should only be triggered by
-			 * cogito usage, and cogito users should understand
-			 * it relates to cg-seek.
-			 */
-			if (!is_empty_or_missing_file(git_path_head_name()))
-				return error(_("won't bisect on cg-seek'ed tree"));
 			strbuf_addstr(&start_head, head);
 		} else {
 			return error(_("bad HEAD - strange symbolic ref"));
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH v2 14/14] bisect: no longer try to clean up left-over `.git/head-name` files
  2022-02-22 16:30 ` [PATCH v2 00/14] " Johannes Schindelin via GitGitGadget
                     ` (12 preceding siblings ...)
  2022-02-22 16:30   ` [PATCH v2 13/14] bisect: remove Cogito-related code Johannes Schindelin via GitGitGadget
@ 2022-02-22 16:30   ` Johannes Schindelin via GitGitGadget
  2022-02-23  1:41   ` [PATCH v2 00/14] Finish converting git bisect into a built-in Elijah Newren
                     ` (2 subsequent siblings)
  16 siblings, 0 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-02-22 16:30 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Johannes Schindelin, Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

As per the code comment, the `.git/head-name` files were cleaned up for
backwards-compatibility: an old version of `git bisect` could have left
them behind.

Now, just how old would such a version be? As of 0f497e75f05 (Eliminate
confusing "won't bisect on seeked tree" failure, 2008-02-23), `git
bisect` does not write that file anymore. Which corresponds to Git
v1.5.4.4.

Even if the likelihood is non-nil that there might still be users out
there who use such an old version to start a bisection, but then decide
to continue bisecting with a current Git version, it is highly
improbable.

So let's remove that code, at long last.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 bisect.c                    | 3 ---
 t/t6030-bisect-porcelain.sh | 1 -
 2 files changed, 4 deletions(-)

diff --git a/bisect.c b/bisect.c
index 888949fba6b..ebd4287c01c 100644
--- a/bisect.c
+++ b/bisect.c
@@ -474,7 +474,6 @@ static GIT_PATH_FUNC(git_path_bisect_start, "BISECT_START")
 static GIT_PATH_FUNC(git_path_bisect_log, "BISECT_LOG")
 static GIT_PATH_FUNC(git_path_bisect_terms, "BISECT_TERMS")
 static GIT_PATH_FUNC(git_path_bisect_first_parent, "BISECT_FIRST_PARENT")
-static GIT_PATH_FUNC(git_path_head_name, "head-name")
 
 static void read_bisect_paths(struct strvec *array)
 {
@@ -1172,8 +1171,6 @@ int bisect_clean_state(void)
 	unlink_or_warn(git_path_bisect_run());
 	unlink_or_warn(git_path_bisect_terms());
 	unlink_or_warn(git_path_bisect_first_parent());
-	/* Cleanup head-name if it got left by an old version of git-bisect */
-	unlink_or_warn(git_path_head_name());
 	/*
 	 * Cleanup BISECT_START last to support the --no-checkout option
 	 * introduced in the commit 4796e823a.
diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh
index 720442de2eb..4f17205c238 100755
--- a/t/t6030-bisect-porcelain.sh
+++ b/t/t6030-bisect-porcelain.sh
@@ -945,7 +945,6 @@ test_expect_success 'git bisect reset cleans bisection state properly' '
 	test_path_is_missing ".git/BISECT_LOG" &&
 	test_path_is_missing ".git/BISECT_RUN" &&
 	test_path_is_missing ".git/BISECT_TERMS" &&
-	test_path_is_missing ".git/head-name" &&
 	test_path_is_missing ".git/BISECT_HEAD" &&
 	test_path_is_missing ".git/BISECT_START"
 '
-- 
gitgitgadget

^ permalink raw reply related	[flat|nested] 147+ messages in thread

* Re: [PATCH v2 00/14] Finish converting git bisect into a built-in
  2022-02-22 16:30 ` [PATCH v2 00/14] " Johannes Schindelin via GitGitGadget
                     ` (13 preceding siblings ...)
  2022-02-22 16:30   ` [PATCH v2 14/14] bisect: no longer try to clean up left-over `.git/head-name` files Johannes Schindelin via GitGitGadget
@ 2022-02-23  1:41   ` Elijah Newren
  2022-02-25 15:59     ` Johannes Schindelin
  2022-02-23 21:35   ` Junio C Hamano
  2022-05-21 14:48   ` [PATCH v3 00/15] " Johannes Schindelin via GitGitGadget
  16 siblings, 1 reply; 147+ messages in thread
From: Elijah Newren @ 2022-02-23  1:41 UTC (permalink / raw)
  To: Johannes Schindelin via GitGitGadget
  Cc: Git Mailing List, Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Johannes Schindelin

On Tue, Feb 22, 2022 at 8:30 AM Johannes Schindelin via GitGitGadget
<gitgitgadget@gmail.com> wrote:
>
> After three GSoC/Outreachy students spent an incredible effort on this, it
> is finally time to put a neat little bow on it.
>
> Changes since v1:
>
>  * Added a regression test to "bisect run: fix the error message".
>  * Added a patch to address an error message that double-single-quoted the
>    command.
>  * Reworked the logic in "bisect--helper: make --bisect-state optional" to
>    delay showing the usage upon an unknown command, which should make the
>    code a lot less confusing.
>  * Split out the change that moved the BISECT_STATE case to the end of the
>    switch block.
>  * Added a patch that replaces the return error() calls in
>    cmd_bisect_helper() with die() calls, to avoid returning -1 as an exit
>    code.
>  * Dropped the use of parse_options() for the single purpose of handling -h;
>    This is now done explicitly.
>  * Simplified the diff of "bisect: move even the option parsing to
>    bisect--helper" by modifying argc and argv instead of modifying all the
>    function calls using those variables.
>  * In the "Turn git bisect into a full built-in" patch, changed the name of
>    the variable holding the usage to use the builtin_ prefix used in other
>    built-ins, too.
>  * Removed the trailing dot from the commit message of "Turn git bisect into
>    a full built-in".
>
> Johannes Schindelin (14):
>   bisect run: fix the error message
>   bisect: avoid double-quoting when printing the failed command
>   bisect--helper: retire the --no-log option
>   bisect--helper: really retire --bisect-next-check
>   bisect--helper: really retire `--bisect-autostart`
>   bisect--helper: using `--bisect-state` without an argument is a bug
>   bisect--helper: align the sub-command order with git-bisect.sh
>   bisect--helper: make `--bisect-state` optional
>   bisect--helper: move the `BISECT_STATE` case to the end
>   bisect--helper: return only correct exit codes in `cmd_*()`
>   bisect: move even the option parsing to `bisect--helper`
>   Turn `git bisect` into a full built-in
>   bisect: remove Cogito-related code
>   bisect: no longer try to clean up left-over `.git/head-name` files
>
>  Makefile                               |   3 +-
>  bisect.c                               |   3 -
>  builtin.h                              |   2 +-
>  builtin/{bisect--helper.c => bisect.c} | 189 ++++++++++---------------
>  git-bisect.sh                          |  84 -----------
>  git.c                                  |   2 +-
>  t/t6030-bisect-porcelain.sh            |  11 +-
>  7 files changed, 88 insertions(+), 206 deletions(-)
>  rename builtin/{bisect--helper.c => bisect.c} (88%)
>  delete mode 100755 git-bisect.sh
>
>
> base-commit: 89bece5c8c96f0b962cfc89e63f82d603fd60bed
> Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-1132%2Fdscho%2Fbisect-in-c-v2
> Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1132/dscho/bisect-in-c-v2
> Pull-Request: https://github.com/gitgitgadget/git/pull/1132
>
> Range-diff vs v1:
>
>   1:  93d19d85ee3 !  1:  81ca0d68cde bisect run: fix the error message
>      @@ Commit message
>           was "good" or "bad", but used a bogus (because non-populated) `args`
>           variable for it.
>
>      +    Helped-by: Elijah Newren <newren@gmail.com>
>           Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
>
>        ## builtin/bisect--helper.c ##
>      @@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, cons
>                 strvec_clear(&run_args);
>                 return res;
>         }
>      +
>      + ## t/t6030-bisect-porcelain.sh ##
>      +@@ t/t6030-bisect-porcelain.sh: test_expect_success 'bisect visualize with a filename with dash and space' '
>      +  git bisect visualize -p -- "-hello 2"
>      + '
>      +
>      ++test_expect_success 'testing' '
>      ++ git bisect reset &&
>      ++ git bisect start $HASH4 $HASH1 &&
>      ++ write_script test_script.sh <<-\EOF &&
>      ++ rm .git/BISECT*
>      ++ EOF
>      ++ test_must_fail git bisect run ./test_script.sh 2>error &&
>      ++ grep "git bisect good.*exited with error code" error
>      ++'
>      ++
>      + test_done
>   -:  ----------- >  2:  4320101f2e0 bisect: avoid double-quoting when printing the failed command
>   2:  8e0e5559980 =  3:  88d7173c86b bisect--helper: retire the --no-log option
>   3:  996a7099bf8 =  4:  b914fe64dda bisect--helper: really retire --bisect-next-check
>   4:  3de4c48b66d =  5:  0d3db63bda6 bisect--helper: really retire `--bisect-autostart`
>   8:  1b14ed3d797 =  6:  a345cf3e0e4 bisect--helper: using `--bisect-state` without an argument is a bug
>   5:  6afc6e0eece =  7:  0487701220b bisect--helper: align the sub-command order with git-bisect.sh
>   6:  eddbdde222a !  8:  d8b2767c148 bisect--helper: make `--bisect-state` optional
>      @@ Commit message
>           `git bisect--helper bad`, i.e. do not require the `--bisect-state`
>           option to be passed explicitly.
>
>      -    To prepare for converting `bisect--helper` to a full built-in
>      -    implementation of `git bisect` (which must not require the
>      -    `--bisect-state` option to be specified at all), let's move the handling
>      -    toward the end of the `switch (cmdmode)` block.
>      -
>           Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
>
>        ## builtin/bisect--helper.c ##
>      @@ builtin/bisect--helper.c: int cmd_bisect__helper(int argc, const char **argv, co
>                              git_bisect_helper_usage,
>                              PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN);
>
>      -+ if (!cmdmode && argc > 0) {
>      -+         set_terms(&terms, "bad", "good");
>      -+         get_terms(&terms);
>      -+         if (!check_and_set_terms(&terms, argv[0]))
>      -+                 cmdmode = BISECT_STATE;
>      -+ }
>      -+
>      -  if (!cmdmode)
>      -          usage_with_options(git_bisect_helper_usage, options);
>      -
>      -@@ builtin/bisect--helper.c: int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
>      +- if (!cmdmode)
>      +-         usage_with_options(git_bisect_helper_usage, options);
>      +-
>      +- switch (cmdmode) {
>      ++ switch (cmdmode ? cmdmode : BISECT_STATE) {
>      +  case BISECT_START:
>                 set_terms(&terms, "bad", "good");
>                 res = bisect_start(&terms, argv, argc);
>      -          break;
>      -- case BISECT_STATE:
>      --         set_terms(&terms, "bad", "good");
>      --         get_terms(&terms);
>      --         res = bisect_state(&terms, argv, argc);
>      --         break;
>      -  case BISECT_TERMS:
>      -          if (argc > 1)
>      -                  return error(_("--bisect-terms requires 0 or 1 argument"));
>       @@ builtin/bisect--helper.c: int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
>      +  case BISECT_STATE:
>      +          set_terms(&terms, "bad", "good");
>                 get_terms(&terms);
>      -          res = bisect_run(&terms, argv, argc);
>      -          break;
>      -+ case BISECT_STATE:
>      -+         if (!terms.term_good) {
>      -+                 set_terms(&terms, "bad", "good");
>      -+                 get_terms(&terms);
>      ++         if (!cmdmode &&
>      ++             (!argc || check_and_set_terms(&terms, argv[0]))) {
>      ++                 char *msg = xstrfmt(_("unknown command: '%s'"), argv[0]);
>      ++                 usage_msg_opt(msg, git_bisect_helper_usage, options);
>       +         }
>      -+         res = bisect_state(&terms, argv, argc);
>      -+         break;
>      -  default:
>      -          BUG("unknown subcommand %d", cmdmode);
>      -  }
>      +          res = bisect_state(&terms, argv, argc);
>      +          break;
>      +  case BISECT_TERMS:
>      +
>      + ## git-bisect.sh ##
>      +@@ git-bisect.sh: case "$#" in
>      +  start)
>      +          git bisect--helper --bisect-start "$@" ;;
>      +  bad|good|new|old|"$TERM_BAD"|"$TERM_GOOD")
>      +-         git bisect--helper --bisect-state "$cmd" "$@" ;;
>      ++         git bisect--helper "$cmd" "$@" ;;
>      +  skip)
>      +          git bisect--helper --bisect-skip "$@" || exit;;
>      +  next)
>   -:  ----------- >  9:  e8904db81c5 bisect--helper: move the `BISECT_STATE` case to the end
>   -:  ----------- > 10:  208f8fa4851 bisect--helper: return only correct exit codes in `cmd_*()`
>   7:  515e86e2075 ! 11:  dc04b06206b bisect: move even the option parsing to `bisect--helper`
>      @@ Commit message
>           together. So it would appear as if a lot of work would have to be done
>           just to be able to use `parse_options()` just to parse the sub-command,
>           instead of a simple `if...else if` chain, the latter being a
>      -    dramatically simpler implementation. Therefore, we now keep the
>      -    `parse_options()` call primarily to support `-h` and little else.
>      +    dramatically simpler implementation.
>
>           Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
>
>      @@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, cons
>       - argc = parse_options(argc, argv, prefix, options,
>       -                      git_bisect_helper_usage,
>       -                      PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN);
>      -+ /* Handle -h and invalid options */
>      -+ parse_options(argc - 1, argv + 1, prefix, options,
>      -+               git_bisect_usage,
>      -+               PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN |
>      -+               PARSE_OPT_ONE_SHOT | PARSE_OPT_STOP_AT_NON_OPTION);
>      -
>      -- if (!cmdmode && argc > 0) {
>      -+ if (!strcmp("help", command))
>      ++ if (!strcmp("-h", command) || !strcmp("help", command))
>       +         usage_with_options(git_bisect_usage, options);
>      -+ else if (!strcmp("start", command)) {
>      -          set_terms(&terms, "bad", "good");
>      --         get_terms(&terms);
>      --         if (!check_and_set_terms(&terms, argv[0]))
>      --                 cmdmode = BISECT_STATE;
>      -- }
>      --
>      -- if (!cmdmode)
>      --         usage_with_options(git_bisect_helper_usage, options);
>      --
>      -- switch (cmdmode) {
>      +
>      +- switch (cmdmode ? cmdmode : BISECT_STATE) {
>       - case BISECT_START:
>      --         set_terms(&terms, "bad", "good");
>      --         res = bisect_start(&terms, argv, argc);
>      ++ argc -= 2;
>      ++ argv += 2;
>      ++
>      ++ if (!strcmp("start", command)) {
>      +          set_terms(&terms, "bad", "good");
>      +          res = bisect_start(&terms, argv, argc);
>       -         break;
>       - case BISECT_TERMS:
>      --         if (argc > 1)
>      --                 return error(_("--bisect-terms requires 0 or 1 argument"));
>      --         res = bisect_terms(&terms, argc == 1 ? argv[0] : NULL);
>      ++ } else if (!strcmp("terms", command)) {
>      +          if (argc > 1)
>      +-                 die(_("--bisect-terms requires 0 or 1 argument"));
>      ++                 die(_("'terms' requires 0 or 1 argument"));
>      +          res = bisect_terms(&terms, argc == 1 ? argv[0] : NULL);
>       -         break;
>       - case BISECT_SKIP:
>      -+         res = bisect_start(&terms, argv + 2, argc - 2);
>      -+ } else if (!strcmp("terms", command)) {
>      -+         if (argc > 3)
>      -+                 return error(_("'terms' requires 0 or 1 argument"));
>      -+         res = bisect_terms(&terms, argc == 3 ? argv[2] : NULL);
>       + } else if (!strcmp("skip", command)) {
>                 set_terms(&terms, "bad", "good");
>                 get_terms(&terms);
>      --         res = bisect_skip(&terms, argv, argc);
>      +          res = bisect_skip(&terms, argv, argc);
>       -         break;
>       - case BISECT_NEXT:
>      --         if (argc)
>      --                 return error(_("--bisect-next requires 0 arguments"));
>      -+         res = bisect_skip(&terms, argv + 2, argc - 2);
>       + } else if (!strcmp("next", command)) {
>      -+         if (argc != 2)
>      -+                 return error(_("'next' requires 0 arguments"));
>      +          if (argc)
>      +-                 die(_("--bisect-next requires 0 arguments"));
>      ++                 die(_("'next' requires 0 arguments"));
>                 get_terms(&terms);
>                 res = bisect_next(&terms, prefix);
>       -         break;
>       - case BISECT_RESET:
>      --         if (argc > 1)
>      --                 return error(_("--bisect-reset requires either no argument or a commit"));
>      --         res = bisect_reset(argc ? argv[0] : NULL);
>      ++ } else if (!strcmp("reset", command)) {
>      +          if (argc > 1)
>      +-                 die(_("--bisect-reset requires either no argument or a commit"));
>      ++                 die(_("'reset' requires either no argument or a commit"));
>      +          res = bisect_reset(argc ? argv[0] : NULL);
>       -         break;
>       - case BISECT_VISUALIZE:
>      -+ } else if (!strcmp("reset", command)) {
>      -+         if (argc > 3)
>      -+                 return error(_("'reset' requires either no argument or a commit"));
>      -+         res = bisect_reset(argc > 2 ? argv[2] : NULL);
>       + } else if (one_of(command, "visualize", "view", NULL)) {
>                 get_terms(&terms);
>      --         res = bisect_visualize(&terms, argv, argc);
>      +          res = bisect_visualize(&terms, argv, argc);
>       -         break;
>       - case BISECT_REPLAY:
>      --         if (argc != 1)
>      -+         res = bisect_visualize(&terms, argv + 2, argc - 2);
>       + } else if (!strcmp("replay", command)) {
>      -+         if (argc != 3)
>      -                  return error(_("no logfile given"));
>      +          if (argc != 1)
>      +                  die(_("no logfile given"));
>                 set_terms(&terms, "bad", "good");
>      --         res = bisect_replay(&terms, argv[0]);
>      +          res = bisect_replay(&terms, argv[0]);
>       -         break;
>       - case BISECT_LOG:
>      --         if (argc)
>      --                 return error(_("--bisect-log requires 0 arguments"));
>      -+         res = bisect_replay(&terms, argv[2]);
>       + } else if (!strcmp("log", command)) {
>      -+         if (argc > 2)
>      -+                 return error(_("'log' requires 0 arguments"));
>      +          if (argc)
>      +-                 die(_("--bisect-log requires 0 arguments"));
>      ++                 die(_("'log' requires 0 arguments"));
>                 res = bisect_log();
>       -         break;
>       - case BISECT_RUN:
>      --         if (!argc)
>       + } else if (!strcmp("run", command)) {
>      -+         if (argc < 3)
>      -                  return error(_("bisect run failed: no command provided."));
>      +          if (!argc)
>      +                  die(_("bisect run failed: no command provided."));
>                 get_terms(&terms);
>      --         res = bisect_run(&terms, argv, argc);
>      +          res = bisect_run(&terms, argv, argc);
>       -         break;
>       - case BISECT_STATE:
>      --         if (!terms.term_good) {
>      --                 set_terms(&terms, "bad", "good");
>      --                 get_terms(&terms);
>      -+         res = bisect_run(&terms, argv + 2, argc - 2);
>       + } else {
>      -+         set_terms(&terms, "bad", "good");
>      -+         get_terms(&terms);
>      -+         if (!check_and_set_terms(&terms, command))
>      -+                 res = bisect_state(&terms, argv + 1, argc - 1);
>      -+         else {
>      +          set_terms(&terms, "bad", "good");
>      +          get_terms(&terms);
>      +-         if (!cmdmode &&
>      +-             (!argc || check_and_set_terms(&terms, argv[0]))) {
>      +-                 char *msg = xstrfmt(_("unknown command: '%s'"), argv[0]);
>      +-                 usage_msg_opt(msg, git_bisect_helper_usage, options);
>      ++         if (check_and_set_terms(&terms, command)) {
>       +                 char *msg = xstrfmt(_("unknown command: '%s'"), command);
>       +                 usage_msg_opt(msg, git_bisect_usage, options);
>                 }
>      --         res = bisect_state(&terms, argv, argc);
>      ++         /* shift the `command` back in */
>      ++         argc++;
>      ++         argv--;
>      +          res = bisect_state(&terms, argv, argc);
>       -         break;
>       - default:
>       -         BUG("unknown subcommand %d", cmdmode);
>      @@ git-bisect.sh: Please use "git help bisect" to get the full man page.'
>       - start)
>       -         git bisect--helper --bisect-start "$@" ;;
>       - bad|good|new|old|"$TERM_BAD"|"$TERM_GOOD")
>      --         git bisect--helper --bisect-state "$cmd" "$@" ;;
>      +-         git bisect--helper "$cmd" "$@" ;;
>       - skip)
>       -         git bisect--helper --bisect-skip "$@" || exit;;
>       - next)
>   9:  1c0bd8a326f ! 12:  7db4b03b668 Turn `git bisect` into a full built-in.
>      @@ Metadata
>       Author: Johannes Schindelin <Johannes.Schindelin@gmx.de>
>
>        ## Commit message ##
>      -    Turn `git bisect` into a full built-in.
>      +    Turn `git bisect` into a full built-in
>
>           Now that the shell script hands off to the `bisect--helper` to do
>           _anything_ (except to show the help), it is but a tiny step to let the
>      @@ builtin.h: int cmd_am(int argc, const char **argv, const char *prefix);
>        int cmd_bugreport(int argc, const char **argv, const char *prefix);
>
>        ## builtin/bisect--helper.c => builtin/bisect.c ##
>      +@@ builtin/bisect.c: static GIT_PATH_FUNC(git_path_bisect_names, "BISECT_NAMES")
>      + static GIT_PATH_FUNC(git_path_bisect_first_parent, "BISECT_FIRST_PARENT")
>      + static GIT_PATH_FUNC(git_path_bisect_run, "BISECT_RUN")
>      +
>      +-static const char * const git_bisect_usage[] = {
>      ++static const char * const builtin_bisect_usage[] = {
>      +  N_("git bisect help\n"
>      +     "\tprint this long help message."),
>      +  N_("git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>]\n"
>       @@ builtin/bisect.c: static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
>         }
>        }
>      @@ builtin/bisect.c: static int bisect_run(struct bisect_terms *terms, const char *
>        {
>         int res = 0;
>         struct option options[] = {
>      +@@ builtin/bisect.c: int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
>      +  const char *command = argc > 1 ? argv[1] : "help";
>      +
>      +  if (!strcmp("-h", command) || !strcmp("help", command))
>      +-         usage_with_options(git_bisect_usage, options);
>      ++         usage_with_options(builtin_bisect_usage, options);
>      +
>      +  argc -= 2;
>      +  argv += 2;
>      +@@ builtin/bisect.c: int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
>      +          get_terms(&terms);
>      +          if (check_and_set_terms(&terms, command)) {
>      +                  char *msg = xstrfmt(_("unknown command: '%s'"), command);
>      +-                 usage_msg_opt(msg, git_bisect_usage, options);
>      ++                 usage_msg_opt(msg, builtin_bisect_usage, options);
>      +          }
>      +          /* shift the `command` back in */
>      +          argc++;
>
>        ## git-bisect.sh (deleted) ##
>       @@
>  10:  cce533486db = 13:  0611d16f772 bisect: remove Cogito-related code
>  11:  dc77297c676 = 14:  e2fa11a819e bisect: no longer try to clean up left-over `.git/head-name` files
>
> --
> gitgitgadget

You've addressed all my feedback from v1, and I've looked over the
changes and they look good to me:

Reviewed-by: Elijah Newren <newren@gmail.com>

^ permalink raw reply	[flat|nested] 147+ messages in thread

* Re: [PATCH v2 11/14] bisect: move even the option parsing to `bisect--helper`
  2022-02-22 16:30   ` [PATCH v2 11/14] bisect: move even the option parsing to `bisect--helper` Johannes Schindelin via GitGitGadget
@ 2022-02-23  9:47     ` Ævar Arnfjörð Bjarmason
  2022-02-25 15:59       ` Johannes Schindelin
  0 siblings, 1 reply; 147+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-02-23  9:47 UTC (permalink / raw)
  To: Johannes Schindelin via GitGitGadget
  Cc: git, Pranit Bauva, Tanushree Tumane, Miriam Rubio, Elijah Newren,
	Johannes Schindelin


On Tue, Feb 22 2022, Johannes Schindelin via GitGitGadget wrote:

> From: Johannes Schindelin <johannes.schindelin@gmx.de>
>
> On our journey to a fully built-in `git bisect`, this is the
> second-to-last step.
>
> Side note: The `if (!strcmp(...)) ... else if (!strcmp(...)) ... else if
> (!strcmp(...)) ...` chain seen in this patch was not actually the first
> idea how to convert the command modes to sub-commands. Since the
> `bisect--helper` command already used the `parse-opions` API with neatly
> set-up command modes, naturally the idea was to use `PARSE_OPT_NODASH`
> to support proper sub-commands instead. However, the `parse-options` API
> is not set up for that, and even after making that option work with long
> options, it turned out that `STOP_AT_NON_OPTION` and `KEEP_UNKNOWN`
> would have to be used but these options were not designed to work
> together. So it would appear as if a lot of work would have to be done
> just to be able to use `parse_options()` just to parse the sub-command,
> instead of a simple `if...else if` chain, the latter being a
> dramatically simpler implementation.

As I noted in
https://lore.kernel.org/git/220129.86pmobauyt.gmgdl@evledraar.gmail.com/:

> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> ---
>  builtin/bisect--helper.c | 133 ++++++++++++++++-----------------------
>  git-bisect.sh            |  49 +--------------
>  2 files changed, 56 insertions(+), 126 deletions(-)
>
> diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
> index 5228964937d..ef0b06d594b 100644
> --- a/builtin/bisect--helper.c
> +++ b/builtin/bisect--helper.c
> @@ -20,18 +20,34 @@ static GIT_PATH_FUNC(git_path_bisect_names, "BISECT_NAMES")
>  static GIT_PATH_FUNC(git_path_bisect_first_parent, "BISECT_FIRST_PARENT")
>  static GIT_PATH_FUNC(git_path_bisect_run, "BISECT_RUN")
>  
> -static const char * const git_bisect_helper_usage[] = {
> -	N_("git bisect--helper --bisect-reset [<commit>]"),
> -	N_("git bisect--helper --bisect-terms [--term-good | --term-old | --term-bad | --term-new]"),
> -	N_("git bisect--helper --bisect-start [--term-{new,bad}=<term> --term-{old,good}=<term>]"
> -					    " [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<paths>...]"),
> -	N_("git bisect--helper --bisect-next"),
> -	N_("git bisect--helper [--bisect-state] (bad|new) [<rev>]"),
> -	N_("git bisect--helper [--bisect-state] (good|old) [<rev>...]"),
> -	N_("git bisect--helper --bisect-replay <filename>"),
> -	N_("git bisect--helper --bisect-skip [(<rev>|<range>)...]"),
> -	N_("git bisect--helper --bisect-visualize"),
> -	N_("git bisect--helper --bisect-run <cmd>..."),
> +static const char * const git_bisect_usage[] = {
> +	N_("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."),
>  	NULL
>  };

Even that doesn't explain why this needs to be changed as
well. I.e. this could just be:
	
	diff --git a/builtin/bisect.c b/builtin/bisect.c
	index e8a346fa516..d27b80ddaf3 100644
	--- a/builtin/bisect.c
	+++ b/builtin/bisect.c
	@@ -20,33 +20,18 @@ static GIT_PATH_FUNC(git_path_bisect_first_parent, "BISECT_FIRST_PARENT")
	 static GIT_PATH_FUNC(git_path_bisect_run, "BISECT_RUN")
	 
	 static const char * const builtin_bisect_usage[] = {
	-	N_("git bisect help\n"
	-	   "\tprint this long help message."),
	+	N_("git bisect reset [<commit>]"),
	+	N_("git bisect terms [--term-good | --term-old | --term-bad | --term-new]"),
	 	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."),
	+	   "                 [--no-checkout] [--first-parent] [<bad> [<good>...]]\n"
	+	   "                 [--] [<paths>...]"),
	+	N_("git bisect next"),
	+	N_("git bisect state (bad|new) [<rev>]"),
	+	N_("git bisect state (good|old) [<rev>...]"),
	+	N_("git bisect replay <filename>"),
	+	N_("git bisect skip [(<rev>|<range>)...]"),
	+	N_("git bisect visualize"),
	+	N_("git bisect run <cmd>..."),
	 	NULL
	 };

Which turns the help output into:
    
    $ ./git bisect -h
    usage: git bisect reset [<commit>]
       or: git bisect terms [--term-good | --term-old | --term-bad | --term-new]
       or: git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>]
                            [--no-checkout] [--first-parent] [<bad> [<good>...]]
                            [--] [<paths>...]
       or: git bisect next
       or: git bisect state (bad|new) [<rev>]
       or: git bisect state (good|old) [<rev>...]
       or: git bisect replay <filename>
       or: git bisect skip [(<rev>|<range>)...]
       or: git bisect visualize
       or: git bisect run <cmd>...

Instead of:
    
    $ ./git bisect -h
    usage: git bisect help
            print this long help message.
       or: git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>]
                     [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<pathspec>...]
            reset bisect state and start bisection.
       or: git bisect (bad|new) [<rev>]
            mark <rev> a known-bad revision/
                    a revision after change in a given property.
       or: git bisect (good|old) [<rev>...]
            mark <rev>... known-good revisions/
                    revisions before change in a given property.
       or: git bisect terms [--term-good | --term-bad]
            show the terms used for old and new commits (default: bad, good)
       or: git bisect skip [(<rev>|<range>)...]
            mark <rev>... untestable revisions.
       or: git bisect next
            find next bisection to test and check it out.
       or: git bisect reset [<commit>]
            finish bisection search and go back to commit.
       or: git bisect (visualize|view)
            show bisect status in gitk.
       or: git bisect replay <logfile>
            replay bisection log.
       or: git bisect log
            show bisect log.
       or: git bisect run <cmd>...
            use <cmd>... to automatically bisect.

I.e. parse_options() != the usage_with_options() formatting function in
parse-options.c. You can use one without using the other. The commit
message only claims (wrongly I think, but let's leave that aside for the
moment) that we can't use parse_options(), but doesn't say why we *also*
need to move to doing our own formatting of the usage output, those are
two different things.

As I noted in the previous round I think you were trying to retain the
OPT_CMDMODE help messages. We could use the "" parse_options() usage
feature to emit output similar to "git bisect--helper -h", but I think
just having it by the same as current built-ins is fine.

I.e. for "stash" etc. we're not emitting human readable help
explanations along with every subcommand, and could just do the same for
"git bisect".

But on to parse_options() usage:

> @@ -1168,108 +1184,69 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
>  
>  int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
>  {
> -	enum {
> -		BISECT_START = 1,
> -		BISECT_STATE,
> -		BISECT_TERMS,
> -		BISECT_SKIP,
> -		BISECT_NEXT,
> -		BISECT_RESET,
> -		BISECT_VISUALIZE,
> -		BISECT_REPLAY,
> -		BISECT_LOG,
> -		BISECT_RUN,
> -	} cmdmode = 0;
>  	int res = 0;
>  	struct option options[] = {
> -		OPT_CMDMODE(0, "bisect-start", &cmdmode,
> -			 N_("start the bisect session"), BISECT_START),
> -		OPT_CMDMODE(0, "bisect-state", &cmdmode,
> -			 N_("mark the state of ref (or refs)"), BISECT_STATE),
> -		OPT_CMDMODE(0, "bisect-terms", &cmdmode,
> -			 N_("print out the bisect terms"), BISECT_TERMS),
> -		OPT_CMDMODE(0, "bisect-skip", &cmdmode,
> -			 N_("skip some commits for checkout"), BISECT_SKIP),
> -		OPT_CMDMODE(0, "bisect-next", &cmdmode,
> -			 N_("find the next bisection commit"), BISECT_NEXT),
> -		OPT_CMDMODE(0, "bisect-reset", &cmdmode,
> -			 N_("reset the bisection state"), BISECT_RESET),
> -		OPT_CMDMODE(0, "bisect-visualize", &cmdmode,
> -			 N_("visualize the bisection"), BISECT_VISUALIZE),
> -		OPT_CMDMODE(0, "bisect-replay", &cmdmode,
> -			 N_("replay the bisection process from the given file"), BISECT_REPLAY),
> -		OPT_CMDMODE(0, "bisect-log", &cmdmode,
> -			 N_("list the bisection steps so far"), BISECT_LOG),
> -		OPT_CMDMODE(0, "bisect-run", &cmdmode,
> -			 N_("use <cmd>... to automatically bisect."), BISECT_RUN),
>  		OPT_END()
>  	};
>  	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
> +	const char *command = argc > 1 ? argv[1] : "help";
>  
> -	argc = parse_options(argc, argv, prefix, options,
> -			     git_bisect_helper_usage,
> -			     PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN);

Because of thinking that we need to get rid of parse_options() here
we...

> +	if (!strcmp("-h", command) || !strcmp("help", command))
> +		usage_with_options(git_bisect_usage, options);

...end up duplicating some of its behavior here...

>  
> -	switch (cmdmode ? cmdmode : BISECT_STATE) {
> -	case BISECT_START:
> +	argc -= 2;
> +	argv += 2;
> +
> +	if (!strcmp("start", command)) {
>  		set_terms(&terms, "bad", "good");
>  		res = bisect_start(&terms, argv, argc);
> -		break;
> -	case BISECT_TERMS:
> +	} else if (!strcmp("terms", command)) {
>  		if (argc > 1)
> -			die(_("--bisect-terms requires 0 or 1 argument"));
> +			die(_("'terms' requires 0 or 1 argument"));
>  		res = bisect_terms(&terms, argc == 1 ? argv[0] : NULL);
> -		break;
> -	case BISECT_SKIP:
> +	} else if (!strcmp("skip", command)) {
>  		set_terms(&terms, "bad", "good");
>  		get_terms(&terms);
>  		res = bisect_skip(&terms, argv, argc);
> -		break;
> -	case BISECT_NEXT:
> +	} else if (!strcmp("next", command)) {
>  		if (argc)
> -			die(_("--bisect-next requires 0 arguments"));
> +			die(_("'next' requires 0 arguments"));
>  		get_terms(&terms);
>  		res = bisect_next(&terms, prefix);
> -		break;
> -	case BISECT_RESET:
> +	} else if (!strcmp("reset", command)) {
>  		if (argc > 1)
> -			die(_("--bisect-reset requires either no argument or a commit"));
> +			die(_("'reset' requires either no argument or a commit"));
>  		res = bisect_reset(argc ? argv[0] : NULL);
> -		break;
> -	case BISECT_VISUALIZE:
> +	} else if (one_of(command, "visualize", "view", NULL)) {
>  		get_terms(&terms);
>  		res = bisect_visualize(&terms, argv, argc);
> -		break;
> -	case BISECT_REPLAY:
> +	} else if (!strcmp("replay", command)) {
>  		if (argc != 1)
>  			die(_("no logfile given"));
>  		set_terms(&terms, "bad", "good");
>  		res = bisect_replay(&terms, argv[0]);
> -		break;
> -	case BISECT_LOG:
> +	} else if (!strcmp("log", command)) {
>  		if (argc)
> -			die(_("--bisect-log requires 0 arguments"));
> +			die(_("'log' requires 0 arguments"));
>  		res = bisect_log();
> -		break;
> -	case BISECT_RUN:
> +	} else if (!strcmp("run", command)) {
>  		if (!argc)
>  			die(_("bisect run failed: no command provided."));
>  		get_terms(&terms);
>  		res = bisect_run(&terms, argv, argc);
> -		break;
> -	case BISECT_STATE:
> +	} else {
>  		set_terms(&terms, "bad", "good");
>  		get_terms(&terms);
> -		if (!cmdmode &&
> -		    (!argc || check_and_set_terms(&terms, argv[0]))) {
> -			char *msg = xstrfmt(_("unknown command: '%s'"), argv[0]);
> -			usage_msg_opt(msg, git_bisect_helper_usage, options);
> +		if (check_and_set_terms(&terms, command)) {
> +			char *msg = xstrfmt(_("unknown command: '%s'"), command);
> +			usage_msg_opt(msg, git_bisect_usage, options);

[Change this usage_msg_opt() to a usage_msg_optf() and drop the
xstrfmt()]

>  		}
> +		/* shift the `command` back in */
> +		argc++;
> +		argv--;
>  		res = bisect_state(&terms, argv, argc);
> -		break;
> -	default:
> -		BUG("unknown subcommand %d", cmdmode);
>  	}

..and introducing bugs here, e.g. "git bisect --blah" is now a valid way
to start a bisect", we no longer understand "git bisect <subcommand>
-h", but did before etc.

Is the reason for further extending the custom command parser here
because of e.g. the "die(..requires N arguments"? For all of those this
could follow the pattern that builtin/commit-graph.c etc. use.

I.e. just define a usage for say "log", and empty options, then pass
argc/argv to that subcommand, and have it call parse_options().

Then not only will the user get an error, they'll get the subset of "git
bisect -h" output appropriate for whatever "git bisect subcommand <bad
usage>" they invoked.

^ permalink raw reply	[flat|nested] 147+ messages in thread

* Re: [PATCH v2 00/14] Finish converting git bisect into a built-in
  2022-02-22 16:30 ` [PATCH v2 00/14] " Johannes Schindelin via GitGitGadget
                     ` (14 preceding siblings ...)
  2022-02-23  1:41   ` [PATCH v2 00/14] Finish converting git bisect into a built-in Elijah Newren
@ 2022-02-23 21:35   ` Junio C Hamano
  2022-02-25 16:03     ` Johannes Schindelin
  2022-05-21 14:48   ` [PATCH v3 00/15] " Johannes Schindelin via GitGitGadget
  16 siblings, 1 reply; 147+ messages in thread
From: Junio C Hamano @ 2022-02-23 21:35 UTC (permalink / raw)
  To: Johannes Schindelin via GitGitGadget
  Cc: git, Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Johannes Schindelin

"Johannes Schindelin via GitGitGadget" <gitgitgadget@gmail.com>
writes:

> After three GSoC/Outreachy students spent an incredible effort on this, it
> is finally time to put a neat little bow on it.

Thanks for tying the loose ends.  I've read the previous one and
also this round, and except for the parse-options bit I am not sure
about (read: I do not have a strong objection, but I do have to
wonder if there is a better way to achieve the goal), everything
else looks good.

Will queue.


^ permalink raw reply	[flat|nested] 147+ messages in thread

* Re: [PATCH v2 11/14] bisect: move even the option parsing to `bisect--helper`
  2022-02-23  9:47     ` Ævar Arnfjörð Bjarmason
@ 2022-02-25 15:59       ` Johannes Schindelin
  2022-02-25 16:49         ` Ævar Arnfjörð Bjarmason
  0 siblings, 1 reply; 147+ messages in thread
From: Johannes Schindelin @ 2022-02-25 15:59 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: Johannes Schindelin via GitGitGadget, git, Pranit Bauva,
	Tanushree Tumane, Miriam Rubio, Elijah Newren

[-- Attachment #1: Type: text/plain, Size: 6765 bytes --]

Hi Ævar,

On Wed, 23 Feb 2022, Ævar Arnfjörð Bjarmason wrote:

> On Tue, Feb 22 2022, Johannes Schindelin via GitGitGadget wrote:
>
> > From: Johannes Schindelin <johannes.schindelin@gmx.de>
> >
> > On our journey to a fully built-in `git bisect`, this is the
> > second-to-last step.
> >
> > Side note: The `if (!strcmp(...)) ... else if (!strcmp(...)) ... else if
> > (!strcmp(...)) ...` chain seen in this patch was not actually the first
> > idea how to convert the command modes to sub-commands. Since the
> > `bisect--helper` command already used the `parse-opions` API with neatly
> > set-up command modes, naturally the idea was to use `PARSE_OPT_NODASH`
> > to support proper sub-commands instead. However, the `parse-options` API
> > is not set up for that, and even after making that option work with long
> > options, it turned out that `STOP_AT_NON_OPTION` and `KEEP_UNKNOWN`
> > would have to be used but these options were not designed to work
> > together. So it would appear as if a lot of work would have to be done
> > just to be able to use `parse_options()` just to parse the sub-command,
> > instead of a simple `if...else if` chain, the latter being a
> > dramatically simpler implementation.
>
> As I noted in
> https://lore.kernel.org/git/220129.86pmobauyt.gmgdl@evledraar.gmail.com/:
>
> > Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> > ---
> >  builtin/bisect--helper.c | 133 ++++++++++++++++-----------------------
> >  git-bisect.sh            |  49 +--------------
> >  2 files changed, 56 insertions(+), 126 deletions(-)
> >
> > diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
> > index 5228964937d..ef0b06d594b 100644
> > --- a/builtin/bisect--helper.c
> > +++ b/builtin/bisect--helper.c
> > @@ -20,18 +20,34 @@ static GIT_PATH_FUNC(git_path_bisect_names, "BISECT_NAMES")
> >  static GIT_PATH_FUNC(git_path_bisect_first_parent, "BISECT_FIRST_PARENT")
> >  static GIT_PATH_FUNC(git_path_bisect_run, "BISECT_RUN")
> >
> > -static const char * const git_bisect_helper_usage[] = {
> > -	N_("git bisect--helper --bisect-reset [<commit>]"),
> > -	N_("git bisect--helper --bisect-terms [--term-good | --term-old | --term-bad | --term-new]"),
> > -	N_("git bisect--helper --bisect-start [--term-{new,bad}=<term> --term-{old,good}=<term>]"
> > -					    " [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<paths>...]"),
> > -	N_("git bisect--helper --bisect-next"),
> > -	N_("git bisect--helper [--bisect-state] (bad|new) [<rev>]"),
> > -	N_("git bisect--helper [--bisect-state] (good|old) [<rev>...]"),
> > -	N_("git bisect--helper --bisect-replay <filename>"),
> > -	N_("git bisect--helper --bisect-skip [(<rev>|<range>)...]"),
> > -	N_("git bisect--helper --bisect-visualize"),
> > -	N_("git bisect--helper --bisect-run <cmd>..."),
> > +static const char * const git_bisect_usage[] = {
> > +	N_("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."),
> >  	NULL
> >  };
>
> Even that doesn't explain why this needs to be changed as
> well.

True. The explanation is easy: I am not in the business of changing the
usage shown by `git bisect -h`.

> we no longer understand "git bisect <subcommand> -h", but did before
> etc.

... for some definition of "understand" ;-) See for yourself:

	$ git bisect visualize -h
	usage: git bisect--helper --bisect-reset [<commit>]
	   or: git bisect--helper --bisect-terms [--term-good | --term-old | --term-bad | --term-new]
	   or: git bisect--helper --bisect-start [--term-{new,bad}=<term> --term-{old,good}=<term>] [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<paths>...]
	   or: git bisect--helper --bisect-next
	   or: git bisect--helper --bisect-state (bad|new) [<rev>]
	   or: git bisect--helper --bisect-state (good|old) [<rev>...]
	   or: git bisect--helper --bisect-replay <filename>
	   or: git bisect--helper --bisect-skip [(<rev>|<range>)...]
	   or: git bisect--helper --bisect-visualize
	   or: git bisect--helper --bisect-run <cmd>...

	    --bisect-reset        reset the bisection state
	    --bisect-next-check   check whether bad or good terms exist
	    --bisect-terms        print out the bisect terms
	    --bisect-start        start the bisect session
	    --bisect-next         find the next bisection commit
	    --bisect-state        mark the state of ref (or refs)
	    --bisect-log          list the bisection steps so far
	    --bisect-replay       replay the bisection process from the given file
	    --bisect-skip         skip some commits for checkout
	    --bisect-visualize    visualize the bisection
	    --bisect-run          use <cmd>... to automatically bisect.
	    --no-log              no log for BISECT_WRITE

That's not a helpful usage for `git bisect visualize`. It's better to
leave it to a future patch for `bisect_visualize()` to handle `-h`.

In other words, what you point out as a bug is actually fixing one.

I find the other comments on not using the `parse_options()` machinery
similar, and your feedback seems to flatly dismiss the side note in the
commit message as irrelevant.

To be clear: I spent a substantial amount of time trying to extend the
`parse_options()` machinery to support dash-less subcommands. The end
result was neither elegant nor particularly useful.

So, with all due respect, I disagree with your disagreeing.

Ciao,
Johannes

^ permalink raw reply	[flat|nested] 147+ messages in thread

* Re: [PATCH v2 00/14] Finish converting git bisect into a built-in
  2022-02-23  1:41   ` [PATCH v2 00/14] Finish converting git bisect into a built-in Elijah Newren
@ 2022-02-25 15:59     ` Johannes Schindelin
  0 siblings, 0 replies; 147+ messages in thread
From: Johannes Schindelin @ 2022-02-25 15:59 UTC (permalink / raw)
  To: Elijah Newren
  Cc: Johannes Schindelin via GitGitGadget, Git Mailing List,
	Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason

Hi Elijah,

On Tue, 22 Feb 2022, Elijah Newren wrote:

> You've addressed all my feedback from v1, and I've looked over the
> changes and they look good to me:
>
> Reviewed-by: Elijah Newren <newren@gmail.com>

Thank you for helping me improve the patch series!
Dscho

^ permalink raw reply	[flat|nested] 147+ messages in thread

* Re: [PATCH v2 00/14] Finish converting git bisect into a built-in
  2022-02-23 21:35   ` Junio C Hamano
@ 2022-02-25 16:03     ` Johannes Schindelin
  2022-02-25 16:44       ` Ævar Arnfjörð Bjarmason
  0 siblings, 1 reply; 147+ messages in thread
From: Johannes Schindelin @ 2022-02-25 16:03 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Johannes Schindelin via GitGitGadget, git, Pranit Bauva,
	Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren

Hi Junio,

On Wed, 23 Feb 2022, Junio C Hamano wrote:

> [...] the parse-options bit I am not sure about (read: I do not have a
> strong objection, but I do have to wonder if there is a better way to
> achieve the goal) [...]

After spending a lot of time to try to make it work, I realized that it's
in the name of `parse_options()` that it's not a `handle_subcommand()`
API.

So yes, I agree there is probably a better way (and e.g. `git bundle`
and `scalar` would benefit from it, too): designing a proper API for
handling subcommands.

That's safely outside the scope of the patch series, of course.

> Will queue.

Thanks,
Dscho

^ permalink raw reply	[flat|nested] 147+ messages in thread

* Re: [PATCH v2 00/14] Finish converting git bisect into a built-in
  2022-02-25 16:03     ` Johannes Schindelin
@ 2022-02-25 16:44       ` Ævar Arnfjörð Bjarmason
  0 siblings, 0 replies; 147+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-02-25 16:44 UTC (permalink / raw)
  To: Johannes Schindelin
  Cc: Junio C Hamano, Johannes Schindelin via GitGitGadget, git,
	Pranit Bauva, Tanushree Tumane, Miriam Rubio, Elijah Newren,
	SZEDER Gábor


On Fri, Feb 25 2022, Johannes Schindelin wrote:

> Hi Junio,
>
> On Wed, 23 Feb 2022, Junio C Hamano wrote:
>
>> [...] the parse-options bit I am not sure about (read: I do not have a
>> strong objection, but I do have to wonder if there is a better way to
>> achieve the goal) [...]
>
> After spending a lot of time to try to make it work, I realized that it's
> in the name of `parse_options()` that it's not a `handle_subcommand()`
> API.
>
> So yes, I agree there is probably a better way (and e.g. `git bundle`
> and `scalar` would benefit from it, too): designing a proper API for
> handling subcommands.
>
> That's safely outside the scope of the patch series, of course.

I think SZEDER has some out-of-tree patches to do that, for what it's
worth.

But it's not emit_usage_info() either (at least not directly), and we
also use it for that.

So this seems like a distraction from the feedback I provided on your
patch.

Which for one is that due to bugs in the conversion things that emitted
usage errors before are now silently accepted.

And that whatever we do to make things *easier* for
bundle/stash/commit-graph etc. when it comes to this, doesn't explain
why you feel the need to introduce yet another pattern of doing this,
when the existing "handle subcommands" built-ins do it rather uniformly,
and AFAICT there's nothing in the "git bisect" case that's special
enough that it wouldn't be served by pretty much copying that template.

^ permalink raw reply	[flat|nested] 147+ messages in thread

* Re: [PATCH v2 11/14] bisect: move even the option parsing to `bisect--helper`
  2022-02-25 15:59       ` Johannes Schindelin
@ 2022-02-25 16:49         ` Ævar Arnfjörð Bjarmason
  0 siblings, 0 replies; 147+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-02-25 16:49 UTC (permalink / raw)
  To: Johannes Schindelin
  Cc: Johannes Schindelin via GitGitGadget, git, Pranit Bauva,
	Tanushree Tumane, Miriam Rubio, Elijah Newren


On Fri, Feb 25 2022, Johannes Schindelin wrote:

> Hi Ævar,
>
> On Wed, 23 Feb 2022, Ævar Arnfjörð Bjarmason wrote:
>
>> On Tue, Feb 22 2022, Johannes Schindelin via GitGitGadget wrote:
>>
>> > From: Johannes Schindelin <johannes.schindelin@gmx.de>
>> >
>> > On our journey to a fully built-in `git bisect`, this is the
>> > second-to-last step.
>> >
>> > Side note: The `if (!strcmp(...)) ... else if (!strcmp(...)) ... else if
>> > (!strcmp(...)) ...` chain seen in this patch was not actually the first
>> > idea how to convert the command modes to sub-commands. Since the
>> > `bisect--helper` command already used the `parse-opions` API with neatly
>> > set-up command modes, naturally the idea was to use `PARSE_OPT_NODASH`
>> > to support proper sub-commands instead. However, the `parse-options` API
>> > is not set up for that, and even after making that option work with long
>> > options, it turned out that `STOP_AT_NON_OPTION` and `KEEP_UNKNOWN`
>> > would have to be used but these options were not designed to work
>> > together. So it would appear as if a lot of work would have to be done
>> > just to be able to use `parse_options()` just to parse the sub-command,
>> > instead of a simple `if...else if` chain, the latter being a
>> > dramatically simpler implementation.
>>
>> As I noted in
>> https://lore.kernel.org/git/220129.86pmobauyt.gmgdl@evledraar.gmail.com/:
>>
>> > Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
>> > ---
>> >  builtin/bisect--helper.c | 133 ++++++++++++++++-----------------------
>> >  git-bisect.sh            |  49 +--------------
>> >  2 files changed, 56 insertions(+), 126 deletions(-)
>> >
>> > diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
>> > index 5228964937d..ef0b06d594b 100644
>> > --- a/builtin/bisect--helper.c
>> > +++ b/builtin/bisect--helper.c
>> > @@ -20,18 +20,34 @@ static GIT_PATH_FUNC(git_path_bisect_names, "BISECT_NAMES")
>> >  static GIT_PATH_FUNC(git_path_bisect_first_parent, "BISECT_FIRST_PARENT")
>> >  static GIT_PATH_FUNC(git_path_bisect_run, "BISECT_RUN")
>> >
>> > -static const char * const git_bisect_helper_usage[] = {
>> > -	N_("git bisect--helper --bisect-reset [<commit>]"),
>> > -	N_("git bisect--helper --bisect-terms [--term-good | --term-old | --term-bad | --term-new]"),
>> > -	N_("git bisect--helper --bisect-start [--term-{new,bad}=<term> --term-{old,good}=<term>]"
>> > -					    " [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<paths>...]"),
>> > -	N_("git bisect--helper --bisect-next"),
>> > -	N_("git bisect--helper [--bisect-state] (bad|new) [<rev>]"),
>> > -	N_("git bisect--helper [--bisect-state] (good|old) [<rev>...]"),
>> > -	N_("git bisect--helper --bisect-replay <filename>"),
>> > -	N_("git bisect--helper --bisect-skip [(<rev>|<range>)...]"),
>> > -	N_("git bisect--helper --bisect-visualize"),
>> > -	N_("git bisect--helper --bisect-run <cmd>..."),
>> > +static const char * const git_bisect_usage[] = {
>> > +	N_("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."),
>> >  	NULL
>> >  };
>>
>> Even that doesn't explain why this needs to be changed as
>> well.
>
> True. The explanation is easy: I am not in the business of changing the
> usage shown by `git bisect -h`.

You are changing it, here's the diff between "master" and "seen":
	
	--- b	2022-02-25 17:49:07.264273673 +0100
	+++ a	2022-02-25 17:48:46.076460197 +0100
	@@ -1,31 +1,28 @@
	-usage: git bisect [help|start|bad|good|new|old|terms|skip|next|reset|visualize|view|replay|log|run]
	+usage: git bisect help
	+       	print this long help message.
	+   or: git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>]
	+       		 [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<pathspec>...]
	+       	reset bisect state and start bisection.
	+   or: git bisect (bad|new) [<rev>]
	+       	mark <rev> a known-bad revision/
	+       		a revision after change in a given property.
	+   or: git bisect (good|old) [<rev>...]
	+       	mark <rev>... known-good revisions/
	+       		revisions before change in a given property.
	+   or: git bisect terms [--term-good | --term-bad]
	+       	show the terms used for old and new commits (default: bad, good)
	+   or: git bisect skip [(<rev>|<range>)...]
	+       	mark <rev>... untestable revisions.
	+   or: git bisect next
	+       	find next bisection to test and check it out.
	+   or: git bisect reset [<commit>]
	+       	finish bisection search and go back to commit.
	+   or: git bisect (visualize|view)
	+       	show bisect status in gitk.
	+   or: git bisect replay <logfile>
	+       	replay bisection log.
	+   or: git bisect log
	+       	show bisect log.
	+   or: git bisect run <cmd>...
	+       	use <cmd>... to automatically bisect.
	 
	-git bisect help
	-	print this long help message.
	-git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>]
	-		 [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<pathspec>...]
	-	reset bisect state and start bisection.
	-git bisect (bad|new) [<rev>]
	-	mark <rev> a known-bad revision/
	-		a revision after change in a given property.
	-git bisect (good|old) [<rev>...]
	-	mark <rev>... known-good revisions/
	-		revisions before change in a given property.
	-git bisect terms [--term-good | --term-bad]
	-	show the terms used for old and new commits (default: bad, good)
	-git bisect skip [(<rev>|<range>)...]
	-	mark <rev>... untestable revisions.
	-git bisect next
	-	find next bisection to test and check it out.
	-git bisect reset [<commit>]
	-	finish bisection search and go back to commit.
	-git bisect (visualize|view)
	-	show bisect status in gitk.
	-git bisect replay <logfile>
	-	replay bisection log.
	-git bisect log
	-	show bisect log.
	-git bisect run <cmd>...
	-	use <cmd>... to automatically bisect.
	-
	-Please use "git help bisect" to get the full man page.

I think such changes are fine, but if you don't then actually
parse_options() would make that easier to emit with the "" delimiter,
i.e. to mark up the rest as free-form text, as it is now.

But I don't see why you'd view that as a goal, for the rest of built-in
migrations we've changed this human-readable output in various ways
while we were at it.

>> we no longer understand "git bisect <subcommand> -h", but did before
>> etc.
>
> ... for some definition of "understand" ;-) See for yourself:
>
> 	$ git bisect visualize -h
> 	usage: git bisect--helper --bisect-reset [<commit>]
> 	   or: git bisect--helper --bisect-terms [--term-good | --term-old | --term-bad | --term-new]
> 	   or: git bisect--helper --bisect-start [--term-{new,bad}=<term> --term-{old,good}=<term>] [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<paths>...]
> 	   or: git bisect--helper --bisect-next
> 	   or: git bisect--helper --bisect-state (bad|new) [<rev>]
> 	   or: git bisect--helper --bisect-state (good|old) [<rev>...]
> 	   or: git bisect--helper --bisect-replay <filename>
> 	   or: git bisect--helper --bisect-skip [(<rev>|<range>)...]
> 	   or: git bisect--helper --bisect-visualize
> 	   or: git bisect--helper --bisect-run <cmd>...
>
> 	    --bisect-reset        reset the bisection state
> 	    --bisect-next-check   check whether bad or good terms exist
> 	    --bisect-terms        print out the bisect terms
> 	    --bisect-start        start the bisect session
> 	    --bisect-next         find the next bisection commit
> 	    --bisect-state        mark the state of ref (or refs)
> 	    --bisect-log          list the bisection steps so far
> 	    --bisect-replay       replay the bisection process from the given file
> 	    --bisect-skip         skip some commits for checkout
> 	    --bisect-visualize    visualize the bisection
> 	    --bisect-run          use <cmd>... to automatically bisect.
> 	    --no-log              no log for BISECT_WRITE
>
> That's not a helpful usage for `git bisect visualize`. It's better to
> leave it to a future patch for `bisect_visualize()` to handle `-h`.

Yes, it could be better, but with your changes:

    git bisect start -h

Or whatever will start a bisection session.

> In other words, what you point out as a bug is actually fixing one.

...

> I find the other comments on not using the `parse_options()` machinery
> similar, and your feedback seems to flatly dismiss the side note in the
> commit message as irrelevant.
>
> To be clear: I spent a substantial amount of time trying to extend the
> `parse_options()` machinery to support dash-less subcommands. The end
> result was neither elegant nor particularly useful.
>
> So, with all due respect, I disagree with your disagreeing.

Yes I agree that trying to get parse_option() to consider --bisect-reset
implicitly as "reset" is a dead-end.

What I'm pointing out is that we could do it exactly as bisect/stash
etc. do it. I don't see how you ended up concluding that your conversion
needed to do anything different, and failing that that you couldn't use
parse_options() at all. Just use it like those other commands use it.

^ permalink raw reply	[flat|nested] 147+ messages in thread

* [PATCH v3 00/15] Finish converting git bisect into a built-in
  2022-02-22 16:30 ` [PATCH v2 00/14] " Johannes Schindelin via GitGitGadget
                     ` (15 preceding siblings ...)
  2022-02-23 21:35   ` Junio C Hamano
@ 2022-05-21 14:48   ` Johannes Schindelin via GitGitGadget
  2022-05-21 14:48     ` [PATCH v3 01/15] bisect run: fix the error message Johannes Schindelin via GitGitGadget
                       ` (16 more replies)
  16 siblings, 17 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-05-21 14:48 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Johannes Schindelin

After three GSoC/Outreachy students spent an incredible effort on this, it
is finally time to put a neat little bow on it.

Changes since v2:

 * We're now careful to provide identical usage strings upon git bisect -h
   and git bisect bogus.
 * When a bogus command is provided, we now error out instead of trying to
   start a git bisect run.
 * Rebased onto main to avoid plenty of merge conflicts with
   rs/bisect-executable-not-found, ac/usage-string-fixups and with
   cd/bisect-messages-from-pre-flight-states.

Changes since v1:

 * Added a regression test to "bisect run: fix the error message".
 * Added a patch to address an error message that double-single-quoted the
   command.
 * Reworked the logic in "bisect--helper: make --bisect-state optional" to
   delay showing the usage upon an unknown command, which should make the
   code a lot less confusing.
 * Split out the change that moved the BISECT_STATE case to the end of the
   switch block.
 * Added a patch that replaces the return error() calls in
   cmd_bisect_helper() with die() calls, to avoid returning -1 as an exit
   code.
 * Dropped the use of parse_options() for the single purpose of handling -h;
   This is now done explicitly.
 * Simplified the diff of "bisect: move even the option parsing to
   bisect--helper" by modifying argc and argv instead of modifying all the
   function calls using those variables.
 * In the "Turn git bisect into a full built-in" patch, changed the name of
   the variable holding the usage to use the builtin_ prefix used in other
   built-ins, too.
 * Removed the trailing dot from the commit message of "Turn git bisect into
   a full built-in".

Johannes Schindelin (15):
  bisect run: fix the error message
  bisect: avoid double-quoting when printing the failed command
  bisect--helper: retire the --no-log option
  bisect--helper: really retire --bisect-next-check
  bisect--helper: really retire `--bisect-autostart`
  bisect--helper: using `--bisect-state` without an argument is a bug
  bisect--helper: align the sub-command order with git-bisect.sh
  bisect--helper: make `--bisect-state` optional
  bisect--helper: move the `BISECT_STATE` case to the end
  bisect--helper: return only correct exit codes in `cmd_*()`
  bisect: move even the command-line parsing to `bisect--helper`
  bisect: teach the `bisect--helper` command to show the correct usage
    strings
  Turn `git bisect` into a full built-in
  bisect: remove Cogito-related code
  bisect: no longer try to clean up left-over `.git/head-name` files

 Makefile                               |   3 +-
 bisect.c                               |   3 -
 builtin.h                              |   2 +-
 builtin/{bisect--helper.c => bisect.c} | 202 +++++++++++--------------
 git-bisect.sh                          |  84 ----------
 git.c                                  |   2 +-
 t/t6030-bisect-porcelain.sh            |  11 +-
 7 files changed, 100 insertions(+), 207 deletions(-)
 rename builtin/{bisect--helper.c => bisect.c} (89%)
 delete mode 100755 git-bisect.sh


base-commit: f9b95943b68b6b8ca5a6072f50a08411c6449b55
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-1132%2Fdscho%2Fbisect-in-c-v3
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1132/dscho/bisect-in-c-v3
Pull-Request: https://github.com/gitgitgadget/git/pull/1132

Range-diff vs v2:

  1:  81ca0d68cde !  1:  cf6034625dd bisect run: fix the error message
     @@ Commit message
          Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
      
       ## builtin/bisect--helper.c ##
     -@@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
     - {
     - 	int res = BISECT_OK;
     - 	struct strbuf command = STRBUF_INIT;
     --	struct strvec args = STRVEC_INIT;
     - 	struct strvec run_args = STRVEC_INIT;
     - 	const char *new_state;
     - 	int temporary_stdout_fd, saved_stdout;
     -@@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
     - 	strvec_push(&run_args, command.buf);
     - 
     - 	while (1) {
     --		strvec_clear(&args);
     --
     - 		printf(_("running %s\n"), command.buf);
     - 		res = run_command_v_opt(run_args.v, RUN_USING_SHELL);
     - 
      @@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
       			printf(_("bisect found first bad commit"));
       			res = BISECT_OK;
       		} else if (res) {
      -			error(_("bisect run failed: 'git bisect--helper --bisect-state"
     --			" %s' exited with error code %d"), args.v[0], res);
      +			error(_("bisect run failed: 'git bisect"
     -+			" %s' exited with error code %d"), new_state, res);
     + 			" %s' exited with error code %d"), new_state, res);
       		} else {
       			continue;
     - 		}
     - 
     - 		strbuf_release(&command);
     --		strvec_clear(&args);
     - 		strvec_clear(&run_args);
     - 		return res;
     - 	}
      
       ## t/t6030-bisect-porcelain.sh ##
     -@@ t/t6030-bisect-porcelain.sh: test_expect_success 'bisect visualize with a filename with dash and space' '
     - 	git bisect visualize -p -- "-hello 2"
     +@@ t/t6030-bisect-porcelain.sh: test_expect_success 'bisect state output with bad commit' '
     + 	grep -F "waiting for good commit(s), bad commit known" output
       '
       
     -+test_expect_success 'testing' '
     ++test_expect_success 'verify correct error message' '
      +	git bisect reset &&
      +	git bisect start $HASH4 $HASH1 &&
      +	write_script test_script.sh <<-\EOF &&
  2:  4320101f2e0 !  2:  955ccd4d8c8 bisect: avoid double-quoting when printing the failed command
     @@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, cons
       			error(_("bisect run failed: exit code %d from"
      -				" '%s' is < 0 or >= 128"), res, command.buf);
      +				" %s is < 0 or >= 128"), res, command.buf);
     - 			strbuf_release(&command);
     - 			return res;
     + 			break;
       		}
     + 
  3:  88d7173c86b !  3:  abcbc25966c bisect--helper: retire the --no-log option
     @@ builtin/bisect--helper.c: int cmd_bisect__helper(int argc, const char **argv, co
      @@ builtin/bisect--helper.c: int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
       			 N_("visualize the bisection"), BISECT_VISUALIZE),
       		OPT_CMDMODE(0, "bisect-run", &cmdmode,
     - 			 N_("use <cmd>... to automatically bisect."), BISECT_RUN),
     + 			 N_("use <cmd>... to automatically bisect"), BISECT_RUN),
      -		OPT_BOOL(0, "no-log", &nolog,
      -			 N_("no log for BISECT_WRITE")),
       		OPT_END()
  4:  b914fe64dda =  4:  af60ef1b5a4 bisect--helper: really retire --bisect-next-check
  5:  0d3db63bda6 =  5:  07a92c58f8e bisect--helper: really retire `--bisect-autostart`
  6:  a345cf3e0e4 =  6:  04ba0950b85 bisect--helper: using `--bisect-state` without an argument is a bug
  7:  0487701220b !  7:  6847af9d485 bisect--helper: align the sub-command order with git-bisect.sh
     @@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, cons
      +		OPT_CMDMODE(0, "bisect-log", &cmdmode,
      +			 N_("list the bisection steps so far"), BISECT_LOG),
       		OPT_CMDMODE(0, "bisect-run", &cmdmode,
     - 			 N_("use <cmd>... to automatically bisect."), BISECT_RUN),
     + 			 N_("use <cmd>... to automatically bisect"), BISECT_RUN),
       		OPT_END()
      @@ builtin/bisect--helper.c: int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
       		usage_with_options(git_bisect_helper_usage, options);
  8:  d8b2767c148 !  8:  b7bc53b9cb6 bisect--helper: make `--bisect-state` optional
     @@ builtin/bisect--helper.c
      @@ builtin/bisect--helper.c: static const char * const git_bisect_helper_usage[] = {
       	N_("git bisect--helper --bisect-start [--term-{new,bad}=<term> --term-{old,good}=<term>]"
       					    " [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<paths>...]"),
     - 	N_("git bisect--helper --bisect-next"),
     + 	"git bisect--helper --bisect-next",
      -	N_("git bisect--helper --bisect-state (bad|new) [<rev>]"),
      -	N_("git bisect--helper --bisect-state (good|old) [<rev>...]"),
      +	N_("git bisect--helper [--bisect-state] (bad|new) [<rev>]"),
      +	N_("git bisect--helper [--bisect-state] (good|old) [<rev>...]"),
       	N_("git bisect--helper --bisect-replay <filename>"),
       	N_("git bisect--helper --bisect-skip [(<rev>|<range>)...]"),
     - 	N_("git bisect--helper --bisect-visualize"),
     + 	"git bisect--helper --bisect-visualize",
      @@ builtin/bisect--helper.c: int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
       			     git_bisect_helper_usage,
       			     PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN);
  9:  e8904db81c5 =  9:  1919237a819 bisect--helper: move the `BISECT_STATE` case to the end
 10:  208f8fa4851 = 10:  1236a731903 bisect--helper: return only correct exit codes in `cmd_*()`
 11:  dc04b06206b ! 11:  4ae78d37d04 bisect: move even the option parsing to `bisect--helper`
     @@ Metadata
      Author: Johannes Schindelin <Johannes.Schindelin@gmx.de>
      
       ## Commit message ##
     -    bisect: move even the option parsing to `bisect--helper`
     +    bisect: move even the command-line parsing to `bisect--helper`
      
          On our journey to a fully built-in `git bisect`, this is the
     -    second-to-last step.
     +    one of the last steps.
      
     -    Side note: The `if (!strcmp(...)) ... else if (!strcmp(...)) ... else if
     -    (!strcmp(...)) ...` chain seen in this patch was not actually the first
     -    idea how to convert the command modes to sub-commands. Since the
     -    `bisect--helper` command already used the `parse-opions` API with neatly
     -    set-up command modes, naturally the idea was to use `PARSE_OPT_NODASH`
     -    to support proper sub-commands instead. However, the `parse-options` API
     -    is not set up for that, and even after making that option work with long
     -    options, it turned out that `STOP_AT_NON_OPTION` and `KEEP_UNKNOWN`
     -    would have to be used but these options were not designed to work
     -    together. So it would appear as if a lot of work would have to be done
     -    just to be able to use `parse_options()` just to parse the sub-command,
     -    instead of a simple `if...else if` chain, the latter being a
     -    dramatically simpler implementation.
     +    Side note: The `parse-options` API is not at all set up to parse
     +    subcommands such as `git bisect start`, `git bisect reset`, etc.
     +    Instead of fighting an up-hill battle trying to "fix" that, we simply
     +    roll the same type of manual subcommand parsing as we already do e.g.
     +    in `builtin/bundle.c`.
      
          Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
      
       ## builtin/bisect--helper.c ##
     -@@ builtin/bisect--helper.c: static GIT_PATH_FUNC(git_path_bisect_names, "BISECT_NAMES")
     - static GIT_PATH_FUNC(git_path_bisect_first_parent, "BISECT_FIRST_PARENT")
     - static GIT_PATH_FUNC(git_path_bisect_run, "BISECT_RUN")
     - 
     --static const char * const git_bisect_helper_usage[] = {
     --	N_("git bisect--helper --bisect-reset [<commit>]"),
     --	N_("git bisect--helper --bisect-terms [--term-good | --term-old | --term-bad | --term-new]"),
     --	N_("git bisect--helper --bisect-start [--term-{new,bad}=<term> --term-{old,good}=<term>]"
     --					    " [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<paths>...]"),
     --	N_("git bisect--helper --bisect-next"),
     --	N_("git bisect--helper [--bisect-state] (bad|new) [<rev>]"),
     --	N_("git bisect--helper [--bisect-state] (good|old) [<rev>...]"),
     --	N_("git bisect--helper --bisect-replay <filename>"),
     --	N_("git bisect--helper --bisect-skip [(<rev>|<range>)...]"),
     --	N_("git bisect--helper --bisect-visualize"),
     --	N_("git bisect--helper --bisect-run <cmd>..."),
     -+static const char * const git_bisect_usage[] = {
     -+	N_("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."),
     - 	NULL
     - };
     - 
      @@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
       
       int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
     @@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, cons
      -		OPT_CMDMODE(0, "bisect-log", &cmdmode,
      -			 N_("list the bisection steps so far"), BISECT_LOG),
      -		OPT_CMDMODE(0, "bisect-run", &cmdmode,
     --			 N_("use <cmd>... to automatically bisect."), BISECT_RUN),
     +-			 N_("use <cmd>... to automatically bisect"), BISECT_RUN),
       		OPT_END()
       	};
       	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
     @@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, cons
      -			     git_bisect_helper_usage,
      -			     PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN);
      +	if (!strcmp("-h", command) || !strcmp("help", command))
     -+		usage_with_options(git_bisect_usage, options);
     ++		usage_with_options(git_bisect_helper_usage, options);
       
      -	switch (cmdmode ? cmdmode : BISECT_STATE) {
      -	case BISECT_START:
     @@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, cons
      -		if (!cmdmode &&
      -		    (!argc || check_and_set_terms(&terms, argv[0]))) {
      -			char *msg = xstrfmt(_("unknown command: '%s'"), argv[0]);
     --			usage_msg_opt(msg, git_bisect_helper_usage, options);
      +		if (check_and_set_terms(&terms, command)) {
      +			char *msg = xstrfmt(_("unknown command: '%s'"), command);
     -+			usage_msg_opt(msg, git_bisect_usage, options);
     + 			usage_msg_opt(msg, git_bisect_helper_usage, options);
       		}
      +		/* shift the `command` back in */
      +		argc++;
  -:  ----------- > 12:  ac472aefb6a bisect: teach the `bisect--helper` command to show the correct usage strings
 12:  7db4b03b668 ! 13:  85f5c256ae3 Turn `git bisect` into a full built-in
     @@ builtin.h: int cmd_am(int argc, const char **argv, const char *prefix);
       int cmd_bugreport(int argc, const char **argv, const char *prefix);
      
       ## builtin/bisect--helper.c => builtin/bisect.c ##
     -@@ builtin/bisect.c: static GIT_PATH_FUNC(git_path_bisect_names, "BISECT_NAMES")
     - static GIT_PATH_FUNC(git_path_bisect_first_parent, "BISECT_FIRST_PARENT")
     - static GIT_PATH_FUNC(git_path_bisect_run, "BISECT_RUN")
     - 
     --static const char * const git_bisect_usage[] = {
     -+static const char * const builtin_bisect_usage[] = {
     - 	N_("git bisect help\n"
     - 	   "\tprint this long help message."),
     - 	N_("git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>]\n"
      @@ builtin/bisect.c: static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
     - 	}
     + 	return res;
       }
       
      -int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
      +int cmd_bisect(int argc, const char **argv, const char *prefix)
       {
       	int res = 0;
     - 	struct option options[] = {
     -@@ builtin/bisect.c: int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
     - 	const char *command = argc > 1 ? argv[1] : "help";
     - 
     - 	if (!strcmp("-h", command) || !strcmp("help", command))
     --		usage_with_options(git_bisect_usage, options);
     -+		usage_with_options(builtin_bisect_usage, options);
     - 
     - 	argc -= 2;
     - 	argv += 2;
     -@@ builtin/bisect.c: int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
     - 		get_terms(&terms);
     - 		if (check_and_set_terms(&terms, command)) {
     - 			char *msg = xstrfmt(_("unknown command: '%s'"), command);
     --			usage_msg_opt(msg, git_bisect_usage, options);
     -+			usage_msg_opt(msg, builtin_bisect_usage, options);
     - 		}
     - 		/* shift the `command` back in */
     - 		argc++;
     + 	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
      
       ## git-bisect.sh (deleted) ##
      @@
 13:  0611d16f772 = 14:  289917e96af bisect: remove Cogito-related code
 14:  e2fa11a819e = 15:  8f8d2ba0fe4 bisect: no longer try to clean up left-over `.git/head-name` files

-- 
gitgitgadget

^ permalink raw reply	[flat|nested] 147+ messages in thread

* [PATCH v3 01/15] bisect run: fix the error message
  2022-05-21 14:48   ` [PATCH v3 00/15] " Johannes Schindelin via GitGitGadget
@ 2022-05-21 14:48     ` Johannes Schindelin via GitGitGadget
  2022-05-21 14:48     ` [PATCH v3 02/15] bisect: avoid double-quoting when printing the failed command Johannes Schindelin via GitGitGadget
                       ` (15 subsequent siblings)
  16 siblings, 0 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-05-21 14:48 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Johannes Schindelin, Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

In d1bbbe45df8 (bisect--helper: reimplement `bisect_run` shell function
in C, 2021-09-13), we ported the `bisect run` subcommand to C, including
the part that prints out an error message when the implicit `git bisect
bad` or `git bisect good` failed.

However, the error message was supposed to print out whether the state
was "good" or "bad", but used a bogus (because non-populated) `args`
variable for it.

Helped-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/bisect--helper.c    |  2 +-
 t/t6030-bisect-porcelain.sh | 10 ++++++++++
 2 files changed, 11 insertions(+), 1 deletion(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index d4eaaa345ee..207479ee9ff 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1261,7 +1261,7 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
 			printf(_("bisect found first bad commit"));
 			res = BISECT_OK;
 		} else if (res) {
-			error(_("bisect run failed: 'git bisect--helper --bisect-state"
+			error(_("bisect run failed: 'git bisect"
 			" %s' exited with error code %d"), new_state, res);
 		} else {
 			continue;
diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh
index 83931d482fb..0cacbf1469a 100755
--- a/t/t6030-bisect-porcelain.sh
+++ b/t/t6030-bisect-porcelain.sh
@@ -1053,4 +1053,14 @@ test_expect_success 'bisect state output with bad commit' '
 	grep -F "waiting for good commit(s), bad commit known" output
 '
 
+test_expect_success 'verify correct error message' '
+	git bisect reset &&
+	git bisect start $HASH4 $HASH1 &&
+	write_script test_script.sh <<-\EOF &&
+	rm .git/BISECT*
+	EOF
+	test_must_fail git bisect run ./test_script.sh 2>error &&
+	grep "git bisect good.*exited with error code" error
+'
+
 test_done
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH v3 02/15] bisect: avoid double-quoting when printing the failed command
  2022-05-21 14:48   ` [PATCH v3 00/15] " Johannes Schindelin via GitGitGadget
  2022-05-21 14:48     ` [PATCH v3 01/15] bisect run: fix the error message Johannes Schindelin via GitGitGadget
@ 2022-05-21 14:48     ` Johannes Schindelin via GitGitGadget
  2022-05-21 14:48     ` [PATCH v3 03/15] bisect--helper: retire the --no-log option Johannes Schindelin via GitGitGadget
                       ` (14 subsequent siblings)
  16 siblings, 0 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-05-21 14:48 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Johannes Schindelin, Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

We already quote the command via `sq_quote_argv()`, no need to enclose
the result in an extraneous pair of single-quotes.

Pointed out by Elijah Newren.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/bisect--helper.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 207479ee9ff..0f49f52ac10 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1221,7 +1221,7 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
 
 		if (res < 0 || 128 <= res) {
 			error(_("bisect run failed: exit code %d from"
-				" '%s' is < 0 or >= 128"), res, command.buf);
+				" %s is < 0 or >= 128"), res, command.buf);
 			break;
 		}
 
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH v3 03/15] bisect--helper: retire the --no-log option
  2022-05-21 14:48   ` [PATCH v3 00/15] " Johannes Schindelin via GitGitGadget
  2022-05-21 14:48     ` [PATCH v3 01/15] bisect run: fix the error message Johannes Schindelin via GitGitGadget
  2022-05-21 14:48     ` [PATCH v3 02/15] bisect: avoid double-quoting when printing the failed command Johannes Schindelin via GitGitGadget
@ 2022-05-21 14:48     ` Johannes Schindelin via GitGitGadget
  2022-05-21 14:48     ` [PATCH v3 04/15] bisect--helper: really retire --bisect-next-check Johannes Schindelin via GitGitGadget
                       ` (13 subsequent siblings)
  16 siblings, 0 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-05-21 14:48 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Johannes Schindelin, Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

Turns out we actually never used it, anyway...

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/bisect--helper.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 0f49f52ac10..39556d60eab 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1290,7 +1290,7 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 		BISECT_VISUALIZE,
 		BISECT_RUN,
 	} cmdmode = 0;
-	int res = 0, nolog = 0;
+	int res = 0;
 	struct option options[] = {
 		OPT_CMDMODE(0, "bisect-reset", &cmdmode,
 			 N_("reset the bisection state"), BISECT_RESET),
@@ -1314,8 +1314,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 			 N_("visualize the bisection"), BISECT_VISUALIZE),
 		OPT_CMDMODE(0, "bisect-run", &cmdmode,
 			 N_("use <cmd>... to automatically bisect"), BISECT_RUN),
-		OPT_BOOL(0, "no-log", &nolog,
-			 N_("no log for BISECT_WRITE")),
 		OPT_END()
 	};
 	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH v3 04/15] bisect--helper: really retire --bisect-next-check
  2022-05-21 14:48   ` [PATCH v3 00/15] " Johannes Schindelin via GitGitGadget
                       ` (2 preceding siblings ...)
  2022-05-21 14:48     ` [PATCH v3 03/15] bisect--helper: retire the --no-log option Johannes Schindelin via GitGitGadget
@ 2022-05-21 14:48     ` Johannes Schindelin via GitGitGadget
  2022-05-21 14:48     ` [PATCH v3 05/15] bisect--helper: really retire `--bisect-autostart` Johannes Schindelin via GitGitGadget
                       ` (12 subsequent siblings)
  16 siblings, 0 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-05-21 14:48 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Johannes Schindelin, Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

In 911aba14205 (bisect--helper: retire `--bisect-next-check` subcommand,
2021-09-13), we removed the usage string and the implementation, but not
actually the option.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/bisect--helper.c | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 39556d60eab..658390952b2 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1278,7 +1278,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 {
 	enum {
 		BISECT_RESET = 1,
-		BISECT_NEXT_CHECK,
 		BISECT_TERMS,
 		BISECT_START,
 		BISECT_AUTOSTART,
@@ -1294,8 +1293,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 	struct option options[] = {
 		OPT_CMDMODE(0, "bisect-reset", &cmdmode,
 			 N_("reset the bisection state"), BISECT_RESET),
-		OPT_CMDMODE(0, "bisect-next-check", &cmdmode,
-			 N_("check whether bad or good terms exist"), BISECT_NEXT_CHECK),
 		OPT_CMDMODE(0, "bisect-terms", &cmdmode,
 			 N_("print out the bisect terms"), BISECT_TERMS),
 		OPT_CMDMODE(0, "bisect-start", &cmdmode,
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH v3 05/15] bisect--helper: really retire `--bisect-autostart`
  2022-05-21 14:48   ` [PATCH v3 00/15] " Johannes Schindelin via GitGitGadget
                       ` (3 preceding siblings ...)
  2022-05-21 14:48     ` [PATCH v3 04/15] bisect--helper: really retire --bisect-next-check Johannes Schindelin via GitGitGadget
@ 2022-05-21 14:48     ` Johannes Schindelin via GitGitGadget
  2022-05-21 14:48     ` [PATCH v3 06/15] bisect--helper: using `--bisect-state` without an argument is a bug Johannes Schindelin via GitGitGadget
                       ` (11 subsequent siblings)
  16 siblings, 0 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-05-21 14:48 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Johannes Schindelin, Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

Since b0f6494f70f (bisect--helper: retire `--bisect-autostart`
subcommand, 2020-10-15), the `--bisect-autostart` option is no more. But
we kept the `enum` value of the command mode around. Let's drop it, too.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/bisect--helper.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 658390952b2..8f4dab48379 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1280,7 +1280,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 		BISECT_RESET = 1,
 		BISECT_TERMS,
 		BISECT_START,
-		BISECT_AUTOSTART,
 		BISECT_NEXT,
 		BISECT_STATE,
 		BISECT_LOG,
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH v3 06/15] bisect--helper: using `--bisect-state` without an argument is a bug
  2022-05-21 14:48   ` [PATCH v3 00/15] " Johannes Schindelin via GitGitGadget
                       ` (4 preceding siblings ...)
  2022-05-21 14:48     ` [PATCH v3 05/15] bisect--helper: really retire `--bisect-autostart` Johannes Schindelin via GitGitGadget
@ 2022-05-21 14:48     ` Johannes Schindelin via GitGitGadget
  2022-05-21 14:48     ` [PATCH v3 07/15] bisect--helper: align the sub-command order with git-bisect.sh Johannes Schindelin via GitGitGadget
                       ` (10 subsequent siblings)
  16 siblings, 0 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-05-21 14:48 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Johannes Schindelin, Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

The `bisect--helper` command is not expected to be used directly by the
user. Therefore, it is a bug if it receives no argument to the
`--bisect-state` command mode, not a user error. Which means that we
need to call `BUG()` instead of `die()`.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/bisect--helper.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 8f4dab48379..343aedbc545 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -899,7 +899,7 @@ static enum bisect_error bisect_state(struct bisect_terms *terms, const char **a
 	struct oid_array revs = OID_ARRAY_INIT;
 
 	if (!argc)
-		return error(_("Please call `--bisect-state` with at least one argument"));
+		BUG("bisect_state() called without argument");
 
 	if (bisect_autostart(terms))
 		return BISECT_FAILED;
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH v3 07/15] bisect--helper: align the sub-command order with git-bisect.sh
  2022-05-21 14:48   ` [PATCH v3 00/15] " Johannes Schindelin via GitGitGadget
                       ` (5 preceding siblings ...)
  2022-05-21 14:48     ` [PATCH v3 06/15] bisect--helper: using `--bisect-state` without an argument is a bug Johannes Schindelin via GitGitGadget
@ 2022-05-21 14:48     ` Johannes Schindelin via GitGitGadget
  2022-05-21 14:48     ` [PATCH v3 08/15] bisect--helper: make `--bisect-state` optional Johannes Schindelin via GitGitGadget
                       ` (9 subsequent siblings)
  16 siblings, 0 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-05-21 14:48 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Johannes Schindelin, Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

We are about to retire the shell implementation of `git bisect`, or
maybe better put: the remainder of the shell implementation (a shell of
a script, if you want).

In preparation for that, align the order of the sub-commands with the
way the outgoing implementation presents them to the user.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/bisect--helper.c | 76 ++++++++++++++++++++--------------------
 1 file changed, 38 insertions(+), 38 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 343aedbc545..37a16c6ac1a 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1277,37 +1277,37 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
 int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 {
 	enum {
-		BISECT_RESET = 1,
-		BISECT_TERMS,
-		BISECT_START,
-		BISECT_NEXT,
+		BISECT_START = 1,
 		BISECT_STATE,
-		BISECT_LOG,
-		BISECT_REPLAY,
+		BISECT_TERMS,
 		BISECT_SKIP,
+		BISECT_NEXT,
+		BISECT_RESET,
 		BISECT_VISUALIZE,
+		BISECT_REPLAY,
+		BISECT_LOG,
 		BISECT_RUN,
 	} cmdmode = 0;
 	int res = 0;
 	struct option options[] = {
-		OPT_CMDMODE(0, "bisect-reset", &cmdmode,
-			 N_("reset the bisection state"), BISECT_RESET),
-		OPT_CMDMODE(0, "bisect-terms", &cmdmode,
-			 N_("print out the bisect terms"), BISECT_TERMS),
 		OPT_CMDMODE(0, "bisect-start", &cmdmode,
 			 N_("start the bisect session"), BISECT_START),
-		OPT_CMDMODE(0, "bisect-next", &cmdmode,
-			 N_("find the next bisection commit"), BISECT_NEXT),
 		OPT_CMDMODE(0, "bisect-state", &cmdmode,
 			 N_("mark the state of ref (or refs)"), BISECT_STATE),
-		OPT_CMDMODE(0, "bisect-log", &cmdmode,
-			 N_("list the bisection steps so far"), BISECT_LOG),
-		OPT_CMDMODE(0, "bisect-replay", &cmdmode,
-			 N_("replay the bisection process from the given file"), BISECT_REPLAY),
+		OPT_CMDMODE(0, "bisect-terms", &cmdmode,
+			 N_("print out the bisect terms"), BISECT_TERMS),
 		OPT_CMDMODE(0, "bisect-skip", &cmdmode,
 			 N_("skip some commits for checkout"), BISECT_SKIP),
+		OPT_CMDMODE(0, "bisect-next", &cmdmode,
+			 N_("find the next bisection commit"), BISECT_NEXT),
+		OPT_CMDMODE(0, "bisect-reset", &cmdmode,
+			 N_("reset the bisection state"), BISECT_RESET),
 		OPT_CMDMODE(0, "bisect-visualize", &cmdmode,
 			 N_("visualize the bisection"), BISECT_VISUALIZE),
+		OPT_CMDMODE(0, "bisect-replay", &cmdmode,
+			 N_("replay the bisection process from the given file"), BISECT_REPLAY),
+		OPT_CMDMODE(0, "bisect-log", &cmdmode,
+			 N_("list the bisection steps so far"), BISECT_LOG),
 		OPT_CMDMODE(0, "bisect-run", &cmdmode,
 			 N_("use <cmd>... to automatically bisect"), BISECT_RUN),
 		OPT_END()
@@ -1322,19 +1322,24 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 		usage_with_options(git_bisect_helper_usage, options);
 
 	switch (cmdmode) {
-	case BISECT_RESET:
-		if (argc > 1)
-			return error(_("--bisect-reset requires either no argument or a commit"));
-		res = bisect_reset(argc ? argv[0] : NULL);
+	case BISECT_START:
+		set_terms(&terms, "bad", "good");
+		res = bisect_start(&terms, argv, argc);
+		break;
+	case BISECT_STATE:
+		set_terms(&terms, "bad", "good");
+		get_terms(&terms);
+		res = bisect_state(&terms, argv, argc);
 		break;
 	case BISECT_TERMS:
 		if (argc > 1)
 			return error(_("--bisect-terms requires 0 or 1 argument"));
 		res = bisect_terms(&terms, argc == 1 ? argv[0] : NULL);
 		break;
-	case BISECT_START:
+	case BISECT_SKIP:
 		set_terms(&terms, "bad", "good");
-		res = bisect_start(&terms, argv, argc);
+		get_terms(&terms);
+		res = bisect_skip(&terms, argv, argc);
 		break;
 	case BISECT_NEXT:
 		if (argc)
@@ -1342,15 +1347,14 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 		get_terms(&terms);
 		res = bisect_next(&terms, prefix);
 		break;
-	case BISECT_STATE:
-		set_terms(&terms, "bad", "good");
-		get_terms(&terms);
-		res = bisect_state(&terms, argv, argc);
+	case BISECT_RESET:
+		if (argc > 1)
+			return error(_("--bisect-reset requires either no argument or a commit"));
+		res = bisect_reset(argc ? argv[0] : NULL);
 		break;
-	case BISECT_LOG:
-		if (argc)
-			return error(_("--bisect-log requires 0 arguments"));
-		res = bisect_log();
+	case BISECT_VISUALIZE:
+		get_terms(&terms);
+		res = bisect_visualize(&terms, argv, argc);
 		break;
 	case BISECT_REPLAY:
 		if (argc != 1)
@@ -1358,14 +1362,10 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 		set_terms(&terms, "bad", "good");
 		res = bisect_replay(&terms, argv[0]);
 		break;
-	case BISECT_SKIP:
-		set_terms(&terms, "bad", "good");
-		get_terms(&terms);
-		res = bisect_skip(&terms, argv, argc);
-		break;
-	case BISECT_VISUALIZE:
-		get_terms(&terms);
-		res = bisect_visualize(&terms, argv, argc);
+	case BISECT_LOG:
+		if (argc)
+			return error(_("--bisect-log requires 0 arguments"));
+		res = bisect_log();
 		break;
 	case BISECT_RUN:
 		if (!argc)
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH v3 08/15] bisect--helper: make `--bisect-state` optional
  2022-05-21 14:48   ` [PATCH v3 00/15] " Johannes Schindelin via GitGitGadget
                       ` (6 preceding siblings ...)
  2022-05-21 14:48     ` [PATCH v3 07/15] bisect--helper: align the sub-command order with git-bisect.sh Johannes Schindelin via GitGitGadget
@ 2022-05-21 14:48     ` Johannes Schindelin via GitGitGadget
  2022-05-21 14:49     ` [PATCH v3 09/15] bisect--helper: move the `BISECT_STATE` case to the end Johannes Schindelin via GitGitGadget
                       ` (8 subsequent siblings)
  16 siblings, 0 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-05-21 14:48 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Johannes Schindelin, Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

In preparation for making `git bisect` a real built-in, let's prepare
the `bisect--helper` built-in to handle `git bisect--helper good` and
`git bisect--helper bad`, i.e. do not require the `--bisect-state`
option to be passed explicitly.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/bisect--helper.c | 14 ++++++++------
 git-bisect.sh            |  2 +-
 2 files changed, 9 insertions(+), 7 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 37a16c6ac1a..94293318619 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -26,8 +26,8 @@ static const char * const git_bisect_helper_usage[] = {
 	N_("git bisect--helper --bisect-start [--term-{new,bad}=<term> --term-{old,good}=<term>]"
 					    " [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<paths>...]"),
 	"git bisect--helper --bisect-next",
-	N_("git bisect--helper --bisect-state (bad|new) [<rev>]"),
-	N_("git bisect--helper --bisect-state (good|old) [<rev>...]"),
+	N_("git bisect--helper [--bisect-state] (bad|new) [<rev>]"),
+	N_("git bisect--helper [--bisect-state] (good|old) [<rev>...]"),
 	N_("git bisect--helper --bisect-replay <filename>"),
 	N_("git bisect--helper --bisect-skip [(<rev>|<range>)...]"),
 	"git bisect--helper --bisect-visualize",
@@ -1318,10 +1318,7 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 			     git_bisect_helper_usage,
 			     PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN);
 
-	if (!cmdmode)
-		usage_with_options(git_bisect_helper_usage, options);
-
-	switch (cmdmode) {
+	switch (cmdmode ? cmdmode : BISECT_STATE) {
 	case BISECT_START:
 		set_terms(&terms, "bad", "good");
 		res = bisect_start(&terms, argv, argc);
@@ -1329,6 +1326,11 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 	case BISECT_STATE:
 		set_terms(&terms, "bad", "good");
 		get_terms(&terms);
+		if (!cmdmode &&
+		    (!argc || check_and_set_terms(&terms, argv[0]))) {
+			char *msg = xstrfmt(_("unknown command: '%s'"), argv[0]);
+			usage_msg_opt(msg, git_bisect_helper_usage, options);
+		}
 		res = bisect_state(&terms, argv, argc);
 		break;
 	case BISECT_TERMS:
diff --git a/git-bisect.sh b/git-bisect.sh
index 405cf76f2a3..fbf56649d7d 100755
--- a/git-bisect.sh
+++ b/git-bisect.sh
@@ -60,7 +60,7 @@ case "$#" in
 	start)
 		git bisect--helper --bisect-start "$@" ;;
 	bad|good|new|old|"$TERM_BAD"|"$TERM_GOOD")
-		git bisect--helper --bisect-state "$cmd" "$@" ;;
+		git bisect--helper "$cmd" "$@" ;;
 	skip)
 		git bisect--helper --bisect-skip "$@" || exit;;
 	next)
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH v3 09/15] bisect--helper: move the `BISECT_STATE` case to the end
  2022-05-21 14:48   ` [PATCH v3 00/15] " Johannes Schindelin via GitGitGadget
                       ` (7 preceding siblings ...)
  2022-05-21 14:48     ` [PATCH v3 08/15] bisect--helper: make `--bisect-state` optional Johannes Schindelin via GitGitGadget
@ 2022-05-21 14:49     ` Johannes Schindelin via GitGitGadget
  2022-05-21 14:49     ` [PATCH v3 10/15] bisect--helper: return only correct exit codes in `cmd_*()` Johannes Schindelin via GitGitGadget
                       ` (7 subsequent siblings)
  16 siblings, 0 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-05-21 14:49 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Johannes Schindelin, Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

In preparation for replacing the command-mode parsing in
`bisect--helper` with an if/else if/else chain, let's move the one
command that will be implicit (i.e. what will become the final `else`
without any `if`) to the end.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/bisect--helper.c | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 94293318619..21a3b913ed3 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1323,16 +1323,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 		set_terms(&terms, "bad", "good");
 		res = bisect_start(&terms, argv, argc);
 		break;
-	case BISECT_STATE:
-		set_terms(&terms, "bad", "good");
-		get_terms(&terms);
-		if (!cmdmode &&
-		    (!argc || check_and_set_terms(&terms, argv[0]))) {
-			char *msg = xstrfmt(_("unknown command: '%s'"), argv[0]);
-			usage_msg_opt(msg, git_bisect_helper_usage, options);
-		}
-		res = bisect_state(&terms, argv, argc);
-		break;
 	case BISECT_TERMS:
 		if (argc > 1)
 			return error(_("--bisect-terms requires 0 or 1 argument"));
@@ -1375,6 +1365,16 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 		get_terms(&terms);
 		res = bisect_run(&terms, argv, argc);
 		break;
+	case BISECT_STATE:
+		set_terms(&terms, "bad", "good");
+		get_terms(&terms);
+		if (!cmdmode &&
+		    (!argc || check_and_set_terms(&terms, argv[0]))) {
+			char *msg = xstrfmt(_("unknown command: '%s'"), argv[0]);
+			usage_msg_opt(msg, git_bisect_helper_usage, options);
+		}
+		res = bisect_state(&terms, argv, argc);
+		break;
 	default:
 		BUG("unknown subcommand %d", cmdmode);
 	}
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH v3 10/15] bisect--helper: return only correct exit codes in `cmd_*()`
  2022-05-21 14:48   ` [PATCH v3 00/15] " Johannes Schindelin via GitGitGadget
                       ` (8 preceding siblings ...)
  2022-05-21 14:49     ` [PATCH v3 09/15] bisect--helper: move the `BISECT_STATE` case to the end Johannes Schindelin via GitGitGadget
@ 2022-05-21 14:49     ` Johannes Schindelin via GitGitGadget
  2022-05-21 16:45       ` Ævar Arnfjörð Bjarmason
  2022-05-21 14:49     ` [PATCH v3 11/15] bisect: move even the command-line parsing to `bisect--helper` Johannes Schindelin via GitGitGadget
                       ` (6 subsequent siblings)
  16 siblings, 1 reply; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-05-21 14:49 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Johannes Schindelin, Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

Exit codes cannot be negative, but `error()` returns -1.

Let's just go with the common pattern and call `die()` in
`cmd_bisect__helper()` when incorrect arguments were detected.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/bisect--helper.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 21a3b913ed3..824f84ae76f 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1325,7 +1325,7 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 		break;
 	case BISECT_TERMS:
 		if (argc > 1)
-			return error(_("--bisect-terms requires 0 or 1 argument"));
+			die(_("--bisect-terms requires 0 or 1 argument"));
 		res = bisect_terms(&terms, argc == 1 ? argv[0] : NULL);
 		break;
 	case BISECT_SKIP:
@@ -1335,13 +1335,13 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 		break;
 	case BISECT_NEXT:
 		if (argc)
-			return error(_("--bisect-next requires 0 arguments"));
+			die(_("--bisect-next requires 0 arguments"));
 		get_terms(&terms);
 		res = bisect_next(&terms, prefix);
 		break;
 	case BISECT_RESET:
 		if (argc > 1)
-			return error(_("--bisect-reset requires either no argument or a commit"));
+			die(_("--bisect-reset requires either no argument or a commit"));
 		res = bisect_reset(argc ? argv[0] : NULL);
 		break;
 	case BISECT_VISUALIZE:
@@ -1350,18 +1350,18 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 		break;
 	case BISECT_REPLAY:
 		if (argc != 1)
-			return error(_("no logfile given"));
+			die(_("no logfile given"));
 		set_terms(&terms, "bad", "good");
 		res = bisect_replay(&terms, argv[0]);
 		break;
 	case BISECT_LOG:
 		if (argc)
-			return error(_("--bisect-log requires 0 arguments"));
+			die(_("--bisect-log requires 0 arguments"));
 		res = bisect_log();
 		break;
 	case BISECT_RUN:
 		if (!argc)
-			return error(_("bisect run failed: no command provided."));
+			die(_("bisect run failed: no command provided."));
 		get_terms(&terms);
 		res = bisect_run(&terms, argv, argc);
 		break;
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH v3 11/15] bisect: move even the command-line parsing to `bisect--helper`
  2022-05-21 14:48   ` [PATCH v3 00/15] " Johannes Schindelin via GitGitGadget
                       ` (9 preceding siblings ...)
  2022-05-21 14:49     ` [PATCH v3 10/15] bisect--helper: return only correct exit codes in `cmd_*()` Johannes Schindelin via GitGitGadget
@ 2022-05-21 14:49     ` Johannes Schindelin via GitGitGadget
  2022-05-21 16:52       ` Ævar Arnfjörð Bjarmason
  2022-05-21 14:49     ` [PATCH v3 12/15] bisect: teach the `bisect--helper` command to show the correct usage strings Johannes Schindelin via GitGitGadget
                       ` (5 subsequent siblings)
  16 siblings, 1 reply; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-05-21 14:49 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Johannes Schindelin, Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

On our journey to a fully built-in `git bisect`, this is the
one of the last steps.

Side note: The `parse-options` API is not at all set up to parse
subcommands such as `git bisect start`, `git bisect reset`, etc.
Instead of fighting an up-hill battle trying to "fix" that, we simply
roll the same type of manual subcommand parsing as we already do e.g.
in `builtin/bundle.c`.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/bisect--helper.c | 91 ++++++++++++----------------------------
 git-bisect.sh            | 49 +---------------------
 2 files changed, 27 insertions(+), 113 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 824f84ae76f..89ff688a4a2 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1276,108 +1276,69 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
 
 int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 {
-	enum {
-		BISECT_START = 1,
-		BISECT_STATE,
-		BISECT_TERMS,
-		BISECT_SKIP,
-		BISECT_NEXT,
-		BISECT_RESET,
-		BISECT_VISUALIZE,
-		BISECT_REPLAY,
-		BISECT_LOG,
-		BISECT_RUN,
-	} cmdmode = 0;
 	int res = 0;
 	struct option options[] = {
-		OPT_CMDMODE(0, "bisect-start", &cmdmode,
-			 N_("start the bisect session"), BISECT_START),
-		OPT_CMDMODE(0, "bisect-state", &cmdmode,
-			 N_("mark the state of ref (or refs)"), BISECT_STATE),
-		OPT_CMDMODE(0, "bisect-terms", &cmdmode,
-			 N_("print out the bisect terms"), BISECT_TERMS),
-		OPT_CMDMODE(0, "bisect-skip", &cmdmode,
-			 N_("skip some commits for checkout"), BISECT_SKIP),
-		OPT_CMDMODE(0, "bisect-next", &cmdmode,
-			 N_("find the next bisection commit"), BISECT_NEXT),
-		OPT_CMDMODE(0, "bisect-reset", &cmdmode,
-			 N_("reset the bisection state"), BISECT_RESET),
-		OPT_CMDMODE(0, "bisect-visualize", &cmdmode,
-			 N_("visualize the bisection"), BISECT_VISUALIZE),
-		OPT_CMDMODE(0, "bisect-replay", &cmdmode,
-			 N_("replay the bisection process from the given file"), BISECT_REPLAY),
-		OPT_CMDMODE(0, "bisect-log", &cmdmode,
-			 N_("list the bisection steps so far"), BISECT_LOG),
-		OPT_CMDMODE(0, "bisect-run", &cmdmode,
-			 N_("use <cmd>... to automatically bisect"), BISECT_RUN),
 		OPT_END()
 	};
 	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
+	const char *command = argc > 1 ? argv[1] : "help";
 
-	argc = parse_options(argc, argv, prefix, options,
-			     git_bisect_helper_usage,
-			     PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN);
+	if (!strcmp("-h", command) || !strcmp("help", command))
+		usage_with_options(git_bisect_helper_usage, options);
 
-	switch (cmdmode ? cmdmode : BISECT_STATE) {
-	case BISECT_START:
+	argc -= 2;
+	argv += 2;
+
+	if (!strcmp("start", command)) {
 		set_terms(&terms, "bad", "good");
 		res = bisect_start(&terms, argv, argc);
-		break;
-	case BISECT_TERMS:
+	} else if (!strcmp("terms", command)) {
 		if (argc > 1)
-			die(_("--bisect-terms requires 0 or 1 argument"));
+			die(_("'terms' requires 0 or 1 argument"));
 		res = bisect_terms(&terms, argc == 1 ? argv[0] : NULL);
-		break;
-	case BISECT_SKIP:
+	} else if (!strcmp("skip", command)) {
 		set_terms(&terms, "bad", "good");
 		get_terms(&terms);
 		res = bisect_skip(&terms, argv, argc);
-		break;
-	case BISECT_NEXT:
+	} else if (!strcmp("next", command)) {
 		if (argc)
-			die(_("--bisect-next requires 0 arguments"));
+			die(_("'next' requires 0 arguments"));
 		get_terms(&terms);
 		res = bisect_next(&terms, prefix);
-		break;
-	case BISECT_RESET:
+	} else if (!strcmp("reset", command)) {
 		if (argc > 1)
-			die(_("--bisect-reset requires either no argument or a commit"));
+			die(_("'reset' requires either no argument or a commit"));
 		res = bisect_reset(argc ? argv[0] : NULL);
-		break;
-	case BISECT_VISUALIZE:
+	} else if (one_of(command, "visualize", "view", NULL)) {
 		get_terms(&terms);
 		res = bisect_visualize(&terms, argv, argc);
-		break;
-	case BISECT_REPLAY:
+	} else if (!strcmp("replay", command)) {
 		if (argc != 1)
 			die(_("no logfile given"));
 		set_terms(&terms, "bad", "good");
 		res = bisect_replay(&terms, argv[0]);
-		break;
-	case BISECT_LOG:
+	} else if (!strcmp("log", command)) {
 		if (argc)
-			die(_("--bisect-log requires 0 arguments"));
+			die(_("'log' requires 0 arguments"));
 		res = bisect_log();
-		break;
-	case BISECT_RUN:
+	} else if (!strcmp("run", command)) {
 		if (!argc)
 			die(_("bisect run failed: no command provided."));
 		get_terms(&terms);
 		res = bisect_run(&terms, argv, argc);
-		break;
-	case BISECT_STATE:
+	} else {
 		set_terms(&terms, "bad", "good");
 		get_terms(&terms);
-		if (!cmdmode &&
-		    (!argc || check_and_set_terms(&terms, argv[0]))) {
-			char *msg = xstrfmt(_("unknown command: '%s'"), argv[0]);
+		if (check_and_set_terms(&terms, command)) {
+			char *msg = xstrfmt(_("unknown command: '%s'"), command);
 			usage_msg_opt(msg, git_bisect_helper_usage, options);
 		}
+		/* shift the `command` back in */
+		argc++;
+		argv--;
 		res = bisect_state(&terms, argv, argc);
-		break;
-	default:
-		BUG("unknown subcommand %d", cmdmode);
 	}
+
 	free_terms(&terms);
 
 	/*
diff --git a/git-bisect.sh b/git-bisect.sh
index fbf56649d7d..028d39cd9ce 100755
--- a/git-bisect.sh
+++ b/git-bisect.sh
@@ -34,51 +34,4 @@ Please use "git help bisect" to get the full man page.'
 OPTIONS_SPEC=
 . git-sh-setup
 
-TERM_BAD=bad
-TERM_GOOD=good
-
-get_terms () {
-	if test -s "$GIT_DIR/BISECT_TERMS"
-	then
-		{
-		read TERM_BAD
-		read TERM_GOOD
-		} <"$GIT_DIR/BISECT_TERMS"
-	fi
-}
-
-case "$#" in
-0)
-	usage ;;
-*)
-	cmd="$1"
-	get_terms
-	shift
-	case "$cmd" in
-	help)
-		git bisect -h ;;
-	start)
-		git bisect--helper --bisect-start "$@" ;;
-	bad|good|new|old|"$TERM_BAD"|"$TERM_GOOD")
-		git bisect--helper "$cmd" "$@" ;;
-	skip)
-		git bisect--helper --bisect-skip "$@" || exit;;
-	next)
-		# Not sure we want "next" at the UI level anymore.
-		git bisect--helper --bisect-next "$@" || exit ;;
-	visualize|view)
-		git bisect--helper --bisect-visualize "$@" || exit;;
-	reset)
-		git bisect--helper --bisect-reset "$@" ;;
-	replay)
-		git bisect--helper --bisect-replay "$@" || exit;;
-	log)
-		git bisect--helper --bisect-log || exit ;;
-	run)
-		git bisect--helper --bisect-run "$@" || exit;;
-	terms)
-		git bisect--helper --bisect-terms "$@" || exit;;
-	*)
-		usage ;;
-	esac
-esac
+exec git bisect--helper "$@"
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH v3 12/15] bisect: teach the `bisect--helper` command to show the correct usage strings
  2022-05-21 14:48   ` [PATCH v3 00/15] " Johannes Schindelin via GitGitGadget
                       ` (10 preceding siblings ...)
  2022-05-21 14:49     ` [PATCH v3 11/15] bisect: move even the command-line parsing to `bisect--helper` Johannes Schindelin via GitGitGadget
@ 2022-05-21 14:49     ` Johannes Schindelin via GitGitGadget
  2022-05-21 14:49     ` [PATCH v3 13/15] Turn `git bisect` into a full built-in Johannes Schindelin via GitGitGadget
                       ` (4 subsequent siblings)
  16 siblings, 0 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-05-21 14:49 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Johannes Schindelin, Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

In preparation for `bisect--helper` graduating to become the actual
`bisect` command, we hereby teach it to print the very same usage
strings as the scripted `git-bisect.sh` does.

With this patch, the `bisect--helper` command is able to do everything
that the `git-bisect.sh` script could, leaving as last step only to
retire that script at long last, which we will do in the next commit.

Note: Since we cannot use the `parse-options` API to handle the
subcommands of `git bisect` anyway, we no longer use it even just to
show the usage string anymore, either.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/bisect--helper.c | 69 ++++++++++++++++++++++++++--------------
 1 file changed, 46 insertions(+), 23 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 89ff688a4a2..a68f2c5a919 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1,6 +1,5 @@
 #include "builtin.h"
 #include "cache.h"
-#include "parse-options.h"
 #include "bisect.h"
 #include "refs.h"
 #include "dir.h"
@@ -20,20 +19,46 @@ static GIT_PATH_FUNC(git_path_bisect_names, "BISECT_NAMES")
 static GIT_PATH_FUNC(git_path_bisect_first_parent, "BISECT_FIRST_PARENT")
 static GIT_PATH_FUNC(git_path_bisect_run, "BISECT_RUN")
 
-static const char * const git_bisect_helper_usage[] = {
-	N_("git bisect--helper --bisect-reset [<commit>]"),
-	"git bisect--helper --bisect-terms [--term-good | --term-old | --term-bad | --term-new]",
-	N_("git bisect--helper --bisect-start [--term-{new,bad}=<term> --term-{old,good}=<term>]"
-					    " [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<paths>...]"),
-	"git bisect--helper --bisect-next",
-	N_("git bisect--helper [--bisect-state] (bad|new) [<rev>]"),
-	N_("git bisect--helper [--bisect-state] (good|old) [<rev>...]"),
-	N_("git bisect--helper --bisect-replay <filename>"),
-	N_("git bisect--helper --bisect-skip [(<rev>|<range>)...]"),
-	"git bisect--helper --bisect-visualize",
-	N_("git bisect--helper --bisect-run <cmd>..."),
-	NULL
-};
+static const char *bisect_usage =
+	N_("git bisect [help|start|bad|good|new|old|terms|skip|next|reset|"
+	   "visualize|view|replay|log|run]");
+
+static const char *bisect_long_usage =
+	N_("git bisect [help|start|bad|good|new|old|terms|skip|next|reset|"
+	   "visualize|view|replay|log|run]\n"
+	   "\n"
+	   "git bisect help\n"
+	   "\tprint this long help message.\n"
+	   "git bisect start [--term-{new,bad}=<term> "
+		"--term-{old,good}=<term>]\n"
+	   "\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	a revision after change in a given property.\n"
+	   "git bisect (good|old) [<rev>...]\n"
+	   "\tmark <rev>... known-good revisions/\n"
+	   "\t	revisions 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.");
 
 struct add_bisect_ref_data {
 	struct rev_info *revs;
@@ -1277,14 +1302,11 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
 int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 {
 	int res = 0;
-	struct option options[] = {
-		OPT_END()
-	};
 	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
 	const char *command = argc > 1 ? argv[1] : "help";
 
 	if (!strcmp("-h", command) || !strcmp("help", command))
-		usage_with_options(git_bisect_helper_usage, options);
+		usage(bisect_long_usage);
 
 	argc -= 2;
 	argv += 2;
@@ -1327,12 +1349,13 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 		get_terms(&terms);
 		res = bisect_run(&terms, argv, argc);
 	} else {
+		if (!file_is_not_empty(git_path_bisect_start()) &&
+		    !one_of(command, "bad", "good", "new", "old", NULL))
+			usage(bisect_usage);
 		set_terms(&terms, "bad", "good");
 		get_terms(&terms);
-		if (check_and_set_terms(&terms, command)) {
-			char *msg = xstrfmt(_("unknown command: '%s'"), command);
-			usage_msg_opt(msg, git_bisect_helper_usage, options);
-		}
+		if (check_and_set_terms(&terms, command))
+			usage(bisect_usage);
 		/* shift the `command` back in */
 		argc++;
 		argv--;
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH v3 13/15] Turn `git bisect` into a full built-in
  2022-05-21 14:48   ` [PATCH v3 00/15] " Johannes Schindelin via GitGitGadget
                       ` (11 preceding siblings ...)
  2022-05-21 14:49     ` [PATCH v3 12/15] bisect: teach the `bisect--helper` command to show the correct usage strings Johannes Schindelin via GitGitGadget
@ 2022-05-21 14:49     ` Johannes Schindelin via GitGitGadget
  2022-05-21 14:49     ` [PATCH v3 14/15] bisect: remove Cogito-related code Johannes Schindelin via GitGitGadget
                       ` (3 subsequent siblings)
  16 siblings, 0 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-05-21 14:49 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Johannes Schindelin, Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

Now that the shell script hands off to the `bisect--helper` to do
_anything_ (except to show the help), it is but a tiny step to let the
helper implement the actual `git bisect` command instead.

This retires `git-bisect.sh`, concluding a multi-year journey that many
hands helped with, in particular Pranit Bauna, Tanushree Tumane and
Miriam Rubio.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 Makefile                               |  3 +--
 builtin.h                              |  2 +-
 builtin/{bisect--helper.c => bisect.c} |  2 +-
 git-bisect.sh                          | 37 --------------------------
 git.c                                  |  2 +-
 5 files changed, 4 insertions(+), 42 deletions(-)
 rename builtin/{bisect--helper.c => bisect.c} (99%)
 delete mode 100755 git-bisect.sh

diff --git a/Makefile b/Makefile
index 61aadf3ce88..824b8a43576 100644
--- a/Makefile
+++ b/Makefile
@@ -611,7 +611,6 @@ THIRD_PARTY_SOURCES =
 # interactive shell sessions without exporting it.
 unexport CDPATH
 
-SCRIPT_SH += git-bisect.sh
 SCRIPT_SH += git-difftool--helper.sh
 SCRIPT_SH += git-filter-branch.sh
 SCRIPT_SH += git-merge-octopus.sh
@@ -1107,7 +1106,7 @@ BUILTIN_OBJS += builtin/am.o
 BUILTIN_OBJS += builtin/annotate.o
 BUILTIN_OBJS += builtin/apply.o
 BUILTIN_OBJS += builtin/archive.o
-BUILTIN_OBJS += builtin/bisect--helper.o
+BUILTIN_OBJS += builtin/bisect.o
 BUILTIN_OBJS += builtin/blame.o
 BUILTIN_OBJS += builtin/branch.o
 BUILTIN_OBJS += builtin/bugreport.o
diff --git a/builtin.h b/builtin.h
index 40e9ecc8485..b9470f8ab4f 100644
--- a/builtin.h
+++ b/builtin.h
@@ -116,7 +116,7 @@ int cmd_am(int argc, const char **argv, const char *prefix);
 int cmd_annotate(int argc, const char **argv, const char *prefix);
 int cmd_apply(int argc, const char **argv, const char *prefix);
 int cmd_archive(int argc, const char **argv, const char *prefix);
-int cmd_bisect__helper(int argc, const char **argv, const char *prefix);
+int cmd_bisect(int argc, const char **argv, const char *prefix);
 int cmd_blame(int argc, const char **argv, const char *prefix);
 int cmd_branch(int argc, const char **argv, const char *prefix);
 int cmd_bugreport(int argc, const char **argv, const char *prefix);
diff --git a/builtin/bisect--helper.c b/builtin/bisect.c
similarity index 99%
rename from builtin/bisect--helper.c
rename to builtin/bisect.c
index a68f2c5a919..d33de133c8c 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect.c
@@ -1299,7 +1299,7 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
 	return res;
 }
 
-int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
+int cmd_bisect(int argc, const char **argv, const char *prefix)
 {
 	int res = 0;
 	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
diff --git a/git-bisect.sh b/git-bisect.sh
deleted file mode 100755
index 028d39cd9ce..00000000000
--- a/git-bisect.sh
+++ /dev/null
@@ -1,37 +0,0 @@
-#!/bin/sh
-
-USAGE='[help|start|bad|good|new|old|terms|skip|next|reset|visualize|view|replay|log|run]'
-LONG_USAGE='git bisect help
-	print this long help message.
-git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>]
-		 [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<pathspec>...]
-	reset bisect state and start bisection.
-git bisect (bad|new) [<rev>]
-	mark <rev> a known-bad revision/
-		a revision after change in a given property.
-git bisect (good|old) [<rev>...]
-	mark <rev>... known-good revisions/
-		revisions before change in a given property.
-git bisect terms [--term-good | --term-bad]
-	show the terms used for old and new commits (default: bad, good)
-git bisect skip [(<rev>|<range>)...]
-	mark <rev>... untestable revisions.
-git bisect next
-	find next bisection to test and check it out.
-git bisect reset [<commit>]
-	finish bisection search and go back to commit.
-git bisect (visualize|view)
-	show bisect status in gitk.
-git bisect replay <logfile>
-	replay bisection log.
-git bisect log
-	show bisect log.
-git bisect run <cmd>...
-	use <cmd>... to automatically bisect.
-
-Please use "git help bisect" to get the full man page.'
-
-OPTIONS_SPEC=
-. git-sh-setup
-
-exec git bisect--helper "$@"
diff --git a/git.c b/git.c
index 5ff4f3e25b7..40ed082e621 100644
--- a/git.c
+++ b/git.c
@@ -492,7 +492,7 @@ static struct cmd_struct commands[] = {
 	{ "annotate", cmd_annotate, RUN_SETUP | NO_PARSEOPT },
 	{ "apply", cmd_apply, RUN_SETUP_GENTLY },
 	{ "archive", cmd_archive, RUN_SETUP_GENTLY },
-	{ "bisect--helper", cmd_bisect__helper, RUN_SETUP },
+	{ "bisect", cmd_bisect, RUN_SETUP },
 	{ "blame", cmd_blame, RUN_SETUP },
 	{ "branch", cmd_branch, RUN_SETUP | DELAY_PAGER_CONFIG },
 	{ "bugreport", cmd_bugreport, RUN_SETUP_GENTLY },
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH v3 14/15] bisect: remove Cogito-related code
  2022-05-21 14:48   ` [PATCH v3 00/15] " Johannes Schindelin via GitGitGadget
                       ` (12 preceding siblings ...)
  2022-05-21 14:49     ` [PATCH v3 13/15] Turn `git bisect` into a full built-in Johannes Schindelin via GitGitGadget
@ 2022-05-21 14:49     ` Johannes Schindelin via GitGitGadget
  2022-05-21 14:49     ` [PATCH v3 15/15] bisect: no longer try to clean up left-over `.git/head-name` files Johannes Schindelin via GitGitGadget
                       ` (2 subsequent siblings)
  16 siblings, 0 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-05-21 14:49 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Johannes Schindelin, Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

Once upon a time, there was this idea that Git would not actually be a
single coherent program, but rather a set of low-level programs that
users cobble together via shell scripts, or develop high-level user
interfaces for Git, or both.

Cogito was such a high-level user interface, incidentally implemented
via shell scripts that cobble together Git calls.

It did turn out relatively quickly that Git would much rather provide a
useful high-level user interface itself.

As of April 19th, 2007, Cogito was therefore discontinued (see
https://lore.kernel.org/git/20070419124648.GL4489@pasky.or.cz/).

Nevertheless, for almost 15 years after that announcement, Git carried
special code in `git bisect` to accommodate Cogito.

Since it is beyond doubt that there are no more Cogito users, let's
remove the last remnant of Cogito-accommodating code.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/bisect.c | 8 --------
 1 file changed, 8 deletions(-)

diff --git a/builtin/bisect.c b/builtin/bisect.c
index d33de133c8c..8f32ccb47b7 100644
--- a/builtin/bisect.c
+++ b/builtin/bisect.c
@@ -14,7 +14,6 @@ static GIT_PATH_FUNC(git_path_bisect_expected_rev, "BISECT_EXPECTED_REV")
 static GIT_PATH_FUNC(git_path_bisect_ancestors_ok, "BISECT_ANCESTORS_OK")
 static GIT_PATH_FUNC(git_path_bisect_start, "BISECT_START")
 static GIT_PATH_FUNC(git_path_bisect_log, "BISECT_LOG")
-static GIT_PATH_FUNC(git_path_head_name, "head-name")
 static GIT_PATH_FUNC(git_path_bisect_names, "BISECT_NAMES")
 static GIT_PATH_FUNC(git_path_bisect_first_parent, "BISECT_FIRST_PARENT")
 static GIT_PATH_FUNC(git_path_bisect_run, "BISECT_RUN")
@@ -808,13 +807,6 @@ static enum bisect_error bisect_start(struct bisect_terms *terms, const char **a
 			strbuf_addstr(&start_head, oid_to_hex(&head_oid));
 		} else if (!get_oid(head, &head_oid) &&
 			   skip_prefix(head, "refs/heads/", &head)) {
-			/*
-			 * This error message should only be triggered by
-			 * cogito usage, and cogito users should understand
-			 * it relates to cg-seek.
-			 */
-			if (!is_empty_or_missing_file(git_path_head_name()))
-				return error(_("won't bisect on cg-seek'ed tree"));
 			strbuf_addstr(&start_head, head);
 		} else {
 			return error(_("bad HEAD - strange symbolic ref"));
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH v3 15/15] bisect: no longer try to clean up left-over `.git/head-name` files
  2022-05-21 14:48   ` [PATCH v3 00/15] " Johannes Schindelin via GitGitGadget
                       ` (13 preceding siblings ...)
  2022-05-21 14:49     ` [PATCH v3 14/15] bisect: remove Cogito-related code Johannes Schindelin via GitGitGadget
@ 2022-05-21 14:49     ` Johannes Schindelin via GitGitGadget
  2022-05-22  3:07     ` [PATCH v3 00/15] Finish converting git bisect into a built-in Bagas Sanjaya
  2022-06-27 18:31     ` [PATCH v4 00/16] " Johannes Schindelin via GitGitGadget
  16 siblings, 0 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-05-21 14:49 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Johannes Schindelin, Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

As per the code comment, the `.git/head-name` files were cleaned up for
backwards-compatibility: an old version of `git bisect` could have left
them behind.

Now, just how old would such a version be? As of 0f497e75f05 (Eliminate
confusing "won't bisect on seeked tree" failure, 2008-02-23), `git
bisect` does not write that file anymore. Which corresponds to Git
v1.5.4.4.

Even if the likelihood is non-nil that there might still be users out
there who use such an old version to start a bisection, but then decide
to continue bisecting with a current Git version, it is highly
improbable.

So let's remove that code, at long last.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 bisect.c                    | 3 ---
 t/t6030-bisect-porcelain.sh | 1 -
 2 files changed, 4 deletions(-)

diff --git a/bisect.c b/bisect.c
index 9e6a2b7f201..8f46c3813ce 100644
--- a/bisect.c
+++ b/bisect.c
@@ -474,7 +474,6 @@ static GIT_PATH_FUNC(git_path_bisect_start, "BISECT_START")
 static GIT_PATH_FUNC(git_path_bisect_log, "BISECT_LOG")
 static GIT_PATH_FUNC(git_path_bisect_terms, "BISECT_TERMS")
 static GIT_PATH_FUNC(git_path_bisect_first_parent, "BISECT_FIRST_PARENT")
-static GIT_PATH_FUNC(git_path_head_name, "head-name")
 
 static void read_bisect_paths(struct strvec *array)
 {
@@ -1173,8 +1172,6 @@ int bisect_clean_state(void)
 	unlink_or_warn(git_path_bisect_run());
 	unlink_or_warn(git_path_bisect_terms());
 	unlink_or_warn(git_path_bisect_first_parent());
-	/* Cleanup head-name if it got left by an old version of git-bisect */
-	unlink_or_warn(git_path_head_name());
 	/*
 	 * Cleanup BISECT_START last to support the --no-checkout option
 	 * introduced in the commit 4796e823a.
diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh
index 0cacbf1469a..d4846ca4de1 100755
--- a/t/t6030-bisect-porcelain.sh
+++ b/t/t6030-bisect-porcelain.sh
@@ -990,7 +990,6 @@ test_expect_success 'git bisect reset cleans bisection state properly' '
 	test_path_is_missing ".git/BISECT_LOG" &&
 	test_path_is_missing ".git/BISECT_RUN" &&
 	test_path_is_missing ".git/BISECT_TERMS" &&
-	test_path_is_missing ".git/head-name" &&
 	test_path_is_missing ".git/BISECT_HEAD" &&
 	test_path_is_missing ".git/BISECT_START"
 '
-- 
gitgitgadget

^ permalink raw reply related	[flat|nested] 147+ messages in thread

* Re: [PATCH v3 10/15] bisect--helper: return only correct exit codes in `cmd_*()`
  2022-05-21 14:49     ` [PATCH v3 10/15] bisect--helper: return only correct exit codes in `cmd_*()` Johannes Schindelin via GitGitGadget
@ 2022-05-21 16:45       ` Ævar Arnfjörð Bjarmason
  0 siblings, 0 replies; 147+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-05-21 16:45 UTC (permalink / raw)
  To: Johannes Schindelin via GitGitGadget
  Cc: git, Pranit Bauva, Tanushree Tumane, Miriam Rubio, Elijah Newren,
	Johannes Schindelin


On Sat, May 21 2022, Johannes Schindelin via GitGitGadget wrote:

> From: Johannes Schindelin <johannes.schindelin@gmx.de>
>
> Exit codes cannot be negative, but `error()` returns -1.
>
> Let's just go with the common pattern and call `die()` in
> `cmd_bisect__helper()` when incorrect arguments were detected.

This is good in that before we'd return e.g. code 255 here:

    $ ./git bisect--helper  --bisect-terms foo bar; echo $?
    error: --bisect-terms requires 0 or 1 argument
    255

But now say:
    
    $ ./git bisect--helper  --bisect-terms foo bar; echo $?
    fatal: --bisect-terms requires 0 or 1 argument
    128

But after this patch we emit e.g. this:

    $ ./git bisect--helper  --bisect-terms ; echo $?
    error: no terms defined
    1

We should instead treat all these usage errors the same. A better fix
would be to either use usage_msg_opt[f]() consistently instead of die().

Or just this, which would narrowly fix the inconsistency and the exit
code:

    diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
    index 21a3b913ed3..e44d894e2ec 100644
    --- a/builtin/bisect--helper.c
    +++ b/builtin/bisect--helper.c
    @@ -1325,7 +1325,7 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
                    break;
            case BISECT_TERMS:
                    if (argc > 1)
    -                       return error(_("--bisect-terms requires 0 or 1 argument"));
    +                       return -error(_("--bisect-terms requires 0 or 1 argument"));
                    res = bisect_terms(&terms, argc == 1 ? argv[0] : NULL);
                    break;
            case BISECT_SKIP:

But returning 129 instead of 1 or 128 is better here, as that's the exit
code we specifically use for bad usage messages.

I'll read on, but changing "error" to "fatal" and the exit code from 255
and 1 to 128 and 1 instead of either always 129 or always 1 in these
cases seems odd, especially as the last part of the function has this
code:

        return -res;

I.e. it's expecting "res" to be e.g. -1 or 0, and to convert that to 1
or 0.

^ permalink raw reply	[flat|nested] 147+ messages in thread

* Re: [PATCH v3 11/15] bisect: move even the command-line parsing to `bisect--helper`
  2022-05-21 14:49     ` [PATCH v3 11/15] bisect: move even the command-line parsing to `bisect--helper` Johannes Schindelin via GitGitGadget
@ 2022-05-21 16:52       ` Ævar Arnfjörð Bjarmason
  0 siblings, 0 replies; 147+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-05-21 16:52 UTC (permalink / raw)
  To: Johannes Schindelin via GitGitGadget
  Cc: git, Pranit Bauva, Tanushree Tumane, Miriam Rubio, Elijah Newren,
	Johannes Schindelin


On Sat, May 21 2022, Johannes Schindelin via GitGitGadget wrote:

> From: Johannes Schindelin <johannes.schindelin@gmx.de>
>
> On our journey to a fully built-in `git bisect`, this is the
> one of the last steps.
>
> Side note: The `parse-options` API is not at all set up to parse
> subcommands such as `git bisect start`, `git bisect reset`, etc.


It seems that since v2 you fixed the bug of "-h" starting a bisection
session, as noted in :
https://lore.kernel.org/git/220225.86ilt27uln.gmgdl@evledraar.gmail.com/


But that problem seems to still be with us in other forms, e.g. just one
thing I tried (the very first thing) was the command I was testing in
10/15, and:
    
    ./git bisect--helper  --bisect-terms 1 2 ; echo $?
    You need to start by "git bisect start"
    
    Do you want me to do it for you [Y/n]? ^C

so that's buggy too.

> Instead of fighting an up-hill battle trying to "fix" that, we simply
> roll the same type of manual subcommand parsing as we already do e.g.
> in `builtin/bundle.c`.

This is particularly confusing because that would be a good approach (as
I pointed out in a previous round), but the end-state here isn't at all
like builtin/bundle.c. I.e. in that case we have a top-level strcmp()
chain dispatching to parse_options() for the sub-command, which would
solve your problems here...

^ permalink raw reply	[flat|nested] 147+ messages in thread

* Re: [PATCH v3 00/15] Finish converting git bisect into a built-in
  2022-05-21 14:48   ` [PATCH v3 00/15] " Johannes Schindelin via GitGitGadget
                       ` (14 preceding siblings ...)
  2022-05-21 14:49     ` [PATCH v3 15/15] bisect: no longer try to clean up left-over `.git/head-name` files Johannes Schindelin via GitGitGadget
@ 2022-05-22  3:07     ` Bagas Sanjaya
  2022-05-23 10:22       ` Ævar Arnfjörð Bjarmason
  2022-06-27 18:31     ` [PATCH v4 00/16] " Johannes Schindelin via GitGitGadget
  16 siblings, 1 reply; 147+ messages in thread
From: Bagas Sanjaya @ 2022-05-22  3:07 UTC (permalink / raw)
  To: Johannes Schindelin via GitGitGadget, git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Johannes Schindelin

On 5/21/22 21:48, Johannes Schindelin via GitGitGadget wrote:
>  * When a bogus command is provided, we now error out instead of trying to
>    start a git bisect run.

Ah! git bisect now behave like other shell commands where bogus
command is given, instead of "accidentally" start the bisection.

BTW, do the current version of git bisect exhibit that accidental
behavior?

-- 
An old man doll... just what I always wanted! - Clara

^ permalink raw reply	[flat|nested] 147+ messages in thread

* Re: [PATCH v3 00/15] Finish converting git bisect into a built-in
  2022-05-22  3:07     ` [PATCH v3 00/15] Finish converting git bisect into a built-in Bagas Sanjaya
@ 2022-05-23 10:22       ` Ævar Arnfjörð Bjarmason
  0 siblings, 0 replies; 147+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-05-23 10:22 UTC (permalink / raw)
  To: Bagas Sanjaya
  Cc: Johannes Schindelin via GitGitGadget, git, Pranit Bauva,
	Tanushree Tumane, Miriam Rubio, Elijah Newren,
	Johannes Schindelin


On Sun, May 22 2022, Bagas Sanjaya wrote:

> On 5/21/22 21:48, Johannes Schindelin via GitGitGadget wrote:
>>  * When a bogus command is provided, we now error out instead of trying to
>>    start a git bisect run.
>
> Ah! git bisect now behave like other shell commands where bogus
> command is given, instead of "accidentally" start the bisection.
>
> BTW, do the current version of git bisect exhibit that accidental
> behavior?

No, this is a fix for a bug introduced in an earlier version of this
topic, but the more general issue remains. See
https://lore.kernel.org/git/220521.86zgjazuy4.gmgdl@evledraar.gmail.com/

Rather than a surgical fix for a specific issue I noted, with the
initial report being:
https://lore.kernel.org/git/220223.86v8x56g7g.gmgdl@evledraar.gmail.com/

This topic could really use some confidence building by adding new "git
bisect" tests. I.e. let's have tests for what exit codes etc. we emit on
various valid and invalid "git bisect" usage.

We clearly don't have that since the proposed v2 would have introduced a
regression, and this v3 would also have done that in other cases (while
fixing the one specific case of "-h").

^ permalink raw reply	[flat|nested] 147+ messages in thread

* [PATCH v4 00/16] Finish converting git bisect into a built-in
  2022-05-21 14:48   ` [PATCH v3 00/15] " Johannes Schindelin via GitGitGadget
                       ` (15 preceding siblings ...)
  2022-05-22  3:07     ` [PATCH v3 00/15] Finish converting git bisect into a built-in Bagas Sanjaya
@ 2022-06-27 18:31     ` Johannes Schindelin via GitGitGadget
  2022-06-27 18:31       ` [PATCH v4 01/16] bisect: verify that a bogus option won't try to start a bisection Johannes Schindelin via GitGitGadget
                         ` (17 more replies)
  16 siblings, 18 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-06-27 18:31 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Bagas Sanjaya, Johannes Schindelin

After three GSoC/Outreachy students spent an incredible effort on this, it
is finally time to put a neat little bow on it.

Changes since v3:

 * Rebased because of merge conflicts with ab/plug-leak-in-revisions.
 * Fixed the bug that git bisect --bisect-terms 1 2 wanted to auto-start a
   bisection if running with a git executable built at the in-between state
   at patch "bisect: move even the command-line parsing to bisect--helper".
   Since this bug was "fixed" in v3 by the very next patch, "bisect: teach
   the bisect--helper command to show the correct usage strings", v4 avoids
   introducing this bug simply by letting these two patches trade places.
   The range-diff admittedly looks quite awful because both patches overlap
   quite a bit in the lines they modify. The end result is the same, though,
   the diff between v3's and v4's builtin/bisect.c would be empty if I
   hadn't been forced to rebase.
 * Added a test case to ensure that this bug won't be introduced again. This
   test case is the only actual difference relative to v3 of this patch
   series.

Changes since v2:

 * We're now careful to provide identical usage strings upon git bisect -h
   and git bisect bogus.
 * When a bogus command is provided, we now error out instead of trying to
   start a git bisect run.
 * Rebased onto main to avoid plenty of merge conflicts with
   rs/bisect-executable-not-found, ac/usage-string-fixups and with
   cd/bisect-messages-from-pre-flight-states.

Changes since v1:

 * Added a regression test to "bisect run: fix the error message".
 * Added a patch to address an error message that double-single-quoted the
   command.
 * Reworked the logic in "bisect--helper: make --bisect-state optional" to
   delay showing the usage upon an unknown command, which should make the
   code a lot less confusing.
 * Split out the change that moved the BISECT_STATE case to the end of the
   switch block.
 * Added a patch that replaces the return error() calls in
   cmd_bisect_helper() with die() calls, to avoid returning -1 as an exit
   code.
 * Dropped the use of parse_options() for the single purpose of handling -h;
   This is now done explicitly.
 * Simplified the diff of "bisect: move even the option parsing to
   bisect--helper" by modifying argc and argv instead of modifying all the
   function calls using those variables.
 * In the "Turn git bisect into a full built-in" patch, changed the name of
   the variable holding the usage to use the builtin_ prefix used in other
   built-ins, too.
 * Removed the trailing dot from the commit message of "Turn git bisect into
   a full built-in".

Johannes Schindelin (16):
  bisect: verify that a bogus option won't try to start a bisection
  bisect run: fix the error message
  bisect: avoid double-quoting when printing the failed command
  bisect--helper: retire the --no-log option
  bisect--helper: really retire --bisect-next-check
  bisect--helper: really retire `--bisect-autostart`
  bisect--helper: using `--bisect-state` without an argument is a bug
  bisect--helper: align the sub-command order with git-bisect.sh
  bisect--helper: make `--bisect-state` optional
  bisect--helper: move the `BISECT_STATE` case to the end
  bisect--helper: return only correct exit codes in `cmd_*()`
  bisect: teach the `bisect--helper` command to show the correct usage
    strings
  bisect: move even the command-line parsing to `bisect--helper`
  Turn `git bisect` into a full built-in
  bisect: remove Cogito-related code
  bisect: no longer try to clean up left-over `.git/head-name` files

 Makefile                               |   3 +-
 bisect.c                               |   3 -
 builtin.h                              |   2 +-
 builtin/{bisect--helper.c => bisect.c} | 202 +++++++++++--------------
 git-bisect.sh                          |  84 ----------
 git.c                                  |   2 +-
 t/t6030-bisect-porcelain.sh            |  21 ++-
 7 files changed, 110 insertions(+), 207 deletions(-)
 rename builtin/{bisect--helper.c => bisect.c} (89%)
 delete mode 100755 git-bisect.sh


base-commit: 8168d5e9c23ed44ae3d604f392320d66556453c9
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-1132%2Fdscho%2Fbisect-in-c-v4
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1132/dscho/bisect-in-c-v4
Pull-Request: https://github.com/gitgitgadget/git/pull/1132

Range-diff vs v3:

  -:  ----------- >  1:  30ddbd7affc bisect: verify that a bogus option won't try to start a bisection
  1:  cf6034625dd =  2:  97dd2da8f89 bisect run: fix the error message
  2:  955ccd4d8c8 =  3:  5571e0f76ff bisect: avoid double-quoting when printing the failed command
  3:  abcbc25966c =  4:  5bfaf0334c3 bisect--helper: retire the --no-log option
  4:  af60ef1b5a4 =  5:  e85f236304b bisect--helper: really retire --bisect-next-check
  5:  07a92c58f8e =  6:  b94b7bb4fd0 bisect--helper: really retire `--bisect-autostart`
  6:  04ba0950b85 =  7:  aad3c9a0850 bisect--helper: using `--bisect-state` without an argument is a bug
  7:  6847af9d485 =  8:  375a46dca9f bisect--helper: align the sub-command order with git-bisect.sh
  8:  b7bc53b9cb6 =  9:  c57f63f6a61 bisect--helper: make `--bisect-state` optional
  9:  1919237a819 = 10:  87f53469a72 bisect--helper: move the `BISECT_STATE` case to the end
 10:  1236a731903 = 11:  ce508583e45 bisect--helper: return only correct exit codes in `cmd_*()`
 12:  ac472aefb6a ! 12:  5dbe233e4ec bisect: teach the `bisect--helper` command to show the correct usage strings
     @@ Commit message
          `bisect` command, we hereby teach it to print the very same usage
          strings as the scripted `git-bisect.sh` does.
      
     -    With this patch, the `bisect--helper` command is able to do everything
     -    that the `git-bisect.sh` script could, leaving as last step only to
     -    retire that script at long last, which we will do in the next commit.
     -
     -    Note: Since we cannot use the `parse-options` API to handle the
     -    subcommands of `git bisect` anyway, we no longer use it even just to
     -    show the usage string anymore, either.
     -
          Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
      
       ## builtin/bisect--helper.c ##
     @@ builtin/bisect--helper.c: static GIT_PATH_FUNC(git_path_bisect_names, "BISECT_NA
      -	N_("git bisect--helper --bisect-skip [(<rev>|<range>)...]"),
      -	"git bisect--helper --bisect-visualize",
      -	N_("git bisect--helper --bisect-run <cmd>..."),
     --	NULL
     --};
      +static const char *bisect_usage =
      +	N_("git bisect [help|start|bad|good|new|old|terms|skip|next|reset|"
      +	   "visualize|view|replay|log|run]");
      +
     -+static const char *bisect_long_usage =
     ++static const char * const bisect_long_usage[] = {
      +	N_("git bisect [help|start|bad|good|new|old|terms|skip|next|reset|"
      +	   "visualize|view|replay|log|run]\n"
      +	   "\n"
     @@ builtin/bisect--helper.c: static GIT_PATH_FUNC(git_path_bisect_names, "BISECT_NA
      +	   "git bisect run <cmd>...\n"
      +	   "\tuse <cmd>... to automatically bisect.\n"
      +	   "\n"
     -+	   "Please use \"git help bisect\" to get the full man page.");
     ++	   "Please use \"git help bisect\" to get the full man page."),
     + 	NULL
     + };
       
     - struct add_bisect_ref_data {
     - 	struct rev_info *revs;
     -@@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
     - int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
     - {
     - 	int res = 0;
     --	struct option options[] = {
     --		OPT_END()
     --	};
     +@@ builtin/bisect--helper.c: int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
       	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
     - 	const char *command = argc > 1 ? argv[1] : "help";
       
     - 	if (!strcmp("-h", command) || !strcmp("help", command))
     --		usage_with_options(git_bisect_helper_usage, options);
     -+		usage(bisect_long_usage);
     + 	argc = parse_options(argc, argv, prefix, options,
     +-			     git_bisect_helper_usage,
     ++			     bisect_long_usage,
     + 			     PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN);
       
     - 	argc -= 2;
     - 	argv += 2;
     + 	switch (cmdmode ? cmdmode : BISECT_STATE) {
      @@ builtin/bisect--helper.c: int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
     - 		get_terms(&terms);
       		res = bisect_run(&terms, argv, argc);
     - 	} else {
     -+		if (!file_is_not_empty(git_path_bisect_start()) &&
     -+		    !one_of(command, "bad", "good", "new", "old", NULL))
     + 		break;
     + 	case BISECT_STATE:
     ++		if (argc &&
     ++		    !file_is_not_empty(git_path_bisect_start()) &&
     ++		    !one_of(argv[0], "bad", "good", "new", "old", NULL))
      +			usage(bisect_usage);
       		set_terms(&terms, "bad", "good");
       		get_terms(&terms);
     --		if (check_and_set_terms(&terms, command)) {
     --			char *msg = xstrfmt(_("unknown command: '%s'"), command);
     + 		if (!cmdmode &&
     +-		    (!argc || check_and_set_terms(&terms, argv[0]))) {
     +-			char *msg = xstrfmt(_("unknown command: '%s'"), argv[0]);
      -			usage_msg_opt(msg, git_bisect_helper_usage, options);
      -		}
     -+		if (check_and_set_terms(&terms, command))
     ++		    (!argc || check_and_set_terms(&terms, argv[0])))
      +			usage(bisect_usage);
     - 		/* shift the `command` back in */
     - 		argc++;
     - 		argv--;
     + 		res = bisect_state(&terms, argv, argc);
     + 		break;
     + 	default:
 11:  4ae78d37d04 ! 13:  d56f2a14060 bisect: move even the command-line parsing to `bisect--helper`
     @@ Commit message
          bisect: move even the command-line parsing to `bisect--helper`
      
          On our journey to a fully built-in `git bisect`, this is the
     -    one of the last steps.
     +    last step.
      
          Side note: The `parse-options` API is not at all set up to parse
          subcommands such as `git bisect start`, `git bisect reset`, etc.
     @@ Commit message
          Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
      
       ## builtin/bisect--helper.c ##
     +@@ builtin/bisect--helper.c: static const char *bisect_usage =
     + 	N_("git bisect [help|start|bad|good|new|old|terms|skip|next|reset|"
     + 	   "visualize|view|replay|log|run]");
     + 
     +-static const char * const bisect_long_usage[] = {
     ++static const char *bisect_long_usage =
     + 	N_("git bisect [help|start|bad|good|new|old|terms|skip|next|reset|"
     + 	   "visualize|view|replay|log|run]\n"
     + 	   "\n"
     +@@ builtin/bisect--helper.c: static const char * const bisect_long_usage[] = {
     + 	   "git bisect run <cmd>...\n"
     + 	   "\tuse <cmd>... to automatically bisect.\n"
     + 	   "\n"
     +-	   "Please use \"git help bisect\" to get the full man page."),
     +-	NULL
     +-};
     ++	   "Please use \"git help bisect\" to get the full man page.");
     + 
     + struct add_bisect_ref_data {
     + 	struct rev_info *revs;
      @@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
       
       int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
     @@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, cons
      -		BISECT_RUN,
      -	} cmdmode = 0;
       	int res = 0;
     - 	struct option options[] = {
     +-	struct option options[] = {
      -		OPT_CMDMODE(0, "bisect-start", &cmdmode,
      -			 N_("start the bisect session"), BISECT_START),
      -		OPT_CMDMODE(0, "bisect-state", &cmdmode,
     @@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, cons
      -			 N_("list the bisection steps so far"), BISECT_LOG),
      -		OPT_CMDMODE(0, "bisect-run", &cmdmode,
      -			 N_("use <cmd>... to automatically bisect"), BISECT_RUN),
     - 		OPT_END()
     - 	};
     +-		OPT_END()
     +-	};
       	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
      +	const char *command = argc > 1 ? argv[1] : "help";
     ++
     ++	if (!strcmp("-h", command) || !strcmp("help", command))
     ++		usage(bisect_long_usage);
       
      -	argc = parse_options(argc, argv, prefix, options,
     --			     git_bisect_helper_usage,
     +-			     bisect_long_usage,
      -			     PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN);
     -+	if (!strcmp("-h", command) || !strcmp("help", command))
     -+		usage_with_options(git_bisect_helper_usage, options);
     ++	argc -= 2;
     ++	argv += 2;
       
      -	switch (cmdmode ? cmdmode : BISECT_STATE) {
      -	case BISECT_START:
     -+	argc -= 2;
     -+	argv += 2;
     -+
      +	if (!strcmp("start", command)) {
       		set_terms(&terms, "bad", "good");
       		res = bisect_start(&terms, argv, argc);
     @@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, cons
       		res = bisect_run(&terms, argv, argc);
      -		break;
      -	case BISECT_STATE:
     +-		if (argc &&
     +-		    !file_is_not_empty(git_path_bisect_start()) &&
     +-		    !one_of(argv[0], "bad", "good", "new", "old", NULL))
      +	} else {
     ++		if (!file_is_not_empty(git_path_bisect_start()) &&
     ++		    !one_of(command, "bad", "good", "new", "old", NULL))
     + 			usage(bisect_usage);
       		set_terms(&terms, "bad", "good");
       		get_terms(&terms);
      -		if (!cmdmode &&
     --		    (!argc || check_and_set_terms(&terms, argv[0]))) {
     --			char *msg = xstrfmt(_("unknown command: '%s'"), argv[0]);
     -+		if (check_and_set_terms(&terms, command)) {
     -+			char *msg = xstrfmt(_("unknown command: '%s'"), command);
     - 			usage_msg_opt(msg, git_bisect_helper_usage, options);
     - 		}
     +-		    (!argc || check_and_set_terms(&terms, argv[0])))
     ++		if (check_and_set_terms(&terms, command))
     + 			usage(bisect_usage);
      +		/* shift the `command` back in */
      +		argc++;
      +		argv--;
 13:  85f5c256ae3 = 14:  378d6d22737 Turn `git bisect` into a full built-in
 14:  289917e96af = 15:  33566b86d77 bisect: remove Cogito-related code
 15:  8f8d2ba0fe4 = 16:  334664f23a8 bisect: no longer try to clean up left-over `.git/head-name` files

-- 
gitgitgadget

^ permalink raw reply	[flat|nested] 147+ messages in thread

* [PATCH v4 01/16] bisect: verify that a bogus option won't try to start a bisection
  2022-06-27 18:31     ` [PATCH v4 00/16] " Johannes Schindelin via GitGitGadget
@ 2022-06-27 18:31       ` Johannes Schindelin via GitGitGadget
  2022-06-28  2:12         ` Junio C Hamano
  2022-06-27 18:31       ` [PATCH v4 02/16] bisect run: fix the error message Johannes Schindelin via GitGitGadget
                         ` (16 subsequent siblings)
  17 siblings, 1 reply; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-06-27 18:31 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Bagas Sanjaya, Johannes Schindelin, Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

We do not want `git bisect --bogus-option` to start a bisection. To
verify that, we look for the tell-tale error message `You need to start
by "git bisect start"` and fail if it was found.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 t/t6030-bisect-porcelain.sh | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh
index 83931d482fb..6d6e72276ae 100755
--- a/t/t6030-bisect-porcelain.sh
+++ b/t/t6030-bisect-porcelain.sh
@@ -900,6 +900,16 @@ test_expect_success 'bisect start with one term1 and term2' '
 	git bisect reset
 '
 
+test_expect_success 'bogus command does not start bisect' '
+	git bisect reset &&
+	test_must_fail git bisect --bisect-terms 1 2 2>out &&
+	! grep "You need to start" out &&
+	test_must_fail git bisect --bisect-terms 2>out &&
+	! grep "You need to start" out &&
+	grep "git bisect.*visualize" out &&
+	git bisect reset
+'
+
 test_expect_success 'bisect replay with term1 and term2' '
 	git bisect replay log_to_replay.txt >bisect_result &&
 	grep "$HASH2 is the first term1 commit" bisect_result &&
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH v4 02/16] bisect run: fix the error message
  2022-06-27 18:31     ` [PATCH v4 00/16] " Johannes Schindelin via GitGitGadget
  2022-06-27 18:31       ` [PATCH v4 01/16] bisect: verify that a bogus option won't try to start a bisection Johannes Schindelin via GitGitGadget
@ 2022-06-27 18:31       ` Johannes Schindelin via GitGitGadget
  2022-06-27 18:31       ` [PATCH v4 03/16] bisect: avoid double-quoting when printing the failed command Johannes Schindelin via GitGitGadget
                         ` (15 subsequent siblings)
  17 siblings, 0 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-06-27 18:31 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Bagas Sanjaya, Johannes Schindelin, Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

In d1bbbe45df8 (bisect--helper: reimplement `bisect_run` shell function
in C, 2021-09-13), we ported the `bisect run` subcommand to C, including
the part that prints out an error message when the implicit `git bisect
bad` or `git bisect good` failed.

However, the error message was supposed to print out whether the state
was "good" or "bad", but used a bogus (because non-populated) `args`
variable for it.

Helped-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/bisect--helper.c    |  2 +-
 t/t6030-bisect-porcelain.sh | 10 ++++++++++
 2 files changed, 11 insertions(+), 1 deletion(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 8a052c7111f..cc38a009bdd 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1263,7 +1263,7 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
 			printf(_("bisect found first bad commit"));
 			res = BISECT_OK;
 		} else if (res) {
-			error(_("bisect run failed: 'git bisect--helper --bisect-state"
+			error(_("bisect run failed: 'git bisect"
 			" %s' exited with error code %d"), new_state, res);
 		} else {
 			continue;
diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh
index 6d6e72276ae..7a76f204083 100755
--- a/t/t6030-bisect-porcelain.sh
+++ b/t/t6030-bisect-porcelain.sh
@@ -1063,4 +1063,14 @@ test_expect_success 'bisect state output with bad commit' '
 	grep -F "waiting for good commit(s), bad commit known" output
 '
 
+test_expect_success 'verify correct error message' '
+	git bisect reset &&
+	git bisect start $HASH4 $HASH1 &&
+	write_script test_script.sh <<-\EOF &&
+	rm .git/BISECT*
+	EOF
+	test_must_fail git bisect run ./test_script.sh 2>error &&
+	grep "git bisect good.*exited with error code" error
+'
+
 test_done
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH v4 03/16] bisect: avoid double-quoting when printing the failed command
  2022-06-27 18:31     ` [PATCH v4 00/16] " Johannes Schindelin via GitGitGadget
  2022-06-27 18:31       ` [PATCH v4 01/16] bisect: verify that a bogus option won't try to start a bisection Johannes Schindelin via GitGitGadget
  2022-06-27 18:31       ` [PATCH v4 02/16] bisect run: fix the error message Johannes Schindelin via GitGitGadget
@ 2022-06-27 18:31       ` Johannes Schindelin via GitGitGadget
  2022-06-27 18:31       ` [PATCH v4 04/16] bisect--helper: retire the --no-log option Johannes Schindelin via GitGitGadget
                         ` (14 subsequent siblings)
  17 siblings, 0 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-06-27 18:31 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Bagas Sanjaya, Johannes Schindelin, Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

We already quote the command via `sq_quote_argv()`, no need to enclose
the result in an extraneous pair of single-quotes.

Pointed out by Elijah Newren.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/bisect--helper.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index cc38a009bdd..2345c9f773e 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1223,7 +1223,7 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
 
 		if (res < 0 || 128 <= res) {
 			error(_("bisect run failed: exit code %d from"
-				" '%s' is < 0 or >= 128"), res, command.buf);
+				" %s is < 0 or >= 128"), res, command.buf);
 			break;
 		}
 
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH v4 04/16] bisect--helper: retire the --no-log option
  2022-06-27 18:31     ` [PATCH v4 00/16] " Johannes Schindelin via GitGitGadget
                         ` (2 preceding siblings ...)
  2022-06-27 18:31       ` [PATCH v4 03/16] bisect: avoid double-quoting when printing the failed command Johannes Schindelin via GitGitGadget
@ 2022-06-27 18:31       ` Johannes Schindelin via GitGitGadget
  2022-06-27 18:31       ` [PATCH v4 05/16] bisect--helper: really retire --bisect-next-check Johannes Schindelin via GitGitGadget
                         ` (13 subsequent siblings)
  17 siblings, 0 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-06-27 18:31 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Bagas Sanjaya, Johannes Schindelin, Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

Turns out we actually never used it, anyway...

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/bisect--helper.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 2345c9f773e..8cfe3926dc7 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1292,7 +1292,7 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 		BISECT_VISUALIZE,
 		BISECT_RUN,
 	} cmdmode = 0;
-	int res = 0, nolog = 0;
+	int res = 0;
 	struct option options[] = {
 		OPT_CMDMODE(0, "bisect-reset", &cmdmode,
 			 N_("reset the bisection state"), BISECT_RESET),
@@ -1316,8 +1316,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 			 N_("visualize the bisection"), BISECT_VISUALIZE),
 		OPT_CMDMODE(0, "bisect-run", &cmdmode,
 			 N_("use <cmd>... to automatically bisect"), BISECT_RUN),
-		OPT_BOOL(0, "no-log", &nolog,
-			 N_("no log for BISECT_WRITE")),
 		OPT_END()
 	};
 	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH v4 05/16] bisect--helper: really retire --bisect-next-check
  2022-06-27 18:31     ` [PATCH v4 00/16] " Johannes Schindelin via GitGitGadget
                         ` (3 preceding siblings ...)
  2022-06-27 18:31       ` [PATCH v4 04/16] bisect--helper: retire the --no-log option Johannes Schindelin via GitGitGadget
@ 2022-06-27 18:31       ` Johannes Schindelin via GitGitGadget
  2022-06-27 18:31       ` [PATCH v4 06/16] bisect--helper: really retire `--bisect-autostart` Johannes Schindelin via GitGitGadget
                         ` (12 subsequent siblings)
  17 siblings, 0 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-06-27 18:31 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Bagas Sanjaya, Johannes Schindelin, Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

In 911aba14205 (bisect--helper: retire `--bisect-next-check` subcommand,
2021-09-13), we removed the usage string and the implementation, but not
actually the option.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/bisect--helper.c | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 8cfe3926dc7..75d008d7fa8 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1280,7 +1280,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 {
 	enum {
 		BISECT_RESET = 1,
-		BISECT_NEXT_CHECK,
 		BISECT_TERMS,
 		BISECT_START,
 		BISECT_AUTOSTART,
@@ -1296,8 +1295,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 	struct option options[] = {
 		OPT_CMDMODE(0, "bisect-reset", &cmdmode,
 			 N_("reset the bisection state"), BISECT_RESET),
-		OPT_CMDMODE(0, "bisect-next-check", &cmdmode,
-			 N_("check whether bad or good terms exist"), BISECT_NEXT_CHECK),
 		OPT_CMDMODE(0, "bisect-terms", &cmdmode,
 			 N_("print out the bisect terms"), BISECT_TERMS),
 		OPT_CMDMODE(0, "bisect-start", &cmdmode,
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH v4 06/16] bisect--helper: really retire `--bisect-autostart`
  2022-06-27 18:31     ` [PATCH v4 00/16] " Johannes Schindelin via GitGitGadget
                         ` (4 preceding siblings ...)
  2022-06-27 18:31       ` [PATCH v4 05/16] bisect--helper: really retire --bisect-next-check Johannes Schindelin via GitGitGadget
@ 2022-06-27 18:31       ` Johannes Schindelin via GitGitGadget
  2022-06-27 18:31       ` [PATCH v4 07/16] bisect--helper: using `--bisect-state` without an argument is a bug Johannes Schindelin via GitGitGadget
                         ` (11 subsequent siblings)
  17 siblings, 0 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-06-27 18:31 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Bagas Sanjaya, Johannes Schindelin, Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

Since b0f6494f70f (bisect--helper: retire `--bisect-autostart`
subcommand, 2020-10-15), the `--bisect-autostart` option is no more. But
we kept the `enum` value of the command mode around. Let's drop it, too.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/bisect--helper.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 75d008d7fa8..477aba811f0 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1282,7 +1282,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 		BISECT_RESET = 1,
 		BISECT_TERMS,
 		BISECT_START,
-		BISECT_AUTOSTART,
 		BISECT_NEXT,
 		BISECT_STATE,
 		BISECT_LOG,
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH v4 07/16] bisect--helper: using `--bisect-state` without an argument is a bug
  2022-06-27 18:31     ` [PATCH v4 00/16] " Johannes Schindelin via GitGitGadget
                         ` (5 preceding siblings ...)
  2022-06-27 18:31       ` [PATCH v4 06/16] bisect--helper: really retire `--bisect-autostart` Johannes Schindelin via GitGitGadget
@ 2022-06-27 18:31       ` Johannes Schindelin via GitGitGadget
  2022-06-27 18:31       ` [PATCH v4 08/16] bisect--helper: align the sub-command order with git-bisect.sh Johannes Schindelin via GitGitGadget
                         ` (10 subsequent siblings)
  17 siblings, 0 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-06-27 18:31 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Bagas Sanjaya, Johannes Schindelin, Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

The `bisect--helper` command is not expected to be used directly by the
user. Therefore, it is a bug if it receives no argument to the
`--bisect-state` command mode, not a user error. Which means that we
need to call `BUG()` instead of `die()`.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/bisect--helper.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 477aba811f0..45983a0a1fc 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -900,7 +900,7 @@ static enum bisect_error bisect_state(struct bisect_terms *terms, const char **a
 	struct oid_array revs = OID_ARRAY_INIT;
 
 	if (!argc)
-		return error(_("Please call `--bisect-state` with at least one argument"));
+		BUG("bisect_state() called without argument");
 
 	if (bisect_autostart(terms))
 		return BISECT_FAILED;
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH v4 08/16] bisect--helper: align the sub-command order with git-bisect.sh
  2022-06-27 18:31     ` [PATCH v4 00/16] " Johannes Schindelin via GitGitGadget
                         ` (6 preceding siblings ...)
  2022-06-27 18:31       ` [PATCH v4 07/16] bisect--helper: using `--bisect-state` without an argument is a bug Johannes Schindelin via GitGitGadget
@ 2022-06-27 18:31       ` Johannes Schindelin via GitGitGadget
  2022-06-27 18:31       ` [PATCH v4 09/16] bisect--helper: make `--bisect-state` optional Johannes Schindelin via GitGitGadget
                         ` (9 subsequent siblings)
  17 siblings, 0 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-06-27 18:31 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Bagas Sanjaya, Johannes Schindelin, Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

We are about to retire the shell implementation of `git bisect`, or
maybe better put: the remainder of the shell implementation (a shell of
a script, if you want).

In preparation for that, align the order of the sub-commands with the
way the outgoing implementation presents them to the user.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/bisect--helper.c | 76 ++++++++++++++++++++--------------------
 1 file changed, 38 insertions(+), 38 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 45983a0a1fc..2d6eafa2abd 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1279,37 +1279,37 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
 int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 {
 	enum {
-		BISECT_RESET = 1,
-		BISECT_TERMS,
-		BISECT_START,
-		BISECT_NEXT,
+		BISECT_START = 1,
 		BISECT_STATE,
-		BISECT_LOG,
-		BISECT_REPLAY,
+		BISECT_TERMS,
 		BISECT_SKIP,
+		BISECT_NEXT,
+		BISECT_RESET,
 		BISECT_VISUALIZE,
+		BISECT_REPLAY,
+		BISECT_LOG,
 		BISECT_RUN,
 	} cmdmode = 0;
 	int res = 0;
 	struct option options[] = {
-		OPT_CMDMODE(0, "bisect-reset", &cmdmode,
-			 N_("reset the bisection state"), BISECT_RESET),
-		OPT_CMDMODE(0, "bisect-terms", &cmdmode,
-			 N_("print out the bisect terms"), BISECT_TERMS),
 		OPT_CMDMODE(0, "bisect-start", &cmdmode,
 			 N_("start the bisect session"), BISECT_START),
-		OPT_CMDMODE(0, "bisect-next", &cmdmode,
-			 N_("find the next bisection commit"), BISECT_NEXT),
 		OPT_CMDMODE(0, "bisect-state", &cmdmode,
 			 N_("mark the state of ref (or refs)"), BISECT_STATE),
-		OPT_CMDMODE(0, "bisect-log", &cmdmode,
-			 N_("list the bisection steps so far"), BISECT_LOG),
-		OPT_CMDMODE(0, "bisect-replay", &cmdmode,
-			 N_("replay the bisection process from the given file"), BISECT_REPLAY),
+		OPT_CMDMODE(0, "bisect-terms", &cmdmode,
+			 N_("print out the bisect terms"), BISECT_TERMS),
 		OPT_CMDMODE(0, "bisect-skip", &cmdmode,
 			 N_("skip some commits for checkout"), BISECT_SKIP),
+		OPT_CMDMODE(0, "bisect-next", &cmdmode,
+			 N_("find the next bisection commit"), BISECT_NEXT),
+		OPT_CMDMODE(0, "bisect-reset", &cmdmode,
+			 N_("reset the bisection state"), BISECT_RESET),
 		OPT_CMDMODE(0, "bisect-visualize", &cmdmode,
 			 N_("visualize the bisection"), BISECT_VISUALIZE),
+		OPT_CMDMODE(0, "bisect-replay", &cmdmode,
+			 N_("replay the bisection process from the given file"), BISECT_REPLAY),
+		OPT_CMDMODE(0, "bisect-log", &cmdmode,
+			 N_("list the bisection steps so far"), BISECT_LOG),
 		OPT_CMDMODE(0, "bisect-run", &cmdmode,
 			 N_("use <cmd>... to automatically bisect"), BISECT_RUN),
 		OPT_END()
@@ -1324,19 +1324,24 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 		usage_with_options(git_bisect_helper_usage, options);
 
 	switch (cmdmode) {
-	case BISECT_RESET:
-		if (argc > 1)
-			return error(_("--bisect-reset requires either no argument or a commit"));
-		res = bisect_reset(argc ? argv[0] : NULL);
+	case BISECT_START:
+		set_terms(&terms, "bad", "good");
+		res = bisect_start(&terms, argv, argc);
+		break;
+	case BISECT_STATE:
+		set_terms(&terms, "bad", "good");
+		get_terms(&terms);
+		res = bisect_state(&terms, argv, argc);
 		break;
 	case BISECT_TERMS:
 		if (argc > 1)
 			return error(_("--bisect-terms requires 0 or 1 argument"));
 		res = bisect_terms(&terms, argc == 1 ? argv[0] : NULL);
 		break;
-	case BISECT_START:
+	case BISECT_SKIP:
 		set_terms(&terms, "bad", "good");
-		res = bisect_start(&terms, argv, argc);
+		get_terms(&terms);
+		res = bisect_skip(&terms, argv, argc);
 		break;
 	case BISECT_NEXT:
 		if (argc)
@@ -1344,15 +1349,14 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 		get_terms(&terms);
 		res = bisect_next(&terms, prefix);
 		break;
-	case BISECT_STATE:
-		set_terms(&terms, "bad", "good");
-		get_terms(&terms);
-		res = bisect_state(&terms, argv, argc);
+	case BISECT_RESET:
+		if (argc > 1)
+			return error(_("--bisect-reset requires either no argument or a commit"));
+		res = bisect_reset(argc ? argv[0] : NULL);
 		break;
-	case BISECT_LOG:
-		if (argc)
-			return error(_("--bisect-log requires 0 arguments"));
-		res = bisect_log();
+	case BISECT_VISUALIZE:
+		get_terms(&terms);
+		res = bisect_visualize(&terms, argv, argc);
 		break;
 	case BISECT_REPLAY:
 		if (argc != 1)
@@ -1360,14 +1364,10 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 		set_terms(&terms, "bad", "good");
 		res = bisect_replay(&terms, argv[0]);
 		break;
-	case BISECT_SKIP:
-		set_terms(&terms, "bad", "good");
-		get_terms(&terms);
-		res = bisect_skip(&terms, argv, argc);
-		break;
-	case BISECT_VISUALIZE:
-		get_terms(&terms);
-		res = bisect_visualize(&terms, argv, argc);
+	case BISECT_LOG:
+		if (argc)
+			return error(_("--bisect-log requires 0 arguments"));
+		res = bisect_log();
 		break;
 	case BISECT_RUN:
 		if (!argc)
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH v4 09/16] bisect--helper: make `--bisect-state` optional
  2022-06-27 18:31     ` [PATCH v4 00/16] " Johannes Schindelin via GitGitGadget
                         ` (7 preceding siblings ...)
  2022-06-27 18:31       ` [PATCH v4 08/16] bisect--helper: align the sub-command order with git-bisect.sh Johannes Schindelin via GitGitGadget
@ 2022-06-27 18:31       ` Johannes Schindelin via GitGitGadget
  2022-06-27 18:31       ` [PATCH v4 10/16] bisect--helper: move the `BISECT_STATE` case to the end Johannes Schindelin via GitGitGadget
                         ` (8 subsequent siblings)
  17 siblings, 0 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-06-27 18:31 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Bagas Sanjaya, Johannes Schindelin, Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

In preparation for making `git bisect` a real built-in, let's prepare
the `bisect--helper` built-in to handle `git bisect--helper good` and
`git bisect--helper bad`, i.e. do not require the `--bisect-state`
option to be passed explicitly.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/bisect--helper.c | 14 ++++++++------
 git-bisect.sh            |  2 +-
 2 files changed, 9 insertions(+), 7 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 2d6eafa2abd..1b1ce0941ff 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -26,8 +26,8 @@ static const char * const git_bisect_helper_usage[] = {
 	N_("git bisect--helper --bisect-start [--term-{new,bad}=<term> --term-{old,good}=<term>]"
 					    " [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<paths>...]"),
 	"git bisect--helper --bisect-next",
-	N_("git bisect--helper --bisect-state (bad|new) [<rev>]"),
-	N_("git bisect--helper --bisect-state (good|old) [<rev>...]"),
+	N_("git bisect--helper [--bisect-state] (bad|new) [<rev>]"),
+	N_("git bisect--helper [--bisect-state] (good|old) [<rev>...]"),
 	N_("git bisect--helper --bisect-replay <filename>"),
 	N_("git bisect--helper --bisect-skip [(<rev>|<range>)...]"),
 	"git bisect--helper --bisect-visualize",
@@ -1320,10 +1320,7 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 			     git_bisect_helper_usage,
 			     PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN);
 
-	if (!cmdmode)
-		usage_with_options(git_bisect_helper_usage, options);
-
-	switch (cmdmode) {
+	switch (cmdmode ? cmdmode : BISECT_STATE) {
 	case BISECT_START:
 		set_terms(&terms, "bad", "good");
 		res = bisect_start(&terms, argv, argc);
@@ -1331,6 +1328,11 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 	case BISECT_STATE:
 		set_terms(&terms, "bad", "good");
 		get_terms(&terms);
+		if (!cmdmode &&
+		    (!argc || check_and_set_terms(&terms, argv[0]))) {
+			char *msg = xstrfmt(_("unknown command: '%s'"), argv[0]);
+			usage_msg_opt(msg, git_bisect_helper_usage, options);
+		}
 		res = bisect_state(&terms, argv, argc);
 		break;
 	case BISECT_TERMS:
diff --git a/git-bisect.sh b/git-bisect.sh
index 405cf76f2a3..fbf56649d7d 100755
--- a/git-bisect.sh
+++ b/git-bisect.sh
@@ -60,7 +60,7 @@ case "$#" in
 	start)
 		git bisect--helper --bisect-start "$@" ;;
 	bad|good|new|old|"$TERM_BAD"|"$TERM_GOOD")
-		git bisect--helper --bisect-state "$cmd" "$@" ;;
+		git bisect--helper "$cmd" "$@" ;;
 	skip)
 		git bisect--helper --bisect-skip "$@" || exit;;
 	next)
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH v4 10/16] bisect--helper: move the `BISECT_STATE` case to the end
  2022-06-27 18:31     ` [PATCH v4 00/16] " Johannes Schindelin via GitGitGadget
                         ` (8 preceding siblings ...)
  2022-06-27 18:31       ` [PATCH v4 09/16] bisect--helper: make `--bisect-state` optional Johannes Schindelin via GitGitGadget
@ 2022-06-27 18:31       ` Johannes Schindelin via GitGitGadget
  2022-06-27 18:31       ` [PATCH v4 11/16] bisect--helper: return only correct exit codes in `cmd_*()` Johannes Schindelin via GitGitGadget
                         ` (7 subsequent siblings)
  17 siblings, 0 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-06-27 18:31 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Bagas Sanjaya, Johannes Schindelin, Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

In preparation for replacing the command-mode parsing in
`bisect--helper` with an if/else if/else chain, let's move the one
command that will be implicit (i.e. what will become the final `else`
without any `if`) to the end.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/bisect--helper.c | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 1b1ce0941ff..22099b9ebe2 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1325,16 +1325,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 		set_terms(&terms, "bad", "good");
 		res = bisect_start(&terms, argv, argc);
 		break;
-	case BISECT_STATE:
-		set_terms(&terms, "bad", "good");
-		get_terms(&terms);
-		if (!cmdmode &&
-		    (!argc || check_and_set_terms(&terms, argv[0]))) {
-			char *msg = xstrfmt(_("unknown command: '%s'"), argv[0]);
-			usage_msg_opt(msg, git_bisect_helper_usage, options);
-		}
-		res = bisect_state(&terms, argv, argc);
-		break;
 	case BISECT_TERMS:
 		if (argc > 1)
 			return error(_("--bisect-terms requires 0 or 1 argument"));
@@ -1377,6 +1367,16 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 		get_terms(&terms);
 		res = bisect_run(&terms, argv, argc);
 		break;
+	case BISECT_STATE:
+		set_terms(&terms, "bad", "good");
+		get_terms(&terms);
+		if (!cmdmode &&
+		    (!argc || check_and_set_terms(&terms, argv[0]))) {
+			char *msg = xstrfmt(_("unknown command: '%s'"), argv[0]);
+			usage_msg_opt(msg, git_bisect_helper_usage, options);
+		}
+		res = bisect_state(&terms, argv, argc);
+		break;
 	default:
 		BUG("unknown subcommand %d", cmdmode);
 	}
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH v4 11/16] bisect--helper: return only correct exit codes in `cmd_*()`
  2022-06-27 18:31     ` [PATCH v4 00/16] " Johannes Schindelin via GitGitGadget
                         ` (9 preceding siblings ...)
  2022-06-27 18:31       ` [PATCH v4 10/16] bisect--helper: move the `BISECT_STATE` case to the end Johannes Schindelin via GitGitGadget
@ 2022-06-27 18:31       ` Johannes Schindelin via GitGitGadget
  2022-06-27 20:09         ` Ævar Arnfjörð Bjarmason
  2022-06-27 18:31       ` [PATCH v4 12/16] bisect: teach the `bisect--helper` command to show the correct usage strings Johannes Schindelin via GitGitGadget
                         ` (6 subsequent siblings)
  17 siblings, 1 reply; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-06-27 18:31 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Bagas Sanjaya, Johannes Schindelin, Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

Exit codes cannot be negative, but `error()` returns -1.

Let's just go with the common pattern and call `die()` in
`cmd_bisect__helper()` when incorrect arguments were detected.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/bisect--helper.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 22099b9ebe2..86195058cd5 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1327,7 +1327,7 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 		break;
 	case BISECT_TERMS:
 		if (argc > 1)
-			return error(_("--bisect-terms requires 0 or 1 argument"));
+			die(_("--bisect-terms requires 0 or 1 argument"));
 		res = bisect_terms(&terms, argc == 1 ? argv[0] : NULL);
 		break;
 	case BISECT_SKIP:
@@ -1337,13 +1337,13 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 		break;
 	case BISECT_NEXT:
 		if (argc)
-			return error(_("--bisect-next requires 0 arguments"));
+			die(_("--bisect-next requires 0 arguments"));
 		get_terms(&terms);
 		res = bisect_next(&terms, prefix);
 		break;
 	case BISECT_RESET:
 		if (argc > 1)
-			return error(_("--bisect-reset requires either no argument or a commit"));
+			die(_("--bisect-reset requires either no argument or a commit"));
 		res = bisect_reset(argc ? argv[0] : NULL);
 		break;
 	case BISECT_VISUALIZE:
@@ -1352,18 +1352,18 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 		break;
 	case BISECT_REPLAY:
 		if (argc != 1)
-			return error(_("no logfile given"));
+			die(_("no logfile given"));
 		set_terms(&terms, "bad", "good");
 		res = bisect_replay(&terms, argv[0]);
 		break;
 	case BISECT_LOG:
 		if (argc)
-			return error(_("--bisect-log requires 0 arguments"));
+			die(_("--bisect-log requires 0 arguments"));
 		res = bisect_log();
 		break;
 	case BISECT_RUN:
 		if (!argc)
-			return error(_("bisect run failed: no command provided."));
+			die(_("bisect run failed: no command provided."));
 		get_terms(&terms);
 		res = bisect_run(&terms, argv, argc);
 		break;
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH v4 12/16] bisect: teach the `bisect--helper` command to show the correct usage strings
  2022-06-27 18:31     ` [PATCH v4 00/16] " Johannes Schindelin via GitGitGadget
                         ` (10 preceding siblings ...)
  2022-06-27 18:31       ` [PATCH v4 11/16] bisect--helper: return only correct exit codes in `cmd_*()` Johannes Schindelin via GitGitGadget
@ 2022-06-27 18:31       ` Johannes Schindelin via GitGitGadget
  2022-06-27 22:11         ` Junio C Hamano
  2022-06-27 18:31       ` [PATCH v4 13/16] bisect: move even the command-line parsing to `bisect--helper` Johannes Schindelin via GitGitGadget
                         ` (5 subsequent siblings)
  17 siblings, 1 reply; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-06-27 18:31 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Bagas Sanjaya, Johannes Schindelin, Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

In preparation for `bisect--helper` graduating to become the actual
`bisect` command, we hereby teach it to print the very same usage
strings as the scripted `git-bisect.sh` does.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/bisect--helper.c | 65 +++++++++++++++++++++++++++++-----------
 1 file changed, 47 insertions(+), 18 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 86195058cd5..1914aa7c69f 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1,6 +1,5 @@
 #include "builtin.h"
 #include "cache.h"
-#include "parse-options.h"
 #include "bisect.h"
 #include "refs.h"
 #include "dir.h"
@@ -20,18 +19,46 @@ static GIT_PATH_FUNC(git_path_bisect_names, "BISECT_NAMES")
 static GIT_PATH_FUNC(git_path_bisect_first_parent, "BISECT_FIRST_PARENT")
 static GIT_PATH_FUNC(git_path_bisect_run, "BISECT_RUN")
 
-static const char * const git_bisect_helper_usage[] = {
-	N_("git bisect--helper --bisect-reset [<commit>]"),
-	"git bisect--helper --bisect-terms [--term-good | --term-old | --term-bad | --term-new]",
-	N_("git bisect--helper --bisect-start [--term-{new,bad}=<term> --term-{old,good}=<term>]"
-					    " [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<paths>...]"),
-	"git bisect--helper --bisect-next",
-	N_("git bisect--helper [--bisect-state] (bad|new) [<rev>]"),
-	N_("git bisect--helper [--bisect-state] (good|old) [<rev>...]"),
-	N_("git bisect--helper --bisect-replay <filename>"),
-	N_("git bisect--helper --bisect-skip [(<rev>|<range>)...]"),
-	"git bisect--helper --bisect-visualize",
-	N_("git bisect--helper --bisect-run <cmd>..."),
+static const char *bisect_usage =
+	N_("git bisect [help|start|bad|good|new|old|terms|skip|next|reset|"
+	   "visualize|view|replay|log|run]");
+
+static const char * const bisect_long_usage[] = {
+	N_("git bisect [help|start|bad|good|new|old|terms|skip|next|reset|"
+	   "visualize|view|replay|log|run]\n"
+	   "\n"
+	   "git bisect help\n"
+	   "\tprint this long help message.\n"
+	   "git bisect start [--term-{new,bad}=<term> "
+		"--term-{old,good}=<term>]\n"
+	   "\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	a revision after change in a given property.\n"
+	   "git bisect (good|old) [<rev>...]\n"
+	   "\tmark <rev>... known-good revisions/\n"
+	   "\t	revisions 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."),
 	NULL
 };
 
@@ -1317,7 +1344,7 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
 
 	argc = parse_options(argc, argv, prefix, options,
-			     git_bisect_helper_usage,
+			     bisect_long_usage,
 			     PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN);
 
 	switch (cmdmode ? cmdmode : BISECT_STATE) {
@@ -1368,13 +1395,15 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 		res = bisect_run(&terms, argv, argc);
 		break;
 	case BISECT_STATE:
+		if (argc &&
+		    !file_is_not_empty(git_path_bisect_start()) &&
+		    !one_of(argv[0], "bad", "good", "new", "old", NULL))
+			usage(bisect_usage);
 		set_terms(&terms, "bad", "good");
 		get_terms(&terms);
 		if (!cmdmode &&
-		    (!argc || check_and_set_terms(&terms, argv[0]))) {
-			char *msg = xstrfmt(_("unknown command: '%s'"), argv[0]);
-			usage_msg_opt(msg, git_bisect_helper_usage, options);
-		}
+		    (!argc || check_and_set_terms(&terms, argv[0])))
+			usage(bisect_usage);
 		res = bisect_state(&terms, argv, argc);
 		break;
 	default:
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH v4 13/16] bisect: move even the command-line parsing to `bisect--helper`
  2022-06-27 18:31     ` [PATCH v4 00/16] " Johannes Schindelin via GitGitGadget
                         ` (11 preceding siblings ...)
  2022-06-27 18:31       ` [PATCH v4 12/16] bisect: teach the `bisect--helper` command to show the correct usage strings Johannes Schindelin via GitGitGadget
@ 2022-06-27 18:31       ` Johannes Schindelin via GitGitGadget
  2022-06-27 18:31       ` [PATCH v4 14/16] Turn `git bisect` into a full built-in Johannes Schindelin via GitGitGadget
                         ` (4 subsequent siblings)
  17 siblings, 0 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-06-27 18:31 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Bagas Sanjaya, Johannes Schindelin, Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

On our journey to a fully built-in `git bisect`, this is the
last step.

Side note: The `parse-options` API is not at all set up to parse
subcommands such as `git bisect start`, `git bisect reset`, etc.
Instead of fighting an up-hill battle trying to "fix" that, we simply
roll the same type of manual subcommand parsing as we already do e.g.
in `builtin/bundle.c`.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/bisect--helper.c | 103 +++++++++++----------------------------
 git-bisect.sh            |  49 +------------------
 2 files changed, 30 insertions(+), 122 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 1914aa7c69f..7232d650905 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -23,7 +23,7 @@ static const char *bisect_usage =
 	N_("git bisect [help|start|bad|good|new|old|terms|skip|next|reset|"
 	   "visualize|view|replay|log|run]");
 
-static const char * const bisect_long_usage[] = {
+static const char *bisect_long_usage =
 	N_("git bisect [help|start|bad|good|new|old|terms|skip|next|reset|"
 	   "visualize|view|replay|log|run]\n"
 	   "\n"
@@ -58,9 +58,7 @@ static const char * const bisect_long_usage[] = {
 	   "git bisect run <cmd>...\n"
 	   "\tuse <cmd>... to automatically bisect.\n"
 	   "\n"
-	   "Please use \"git help bisect\" to get the full man page."),
-	NULL
-};
+	   "Please use \"git help bisect\" to get the full man page.");
 
 struct add_bisect_ref_data {
 	struct rev_info *revs;
@@ -1305,110 +1303,67 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
 
 int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 {
-	enum {
-		BISECT_START = 1,
-		BISECT_STATE,
-		BISECT_TERMS,
-		BISECT_SKIP,
-		BISECT_NEXT,
-		BISECT_RESET,
-		BISECT_VISUALIZE,
-		BISECT_REPLAY,
-		BISECT_LOG,
-		BISECT_RUN,
-	} cmdmode = 0;
 	int res = 0;
-	struct option options[] = {
-		OPT_CMDMODE(0, "bisect-start", &cmdmode,
-			 N_("start the bisect session"), BISECT_START),
-		OPT_CMDMODE(0, "bisect-state", &cmdmode,
-			 N_("mark the state of ref (or refs)"), BISECT_STATE),
-		OPT_CMDMODE(0, "bisect-terms", &cmdmode,
-			 N_("print out the bisect terms"), BISECT_TERMS),
-		OPT_CMDMODE(0, "bisect-skip", &cmdmode,
-			 N_("skip some commits for checkout"), BISECT_SKIP),
-		OPT_CMDMODE(0, "bisect-next", &cmdmode,
-			 N_("find the next bisection commit"), BISECT_NEXT),
-		OPT_CMDMODE(0, "bisect-reset", &cmdmode,
-			 N_("reset the bisection state"), BISECT_RESET),
-		OPT_CMDMODE(0, "bisect-visualize", &cmdmode,
-			 N_("visualize the bisection"), BISECT_VISUALIZE),
-		OPT_CMDMODE(0, "bisect-replay", &cmdmode,
-			 N_("replay the bisection process from the given file"), BISECT_REPLAY),
-		OPT_CMDMODE(0, "bisect-log", &cmdmode,
-			 N_("list the bisection steps so far"), BISECT_LOG),
-		OPT_CMDMODE(0, "bisect-run", &cmdmode,
-			 N_("use <cmd>... to automatically bisect"), BISECT_RUN),
-		OPT_END()
-	};
 	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
+	const char *command = argc > 1 ? argv[1] : "help";
+
+	if (!strcmp("-h", command) || !strcmp("help", command))
+		usage(bisect_long_usage);
 
-	argc = parse_options(argc, argv, prefix, options,
-			     bisect_long_usage,
-			     PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN);
+	argc -= 2;
+	argv += 2;
 
-	switch (cmdmode ? cmdmode : BISECT_STATE) {
-	case BISECT_START:
+	if (!strcmp("start", command)) {
 		set_terms(&terms, "bad", "good");
 		res = bisect_start(&terms, argv, argc);
-		break;
-	case BISECT_TERMS:
+	} else if (!strcmp("terms", command)) {
 		if (argc > 1)
-			die(_("--bisect-terms requires 0 or 1 argument"));
+			die(_("'terms' requires 0 or 1 argument"));
 		res = bisect_terms(&terms, argc == 1 ? argv[0] : NULL);
-		break;
-	case BISECT_SKIP:
+	} else if (!strcmp("skip", command)) {
 		set_terms(&terms, "bad", "good");
 		get_terms(&terms);
 		res = bisect_skip(&terms, argv, argc);
-		break;
-	case BISECT_NEXT:
+	} else if (!strcmp("next", command)) {
 		if (argc)
-			die(_("--bisect-next requires 0 arguments"));
+			die(_("'next' requires 0 arguments"));
 		get_terms(&terms);
 		res = bisect_next(&terms, prefix);
-		break;
-	case BISECT_RESET:
+	} else if (!strcmp("reset", command)) {
 		if (argc > 1)
-			die(_("--bisect-reset requires either no argument or a commit"));
+			die(_("'reset' requires either no argument or a commit"));
 		res = bisect_reset(argc ? argv[0] : NULL);
-		break;
-	case BISECT_VISUALIZE:
+	} else if (one_of(command, "visualize", "view", NULL)) {
 		get_terms(&terms);
 		res = bisect_visualize(&terms, argv, argc);
-		break;
-	case BISECT_REPLAY:
+	} else if (!strcmp("replay", command)) {
 		if (argc != 1)
 			die(_("no logfile given"));
 		set_terms(&terms, "bad", "good");
 		res = bisect_replay(&terms, argv[0]);
-		break;
-	case BISECT_LOG:
+	} else if (!strcmp("log", command)) {
 		if (argc)
-			die(_("--bisect-log requires 0 arguments"));
+			die(_("'log' requires 0 arguments"));
 		res = bisect_log();
-		break;
-	case BISECT_RUN:
+	} else if (!strcmp("run", command)) {
 		if (!argc)
 			die(_("bisect run failed: no command provided."));
 		get_terms(&terms);
 		res = bisect_run(&terms, argv, argc);
-		break;
-	case BISECT_STATE:
-		if (argc &&
-		    !file_is_not_empty(git_path_bisect_start()) &&
-		    !one_of(argv[0], "bad", "good", "new", "old", NULL))
+	} else {
+		if (!file_is_not_empty(git_path_bisect_start()) &&
+		    !one_of(command, "bad", "good", "new", "old", NULL))
 			usage(bisect_usage);
 		set_terms(&terms, "bad", "good");
 		get_terms(&terms);
-		if (!cmdmode &&
-		    (!argc || check_and_set_terms(&terms, argv[0])))
+		if (check_and_set_terms(&terms, command))
 			usage(bisect_usage);
+		/* shift the `command` back in */
+		argc++;
+		argv--;
 		res = bisect_state(&terms, argv, argc);
-		break;
-	default:
-		BUG("unknown subcommand %d", cmdmode);
 	}
+
 	free_terms(&terms);
 
 	/*
diff --git a/git-bisect.sh b/git-bisect.sh
index fbf56649d7d..028d39cd9ce 100755
--- a/git-bisect.sh
+++ b/git-bisect.sh
@@ -34,51 +34,4 @@ Please use "git help bisect" to get the full man page.'
 OPTIONS_SPEC=
 . git-sh-setup
 
-TERM_BAD=bad
-TERM_GOOD=good
-
-get_terms () {
-	if test -s "$GIT_DIR/BISECT_TERMS"
-	then
-		{
-		read TERM_BAD
-		read TERM_GOOD
-		} <"$GIT_DIR/BISECT_TERMS"
-	fi
-}
-
-case "$#" in
-0)
-	usage ;;
-*)
-	cmd="$1"
-	get_terms
-	shift
-	case "$cmd" in
-	help)
-		git bisect -h ;;
-	start)
-		git bisect--helper --bisect-start "$@" ;;
-	bad|good|new|old|"$TERM_BAD"|"$TERM_GOOD")
-		git bisect--helper "$cmd" "$@" ;;
-	skip)
-		git bisect--helper --bisect-skip "$@" || exit;;
-	next)
-		# Not sure we want "next" at the UI level anymore.
-		git bisect--helper --bisect-next "$@" || exit ;;
-	visualize|view)
-		git bisect--helper --bisect-visualize "$@" || exit;;
-	reset)
-		git bisect--helper --bisect-reset "$@" ;;
-	replay)
-		git bisect--helper --bisect-replay "$@" || exit;;
-	log)
-		git bisect--helper --bisect-log || exit ;;
-	run)
-		git bisect--helper --bisect-run "$@" || exit;;
-	terms)
-		git bisect--helper --bisect-terms "$@" || exit;;
-	*)
-		usage ;;
-	esac
-esac
+exec git bisect--helper "$@"
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH v4 14/16] Turn `git bisect` into a full built-in
  2022-06-27 18:31     ` [PATCH v4 00/16] " Johannes Schindelin via GitGitGadget
                         ` (12 preceding siblings ...)
  2022-06-27 18:31       ` [PATCH v4 13/16] bisect: move even the command-line parsing to `bisect--helper` Johannes Schindelin via GitGitGadget
@ 2022-06-27 18:31       ` Johannes Schindelin via GitGitGadget
  2022-06-27 22:13         ` Junio C Hamano
  2022-06-27 18:31       ` [PATCH v4 15/16] bisect: remove Cogito-related code Johannes Schindelin via GitGitGadget
                         ` (3 subsequent siblings)
  17 siblings, 1 reply; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-06-27 18:31 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Bagas Sanjaya, Johannes Schindelin, Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

Now that the shell script hands off to the `bisect--helper` to do
_anything_ (except to show the help), it is but a tiny step to let the
helper implement the actual `git bisect` command instead.

This retires `git-bisect.sh`, concluding a multi-year journey that many
hands helped with, in particular Pranit Bauna, Tanushree Tumane and
Miriam Rubio.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 Makefile                               |  3 +--
 builtin.h                              |  2 +-
 builtin/{bisect--helper.c => bisect.c} |  2 +-
 git-bisect.sh                          | 37 --------------------------
 git.c                                  |  2 +-
 5 files changed, 4 insertions(+), 42 deletions(-)
 rename builtin/{bisect--helper.c => bisect.c} (99%)
 delete mode 100755 git-bisect.sh

diff --git a/Makefile b/Makefile
index 04d0fd1fe60..3462bad4f15 100644
--- a/Makefile
+++ b/Makefile
@@ -619,7 +619,6 @@ THIRD_PARTY_SOURCES =
 # interactive shell sessions without exporting it.
 unexport CDPATH
 
-SCRIPT_SH += git-bisect.sh
 SCRIPT_SH += git-difftool--helper.sh
 SCRIPT_SH += git-filter-branch.sh
 SCRIPT_SH += git-merge-octopus.sh
@@ -1119,7 +1118,7 @@ BUILTIN_OBJS += builtin/am.o
 BUILTIN_OBJS += builtin/annotate.o
 BUILTIN_OBJS += builtin/apply.o
 BUILTIN_OBJS += builtin/archive.o
-BUILTIN_OBJS += builtin/bisect--helper.o
+BUILTIN_OBJS += builtin/bisect.o
 BUILTIN_OBJS += builtin/blame.o
 BUILTIN_OBJS += builtin/branch.o
 BUILTIN_OBJS += builtin/bugreport.o
diff --git a/builtin.h b/builtin.h
index 40e9ecc8485..b9470f8ab4f 100644
--- a/builtin.h
+++ b/builtin.h
@@ -116,7 +116,7 @@ int cmd_am(int argc, const char **argv, const char *prefix);
 int cmd_annotate(int argc, const char **argv, const char *prefix);
 int cmd_apply(int argc, const char **argv, const char *prefix);
 int cmd_archive(int argc, const char **argv, const char *prefix);
-int cmd_bisect__helper(int argc, const char **argv, const char *prefix);
+int cmd_bisect(int argc, const char **argv, const char *prefix);
 int cmd_blame(int argc, const char **argv, const char *prefix);
 int cmd_branch(int argc, const char **argv, const char *prefix);
 int cmd_bugreport(int argc, const char **argv, const char *prefix);
diff --git a/builtin/bisect--helper.c b/builtin/bisect.c
similarity index 99%
rename from builtin/bisect--helper.c
rename to builtin/bisect.c
index 7232d650905..380fef852f3 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect.c
@@ -1301,7 +1301,7 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
 	return res;
 }
 
-int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
+int cmd_bisect(int argc, const char **argv, const char *prefix)
 {
 	int res = 0;
 	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
diff --git a/git-bisect.sh b/git-bisect.sh
deleted file mode 100755
index 028d39cd9ce..00000000000
--- a/git-bisect.sh
+++ /dev/null
@@ -1,37 +0,0 @@
-#!/bin/sh
-
-USAGE='[help|start|bad|good|new|old|terms|skip|next|reset|visualize|view|replay|log|run]'
-LONG_USAGE='git bisect help
-	print this long help message.
-git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>]
-		 [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<pathspec>...]
-	reset bisect state and start bisection.
-git bisect (bad|new) [<rev>]
-	mark <rev> a known-bad revision/
-		a revision after change in a given property.
-git bisect (good|old) [<rev>...]
-	mark <rev>... known-good revisions/
-		revisions before change in a given property.
-git bisect terms [--term-good | --term-bad]
-	show the terms used for old and new commits (default: bad, good)
-git bisect skip [(<rev>|<range>)...]
-	mark <rev>... untestable revisions.
-git bisect next
-	find next bisection to test and check it out.
-git bisect reset [<commit>]
-	finish bisection search and go back to commit.
-git bisect (visualize|view)
-	show bisect status in gitk.
-git bisect replay <logfile>
-	replay bisection log.
-git bisect log
-	show bisect log.
-git bisect run <cmd>...
-	use <cmd>... to automatically bisect.
-
-Please use "git help bisect" to get the full man page.'
-
-OPTIONS_SPEC=
-. git-sh-setup
-
-exec git bisect--helper "$@"
diff --git a/git.c b/git.c
index d7a7a82008b..1ad501058a8 100644
--- a/git.c
+++ b/git.c
@@ -492,7 +492,7 @@ static struct cmd_struct commands[] = {
 	{ "annotate", cmd_annotate, RUN_SETUP | NO_PARSEOPT },
 	{ "apply", cmd_apply, RUN_SETUP_GENTLY },
 	{ "archive", cmd_archive, RUN_SETUP_GENTLY },
-	{ "bisect--helper", cmd_bisect__helper, RUN_SETUP },
+	{ "bisect", cmd_bisect, RUN_SETUP },
 	{ "blame", cmd_blame, RUN_SETUP },
 	{ "branch", cmd_branch, RUN_SETUP | DELAY_PAGER_CONFIG },
 	{ "bugreport", cmd_bugreport, RUN_SETUP_GENTLY },
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH v4 15/16] bisect: remove Cogito-related code
  2022-06-27 18:31     ` [PATCH v4 00/16] " Johannes Schindelin via GitGitGadget
                         ` (13 preceding siblings ...)
  2022-06-27 18:31       ` [PATCH v4 14/16] Turn `git bisect` into a full built-in Johannes Schindelin via GitGitGadget
@ 2022-06-27 18:31       ` Johannes Schindelin via GitGitGadget
  2022-06-27 22:18         ` Junio C Hamano
  2022-06-27 18:31       ` [PATCH v4 16/16] bisect: no longer try to clean up left-over `.git/head-name` files Johannes Schindelin via GitGitGadget
                         ` (2 subsequent siblings)
  17 siblings, 1 reply; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-06-27 18:31 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Bagas Sanjaya, Johannes Schindelin, Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

Once upon a time, there was this idea that Git would not actually be a
single coherent program, but rather a set of low-level programs that
users cobble together via shell scripts, or develop high-level user
interfaces for Git, or both.

Cogito was such a high-level user interface, incidentally implemented
via shell scripts that cobble together Git calls.

It did turn out relatively quickly that Git would much rather provide a
useful high-level user interface itself.

As of April 19th, 2007, Cogito was therefore discontinued (see
https://lore.kernel.org/git/20070419124648.GL4489@pasky.or.cz/).

Nevertheless, for almost 15 years after that announcement, Git carried
special code in `git bisect` to accommodate Cogito.

Since it is beyond doubt that there are no more Cogito users, let's
remove the last remnant of Cogito-accommodating code.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/bisect.c | 8 --------
 1 file changed, 8 deletions(-)

diff --git a/builtin/bisect.c b/builtin/bisect.c
index 380fef852f3..47103ebf3f2 100644
--- a/builtin/bisect.c
+++ b/builtin/bisect.c
@@ -14,7 +14,6 @@ static GIT_PATH_FUNC(git_path_bisect_expected_rev, "BISECT_EXPECTED_REV")
 static GIT_PATH_FUNC(git_path_bisect_ancestors_ok, "BISECT_ANCESTORS_OK")
 static GIT_PATH_FUNC(git_path_bisect_start, "BISECT_START")
 static GIT_PATH_FUNC(git_path_bisect_log, "BISECT_LOG")
-static GIT_PATH_FUNC(git_path_head_name, "head-name")
 static GIT_PATH_FUNC(git_path_bisect_names, "BISECT_NAMES")
 static GIT_PATH_FUNC(git_path_bisect_first_parent, "BISECT_FIRST_PARENT")
 static GIT_PATH_FUNC(git_path_bisect_run, "BISECT_RUN")
@@ -809,13 +808,6 @@ static enum bisect_error bisect_start(struct bisect_terms *terms, const char **a
 			strbuf_addstr(&start_head, oid_to_hex(&head_oid));
 		} else if (!get_oid(head, &head_oid) &&
 			   skip_prefix(head, "refs/heads/", &head)) {
-			/*
-			 * This error message should only be triggered by
-			 * cogito usage, and cogito users should understand
-			 * it relates to cg-seek.
-			 */
-			if (!is_empty_or_missing_file(git_path_head_name()))
-				return error(_("won't bisect on cg-seek'ed tree"));
 			strbuf_addstr(&start_head, head);
 		} else {
 			return error(_("bad HEAD - strange symbolic ref"));
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH v4 16/16] bisect: no longer try to clean up left-over `.git/head-name` files
  2022-06-27 18:31     ` [PATCH v4 00/16] " Johannes Schindelin via GitGitGadget
                         ` (14 preceding siblings ...)
  2022-06-27 18:31       ` [PATCH v4 15/16] bisect: remove Cogito-related code Johannes Schindelin via GitGitGadget
@ 2022-06-27 18:31       ` Johannes Schindelin via GitGitGadget
  2022-06-27 19:45       ` [PATCH v4 00/16] Finish converting git bisect into a built-in Ævar Arnfjörð Bjarmason
  2022-08-27 12:44       ` [PATCH v5 " Johannes Schindelin via GitGitGadget
  17 siblings, 0 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-06-27 18:31 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Bagas Sanjaya, Johannes Schindelin, Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

As per the code comment, the `.git/head-name` files were cleaned up for
backwards-compatibility: an old version of `git bisect` could have left
them behind.

Now, just how old would such a version be? As of 0f497e75f05 (Eliminate
confusing "won't bisect on seeked tree" failure, 2008-02-23), `git
bisect` does not write that file anymore. Which corresponds to Git
v1.5.4.4.

Even if the likelihood is non-nil that there might still be users out
there who use such an old version to start a bisection, but then decide
to continue bisecting with a current Git version, it is highly
improbable.

So let's remove that code, at long last.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 bisect.c                    | 3 ---
 t/t6030-bisect-porcelain.sh | 1 -
 2 files changed, 4 deletions(-)

diff --git a/bisect.c b/bisect.c
index b63669cc9d7..00bd4ba581c 100644
--- a/bisect.c
+++ b/bisect.c
@@ -474,7 +474,6 @@ static GIT_PATH_FUNC(git_path_bisect_start, "BISECT_START")
 static GIT_PATH_FUNC(git_path_bisect_log, "BISECT_LOG")
 static GIT_PATH_FUNC(git_path_bisect_terms, "BISECT_TERMS")
 static GIT_PATH_FUNC(git_path_bisect_first_parent, "BISECT_FIRST_PARENT")
-static GIT_PATH_FUNC(git_path_head_name, "head-name")
 
 static void read_bisect_paths(struct strvec *array)
 {
@@ -1181,8 +1180,6 @@ int bisect_clean_state(void)
 	unlink_or_warn(git_path_bisect_run());
 	unlink_or_warn(git_path_bisect_terms());
 	unlink_or_warn(git_path_bisect_first_parent());
-	/* Cleanup head-name if it got left by an old version of git-bisect */
-	unlink_or_warn(git_path_head_name());
 	/*
 	 * Cleanup BISECT_START last to support the --no-checkout option
 	 * introduced in the commit 4796e823a.
diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh
index 7a76f204083..1d9cbf229e2 100755
--- a/t/t6030-bisect-porcelain.sh
+++ b/t/t6030-bisect-porcelain.sh
@@ -1000,7 +1000,6 @@ test_expect_success 'git bisect reset cleans bisection state properly' '
 	test_path_is_missing ".git/BISECT_LOG" &&
 	test_path_is_missing ".git/BISECT_RUN" &&
 	test_path_is_missing ".git/BISECT_TERMS" &&
-	test_path_is_missing ".git/head-name" &&
 	test_path_is_missing ".git/BISECT_HEAD" &&
 	test_path_is_missing ".git/BISECT_START"
 '
-- 
gitgitgadget

^ permalink raw reply related	[flat|nested] 147+ messages in thread

* Re: [PATCH v4 00/16] Finish converting git bisect into a built-in
  2022-06-27 18:31     ` [PATCH v4 00/16] " Johannes Schindelin via GitGitGadget
                         ` (15 preceding siblings ...)
  2022-06-27 18:31       ` [PATCH v4 16/16] bisect: no longer try to clean up left-over `.git/head-name` files Johannes Schindelin via GitGitGadget
@ 2022-06-27 19:45       ` Ævar Arnfjörð Bjarmason
  2022-08-27 12:44       ` [PATCH v5 " Johannes Schindelin via GitGitGadget
  17 siblings, 0 replies; 147+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-06-27 19:45 UTC (permalink / raw)
  To: Johannes Schindelin via GitGitGadget
  Cc: git, Pranit Bauva, Tanushree Tumane, Miriam Rubio, Elijah Newren,
	Bagas Sanjaya, Johannes Schindelin


On Mon, Jun 27 2022, Johannes Schindelin via GitGitGadget wrote:

> After three GSoC/Outreachy students spent an incredible effort on this, it
> is finally time to put a neat little bow on it.

I probably just missed this in past iterations, but there's no
GSOC/Outreachy students in SOB, or even Helped-by. Was their code not
usable & this is the rewrite?

If that's the case it's not clear what that has to do with the current
state of this series...

> Changes since v3:
>
>  * Rebased because of merge conflicts with ab/plug-leak-in-revisions.
>  * Fixed the bug that git bisect --bisect-terms 1 2 wanted to auto-start a
>    bisection if running with a git executable built at the in-between state
>    at patch "bisect: move even the command-line parsing to bisect--helper".
>    Since this bug was "fixed" in v3 by the very next patch, "bisect: teach
>    the bisect--helper command to show the correct usage strings", v4 avoids
>    introducing this bug simply by letting these two patches trade places.
>    The range-diff admittedly looks quite awful because both patches overlap
>    quite a bit in the lines they modify. The end result is the same, though,
>    the diff between v3's and v4's builtin/bisect.c would be empty if I
>    hadn't been forced to rebase.
>  * Added a test case to ensure that this bug won't be introduced again. This
>    test case is the only actual difference relative to v3 of this patch
>    series.

I think there's still a lot of unnecessary churn in this series related
to migrating away from parse_options(). Your 13/16 still has a side-note
that I noted as not making sense in a past iteration.

On top of "master" I tried this trivial alternative to what you're doing
here in a *lot* more lines:
	
	diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
	index 8a052c7111f..38b23ee5fd4 100644
	--- a/builtin/bisect--helper.c
	+++ b/builtin/bisect--helper.c
	@@ -1321,6 +1321,29 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
	 		OPT_END()
	 	};
	 	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
	+	int i;
	+	struct strvec args = STRVEC_INIT;
	+	
	+	for (i = 0; i < argc; i++) {
	+		const char *arg = argv[i];
	+		int is_cmd = 0;
	+		const struct option *o = options;
	+
	+		for (; o->type != OPTION_END; o++)
	+			if (o->flags & PARSE_OPT_CMDMODE &&
	+			    !strcmp(o->long_name, arg)) {
	+				is_cmd = 1;
	+				break;
	+			}
	+
	+		if (is_cmd)
	+			strvec_pushf(&args, "--%s", arg);
	+		else
	+			strvec_push(&args, argv[i]);
	+
	+	}
	+	argc = args.nr;
	+	argv = args.v;
	 
	 	argc = parse_options(argc, argv, prefix, options,
	 			     git_bisect_helper_usage,
	diff --git a/git-bisect.sh b/git-bisect.sh
	index 405cf76f2a3..0fd63bf34db 100755
	--- a/git-bisect.sh
	+++ b/git-bisect.sh
	@@ -57,27 +57,10 @@ case "$#" in
	 	case "$cmd" in
	 	help)
	 		git bisect -h ;;
	-	start)
	-		git bisect--helper --bisect-start "$@" ;;
	 	bad|good|new|old|"$TERM_BAD"|"$TERM_GOOD")
	 		git bisect--helper --bisect-state "$cmd" "$@" ;;
	-	skip)
	-		git bisect--helper --bisect-skip "$@" || exit;;
	-	next)
	-		# Not sure we want "next" at the UI level anymore.
	-		git bisect--helper --bisect-next "$@" || exit ;;
	-	visualize|view)
	-		git bisect--helper --bisect-visualize "$@" || exit;;
	-	reset)
	-		git bisect--helper --bisect-reset "$@" ;;
	-	replay)
	-		git bisect--helper --bisect-replay "$@" || exit;;
	-	log)
	-		git bisect--helper --bisect-log || exit ;;
	-	run)
	-		git bisect--helper --bisect-run "$@" || exit;;
	-	terms)
	-		git bisect--helper --bisect-terms "$@" || exit;;
	+	start|skip|next|visualize|view|reset|replay|log|run|terms)
	+		git bisect--helper "--bisect-$cmd" "$@" || exit;;
	 	*)
	 		usage ;;
	 	esac

I.e. you're spending a lot of effort on working around the
parse_options() API supporting "--options-like-this" but not
"options-like-this". In this case it's much easier just to "fake it",
isn't it?

Of course near the end of this series we'd need to adjust that, but
doing so seems pretty easy, either just treat "start" as "--start", or
perhaps patch the relevant bits of parse_options(), but just
constructing a new command-line as I'm doing here seemed easier.

Now, there's a subtle bug in the above, I passed "view" as-is, but this
will error out. I don't think your topic introduces any bugs related to
that (that I've seen), but it goes to the "confidence building" part of [1].

I.e. here we're converting a bunch of code that doesn't have tests, and
as seen above v.s. the relevant parts of your series doing so in a way
that's not the least invasive path to that goal.

In particular I think all of 08/16, 09/16 and 13/16 (and maybe 10/16?)
would be easier & more straightforward to do with such one-pass argv
construction. I.e. if we make "start" a "--start" and e.g. "good" a
["--bisect-state", "good"] shouldn't this all just work without
migrating bisect--helper away from parse_options()?

In that way this seems a bit like two steps forward & one step back,
e.g. with the above patch we could drive 'git bisect' completion via the
usual --git-completion-helper facility (with a trivial s/--//)
workaround.

B.t.w. I think your tip is buggy with regards to that, i.e. don't you
need a NO_PARSEOPT flag in git.c when you s/bisect--helper/bisect/ so
that the completion doesn't try to use both --git-completion-helper and
its own current 'bisect function' (but maybe it works by happy accident
now?). In any case if you're set on converting this away from
parse_options() you should add that flag in git.c.

I think as far as this conversion goes we could say "we'll use
parse_options() again later", even though I think doing so is
unfortunate, as I think you're going the long way around to migrate away
from an API we're generally migrating to, when we can use it rather
easily.

I'm mainly concerned with the lack of testing. You have a new 01/16
here, but as noted in[1] and above that's really the tip of the iceberg.

Maybe you're really confident that that was the last bug, even without
testing basic things like "view" working at all, but the CL here doesn't
really make for a convincing (to me) argument.

1. https://lore.kernel.org/git/220523.865ylwzgji.gmgdl@evledraar.gmail.com/

^ permalink raw reply	[flat|nested] 147+ messages in thread

* Re: [PATCH v4 11/16] bisect--helper: return only correct exit codes in `cmd_*()`
  2022-06-27 18:31       ` [PATCH v4 11/16] bisect--helper: return only correct exit codes in `cmd_*()` Johannes Schindelin via GitGitGadget
@ 2022-06-27 20:09         ` Ævar Arnfjörð Bjarmason
  0 siblings, 0 replies; 147+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-06-27 20:09 UTC (permalink / raw)
  To: Johannes Schindelin via GitGitGadget
  Cc: git, Pranit Bauva, Tanushree Tumane, Miriam Rubio, Elijah Newren,
	Bagas Sanjaya, Johannes Schindelin


On Mon, Jun 27 2022, Johannes Schindelin via GitGitGadget wrote:

> From: Johannes Schindelin <johannes.schindelin@gmx.de>
>
> Exit codes cannot be negative, but `error()` returns -1.

That's good, but...

> Let's just go with the common pattern and call `die()` in
> `cmd_bisect__helper()` when incorrect arguments were detected.

...the common and correct pattern on bad options is to return 129, not
128, which using use usage_msg_opt() instead of die() here would give
you for free. I think this should use that instead.

^ permalink raw reply	[flat|nested] 147+ messages in thread

* Re: [PATCH v4 12/16] bisect: teach the `bisect--helper` command to show the correct usage strings
  2022-06-27 18:31       ` [PATCH v4 12/16] bisect: teach the `bisect--helper` command to show the correct usage strings Johannes Schindelin via GitGitGadget
@ 2022-06-27 22:11         ` Junio C Hamano
  0 siblings, 0 replies; 147+ messages in thread
From: Junio C Hamano @ 2022-06-27 22:11 UTC (permalink / raw)
  To: Johannes Schindelin via GitGitGadget
  Cc: git, Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Bagas Sanjaya, Johannes Schindelin

"Johannes Schindelin via GitGitGadget" <gitgitgadget@gmail.com>
writes:

> From: Johannes Schindelin <johannes.schindelin@gmx.de>
>
> In preparation for `bisect--helper` graduating to become the actual
> `bisect` command, we hereby teach it to print the very same usage
> strings as the scripted `git-bisect.sh` does.

Sounds good.  If we stop the series at this stage, a misimplemented
caller might give us an awkweard output, but we are not expecting
end-users to invoke "git bisect--helper -h" to begin with, so it is
perfectly OK.  Somewhere during the journey to fully move it to
builtin/bisect.c this needs to be done, and this step may probably
be the right spot in the series.

^ permalink raw reply	[flat|nested] 147+ messages in thread

* Re: [PATCH v4 14/16] Turn `git bisect` into a full built-in
  2022-06-27 18:31       ` [PATCH v4 14/16] Turn `git bisect` into a full built-in Johannes Schindelin via GitGitGadget
@ 2022-06-27 22:13         ` Junio C Hamano
  0 siblings, 0 replies; 147+ messages in thread
From: Junio C Hamano @ 2022-06-27 22:13 UTC (permalink / raw)
  To: Johannes Schindelin via GitGitGadget
  Cc: git, Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Bagas Sanjaya, Johannes Schindelin

"Johannes Schindelin via GitGitGadget" <gitgitgadget@gmail.com>
writes:

> From: Johannes Schindelin <johannes.schindelin@gmx.de>
>
> Now that the shell script hands off to the `bisect--helper` to do
> _anything_ (except to show the help), it is but a tiny step to let the
> helper implement the actual `git bisect` command instead.
>
> This retires `git-bisect.sh`, concluding a multi-year journey that many
> hands helped with, in particular Pranit Bauna, Tanushree Tumane and
> Miriam Rubio.
>
> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> ---
>  Makefile                               |  3 +--
>  builtin.h                              |  2 +-
>  builtin/{bisect--helper.c => bisect.c} |  2 +-
>  git-bisect.sh                          | 37 --------------------------
>  git.c                                  |  2 +-
>  5 files changed, 4 insertions(+), 42 deletions(-)
>  rename builtin/{bisect--helper.c => bisect.c} (99%)
>  delete mode 100755 git-bisect.sh

Good.


^ permalink raw reply	[flat|nested] 147+ messages in thread

* Re: [PATCH v4 15/16] bisect: remove Cogito-related code
  2022-06-27 18:31       ` [PATCH v4 15/16] bisect: remove Cogito-related code Johannes Schindelin via GitGitGadget
@ 2022-06-27 22:18         ` Junio C Hamano
  0 siblings, 0 replies; 147+ messages in thread
From: Junio C Hamano @ 2022-06-27 22:18 UTC (permalink / raw)
  To: Johannes Schindelin via GitGitGadget
  Cc: git, Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Bagas Sanjaya, Johannes Schindelin

"Johannes Schindelin via GitGitGadget" <gitgitgadget@gmail.com>
writes:

> As of April 19th, 2007, Cogito was therefore discontinued (see
> https://lore.kernel.org/git/20070419124648.GL4489@pasky.or.cz/).
>
> Nevertheless, for almost 15 years after that announcement, Git carried
> special code in `git bisect` to accommodate Cogito.

Good eyes.  Doesn't steps 15 & 16 cover the same theme, though?
IOW, if surviving Cogito users appear after we take this 16-patch
series, would reverting this step the only thing needed if we decide
to accomodate them again (and removal of head-name done in step 16
can still be kept without harming these Cogito users)?  I am wondering
if these should be merged into one patch.

Thanks.


>
> Since it is beyond doubt that there are no more Cogito users, let's
> remove the last remnant of Cogito-accommodating code.
>
> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> ---
>  builtin/bisect.c | 8 --------
>  1 file changed, 8 deletions(-)



>
> diff --git a/builtin/bisect.c b/builtin/bisect.c
> index 380fef852f3..47103ebf3f2 100644
> --- a/builtin/bisect.c
> +++ b/builtin/bisect.c
> @@ -14,7 +14,6 @@ static GIT_PATH_FUNC(git_path_bisect_expected_rev, "BISECT_EXPECTED_REV")
>  static GIT_PATH_FUNC(git_path_bisect_ancestors_ok, "BISECT_ANCESTORS_OK")
>  static GIT_PATH_FUNC(git_path_bisect_start, "BISECT_START")
>  static GIT_PATH_FUNC(git_path_bisect_log, "BISECT_LOG")
> -static GIT_PATH_FUNC(git_path_head_name, "head-name")
>  static GIT_PATH_FUNC(git_path_bisect_names, "BISECT_NAMES")
>  static GIT_PATH_FUNC(git_path_bisect_first_parent, "BISECT_FIRST_PARENT")
>  static GIT_PATH_FUNC(git_path_bisect_run, "BISECT_RUN")
> @@ -809,13 +808,6 @@ static enum bisect_error bisect_start(struct bisect_terms *terms, const char **a
>  			strbuf_addstr(&start_head, oid_to_hex(&head_oid));
>  		} else if (!get_oid(head, &head_oid) &&
>  			   skip_prefix(head, "refs/heads/", &head)) {
> -			/*
> -			 * This error message should only be triggered by
> -			 * cogito usage, and cogito users should understand
> -			 * it relates to cg-seek.
> -			 */
> -			if (!is_empty_or_missing_file(git_path_head_name()))
> -				return error(_("won't bisect on cg-seek'ed tree"));
>  			strbuf_addstr(&start_head, head);
>  		} else {
>  			return error(_("bad HEAD - strange symbolic ref"));

^ permalink raw reply	[flat|nested] 147+ messages in thread

* Re: [PATCH v4 01/16] bisect: verify that a bogus option won't try to start a bisection
  2022-06-27 18:31       ` [PATCH v4 01/16] bisect: verify that a bogus option won't try to start a bisection Johannes Schindelin via GitGitGadget
@ 2022-06-28  2:12         ` Junio C Hamano
  0 siblings, 0 replies; 147+ messages in thread
From: Junio C Hamano @ 2022-06-28  2:12 UTC (permalink / raw)
  To: Johannes Schindelin via GitGitGadget
  Cc: git, Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Bagas Sanjaya, Johannes Schindelin

"Johannes Schindelin via GitGitGadget" <gitgitgadget@gmail.com>
writes:

> From: Johannes Schindelin <johannes.schindelin@gmx.de>
>
> We do not want `git bisect --bogus-option` to start a bisection. To
> verify that, we look for the tell-tale error message `You need to start
> by "git bisect start"` and fail if it was found.
>
> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> ---

Sorry, but this looks unclear to me.

In the test "--bisect-terms" is used, and from "git grep" it does
seem to be one of the valid options "git bisect--helper" can take.
It is unclear if the patch wanted to literally use "--bogus-option"
insteaed of it but used "--bisect-terms" by mistake, or if that
valid option is "bogus" only in the sense that the option is not yet
relevant immediately after "git bisect reset" before a new "git
bisect start" session has begun.  IOW, "bogus" both in the patch
title and the test title needs to be clarified.

To put it another way, can we demonstrate the same correctness by
seeing "git bisect --no-such-option" fail immediately after "git
bisect reset"?



>  t/t6030-bisect-porcelain.sh | 10 ++++++++++
>  1 file changed, 10 insertions(+)
>
> diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh
> index 83931d482fb..6d6e72276ae 100755
> --- a/t/t6030-bisect-porcelain.sh
> +++ b/t/t6030-bisect-porcelain.sh
> @@ -900,6 +900,16 @@ test_expect_success 'bisect start with one term1 and term2' '
>  	git bisect reset
>  '
>  
> +test_expect_success 'bogus command does not start bisect' '
> +	git bisect reset &&
> +	test_must_fail git bisect --bisect-terms 1 2 2>out &&
> +	! grep "You need to start" out &&
> +	test_must_fail git bisect --bisect-terms 2>out &&
> +	! grep "You need to start" out &&
> +	grep "git bisect.*visualize" out &&
> +	git bisect reset
> +'
> +
>  test_expect_success 'bisect replay with term1 and term2' '
>  	git bisect replay log_to_replay.txt >bisect_result &&
>  	grep "$HASH2 is the first term1 commit" bisect_result &&

^ permalink raw reply	[flat|nested] 147+ messages in thread

* [PATCH v5 00/16] Finish converting git bisect into a built-in
  2022-06-27 18:31     ` [PATCH v4 00/16] " Johannes Schindelin via GitGitGadget
                         ` (16 preceding siblings ...)
  2022-06-27 19:45       ` [PATCH v4 00/16] Finish converting git bisect into a built-in Ævar Arnfjörð Bjarmason
@ 2022-08-27 12:44       ` Johannes Schindelin via GitGitGadget
  2022-08-27 12:44         ` [PATCH v5 01/16] bisect--helper: retire the --no-log option Johannes Schindelin via GitGitGadget
                           ` (16 more replies)
  17 siblings, 17 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-08-27 12:44 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Bagas Sanjaya, Junio C Hamano, Johannes Schindelin

After three GSoC/Outreachy students spent an incredible effort on this, it
is finally time to put a neat little bow on it, or maybe more like a big
bow, maybe even a very large one, seeing as it takes quite a while to tie
(half a year at the time of writing)...

Changes since v4:

 * rebased onto sg/parse-options-subcommand
 * migrated to OPT_SUBCOMMAND().
 * As a consequence, this patch series is now unfortunately very large. And
   the range-diff is much less useful than I'd like because of the extensive
   changes that were de facto made a precondition to moving this patch
   series further. Junio, I would have liked to keep the scope (and burden
   for the reviewers) substantially smaller, maybe you can help with the
   review?

Changes since v3:

 * Rebased because of merge conflicts with ab/plug-leak-in-revisions.
 * Fixed the bug that git bisect --bisect-terms 1 2 wanted to auto-start a
   bisection if running with a git executable built at the in-between state
   at patch "bisect: move even the command-line parsing to bisect--helper".
   Since this bug was "fixed" in v3 by the very next patch, "bisect: teach
   the bisect--helper command to show the correct usage strings", v4 avoids
   introducing this bug simply by letting these two patches trade places.
   The range-diff admittedly looks quite awful because both patches overlap
   quite a bit in the lines they modify. The end result is the same, though,
   the diff between v3's and v4's builtin/bisect.c would be empty if I
   hadn't been forced to rebase.
 * Added a test case to ensure that this bug won't be introduced again. This
   test case is the only actual difference relative to v3 of this patch
   series.

Changes since v2:

 * We're now careful to provide identical usage strings upon git bisect -h
   and git bisect bogus.
 * When a bogus command is provided, we now error out instead of trying to
   start a git bisect run.
 * Rebased onto main to avoid plenty of merge conflicts with
   rs/bisect-executable-not-found, ac/usage-string-fixups and with
   cd/bisect-messages-from-pre-flight-states.

Changes since v1:

 * Added a regression test to "bisect run: fix the error message".
 * Added a patch to address an error message that double-single-quoted the
   command.
 * Reworked the logic in "bisect--helper: make --bisect-state optional" to
   delay showing the usage upon an unknown command, which should make the
   code a lot less confusing.
 * Split out the change that moved the BISECT_STATE case to the end of the
   switch block.
 * Added a patch that replaces the return error() calls in
   cmd_bisect_helper() with die() calls, to avoid returning -1 as an exit
   code.
 * Dropped the use of parse_options() for the single purpose of handling -h;
   This is now done explicitly.
 * Simplified the diff of "bisect: move even the option parsing to
   bisect--helper" by modifying argc and argv instead of modifying all the
   function calls using those variables.
 * In the "Turn git bisect into a full built-in" patch, changed the name of
   the variable holding the usage to use the builtin_ prefix used in other
   built-ins, too.
 * Removed the trailing dot from the commit message of "Turn git bisect into
   a full built-in".

Johannes Schindelin (16):
  bisect--helper: retire the --no-log option
  bisect--helper: really retire --bisect-next-check
  bisect--helper: really retire `--bisect-autostart`
  bisect--helper: simplify exit code computation
  bisect--helper: make `terms` an explicit singleton
  bisect--helper: make the order consistently `argc, argv`
  bisect--helper: migrate to OPT_SUBCOMMAND()
  bisect: verify that a bogus option won't try to start a bisection
  bisect run: fix the error message
  bisect: avoid double-quoting when printing the failed command
  bisect--helper: calling `bisect_state()` without an argument is a bug
  bisect--helper: make `state` optional
  bisect: move even the command-line parsing to `bisect--helper`
  Turn `git bisect` into a full built-in
  bisect: remove Cogito-related code
  bisect: no longer try to clean up left-over `.git/head-name` files

 Makefile                               |   3 +-
 bisect.c                               |   3 -
 builtin.h                              |   2 +-
 builtin/{bisect--helper.c => bisect.c} | 679 ++++++++++++++-----------
 git-bisect.sh                          |  84 ---
 git.c                                  |   2 +-
 t/t6030-bisect-porcelain.sh            |  21 +-
 7 files changed, 406 insertions(+), 388 deletions(-)
 rename builtin/{bisect--helper.c => bisect.c} (67%)
 delete mode 100755 git-bisect.sh


base-commit: 8f9d80f6c06369b563c76ec46c462e740a1a2cf0
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-1132%2Fdscho%2Fbisect-in-c-v5
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1132/dscho/bisect-in-c-v5
Pull-Request: https://github.com/gitgitgadget/git/pull/1132

Range-diff vs v4:

  4:  5bfaf0334c3 =  1:  05262b6a7d1 bisect--helper: retire the --no-log option
  5:  e85f236304b =  2:  1e43148864a bisect--helper: really retire --bisect-next-check
  6:  b94b7bb4fd0 =  3:  1a1649d9d0d bisect--helper: really retire `--bisect-autostart`
  -:  ----------- >  4:  9ab30552c6a bisect--helper: simplify exit code computation
  -:  ----------- >  5:  92b3b116ef8 bisect--helper: make `terms` an explicit singleton
 11:  ce508583e45 !  6:  c9dc0281e38 bisect--helper: return only correct exit codes in `cmd_*()`
     @@ Metadata
      Author: Johannes Schindelin <Johannes.Schindelin@gmx.de>
      
       ## Commit message ##
     -    bisect--helper: return only correct exit codes in `cmd_*()`
     +    bisect--helper: make the order consistently `argc, argv`
      
     -    Exit codes cannot be negative, but `error()` returns -1.
     +    In C, the natural order is for `argc` to come before `argv` by virtue of
     +    the `main()` function declaring the parameters in precisely that order.
      
     -    Let's just go with the common pattern and call `die()` in
     -    `cmd_bisect__helper()` when incorrect arguments were detected.
     +    It is confusing & distracting, then, when readers familiar with the C
     +    language read code where that order is switched around.
     +
     +    Let's just change the order and avoid that type of developer friction.
      
          Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
      
       ## builtin/bisect--helper.c ##
     +@@ builtin/bisect--helper.c: static enum bisect_error bisect_auto_next(const char *prefix)
     + 	return bisect_next(prefix);
     + }
     + 
     +-static enum bisect_error bisect_start(const char **argv, int argc)
     ++static enum bisect_error bisect_start(int argc, const char **argv)
     + {
     + 	int no_checkout = 0;
     + 	int first_parent_only = 0;
     +@@ builtin/bisect--helper.c: static int bisect_autostart(void)
     + 	yesno = git_prompt(_("Do you want me to do it for you "
     + 			     "[Y/n]? "), PROMPT_ECHO);
     + 	res = tolower(*yesno) == 'n' ?
     +-		-1 : bisect_start(empty_strvec, 0);
     ++		-1 : bisect_start(0, empty_strvec);
     + 
     + 	return res;
     + }
     + 
     +-static enum bisect_error bisect_state(const char **argv,
     +-				      int argc)
     ++static enum bisect_error bisect_state(int argc, const char **argv)
     + {
     + 	const char *state;
     + 	int i, verify_expected = 1;
     +@@ builtin/bisect--helper.c: static int process_replay_line(struct strbuf *line)
     + 		struct strvec argv = STRVEC_INIT;
     + 		int res;
     + 		sq_dequote_to_strvec(rev, &argv);
     +-		res = bisect_start(argv.v, argv.nr);
     ++		res = bisect_start(argv.nr, argv.v);
     + 		strvec_clear(&argv);
     + 		return res;
     + 	}
     +@@ builtin/bisect--helper.c: static enum bisect_error bisect_replay(const char *filename)
     + 	return bisect_auto_next(NULL);
     + }
     + 
     +-static enum bisect_error bisect_skip(const char **argv, int argc)
     ++static enum bisect_error bisect_skip(int argc, const char **argv)
     + {
     + 	int i;
     + 	enum bisect_error res;
     +@@ builtin/bisect--helper.c: static enum bisect_error bisect_skip(const char **argv, int argc)
     + 			strvec_push(&argv_state, argv[i]);
     + 		}
     + 	}
     +-	res = bisect_state(argv_state.v, argv_state.nr);
     ++	res = bisect_state(argv_state.nr, argv_state.v);
     + 
     + 	strvec_clear(&argv_state);
     + 	return res;
     + }
     + 
     +-static int bisect_visualize(const char **argv, int argc)
     ++static int bisect_visualize(int argc, const char **argv)
     + {
     + 	struct strvec args = STRVEC_INIT;
     + 	int flags = RUN_COMMAND_NO_STDIN, res = 0;
     +@@ builtin/bisect--helper.c: static int verify_good(const char **quoted_argv)
     + 	return rc;
     + }
     + 
     +-static int bisect_run(const char **argv, int argc)
     ++static int bisect_run(int argc, const char **argv)
     + {
     + 	int res = BISECT_OK;
     + 	struct strbuf command = STRBUF_INIT;
     +@@ builtin/bisect--helper.c: static int bisect_run(const char **argv, int argc)
     + 		saved_stdout = dup(1);
     + 		dup2(temporary_stdout_fd, 1);
     + 
     +-		res = bisect_state(&new_state, 1);
     ++		res = bisect_state(1, &new_state);
     + 
     + 		fflush(stdout);
     + 		dup2(saved_stdout, 1);
      @@ builtin/bisect--helper.c: int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
       		break;
     - 	case BISECT_TERMS:
     - 		if (argc > 1)
     --			return error(_("--bisect-terms requires 0 or 1 argument"));
     -+			die(_("--bisect-terms requires 0 or 1 argument"));
     - 		res = bisect_terms(&terms, argc == 1 ? argv[0] : NULL);
     - 		break;
     - 	case BISECT_SKIP:
     -@@ builtin/bisect--helper.c: int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
     + 	case BISECT_START:
     + 		set_terms("bad", "good");
     +-		res = bisect_start(argv, argc);
     ++		res = bisect_start(argc, argv);
       		break;
       	case BISECT_NEXT:
       		if (argc)
     --			return error(_("--bisect-next requires 0 arguments"));
     -+			die(_("--bisect-next requires 0 arguments"));
     - 		get_terms(&terms);
     - 		res = bisect_next(&terms, prefix);
     - 		break;
     - 	case BISECT_RESET:
     - 		if (argc > 1)
     --			return error(_("--bisect-reset requires either no argument or a commit"));
     -+			die(_("--bisect-reset requires either no argument or a commit"));
     - 		res = bisect_reset(argc ? argv[0] : NULL);
     - 		break;
     - 	case BISECT_VISUALIZE:
      @@ builtin/bisect--helper.c: int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
     - 		break;
     - 	case BISECT_REPLAY:
     - 		if (argc != 1)
     --			return error(_("no logfile given"));
     -+			die(_("no logfile given"));
     - 		set_terms(&terms, "bad", "good");
     - 		res = bisect_replay(&terms, argv[0]);
     + 	case BISECT_STATE:
     + 		set_terms("bad", "good");
     + 		get_terms();
     +-		res = bisect_state(argv, argc);
     ++		res = bisect_state(argc, argv);
       		break;
       	case BISECT_LOG:
       		if (argc)
     --			return error(_("--bisect-log requires 0 arguments"));
     -+			die(_("--bisect-log requires 0 arguments"));
     - 		res = bisect_log();
     +@@ builtin/bisect--helper.c: int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
     + 	case BISECT_SKIP:
     + 		set_terms("bad", "good");
     + 		get_terms();
     +-		res = bisect_skip(argv, argc);
     ++		res = bisect_skip(argc, argv);
     + 		break;
     + 	case BISECT_VISUALIZE:
     + 		get_terms();
     +-		res = bisect_visualize(argv, argc);
     ++		res = bisect_visualize(argc, argv);
       		break;
       	case BISECT_RUN:
       		if (!argc)
     --			return error(_("bisect run failed: no command provided."));
     -+			die(_("bisect run failed: no command provided."));
     - 		get_terms(&terms);
     - 		res = bisect_run(&terms, argv, argc);
     + 			return error(_("bisect run failed: no command provided."));
     + 		get_terms();
     +-		res = bisect_run(argv, argc);
     ++		res = bisect_run(argc, argv);
       		break;
     + 	default:
     + 		BUG("unknown subcommand %d", cmdmode);
  -:  ----------- >  7:  5b7a3d58b4f bisect--helper: migrate to OPT_SUBCOMMAND()
  1:  30ddbd7affc =  8:  ba537af7066 bisect: verify that a bogus option won't try to start a bisection
  2:  97dd2da8f89 !  9:  409492ad830 bisect run: fix the error message
     @@ Commit message
          Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
      
       ## builtin/bisect--helper.c ##
     -@@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
     +@@ builtin/bisect--helper.c: static int cmd_bisect_run(int argc, const char **argv, const char *prefix)
       			printf(_("bisect found first bad commit"));
       			res = BISECT_OK;
       		} else if (res) {
  3:  5571e0f76ff ! 10:  bc5efc8fbfe bisect: avoid double-quoting when printing the failed command
     @@ Commit message
          Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
      
       ## builtin/bisect--helper.c ##
     -@@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
     +@@ builtin/bisect--helper.c: static int cmd_bisect_run(int argc, const char **argv, const char *prefix)
       
       		if (res < 0 || 128 <= res) {
       			error(_("bisect run failed: exit code %d from"
  7:  aad3c9a0850 ! 11:  8a0adfe3867 bisect--helper: using `--bisect-state` without an argument is a bug
     @@ Metadata
      Author: Johannes Schindelin <Johannes.Schindelin@gmx.de>
      
       ## Commit message ##
     -    bisect--helper: using `--bisect-state` without an argument is a bug
     +    bisect--helper: calling `bisect_state()` without an argument is a bug
      
     -    The `bisect--helper` command is not expected to be used directly by the
     -    user. Therefore, it is a bug if it receives no argument to the
     -    `--bisect-state` command mode, not a user error. Which means that we
     -    need to call `BUG()` instead of `die()`.
     +    The `bisect_state()` function is now a purely internal function and must
     +    be called with a valid state, everything else is a bug.
      
          Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
      
       ## builtin/bisect--helper.c ##
     -@@ builtin/bisect--helper.c: static enum bisect_error bisect_state(struct bisect_terms *terms, const char **a
     +@@ builtin/bisect--helper.c: static enum bisect_error bisect_state(int argc, const char **argv,
     + 	struct strbuf buf = STRBUF_INIT;
       	struct oid_array revs = OID_ARRAY_INIT;
       
     - 	if (!argc)
     --		return error(_("Please call `--bisect-state` with at least one argument"));
     ++	if (!argc)
      +		BUG("bisect_state() called without argument");
       
     - 	if (bisect_autostart(terms))
     + 	if (bisect_autostart(prefix))
       		return BISECT_FAILED;
  8:  375a46dca9f <  -:  ----------- bisect--helper: align the sub-command order with git-bisect.sh
  9:  c57f63f6a61 ! 12:  189d2b3ba46 bisect--helper: make `--bisect-state` optional
     @@ Metadata
      Author: Johannes Schindelin <Johannes.Schindelin@gmx.de>
      
       ## Commit message ##
     -    bisect--helper: make `--bisect-state` optional
     +    bisect--helper: make `state` optional
      
          In preparation for making `git bisect` a real built-in, let's prepare
          the `bisect--helper` built-in to handle `git bisect--helper good` and
     -    `git bisect--helper bad`, i.e. do not require the `--bisect-state`
     -    option to be passed explicitly.
     +    `git bisect--helper bad`, i.e. do not require the `state` subcommand to
     +    be passed explicitly.
      
          Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
      
       ## builtin/bisect--helper.c ##
     -@@ builtin/bisect--helper.c: static const char * const git_bisect_helper_usage[] = {
     - 	N_("git bisect--helper --bisect-start [--term-{new,bad}=<term> --term-{old,good}=<term>]"
     - 					    " [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<paths>...]"),
     - 	"git bisect--helper --bisect-next",
     --	N_("git bisect--helper --bisect-state (bad|new) [<rev>]"),
     --	N_("git bisect--helper --bisect-state (good|old) [<rev>...]"),
     -+	N_("git bisect--helper [--bisect-state] (bad|new) [<rev>]"),
     -+	N_("git bisect--helper [--bisect-state] (good|old) [<rev>...]"),
     - 	N_("git bisect--helper --bisect-replay <filename>"),
     - 	N_("git bisect--helper --bisect-skip [(<rev>|<range>)...]"),
     - 	"git bisect--helper --bisect-visualize",
     -@@ builtin/bisect--helper.c: int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
     - 			     git_bisect_helper_usage,
     - 			     PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN);
     +@@ builtin/bisect--helper.c: static int cmd_bisect_run(int argc, const char **argv, const char *prefix)
       
     --	if (!cmdmode)
     --		usage_with_options(git_bisect_helper_usage, options);
     --
     --	switch (cmdmode) {
     -+	switch (cmdmode ? cmdmode : BISECT_STATE) {
     - 	case BISECT_START:
     - 		set_terms(&terms, "bad", "good");
     - 		res = bisect_start(&terms, argv, argc);
     + int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
     + {
     ++	struct strvec args = STRVEC_INIT;
     + 	parse_opt_subcommand_fn *fn = NULL;
     + 	int res = 0;
     + 	struct option options[] = {
      @@ builtin/bisect--helper.c: int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
     - 	case BISECT_STATE:
     - 		set_terms(&terms, "bad", "good");
     - 		get_terms(&terms);
     -+		if (!cmdmode &&
     -+		    (!argc || check_and_set_terms(&terms, argv[0]))) {
     -+			char *msg = xstrfmt(_("unknown command: '%s'"), argv[0]);
     -+			usage_msg_opt(msg, git_bisect_helper_usage, options);
     -+		}
     - 		res = bisect_state(&terms, argv, argc);
     - 		break;
     - 	case BISECT_TERMS:
     + 	};
     + 
     + 	argc = parse_options(argc, argv, prefix, options,
     +-			     bisect_usage, 0);
     ++			     bisect_usage, PARSE_OPT_SUBCOMMAND_OPTIONAL);
     ++
     ++	if (!fn) {
     ++		if (!argc)
     ++			usage_msg_opt(_("need a command"), bisect_usage,
     ++				      options);
     ++
     ++		set_terms("bad", "good");
     ++		get_terms();
     ++		if (check_and_set_terms(argv[0]))
     ++			usage_msg_optf(_("unknown command: '%s'"), bisect_usage,
     ++				       options, argv[0]);
     ++
     ++		strvec_push(&args, "state");
     ++		strvec_pushv(&args, argv);
     ++		argc = args.nr;
     ++		argv = args.v;
     ++		fn = cmd_bisect_state;
     ++	}
     + 
     + 	res = fn(argc, argv, prefix);
     + 	free_terms();
     ++	strvec_clear(&args);
     + 
     + 	return is_bisect_success(res) ? 0 : -res;
     + }
      
       ## git-bisect.sh ##
      @@ git-bisect.sh: case "$#" in
       	start)
     - 		git bisect--helper --bisect-start "$@" ;;
     + 		git bisect--helper start "$@" ;;
       	bad|good|new|old|"$TERM_BAD"|"$TERM_GOOD")
     --		git bisect--helper --bisect-state "$cmd" "$@" ;;
     +-		git bisect--helper state "$cmd" "$@" ;;
      +		git bisect--helper "$cmd" "$@" ;;
       	skip)
     - 		git bisect--helper --bisect-skip "$@" || exit;;
     + 		git bisect--helper skip "$@" || exit;;
       	next)
 10:  87f53469a72 <  -:  ----------- bisect--helper: move the `BISECT_STATE` case to the end
 12:  5dbe233e4ec <  -:  ----------- bisect: teach the `bisect--helper` command to show the correct usage strings
 13:  d56f2a14060 ! 13:  32bf74e3050 bisect: move even the command-line parsing to `bisect--helper`
     @@ Commit message
          On our journey to a fully built-in `git bisect`, this is the
          last step.
      
     -    Side note: The `parse-options` API is not at all set up to parse
     -    subcommands such as `git bisect start`, `git bisect reset`, etc.
     -    Instead of fighting an up-hill battle trying to "fix" that, we simply
     -    roll the same type of manual subcommand parsing as we already do e.g.
     -    in `builtin/bundle.c`.
     -
          Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
      
       ## builtin/bisect--helper.c ##
     -@@ builtin/bisect--helper.c: static const char *bisect_usage =
     - 	N_("git bisect [help|start|bad|good|new|old|terms|skip|next|reset|"
     - 	   "visualize|view|replay|log|run]");
     - 
     --static const char * const bisect_long_usage[] = {
     -+static const char *bisect_long_usage =
     - 	N_("git bisect [help|start|bad|good|new|old|terms|skip|next|reset|"
     - 	   "visualize|view|replay|log|run]\n"
     - 	   "\n"
     -@@ builtin/bisect--helper.c: static const char * const bisect_long_usage[] = {
     - 	   "git bisect run <cmd>...\n"
     - 	   "\tuse <cmd>... to automatically bisect.\n"
     - 	   "\n"
     --	   "Please use \"git help bisect\" to get the full man page."),
     --	NULL
     --};
     -+	   "Please use \"git help bisect\" to get the full man page.");
     - 
     - struct add_bisect_ref_data {
     - 	struct rev_info *revs;
     -@@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
     - 
     - int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
     - {
     --	enum {
     --		BISECT_START = 1,
     --		BISECT_STATE,
     --		BISECT_TERMS,
     --		BISECT_SKIP,
     --		BISECT_NEXT,
     --		BISECT_RESET,
     --		BISECT_VISUALIZE,
     --		BISECT_REPLAY,
     --		BISECT_LOG,
     --		BISECT_RUN,
     --	} cmdmode = 0;
     - 	int res = 0;
     --	struct option options[] = {
     --		OPT_CMDMODE(0, "bisect-start", &cmdmode,
     --			 N_("start the bisect session"), BISECT_START),
     --		OPT_CMDMODE(0, "bisect-state", &cmdmode,
     --			 N_("mark the state of ref (or refs)"), BISECT_STATE),
     --		OPT_CMDMODE(0, "bisect-terms", &cmdmode,
     --			 N_("print out the bisect terms"), BISECT_TERMS),
     --		OPT_CMDMODE(0, "bisect-skip", &cmdmode,
     --			 N_("skip some commits for checkout"), BISECT_SKIP),
     --		OPT_CMDMODE(0, "bisect-next", &cmdmode,
     --			 N_("find the next bisection commit"), BISECT_NEXT),
     --		OPT_CMDMODE(0, "bisect-reset", &cmdmode,
     --			 N_("reset the bisection state"), BISECT_RESET),
     --		OPT_CMDMODE(0, "bisect-visualize", &cmdmode,
     --			 N_("visualize the bisection"), BISECT_VISUALIZE),
     --		OPT_CMDMODE(0, "bisect-replay", &cmdmode,
     --			 N_("replay the bisection process from the given file"), BISECT_REPLAY),
     --		OPT_CMDMODE(0, "bisect-log", &cmdmode,
     --			 N_("list the bisection steps so far"), BISECT_LOG),
     --		OPT_CMDMODE(0, "bisect-run", &cmdmode,
     --			 N_("use <cmd>... to automatically bisect"), BISECT_RUN),
     --		OPT_END()
     --	};
     - 	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
     -+	const char *command = argc > 1 ? argv[1] : "help";
     -+
     -+	if (!strcmp("-h", command) || !strcmp("help", command))
     -+		usage(bisect_long_usage);
     - 
     --	argc = parse_options(argc, argv, prefix, options,
     --			     bisect_long_usage,
     --			     PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN);
     -+	argc -= 2;
     -+	argv += 2;
     - 
     --	switch (cmdmode ? cmdmode : BISECT_STATE) {
     --	case BISECT_START:
     -+	if (!strcmp("start", command)) {
     - 		set_terms(&terms, "bad", "good");
     - 		res = bisect_start(&terms, argv, argc);
     --		break;
     --	case BISECT_TERMS:
     -+	} else if (!strcmp("terms", command)) {
     - 		if (argc > 1)
     --			die(_("--bisect-terms requires 0 or 1 argument"));
     -+			die(_("'terms' requires 0 or 1 argument"));
     - 		res = bisect_terms(&terms, argc == 1 ? argv[0] : NULL);
     --		break;
     --	case BISECT_SKIP:
     -+	} else if (!strcmp("skip", command)) {
     - 		set_terms(&terms, "bad", "good");
     - 		get_terms(&terms);
     - 		res = bisect_skip(&terms, argv, argc);
     --		break;
     --	case BISECT_NEXT:
     -+	} else if (!strcmp("next", command)) {
     - 		if (argc)
     --			die(_("--bisect-next requires 0 arguments"));
     -+			die(_("'next' requires 0 arguments"));
     - 		get_terms(&terms);
     - 		res = bisect_next(&terms, prefix);
     --		break;
     --	case BISECT_RESET:
     -+	} else if (!strcmp("reset", command)) {
     - 		if (argc > 1)
     --			die(_("--bisect-reset requires either no argument or a commit"));
     -+			die(_("'reset' requires either no argument or a commit"));
     - 		res = bisect_reset(argc ? argv[0] : NULL);
     --		break;
     --	case BISECT_VISUALIZE:
     -+	} else if (one_of(command, "visualize", "view", NULL)) {
     - 		get_terms(&terms);
     - 		res = bisect_visualize(&terms, argv, argc);
     --		break;
     --	case BISECT_REPLAY:
     -+	} else if (!strcmp("replay", command)) {
     - 		if (argc != 1)
     - 			die(_("no logfile given"));
     - 		set_terms(&terms, "bad", "good");
     - 		res = bisect_replay(&terms, argv[0]);
     --		break;
     --	case BISECT_LOG:
     -+	} else if (!strcmp("log", command)) {
     - 		if (argc)
     --			die(_("--bisect-log requires 0 arguments"));
     -+			die(_("'log' requires 0 arguments"));
     - 		res = bisect_log();
     --		break;
     --	case BISECT_RUN:
     -+	} else if (!strcmp("run", command)) {
     - 		if (!argc)
     - 			die(_("bisect run failed: no command provided."));
     - 		get_terms(&terms);
     - 		res = bisect_run(&terms, argv, argc);
     --		break;
     --	case BISECT_STATE:
     --		if (argc &&
     --		    !file_is_not_empty(git_path_bisect_start()) &&
     --		    !one_of(argv[0], "bad", "good", "new", "old", NULL))
     -+	} else {
     -+		if (!file_is_not_empty(git_path_bisect_start()) &&
     -+		    !one_of(command, "bad", "good", "new", "old", NULL))
     - 			usage(bisect_usage);
     - 		set_terms(&terms, "bad", "good");
     - 		get_terms(&terms);
     --		if (!cmdmode &&
     --		    (!argc || check_and_set_terms(&terms, argv[0])))
     -+		if (check_and_set_terms(&terms, command))
     - 			usage(bisect_usage);
     -+		/* shift the `command` back in */
     -+		argc++;
     -+		argv--;
     - 		res = bisect_state(&terms, argv, argc);
     --		break;
     --	default:
     --		BUG("unknown subcommand %d", cmdmode);
     - 	}
     -+
     - 	free_terms(&terms);
     - 
     - 	/*
     +@@ builtin/bisect--helper.c: int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
     + 		OPT_SUBCOMMAND("terms", &fn, cmd_bisect_terms),
     + 		OPT_SUBCOMMAND("start", &fn, cmd_bisect_start),
     + 		OPT_SUBCOMMAND("next", &fn, cmd_bisect_next),
     +-		OPT_SUBCOMMAND("state", &fn, cmd_bisect_state),
     + 		OPT_SUBCOMMAND("log", &fn, cmd_bisect_log),
     + 		OPT_SUBCOMMAND("replay", &fn, cmd_bisect_replay),
     + 		OPT_SUBCOMMAND("skip", &fn, cmd_bisect_skip),
      
       ## git-bisect.sh ##
      @@ git-bisect.sh: Please use "git help bisect" to get the full man page.'
     @@ git-bisect.sh: Please use "git help bisect" to get the full man page.'
      -	help)
      -		git bisect -h ;;
      -	start)
     --		git bisect--helper --bisect-start "$@" ;;
     +-		git bisect--helper start "$@" ;;
      -	bad|good|new|old|"$TERM_BAD"|"$TERM_GOOD")
      -		git bisect--helper "$cmd" "$@" ;;
      -	skip)
     --		git bisect--helper --bisect-skip "$@" || exit;;
     +-		git bisect--helper skip "$@" || exit;;
      -	next)
      -		# Not sure we want "next" at the UI level anymore.
     --		git bisect--helper --bisect-next "$@" || exit ;;
     +-		git bisect--helper next "$@" || exit ;;
      -	visualize|view)
     --		git bisect--helper --bisect-visualize "$@" || exit;;
     +-		git bisect--helper visualize "$@" || exit;;
      -	reset)
     --		git bisect--helper --bisect-reset "$@" ;;
     +-		git bisect--helper reset "$@" ;;
      -	replay)
     --		git bisect--helper --bisect-replay "$@" || exit;;
     +-		git bisect--helper replay "$@" || exit;;
      -	log)
     --		git bisect--helper --bisect-log || exit ;;
     +-		git bisect--helper log || exit ;;
      -	run)
     --		git bisect--helper --bisect-run "$@" || exit;;
     +-		git bisect--helper run "$@" || exit;;
      -	terms)
     --		git bisect--helper --bisect-terms "$@" || exit;;
     +-		git bisect--helper terms "$@" || exit;;
      -	*)
      -		usage ;;
      -	esac
 14:  378d6d22737 ! 14:  a8f08f5e0cb Turn `git bisect` into a full built-in
     @@ builtin.h: int cmd_am(int argc, const char **argv, const char *prefix);
       int cmd_bugreport(int argc, const char **argv, const char *prefix);
      
       ## builtin/bisect--helper.c => builtin/bisect.c ##
     -@@ builtin/bisect.c: static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
     +@@ builtin/bisect.c: static int cmd_bisect_run(int argc, const char **argv, const char *prefix)
       	return res;
       }
       
      -int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
      +int cmd_bisect(int argc, const char **argv, const char *prefix)
       {
     - 	int res = 0;
     - 	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
     + 	struct strvec args = STRVEC_INIT;
     + 	parse_opt_subcommand_fn *fn = NULL;
      
       ## git-bisect.sh (deleted) ##
      @@
     @@ git-bisect.sh (deleted)
      
       ## git.c ##
      @@ git.c: static struct cmd_struct commands[] = {
     - 	{ "annotate", cmd_annotate, RUN_SETUP | NO_PARSEOPT },
     + 	{ "annotate", cmd_annotate, RUN_SETUP },
       	{ "apply", cmd_apply, RUN_SETUP_GENTLY },
       	{ "archive", cmd_archive, RUN_SETUP_GENTLY },
      -	{ "bisect--helper", cmd_bisect__helper, RUN_SETUP },
 15:  33566b86d77 ! 15:  a96489310d3 bisect: remove Cogito-related code
     @@ builtin/bisect.c: static GIT_PATH_FUNC(git_path_bisect_expected_rev, "BISECT_EXP
       static GIT_PATH_FUNC(git_path_bisect_names, "BISECT_NAMES")
       static GIT_PATH_FUNC(git_path_bisect_first_parent, "BISECT_FIRST_PARENT")
       static GIT_PATH_FUNC(git_path_bisect_run, "BISECT_RUN")
     -@@ builtin/bisect.c: static enum bisect_error bisect_start(struct bisect_terms *terms, const char **a
     +@@ builtin/bisect.c: static int cmd_bisect_start(int argc, const char **argv, const char *prefix)
       			strbuf_addstr(&start_head, oid_to_hex(&head_oid));
       		} else if (!get_oid(head, &head_oid) &&
       			   skip_prefix(head, "refs/heads/", &head)) {
 16:  334664f23a8 = 16:  bfa7aa19f03 bisect: no longer try to clean up left-over `.git/head-name` files

-- 
gitgitgadget

^ permalink raw reply	[flat|nested] 147+ messages in thread

* [PATCH v5 01/16] bisect--helper: retire the --no-log option
  2022-08-27 12:44       ` [PATCH v5 " Johannes Schindelin via GitGitGadget
@ 2022-08-27 12:44         ` Johannes Schindelin via GitGitGadget
  2022-08-27 12:44         ` [PATCH v5 02/16] bisect--helper: really retire --bisect-next-check Johannes Schindelin via GitGitGadget
                           ` (15 subsequent siblings)
  16 siblings, 0 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-08-27 12:44 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Bagas Sanjaya, Junio C Hamano, Johannes Schindelin,
	Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

Turns out we actually never used it, anyway...

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/bisect--helper.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 7097750fc6b..2cc69e1eee5 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1292,7 +1292,7 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 		BISECT_VISUALIZE,
 		BISECT_RUN,
 	} cmdmode = 0;
-	int res = 0, nolog = 0;
+	int res = 0;
 	struct option options[] = {
 		OPT_CMDMODE(0, "bisect-reset", &cmdmode,
 			 N_("reset the bisection state"), BISECT_RESET),
@@ -1316,8 +1316,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 			 N_("visualize the bisection"), BISECT_VISUALIZE),
 		OPT_CMDMODE(0, "bisect-run", &cmdmode,
 			 N_("use <cmd>... to automatically bisect"), BISECT_RUN),
-		OPT_BOOL(0, "no-log", &nolog,
-			 N_("no log for BISECT_WRITE")),
 		OPT_END()
 	};
 	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH v5 02/16] bisect--helper: really retire --bisect-next-check
  2022-08-27 12:44       ` [PATCH v5 " Johannes Schindelin via GitGitGadget
  2022-08-27 12:44         ` [PATCH v5 01/16] bisect--helper: retire the --no-log option Johannes Schindelin via GitGitGadget
@ 2022-08-27 12:44         ` Johannes Schindelin via GitGitGadget
  2022-08-27 12:44         ` [PATCH v5 03/16] bisect--helper: really retire `--bisect-autostart` Johannes Schindelin via GitGitGadget
                           ` (14 subsequent siblings)
  16 siblings, 0 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-08-27 12:44 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Bagas Sanjaya, Junio C Hamano, Johannes Schindelin,
	Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

In 911aba14205 (bisect--helper: retire `--bisect-next-check` subcommand,
2021-09-13), we removed the usage string and the implementation, but not
actually the option.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/bisect--helper.c | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 2cc69e1eee5..bdf7ce18d7a 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1280,7 +1280,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 {
 	enum {
 		BISECT_RESET = 1,
-		BISECT_NEXT_CHECK,
 		BISECT_TERMS,
 		BISECT_START,
 		BISECT_AUTOSTART,
@@ -1296,8 +1295,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 	struct option options[] = {
 		OPT_CMDMODE(0, "bisect-reset", &cmdmode,
 			 N_("reset the bisection state"), BISECT_RESET),
-		OPT_CMDMODE(0, "bisect-next-check", &cmdmode,
-			 N_("check whether bad or good terms exist"), BISECT_NEXT_CHECK),
 		OPT_CMDMODE(0, "bisect-terms", &cmdmode,
 			 N_("print out the bisect terms"), BISECT_TERMS),
 		OPT_CMDMODE(0, "bisect-start", &cmdmode,
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH v5 03/16] bisect--helper: really retire `--bisect-autostart`
  2022-08-27 12:44       ` [PATCH v5 " Johannes Schindelin via GitGitGadget
  2022-08-27 12:44         ` [PATCH v5 01/16] bisect--helper: retire the --no-log option Johannes Schindelin via GitGitGadget
  2022-08-27 12:44         ` [PATCH v5 02/16] bisect--helper: really retire --bisect-next-check Johannes Schindelin via GitGitGadget
@ 2022-08-27 12:44         ` Johannes Schindelin via GitGitGadget
  2022-08-27 12:44         ` [PATCH v5 04/16] bisect--helper: simplify exit code computation Johannes Schindelin via GitGitGadget
                           ` (13 subsequent siblings)
  16 siblings, 0 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-08-27 12:44 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Bagas Sanjaya, Junio C Hamano, Johannes Schindelin,
	Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

Since b0f6494f70f (bisect--helper: retire `--bisect-autostart`
subcommand, 2020-10-15), the `--bisect-autostart` option is no more. But
we kept the `enum` value of the command mode around. Let's drop it, too.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/bisect--helper.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index bdf7ce18d7a..aa94c25ec73 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1282,7 +1282,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 		BISECT_RESET = 1,
 		BISECT_TERMS,
 		BISECT_START,
-		BISECT_AUTOSTART,
 		BISECT_NEXT,
 		BISECT_STATE,
 		BISECT_LOG,
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH v5 04/16] bisect--helper: simplify exit code computation
  2022-08-27 12:44       ` [PATCH v5 " Johannes Schindelin via GitGitGadget
                           ` (2 preceding siblings ...)
  2022-08-27 12:44         ` [PATCH v5 03/16] bisect--helper: really retire `--bisect-autostart` Johannes Schindelin via GitGitGadget
@ 2022-08-27 12:44         ` Johannes Schindelin via GitGitGadget
  2022-08-28  6:43           ` Junio C Hamano
  2022-08-27 12:44         ` [PATCH v5 05/16] bisect--helper: make `terms` an explicit singleton Johannes Schindelin via GitGitGadget
                           ` (12 subsequent siblings)
  16 siblings, 1 reply; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-08-27 12:44 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Bagas Sanjaya, Junio C Hamano, Johannes Schindelin,
	Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

We _already_ have a function to determine whether a given `enum
bisect_error` value is non-zero but still _actually_ indicates success.

Let's use it instead of duplicating the logic.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/bisect--helper.c | 9 +--------
 1 file changed, 1 insertion(+), 8 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index aa94c25ec73..2f9c7f54f3f 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1380,12 +1380,5 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 	}
 	free_terms(&terms);
 
-	/*
-	 * Handle early success
-	 * From check_merge_bases > check_good_are_ancestors_of_bad > bisect_next_all
-	 */
-	if ((res == BISECT_INTERNAL_SUCCESS_MERGE_BASE) || (res == BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND))
-		res = BISECT_OK;
-
-	return -res;
+	return is_bisect_success(res) ? 0 : -res;
 }
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH v5 05/16] bisect--helper: make `terms` an explicit singleton
  2022-08-27 12:44       ` [PATCH v5 " Johannes Schindelin via GitGitGadget
                           ` (3 preceding siblings ...)
  2022-08-27 12:44         ` [PATCH v5 04/16] bisect--helper: simplify exit code computation Johannes Schindelin via GitGitGadget
@ 2022-08-27 12:44         ` Johannes Schindelin via GitGitGadget
  2022-08-28  6:53           ` Junio C Hamano
  2022-08-29 10:20           ` Ævar Arnfjörð Bjarmason
  2022-08-27 12:44         ` [PATCH v5 06/16] bisect--helper: make the order consistently `argc, argv` Johannes Schindelin via GitGitGadget
                           ` (11 subsequent siblings)
  16 siblings, 2 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-08-27 12:44 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Bagas Sanjaya, Junio C Hamano, Johannes Schindelin,
	Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

We tried very hard to keep code in `builtin/bisect--helper.c` in as
libifyable a state as possible.

However, we are about to migrate this built-in to the `OPT_SUBCOMMAND()`
API, which does not allow for passing any context (e.g. via a `void
*data` parameters as they are used in the config API).

Therefore, we _have_ to move the `terms` variable outside of
`cmd_bisect__helper()` and explicitly make it a singleton (as it
currently is, anyway).

Let's just make things consistent and stop passing around pointers to
that singleton; Use it directly instead.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/bisect--helper.c | 262 +++++++++++++++++++--------------------
 1 file changed, 128 insertions(+), 134 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 2f9c7f54f3f..7f4e8e707c1 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -40,30 +40,30 @@ struct add_bisect_ref_data {
 	unsigned int object_flags;
 };
 
-struct bisect_terms {
+static struct bisect_terms {
 	char *term_good;
 	char *term_bad;
-};
+} terms;
 
-static void free_terms(struct bisect_terms *terms)
+static void free_terms(void)
 {
-	FREE_AND_NULL(terms->term_good);
-	FREE_AND_NULL(terms->term_bad);
+	FREE_AND_NULL(terms.term_good);
+	FREE_AND_NULL(terms.term_bad);
 }
 
-static void set_terms(struct bisect_terms *terms, const char *bad,
+static void set_terms(const char *bad,
 		      const char *good)
 {
-	free((void *)terms->term_good);
-	terms->term_good = xstrdup(good);
-	free((void *)terms->term_bad);
-	terms->term_bad = xstrdup(bad);
+	free((void *)terms.term_good);
+	terms.term_good = xstrdup(good);
+	free((void *)terms.term_bad);
+	terms.term_bad = xstrdup(bad);
 }
 
 static const char vocab_bad[] = "bad|new";
 static const char vocab_good[] = "good|old";
 
-static int bisect_autostart(struct bisect_terms *terms);
+static int bisect_autostart(void);
 
 /*
  * Check whether the string `term` belongs to the set of strings
@@ -254,8 +254,7 @@ static void log_commit(FILE *fp, char *fmt, const char *state,
 	free(label);
 }
 
-static int bisect_write(const char *state, const char *rev,
-			const struct bisect_terms *terms, int nolog)
+static int bisect_write(const char *state, const char *rev, int nolog)
 {
 	struct strbuf tag = STRBUF_INIT;
 	struct object_id oid;
@@ -263,9 +262,9 @@ static int bisect_write(const char *state, const char *rev,
 	FILE *fp = NULL;
 	int res = 0;
 
-	if (!strcmp(state, terms->term_bad)) {
+	if (!strcmp(state, terms.term_bad)) {
 		strbuf_addf(&tag, "refs/bisect/%s", state);
-	} else if (one_of(state, terms->term_good, "skip", NULL)) {
+	} else if (one_of(state, terms.term_good, "skip", NULL)) {
 		strbuf_addf(&tag, "refs/bisect/%s-%s", state, rev);
 	} else {
 		res = error(_("Bad bisect_write argument: %s"), state);
@@ -302,27 +301,27 @@ finish:
 	return res;
 }
 
-static int check_and_set_terms(struct bisect_terms *terms, const char *cmd)
+static int check_and_set_terms(const char *cmd)
 {
 	int has_term_file = !is_empty_or_missing_file(git_path_bisect_terms());
 
 	if (one_of(cmd, "skip", "start", "terms", NULL))
 		return 0;
 
-	if (has_term_file && strcmp(cmd, terms->term_bad) &&
-	    strcmp(cmd, terms->term_good))
+	if (has_term_file && strcmp(cmd, terms.term_bad) &&
+	    strcmp(cmd, terms.term_good))
 		return error(_("Invalid command: you're currently in a "
-				"%s/%s bisect"), terms->term_bad,
-				terms->term_good);
+				"%s/%s bisect"), terms.term_bad,
+				terms.term_good);
 
 	if (!has_term_file) {
 		if (one_of(cmd, "bad", "good", NULL)) {
-			set_terms(terms, "bad", "good");
-			return write_terms(terms->term_bad, terms->term_good);
+			set_terms("bad", "good");
+			return write_terms(terms.term_bad, terms.term_good);
 		}
 		if (one_of(cmd, "new", "old", NULL)) {
-			set_terms(terms, "new", "old");
-			return write_terms(terms->term_bad, terms->term_good);
+			set_terms("new", "old");
+			return write_terms(terms.term_bad, terms.term_good);
 		}
 	}
 
@@ -346,8 +345,7 @@ static const char need_bisect_start_warning[] =
 	   "You then need to give me at least one %s and %s revision.\n"
 	   "You can use \"git bisect %s\" and \"git bisect %s\" for that.");
 
-static int decide_next(const struct bisect_terms *terms,
-		       const char *current_term, int missing_good,
+static int decide_next(const char *current_term, int missing_good,
 		       int missing_bad)
 {
 	if (!missing_good && !missing_bad)
@@ -356,13 +354,13 @@ static int decide_next(const struct bisect_terms *terms,
 		return -1;
 
 	if (missing_good && !missing_bad &&
-	    !strcmp(current_term, terms->term_good)) {
+	    !strcmp(current_term, terms.term_good)) {
 		char *yesno;
 		/*
 		 * have bad (or new) but not good (or old). We could bisect
 		 * although this is less optimum.
 		 */
-		warning(_("bisecting only with a %s commit"), terms->term_bad);
+		warning(_("bisecting only with a %s commit"), terms.term_bad);
 		if (!isatty(0))
 			return 0;
 		/*
@@ -384,11 +382,10 @@ static int decide_next(const struct bisect_terms *terms,
 			     vocab_good, vocab_bad, vocab_good, vocab_bad);
 }
 
-static void bisect_status(struct bisect_state *state,
-			  const struct bisect_terms *terms)
+static void bisect_status(struct bisect_state *state)
 {
-	char *bad_ref = xstrfmt("refs/bisect/%s", terms->term_bad);
-	char *good_glob = xstrfmt("%s-*", terms->term_good);
+	char *bad_ref = xstrfmt("refs/bisect/%s", terms.term_bad);
+	char *good_glob = xstrfmt("%s-*", terms.term_good);
 
 	if (ref_exists(bad_ref))
 		state->nr_bad = 1;
@@ -416,11 +413,11 @@ static void bisect_log_printf(const char *fmt, ...)
 	strbuf_release(&buf);
 }
 
-static void bisect_print_status(const struct bisect_terms *terms)
+static void bisect_print_status(void)
 {
 	struct bisect_state state = { 0 };
 
-	bisect_status(&state, terms);
+	bisect_status(&state);
 
 	/* If we had both, we'd already be started, and shouldn't get here. */
 	if (state.nr_good && state.nr_bad)
@@ -436,15 +433,14 @@ static void bisect_print_status(const struct bisect_terms *terms)
 		bisect_log_printf(_("status: waiting for good commit(s), bad commit known\n"));
 }
 
-static int bisect_next_check(const struct bisect_terms *terms,
-			     const char *current_term)
+static int bisect_next_check(const char *current_term)
 {
 	struct bisect_state state = { 0 };
-	bisect_status(&state, terms);
-	return decide_next(terms, current_term, !state.nr_good, !state.nr_bad);
+	bisect_status(&state);
+	return decide_next(current_term, !state.nr_good, !state.nr_bad);
 }
 
-static int get_terms(struct bisect_terms *terms)
+static int get_terms(void)
 {
 	struct strbuf str = STRBUF_INIT;
 	FILE *fp = NULL;
@@ -456,11 +452,11 @@ static int get_terms(struct bisect_terms *terms)
 		goto finish;
 	}
 
-	free_terms(terms);
+	free_terms();
 	strbuf_getline_lf(&str, fp);
-	terms->term_bad = strbuf_detach(&str, NULL);
+	terms.term_bad = strbuf_detach(&str, NULL);
 	strbuf_getline_lf(&str, fp);
-	terms->term_good = strbuf_detach(&str, NULL);
+	terms.term_good = strbuf_detach(&str, NULL);
 
 finish:
 	if (fp)
@@ -469,21 +465,21 @@ finish:
 	return res;
 }
 
-static int bisect_terms(struct bisect_terms *terms, const char *option)
+static int bisect_terms(const char *option)
 {
-	if (get_terms(terms))
+	if (get_terms())
 		return error(_("no terms defined"));
 
 	if (!option) {
 		printf(_("Your current terms are %s for the old state\n"
 			 "and %s for the new state.\n"),
-		       terms->term_good, terms->term_bad);
+		       terms.term_good, terms.term_bad);
 		return 0;
 	}
 	if (one_of(option, "--term-good", "--term-old", NULL))
-		printf("%s\n", terms->term_good);
+		printf("%s\n", terms.term_good);
 	else if (one_of(option, "--term-bad", "--term-new", NULL))
-		printf("%s\n", terms->term_bad);
+		printf("%s\n", terms.term_bad);
 	else
 		return error(_("invalid argument %s for 'git bisect terms'.\n"
 			       "Supported options are: "
@@ -527,18 +523,18 @@ static int add_bisect_ref(const char *refname, const struct object_id *oid,
 	return 0;
 }
 
-static int prepare_revs(struct bisect_terms *terms, struct rev_info *revs)
+static int prepare_revs(struct rev_info *revs)
 {
 	int res = 0;
 	struct add_bisect_ref_data cb = { revs };
-	char *good = xstrfmt("%s-*", terms->term_good);
+	char *good = xstrfmt("%s-*", terms.term_good);
 
 	/*
-	 * We cannot use terms->term_bad directly in
+	 * We cannot use terms.term_bad directly in
 	 * for_each_glob_ref_in() and we have to append a '*' to it,
 	 * otherwise for_each_glob_ref_in() will append '/' and '*'.
 	 */
-	char *bad = xstrfmt("%s*", terms->term_bad);
+	char *bad = xstrfmt("%s*", terms.term_bad);
 
 	/*
 	 * It is important to reset the flags used by revision walks
@@ -559,7 +555,7 @@ static int prepare_revs(struct bisect_terms *terms, struct rev_info *revs)
 	return res;
 }
 
-static int bisect_skipped_commits(struct bisect_terms *terms)
+static int bisect_skipped_commits(void)
 {
 	int res;
 	FILE *fp = NULL;
@@ -568,7 +564,7 @@ static int bisect_skipped_commits(struct bisect_terms *terms)
 	struct pretty_print_context pp = {0};
 	struct strbuf commit_name = STRBUF_INIT;
 
-	res = prepare_revs(terms, &revs);
+	res = prepare_revs(&revs);
 	if (res)
 		return res;
 
@@ -585,7 +581,7 @@ static int bisect_skipped_commits(struct bisect_terms *terms)
 		format_commit_message(commit, "%s",
 				      &commit_name, &pp);
 		fprintf(fp, "# possible first %s commit: [%s] %s\n",
-			terms->term_bad, oid_to_hex(&commit->object.oid),
+			terms.term_bad, oid_to_hex(&commit->object.oid),
 			commit_name.buf);
 	}
 
@@ -601,13 +597,13 @@ static int bisect_skipped_commits(struct bisect_terms *terms)
 	return 0;
 }
 
-static int bisect_successful(struct bisect_terms *terms)
+static int bisect_successful(void)
 {
 	struct object_id oid;
 	struct commit *commit;
 	struct pretty_print_context pp = {0};
 	struct strbuf commit_name = STRBUF_INIT;
-	char *bad_ref = xstrfmt("refs/bisect/%s",terms->term_bad);
+	char *bad_ref = xstrfmt("refs/bisect/%s",terms.term_bad);
 	int res;
 
 	read_ref(bad_ref, &oid);
@@ -615,7 +611,7 @@ static int bisect_successful(struct bisect_terms *terms)
 	format_commit_message(commit, "%s", &commit_name, &pp);
 
 	res = append_to_file(git_path_bisect_log(), "# first %s commit: [%s] %s\n",
-			    terms->term_bad, oid_to_hex(&commit->object.oid),
+			    terms.term_bad, oid_to_hex(&commit->object.oid),
 			    commit_name.buf);
 
 	strbuf_release(&commit_name);
@@ -623,40 +619,40 @@ static int bisect_successful(struct bisect_terms *terms)
 	return res;
 }
 
-static enum bisect_error bisect_next(struct bisect_terms *terms, const char *prefix)
+static enum bisect_error bisect_next(const char *prefix)
 {
 	enum bisect_error res;
 
-	if (bisect_autostart(terms))
+	if (bisect_autostart())
 		return BISECT_FAILED;
 
-	if (bisect_next_check(terms, terms->term_good))
+	if (bisect_next_check(terms.term_good))
 		return BISECT_FAILED;
 
 	/* Perform all bisection computation */
 	res = bisect_next_all(the_repository, prefix);
 
 	if (res == BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND) {
-		res = bisect_successful(terms);
+		res = bisect_successful();
 		return res ? res : BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND;
 	} else if (res == BISECT_ONLY_SKIPPED_LEFT) {
-		res = bisect_skipped_commits(terms);
+		res = bisect_skipped_commits();
 		return res ? res : BISECT_ONLY_SKIPPED_LEFT;
 	}
 	return res;
 }
 
-static enum bisect_error bisect_auto_next(struct bisect_terms *terms, const char *prefix)
+static enum bisect_error bisect_auto_next(const char *prefix)
 {
-	if (bisect_next_check(terms, NULL)) {
-		bisect_print_status(terms);
+	if (bisect_next_check(NULL)) {
+		bisect_print_status();
 		return BISECT_OK;
 	}
 
-	return bisect_next(terms, prefix);
+	return bisect_next(prefix);
 }
 
-static enum bisect_error bisect_start(struct bisect_terms *terms, const char **argv, int argc)
+static enum bisect_error bisect_start(const char **argv, int argc)
 {
 	int no_checkout = 0;
 	int first_parent_only = 0;
@@ -698,26 +694,26 @@ static enum bisect_error bisect_start(struct bisect_terms *terms, const char **a
 			if (argc <= i)
 				return error(_("'' is not a valid term"));
 			must_write_terms = 1;
-			free((void *) terms->term_good);
-			terms->term_good = xstrdup(argv[i]);
+			free((void *) terms.term_good);
+			terms.term_good = xstrdup(argv[i]);
 		} else if (skip_prefix(arg, "--term-good=", &arg) ||
 			   skip_prefix(arg, "--term-old=", &arg)) {
 			must_write_terms = 1;
-			free((void *) terms->term_good);
-			terms->term_good = xstrdup(arg);
+			free((void *) terms.term_good);
+			terms.term_good = xstrdup(arg);
 		} else if (!strcmp(arg, "--term-bad") ||
 			 !strcmp(arg, "--term-new")) {
 			i++;
 			if (argc <= i)
 				return error(_("'' is not a valid term"));
 			must_write_terms = 1;
-			free((void *) terms->term_bad);
-			terms->term_bad = xstrdup(argv[i]);
+			free((void *) terms.term_bad);
+			terms.term_bad = xstrdup(argv[i]);
 		} else if (skip_prefix(arg, "--term-bad=", &arg) ||
 			   skip_prefix(arg, "--term-new=", &arg)) {
 			must_write_terms = 1;
-			free((void *) terms->term_bad);
-			terms->term_bad = xstrdup(arg);
+			free((void *) terms.term_bad);
+			terms.term_bad = xstrdup(arg);
 		} else if (starts_with(arg, "--")) {
 			return error(_("unrecognized option: '%s'"), arg);
 		} else if (!get_oidf(&oid, "%s^{commit}", arg)) {
@@ -741,10 +737,10 @@ static enum bisect_error bisect_start(struct bisect_terms *terms, const char **a
 		must_write_terms = 1;
 	for (i = 0; i < revs.nr; i++) {
 		if (bad_seen) {
-			string_list_append(&states, terms->term_good);
+			string_list_append(&states, terms.term_good);
 		} else {
 			bad_seen = 1;
-			string_list_append(&states, terms->term_bad);
+			string_list_append(&states, terms.term_bad);
 		}
 	}
 
@@ -829,13 +825,13 @@ static enum bisect_error bisect_start(struct bisect_terms *terms, const char **a
 
 	for (i = 0; i < states.nr; i++)
 		if (bisect_write(states.items[i].string,
-				 revs.items[i].string, terms, 1)) {
+				 revs.items[i].string, 1)) {
 			res = BISECT_FAILED;
 			goto finish;
 		}
 
-	if (must_write_terms && write_terms(terms->term_bad,
-					    terms->term_good)) {
+	if (must_write_terms && write_terms(terms.term_bad,
+					    terms.term_good)) {
 		res = BISECT_FAILED;
 		goto finish;
 	}
@@ -852,7 +848,7 @@ finish:
 	if (res)
 		return res;
 
-	res = bisect_auto_next(terms, NULL);
+	res = bisect_auto_next(NULL);
 	if (!is_bisect_success(res))
 		bisect_clean_state();
 	return res;
@@ -863,7 +859,7 @@ static inline int file_is_not_empty(const char *path)
 	return !is_empty_or_missing_file(path);
 }
 
-static int bisect_autostart(struct bisect_terms *terms)
+static int bisect_autostart(void)
 {
 	int res;
 	const char *yesno;
@@ -885,12 +881,12 @@ static int bisect_autostart(struct bisect_terms *terms)
 	yesno = git_prompt(_("Do you want me to do it for you "
 			     "[Y/n]? "), PROMPT_ECHO);
 	res = tolower(*yesno) == 'n' ?
-		-1 : bisect_start(terms, empty_strvec, 0);
+		-1 : bisect_start(empty_strvec, 0);
 
 	return res;
 }
 
-static enum bisect_error bisect_state(struct bisect_terms *terms, const char **argv,
+static enum bisect_error bisect_state(const char **argv,
 				      int argc)
 {
 	const char *state;
@@ -902,18 +898,18 @@ static enum bisect_error bisect_state(struct bisect_terms *terms, const char **a
 	if (!argc)
 		return error(_("Please call `--bisect-state` with at least one argument"));
 
-	if (bisect_autostart(terms))
+	if (bisect_autostart())
 		return BISECT_FAILED;
 
 	state = argv[0];
-	if (check_and_set_terms(terms, state) ||
-	    !one_of(state, terms->term_good, terms->term_bad, "skip", NULL))
+	if (check_and_set_terms(state) ||
+	    !one_of(state, terms.term_good, terms.term_bad, "skip", NULL))
 		return BISECT_FAILED;
 
 	argv++;
 	argc--;
-	if (argc > 1 && !strcmp(state, terms->term_bad))
-		return error(_("'git bisect %s' can take only one argument."), terms->term_bad);
+	if (argc > 1 && !strcmp(state, terms.term_bad))
+		return error(_("'git bisect %s' can take only one argument."), terms.term_bad);
 
 	if (argc == 0) {
 		const char *head = "BISECT_HEAD";
@@ -956,7 +952,7 @@ static enum bisect_error bisect_state(struct bisect_terms *terms, const char **a
 	strbuf_release(&buf);
 
 	for (i = 0; i < revs.nr; i++) {
-		if (bisect_write(state, oid_to_hex(&revs.oid[i]), terms, 0)) {
+		if (bisect_write(state, oid_to_hex(&revs.oid[i]), 0)) {
 			oid_array_clear(&revs);
 			return BISECT_FAILED;
 		}
@@ -968,7 +964,7 @@ static enum bisect_error bisect_state(struct bisect_terms *terms, const char **a
 	}
 
 	oid_array_clear(&revs);
-	return bisect_auto_next(terms, NULL);
+	return bisect_auto_next(NULL);
 }
 
 static enum bisect_error bisect_log(void)
@@ -988,7 +984,7 @@ static enum bisect_error bisect_log(void)
 	return status ? BISECT_FAILED : BISECT_OK;
 }
 
-static int process_replay_line(struct bisect_terms *terms, struct strbuf *line)
+static int process_replay_line(struct strbuf *line)
 {
 	const char *p = line->buf + strspn(line->buf, " \t");
 	char *word_end, *rev;
@@ -1002,28 +998,28 @@ static int process_replay_line(struct bisect_terms *terms, struct strbuf *line)
 	rev = word_end + strspn(word_end, " \t");
 	*word_end = '\0'; /* NUL-terminate the word */
 
-	get_terms(terms);
-	if (check_and_set_terms(terms, p))
+	get_terms();
+	if (check_and_set_terms(p))
 		return -1;
 
 	if (!strcmp(p, "start")) {
 		struct strvec argv = STRVEC_INIT;
 		int res;
 		sq_dequote_to_strvec(rev, &argv);
-		res = bisect_start(terms, argv.v, argv.nr);
+		res = bisect_start(argv.v, argv.nr);
 		strvec_clear(&argv);
 		return res;
 	}
 
-	if (one_of(p, terms->term_good,
-	   terms->term_bad, "skip", NULL))
-		return bisect_write(p, rev, terms, 0);
+	if (one_of(p, terms.term_good,
+	   terms.term_bad, "skip", NULL))
+		return bisect_write(p, rev, 0);
 
 	if (!strcmp(p, "terms")) {
 		struct strvec argv = STRVEC_INIT;
 		int res;
 		sq_dequote_to_strvec(rev, &argv);
-		res = bisect_terms(terms, argv.nr == 1 ? argv.v[0] : NULL);
+		res = bisect_terms(argv.nr == 1 ? argv.v[0] : NULL);
 		strvec_clear(&argv);
 		return res;
 	}
@@ -1032,7 +1028,7 @@ static int process_replay_line(struct bisect_terms *terms, struct strbuf *line)
 	return -1;
 }
 
-static enum bisect_error bisect_replay(struct bisect_terms *terms, const char *filename)
+static enum bisect_error bisect_replay(const char *filename)
 {
 	FILE *fp = NULL;
 	enum bisect_error res = BISECT_OK;
@@ -1049,7 +1045,7 @@ static enum bisect_error bisect_replay(struct bisect_terms *terms, const char *f
 		return BISECT_FAILED;
 
 	while ((strbuf_getline(&line, fp) != EOF) && !res)
-		res = process_replay_line(terms, &line);
+		res = process_replay_line(&line);
 
 	strbuf_release(&line);
 	fclose(fp);
@@ -1057,10 +1053,10 @@ static enum bisect_error bisect_replay(struct bisect_terms *terms, const char *f
 	if (res)
 		return BISECT_FAILED;
 
-	return bisect_auto_next(terms, NULL);
+	return bisect_auto_next(NULL);
 }
 
-static enum bisect_error bisect_skip(struct bisect_terms *terms, const char **argv, int argc)
+static enum bisect_error bisect_skip(const char **argv, int argc)
 {
 	int i;
 	enum bisect_error res;
@@ -1090,19 +1086,19 @@ static enum bisect_error bisect_skip(struct bisect_terms *terms, const char **ar
 			strvec_push(&argv_state, argv[i]);
 		}
 	}
-	res = bisect_state(terms, argv_state.v, argv_state.nr);
+	res = bisect_state(argv_state.v, argv_state.nr);
 
 	strvec_clear(&argv_state);
 	return res;
 }
 
-static int bisect_visualize(struct bisect_terms *terms, const char **argv, int argc)
+static int bisect_visualize(const char **argv, int argc)
 {
 	struct strvec args = STRVEC_INIT;
 	int flags = RUN_COMMAND_NO_STDIN, res = 0;
 	struct strbuf sb = STRBUF_INIT;
 
-	if (bisect_next_check(terms, NULL) != 0)
+	if (bisect_next_check(NULL) != 0)
 		return BISECT_FAILED;
 
 	if (!argc) {
@@ -1141,14 +1137,13 @@ static int get_first_good(const char *refname, const struct object_id *oid,
 	return 1;
 }
 
-static int verify_good(const struct bisect_terms *terms,
-		       const char **quoted_argv)
+static int verify_good(const char **quoted_argv)
 {
 	int rc;
 	enum bisect_error res;
 	struct object_id good_rev;
 	struct object_id current_rev;
-	char *good_glob = xstrfmt("%s-*", terms->term_good);
+	char *good_glob = xstrfmt("%s-*", terms.term_good);
 	int no_checkout = ref_exists("BISECT_HEAD");
 
 	for_each_glob_ref_in(get_first_good, good_glob, "refs/bisect/",
@@ -1172,7 +1167,7 @@ static int verify_good(const struct bisect_terms *terms,
 	return rc;
 }
 
-static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
+static int bisect_run(const char **argv, int argc)
 {
 	int res = BISECT_OK;
 	struct strbuf command = STRBUF_INIT;
@@ -1181,7 +1176,7 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
 	int temporary_stdout_fd, saved_stdout;
 	int is_first_run = 1;
 
-	if (bisect_next_check(terms, NULL))
+	if (bisect_next_check(NULL))
 		return BISECT_FAILED;
 
 	if (argc)
@@ -1205,7 +1200,7 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
 		 * missing or non-executable script.
 		 */
 		if (is_first_run && (res == 126 || res == 127)) {
-			int rc = verify_good(terms, run_args.v);
+			int rc = verify_good(run_args.v);
 			is_first_run = 0;
 			if (rc < 0) {
 				error(_("unable to verify '%s' on good"
@@ -1230,9 +1225,9 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
 		if (res == 125)
 			new_state = "skip";
 		else if (!res)
-			new_state = terms->term_good;
+			new_state = terms.term_good;
 		else
-			new_state = terms->term_bad;
+			new_state = terms.term_bad;
 
 		temporary_stdout_fd = open(git_path_bisect_run(), O_CREAT | O_WRONLY | O_TRUNC, 0666);
 
@@ -1245,7 +1240,7 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
 		saved_stdout = dup(1);
 		dup2(temporary_stdout_fd, 1);
 
-		res = bisect_state(terms, &new_state, 1);
+		res = bisect_state(&new_state, 1);
 
 		fflush(stdout);
 		dup2(saved_stdout, 1);
@@ -1314,7 +1309,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 			 N_("use <cmd>... to automatically bisect"), BISECT_RUN),
 		OPT_END()
 	};
-	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
 
 	argc = parse_options(argc, argv, prefix, options,
 			     git_bisect_helper_usage,
@@ -1332,22 +1326,22 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 	case BISECT_TERMS:
 		if (argc > 1)
 			return error(_("--bisect-terms requires 0 or 1 argument"));
-		res = bisect_terms(&terms, argc == 1 ? argv[0] : NULL);
+		res = bisect_terms(argc == 1 ? argv[0] : NULL);
 		break;
 	case BISECT_START:
-		set_terms(&terms, "bad", "good");
-		res = bisect_start(&terms, argv, argc);
+		set_terms("bad", "good");
+		res = bisect_start(argv, argc);
 		break;
 	case BISECT_NEXT:
 		if (argc)
 			return error(_("--bisect-next requires 0 arguments"));
-		get_terms(&terms);
-		res = bisect_next(&terms, prefix);
+		get_terms();
+		res = bisect_next(prefix);
 		break;
 	case BISECT_STATE:
-		set_terms(&terms, "bad", "good");
-		get_terms(&terms);
-		res = bisect_state(&terms, argv, argc);
+		set_terms("bad", "good");
+		get_terms();
+		res = bisect_state(argv, argc);
 		break;
 	case BISECT_LOG:
 		if (argc)
@@ -1357,28 +1351,28 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 	case BISECT_REPLAY:
 		if (argc != 1)
 			return error(_("no logfile given"));
-		set_terms(&terms, "bad", "good");
-		res = bisect_replay(&terms, argv[0]);
+		set_terms("bad", "good");
+		res = bisect_replay(argv[0]);
 		break;
 	case BISECT_SKIP:
-		set_terms(&terms, "bad", "good");
-		get_terms(&terms);
-		res = bisect_skip(&terms, argv, argc);
+		set_terms("bad", "good");
+		get_terms();
+		res = bisect_skip(argv, argc);
 		break;
 	case BISECT_VISUALIZE:
-		get_terms(&terms);
-		res = bisect_visualize(&terms, argv, argc);
+		get_terms();
+		res = bisect_visualize(argv, argc);
 		break;
 	case BISECT_RUN:
 		if (!argc)
 			return error(_("bisect run failed: no command provided."));
-		get_terms(&terms);
-		res = bisect_run(&terms, argv, argc);
+		get_terms();
+		res = bisect_run(argv, argc);
 		break;
 	default:
 		BUG("unknown subcommand %d", cmdmode);
 	}
-	free_terms(&terms);
+	free_terms();
 
 	return is_bisect_success(res) ? 0 : -res;
 }
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH v5 06/16] bisect--helper: make the order consistently `argc, argv`
  2022-08-27 12:44       ` [PATCH v5 " Johannes Schindelin via GitGitGadget
                           ` (4 preceding siblings ...)
  2022-08-27 12:44         ` [PATCH v5 05/16] bisect--helper: make `terms` an explicit singleton Johannes Schindelin via GitGitGadget
@ 2022-08-27 12:44         ` Johannes Schindelin via GitGitGadget
  2022-08-28  6:53           ` Junio C Hamano
  2022-08-27 12:44         ` [PATCH v5 07/16] bisect--helper: migrate to OPT_SUBCOMMAND() Johannes Schindelin via GitGitGadget
                           ` (10 subsequent siblings)
  16 siblings, 1 reply; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-08-27 12:44 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Bagas Sanjaya, Junio C Hamano, Johannes Schindelin,
	Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

In C, the natural order is for `argc` to come before `argv` by virtue of
the `main()` function declaring the parameters in precisely that order.

It is confusing & distracting, then, when readers familiar with the C
language read code where that order is switched around.

Let's just change the order and avoid that type of developer friction.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/bisect--helper.c | 29 ++++++++++++++---------------
 1 file changed, 14 insertions(+), 15 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 7f4e8e707c1..0d7cc20f9c9 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -652,7 +652,7 @@ static enum bisect_error bisect_auto_next(const char *prefix)
 	return bisect_next(prefix);
 }
 
-static enum bisect_error bisect_start(const char **argv, int argc)
+static enum bisect_error bisect_start(int argc, const char **argv)
 {
 	int no_checkout = 0;
 	int first_parent_only = 0;
@@ -881,13 +881,12 @@ static int bisect_autostart(void)
 	yesno = git_prompt(_("Do you want me to do it for you "
 			     "[Y/n]? "), PROMPT_ECHO);
 	res = tolower(*yesno) == 'n' ?
-		-1 : bisect_start(empty_strvec, 0);
+		-1 : bisect_start(0, empty_strvec);
 
 	return res;
 }
 
-static enum bisect_error bisect_state(const char **argv,
-				      int argc)
+static enum bisect_error bisect_state(int argc, const char **argv)
 {
 	const char *state;
 	int i, verify_expected = 1;
@@ -1006,7 +1005,7 @@ static int process_replay_line(struct strbuf *line)
 		struct strvec argv = STRVEC_INIT;
 		int res;
 		sq_dequote_to_strvec(rev, &argv);
-		res = bisect_start(argv.v, argv.nr);
+		res = bisect_start(argv.nr, argv.v);
 		strvec_clear(&argv);
 		return res;
 	}
@@ -1056,7 +1055,7 @@ static enum bisect_error bisect_replay(const char *filename)
 	return bisect_auto_next(NULL);
 }
 
-static enum bisect_error bisect_skip(const char **argv, int argc)
+static enum bisect_error bisect_skip(int argc, const char **argv)
 {
 	int i;
 	enum bisect_error res;
@@ -1086,13 +1085,13 @@ static enum bisect_error bisect_skip(const char **argv, int argc)
 			strvec_push(&argv_state, argv[i]);
 		}
 	}
-	res = bisect_state(argv_state.v, argv_state.nr);
+	res = bisect_state(argv_state.nr, argv_state.v);
 
 	strvec_clear(&argv_state);
 	return res;
 }
 
-static int bisect_visualize(const char **argv, int argc)
+static int bisect_visualize(int argc, const char **argv)
 {
 	struct strvec args = STRVEC_INIT;
 	int flags = RUN_COMMAND_NO_STDIN, res = 0;
@@ -1167,7 +1166,7 @@ static int verify_good(const char **quoted_argv)
 	return rc;
 }
 
-static int bisect_run(const char **argv, int argc)
+static int bisect_run(int argc, const char **argv)
 {
 	int res = BISECT_OK;
 	struct strbuf command = STRBUF_INIT;
@@ -1240,7 +1239,7 @@ static int bisect_run(const char **argv, int argc)
 		saved_stdout = dup(1);
 		dup2(temporary_stdout_fd, 1);
 
-		res = bisect_state(&new_state, 1);
+		res = bisect_state(1, &new_state);
 
 		fflush(stdout);
 		dup2(saved_stdout, 1);
@@ -1330,7 +1329,7 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 		break;
 	case BISECT_START:
 		set_terms("bad", "good");
-		res = bisect_start(argv, argc);
+		res = bisect_start(argc, argv);
 		break;
 	case BISECT_NEXT:
 		if (argc)
@@ -1341,7 +1340,7 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 	case BISECT_STATE:
 		set_terms("bad", "good");
 		get_terms();
-		res = bisect_state(argv, argc);
+		res = bisect_state(argc, argv);
 		break;
 	case BISECT_LOG:
 		if (argc)
@@ -1357,17 +1356,17 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 	case BISECT_SKIP:
 		set_terms("bad", "good");
 		get_terms();
-		res = bisect_skip(argv, argc);
+		res = bisect_skip(argc, argv);
 		break;
 	case BISECT_VISUALIZE:
 		get_terms();
-		res = bisect_visualize(argv, argc);
+		res = bisect_visualize(argc, argv);
 		break;
 	case BISECT_RUN:
 		if (!argc)
 			return error(_("bisect run failed: no command provided."));
 		get_terms();
-		res = bisect_run(argv, argc);
+		res = bisect_run(argc, argv);
 		break;
 	default:
 		BUG("unknown subcommand %d", cmdmode);
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH v5 07/16] bisect--helper: migrate to OPT_SUBCOMMAND()
  2022-08-27 12:44       ` [PATCH v5 " Johannes Schindelin via GitGitGadget
                           ` (5 preceding siblings ...)
  2022-08-27 12:44         ` [PATCH v5 06/16] bisect--helper: make the order consistently `argc, argv` Johannes Schindelin via GitGitGadget
@ 2022-08-27 12:44         ` Johannes Schindelin via GitGitGadget
  2022-08-29  9:38           ` Ævar Arnfjörð Bjarmason
  2022-08-27 12:44         ` [PATCH v5 08/16] bisect: verify that a bogus option won't try to start a bisection Johannes Schindelin via GitGitGadget
                           ` (9 subsequent siblings)
  16 siblings, 1 reply; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-08-27 12:44 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Bagas Sanjaya, Junio C Hamano, Johannes Schindelin,
	Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

We just introduced a new way to process subcommands, and the
`bisect--helper` learns about it in preparation for replacing the
`git-bisect.sh` script altogether.

Note that a couple of `bisect_*()` functions are not converted into
`cmd_bisect_*()` functions directly, as they have callers other than the
`OPT_SUBCOMMAND()` one (and the original functions did not expect
a subcommand name to be passed as `argv[0]`, unlike the convention for
the `cmd_*()` functions. In those cases, we introduce wrapper functions
`cmd_*()` that also call the original function.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/bisect--helper.c | 462 +++++++++++++++++++++++----------------
 git-bisect.sh            |  20 +-
 2 files changed, 288 insertions(+), 194 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 0d7cc20f9c9..d797cd1cef8 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -20,18 +20,71 @@ static GIT_PATH_FUNC(git_path_bisect_names, "BISECT_NAMES")
 static GIT_PATH_FUNC(git_path_bisect_first_parent, "BISECT_FIRST_PARENT")
 static GIT_PATH_FUNC(git_path_bisect_run, "BISECT_RUN")
 
-static const char * const git_bisect_helper_usage[] = {
-	N_("git bisect--helper --bisect-reset [<commit>]"),
-	"git bisect--helper --bisect-terms [--term-good | --term-old | --term-bad | --term-new]",
-	N_("git bisect--helper --bisect-start [--term-{new,bad}=<term> --term-{old,good}=<term>]"
-					    " [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<paths>...]"),
-	"git bisect--helper --bisect-next",
-	N_("git bisect--helper --bisect-state (bad|new) [<rev>]"),
-	N_("git bisect--helper --bisect-state (good|old) [<rev>...]"),
-	N_("git bisect--helper --bisect-replay <filename>"),
-	N_("git bisect--helper --bisect-skip [(<rev>|<range>)...]"),
-	"git bisect--helper --bisect-visualize",
-	N_("git bisect--helper --bisect-run <cmd>..."),
+static const char * const bisect_usage[] = {
+	N_("git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>]"
+	   "    [--no-checkout] [--first-parent] [<bad> [<good>...]] [--]"
+	   "    [<pathspec>...]"),
+	N_("git bisect (bad|new) [<rev>]"),
+	N_("git bisect (good|old) [<rev>...]"),
+	N_("git bisect terms [--term-good | --term-bad]"),
+	N_("git bisect skip [(<rev>|<range>)...]"),
+	N_("git bisect next"),
+	N_("git bisect reset [<commit>]"),
+	N_("git bisect (visualize|view)"),
+	N_("git bisect replay <logfile>"),
+	N_("git bisect log"),
+	N_("git bisect run <cmd>..."),
+	NULL
+};
+
+static const char * const bisect_start_usage[] = {
+	N_("git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>]"
+	   "    [--no-checkout] [--first-parent] [<bad> [<good>...]] [--]"
+	   "    [<pathspec>...]"),
+	NULL
+};
+static const char * const bisect_state_usage[] = {
+	N_("git bisect (good|bad) [<rev>...]"),
+	NULL
+};
+
+static const char * const bisect_terms_usage[] = {
+	N_("git bisect terms [--term-good | --term-bad]"),
+	NULL
+};
+
+static const char * const bisect_skip_usage[] = {
+	N_("git bisect skip [(<rev>|<range>)...]"),
+	NULL
+};
+
+static const char * const bisect_next_usage[] = {
+	N_("git bisect next"),
+	NULL
+};
+
+static const char * const bisect_reset_usage[] = {
+	N_("git bisect reset [<commit>]"),
+	NULL
+};
+
+static const char * const bisect_visualize_usage[] = {
+	N_("git bisect visualize"),
+	NULL
+};
+
+static const char * const bisect_replay_usage[] = {
+	N_("git bisect replay <logfile>"),
+	NULL
+};
+
+static const char * const bisect_log_usage[] = {
+	N_("git bisect log"),
+	NULL
+};
+
+static const char * const bisect_run_usage[] = {
+	N_("git bisect run <cmd>..."),
 	NULL
 };
 
@@ -63,7 +116,7 @@ static void set_terms(const char *bad,
 static const char vocab_bad[] = "bad|new";
 static const char vocab_good[] = "good|old";
 
-static int bisect_autostart(void);
+static int bisect_autostart(const char *prefix);
 
 /*
  * Check whether the string `term` belongs to the set of strings
@@ -238,6 +291,21 @@ static int bisect_reset(const char *commit)
 	return bisect_clean_state();
 }
 
+static int cmd_bisect_reset(int argc, const char **argv, const char *prefix)
+{
+	struct option options[] = {
+		OPT_END()
+	};
+	argc = parse_options(argc, argv, prefix, options,
+			     bisect_reset_usage,  PARSE_OPT_STOP_AT_NON_OPTION);
+
+	if (argc > 1)
+		usage_msg_opt(_("requires either no argument or a commit"),
+			      bisect_reset_usage, options);
+
+	return bisect_reset(argc == 1 ? argv[0] : NULL);
+}
+
 static void log_commit(FILE *fp, char *fmt, const char *state,
 		       struct commit *commit)
 {
@@ -465,26 +533,41 @@ finish:
 	return res;
 }
 
-static int bisect_terms(const char *option)
+static int cmd_bisect_terms(int argc, const char **argv, const char *prefix)
 {
+	int mode = -1;
+	struct option options[] = {
+		OPT_SET_INT(0, "term-good", &mode,
+			    N_("show term for good/old"), 1),
+		OPT_SET_INT(0, "term-old", &mode,
+			    N_("show term for good/old"), 1),
+		OPT_SET_INT(0, "term-bad", &mode,
+			    N_("show term for bad/new"), 0),
+		OPT_SET_INT(0, "term-new", &mode,
+			    N_("show term for bad/new"), 0),
+		OPT_END()
+	};
+
+	argc = parse_options(argc, argv, prefix, options,
+			     bisect_terms_usage,  PARSE_OPT_STOP_AT_NON_OPTION);
+
+	if (argc > 1)
+		usage_msg_opt(_("terms: requires 0 or 1 argument"),
+			      bisect_terms_usage, options);
+
 	if (get_terms())
 		return error(_("no terms defined"));
 
-	if (!option) {
+	if (mode < 0) {
 		printf(_("Your current terms are %s for the old state\n"
 			 "and %s for the new state.\n"),
 		       terms.term_good, terms.term_bad);
 		return 0;
 	}
-	if (one_of(option, "--term-good", "--term-old", NULL))
+	if (mode == 1)
 		printf("%s\n", terms.term_good);
-	else if (one_of(option, "--term-bad", "--term-new", NULL))
-		printf("%s\n", terms.term_bad);
 	else
-		return error(_("invalid argument %s for 'git bisect terms'.\n"
-			       "Supported options are: "
-			       "--term-good|--term-old and "
-			       "--term-bad|--term-new."), option);
+		printf("%s\n", terms.term_bad);
 
 	return 0;
 }
@@ -623,7 +706,7 @@ static enum bisect_error bisect_next(const char *prefix)
 {
 	enum bisect_error res;
 
-	if (bisect_autostart())
+	if (bisect_autostart(prefix))
 		return BISECT_FAILED;
 
 	if (bisect_next_check(terms.term_good))
@@ -642,6 +725,24 @@ static enum bisect_error bisect_next(const char *prefix)
 	return res;
 }
 
+static int cmd_bisect_next(int argc, const char **argv, const char *prefix)
+{
+	struct option options[] = {
+		OPT_END()
+	};
+
+	get_terms();
+	argc = parse_options(argc, argv, prefix, options,
+				bisect_next_usage,
+				PARSE_OPT_STOP_AT_NON_OPTION);
+
+	if (argc > 0)
+		usage_msg_opt(_("requires 0 argument"),
+			      bisect_next_usage, options);
+
+	return bisect_next(prefix);
+}
+
 static enum bisect_error bisect_auto_next(const char *prefix)
 {
 	if (bisect_next_check(NULL)) {
@@ -652,8 +753,9 @@ static enum bisect_error bisect_auto_next(const char *prefix)
 	return bisect_next(prefix);
 }
 
-static enum bisect_error bisect_start(int argc, const char **argv)
+static int cmd_bisect_start(int argc, const char **argv, const char *prefix)
 {
+	struct strvec orig_argv = STRVEC_INIT;
 	int no_checkout = 0;
 	int first_parent_only = 0;
 	int i, has_double_dash = 0, must_write_terms = 0, bad_seen = 0;
@@ -665,66 +767,64 @@ static enum bisect_error bisect_start(int argc, const char **argv)
 	struct strbuf bisect_names = STRBUF_INIT;
 	struct object_id head_oid;
 	struct object_id oid;
-	const char *head;
+	const char *head, *term_good = NULL, *term_bad = NULL;
+	struct option options[] = {
+		OPT_BOOL(0, "no-checkout", &no_checkout,
+			 N_("do not update worktree")),
+		OPT_BOOL(0, "first-parent", &first_parent_only,
+			 N_("follow only first parent of merge commits")),
+		OPT_STRING(0, "term-good", &term_good, N_("term"),
+			   N_("use this term instead of 'good'")),
+		OPT_STRING(0, "term-bad", &term_bad, N_("term"),
+			   N_("use this term instead of 'bad'")),
+		OPT_STRING(0, "term-old", &term_good, N_("term"),
+			   N_("use this term instead of 'good'")),
+		OPT_STRING(0, "term-new", &term_bad, N_("term"),
+			   N_("use this term instead of 'bad'")),
+		OPT_END()
+	};
+
+	set_terms("bad", "good");
 
 	if (is_bare_repository())
 		no_checkout = 1;
 
-	/*
-	 * Check for one bad and then some good revisions
-	 */
-	for (i = 0; i < argc; i++) {
+	strvec_pushv(&orig_argv, argv); /* save the command-line for logging */
+	argc = parse_options(argc, argv, prefix, options, bisect_start_usage,
+			     PARSE_OPT_KEEP_DASHDASH);
+
+	if (term_good) {
+		free(terms.term_good);
+		terms.term_good = xstrdup(term_good);
+		must_write_terms = 1;
+	}
+
+	if (term_bad) {
+		free(terms.term_bad);
+		terms.term_bad = xstrdup(term_bad);
+		must_write_terms = 1;
+	}
+
+	for (i = 0; i < argc; i++)
 		if (!strcmp(argv[i], "--")) {
 			has_double_dash = 1;
 			break;
 		}
-	}
 
-	for (i = 0; i < argc; i++) {
-		const char *arg = argv[i];
-		if (!strcmp(argv[i], "--")) {
-			break;
-		} else if (!strcmp(arg, "--no-checkout")) {
-			no_checkout = 1;
-		} else if (!strcmp(arg, "--first-parent")) {
-			first_parent_only = 1;
-		} else if (!strcmp(arg, "--term-good") ||
-			 !strcmp(arg, "--term-old")) {
-			i++;
-			if (argc <= i)
-				return error(_("'' is not a valid term"));
-			must_write_terms = 1;
-			free((void *) terms.term_good);
-			terms.term_good = xstrdup(argv[i]);
-		} else if (skip_prefix(arg, "--term-good=", &arg) ||
-			   skip_prefix(arg, "--term-old=", &arg)) {
-			must_write_terms = 1;
-			free((void *) terms.term_good);
-			terms.term_good = xstrdup(arg);
-		} else if (!strcmp(arg, "--term-bad") ||
-			 !strcmp(arg, "--term-new")) {
-			i++;
-			if (argc <= i)
-				return error(_("'' is not a valid term"));
-			must_write_terms = 1;
-			free((void *) terms.term_bad);
-			terms.term_bad = xstrdup(argv[i]);
-		} else if (skip_prefix(arg, "--term-bad=", &arg) ||
-			   skip_prefix(arg, "--term-new=", &arg)) {
-			must_write_terms = 1;
-			free((void *) terms.term_bad);
-			terms.term_bad = xstrdup(arg);
-		} else if (starts_with(arg, "--")) {
-			return error(_("unrecognized option: '%s'"), arg);
-		} else if (!get_oidf(&oid, "%s^{commit}", arg)) {
+	/*
+	 * Check for one bad and then some good revisions
+	 */
+
+	for (i = 0; i < argc && strcmp(argv[i], "--"); i++)
+		if (!get_oidf(&oid, "%s^{commit}", argv[i])) {
 			string_list_append(&revs, oid_to_hex(&oid));
 		} else if (has_double_dash) {
 			die(_("'%s' does not appear to be a valid "
-			      "revision"), arg);
+			      "revision"), argv[i]);
 		} else {
 			break;
 		}
-	}
+
 	pathspec_pos = i;
 
 	/*
@@ -836,11 +936,13 @@ static enum bisect_error bisect_start(int argc, const char **argv)
 		goto finish;
 	}
 
-	res = bisect_append_log_quoted(argv);
+	res = bisect_append_log_quoted(orig_argv.v + 1);
 	if (res)
 		res = BISECT_FAILED;
 
 finish:
+	strvec_clear(&orig_argv);
+
 	string_list_clear(&revs, 0);
 	string_list_clear(&states, 0);
 	strbuf_release(&start_head);
@@ -848,7 +950,7 @@ finish:
 	if (res)
 		return res;
 
-	res = bisect_auto_next(NULL);
+	res = bisect_auto_next(prefix);
 	if (!is_bisect_success(res))
 		bisect_clean_state();
 	return res;
@@ -859,7 +961,7 @@ static inline int file_is_not_empty(const char *path)
 	return !is_empty_or_missing_file(path);
 }
 
-static int bisect_autostart(void)
+static int bisect_autostart(const char *prefix)
 {
 	int res;
 	const char *yesno;
@@ -881,12 +983,13 @@ static int bisect_autostart(void)
 	yesno = git_prompt(_("Do you want me to do it for you "
 			     "[Y/n]? "), PROMPT_ECHO);
 	res = tolower(*yesno) == 'n' ?
-		-1 : bisect_start(0, empty_strvec);
+		-1 : cmd_bisect_start(1, &yesno, prefix);
 
 	return res;
 }
 
-static enum bisect_error bisect_state(int argc, const char **argv)
+static enum bisect_error bisect_state(int argc, const char **argv,
+				      const char *prefix)
 {
 	const char *state;
 	int i, verify_expected = 1;
@@ -894,10 +997,8 @@ static enum bisect_error bisect_state(int argc, const char **argv)
 	struct strbuf buf = STRBUF_INIT;
 	struct oid_array revs = OID_ARRAY_INIT;
 
-	if (!argc)
-		return error(_("Please call `--bisect-state` with at least one argument"));
 
-	if (bisect_autostart())
+	if (bisect_autostart(prefix))
 		return BISECT_FAILED;
 
 	state = argv[0];
@@ -966,11 +1067,41 @@ static enum bisect_error bisect_state(int argc, const char **argv)
 	return bisect_auto_next(NULL);
 }
 
-static enum bisect_error bisect_log(void)
+static int cmd_bisect_state(int argc, const char **argv,
+				const char *prefix)
 {
+	struct option options[] = {
+		OPT_END()
+	};
+
+	set_terms("bad", "good");
+	get_terms();
+
+	argc = parse_options(argc, argv, prefix, options,
+			     bisect_state_usage,  PARSE_OPT_STOP_AT_NON_OPTION);
+
+	if (!argc)
+		usage_msg_opt(_("need at least one argument"),
+			      bisect_state_usage, options);
+
+	return bisect_state(argc, argv, prefix);
+}
+
+static int cmd_bisect_log(int argc, const char **argv, const char *prefix)
+{
+	struct option options[] = {
+		OPT_END()
+	};
 	int fd, status;
 	const char* filename = git_path_bisect_log();
 
+	argc = parse_options(argc, argv, prefix, options,
+			     bisect_log_usage,  PARSE_OPT_STOP_AT_NON_OPTION);
+
+	if (argc > 0)
+		usage_msg_opt(_("require 0 argument"), bisect_log_usage,
+			      options);
+
 	if (is_empty_or_missing_file(filename))
 		return error(_("We are not bisecting."));
 
@@ -983,7 +1114,7 @@ static enum bisect_error bisect_log(void)
 	return status ? BISECT_FAILED : BISECT_OK;
 }
 
-static int process_replay_line(struct strbuf *line)
+static int process_replay_line(struct strbuf *line, const char *prefix)
 {
 	const char *p = line->buf + strspn(line->buf, " \t");
 	char *word_end, *rev;
@@ -1004,8 +1135,10 @@ static int process_replay_line(struct strbuf *line)
 	if (!strcmp(p, "start")) {
 		struct strvec argv = STRVEC_INIT;
 		int res;
+
+		strvec_push(&argv, p);
 		sq_dequote_to_strvec(rev, &argv);
-		res = bisect_start(argv.nr, argv.v);
+		res = cmd_bisect_start(argv.nr, argv.v, prefix);
 		strvec_clear(&argv);
 		return res;
 	}
@@ -1017,8 +1150,11 @@ static int process_replay_line(struct strbuf *line)
 	if (!strcmp(p, "terms")) {
 		struct strvec argv = STRVEC_INIT;
 		int res;
+
+		strvec_push(&argv, p);
 		sq_dequote_to_strvec(rev, &argv);
-		res = bisect_terms(argv.nr == 1 ? argv.v[0] : NULL);
+		res = cmd_bisect_terms(argv.nr, argv.v, NULL);
+
 		strvec_clear(&argv);
 		return res;
 	}
@@ -1027,12 +1163,25 @@ static int process_replay_line(struct strbuf *line)
 	return -1;
 }
 
-static enum bisect_error bisect_replay(const char *filename)
+static int cmd_bisect_replay(int argc, const char **argv, const char *prefix)
 {
+	struct option options[] = {
+		OPT_END()
+	};
+	const char *filename;
 	FILE *fp = NULL;
 	enum bisect_error res = BISECT_OK;
 	struct strbuf line = STRBUF_INIT;
 
+	set_terms("bad", "good");
+	argc = parse_options(argc, argv, prefix, options,
+			     bisect_reset_usage,  PARSE_OPT_STOP_AT_NON_OPTION);
+
+	if (argc != 1)
+		usage_msg_opt(_("no logfile given"), bisect_replay_usage,
+			      options);
+
+	filename = argv[0];
 	if (is_empty_or_missing_file(filename))
 		return error(_("cannot read file '%s' for replaying"), filename);
 
@@ -1044,7 +1193,7 @@ static enum bisect_error bisect_replay(const char *filename)
 		return BISECT_FAILED;
 
 	while ((strbuf_getline(&line, fp) != EOF) && !res)
-		res = process_replay_line(&line);
+		res = process_replay_line(&line, prefix);
 
 	strbuf_release(&line);
 	fclose(fp);
@@ -1055,12 +1204,20 @@ static enum bisect_error bisect_replay(const char *filename)
 	return bisect_auto_next(NULL);
 }
 
-static enum bisect_error bisect_skip(int argc, const char **argv)
+static int cmd_bisect_skip(int argc, const char **argv, const char *prefix)
 {
+	struct option options[] = {
+		OPT_END()
+	};
 	int i;
 	enum bisect_error res;
 	struct strvec argv_state = STRVEC_INIT;
 
+	set_terms("bad", "good");
+	get_terms();
+	argc = parse_options(argc, argv, prefix, options,
+			     bisect_skip_usage,  PARSE_OPT_STOP_AT_NON_OPTION);
+
 	strvec_push(&argv_state, "skip");
 
 	for (i = 0; i < argc; i++) {
@@ -1085,18 +1242,28 @@ static enum bisect_error bisect_skip(int argc, const char **argv)
 			strvec_push(&argv_state, argv[i]);
 		}
 	}
-	res = bisect_state(argv_state.nr, argv_state.v);
+	res = bisect_state(argv_state.nr, argv_state.v, prefix);
 
 	strvec_clear(&argv_state);
 	return res;
 }
 
-static int bisect_visualize(int argc, const char **argv)
+static int cmd_bisect_visualize(int argc, const char **argv, const char *prefix)
 {
+	struct option options[] = {
+		OPT_END()
+	};
 	struct strvec args = STRVEC_INIT;
 	int flags = RUN_COMMAND_NO_STDIN, res = 0;
 	struct strbuf sb = STRBUF_INIT;
 
+	set_terms("bad", "good");
+	get_terms();
+	argc = parse_options(argc, argv, prefix, options,
+			     bisect_visualize_usage,
+			     PARSE_OPT_KEEP_DASHDASH |
+			     PARSE_OPT_KEEP_UNKNOWN_OPT);
+
 	if (bisect_next_check(NULL) != 0)
 		return BISECT_FAILED;
 
@@ -1166,8 +1333,11 @@ static int verify_good(const char **quoted_argv)
 	return rc;
 }
 
-static int bisect_run(int argc, const char **argv)
+static int cmd_bisect_run(int argc, const char **argv, const char *prefix)
 {
+	struct option options[] = {
+		OPT_END()
+	};
 	int res = BISECT_OK;
 	struct strbuf command = STRBUF_INIT;
 	struct strvec run_args = STRVEC_INIT;
@@ -1175,15 +1345,18 @@ static int bisect_run(int argc, const char **argv)
 	int temporary_stdout_fd, saved_stdout;
 	int is_first_run = 1;
 
+	get_terms();
+	argc = parse_options(argc, argv, prefix, options,
+			     bisect_run_usage,  PARSE_OPT_STOP_AT_NON_OPTION);
+
 	if (bisect_next_check(NULL))
 		return BISECT_FAILED;
 
 	if (argc)
 		sq_quote_argv(&command, argv);
-	else {
-		error(_("bisect run failed: no command provided."));
-		return BISECT_FAILED;
-	}
+	else
+		usage_msg_opt(_("bisect run failed: no command provided."),
+			      bisect_run_usage, options);
 
 	strvec_push(&run_args, command.buf);
 
@@ -1239,7 +1412,7 @@ static int bisect_run(int argc, const char **argv)
 		saved_stdout = dup(1);
 		dup2(temporary_stdout_fd, 1);
 
-		res = bisect_state(1, &new_state);
+		res = bisect_state(1, &new_state, prefix);
 
 		fflush(stdout);
 		dup2(saved_stdout, 1);
@@ -1272,105 +1445,26 @@ static int bisect_run(int argc, const char **argv)
 
 int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 {
-	enum {
-		BISECT_RESET = 1,
-		BISECT_TERMS,
-		BISECT_START,
-		BISECT_NEXT,
-		BISECT_STATE,
-		BISECT_LOG,
-		BISECT_REPLAY,
-		BISECT_SKIP,
-		BISECT_VISUALIZE,
-		BISECT_RUN,
-	} cmdmode = 0;
+	parse_opt_subcommand_fn *fn = NULL;
 	int res = 0;
 	struct option options[] = {
-		OPT_CMDMODE(0, "bisect-reset", &cmdmode,
-			 N_("reset the bisection state"), BISECT_RESET),
-		OPT_CMDMODE(0, "bisect-terms", &cmdmode,
-			 N_("print out the bisect terms"), BISECT_TERMS),
-		OPT_CMDMODE(0, "bisect-start", &cmdmode,
-			 N_("start the bisect session"), BISECT_START),
-		OPT_CMDMODE(0, "bisect-next", &cmdmode,
-			 N_("find the next bisection commit"), BISECT_NEXT),
-		OPT_CMDMODE(0, "bisect-state", &cmdmode,
-			 N_("mark the state of ref (or refs)"), BISECT_STATE),
-		OPT_CMDMODE(0, "bisect-log", &cmdmode,
-			 N_("list the bisection steps so far"), BISECT_LOG),
-		OPT_CMDMODE(0, "bisect-replay", &cmdmode,
-			 N_("replay the bisection process from the given file"), BISECT_REPLAY),
-		OPT_CMDMODE(0, "bisect-skip", &cmdmode,
-			 N_("skip some commits for checkout"), BISECT_SKIP),
-		OPT_CMDMODE(0, "bisect-visualize", &cmdmode,
-			 N_("visualize the bisection"), BISECT_VISUALIZE),
-		OPT_CMDMODE(0, "bisect-run", &cmdmode,
-			 N_("use <cmd>... to automatically bisect"), BISECT_RUN),
+		OPT_SUBCOMMAND("reset", &fn, cmd_bisect_reset),
+		OPT_SUBCOMMAND("terms", &fn, cmd_bisect_terms),
+		OPT_SUBCOMMAND("start", &fn, cmd_bisect_start),
+		OPT_SUBCOMMAND("next", &fn, cmd_bisect_next),
+		OPT_SUBCOMMAND("state", &fn, cmd_bisect_state),
+		OPT_SUBCOMMAND("log", &fn, cmd_bisect_log),
+		OPT_SUBCOMMAND("replay", &fn, cmd_bisect_replay),
+		OPT_SUBCOMMAND("skip", &fn, cmd_bisect_skip),
+		OPT_SUBCOMMAND("visualize", &fn, cmd_bisect_visualize),
+		OPT_SUBCOMMAND("run", &fn, cmd_bisect_run),
 		OPT_END()
 	};
 
 	argc = parse_options(argc, argv, prefix, options,
-			     git_bisect_helper_usage,
-			     PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN_OPT);
-
-	if (!cmdmode)
-		usage_with_options(git_bisect_helper_usage, options);
+			     bisect_usage, 0);
 
-	switch (cmdmode) {
-	case BISECT_RESET:
-		if (argc > 1)
-			return error(_("--bisect-reset requires either no argument or a commit"));
-		res = bisect_reset(argc ? argv[0] : NULL);
-		break;
-	case BISECT_TERMS:
-		if (argc > 1)
-			return error(_("--bisect-terms requires 0 or 1 argument"));
-		res = bisect_terms(argc == 1 ? argv[0] : NULL);
-		break;
-	case BISECT_START:
-		set_terms("bad", "good");
-		res = bisect_start(argc, argv);
-		break;
-	case BISECT_NEXT:
-		if (argc)
-			return error(_("--bisect-next requires 0 arguments"));
-		get_terms();
-		res = bisect_next(prefix);
-		break;
-	case BISECT_STATE:
-		set_terms("bad", "good");
-		get_terms();
-		res = bisect_state(argc, argv);
-		break;
-	case BISECT_LOG:
-		if (argc)
-			return error(_("--bisect-log requires 0 arguments"));
-		res = bisect_log();
-		break;
-	case BISECT_REPLAY:
-		if (argc != 1)
-			return error(_("no logfile given"));
-		set_terms("bad", "good");
-		res = bisect_replay(argv[0]);
-		break;
-	case BISECT_SKIP:
-		set_terms("bad", "good");
-		get_terms();
-		res = bisect_skip(argc, argv);
-		break;
-	case BISECT_VISUALIZE:
-		get_terms();
-		res = bisect_visualize(argc, argv);
-		break;
-	case BISECT_RUN:
-		if (!argc)
-			return error(_("bisect run failed: no command provided."));
-		get_terms();
-		res = bisect_run(argc, argv);
-		break;
-	default:
-		BUG("unknown subcommand %d", cmdmode);
-	}
+	res = fn(argc, argv, prefix);
 	free_terms();
 
 	return is_bisect_success(res) ? 0 : -res;
diff --git a/git-bisect.sh b/git-bisect.sh
index 405cf76f2a3..e19847eba0d 100755
--- a/git-bisect.sh
+++ b/git-bisect.sh
@@ -58,26 +58,26 @@ case "$#" in
 	help)
 		git bisect -h ;;
 	start)
-		git bisect--helper --bisect-start "$@" ;;
+		git bisect--helper start "$@" ;;
 	bad|good|new|old|"$TERM_BAD"|"$TERM_GOOD")
-		git bisect--helper --bisect-state "$cmd" "$@" ;;
+		git bisect--helper state "$cmd" "$@" ;;
 	skip)
-		git bisect--helper --bisect-skip "$@" || exit;;
+		git bisect--helper skip "$@" || exit;;
 	next)
 		# Not sure we want "next" at the UI level anymore.
-		git bisect--helper --bisect-next "$@" || exit ;;
+		git bisect--helper next "$@" || exit ;;
 	visualize|view)
-		git bisect--helper --bisect-visualize "$@" || exit;;
+		git bisect--helper visualize "$@" || exit;;
 	reset)
-		git bisect--helper --bisect-reset "$@" ;;
+		git bisect--helper reset "$@" ;;
 	replay)
-		git bisect--helper --bisect-replay "$@" || exit;;
+		git bisect--helper replay "$@" || exit;;
 	log)
-		git bisect--helper --bisect-log || exit ;;
+		git bisect--helper log || exit ;;
 	run)
-		git bisect--helper --bisect-run "$@" || exit;;
+		git bisect--helper run "$@" || exit;;
 	terms)
-		git bisect--helper --bisect-terms "$@" || exit;;
+		git bisect--helper terms "$@" || exit;;
 	*)
 		usage ;;
 	esac
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH v5 08/16] bisect: verify that a bogus option won't try to start a bisection
  2022-08-27 12:44       ` [PATCH v5 " Johannes Schindelin via GitGitGadget
                           ` (6 preceding siblings ...)
  2022-08-27 12:44         ` [PATCH v5 07/16] bisect--helper: migrate to OPT_SUBCOMMAND() Johannes Schindelin via GitGitGadget
@ 2022-08-27 12:44         ` Johannes Schindelin via GitGitGadget
  2022-08-27 12:44         ` [PATCH v5 09/16] bisect run: fix the error message Johannes Schindelin via GitGitGadget
                           ` (8 subsequent siblings)
  16 siblings, 0 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-08-27 12:44 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Bagas Sanjaya, Junio C Hamano, Johannes Schindelin,
	Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

We do not want `git bisect --bogus-option` to start a bisection. To
verify that, we look for the tell-tale error message `You need to start
by "git bisect start"` and fail if it was found.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 t/t6030-bisect-porcelain.sh | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh
index 83931d482fb..6d6e72276ae 100755
--- a/t/t6030-bisect-porcelain.sh
+++ b/t/t6030-bisect-porcelain.sh
@@ -900,6 +900,16 @@ test_expect_success 'bisect start with one term1 and term2' '
 	git bisect reset
 '
 
+test_expect_success 'bogus command does not start bisect' '
+	git bisect reset &&
+	test_must_fail git bisect --bisect-terms 1 2 2>out &&
+	! grep "You need to start" out &&
+	test_must_fail git bisect --bisect-terms 2>out &&
+	! grep "You need to start" out &&
+	grep "git bisect.*visualize" out &&
+	git bisect reset
+'
+
 test_expect_success 'bisect replay with term1 and term2' '
 	git bisect replay log_to_replay.txt >bisect_result &&
 	grep "$HASH2 is the first term1 commit" bisect_result &&
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH v5 09/16] bisect run: fix the error message
  2022-08-27 12:44       ` [PATCH v5 " Johannes Schindelin via GitGitGadget
                           ` (7 preceding siblings ...)
  2022-08-27 12:44         ` [PATCH v5 08/16] bisect: verify that a bogus option won't try to start a bisection Johannes Schindelin via GitGitGadget
@ 2022-08-27 12:44         ` Johannes Schindelin via GitGitGadget
  2022-08-28  7:03           ` Junio C Hamano
  2022-08-27 12:44         ` [PATCH v5 10/16] bisect: avoid double-quoting when printing the failed command Johannes Schindelin via GitGitGadget
                           ` (7 subsequent siblings)
  16 siblings, 1 reply; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-08-27 12:44 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Bagas Sanjaya, Junio C Hamano, Johannes Schindelin,
	Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

In d1bbbe45df8 (bisect--helper: reimplement `bisect_run` shell function
in C, 2021-09-13), we ported the `bisect run` subcommand to C, including
the part that prints out an error message when the implicit `git bisect
bad` or `git bisect good` failed.

However, the error message was supposed to print out whether the state
was "good" or "bad", but used a bogus (because non-populated) `args`
variable for it.

Helped-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/bisect--helper.c    |  2 +-
 t/t6030-bisect-porcelain.sh | 10 ++++++++++
 2 files changed, 11 insertions(+), 1 deletion(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index d797cd1cef8..a00167f1373 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1430,7 +1430,7 @@ static int cmd_bisect_run(int argc, const char **argv, const char *prefix)
 			printf(_("bisect found first bad commit"));
 			res = BISECT_OK;
 		} else if (res) {
-			error(_("bisect run failed: 'git bisect--helper --bisect-state"
+			error(_("bisect run failed: 'git bisect"
 			" %s' exited with error code %d"), new_state, res);
 		} else {
 			continue;
diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh
index 6d6e72276ae..7a76f204083 100755
--- a/t/t6030-bisect-porcelain.sh
+++ b/t/t6030-bisect-porcelain.sh
@@ -1063,4 +1063,14 @@ test_expect_success 'bisect state output with bad commit' '
 	grep -F "waiting for good commit(s), bad commit known" output
 '
 
+test_expect_success 'verify correct error message' '
+	git bisect reset &&
+	git bisect start $HASH4 $HASH1 &&
+	write_script test_script.sh <<-\EOF &&
+	rm .git/BISECT*
+	EOF
+	test_must_fail git bisect run ./test_script.sh 2>error &&
+	grep "git bisect good.*exited with error code" error
+'
+
 test_done
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH v5 10/16] bisect: avoid double-quoting when printing the failed command
  2022-08-27 12:44       ` [PATCH v5 " Johannes Schindelin via GitGitGadget
                           ` (8 preceding siblings ...)
  2022-08-27 12:44         ` [PATCH v5 09/16] bisect run: fix the error message Johannes Schindelin via GitGitGadget
@ 2022-08-27 12:44         ` Johannes Schindelin via GitGitGadget
  2022-08-27 12:44         ` [PATCH v5 11/16] bisect--helper: calling `bisect_state()` without an argument is a bug Johannes Schindelin via GitGitGadget
                           ` (6 subsequent siblings)
  16 siblings, 0 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-08-27 12:44 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Bagas Sanjaya, Junio C Hamano, Johannes Schindelin,
	Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

We already quote the command via `sq_quote_argv()`, no need to enclose
the result in an extraneous pair of single-quotes.

Pointed out by Elijah Newren.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/bisect--helper.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index a00167f1373..5cf688c0dac 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1390,7 +1390,7 @@ static int cmd_bisect_run(int argc, const char **argv, const char *prefix)
 
 		if (res < 0 || 128 <= res) {
 			error(_("bisect run failed: exit code %d from"
-				" '%s' is < 0 or >= 128"), res, command.buf);
+				" %s is < 0 or >= 128"), res, command.buf);
 			break;
 		}
 
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH v5 11/16] bisect--helper: calling `bisect_state()` without an argument is a bug
  2022-08-27 12:44       ` [PATCH v5 " Johannes Schindelin via GitGitGadget
                           ` (9 preceding siblings ...)
  2022-08-27 12:44         ` [PATCH v5 10/16] bisect: avoid double-quoting when printing the failed command Johannes Schindelin via GitGitGadget
@ 2022-08-27 12:44         ` Johannes Schindelin via GitGitGadget
  2022-08-29 10:11           ` Ævar Arnfjörð Bjarmason
  2022-08-27 12:44         ` [PATCH v5 12/16] bisect--helper: make `state` optional Johannes Schindelin via GitGitGadget
                           ` (5 subsequent siblings)
  16 siblings, 1 reply; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-08-27 12:44 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Bagas Sanjaya, Junio C Hamano, Johannes Schindelin,
	Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

The `bisect_state()` function is now a purely internal function and must
be called with a valid state, everything else is a bug.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/bisect--helper.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 5cf688c0dac..3f333cfae76 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -997,6 +997,8 @@ static enum bisect_error bisect_state(int argc, const char **argv,
 	struct strbuf buf = STRBUF_INIT;
 	struct oid_array revs = OID_ARRAY_INIT;
 
+	if (!argc)
+		BUG("bisect_state() called without argument");
 
 	if (bisect_autostart(prefix))
 		return BISECT_FAILED;
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH v5 12/16] bisect--helper: make `state` optional
  2022-08-27 12:44       ` [PATCH v5 " Johannes Schindelin via GitGitGadget
                           ` (10 preceding siblings ...)
  2022-08-27 12:44         ` [PATCH v5 11/16] bisect--helper: calling `bisect_state()` without an argument is a bug Johannes Schindelin via GitGitGadget
@ 2022-08-27 12:44         ` Johannes Schindelin via GitGitGadget
  2022-08-27 12:44         ` [PATCH v5 13/16] bisect: move even the command-line parsing to `bisect--helper` Johannes Schindelin via GitGitGadget
                           ` (4 subsequent siblings)
  16 siblings, 0 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-08-27 12:44 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Bagas Sanjaya, Junio C Hamano, Johannes Schindelin,
	Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

In preparation for making `git bisect` a real built-in, let's prepare
the `bisect--helper` built-in to handle `git bisect--helper good` and
`git bisect--helper bad`, i.e. do not require the `state` subcommand to
be passed explicitly.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/bisect--helper.c | 22 +++++++++++++++++++++-
 git-bisect.sh            |  2 +-
 2 files changed, 22 insertions(+), 2 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 3f333cfae76..9f78bd45ca5 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1447,6 +1447,7 @@ static int cmd_bisect_run(int argc, const char **argv, const char *prefix)
 
 int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 {
+	struct strvec args = STRVEC_INIT;
 	parse_opt_subcommand_fn *fn = NULL;
 	int res = 0;
 	struct option options[] = {
@@ -1464,10 +1465,29 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 	};
 
 	argc = parse_options(argc, argv, prefix, options,
-			     bisect_usage, 0);
+			     bisect_usage, PARSE_OPT_SUBCOMMAND_OPTIONAL);
+
+	if (!fn) {
+		if (!argc)
+			usage_msg_opt(_("need a command"), bisect_usage,
+				      options);
+
+		set_terms("bad", "good");
+		get_terms();
+		if (check_and_set_terms(argv[0]))
+			usage_msg_optf(_("unknown command: '%s'"), bisect_usage,
+				       options, argv[0]);
+
+		strvec_push(&args, "state");
+		strvec_pushv(&args, argv);
+		argc = args.nr;
+		argv = args.v;
+		fn = cmd_bisect_state;
+	}
 
 	res = fn(argc, argv, prefix);
 	free_terms();
+	strvec_clear(&args);
 
 	return is_bisect_success(res) ? 0 : -res;
 }
diff --git a/git-bisect.sh b/git-bisect.sh
index e19847eba0d..f4df8709d84 100755
--- a/git-bisect.sh
+++ b/git-bisect.sh
@@ -60,7 +60,7 @@ case "$#" in
 	start)
 		git bisect--helper start "$@" ;;
 	bad|good|new|old|"$TERM_BAD"|"$TERM_GOOD")
-		git bisect--helper state "$cmd" "$@" ;;
+		git bisect--helper "$cmd" "$@" ;;
 	skip)
 		git bisect--helper skip "$@" || exit;;
 	next)
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH v5 13/16] bisect: move even the command-line parsing to `bisect--helper`
  2022-08-27 12:44       ` [PATCH v5 " Johannes Schindelin via GitGitGadget
                           ` (11 preceding siblings ...)
  2022-08-27 12:44         ` [PATCH v5 12/16] bisect--helper: make `state` optional Johannes Schindelin via GitGitGadget
@ 2022-08-27 12:44         ` Johannes Schindelin via GitGitGadget
  2022-08-27 12:44         ` [PATCH v5 14/16] Turn `git bisect` into a full built-in Johannes Schindelin via GitGitGadget
                           ` (3 subsequent siblings)
  16 siblings, 0 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-08-27 12:44 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Bagas Sanjaya, Junio C Hamano, Johannes Schindelin,
	Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

On our journey to a fully built-in `git bisect`, this is the
last step.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/bisect--helper.c |  1 -
 git-bisect.sh            | 49 +---------------------------------------
 2 files changed, 1 insertion(+), 49 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 9f78bd45ca5..d243a9132e2 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1455,7 +1455,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 		OPT_SUBCOMMAND("terms", &fn, cmd_bisect_terms),
 		OPT_SUBCOMMAND("start", &fn, cmd_bisect_start),
 		OPT_SUBCOMMAND("next", &fn, cmd_bisect_next),
-		OPT_SUBCOMMAND("state", &fn, cmd_bisect_state),
 		OPT_SUBCOMMAND("log", &fn, cmd_bisect_log),
 		OPT_SUBCOMMAND("replay", &fn, cmd_bisect_replay),
 		OPT_SUBCOMMAND("skip", &fn, cmd_bisect_skip),
diff --git a/git-bisect.sh b/git-bisect.sh
index f4df8709d84..028d39cd9ce 100755
--- a/git-bisect.sh
+++ b/git-bisect.sh
@@ -34,51 +34,4 @@ Please use "git help bisect" to get the full man page.'
 OPTIONS_SPEC=
 . git-sh-setup
 
-TERM_BAD=bad
-TERM_GOOD=good
-
-get_terms () {
-	if test -s "$GIT_DIR/BISECT_TERMS"
-	then
-		{
-		read TERM_BAD
-		read TERM_GOOD
-		} <"$GIT_DIR/BISECT_TERMS"
-	fi
-}
-
-case "$#" in
-0)
-	usage ;;
-*)
-	cmd="$1"
-	get_terms
-	shift
-	case "$cmd" in
-	help)
-		git bisect -h ;;
-	start)
-		git bisect--helper start "$@" ;;
-	bad|good|new|old|"$TERM_BAD"|"$TERM_GOOD")
-		git bisect--helper "$cmd" "$@" ;;
-	skip)
-		git bisect--helper skip "$@" || exit;;
-	next)
-		# Not sure we want "next" at the UI level anymore.
-		git bisect--helper next "$@" || exit ;;
-	visualize|view)
-		git bisect--helper visualize "$@" || exit;;
-	reset)
-		git bisect--helper reset "$@" ;;
-	replay)
-		git bisect--helper replay "$@" || exit;;
-	log)
-		git bisect--helper log || exit ;;
-	run)
-		git bisect--helper run "$@" || exit;;
-	terms)
-		git bisect--helper terms "$@" || exit;;
-	*)
-		usage ;;
-	esac
-esac
+exec git bisect--helper "$@"
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH v5 14/16] Turn `git bisect` into a full built-in
  2022-08-27 12:44       ` [PATCH v5 " Johannes Schindelin via GitGitGadget
                           ` (12 preceding siblings ...)
  2022-08-27 12:44         ` [PATCH v5 13/16] bisect: move even the command-line parsing to `bisect--helper` Johannes Schindelin via GitGitGadget
@ 2022-08-27 12:44         ` Johannes Schindelin via GitGitGadget
  2022-08-27 12:44         ` [PATCH v5 15/16] bisect: remove Cogito-related code Johannes Schindelin via GitGitGadget
                           ` (2 subsequent siblings)
  16 siblings, 0 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-08-27 12:44 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Bagas Sanjaya, Junio C Hamano, Johannes Schindelin,
	Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

Now that the shell script hands off to the `bisect--helper` to do
_anything_ (except to show the help), it is but a tiny step to let the
helper implement the actual `git bisect` command instead.

This retires `git-bisect.sh`, concluding a multi-year journey that many
hands helped with, in particular Pranit Bauna, Tanushree Tumane and
Miriam Rubio.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 Makefile                               |  3 +--
 builtin.h                              |  2 +-
 builtin/{bisect--helper.c => bisect.c} |  2 +-
 git-bisect.sh                          | 37 --------------------------
 git.c                                  |  2 +-
 5 files changed, 4 insertions(+), 42 deletions(-)
 rename builtin/{bisect--helper.c => bisect.c} (99%)
 delete mode 100755 git-bisect.sh

diff --git a/Makefile b/Makefile
index 1624471badc..4a79b2ba2fe 100644
--- a/Makefile
+++ b/Makefile
@@ -627,7 +627,6 @@ THIRD_PARTY_SOURCES =
 # interactive shell sessions without exporting it.
 unexport CDPATH
 
-SCRIPT_SH += git-bisect.sh
 SCRIPT_SH += git-difftool--helper.sh
 SCRIPT_SH += git-filter-branch.sh
 SCRIPT_SH += git-merge-octopus.sh
@@ -1127,7 +1126,7 @@ BUILTIN_OBJS += builtin/am.o
 BUILTIN_OBJS += builtin/annotate.o
 BUILTIN_OBJS += builtin/apply.o
 BUILTIN_OBJS += builtin/archive.o
-BUILTIN_OBJS += builtin/bisect--helper.o
+BUILTIN_OBJS += builtin/bisect.o
 BUILTIN_OBJS += builtin/blame.o
 BUILTIN_OBJS += builtin/branch.o
 BUILTIN_OBJS += builtin/bugreport.o
diff --git a/builtin.h b/builtin.h
index 40e9ecc8485..b9470f8ab4f 100644
--- a/builtin.h
+++ b/builtin.h
@@ -116,7 +116,7 @@ int cmd_am(int argc, const char **argv, const char *prefix);
 int cmd_annotate(int argc, const char **argv, const char *prefix);
 int cmd_apply(int argc, const char **argv, const char *prefix);
 int cmd_archive(int argc, const char **argv, const char *prefix);
-int cmd_bisect__helper(int argc, const char **argv, const char *prefix);
+int cmd_bisect(int argc, const char **argv, const char *prefix);
 int cmd_blame(int argc, const char **argv, const char *prefix);
 int cmd_branch(int argc, const char **argv, const char *prefix);
 int cmd_bugreport(int argc, const char **argv, const char *prefix);
diff --git a/builtin/bisect--helper.c b/builtin/bisect.c
similarity index 99%
rename from builtin/bisect--helper.c
rename to builtin/bisect.c
index d243a9132e2..16f5c92bb9e 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect.c
@@ -1445,7 +1445,7 @@ static int cmd_bisect_run(int argc, const char **argv, const char *prefix)
 	return res;
 }
 
-int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
+int cmd_bisect(int argc, const char **argv, const char *prefix)
 {
 	struct strvec args = STRVEC_INIT;
 	parse_opt_subcommand_fn *fn = NULL;
diff --git a/git-bisect.sh b/git-bisect.sh
deleted file mode 100755
index 028d39cd9ce..00000000000
--- a/git-bisect.sh
+++ /dev/null
@@ -1,37 +0,0 @@
-#!/bin/sh
-
-USAGE='[help|start|bad|good|new|old|terms|skip|next|reset|visualize|view|replay|log|run]'
-LONG_USAGE='git bisect help
-	print this long help message.
-git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>]
-		 [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<pathspec>...]
-	reset bisect state and start bisection.
-git bisect (bad|new) [<rev>]
-	mark <rev> a known-bad revision/
-		a revision after change in a given property.
-git bisect (good|old) [<rev>...]
-	mark <rev>... known-good revisions/
-		revisions before change in a given property.
-git bisect terms [--term-good | --term-bad]
-	show the terms used for old and new commits (default: bad, good)
-git bisect skip [(<rev>|<range>)...]
-	mark <rev>... untestable revisions.
-git bisect next
-	find next bisection to test and check it out.
-git bisect reset [<commit>]
-	finish bisection search and go back to commit.
-git bisect (visualize|view)
-	show bisect status in gitk.
-git bisect replay <logfile>
-	replay bisection log.
-git bisect log
-	show bisect log.
-git bisect run <cmd>...
-	use <cmd>... to automatically bisect.
-
-Please use "git help bisect" to get the full man page.'
-
-OPTIONS_SPEC=
-. git-sh-setup
-
-exec git bisect--helper "$@"
diff --git a/git.c b/git.c
index f52a9554103..9c11727e29d 100644
--- a/git.c
+++ b/git.c
@@ -492,7 +492,7 @@ static struct cmd_struct commands[] = {
 	{ "annotate", cmd_annotate, RUN_SETUP },
 	{ "apply", cmd_apply, RUN_SETUP_GENTLY },
 	{ "archive", cmd_archive, RUN_SETUP_GENTLY },
-	{ "bisect--helper", cmd_bisect__helper, RUN_SETUP },
+	{ "bisect", cmd_bisect, RUN_SETUP },
 	{ "blame", cmd_blame, RUN_SETUP },
 	{ "branch", cmd_branch, RUN_SETUP | DELAY_PAGER_CONFIG },
 	{ "bugreport", cmd_bugreport, RUN_SETUP_GENTLY },
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH v5 15/16] bisect: remove Cogito-related code
  2022-08-27 12:44       ` [PATCH v5 " Johannes Schindelin via GitGitGadget
                           ` (13 preceding siblings ...)
  2022-08-27 12:44         ` [PATCH v5 14/16] Turn `git bisect` into a full built-in Johannes Schindelin via GitGitGadget
@ 2022-08-27 12:44         ` Johannes Schindelin via GitGitGadget
  2022-08-27 12:44         ` [PATCH v5 16/16] bisect: no longer try to clean up left-over `.git/head-name` files Johannes Schindelin via GitGitGadget
  2022-08-30 18:50         ` [PATCH v6 00/16] Finish converting git bisect into a built-in Johannes Schindelin via GitGitGadget
  16 siblings, 0 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-08-27 12:44 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Bagas Sanjaya, Junio C Hamano, Johannes Schindelin,
	Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

Once upon a time, there was this idea that Git would not actually be a
single coherent program, but rather a set of low-level programs that
users cobble together via shell scripts, or develop high-level user
interfaces for Git, or both.

Cogito was such a high-level user interface, incidentally implemented
via shell scripts that cobble together Git calls.

It did turn out relatively quickly that Git would much rather provide a
useful high-level user interface itself.

As of April 19th, 2007, Cogito was therefore discontinued (see
https://lore.kernel.org/git/20070419124648.GL4489@pasky.or.cz/).

Nevertheless, for almost 15 years after that announcement, Git carried
special code in `git bisect` to accommodate Cogito.

Since it is beyond doubt that there are no more Cogito users, let's
remove the last remnant of Cogito-accommodating code.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/bisect.c | 8 --------
 1 file changed, 8 deletions(-)

diff --git a/builtin/bisect.c b/builtin/bisect.c
index 16f5c92bb9e..cfd6b63214a 100644
--- a/builtin/bisect.c
+++ b/builtin/bisect.c
@@ -15,7 +15,6 @@ static GIT_PATH_FUNC(git_path_bisect_expected_rev, "BISECT_EXPECTED_REV")
 static GIT_PATH_FUNC(git_path_bisect_ancestors_ok, "BISECT_ANCESTORS_OK")
 static GIT_PATH_FUNC(git_path_bisect_start, "BISECT_START")
 static GIT_PATH_FUNC(git_path_bisect_log, "BISECT_LOG")
-static GIT_PATH_FUNC(git_path_head_name, "head-name")
 static GIT_PATH_FUNC(git_path_bisect_names, "BISECT_NAMES")
 static GIT_PATH_FUNC(git_path_bisect_first_parent, "BISECT_FIRST_PARENT")
 static GIT_PATH_FUNC(git_path_bisect_run, "BISECT_RUN")
@@ -880,13 +879,6 @@ static int cmd_bisect_start(int argc, const char **argv, const char *prefix)
 			strbuf_addstr(&start_head, oid_to_hex(&head_oid));
 		} else if (!get_oid(head, &head_oid) &&
 			   skip_prefix(head, "refs/heads/", &head)) {
-			/*
-			 * This error message should only be triggered by
-			 * cogito usage, and cogito users should understand
-			 * it relates to cg-seek.
-			 */
-			if (!is_empty_or_missing_file(git_path_head_name()))
-				return error(_("won't bisect on cg-seek'ed tree"));
 			strbuf_addstr(&start_head, head);
 		} else {
 			return error(_("bad HEAD - strange symbolic ref"));
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH v5 16/16] bisect: no longer try to clean up left-over `.git/head-name` files
  2022-08-27 12:44       ` [PATCH v5 " Johannes Schindelin via GitGitGadget
                           ` (14 preceding siblings ...)
  2022-08-27 12:44         ` [PATCH v5 15/16] bisect: remove Cogito-related code Johannes Schindelin via GitGitGadget
@ 2022-08-27 12:44         ` Johannes Schindelin via GitGitGadget
  2022-08-30 18:50         ` [PATCH v6 00/16] Finish converting git bisect into a built-in Johannes Schindelin via GitGitGadget
  16 siblings, 0 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-08-27 12:44 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Bagas Sanjaya, Junio C Hamano, Johannes Schindelin,
	Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

As per the code comment, the `.git/head-name` files were cleaned up for
backwards-compatibility: an old version of `git bisect` could have left
them behind.

Now, just how old would such a version be? As of 0f497e75f05 (Eliminate
confusing "won't bisect on seeked tree" failure, 2008-02-23), `git
bisect` does not write that file anymore. Which corresponds to Git
v1.5.4.4.

Even if the likelihood is non-nil that there might still be users out
there who use such an old version to start a bisection, but then decide
to continue bisecting with a current Git version, it is highly
improbable.

So let's remove that code, at long last.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 bisect.c                    | 3 ---
 t/t6030-bisect-porcelain.sh | 1 -
 2 files changed, 4 deletions(-)

diff --git a/bisect.c b/bisect.c
index b63669cc9d7..00bd4ba581c 100644
--- a/bisect.c
+++ b/bisect.c
@@ -474,7 +474,6 @@ static GIT_PATH_FUNC(git_path_bisect_start, "BISECT_START")
 static GIT_PATH_FUNC(git_path_bisect_log, "BISECT_LOG")
 static GIT_PATH_FUNC(git_path_bisect_terms, "BISECT_TERMS")
 static GIT_PATH_FUNC(git_path_bisect_first_parent, "BISECT_FIRST_PARENT")
-static GIT_PATH_FUNC(git_path_head_name, "head-name")
 
 static void read_bisect_paths(struct strvec *array)
 {
@@ -1181,8 +1180,6 @@ int bisect_clean_state(void)
 	unlink_or_warn(git_path_bisect_run());
 	unlink_or_warn(git_path_bisect_terms());
 	unlink_or_warn(git_path_bisect_first_parent());
-	/* Cleanup head-name if it got left by an old version of git-bisect */
-	unlink_or_warn(git_path_head_name());
 	/*
 	 * Cleanup BISECT_START last to support the --no-checkout option
 	 * introduced in the commit 4796e823a.
diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh
index 7a76f204083..1d9cbf229e2 100755
--- a/t/t6030-bisect-porcelain.sh
+++ b/t/t6030-bisect-porcelain.sh
@@ -1000,7 +1000,6 @@ test_expect_success 'git bisect reset cleans bisection state properly' '
 	test_path_is_missing ".git/BISECT_LOG" &&
 	test_path_is_missing ".git/BISECT_RUN" &&
 	test_path_is_missing ".git/BISECT_TERMS" &&
-	test_path_is_missing ".git/head-name" &&
 	test_path_is_missing ".git/BISECT_HEAD" &&
 	test_path_is_missing ".git/BISECT_START"
 '
-- 
gitgitgadget

^ permalink raw reply related	[flat|nested] 147+ messages in thread

* Re: [PATCH v5 04/16] bisect--helper: simplify exit code computation
  2022-08-27 12:44         ` [PATCH v5 04/16] bisect--helper: simplify exit code computation Johannes Schindelin via GitGitGadget
@ 2022-08-28  6:43           ` Junio C Hamano
  0 siblings, 0 replies; 147+ messages in thread
From: Junio C Hamano @ 2022-08-28  6:43 UTC (permalink / raw)
  To: Johannes Schindelin via GitGitGadget
  Cc: git, Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Bagas Sanjaya, Johannes Schindelin

"Johannes Schindelin via GitGitGadget" <gitgitgadget@gmail.com>
writes:

> From: Johannes Schindelin <johannes.schindelin@gmx.de>
>
> We _already_ have a function to determine whether a given `enum
> bisect_error` value is non-zero but still _actually_ indicates success.
>
> Let's use it instead of duplicating the logic.

Yeah, looking very good.


>
> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> ---
>  builtin/bisect--helper.c | 9 +--------
>  1 file changed, 1 insertion(+), 8 deletions(-)
>
> diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
> index aa94c25ec73..2f9c7f54f3f 100644
> --- a/builtin/bisect--helper.c
> +++ b/builtin/bisect--helper.c
> @@ -1380,12 +1380,5 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
>  	}
>  	free_terms(&terms);
>  
> -	/*
> -	 * Handle early success
> -	 * From check_merge_bases > check_good_are_ancestors_of_bad > bisect_next_all
> -	 */
> -	if ((res == BISECT_INTERNAL_SUCCESS_MERGE_BASE) || (res == BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND))
> -		res = BISECT_OK;
> -
> -	return -res;
> +	return is_bisect_success(res) ? 0 : -res;
>  }

^ permalink raw reply	[flat|nested] 147+ messages in thread

* Re: [PATCH v5 05/16] bisect--helper: make `terms` an explicit singleton
  2022-08-27 12:44         ` [PATCH v5 05/16] bisect--helper: make `terms` an explicit singleton Johannes Schindelin via GitGitGadget
@ 2022-08-28  6:53           ` Junio C Hamano
  2022-08-29 12:13             ` Johannes Schindelin
  2022-08-29 10:20           ` Ævar Arnfjörð Bjarmason
  1 sibling, 1 reply; 147+ messages in thread
From: Junio C Hamano @ 2022-08-28  6:53 UTC (permalink / raw)
  To: Johannes Schindelin via GitGitGadget
  Cc: git, Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Bagas Sanjaya, Johannes Schindelin

"Johannes Schindelin via GitGitGadget" <gitgitgadget@gmail.com>
writes:

> -struct bisect_terms {
> +static struct bisect_terms {
>  	char *term_good;
>  	char *term_bad;
> -};
> +} terms;

On the surface, more global state may feel sad, but I do not think
we want to run multiple bisection in one session anyway.  Overall
this may result in a simplicity win, hopefully.

The patch is noisy, but mostly from rewriting "terms->member" to
"terms.member".  I am not sure if that was worth the effort, though.
You had a code that plumbed a parameter through the call graph, and
instead of destroying that arrangement, you could have just replaced
the reference at the beginning of the call chain to use the global
state instead of an on-stack variable that the caller used to have.

I have no strong preference, but I do not think that it particularly
contributes to "clarifying that we are using global state" to make
direct accesses to the variable everywhere.  I dunno.


^ permalink raw reply	[flat|nested] 147+ messages in thread

* Re: [PATCH v5 06/16] bisect--helper: make the order consistently `argc, argv`
  2022-08-27 12:44         ` [PATCH v5 06/16] bisect--helper: make the order consistently `argc, argv` Johannes Schindelin via GitGitGadget
@ 2022-08-28  6:53           ` Junio C Hamano
  0 siblings, 0 replies; 147+ messages in thread
From: Junio C Hamano @ 2022-08-28  6:53 UTC (permalink / raw)
  To: Johannes Schindelin via GitGitGadget
  Cc: git, Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Bagas Sanjaya, Johannes Schindelin

"Johannes Schindelin via GitGitGadget" <gitgitgadget@gmail.com>
writes:

> From: Johannes Schindelin <johannes.schindelin@gmx.de>
>
> In C, the natural order is for `argc` to come before `argv` by virtue of
> the `main()` function declaring the parameters in precisely that order.
>
> It is confusing & distracting, then, when readers familiar with the C
> language read code where that order is switched around.
>
> Let's just change the order and avoid that type of developer friction.

Thanks.  This did look disturbing to me every time I peeked into
this part of the code.  To some it may be insignificant detail, but
these things add up.  The result is much nicer.

^ permalink raw reply	[flat|nested] 147+ messages in thread

* Re: [PATCH v5 09/16] bisect run: fix the error message
  2022-08-27 12:44         ` [PATCH v5 09/16] bisect run: fix the error message Johannes Schindelin via GitGitGadget
@ 2022-08-28  7:03           ` Junio C Hamano
  2022-08-29 12:20             ` Johannes Schindelin
  0 siblings, 1 reply; 147+ messages in thread
From: Junio C Hamano @ 2022-08-28  7:03 UTC (permalink / raw)
  To: Johannes Schindelin via GitGitGadget
  Cc: git, Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Bagas Sanjaya, Johannes Schindelin

"Johannes Schindelin via GitGitGadget" <gitgitgadget@gmail.com>
writes:

> From: Johannes Schindelin <johannes.schindelin@gmx.de>
>
> In d1bbbe45df8 (bisect--helper: reimplement `bisect_run` shell function
> in C, 2021-09-13), we ported the `bisect run` subcommand to C, including
> the part that prints out an error message when the implicit `git bisect
> bad` or `git bisect good` failed.
>
> However, the error message was supposed to print out whether the state
> was "good" or "bad", but used a bogus (because non-populated) `args`
> variable for it.
>
> Helped-by: Elijah Newren <newren@gmail.com>
> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> ---
>  builtin/bisect--helper.c    |  2 +-
>  t/t6030-bisect-porcelain.sh | 10 ++++++++++
>  2 files changed, 11 insertions(+), 1 deletion(-)
>
> diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
> index d797cd1cef8..a00167f1373 100644
> --- a/builtin/bisect--helper.c
> +++ b/builtin/bisect--helper.c
> @@ -1430,7 +1430,7 @@ static int cmd_bisect_run(int argc, const char **argv, const char *prefix)
>  			printf(_("bisect found first bad commit"));
>  			res = BISECT_OK;
>  		} else if (res) {
> -			error(_("bisect run failed: 'git bisect--helper --bisect-state"
> +			error(_("bisect run failed: 'git bisect"
>  			" %s' exited with error code %d"), new_state, res);
>  		} else {
>  			continue;

The change to retire "bisect--helper" from the end-user facing error
message makes tons of sense, but I am not quite sure if the proposed
log message describes the change correctly.  Or is this a fallout of
some "rebase -i" gotcha that a log message meant for one commit was
applied to a different commit, or something?

^ permalink raw reply	[flat|nested] 147+ messages in thread

* Re: [PATCH v5 07/16] bisect--helper: migrate to OPT_SUBCOMMAND()
  2022-08-27 12:44         ` [PATCH v5 07/16] bisect--helper: migrate to OPT_SUBCOMMAND() Johannes Schindelin via GitGitGadget
@ 2022-08-29  9:38           ` Ævar Arnfjörð Bjarmason
  2022-08-30 15:42             ` Johannes Schindelin
  0 siblings, 1 reply; 147+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-08-29  9:38 UTC (permalink / raw)
  To: Johannes Schindelin via GitGitGadget
  Cc: git, Pranit Bauva, Tanushree Tumane, Miriam Rubio, Elijah Newren,
	Bagas Sanjaya, Junio C Hamano, Johannes Schindelin


On Sat, Aug 27 2022, Johannes Schindelin via GitGitGadget wrote:

> From: Johannes Schindelin <johannes.schindelin@gmx.de>

> -static const char * const git_bisect_helper_usage[] = {
> -	N_("git bisect--helper --bisect-reset [<commit>]"),
> -	"git bisect--helper --bisect-terms [--term-good | --term-old | --term-bad | --term-new]",
> -	N_("git bisect--helper --bisect-start [--term-{new,bad}=<term> --term-{old,good}=<term>]"
> -					    " [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<paths>...]"),
> -	"git bisect--helper --bisect-next",
> -	N_("git bisect--helper --bisect-state (bad|new) [<rev>]"),
> -	N_("git bisect--helper --bisect-state (good|old) [<rev>...]"),
> -	N_("git bisect--helper --bisect-replay <filename>"),
> -	N_("git bisect--helper --bisect-skip [(<rev>|<range>)...]"),
> -	"git bisect--helper --bisect-visualize",
> -	N_("git bisect--helper --bisect-run <cmd>..."),
> +static const char * const bisect_usage[] = {
> +	N_("git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>]"
> +	   "    [--no-checkout] [--first-parent] [<bad> [<good>...]] [--]"
> +	   "    [<pathspec>...]"),
> +	N_("git bisect (bad|new) [<rev>]"),
> +	N_("git bisect (good|old) [<rev>...]"),
> +	N_("git bisect terms [--term-good | --term-bad]"),
> +	N_("git bisect skip [(<rev>|<range>)...]"),
> +	N_("git bisect next"),
> +	N_("git bisect reset [<commit>]"),
> +	N_("git bisect (visualize|view)"),
> +	N_("git bisect replay <logfile>"),
> +	N_("git bisect log"),
> +	N_("git bisect run <cmd>..."),
> +	NULL
> +};

Parts of this are erroneously reverting bits of 959d670d1a4 (i18n:
remove from i18n strings that do not hold translatable parts,
2022-01-31).

I.e. the N_() should not be there in cases like "git bisect next", only
commands that have placeholders like "<rev>".

> +static const char * const bisect_start_usage[] = {
> +	N_("git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>]"
> +	   "    [--no-checkout] [--first-parent] [<bad> [<good>...]] [--]"
> +	   "    [<pathspec>...]"),
> +	NULL
> +};

Rather than copy/pasting these we can define them once & re-use that
definition with a macro. See builtin/commit-graph.c and 8757b35d443
(commit-graph: define common usage with a macro, 2021-08-23).

(Ditto elided below)

> +	argc = parse_options(argc, argv, prefix, options,
> +			     bisect_reset_usage,  PARSE_OPT_STOP_AT_NON_OPTION);

Nit: Stray " " (double space) here in the argument list.

>  		printf(_("Your current terms are %s for the old state\n"
>  			 "and %s for the new state.\n"),
>  		       terms.term_good, terms.term_bad);
>  		return 0;

Using '%s'-quoting here for the interpolated terms would help
translators & normalize this with other bessages. It was (partially)
like this in the pre-image, but since we're changing the whole string
anyway...

> +	if (argc > 0)
> +		usage_msg_opt(_("requires 0 argument"),
> +			      bisect_next_usage, options);

Earlier a message says "requires either no argument[...]", but here we
say "requires 0 argument", which sounds like it expects a literal "0" in
the argument list.

But what we actually mean is "requires no arguments", let's change the
string to that.

> -	}
> +

Here's a "whitespace change while at it..."...

>  finish:
> +	strvec_clear(&orig_argv);
> +

Ditto here, why make this clear/release visually separate from the
cleanup below?:

>  	string_list_clear(&revs, 0);
>  	string_list_clear(&states, 0);
>  	strbuf_release(&start_head);

^^^ i.e. this.

> @@ -1004,8 +1135,10 @@ static int process_replay_line(struct strbuf *line)
>  	if (!strcmp(p, "start")) {
>  		struct strvec argv = STRVEC_INIT;
>  		int res;
> +

Ditto whitespace change here...

> +		strvec_push(&argv, p);
>  		sq_dequote_to_strvec(rev, &argv);
> [...]
>  		struct strvec argv = STRVEC_INIT;
>  		int res;
> +

...and here.., I think these are good, but they add up, perhaps worth
splitting up various whitespace-prettification in this series for
readability into its own commit.

> [...]
> @@ -1272,105 +1445,26 @@ static int bisect_run(int argc, const char **argv)
>  
>  int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
>  {
> -	enum {
> -		BISECT_RESET = 1,
> -		BISECT_TERMS,
> -		BISECT_START,
> -		BISECT_NEXT,
> -		BISECT_STATE,
> -		BISECT_LOG,
> -		BISECT_REPLAY,
> -		BISECT_SKIP,
> -		BISECT_VISUALIZE,
> -		BISECT_RUN,
> -	} cmdmode = 0;
> +	parse_opt_subcommand_fn *fn = NULL;
>  	int res = 0;
>  	struct option options[] = {
> -		OPT_CMDMODE(0, "bisect-reset", &cmdmode,
> -			 N_("reset the bisection state"), BISECT_RESET),
> -		OPT_CMDMODE(0, "bisect-terms", &cmdmode,
> -			 N_("print out the bisect terms"), BISECT_TERMS),
> -		OPT_CMDMODE(0, "bisect-start", &cmdmode,
> -			 N_("start the bisect session"), BISECT_START),
> -		OPT_CMDMODE(0, "bisect-next", &cmdmode,
> -			 N_("find the next bisection commit"), BISECT_NEXT),
> -		OPT_CMDMODE(0, "bisect-state", &cmdmode,
> -			 N_("mark the state of ref (or refs)"), BISECT_STATE),
> -		OPT_CMDMODE(0, "bisect-log", &cmdmode,
> -			 N_("list the bisection steps so far"), BISECT_LOG),
> -		OPT_CMDMODE(0, "bisect-replay", &cmdmode,
> -			 N_("replay the bisection process from the given file"), BISECT_REPLAY),
> -		OPT_CMDMODE(0, "bisect-skip", &cmdmode,
> -			 N_("skip some commits for checkout"), BISECT_SKIP),
> -		OPT_CMDMODE(0, "bisect-visualize", &cmdmode,
> -			 N_("visualize the bisection"), BISECT_VISUALIZE),
> -		OPT_CMDMODE(0, "bisect-run", &cmdmode,
> -			 N_("use <cmd>... to automatically bisect"), BISECT_RUN),
> +		OPT_SUBCOMMAND("reset", &fn, cmd_bisect_reset),
> +		OPT_SUBCOMMAND("terms", &fn, cmd_bisect_terms),
> +		OPT_SUBCOMMAND("start", &fn, cmd_bisect_start),
> +		OPT_SUBCOMMAND("next", &fn, cmd_bisect_next),
> +		OPT_SUBCOMMAND("state", &fn, cmd_bisect_state),
> +		OPT_SUBCOMMAND("log", &fn, cmd_bisect_log),
> +		OPT_SUBCOMMAND("replay", &fn, cmd_bisect_replay),
> +		OPT_SUBCOMMAND("skip", &fn, cmd_bisect_skip),
> +		OPT_SUBCOMMAND("visualize", &fn, cmd_bisect_visualize),
> +		OPT_SUBCOMMAND("run", &fn, cmd_bisect_run),
>  		OPT_END()
>  	};
>  
>  	argc = parse_options(argc, argv, prefix, options,
> -			     git_bisect_helper_usage,
> -			     PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN_OPT);
> -
> -	if (!cmdmode)
> -		usage_with_options(git_bisect_helper_usage, options);
> +			     bisect_usage, 0);
>  
> -	switch (cmdmode) {
> -	case BISECT_RESET:
> -		if (argc > 1)
> -			return error(_("--bisect-reset requires either no argument or a commit"));
> -		res = bisect_reset(argc ? argv[0] : NULL);
> -		break;
> -	case BISECT_TERMS:
> -		if (argc > 1)
> -			return error(_("--bisect-terms requires 0 or 1 argument"));
> -		res = bisect_terms(argc == 1 ? argv[0] : NULL);
> -		break;
> -	case BISECT_START:
> -		set_terms("bad", "good");
> -		res = bisect_start(argc, argv);
> -		break;
> -	case BISECT_NEXT:
> -		if (argc)
> -			return error(_("--bisect-next requires 0 arguments"));
> -		get_terms();
> -		res = bisect_next(prefix);
> -		break;
> -	case BISECT_STATE:
> -		set_terms("bad", "good");
> -		get_terms();
> -		res = bisect_state(argc, argv);
> -		break;
> -	case BISECT_LOG:
> -		if (argc)
> -			return error(_("--bisect-log requires 0 arguments"));
> -		res = bisect_log();
> -		break;
> -	case BISECT_REPLAY:
> -		if (argc != 1)
> -			return error(_("no logfile given"));
> -		set_terms("bad", "good");
> -		res = bisect_replay(argv[0]);
> -		break;
> -	case BISECT_SKIP:
> -		set_terms("bad", "good");
> -		get_terms();
> -		res = bisect_skip(argc, argv);
> -		break;
> -	case BISECT_VISUALIZE:
> -		get_terms();
> -		res = bisect_visualize(argc, argv);
> -		break;
> -	case BISECT_RUN:
> -		if (!argc)
> -			return error(_("bisect run failed: no command provided."));
> -		get_terms();
> -		res = bisect_run(argc, argv);
> -		break;
> -	default:
> -		BUG("unknown subcommand %d", cmdmode);
> -	}
> +	res = fn(argc, argv, prefix);
>  	free_terms();

The real meat of this is here, and looks much better on top of SZEDER's
series in "next" ...

>  
>  	return is_bisect_success(res) ? 0 : -res;
> diff --git a/git-bisect.sh b/git-bisect.sh
> index 405cf76f2a3..e19847eba0d 100755
> --- a/git-bisect.sh
> +++ b/git-bisect.sh
> @@ -58,26 +58,26 @@ case "$#" in
>  	help)
>  		git bisect -h ;;
>  	start)
> -		git bisect--helper --bisect-start "$@" ;;
> +		git bisect--helper start "$@" ;;
>  	bad|good|new|old|"$TERM_BAD"|"$TERM_GOOD")
> -		git bisect--helper --bisect-state "$cmd" "$@" ;;
> +		git bisect--helper state "$cmd" "$@" ;;
>  	skip)
> -		git bisect--helper --bisect-skip "$@" || exit;;
> +		git bisect--helper skip "$@" || exit;;
>  	next)
>  		# Not sure we want "next" at the UI level anymore.
> -		git bisect--helper --bisect-next "$@" || exit ;;
> +		git bisect--helper next "$@" || exit ;;
>  	visualize|view)
> -		git bisect--helper --bisect-visualize "$@" || exit;;
> +		git bisect--helper visualize "$@" || exit;;
>  	reset)
> -		git bisect--helper --bisect-reset "$@" ;;
> +		git bisect--helper reset "$@" ;;
>  	replay)
> -		git bisect--helper --bisect-replay "$@" || exit;;
> +		git bisect--helper replay "$@" || exit;;
>  	log)
> -		git bisect--helper --bisect-log || exit ;;
> +		git bisect--helper log || exit ;;
>  	run)
> -		git bisect--helper --bisect-run "$@" || exit;;
> +		git bisect--helper run "$@" || exit;;
>  	terms)
> -		git bisect--helper --bisect-terms "$@" || exit;;
> +		git bisect--helper terms "$@" || exit;;
>  	*)
>  		usage ;;
>  	esac

...I did wonder if OPT_SUBCOMMAND() supported subcommands "--like-this"
as opposed to "this", if so the renaming of all of these could be split
up into its own change.

Maybe not worth it, but it's a very large commit, which does at least:

 * Migration to that new API
 * Stray whitespace changes while at it
 * Migrating the sub-command functions themselves to parse_options()
   (good!), but not strictly required for OPT_SUBCOMMAND() (an
   orthagonal change).
 * Renaming the "verbs" for the internal helper from
   e.g. "--bisect-skip" to "skip", which is what we want eventually, but
   does inflate the almost 500-line change.


^ permalink raw reply	[flat|nested] 147+ messages in thread

* Re: [PATCH v5 11/16] bisect--helper: calling `bisect_state()` without an argument is a bug
  2022-08-27 12:44         ` [PATCH v5 11/16] bisect--helper: calling `bisect_state()` without an argument is a bug Johannes Schindelin via GitGitGadget
@ 2022-08-29 10:11           ` Ævar Arnfjörð Bjarmason
  2022-08-30 14:47             ` Johannes Schindelin
  0 siblings, 1 reply; 147+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-08-29 10:11 UTC (permalink / raw)
  To: Johannes Schindelin via GitGitGadget
  Cc: git, Pranit Bauva, Tanushree Tumane, Miriam Rubio, Elijah Newren,
	Bagas Sanjaya, Junio C Hamano, Johannes Schindelin


On Sat, Aug 27 2022, Johannes Schindelin via GitGitGadget wrote:

> From: Johannes Schindelin <johannes.schindelin@gmx.de>
>
> The `bisect_state()` function is now a purely internal function and must
> be called with a valid state, everything else is a bug.

I'm confused by the "is now purely an internal", when did that happen
exactly? That wording is new in this v5.

Before this series wasn't the only caller "internal" (git-bisect.sh) as
well? From the CL:

     -    bisect--helper: using `--bisect-state` without an argument is a bug
     +    bisect--helper: calling `bisect_state()` without an argument is a bug
      
     -    The `bisect--helper` command is not expected to be used directly by the
     -    user. Therefore, it is a bug if it receives no argument to the
     -    `--bisect-state` command mode, not a user error. Which means that we
     -    need to call `BUG()` instead of `die()`.
     +    The `bisect_state()` function is now a purely internal function and must
     +    be called with a valid state, everything else is a bug.

Before the migration to OPT_SUBCOMMAND earlier in this series:

	$ ./git bisect--helper state
	usage: git bisect--helper --bisect-reset [<commit>]
	   or: git bisect--helper --bisect-terms [--term-good | --term-old | --term-bad | --term-new]
	   or: git bisect--helper --bisect-start [--term-{new,bad}=<term> --term-{old,good}=<term>] [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<paths>...]
	   or: git bisect--helper --bisect-next
	   or: git bisect--helper --bisect-state (bad|new) [<rev>]
	   or: git bisect--helper --bisect-state (good|old) [<rev>...]
	   or: git bisect--helper --bisect-replay <filename>
	   or: git bisect--helper --bisect-skip [(<rev>|<range>)...]
	   or: git bisect--helper --bisect-visualize
	   or: git bisect--helper --bisect-run <cmd>...

	    --bisect-reset        reset the bisection state
	    --bisect-terms        print out the bisect terms
	    --bisect-start        start the bisect session
	    --bisect-next         find the next bisection commit
	    --bisect-state        mark the state of ref (or refs)
	    --bisect-log          list the bisection steps so far
	    --bisect-replay       replay the bisection process from the given file
	    --bisect-skip         skip some commits for checkout
	    --bisect-visualize    visualize the bisection
	    --bisect-run          use <cmd>... to automatically bisect

After that:

	$ ./git bisect--helper state 
	fatal: need at least one argument

	usage: git bisect (good|bad) [<rev>...]

So intra-series we were showing the wrong SYNOPSIS for this
internal-only command. I don't think that matters per-se (and the
end-state fixes it up), but doesn't it point to some ordering oddity
here?

AFAICT we couldn't call "state" without an argument from git-bisect.sh
before, and that's the only (and internal) caller, so shouldn't this
BUG() come earlier?

^ permalink raw reply	[flat|nested] 147+ messages in thread

* Re: [PATCH v5 05/16] bisect--helper: make `terms` an explicit singleton
  2022-08-27 12:44         ` [PATCH v5 05/16] bisect--helper: make `terms` an explicit singleton Johannes Schindelin via GitGitGadget
  2022-08-28  6:53           ` Junio C Hamano
@ 2022-08-29 10:20           ` Ævar Arnfjörð Bjarmason
  2022-08-29 12:30             ` Johannes Schindelin
  2022-08-29 17:47             ` Junio C Hamano
  1 sibling, 2 replies; 147+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-08-29 10:20 UTC (permalink / raw)
  To: Johannes Schindelin via GitGitGadget
  Cc: git, Pranit Bauva, Tanushree Tumane, Miriam Rubio, Elijah Newren,
	Bagas Sanjaya, Junio C Hamano, Johannes Schindelin


On Sat, Aug 27 2022, Johannes Schindelin via GitGitGadget wrote:

> From: Johannes Schindelin <johannes.schindelin@gmx.de>
> [...]
> -	free((void *)terms->term_good);
> -	terms->term_good = xstrdup(good);
> -	free((void *)terms->term_bad);
> -	terms->term_bad = xstrdup(bad);
> +	free((void *)terms.term_good);
> +	terms.term_good = xstrdup(good);
> +	free((void *)terms.term_bad);
> +	terms.term_bad = xstrdup(bad);
>  }

This is pre-existing, and dates back to 0f30233a11f (bisect--helper:
`bisect_write` shell function in C, 2019-01-02), but it appears this
cast to a "void *" was never needed. Perhaps some C++-ism that crept in
here?

As we're changing this all around perhaps it's worth droppping the cast,
or it could be left for some other "remove redundant casts" series.

^ permalink raw reply	[flat|nested] 147+ messages in thread

* Re: [PATCH v5 05/16] bisect--helper: make `terms` an explicit singleton
  2022-08-28  6:53           ` Junio C Hamano
@ 2022-08-29 12:13             ` Johannes Schindelin
  2022-08-29 17:04               ` Junio C Hamano
  0 siblings, 1 reply; 147+ messages in thread
From: Johannes Schindelin @ 2022-08-29 12:13 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Johannes Schindelin via GitGitGadget, git, Pranit Bauva,
	Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Bagas Sanjaya

Hi Junio,

On Sat, 27 Aug 2022, Junio C Hamano wrote:

> "Johannes Schindelin via GitGitGadget" <gitgitgadget@gmail.com>
> writes:
>
> > -struct bisect_terms {
> > +static struct bisect_terms {
> >  	char *term_good;
> >  	char *term_bad;
> > -};
> > +} terms;
>
> On the surface, more global state may feel sad, but I do not think
> we want to run multiple bisection in one session anyway.  Overall
> this may result in a simplicity win, hopefully.
>
> The patch is noisy, but mostly from rewriting "terms->member" to
> "terms.member".  I am not sure if that was worth the effort, though.
> You had a code that plumbed a parameter through the call graph, and
> instead of destroying that arrangement, you could have just replaced
> the reference at the beginning of the call chain to use the global
> state instead of an on-stack variable that the caller used to have.
>
> I have no strong preference, but I do not think that it particularly
> contributes to "clarifying that we are using global state" to make
> direct accesses to the variable everywhere.  I dunno.

I do have a strong preference to avoid mixing and matching global
variables with functions that pretend not to use said global variables, as
it is too easy to forget to pass through the corresponding parameter to a
function at a lower layer when that function accesses the global variable
anyway.

Ciao,
Dscho

^ permalink raw reply	[flat|nested] 147+ messages in thread

* Re: [PATCH v5 09/16] bisect run: fix the error message
  2022-08-28  7:03           ` Junio C Hamano
@ 2022-08-29 12:20             ` Johannes Schindelin
  0 siblings, 0 replies; 147+ messages in thread
From: Johannes Schindelin @ 2022-08-29 12:20 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Johannes Schindelin via GitGitGadget, git, Pranit Bauva,
	Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Bagas Sanjaya

Hi Junio,

On Sun, 28 Aug 2022, Junio C Hamano wrote:

> "Johannes Schindelin via GitGitGadget" <gitgitgadget@gmail.com>
> writes:
>
> > From: Johannes Schindelin <johannes.schindelin@gmx.de>
> >
> > In d1bbbe45df8 (bisect--helper: reimplement `bisect_run` shell function
> > in C, 2021-09-13), we ported the `bisect run` subcommand to C, including
> > the part that prints out an error message when the implicit `git bisect
> > bad` or `git bisect good` failed.
> >
> > However, the error message was supposed to print out whether the state
> > was "good" or "bad", but used a bogus (because non-populated) `args`
> > variable for it.
> >
> > Helped-by: Elijah Newren <newren@gmail.com>
> > Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> > ---
> >  builtin/bisect--helper.c    |  2 +-
> >  t/t6030-bisect-porcelain.sh | 10 ++++++++++
> >  2 files changed, 11 insertions(+), 1 deletion(-)
> >
> > diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
> > index d797cd1cef8..a00167f1373 100644
> > --- a/builtin/bisect--helper.c
> > +++ b/builtin/bisect--helper.c
> > @@ -1430,7 +1430,7 @@ static int cmd_bisect_run(int argc, const char **argv, const char *prefix)
> >  			printf(_("bisect found first bad commit"));
> >  			res = BISECT_OK;
> >  		} else if (res) {
> > -			error(_("bisect run failed: 'git bisect--helper --bisect-state"
> > +			error(_("bisect run failed: 'git bisect"
> >  			" %s' exited with error code %d"), new_state, res);
> >  		} else {
> >  			continue;
>
> The change to retire "bisect--helper" from the end-user facing error
> message makes tons of sense, but I am not quite sure if the proposed
> log message describes the change correctly.  Or is this a fallout of
> some "rebase -i" gotcha that a log message meant for one commit was
> applied to a different commit, or something?

This is indeed a fall-out from some interactive rebase. Thank you for
catching it.

You can actually see it in the thread history: v2 still had a diff that
was aligned with the commit message, but
<46fe0774-66e7-8947-cd79-d35229eec25a@web.de> graduated between v2 and v3
and partially addressed the issue fixed by this here patch.

I'm glad that we caught this in time for v6. This is the commit message I
plan on using:

-- snip --
    bisect run: fix the error message

    In d1bbbe45df8 (bisect--helper: reimplement `bisect_run` shell function
    in C, 2021-09-13), we ported the `bisect run` subcommand to C, including
    the part that prints out an error message when the implicit `git bisect
    bad` or `git bisect good` failed.

    However, the error message was supposed to print out whether the state
    was "good" or "bad", but used a bogus (because non-populated) `args`
    variable for it. This was fixed in 80c2e9657f2 (bisect--helper: report
    actual bisect_state() argument on error, 2022-01-18), but the error
    message still talks about `bisect--helper`, which is an implementation
    detail that should not concern end users.

    Fix that, and add a regression test to ensure that the intended form of
    the error message.
-- snap --

Ciao,
Dscho

^ permalink raw reply	[flat|nested] 147+ messages in thread

* Re: [PATCH v5 05/16] bisect--helper: make `terms` an explicit singleton
  2022-08-29 10:20           ` Ævar Arnfjörð Bjarmason
@ 2022-08-29 12:30             ` Johannes Schindelin
  2022-08-29 17:47             ` Junio C Hamano
  1 sibling, 0 replies; 147+ messages in thread
From: Johannes Schindelin @ 2022-08-29 12:30 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: Johannes Schindelin via GitGitGadget, git, Pranit Bauva,
	Tanushree Tumane, Miriam Rubio, Elijah Newren, Bagas Sanjaya,
	Junio C Hamano

[-- Attachment #1: Type: text/plain, Size: 952 bytes --]

Hi Ævar,

On Mon, 29 Aug 2022, Ævar Arnfjörð Bjarmason wrote:

>
> On Sat, Aug 27 2022, Johannes Schindelin via GitGitGadget wrote:
>
> > From: Johannes Schindelin <johannes.schindelin@gmx.de>
> > [...]
> > -	free((void *)terms->term_good);
> > -	terms->term_good = xstrdup(good);
> > -	free((void *)terms->term_bad);
> > -	terms->term_bad = xstrdup(bad);
> > +	free((void *)terms.term_good);
> > +	terms.term_good = xstrdup(good);
> > +	free((void *)terms.term_bad);
> > +	terms.term_bad = xstrdup(bad);
> >  }
>
> This is pre-existing, and dates back to 0f30233a11f (bisect--helper:
> `bisect_write` shell function in C, 2019-01-02), but it appears this
> cast to a "void *" was never needed. Perhaps some C++-ism that crept in
> here?

While this is all true, this feedback is about code that is not changed by
this patch.

I am afraid that this review therefore misses the intention of the patch.

Ciao,
Johannes

^ permalink raw reply	[flat|nested] 147+ messages in thread

* Re: [PATCH v5 05/16] bisect--helper: make `terms` an explicit singleton
  2022-08-29 12:13             ` Johannes Schindelin
@ 2022-08-29 17:04               ` Junio C Hamano
  0 siblings, 0 replies; 147+ messages in thread
From: Junio C Hamano @ 2022-08-29 17:04 UTC (permalink / raw)
  To: Johannes Schindelin
  Cc: Johannes Schindelin via GitGitGadget, git, Pranit Bauva,
	Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Bagas Sanjaya

Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:

>> I have no strong preference, but I do not think that it particularly
>> contributes to "clarifying that we are using global state" to make
>> direct accesses to the variable everywhere.  I dunno.
>
> I do have a strong preference to avoid mixing and matching global
> variables with functions that pretend not to use said global variables, as
> it is too easy to forget to pass through the corresponding parameter to a
> function at a lower layer when that function accesses the global variable
> anyway.

When you have a truly well "libified" API and a program that needs
to use global to communicate to other parts of the system, then the
approach I suggested would follow a much better design taste.  For
example, if your program takes an argument --option=string, and you
for whatever reason have to use a global variable to store the value
due to limitation of your option parsing API, you'd create a global
variable to store the string.  But well libified API functions (say,
the ones from the C library) do not have to care if you are using a
global or an on-stack variable.  I would not rewrite strlen(const
char *) to my_strlen(void) that only looks at the global variable
and use it instead.

But it is quite possible that bisect--helper may not have such a
clean interface, in which case it is pefectly OK for everybody to
look at the global directly.  My comment was mostly a reaction based
on the assumption that your earlier "libifyable state" comment meant
that these call graphs are nicely libified and pass everything they
need through via parameters, in which case, the ultimate callers of
these helper functions that take "struct bisect_terms *", like
free_terms(), may have the parameter they pass down to the callchain
on their stack, and now have to pass a pointer to a global, without
the callchain that is "as libified as possible" having to know.




^ permalink raw reply	[flat|nested] 147+ messages in thread

* Re: [PATCH v5 05/16] bisect--helper: make `terms` an explicit singleton
  2022-08-29 10:20           ` Ævar Arnfjörð Bjarmason
  2022-08-29 12:30             ` Johannes Schindelin
@ 2022-08-29 17:47             ` Junio C Hamano
  1 sibling, 0 replies; 147+ messages in thread
From: Junio C Hamano @ 2022-08-29 17:47 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: Johannes Schindelin via GitGitGadget, git, Pranit Bauva,
	Tanushree Tumane, Miriam Rubio, Elijah Newren, Bagas Sanjaya,
	Johannes Schindelin

Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:

> On Sat, Aug 27 2022, Johannes Schindelin via GitGitGadget wrote:
>
>> From: Johannes Schindelin <johannes.schindelin@gmx.de>
>> [...]
>> -	free((void *)terms->term_good);
>> -	terms->term_good = xstrdup(good);
>> -	free((void *)terms->term_bad);
>> -	terms->term_bad = xstrdup(bad);
>> +	free((void *)terms.term_good);
>> +	terms.term_good = xstrdup(good);
>> +	free((void *)terms.term_bad);
>> +	terms.term_bad = xstrdup(bad);
>>  }
>
> This is pre-existing, and dates back to 0f30233a11f (bisect--helper:
> `bisect_write` shell function in C, 2019-01-02), but it appears this
> cast to a "void *" was never needed. Perhaps some C++-ism that crept in
> here?
>
> As we're changing this all around perhaps it's worth droppping the cast,
> or it could be left for some other "remove redundant casts" series.

Nice to notice it.  I suspect that at some point in the evolution of
the offending patch in 2019 the members were of type "const char *"
and needed to cast the constness away, or something, perhaps?

In any case, such a change belongs to either preliminary clean-up
before the series, or post clean-up after the dust settles, not
something we'd want to see "while we are at it" to distract us.

^ permalink raw reply	[flat|nested] 147+ messages in thread

* Re: [PATCH v5 11/16] bisect--helper: calling `bisect_state()` without an argument is a bug
  2022-08-29 10:11           ` Ævar Arnfjörð Bjarmason
@ 2022-08-30 14:47             ` Johannes Schindelin
  0 siblings, 0 replies; 147+ messages in thread
From: Johannes Schindelin @ 2022-08-30 14:47 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: Johannes Schindelin via GitGitGadget, git, Pranit Bauva,
	Tanushree Tumane, Miriam Rubio, Elijah Newren, Bagas Sanjaya,
	Junio C Hamano

[-- Attachment #1: Type: text/plain, Size: 5309 bytes --]

Hi Ævar,

On Mon, 29 Aug 2022, Ævar Arnfjörð Bjarmason wrote:

>
> On Sat, Aug 27 2022, Johannes Schindelin via GitGitGadget wrote:
>
> > From: Johannes Schindelin <johannes.schindelin@gmx.de>
> >
> > The `bisect_state()` function is now a purely internal function and must
> > be called with a valid state, everything else is a bug.
>
> I'm confused by the "is now purely an internal", when did that happen
> exactly? That wording is new in this v5.

Yes, it is new. It is part of that huge amount of work to not only convert
the script to a built-in but also "while at it" migrate the entire
`bisect--helper` on top of the subcommand API, as you specifically asked
for, and it was that ask that blocked the patch series which would
probably otherwise have been accepted as-is, with the subcommand migration
left as a follow-up patch series with a much narrower scope than the
current iteration.

As to when it happened exactly? In 07/16 of this patch series iteration,
as explained as part of the commit message:

	Note that a couple of `bisect_*()` functions are not converted into
	`cmd_bisect_*()` functions directly, as they have callers other than the
	`OPT_SUBCOMMAND()` one (and the original functions did not expect
	a subcommand name to be passed as `argv[0]`, unlike the convention for
	the `cmd_*()` functions. In those cases, we introduce wrapper functions
	`cmd_*()` that also call the original function.

I did not repeat in the commit message all details that the diff explains
much more eloquently, such as `cmd_bisect_state()` now being a wrapper
around `bisect_state()`.

> Before this series wasn't the only caller "internal" (git-bisect.sh) as
> well? From the CL:
>
>      -    bisect--helper: using `--bisect-state` without an argument is a bug
>      +    bisect--helper: calling `bisect_state()` without an argument is a bug
>
>      -    The `bisect--helper` command is not expected to be used directly by the
>      -    user. Therefore, it is a bug if it receives no argument to the
>      -    `--bisect-state` command mode, not a user error. Which means that we
>      -    need to call `BUG()` instead of `die()`.
>      +    The `bisect_state()` function is now a purely internal function and must
>      +    be called with a valid state, everything else is a bug.
>
> Before the migration to OPT_SUBCOMMAND earlier in this series:
>
> 	$ ./git bisect--helper state
> 	usage: git bisect--helper --bisect-reset [<commit>]
> 	   or: git bisect--helper --bisect-terms [--term-good | --term-old | --term-bad | --term-new]
> 	   or: git bisect--helper --bisect-start [--term-{new,bad}=<term> --term-{old,good}=<term>] [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<paths>...]
> 	   or: git bisect--helper --bisect-next
> 	   or: git bisect--helper --bisect-state (bad|new) [<rev>]
> 	   or: git bisect--helper --bisect-state (good|old) [<rev>...]
> 	   or: git bisect--helper --bisect-replay <filename>
> 	   or: git bisect--helper --bisect-skip [(<rev>|<range>)...]
> 	   or: git bisect--helper --bisect-visualize
> 	   or: git bisect--helper --bisect-run <cmd>...
>
> 	    --bisect-reset        reset the bisection state
> 	    --bisect-terms        print out the bisect terms
> 	    --bisect-start        start the bisect session
> 	    --bisect-next         find the next bisection commit
> 	    --bisect-state        mark the state of ref (or refs)
> 	    --bisect-log          list the bisection steps so far
> 	    --bisect-replay       replay the bisection process from the given file
> 	    --bisect-skip         skip some commits for checkout
> 	    --bisect-visualize    visualize the bisection
> 	    --bisect-run          use <cmd>... to automatically bisect
>
> After that:
>
> 	$ ./git bisect--helper state
> 	fatal: need at least one argument
>
> 	usage: git bisect (good|bad) [<rev>...]
>
> So intra-series we were showing the wrong SYNOPSIS for this
> internal-only command. I don't think that matters per-se (and the
> end-state fixes it up), but doesn't it point to some ordering oddity
> here?
>
> AFAICT we couldn't call "state" without an argument from git-bisect.sh
> before, and that's the only (and internal) caller, so shouldn't this
> BUG() come earlier?

Yes, it could come earlier. Or later. It is part of some follow-up patches
that need to come after 07/16, in whatever order.

I appreciate that you want to help.

My concern is that by having to focus on answering such questions that I
consider a thorough review of the iteration to answer handily, I cannot
spend the same time and focus on preventing bugs I consider a lot more
critical. We saw some bug reports about the built-in `add -i` recently,
for example, that could have been prevented if the focus of the code
review was not so much on details that the end user won't ever see (such
as the order of patches or whether to broaden the scope and size of a
patch series instead of leaving follow-up work to subsequent patch
series), and more on unintentional changes that the users very much
experience, and not in a good way. I would appreciate it a lot if we could
focus first and foremost on preventing bugs cause problems to Git's users.

Thank you,
Johannes

^ permalink raw reply	[flat|nested] 147+ messages in thread

* Re: [PATCH v5 07/16] bisect--helper: migrate to OPT_SUBCOMMAND()
  2022-08-29  9:38           ` Ævar Arnfjörð Bjarmason
@ 2022-08-30 15:42             ` Johannes Schindelin
  0 siblings, 0 replies; 147+ messages in thread
From: Johannes Schindelin @ 2022-08-30 15:42 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: Johannes Schindelin via GitGitGadget, git, Pranit Bauva,
	Tanushree Tumane, Miriam Rubio, Elijah Newren, Bagas Sanjaya,
	Junio C Hamano

[-- Attachment #1: Type: text/plain, Size: 16260 bytes --]

Hi Ævar,

On Mon, 29 Aug 2022, Ævar Arnfjörð Bjarmason wrote:

> On Sat, Aug 27 2022, Johannes Schindelin via GitGitGadget wrote:
>
> > From: Johannes Schindelin <johannes.schindelin@gmx.de>
>
> > -static const char * const git_bisect_helper_usage[] = {
> > -	N_("git bisect--helper --bisect-reset [<commit>]"),
> > -	"git bisect--helper --bisect-terms [--term-good | --term-old | --term-bad | --term-new]",
> > -	N_("git bisect--helper --bisect-start [--term-{new,bad}=<term> --term-{old,good}=<term>]"
> > -					    " [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<paths>...]"),
> > -	"git bisect--helper --bisect-next",
> > -	N_("git bisect--helper --bisect-state (bad|new) [<rev>]"),
> > -	N_("git bisect--helper --bisect-state (good|old) [<rev>...]"),
> > -	N_("git bisect--helper --bisect-replay <filename>"),
> > -	N_("git bisect--helper --bisect-skip [(<rev>|<range>)...]"),
> > -	"git bisect--helper --bisect-visualize",
> > -	N_("git bisect--helper --bisect-run <cmd>..."),
> > +static const char * const bisect_usage[] = {
> > +	N_("git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>]"
> > +	   "    [--no-checkout] [--first-parent] [<bad> [<good>...]] [--]"
> > +	   "    [<pathspec>...]"),
> > +	N_("git bisect (bad|new) [<rev>]"),
> > +	N_("git bisect (good|old) [<rev>...]"),
> > +	N_("git bisect terms [--term-good | --term-bad]"),
> > +	N_("git bisect skip [(<rev>|<range>)...]"),
> > +	N_("git bisect next"),
> > +	N_("git bisect reset [<commit>]"),
> > +	N_("git bisect (visualize|view)"),
> > +	N_("git bisect replay <logfile>"),
> > +	N_("git bisect log"),
> > +	N_("git bisect run <cmd>..."),
> > +	NULL
> > +};
>
> Parts of this are erroneously reverting bits of 959d670d1a4 (i18n:
> remove from i18n strings that do not hold translatable parts,
> 2022-01-31).

That is misreading what this patch does. I did not turn the pre-image into
the post-image.

As the commit message states, we now use the subcommand API with the
intention to replace the `git-bisect.sh` script altogether (that's written
in the first paragraph of the proposed commit message).

This means that the command modes are replaced by subcommands, and the
usage of the subcommands is copied from the script.

And that is the reason why you see a usage about `view` and `log`, as I
assume you noticed.

By the way, this here distraction makes a really fine case why it would
have been better to leave the migration to the subcommand API to a
follow-up patch series. You will recall that I favored that, and I would
have loved for you to agree.

Having said that, it is a good point that we do not want to reintroduce
the problem that was fixed by 959d670d1a4 (i18n: remove from i18n strings
that do not hold translatable parts, 2022-01-31).

> I.e. the N_() should not be there in cases like "git bisect next", only
> commands that have placeholders like "<rev>".
>
> > +static const char * const bisect_start_usage[] = {
> > +	N_("git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>]"
> > +	   "    [--no-checkout] [--first-parent] [<bad> [<good>...]] [--]"
> > +	   "    [<pathspec>...]"),
> > +	NULL
> > +};
>
> Rather than copy/pasting these we can define them once & re-use that
> definition with a macro. See builtin/commit-graph.c and 8757b35d443
> (commit-graph: define common usage with a macro, 2021-08-23).

I would do this if I found it elegant.

> (Ditto elided below)
>
> > +	argc = parse_options(argc, argv, prefix, options,
> > +			     bisect_reset_usage,  PARSE_OPT_STOP_AT_NON_OPTION);
>
> Nit: Stray " " (double space) here in the argument list.

Good find! Will fix. And obviously not only the `reset` case.

>
> >  		printf(_("Your current terms are %s for the old state\n"
> >  			 "and %s for the new state.\n"),
> >  		       terms.term_good, terms.term_bad);
> >  		return 0;
>
> Using '%s'-quoting here for the interpolated terms would help
> translators & normalize this with other bessages. It was (partially)
> like this in the pre-image, but since we're changing the whole string
> anyway...

It is a bad practice to draw out code contributions by asking contributors
to add unrelated changes. This here mail thread presents a fine example
why. Let's avoid doing that from now on.

> > +	if (argc > 0)
> > +		usage_msg_opt(_("requires 0 argument"),
> > +			      bisect_next_usage, options);
>
> Earlier a message says "requires either no argument[...]", but here we
> say "requires 0 argument", which sounds like it expects a literal "0" in
> the argument list.

As you undoubtedly noticed, this message was moved from the
`cmd_bisect__helper()` function, with its `--bisect-next` part deleted
(because it is incorrect now that we no longer have command modes).

> But what we actually mean is "requires no arguments", let's change the
> string to that.

No, let's not. For the same reason as noted above.

> > -	}
> > +
>
> Here's a "whitespace change while at it..."...

This removes a curly bracket and adds an empty line. You are referring to
the empty line?

It is a bit hard to understand what you mean, not only because of the lack
of clarity but also because too much context was clipped to easily find
the part of the patch that you were referring to. Please be more
considerate in the future.

I have to assume that you are referring to a tiny part of one hunk that
describes how `bisect_start()` became `cmd_bisect_start()`. If that is
indeed what you were referring to, then you are talking about a hunk that
seemingly replaces a `for (i = 0; i < argc; i++)` loop that parses the
command-line with a loop that validates that only revision parameters are
specified before the double dash, if any. In other words, the "introduced"
white-space is part of a completely new loop.

>
> >  finish:
> > +	strvec_clear(&orig_argv);
> > +
>
> Ditto here, why make this clear/release visually separate from the
> cleanup below?:
>
> >  	string_list_clear(&revs, 0);
> >  	string_list_clear(&states, 0);
> >  	strbuf_release(&start_head);
>
> ^^^ i.e. this.

Because the latter statements clean up data structures that were used for
the core functionality of `bisect start`, while the `orig_argv` purely
were a copy for the sake of the bisect log. Therefore, they are logically
separate, and the empty line helps readers such as myself.

>
> > @@ -1004,8 +1135,10 @@ static int process_replay_line(struct strbuf *line)
> >  	if (!strcmp(p, "start")) {
> >  		struct strvec argv = STRVEC_INIT;
> >  		int res;
> > +
>
> Ditto whitespace change here...
>
> > +		strvec_push(&argv, p);
> >  		sq_dequote_to_strvec(rev, &argv);
> > [...]
> >  		struct strvec argv = STRVEC_INIT;
> >  		int res;
> > +
>
> ...and here.., I think these are good, but they add up, perhaps worth
> splitting up various whitespace-prettification in this series for
> readability into its own commit.
>
> > [...]
> > @@ -1272,105 +1445,26 @@ static int bisect_run(int argc, const char **argv)
> >
> >  int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
> >  {
> > -	enum {
> > -		BISECT_RESET = 1,
> > -		BISECT_TERMS,
> > -		BISECT_START,
> > -		BISECT_NEXT,
> > -		BISECT_STATE,
> > -		BISECT_LOG,
> > -		BISECT_REPLAY,
> > -		BISECT_SKIP,
> > -		BISECT_VISUALIZE,
> > -		BISECT_RUN,
> > -	} cmdmode = 0;
> > +	parse_opt_subcommand_fn *fn = NULL;
> >  	int res = 0;
> >  	struct option options[] = {
> > -		OPT_CMDMODE(0, "bisect-reset", &cmdmode,
> > -			 N_("reset the bisection state"), BISECT_RESET),
> > -		OPT_CMDMODE(0, "bisect-terms", &cmdmode,
> > -			 N_("print out the bisect terms"), BISECT_TERMS),
> > -		OPT_CMDMODE(0, "bisect-start", &cmdmode,
> > -			 N_("start the bisect session"), BISECT_START),
> > -		OPT_CMDMODE(0, "bisect-next", &cmdmode,
> > -			 N_("find the next bisection commit"), BISECT_NEXT),
> > -		OPT_CMDMODE(0, "bisect-state", &cmdmode,
> > -			 N_("mark the state of ref (or refs)"), BISECT_STATE),
> > -		OPT_CMDMODE(0, "bisect-log", &cmdmode,
> > -			 N_("list the bisection steps so far"), BISECT_LOG),
> > -		OPT_CMDMODE(0, "bisect-replay", &cmdmode,
> > -			 N_("replay the bisection process from the given file"), BISECT_REPLAY),
> > -		OPT_CMDMODE(0, "bisect-skip", &cmdmode,
> > -			 N_("skip some commits for checkout"), BISECT_SKIP),
> > -		OPT_CMDMODE(0, "bisect-visualize", &cmdmode,
> > -			 N_("visualize the bisection"), BISECT_VISUALIZE),
> > -		OPT_CMDMODE(0, "bisect-run", &cmdmode,
> > -			 N_("use <cmd>... to automatically bisect"), BISECT_RUN),
> > +		OPT_SUBCOMMAND("reset", &fn, cmd_bisect_reset),
> > +		OPT_SUBCOMMAND("terms", &fn, cmd_bisect_terms),
> > +		OPT_SUBCOMMAND("start", &fn, cmd_bisect_start),
> > +		OPT_SUBCOMMAND("next", &fn, cmd_bisect_next),
> > +		OPT_SUBCOMMAND("state", &fn, cmd_bisect_state),
> > +		OPT_SUBCOMMAND("log", &fn, cmd_bisect_log),
> > +		OPT_SUBCOMMAND("replay", &fn, cmd_bisect_replay),
> > +		OPT_SUBCOMMAND("skip", &fn, cmd_bisect_skip),
> > +		OPT_SUBCOMMAND("visualize", &fn, cmd_bisect_visualize),
> > +		OPT_SUBCOMMAND("run", &fn, cmd_bisect_run),
> >  		OPT_END()
> >  	};
> >
> >  	argc = parse_options(argc, argv, prefix, options,
> > -			     git_bisect_helper_usage,
> > -			     PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN_OPT);
> > -
> > -	if (!cmdmode)
> > -		usage_with_options(git_bisect_helper_usage, options);
> > +			     bisect_usage, 0);
> >
> > -	switch (cmdmode) {
> > -	case BISECT_RESET:
> > -		if (argc > 1)
> > -			return error(_("--bisect-reset requires either no argument or a commit"));
> > -		res = bisect_reset(argc ? argv[0] : NULL);
> > -		break;
> > -	case BISECT_TERMS:
> > -		if (argc > 1)
> > -			return error(_("--bisect-terms requires 0 or 1 argument"));
> > -		res = bisect_terms(argc == 1 ? argv[0] : NULL);
> > -		break;
> > -	case BISECT_START:
> > -		set_terms("bad", "good");
> > -		res = bisect_start(argc, argv);
> > -		break;
> > -	case BISECT_NEXT:
> > -		if (argc)
> > -			return error(_("--bisect-next requires 0 arguments"));
> > -		get_terms();
> > -		res = bisect_next(prefix);
> > -		break;
> > -	case BISECT_STATE:
> > -		set_terms("bad", "good");
> > -		get_terms();
> > -		res = bisect_state(argc, argv);
> > -		break;
> > -	case BISECT_LOG:
> > -		if (argc)
> > -			return error(_("--bisect-log requires 0 arguments"));
> > -		res = bisect_log();
> > -		break;
> > -	case BISECT_REPLAY:
> > -		if (argc != 1)
> > -			return error(_("no logfile given"));
> > -		set_terms("bad", "good");
> > -		res = bisect_replay(argv[0]);
> > -		break;
> > -	case BISECT_SKIP:
> > -		set_terms("bad", "good");
> > -		get_terms();
> > -		res = bisect_skip(argc, argv);
> > -		break;
> > -	case BISECT_VISUALIZE:
> > -		get_terms();
> > -		res = bisect_visualize(argc, argv);
> > -		break;
> > -	case BISECT_RUN:
> > -		if (!argc)
> > -			return error(_("bisect run failed: no command provided."));
> > -		get_terms();
> > -		res = bisect_run(argc, argv);
> > -		break;
> > -	default:
> > -		BUG("unknown subcommand %d", cmdmode);
> > -	}
> > +	res = fn(argc, argv, prefix);
> >  	free_terms();
>
> The real meat of this is here, and looks much better on top of SZEDER's
> series in "next" ...

Beauty is no quality in things themselves: It exists merely in the mind
which contemplates them; and each mind perceives a different beauty.

Plus, this hunk cannot be taken out of context: It requires all the
lengthy hunks that come before it, and that are relatively hard to parse
as you found out.

> >
> >  	return is_bisect_success(res) ? 0 : -res;
> > diff --git a/git-bisect.sh b/git-bisect.sh
> > index 405cf76f2a3..e19847eba0d 100755
> > --- a/git-bisect.sh
> > +++ b/git-bisect.sh
> > @@ -58,26 +58,26 @@ case "$#" in
> >  	help)
> >  		git bisect -h ;;
> >  	start)
> > -		git bisect--helper --bisect-start "$@" ;;
> > +		git bisect--helper start "$@" ;;
> >  	bad|good|new|old|"$TERM_BAD"|"$TERM_GOOD")
> > -		git bisect--helper --bisect-state "$cmd" "$@" ;;
> > +		git bisect--helper state "$cmd" "$@" ;;
> >  	skip)
> > -		git bisect--helper --bisect-skip "$@" || exit;;
> > +		git bisect--helper skip "$@" || exit;;
> >  	next)
> >  		# Not sure we want "next" at the UI level anymore.
> > -		git bisect--helper --bisect-next "$@" || exit ;;
> > +		git bisect--helper next "$@" || exit ;;
> >  	visualize|view)
> > -		git bisect--helper --bisect-visualize "$@" || exit;;
> > +		git bisect--helper visualize "$@" || exit;;
> >  	reset)
> > -		git bisect--helper --bisect-reset "$@" ;;
> > +		git bisect--helper reset "$@" ;;
> >  	replay)
> > -		git bisect--helper --bisect-replay "$@" || exit;;
> > +		git bisect--helper replay "$@" || exit;;
> >  	log)
> > -		git bisect--helper --bisect-log || exit ;;
> > +		git bisect--helper log || exit ;;
> >  	run)
> > -		git bisect--helper --bisect-run "$@" || exit;;
> > +		git bisect--helper run "$@" || exit;;
> >  	terms)
> > -		git bisect--helper --bisect-terms "$@" || exit;;
> > +		git bisect--helper terms "$@" || exit;;
> >  	*)
> >  		usage ;;
> >  	esac
>
> ...I did wonder if OPT_SUBCOMMAND() supported subcommands "--like-this"
> as opposed to "this", if so the renaming of all of these could be split
> up into its own change.
>
> Maybe not worth it, but it's a very large commit, which does at least:
>
>  * Migration to that new API
>  * Stray whitespace changes while at it
>  * Migrating the sub-command functions themselves to parse_options()
>    (good!), but not strictly required for OPT_SUBCOMMAND() (an
>    orthagonal change).
>  * Renaming the "verbs" for the internal helper from
>    e.g. "--bisect-skip" to "skip", which is what we want eventually, but
>    does inflate the almost 500-line change.

These suggestions could very easily be construed to be intentionally
drawing out a patch contribution that pretty much all other participants
in the mail thread have expressed a desire to be done with.

I do understand that you care a lot about these details and about
white-space and the parse_options API.

Please do understand that I care about the correctness of the code, and
wish I could see more suggestions between all those suggestions that would
be conducive to further that goal.

This is a complex patch, to be sure, and it is pretty much solely due to
having had to include the move from the command-mode paradigm to the
subcommand paradigm in the patch series, which I would very much have
preferred to do in a separate patch series.

Could that move have been done more incrementally? Maybe. I tried to split
it up as much as I could _without_ losing focus of the actual goal of this
patch series: the conversion from a script that implemented the `bisect`
operation to a pure built-in that is supposed to perform the same
operation without introducing regressions. If it were a follow-up patch
series whose sole intention is to migrate `git bisect` to the subcommand
API, I would have been eager to spent more time on making it more
incremental. However, the goal of this patch series was, and is, to finish
the conversion of `git bisect` from a script to a built-in.

That goal was unfortuntely made a lot harder than I wanted to by the
feedback I received, and I really wish that it would have been easier to
convert `git-bisect.sh` to `builtin/bisect.c`. I would see the feedback in
more favorable light if I could see how that feedback furthered that goal,
but I have a hard time finding enough evidence that I could consider to
merit 5 iterations and 7 months of work.

I want to be clear: any feedback you provide that helps me improve the
quality and correctness of my patches is appreciated. Your feedback where
you pointed out that my v5 would regress on 959d670d1a4 (i18n: remove from
i18n strings that do not hold translatable parts, 2022-01-31) is such a
feedback. I want to see more of that kind of feedback from you, and will
not hold it against you if you reduce tangential feedback in order to do
that.

Thank you,
Johannes

^ permalink raw reply	[flat|nested] 147+ messages in thread

* [PATCH v6 00/16] Finish converting git bisect into a built-in
  2022-08-27 12:44       ` [PATCH v5 " Johannes Schindelin via GitGitGadget
                           ` (15 preceding siblings ...)
  2022-08-27 12:44         ` [PATCH v5 16/16] bisect: no longer try to clean up left-over `.git/head-name` files Johannes Schindelin via GitGitGadget
@ 2022-08-30 18:50         ` Johannes Schindelin via GitGitGadget
  2022-08-30 18:50           ` [PATCH v6 01/16] bisect--helper: retire the --no-log option Johannes Schindelin via GitGitGadget
                             ` (16 more replies)
  16 siblings, 17 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-08-30 18:50 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Bagas Sanjaya, Junio C Hamano, Johannes Schindelin

After three GSoC/Outreachy students spent an incredible effort on this, it
is finally time to put a neat little bow on it, or maybe more like a big
bow, maybe even a very large one, seeing as it takes quite a while to tie
(half a year at the time of writing)...

Changes since v5:

 * Fixed the commit message of "bisect run: fix the error message" that had
   become stale as of v3 due to 80c2e9657f2 "overtaking" it and doing half
   of its job.
 * Skipped translation usage strings in "bisect--helper: migrate to
   OPT_SUBCOMMAND()" that do not contain translatable parts.
 * Minor white-space clean-up in "bisect--helper: migrate to
   OPT_SUBCOMMAND()".

Changes since v4:

 * rebased onto sg/parse-options-subcommand
 * migrated to OPT_SUBCOMMAND().
 * As a consequence, this patch series is now unfortunately very large. And
   the range-diff is much less useful than I'd like because of the extensive
   changes that were de facto made a precondition to moving this patch
   series further. Junio, I would have liked to keep the scope (and burden
   for the reviewers) substantially smaller, maybe you can help with the
   review?

Changes since v3:

 * Rebased because of merge conflicts with ab/plug-leak-in-revisions.
 * Fixed the bug that git bisect --bisect-terms 1 2 wanted to auto-start a
   bisection if running with a git executable built at the in-between state
   at patch "bisect: move even the command-line parsing to bisect--helper".
   Since this bug was "fixed" in v3 by the very next patch, "bisect: teach
   the bisect--helper command to show the correct usage strings", v4 avoids
   introducing this bug simply by letting these two patches trade places.
   The range-diff admittedly looks quite awful because both patches overlap
   quite a bit in the lines they modify. The end result is the same, though,
   the diff between v3's and v4's builtin/bisect.c would be empty if I
   hadn't been forced to rebase.
 * Added a test case to ensure that this bug won't be introduced again. This
   test case is the only actual difference relative to v3 of this patch
   series.

Changes since v2:

 * We're now careful to provide identical usage strings upon git bisect -h
   and git bisect bogus.
 * When a bogus command is provided, we now error out instead of trying to
   start a git bisect run.
 * Rebased onto main to avoid plenty of merge conflicts with
   rs/bisect-executable-not-found, ac/usage-string-fixups and with
   cd/bisect-messages-from-pre-flight-states.

Changes since v1:

 * Added a regression test to "bisect run: fix the error message".
 * Added a patch to address an error message that double-single-quoted the
   command.
 * Reworked the logic in "bisect--helper: make --bisect-state optional" to
   delay showing the usage upon an unknown command, which should make the
   code a lot less confusing.
 * Split out the change that moved the BISECT_STATE case to the end of the
   switch block.
 * Added a patch that replaces the return error() calls in
   cmd_bisect_helper() with die() calls, to avoid returning -1 as an exit
   code.
 * Dropped the use of parse_options() for the single purpose of handling -h;
   This is now done explicitly.
 * Simplified the diff of "bisect: move even the option parsing to
   bisect--helper" by modifying argc and argv instead of modifying all the
   function calls using those variables.
 * In the "Turn git bisect into a full built-in" patch, changed the name of
   the variable holding the usage to use the builtin_ prefix used in other
   built-ins, too.
 * Removed the trailing dot from the commit message of "Turn git bisect into
   a full built-in".

Johannes Schindelin (16):
  bisect--helper: retire the --no-log option
  bisect--helper: really retire --bisect-next-check
  bisect--helper: really retire `--bisect-autostart`
  bisect--helper: simplify exit code computation
  bisect--helper: make `terms` an explicit singleton
  bisect--helper: make the order consistently `argc, argv`
  bisect--helper: migrate to OPT_SUBCOMMAND()
  bisect: verify that a bogus option won't try to start a bisection
  bisect run: fix the error message
  bisect: avoid double-quoting when printing the failed command
  bisect--helper: calling `bisect_state()` without an argument is a bug
  bisect--helper: make `state` optional
  bisect: move even the command-line parsing to `bisect--helper`
  Turn `git bisect` into a full built-in
  bisect: remove Cogito-related code
  bisect: no longer try to clean up left-over `.git/head-name` files

 Makefile                               |   3 +-
 bisect.c                               |   3 -
 builtin.h                              |   2 +-
 builtin/{bisect--helper.c => bisect.c} | 679 ++++++++++++++-----------
 git-bisect.sh                          |  84 ---
 git.c                                  |   2 +-
 t/t6030-bisect-porcelain.sh            |  21 +-
 7 files changed, 406 insertions(+), 388 deletions(-)
 rename builtin/{bisect--helper.c => bisect.c} (67%)
 delete mode 100755 git-bisect.sh


base-commit: 8f9d80f6c06369b563c76ec46c462e740a1a2cf0
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-1132%2Fdscho%2Fbisect-in-c-v6
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1132/dscho/bisect-in-c-v6
Pull-Request: https://github.com/gitgitgadget/git/pull/1132

Range-diff vs v5:

  1:  05262b6a7d1 =  1:  05262b6a7d1 bisect--helper: retire the --no-log option
  2:  1e43148864a =  2:  1e43148864a bisect--helper: really retire --bisect-next-check
  3:  1a1649d9d0d =  3:  1a1649d9d0d bisect--helper: really retire `--bisect-autostart`
  4:  9ab30552c6a =  4:  9ab30552c6a bisect--helper: simplify exit code computation
  5:  92b3b116ef8 =  5:  92b3b116ef8 bisect--helper: make `terms` an explicit singleton
  6:  c9dc0281e38 =  6:  c9dc0281e38 bisect--helper: make the order consistently `argc, argv`
  7:  5b7a3d58b4f !  7:  e97e187bbec bisect--helper: migrate to OPT_SUBCOMMAND()
     @@ Commit message
          `bisect--helper` learns about it in preparation for replacing the
          `git-bisect.sh` script altogether.
      
     +    As a consequence, the usage strings are copied over from the scripted
     +    version of the `git bisect` command. To avoid regressing on 959d670d1a4
     +    (i18n: remove from i18n strings that do not hold translatable parts,
     +    2022-01-31), we specifically do not enclose usage strings in `N_(...)`
     +    that do not contain any translatable parts.
     +
          Note that a couple of `bisect_*()` functions are not converted into
          `cmd_bisect_*()` functions directly, as they have callers other than the
          `OPT_SUBCOMMAND()` one (and the original functions did not expect
     @@ builtin/bisect--helper.c: static GIT_PATH_FUNC(git_path_bisect_names, "BISECT_NA
      +	   "    [<pathspec>...]"),
      +	N_("git bisect (bad|new) [<rev>]"),
      +	N_("git bisect (good|old) [<rev>...]"),
     -+	N_("git bisect terms [--term-good | --term-bad]"),
     ++	"git bisect terms [--term-good | --term-bad]",
      +	N_("git bisect skip [(<rev>|<range>)...]"),
     -+	N_("git bisect next"),
     ++	"git bisect next",
      +	N_("git bisect reset [<commit>]"),
     -+	N_("git bisect (visualize|view)"),
     ++	"git bisect (visualize|view)",
      +	N_("git bisect replay <logfile>"),
     -+	N_("git bisect log"),
     ++	"git bisect log",
      +	N_("git bisect run <cmd>..."),
      +	NULL
      +};
     @@ builtin/bisect--helper.c: static GIT_PATH_FUNC(git_path_bisect_names, "BISECT_NA
      +};
      +
      +static const char * const bisect_terms_usage[] = {
     -+	N_("git bisect terms [--term-good | --term-bad]"),
     ++	"git bisect terms [--term-good | --term-bad]",
      +	NULL
      +};
      +
     @@ builtin/bisect--helper.c: static GIT_PATH_FUNC(git_path_bisect_names, "BISECT_NA
      +};
      +
      +static const char * const bisect_next_usage[] = {
     -+	N_("git bisect next"),
     ++	"git bisect next",
      +	NULL
      +};
      +
     @@ builtin/bisect--helper.c: static GIT_PATH_FUNC(git_path_bisect_names, "BISECT_NA
      +};
      +
      +static const char * const bisect_visualize_usage[] = {
     -+	N_("git bisect visualize"),
     ++	"git bisect visualize",
      +	NULL
      +};
      +
     @@ builtin/bisect--helper.c: static GIT_PATH_FUNC(git_path_bisect_names, "BISECT_NA
      +};
      +
      +static const char * const bisect_log_usage[] = {
     -+	N_("git bisect log"),
     ++	"git bisect log",
      +	NULL
      +};
      +
     @@ builtin/bisect--helper.c: static int bisect_reset(const char *commit)
      +		OPT_END()
      +	};
      +	argc = parse_options(argc, argv, prefix, options,
     -+			     bisect_reset_usage,  PARSE_OPT_STOP_AT_NON_OPTION);
     ++			     bisect_reset_usage, PARSE_OPT_STOP_AT_NON_OPTION);
      +
      +	if (argc > 1)
      +		usage_msg_opt(_("requires either no argument or a commit"),
     @@ builtin/bisect--helper.c: finish:
      +	};
      +
      +	argc = parse_options(argc, argv, prefix, options,
     -+			     bisect_terms_usage,  PARSE_OPT_STOP_AT_NON_OPTION);
     ++			     bisect_terms_usage, PARSE_OPT_STOP_AT_NON_OPTION);
      +
      +	if (argc > 1)
      +		usage_msg_opt(_("terms: requires 0 or 1 argument"),
     @@ builtin/bisect--helper.c: static enum bisect_error bisect_state(int argc, const
      +	get_terms();
      +
      +	argc = parse_options(argc, argv, prefix, options,
     -+			     bisect_state_usage,  PARSE_OPT_STOP_AT_NON_OPTION);
     ++			     bisect_state_usage, PARSE_OPT_STOP_AT_NON_OPTION);
      +
      +	if (!argc)
      +		usage_msg_opt(_("need at least one argument"),
     @@ builtin/bisect--helper.c: static enum bisect_error bisect_state(int argc, const
       	const char* filename = git_path_bisect_log();
       
      +	argc = parse_options(argc, argv, prefix, options,
     -+			     bisect_log_usage,  PARSE_OPT_STOP_AT_NON_OPTION);
     ++			     bisect_log_usage, PARSE_OPT_STOP_AT_NON_OPTION);
      +
      +	if (argc > 0)
      +		usage_msg_opt(_("require 0 argument"), bisect_log_usage,
     @@ builtin/bisect--helper.c: static int process_replay_line(struct strbuf *line)
       
      +	set_terms("bad", "good");
      +	argc = parse_options(argc, argv, prefix, options,
     -+			     bisect_reset_usage,  PARSE_OPT_STOP_AT_NON_OPTION);
     ++			     bisect_reset_usage, PARSE_OPT_STOP_AT_NON_OPTION);
      +
      +	if (argc != 1)
      +		usage_msg_opt(_("no logfile given"), bisect_replay_usage,
     @@ builtin/bisect--helper.c: static enum bisect_error bisect_replay(const char *fil
      +	set_terms("bad", "good");
      +	get_terms();
      +	argc = parse_options(argc, argv, prefix, options,
     -+			     bisect_skip_usage,  PARSE_OPT_STOP_AT_NON_OPTION);
     ++			     bisect_skip_usage, PARSE_OPT_STOP_AT_NON_OPTION);
      +
       	strvec_push(&argv_state, "skip");
       
     @@ builtin/bisect--helper.c: static int bisect_run(int argc, const char **argv)
       
      +	get_terms();
      +	argc = parse_options(argc, argv, prefix, options,
     -+			     bisect_run_usage,  PARSE_OPT_STOP_AT_NON_OPTION);
     ++			     bisect_run_usage, PARSE_OPT_STOP_AT_NON_OPTION);
      +
       	if (bisect_next_check(NULL))
       		return BISECT_FAILED;
  8:  ba537af7066 =  8:  30c87f2e92e bisect: verify that a bogus option won't try to start a bisection
  9:  409492ad830 !  9:  4696652b99c bisect run: fix the error message
     @@ Commit message
      
          However, the error message was supposed to print out whether the state
          was "good" or "bad", but used a bogus (because non-populated) `args`
     -    variable for it.
     +    variable for it. This was fixed in 80c2e9657f2 (bisect--helper: report
     +    actual bisect_state() argument on error, 2022-01-18), but the error
     +    message still talks about `bisect--helper`, which is an implementation
     +    detail that should not concern end users.
     +
     +    Fix that, and add a regression test to ensure that the intended form of
     +    the error message.
      
          Helped-by: Elijah Newren <newren@gmail.com>
          Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
 10:  bc5efc8fbfe = 10:  b202a0e386c bisect: avoid double-quoting when printing the failed command
 11:  8a0adfe3867 = 11:  3376b450867 bisect--helper: calling `bisect_state()` without an argument is a bug
 12:  189d2b3ba46 = 12:  e7623508f90 bisect--helper: make `state` optional
 13:  32bf74e3050 = 13:  3f052580c95 bisect: move even the command-line parsing to `bisect--helper`
 14:  a8f08f5e0cb = 14:  a83fe3dc3c2 Turn `git bisect` into a full built-in
 15:  a96489310d3 = 15:  f2132b61ff7 bisect: remove Cogito-related code
 16:  bfa7aa19f03 = 16:  4f93692e071 bisect: no longer try to clean up left-over `.git/head-name` files

-- 
gitgitgadget

^ permalink raw reply	[flat|nested] 147+ messages in thread

* [PATCH v6 01/16] bisect--helper: retire the --no-log option
  2022-08-30 18:50         ` [PATCH v6 00/16] Finish converting git bisect into a built-in Johannes Schindelin via GitGitGadget
@ 2022-08-30 18:50           ` Johannes Schindelin via GitGitGadget
  2022-08-30 18:50           ` [PATCH v6 02/16] bisect--helper: really retire --bisect-next-check Johannes Schindelin via GitGitGadget
                             ` (15 subsequent siblings)
  16 siblings, 0 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-08-30 18:50 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Bagas Sanjaya, Junio C Hamano, Johannes Schindelin,
	Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

Turns out we actually never used it, anyway...

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/bisect--helper.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 7097750fc6b..2cc69e1eee5 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1292,7 +1292,7 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 		BISECT_VISUALIZE,
 		BISECT_RUN,
 	} cmdmode = 0;
-	int res = 0, nolog = 0;
+	int res = 0;
 	struct option options[] = {
 		OPT_CMDMODE(0, "bisect-reset", &cmdmode,
 			 N_("reset the bisection state"), BISECT_RESET),
@@ -1316,8 +1316,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 			 N_("visualize the bisection"), BISECT_VISUALIZE),
 		OPT_CMDMODE(0, "bisect-run", &cmdmode,
 			 N_("use <cmd>... to automatically bisect"), BISECT_RUN),
-		OPT_BOOL(0, "no-log", &nolog,
-			 N_("no log for BISECT_WRITE")),
 		OPT_END()
 	};
 	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH v6 02/16] bisect--helper: really retire --bisect-next-check
  2022-08-30 18:50         ` [PATCH v6 00/16] Finish converting git bisect into a built-in Johannes Schindelin via GitGitGadget
  2022-08-30 18:50           ` [PATCH v6 01/16] bisect--helper: retire the --no-log option Johannes Schindelin via GitGitGadget
@ 2022-08-30 18:50           ` Johannes Schindelin via GitGitGadget
  2022-08-30 18:50           ` [PATCH v6 03/16] bisect--helper: really retire `--bisect-autostart` Johannes Schindelin via GitGitGadget
                             ` (14 subsequent siblings)
  16 siblings, 0 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-08-30 18:50 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Bagas Sanjaya, Junio C Hamano, Johannes Schindelin,
	Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

In 911aba14205 (bisect--helper: retire `--bisect-next-check` subcommand,
2021-09-13), we removed the usage string and the implementation, but not
actually the option.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/bisect--helper.c | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 2cc69e1eee5..bdf7ce18d7a 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1280,7 +1280,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 {
 	enum {
 		BISECT_RESET = 1,
-		BISECT_NEXT_CHECK,
 		BISECT_TERMS,
 		BISECT_START,
 		BISECT_AUTOSTART,
@@ -1296,8 +1295,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 	struct option options[] = {
 		OPT_CMDMODE(0, "bisect-reset", &cmdmode,
 			 N_("reset the bisection state"), BISECT_RESET),
-		OPT_CMDMODE(0, "bisect-next-check", &cmdmode,
-			 N_("check whether bad or good terms exist"), BISECT_NEXT_CHECK),
 		OPT_CMDMODE(0, "bisect-terms", &cmdmode,
 			 N_("print out the bisect terms"), BISECT_TERMS),
 		OPT_CMDMODE(0, "bisect-start", &cmdmode,
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH v6 03/16] bisect--helper: really retire `--bisect-autostart`
  2022-08-30 18:50         ` [PATCH v6 00/16] Finish converting git bisect into a built-in Johannes Schindelin via GitGitGadget
  2022-08-30 18:50           ` [PATCH v6 01/16] bisect--helper: retire the --no-log option Johannes Schindelin via GitGitGadget
  2022-08-30 18:50           ` [PATCH v6 02/16] bisect--helper: really retire --bisect-next-check Johannes Schindelin via GitGitGadget
@ 2022-08-30 18:50           ` Johannes Schindelin via GitGitGadget
  2022-08-30 18:50           ` [PATCH v6 04/16] bisect--helper: simplify exit code computation Johannes Schindelin via GitGitGadget
                             ` (13 subsequent siblings)
  16 siblings, 0 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-08-30 18:50 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Bagas Sanjaya, Junio C Hamano, Johannes Schindelin,
	Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

Since b0f6494f70f (bisect--helper: retire `--bisect-autostart`
subcommand, 2020-10-15), the `--bisect-autostart` option is no more. But
we kept the `enum` value of the command mode around. Let's drop it, too.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/bisect--helper.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index bdf7ce18d7a..aa94c25ec73 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1282,7 +1282,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 		BISECT_RESET = 1,
 		BISECT_TERMS,
 		BISECT_START,
-		BISECT_AUTOSTART,
 		BISECT_NEXT,
 		BISECT_STATE,
 		BISECT_LOG,
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH v6 04/16] bisect--helper: simplify exit code computation
  2022-08-30 18:50         ` [PATCH v6 00/16] Finish converting git bisect into a built-in Johannes Schindelin via GitGitGadget
                             ` (2 preceding siblings ...)
  2022-08-30 18:50           ` [PATCH v6 03/16] bisect--helper: really retire `--bisect-autostart` Johannes Schindelin via GitGitGadget
@ 2022-08-30 18:50           ` Johannes Schindelin via GitGitGadget
  2022-08-30 18:50           ` [PATCH v6 05/16] bisect--helper: make `terms` an explicit singleton Johannes Schindelin via GitGitGadget
                             ` (12 subsequent siblings)
  16 siblings, 0 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-08-30 18:50 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Bagas Sanjaya, Junio C Hamano, Johannes Schindelin,
	Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

We _already_ have a function to determine whether a given `enum
bisect_error` value is non-zero but still _actually_ indicates success.

Let's use it instead of duplicating the logic.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/bisect--helper.c | 9 +--------
 1 file changed, 1 insertion(+), 8 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index aa94c25ec73..2f9c7f54f3f 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1380,12 +1380,5 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 	}
 	free_terms(&terms);
 
-	/*
-	 * Handle early success
-	 * From check_merge_bases > check_good_are_ancestors_of_bad > bisect_next_all
-	 */
-	if ((res == BISECT_INTERNAL_SUCCESS_MERGE_BASE) || (res == BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND))
-		res = BISECT_OK;
-
-	return -res;
+	return is_bisect_success(res) ? 0 : -res;
 }
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH v6 05/16] bisect--helper: make `terms` an explicit singleton
  2022-08-30 18:50         ` [PATCH v6 00/16] Finish converting git bisect into a built-in Johannes Schindelin via GitGitGadget
                             ` (3 preceding siblings ...)
  2022-08-30 18:50           ` [PATCH v6 04/16] bisect--helper: simplify exit code computation Johannes Schindelin via GitGitGadget
@ 2022-08-30 18:50           ` Johannes Schindelin via GitGitGadget
  2022-08-30 21:11             ` Junio C Hamano
  2022-08-30 18:50           ` [PATCH v6 06/16] bisect--helper: make the order consistently `argc, argv` Johannes Schindelin via GitGitGadget
                             ` (11 subsequent siblings)
  16 siblings, 1 reply; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-08-30 18:50 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Bagas Sanjaya, Junio C Hamano, Johannes Schindelin,
	Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

We tried very hard to keep code in `builtin/bisect--helper.c` in as
libifyable a state as possible.

However, we are about to migrate this built-in to the `OPT_SUBCOMMAND()`
API, which does not allow for passing any context (e.g. via a `void
*data` parameters as they are used in the config API).

Therefore, we _have_ to move the `terms` variable outside of
`cmd_bisect__helper()` and explicitly make it a singleton (as it
currently is, anyway).

Let's just make things consistent and stop passing around pointers to
that singleton; Use it directly instead.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/bisect--helper.c | 262 +++++++++++++++++++--------------------
 1 file changed, 128 insertions(+), 134 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 2f9c7f54f3f..7f4e8e707c1 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -40,30 +40,30 @@ struct add_bisect_ref_data {
 	unsigned int object_flags;
 };
 
-struct bisect_terms {
+static struct bisect_terms {
 	char *term_good;
 	char *term_bad;
-};
+} terms;
 
-static void free_terms(struct bisect_terms *terms)
+static void free_terms(void)
 {
-	FREE_AND_NULL(terms->term_good);
-	FREE_AND_NULL(terms->term_bad);
+	FREE_AND_NULL(terms.term_good);
+	FREE_AND_NULL(terms.term_bad);
 }
 
-static void set_terms(struct bisect_terms *terms, const char *bad,
+static void set_terms(const char *bad,
 		      const char *good)
 {
-	free((void *)terms->term_good);
-	terms->term_good = xstrdup(good);
-	free((void *)terms->term_bad);
-	terms->term_bad = xstrdup(bad);
+	free((void *)terms.term_good);
+	terms.term_good = xstrdup(good);
+	free((void *)terms.term_bad);
+	terms.term_bad = xstrdup(bad);
 }
 
 static const char vocab_bad[] = "bad|new";
 static const char vocab_good[] = "good|old";
 
-static int bisect_autostart(struct bisect_terms *terms);
+static int bisect_autostart(void);
 
 /*
  * Check whether the string `term` belongs to the set of strings
@@ -254,8 +254,7 @@ static void log_commit(FILE *fp, char *fmt, const char *state,
 	free(label);
 }
 
-static int bisect_write(const char *state, const char *rev,
-			const struct bisect_terms *terms, int nolog)
+static int bisect_write(const char *state, const char *rev, int nolog)
 {
 	struct strbuf tag = STRBUF_INIT;
 	struct object_id oid;
@@ -263,9 +262,9 @@ static int bisect_write(const char *state, const char *rev,
 	FILE *fp = NULL;
 	int res = 0;
 
-	if (!strcmp(state, terms->term_bad)) {
+	if (!strcmp(state, terms.term_bad)) {
 		strbuf_addf(&tag, "refs/bisect/%s", state);
-	} else if (one_of(state, terms->term_good, "skip", NULL)) {
+	} else if (one_of(state, terms.term_good, "skip", NULL)) {
 		strbuf_addf(&tag, "refs/bisect/%s-%s", state, rev);
 	} else {
 		res = error(_("Bad bisect_write argument: %s"), state);
@@ -302,27 +301,27 @@ finish:
 	return res;
 }
 
-static int check_and_set_terms(struct bisect_terms *terms, const char *cmd)
+static int check_and_set_terms(const char *cmd)
 {
 	int has_term_file = !is_empty_or_missing_file(git_path_bisect_terms());
 
 	if (one_of(cmd, "skip", "start", "terms", NULL))
 		return 0;
 
-	if (has_term_file && strcmp(cmd, terms->term_bad) &&
-	    strcmp(cmd, terms->term_good))
+	if (has_term_file && strcmp(cmd, terms.term_bad) &&
+	    strcmp(cmd, terms.term_good))
 		return error(_("Invalid command: you're currently in a "
-				"%s/%s bisect"), terms->term_bad,
-				terms->term_good);
+				"%s/%s bisect"), terms.term_bad,
+				terms.term_good);
 
 	if (!has_term_file) {
 		if (one_of(cmd, "bad", "good", NULL)) {
-			set_terms(terms, "bad", "good");
-			return write_terms(terms->term_bad, terms->term_good);
+			set_terms("bad", "good");
+			return write_terms(terms.term_bad, terms.term_good);
 		}
 		if (one_of(cmd, "new", "old", NULL)) {
-			set_terms(terms, "new", "old");
-			return write_terms(terms->term_bad, terms->term_good);
+			set_terms("new", "old");
+			return write_terms(terms.term_bad, terms.term_good);
 		}
 	}
 
@@ -346,8 +345,7 @@ static const char need_bisect_start_warning[] =
 	   "You then need to give me at least one %s and %s revision.\n"
 	   "You can use \"git bisect %s\" and \"git bisect %s\" for that.");
 
-static int decide_next(const struct bisect_terms *terms,
-		       const char *current_term, int missing_good,
+static int decide_next(const char *current_term, int missing_good,
 		       int missing_bad)
 {
 	if (!missing_good && !missing_bad)
@@ -356,13 +354,13 @@ static int decide_next(const struct bisect_terms *terms,
 		return -1;
 
 	if (missing_good && !missing_bad &&
-	    !strcmp(current_term, terms->term_good)) {
+	    !strcmp(current_term, terms.term_good)) {
 		char *yesno;
 		/*
 		 * have bad (or new) but not good (or old). We could bisect
 		 * although this is less optimum.
 		 */
-		warning(_("bisecting only with a %s commit"), terms->term_bad);
+		warning(_("bisecting only with a %s commit"), terms.term_bad);
 		if (!isatty(0))
 			return 0;
 		/*
@@ -384,11 +382,10 @@ static int decide_next(const struct bisect_terms *terms,
 			     vocab_good, vocab_bad, vocab_good, vocab_bad);
 }
 
-static void bisect_status(struct bisect_state *state,
-			  const struct bisect_terms *terms)
+static void bisect_status(struct bisect_state *state)
 {
-	char *bad_ref = xstrfmt("refs/bisect/%s", terms->term_bad);
-	char *good_glob = xstrfmt("%s-*", terms->term_good);
+	char *bad_ref = xstrfmt("refs/bisect/%s", terms.term_bad);
+	char *good_glob = xstrfmt("%s-*", terms.term_good);
 
 	if (ref_exists(bad_ref))
 		state->nr_bad = 1;
@@ -416,11 +413,11 @@ static void bisect_log_printf(const char *fmt, ...)
 	strbuf_release(&buf);
 }
 
-static void bisect_print_status(const struct bisect_terms *terms)
+static void bisect_print_status(void)
 {
 	struct bisect_state state = { 0 };
 
-	bisect_status(&state, terms);
+	bisect_status(&state);
 
 	/* If we had both, we'd already be started, and shouldn't get here. */
 	if (state.nr_good && state.nr_bad)
@@ -436,15 +433,14 @@ static void bisect_print_status(const struct bisect_terms *terms)
 		bisect_log_printf(_("status: waiting for good commit(s), bad commit known\n"));
 }
 
-static int bisect_next_check(const struct bisect_terms *terms,
-			     const char *current_term)
+static int bisect_next_check(const char *current_term)
 {
 	struct bisect_state state = { 0 };
-	bisect_status(&state, terms);
-	return decide_next(terms, current_term, !state.nr_good, !state.nr_bad);
+	bisect_status(&state);
+	return decide_next(current_term, !state.nr_good, !state.nr_bad);
 }
 
-static int get_terms(struct bisect_terms *terms)
+static int get_terms(void)
 {
 	struct strbuf str = STRBUF_INIT;
 	FILE *fp = NULL;
@@ -456,11 +452,11 @@ static int get_terms(struct bisect_terms *terms)
 		goto finish;
 	}
 
-	free_terms(terms);
+	free_terms();
 	strbuf_getline_lf(&str, fp);
-	terms->term_bad = strbuf_detach(&str, NULL);
+	terms.term_bad = strbuf_detach(&str, NULL);
 	strbuf_getline_lf(&str, fp);
-	terms->term_good = strbuf_detach(&str, NULL);
+	terms.term_good = strbuf_detach(&str, NULL);
 
 finish:
 	if (fp)
@@ -469,21 +465,21 @@ finish:
 	return res;
 }
 
-static int bisect_terms(struct bisect_terms *terms, const char *option)
+static int bisect_terms(const char *option)
 {
-	if (get_terms(terms))
+	if (get_terms())
 		return error(_("no terms defined"));
 
 	if (!option) {
 		printf(_("Your current terms are %s for the old state\n"
 			 "and %s for the new state.\n"),
-		       terms->term_good, terms->term_bad);
+		       terms.term_good, terms.term_bad);
 		return 0;
 	}
 	if (one_of(option, "--term-good", "--term-old", NULL))
-		printf("%s\n", terms->term_good);
+		printf("%s\n", terms.term_good);
 	else if (one_of(option, "--term-bad", "--term-new", NULL))
-		printf("%s\n", terms->term_bad);
+		printf("%s\n", terms.term_bad);
 	else
 		return error(_("invalid argument %s for 'git bisect terms'.\n"
 			       "Supported options are: "
@@ -527,18 +523,18 @@ static int add_bisect_ref(const char *refname, const struct object_id *oid,
 	return 0;
 }
 
-static int prepare_revs(struct bisect_terms *terms, struct rev_info *revs)
+static int prepare_revs(struct rev_info *revs)
 {
 	int res = 0;
 	struct add_bisect_ref_data cb = { revs };
-	char *good = xstrfmt("%s-*", terms->term_good);
+	char *good = xstrfmt("%s-*", terms.term_good);
 
 	/*
-	 * We cannot use terms->term_bad directly in
+	 * We cannot use terms.term_bad directly in
 	 * for_each_glob_ref_in() and we have to append a '*' to it,
 	 * otherwise for_each_glob_ref_in() will append '/' and '*'.
 	 */
-	char *bad = xstrfmt("%s*", terms->term_bad);
+	char *bad = xstrfmt("%s*", terms.term_bad);
 
 	/*
 	 * It is important to reset the flags used by revision walks
@@ -559,7 +555,7 @@ static int prepare_revs(struct bisect_terms *terms, struct rev_info *revs)
 	return res;
 }
 
-static int bisect_skipped_commits(struct bisect_terms *terms)
+static int bisect_skipped_commits(void)
 {
 	int res;
 	FILE *fp = NULL;
@@ -568,7 +564,7 @@ static int bisect_skipped_commits(struct bisect_terms *terms)
 	struct pretty_print_context pp = {0};
 	struct strbuf commit_name = STRBUF_INIT;
 
-	res = prepare_revs(terms, &revs);
+	res = prepare_revs(&revs);
 	if (res)
 		return res;
 
@@ -585,7 +581,7 @@ static int bisect_skipped_commits(struct bisect_terms *terms)
 		format_commit_message(commit, "%s",
 				      &commit_name, &pp);
 		fprintf(fp, "# possible first %s commit: [%s] %s\n",
-			terms->term_bad, oid_to_hex(&commit->object.oid),
+			terms.term_bad, oid_to_hex(&commit->object.oid),
 			commit_name.buf);
 	}
 
@@ -601,13 +597,13 @@ static int bisect_skipped_commits(struct bisect_terms *terms)
 	return 0;
 }
 
-static int bisect_successful(struct bisect_terms *terms)
+static int bisect_successful(void)
 {
 	struct object_id oid;
 	struct commit *commit;
 	struct pretty_print_context pp = {0};
 	struct strbuf commit_name = STRBUF_INIT;
-	char *bad_ref = xstrfmt("refs/bisect/%s",terms->term_bad);
+	char *bad_ref = xstrfmt("refs/bisect/%s",terms.term_bad);
 	int res;
 
 	read_ref(bad_ref, &oid);
@@ -615,7 +611,7 @@ static int bisect_successful(struct bisect_terms *terms)
 	format_commit_message(commit, "%s", &commit_name, &pp);
 
 	res = append_to_file(git_path_bisect_log(), "# first %s commit: [%s] %s\n",
-			    terms->term_bad, oid_to_hex(&commit->object.oid),
+			    terms.term_bad, oid_to_hex(&commit->object.oid),
 			    commit_name.buf);
 
 	strbuf_release(&commit_name);
@@ -623,40 +619,40 @@ static int bisect_successful(struct bisect_terms *terms)
 	return res;
 }
 
-static enum bisect_error bisect_next(struct bisect_terms *terms, const char *prefix)
+static enum bisect_error bisect_next(const char *prefix)
 {
 	enum bisect_error res;
 
-	if (bisect_autostart(terms))
+	if (bisect_autostart())
 		return BISECT_FAILED;
 
-	if (bisect_next_check(terms, terms->term_good))
+	if (bisect_next_check(terms.term_good))
 		return BISECT_FAILED;
 
 	/* Perform all bisection computation */
 	res = bisect_next_all(the_repository, prefix);
 
 	if (res == BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND) {
-		res = bisect_successful(terms);
+		res = bisect_successful();
 		return res ? res : BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND;
 	} else if (res == BISECT_ONLY_SKIPPED_LEFT) {
-		res = bisect_skipped_commits(terms);
+		res = bisect_skipped_commits();
 		return res ? res : BISECT_ONLY_SKIPPED_LEFT;
 	}
 	return res;
 }
 
-static enum bisect_error bisect_auto_next(struct bisect_terms *terms, const char *prefix)
+static enum bisect_error bisect_auto_next(const char *prefix)
 {
-	if (bisect_next_check(terms, NULL)) {
-		bisect_print_status(terms);
+	if (bisect_next_check(NULL)) {
+		bisect_print_status();
 		return BISECT_OK;
 	}
 
-	return bisect_next(terms, prefix);
+	return bisect_next(prefix);
 }
 
-static enum bisect_error bisect_start(struct bisect_terms *terms, const char **argv, int argc)
+static enum bisect_error bisect_start(const char **argv, int argc)
 {
 	int no_checkout = 0;
 	int first_parent_only = 0;
@@ -698,26 +694,26 @@ static enum bisect_error bisect_start(struct bisect_terms *terms, const char **a
 			if (argc <= i)
 				return error(_("'' is not a valid term"));
 			must_write_terms = 1;
-			free((void *) terms->term_good);
-			terms->term_good = xstrdup(argv[i]);
+			free((void *) terms.term_good);
+			terms.term_good = xstrdup(argv[i]);
 		} else if (skip_prefix(arg, "--term-good=", &arg) ||
 			   skip_prefix(arg, "--term-old=", &arg)) {
 			must_write_terms = 1;
-			free((void *) terms->term_good);
-			terms->term_good = xstrdup(arg);
+			free((void *) terms.term_good);
+			terms.term_good = xstrdup(arg);
 		} else if (!strcmp(arg, "--term-bad") ||
 			 !strcmp(arg, "--term-new")) {
 			i++;
 			if (argc <= i)
 				return error(_("'' is not a valid term"));
 			must_write_terms = 1;
-			free((void *) terms->term_bad);
-			terms->term_bad = xstrdup(argv[i]);
+			free((void *) terms.term_bad);
+			terms.term_bad = xstrdup(argv[i]);
 		} else if (skip_prefix(arg, "--term-bad=", &arg) ||
 			   skip_prefix(arg, "--term-new=", &arg)) {
 			must_write_terms = 1;
-			free((void *) terms->term_bad);
-			terms->term_bad = xstrdup(arg);
+			free((void *) terms.term_bad);
+			terms.term_bad = xstrdup(arg);
 		} else if (starts_with(arg, "--")) {
 			return error(_("unrecognized option: '%s'"), arg);
 		} else if (!get_oidf(&oid, "%s^{commit}", arg)) {
@@ -741,10 +737,10 @@ static enum bisect_error bisect_start(struct bisect_terms *terms, const char **a
 		must_write_terms = 1;
 	for (i = 0; i < revs.nr; i++) {
 		if (bad_seen) {
-			string_list_append(&states, terms->term_good);
+			string_list_append(&states, terms.term_good);
 		} else {
 			bad_seen = 1;
-			string_list_append(&states, terms->term_bad);
+			string_list_append(&states, terms.term_bad);
 		}
 	}
 
@@ -829,13 +825,13 @@ static enum bisect_error bisect_start(struct bisect_terms *terms, const char **a
 
 	for (i = 0; i < states.nr; i++)
 		if (bisect_write(states.items[i].string,
-				 revs.items[i].string, terms, 1)) {
+				 revs.items[i].string, 1)) {
 			res = BISECT_FAILED;
 			goto finish;
 		}
 
-	if (must_write_terms && write_terms(terms->term_bad,
-					    terms->term_good)) {
+	if (must_write_terms && write_terms(terms.term_bad,
+					    terms.term_good)) {
 		res = BISECT_FAILED;
 		goto finish;
 	}
@@ -852,7 +848,7 @@ finish:
 	if (res)
 		return res;
 
-	res = bisect_auto_next(terms, NULL);
+	res = bisect_auto_next(NULL);
 	if (!is_bisect_success(res))
 		bisect_clean_state();
 	return res;
@@ -863,7 +859,7 @@ static inline int file_is_not_empty(const char *path)
 	return !is_empty_or_missing_file(path);
 }
 
-static int bisect_autostart(struct bisect_terms *terms)
+static int bisect_autostart(void)
 {
 	int res;
 	const char *yesno;
@@ -885,12 +881,12 @@ static int bisect_autostart(struct bisect_terms *terms)
 	yesno = git_prompt(_("Do you want me to do it for you "
 			     "[Y/n]? "), PROMPT_ECHO);
 	res = tolower(*yesno) == 'n' ?
-		-1 : bisect_start(terms, empty_strvec, 0);
+		-1 : bisect_start(empty_strvec, 0);
 
 	return res;
 }
 
-static enum bisect_error bisect_state(struct bisect_terms *terms, const char **argv,
+static enum bisect_error bisect_state(const char **argv,
 				      int argc)
 {
 	const char *state;
@@ -902,18 +898,18 @@ static enum bisect_error bisect_state(struct bisect_terms *terms, const char **a
 	if (!argc)
 		return error(_("Please call `--bisect-state` with at least one argument"));
 
-	if (bisect_autostart(terms))
+	if (bisect_autostart())
 		return BISECT_FAILED;
 
 	state = argv[0];
-	if (check_and_set_terms(terms, state) ||
-	    !one_of(state, terms->term_good, terms->term_bad, "skip", NULL))
+	if (check_and_set_terms(state) ||
+	    !one_of(state, terms.term_good, terms.term_bad, "skip", NULL))
 		return BISECT_FAILED;
 
 	argv++;
 	argc--;
-	if (argc > 1 && !strcmp(state, terms->term_bad))
-		return error(_("'git bisect %s' can take only one argument."), terms->term_bad);
+	if (argc > 1 && !strcmp(state, terms.term_bad))
+		return error(_("'git bisect %s' can take only one argument."), terms.term_bad);
 
 	if (argc == 0) {
 		const char *head = "BISECT_HEAD";
@@ -956,7 +952,7 @@ static enum bisect_error bisect_state(struct bisect_terms *terms, const char **a
 	strbuf_release(&buf);
 
 	for (i = 0; i < revs.nr; i++) {
-		if (bisect_write(state, oid_to_hex(&revs.oid[i]), terms, 0)) {
+		if (bisect_write(state, oid_to_hex(&revs.oid[i]), 0)) {
 			oid_array_clear(&revs);
 			return BISECT_FAILED;
 		}
@@ -968,7 +964,7 @@ static enum bisect_error bisect_state(struct bisect_terms *terms, const char **a
 	}
 
 	oid_array_clear(&revs);
-	return bisect_auto_next(terms, NULL);
+	return bisect_auto_next(NULL);
 }
 
 static enum bisect_error bisect_log(void)
@@ -988,7 +984,7 @@ static enum bisect_error bisect_log(void)
 	return status ? BISECT_FAILED : BISECT_OK;
 }
 
-static int process_replay_line(struct bisect_terms *terms, struct strbuf *line)
+static int process_replay_line(struct strbuf *line)
 {
 	const char *p = line->buf + strspn(line->buf, " \t");
 	char *word_end, *rev;
@@ -1002,28 +998,28 @@ static int process_replay_line(struct bisect_terms *terms, struct strbuf *line)
 	rev = word_end + strspn(word_end, " \t");
 	*word_end = '\0'; /* NUL-terminate the word */
 
-	get_terms(terms);
-	if (check_and_set_terms(terms, p))
+	get_terms();
+	if (check_and_set_terms(p))
 		return -1;
 
 	if (!strcmp(p, "start")) {
 		struct strvec argv = STRVEC_INIT;
 		int res;
 		sq_dequote_to_strvec(rev, &argv);
-		res = bisect_start(terms, argv.v, argv.nr);
+		res = bisect_start(argv.v, argv.nr);
 		strvec_clear(&argv);
 		return res;
 	}
 
-	if (one_of(p, terms->term_good,
-	   terms->term_bad, "skip", NULL))
-		return bisect_write(p, rev, terms, 0);
+	if (one_of(p, terms.term_good,
+	   terms.term_bad, "skip", NULL))
+		return bisect_write(p, rev, 0);
 
 	if (!strcmp(p, "terms")) {
 		struct strvec argv = STRVEC_INIT;
 		int res;
 		sq_dequote_to_strvec(rev, &argv);
-		res = bisect_terms(terms, argv.nr == 1 ? argv.v[0] : NULL);
+		res = bisect_terms(argv.nr == 1 ? argv.v[0] : NULL);
 		strvec_clear(&argv);
 		return res;
 	}
@@ -1032,7 +1028,7 @@ static int process_replay_line(struct bisect_terms *terms, struct strbuf *line)
 	return -1;
 }
 
-static enum bisect_error bisect_replay(struct bisect_terms *terms, const char *filename)
+static enum bisect_error bisect_replay(const char *filename)
 {
 	FILE *fp = NULL;
 	enum bisect_error res = BISECT_OK;
@@ -1049,7 +1045,7 @@ static enum bisect_error bisect_replay(struct bisect_terms *terms, const char *f
 		return BISECT_FAILED;
 
 	while ((strbuf_getline(&line, fp) != EOF) && !res)
-		res = process_replay_line(terms, &line);
+		res = process_replay_line(&line);
 
 	strbuf_release(&line);
 	fclose(fp);
@@ -1057,10 +1053,10 @@ static enum bisect_error bisect_replay(struct bisect_terms *terms, const char *f
 	if (res)
 		return BISECT_FAILED;
 
-	return bisect_auto_next(terms, NULL);
+	return bisect_auto_next(NULL);
 }
 
-static enum bisect_error bisect_skip(struct bisect_terms *terms, const char **argv, int argc)
+static enum bisect_error bisect_skip(const char **argv, int argc)
 {
 	int i;
 	enum bisect_error res;
@@ -1090,19 +1086,19 @@ static enum bisect_error bisect_skip(struct bisect_terms *terms, const char **ar
 			strvec_push(&argv_state, argv[i]);
 		}
 	}
-	res = bisect_state(terms, argv_state.v, argv_state.nr);
+	res = bisect_state(argv_state.v, argv_state.nr);
 
 	strvec_clear(&argv_state);
 	return res;
 }
 
-static int bisect_visualize(struct bisect_terms *terms, const char **argv, int argc)
+static int bisect_visualize(const char **argv, int argc)
 {
 	struct strvec args = STRVEC_INIT;
 	int flags = RUN_COMMAND_NO_STDIN, res = 0;
 	struct strbuf sb = STRBUF_INIT;
 
-	if (bisect_next_check(terms, NULL) != 0)
+	if (bisect_next_check(NULL) != 0)
 		return BISECT_FAILED;
 
 	if (!argc) {
@@ -1141,14 +1137,13 @@ static int get_first_good(const char *refname, const struct object_id *oid,
 	return 1;
 }
 
-static int verify_good(const struct bisect_terms *terms,
-		       const char **quoted_argv)
+static int verify_good(const char **quoted_argv)
 {
 	int rc;
 	enum bisect_error res;
 	struct object_id good_rev;
 	struct object_id current_rev;
-	char *good_glob = xstrfmt("%s-*", terms->term_good);
+	char *good_glob = xstrfmt("%s-*", terms.term_good);
 	int no_checkout = ref_exists("BISECT_HEAD");
 
 	for_each_glob_ref_in(get_first_good, good_glob, "refs/bisect/",
@@ -1172,7 +1167,7 @@ static int verify_good(const struct bisect_terms *terms,
 	return rc;
 }
 
-static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
+static int bisect_run(const char **argv, int argc)
 {
 	int res = BISECT_OK;
 	struct strbuf command = STRBUF_INIT;
@@ -1181,7 +1176,7 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
 	int temporary_stdout_fd, saved_stdout;
 	int is_first_run = 1;
 
-	if (bisect_next_check(terms, NULL))
+	if (bisect_next_check(NULL))
 		return BISECT_FAILED;
 
 	if (argc)
@@ -1205,7 +1200,7 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
 		 * missing or non-executable script.
 		 */
 		if (is_first_run && (res == 126 || res == 127)) {
-			int rc = verify_good(terms, run_args.v);
+			int rc = verify_good(run_args.v);
 			is_first_run = 0;
 			if (rc < 0) {
 				error(_("unable to verify '%s' on good"
@@ -1230,9 +1225,9 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
 		if (res == 125)
 			new_state = "skip";
 		else if (!res)
-			new_state = terms->term_good;
+			new_state = terms.term_good;
 		else
-			new_state = terms->term_bad;
+			new_state = terms.term_bad;
 
 		temporary_stdout_fd = open(git_path_bisect_run(), O_CREAT | O_WRONLY | O_TRUNC, 0666);
 
@@ -1245,7 +1240,7 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
 		saved_stdout = dup(1);
 		dup2(temporary_stdout_fd, 1);
 
-		res = bisect_state(terms, &new_state, 1);
+		res = bisect_state(&new_state, 1);
 
 		fflush(stdout);
 		dup2(saved_stdout, 1);
@@ -1314,7 +1309,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 			 N_("use <cmd>... to automatically bisect"), BISECT_RUN),
 		OPT_END()
 	};
-	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
 
 	argc = parse_options(argc, argv, prefix, options,
 			     git_bisect_helper_usage,
@@ -1332,22 +1326,22 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 	case BISECT_TERMS:
 		if (argc > 1)
 			return error(_("--bisect-terms requires 0 or 1 argument"));
-		res = bisect_terms(&terms, argc == 1 ? argv[0] : NULL);
+		res = bisect_terms(argc == 1 ? argv[0] : NULL);
 		break;
 	case BISECT_START:
-		set_terms(&terms, "bad", "good");
-		res = bisect_start(&terms, argv, argc);
+		set_terms("bad", "good");
+		res = bisect_start(argv, argc);
 		break;
 	case BISECT_NEXT:
 		if (argc)
 			return error(_("--bisect-next requires 0 arguments"));
-		get_terms(&terms);
-		res = bisect_next(&terms, prefix);
+		get_terms();
+		res = bisect_next(prefix);
 		break;
 	case BISECT_STATE:
-		set_terms(&terms, "bad", "good");
-		get_terms(&terms);
-		res = bisect_state(&terms, argv, argc);
+		set_terms("bad", "good");
+		get_terms();
+		res = bisect_state(argv, argc);
 		break;
 	case BISECT_LOG:
 		if (argc)
@@ -1357,28 +1351,28 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 	case BISECT_REPLAY:
 		if (argc != 1)
 			return error(_("no logfile given"));
-		set_terms(&terms, "bad", "good");
-		res = bisect_replay(&terms, argv[0]);
+		set_terms("bad", "good");
+		res = bisect_replay(argv[0]);
 		break;
 	case BISECT_SKIP:
-		set_terms(&terms, "bad", "good");
-		get_terms(&terms);
-		res = bisect_skip(&terms, argv, argc);
+		set_terms("bad", "good");
+		get_terms();
+		res = bisect_skip(argv, argc);
 		break;
 	case BISECT_VISUALIZE:
-		get_terms(&terms);
-		res = bisect_visualize(&terms, argv, argc);
+		get_terms();
+		res = bisect_visualize(argv, argc);
 		break;
 	case BISECT_RUN:
 		if (!argc)
 			return error(_("bisect run failed: no command provided."));
-		get_terms(&terms);
-		res = bisect_run(&terms, argv, argc);
+		get_terms();
+		res = bisect_run(argv, argc);
 		break;
 	default:
 		BUG("unknown subcommand %d", cmdmode);
 	}
-	free_terms(&terms);
+	free_terms();
 
 	return is_bisect_success(res) ? 0 : -res;
 }
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH v6 06/16] bisect--helper: make the order consistently `argc, argv`
  2022-08-30 18:50         ` [PATCH v6 00/16] Finish converting git bisect into a built-in Johannes Schindelin via GitGitGadget
                             ` (4 preceding siblings ...)
  2022-08-30 18:50           ` [PATCH v6 05/16] bisect--helper: make `terms` an explicit singleton Johannes Schindelin via GitGitGadget
@ 2022-08-30 18:50           ` Johannes Schindelin via GitGitGadget
  2022-08-30 18:50           ` [PATCH v6 07/16] bisect--helper: migrate to OPT_SUBCOMMAND() Johannes Schindelin via GitGitGadget
                             ` (10 subsequent siblings)
  16 siblings, 0 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-08-30 18:50 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Bagas Sanjaya, Junio C Hamano, Johannes Schindelin,
	Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

In C, the natural order is for `argc` to come before `argv` by virtue of
the `main()` function declaring the parameters in precisely that order.

It is confusing & distracting, then, when readers familiar with the C
language read code where that order is switched around.

Let's just change the order and avoid that type of developer friction.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/bisect--helper.c | 29 ++++++++++++++---------------
 1 file changed, 14 insertions(+), 15 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 7f4e8e707c1..0d7cc20f9c9 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -652,7 +652,7 @@ static enum bisect_error bisect_auto_next(const char *prefix)
 	return bisect_next(prefix);
 }
 
-static enum bisect_error bisect_start(const char **argv, int argc)
+static enum bisect_error bisect_start(int argc, const char **argv)
 {
 	int no_checkout = 0;
 	int first_parent_only = 0;
@@ -881,13 +881,12 @@ static int bisect_autostart(void)
 	yesno = git_prompt(_("Do you want me to do it for you "
 			     "[Y/n]? "), PROMPT_ECHO);
 	res = tolower(*yesno) == 'n' ?
-		-1 : bisect_start(empty_strvec, 0);
+		-1 : bisect_start(0, empty_strvec);
 
 	return res;
 }
 
-static enum bisect_error bisect_state(const char **argv,
-				      int argc)
+static enum bisect_error bisect_state(int argc, const char **argv)
 {
 	const char *state;
 	int i, verify_expected = 1;
@@ -1006,7 +1005,7 @@ static int process_replay_line(struct strbuf *line)
 		struct strvec argv = STRVEC_INIT;
 		int res;
 		sq_dequote_to_strvec(rev, &argv);
-		res = bisect_start(argv.v, argv.nr);
+		res = bisect_start(argv.nr, argv.v);
 		strvec_clear(&argv);
 		return res;
 	}
@@ -1056,7 +1055,7 @@ static enum bisect_error bisect_replay(const char *filename)
 	return bisect_auto_next(NULL);
 }
 
-static enum bisect_error bisect_skip(const char **argv, int argc)
+static enum bisect_error bisect_skip(int argc, const char **argv)
 {
 	int i;
 	enum bisect_error res;
@@ -1086,13 +1085,13 @@ static enum bisect_error bisect_skip(const char **argv, int argc)
 			strvec_push(&argv_state, argv[i]);
 		}
 	}
-	res = bisect_state(argv_state.v, argv_state.nr);
+	res = bisect_state(argv_state.nr, argv_state.v);
 
 	strvec_clear(&argv_state);
 	return res;
 }
 
-static int bisect_visualize(const char **argv, int argc)
+static int bisect_visualize(int argc, const char **argv)
 {
 	struct strvec args = STRVEC_INIT;
 	int flags = RUN_COMMAND_NO_STDIN, res = 0;
@@ -1167,7 +1166,7 @@ static int verify_good(const char **quoted_argv)
 	return rc;
 }
 
-static int bisect_run(const char **argv, int argc)
+static int bisect_run(int argc, const char **argv)
 {
 	int res = BISECT_OK;
 	struct strbuf command = STRBUF_INIT;
@@ -1240,7 +1239,7 @@ static int bisect_run(const char **argv, int argc)
 		saved_stdout = dup(1);
 		dup2(temporary_stdout_fd, 1);
 
-		res = bisect_state(&new_state, 1);
+		res = bisect_state(1, &new_state);
 
 		fflush(stdout);
 		dup2(saved_stdout, 1);
@@ -1330,7 +1329,7 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 		break;
 	case BISECT_START:
 		set_terms("bad", "good");
-		res = bisect_start(argv, argc);
+		res = bisect_start(argc, argv);
 		break;
 	case BISECT_NEXT:
 		if (argc)
@@ -1341,7 +1340,7 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 	case BISECT_STATE:
 		set_terms("bad", "good");
 		get_terms();
-		res = bisect_state(argv, argc);
+		res = bisect_state(argc, argv);
 		break;
 	case BISECT_LOG:
 		if (argc)
@@ -1357,17 +1356,17 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 	case BISECT_SKIP:
 		set_terms("bad", "good");
 		get_terms();
-		res = bisect_skip(argv, argc);
+		res = bisect_skip(argc, argv);
 		break;
 	case BISECT_VISUALIZE:
 		get_terms();
-		res = bisect_visualize(argv, argc);
+		res = bisect_visualize(argc, argv);
 		break;
 	case BISECT_RUN:
 		if (!argc)
 			return error(_("bisect run failed: no command provided."));
 		get_terms();
-		res = bisect_run(argv, argc);
+		res = bisect_run(argc, argv);
 		break;
 	default:
 		BUG("unknown subcommand %d", cmdmode);
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH v6 07/16] bisect--helper: migrate to OPT_SUBCOMMAND()
  2022-08-30 18:50         ` [PATCH v6 00/16] Finish converting git bisect into a built-in Johannes Schindelin via GitGitGadget
                             ` (5 preceding siblings ...)
  2022-08-30 18:50           ` [PATCH v6 06/16] bisect--helper: make the order consistently `argc, argv` Johannes Schindelin via GitGitGadget
@ 2022-08-30 18:50           ` Johannes Schindelin via GitGitGadget
  2022-08-30 18:50           ` [PATCH v6 08/16] bisect: verify that a bogus option won't try to start a bisection Johannes Schindelin via GitGitGadget
                             ` (9 subsequent siblings)
  16 siblings, 0 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-08-30 18:50 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Bagas Sanjaya, Junio C Hamano, Johannes Schindelin,
	Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

We just introduced a new way to process subcommands, and the
`bisect--helper` learns about it in preparation for replacing the
`git-bisect.sh` script altogether.

As a consequence, the usage strings are copied over from the scripted
version of the `git bisect` command. To avoid regressing on 959d670d1a4
(i18n: remove from i18n strings that do not hold translatable parts,
2022-01-31), we specifically do not enclose usage strings in `N_(...)`
that do not contain any translatable parts.

Note that a couple of `bisect_*()` functions are not converted into
`cmd_bisect_*()` functions directly, as they have callers other than the
`OPT_SUBCOMMAND()` one (and the original functions did not expect
a subcommand name to be passed as `argv[0]`, unlike the convention for
the `cmd_*()` functions. In those cases, we introduce wrapper functions
`cmd_*()` that also call the original function.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/bisect--helper.c | 462 +++++++++++++++++++++++----------------
 git-bisect.sh            |  20 +-
 2 files changed, 288 insertions(+), 194 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 0d7cc20f9c9..56d900c3d3c 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -20,18 +20,71 @@ static GIT_PATH_FUNC(git_path_bisect_names, "BISECT_NAMES")
 static GIT_PATH_FUNC(git_path_bisect_first_parent, "BISECT_FIRST_PARENT")
 static GIT_PATH_FUNC(git_path_bisect_run, "BISECT_RUN")
 
-static const char * const git_bisect_helper_usage[] = {
-	N_("git bisect--helper --bisect-reset [<commit>]"),
-	"git bisect--helper --bisect-terms [--term-good | --term-old | --term-bad | --term-new]",
-	N_("git bisect--helper --bisect-start [--term-{new,bad}=<term> --term-{old,good}=<term>]"
-					    " [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<paths>...]"),
-	"git bisect--helper --bisect-next",
-	N_("git bisect--helper --bisect-state (bad|new) [<rev>]"),
-	N_("git bisect--helper --bisect-state (good|old) [<rev>...]"),
-	N_("git bisect--helper --bisect-replay <filename>"),
-	N_("git bisect--helper --bisect-skip [(<rev>|<range>)...]"),
-	"git bisect--helper --bisect-visualize",
-	N_("git bisect--helper --bisect-run <cmd>..."),
+static const char * const bisect_usage[] = {
+	N_("git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>]"
+	   "    [--no-checkout] [--first-parent] [<bad> [<good>...]] [--]"
+	   "    [<pathspec>...]"),
+	N_("git bisect (bad|new) [<rev>]"),
+	N_("git bisect (good|old) [<rev>...]"),
+	"git bisect terms [--term-good | --term-bad]",
+	N_("git bisect skip [(<rev>|<range>)...]"),
+	"git bisect next",
+	N_("git bisect reset [<commit>]"),
+	"git bisect (visualize|view)",
+	N_("git bisect replay <logfile>"),
+	"git bisect log",
+	N_("git bisect run <cmd>..."),
+	NULL
+};
+
+static const char * const bisect_start_usage[] = {
+	N_("git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>]"
+	   "    [--no-checkout] [--first-parent] [<bad> [<good>...]] [--]"
+	   "    [<pathspec>...]"),
+	NULL
+};
+static const char * const bisect_state_usage[] = {
+	N_("git bisect (good|bad) [<rev>...]"),
+	NULL
+};
+
+static const char * const bisect_terms_usage[] = {
+	"git bisect terms [--term-good | --term-bad]",
+	NULL
+};
+
+static const char * const bisect_skip_usage[] = {
+	N_("git bisect skip [(<rev>|<range>)...]"),
+	NULL
+};
+
+static const char * const bisect_next_usage[] = {
+	"git bisect next",
+	NULL
+};
+
+static const char * const bisect_reset_usage[] = {
+	N_("git bisect reset [<commit>]"),
+	NULL
+};
+
+static const char * const bisect_visualize_usage[] = {
+	"git bisect visualize",
+	NULL
+};
+
+static const char * const bisect_replay_usage[] = {
+	N_("git bisect replay <logfile>"),
+	NULL
+};
+
+static const char * const bisect_log_usage[] = {
+	"git bisect log",
+	NULL
+};
+
+static const char * const bisect_run_usage[] = {
+	N_("git bisect run <cmd>..."),
 	NULL
 };
 
@@ -63,7 +116,7 @@ static void set_terms(const char *bad,
 static const char vocab_bad[] = "bad|new";
 static const char vocab_good[] = "good|old";
 
-static int bisect_autostart(void);
+static int bisect_autostart(const char *prefix);
 
 /*
  * Check whether the string `term` belongs to the set of strings
@@ -238,6 +291,21 @@ static int bisect_reset(const char *commit)
 	return bisect_clean_state();
 }
 
+static int cmd_bisect_reset(int argc, const char **argv, const char *prefix)
+{
+	struct option options[] = {
+		OPT_END()
+	};
+	argc = parse_options(argc, argv, prefix, options,
+			     bisect_reset_usage, PARSE_OPT_STOP_AT_NON_OPTION);
+
+	if (argc > 1)
+		usage_msg_opt(_("requires either no argument or a commit"),
+			      bisect_reset_usage, options);
+
+	return bisect_reset(argc == 1 ? argv[0] : NULL);
+}
+
 static void log_commit(FILE *fp, char *fmt, const char *state,
 		       struct commit *commit)
 {
@@ -465,26 +533,41 @@ finish:
 	return res;
 }
 
-static int bisect_terms(const char *option)
+static int cmd_bisect_terms(int argc, const char **argv, const char *prefix)
 {
+	int mode = -1;
+	struct option options[] = {
+		OPT_SET_INT(0, "term-good", &mode,
+			    N_("show term for good/old"), 1),
+		OPT_SET_INT(0, "term-old", &mode,
+			    N_("show term for good/old"), 1),
+		OPT_SET_INT(0, "term-bad", &mode,
+			    N_("show term for bad/new"), 0),
+		OPT_SET_INT(0, "term-new", &mode,
+			    N_("show term for bad/new"), 0),
+		OPT_END()
+	};
+
+	argc = parse_options(argc, argv, prefix, options,
+			     bisect_terms_usage, PARSE_OPT_STOP_AT_NON_OPTION);
+
+	if (argc > 1)
+		usage_msg_opt(_("terms: requires 0 or 1 argument"),
+			      bisect_terms_usage, options);
+
 	if (get_terms())
 		return error(_("no terms defined"));
 
-	if (!option) {
+	if (mode < 0) {
 		printf(_("Your current terms are %s for the old state\n"
 			 "and %s for the new state.\n"),
 		       terms.term_good, terms.term_bad);
 		return 0;
 	}
-	if (one_of(option, "--term-good", "--term-old", NULL))
+	if (mode == 1)
 		printf("%s\n", terms.term_good);
-	else if (one_of(option, "--term-bad", "--term-new", NULL))
-		printf("%s\n", terms.term_bad);
 	else
-		return error(_("invalid argument %s for 'git bisect terms'.\n"
-			       "Supported options are: "
-			       "--term-good|--term-old and "
-			       "--term-bad|--term-new."), option);
+		printf("%s\n", terms.term_bad);
 
 	return 0;
 }
@@ -623,7 +706,7 @@ static enum bisect_error bisect_next(const char *prefix)
 {
 	enum bisect_error res;
 
-	if (bisect_autostart())
+	if (bisect_autostart(prefix))
 		return BISECT_FAILED;
 
 	if (bisect_next_check(terms.term_good))
@@ -642,6 +725,24 @@ static enum bisect_error bisect_next(const char *prefix)
 	return res;
 }
 
+static int cmd_bisect_next(int argc, const char **argv, const char *prefix)
+{
+	struct option options[] = {
+		OPT_END()
+	};
+
+	get_terms();
+	argc = parse_options(argc, argv, prefix, options,
+				bisect_next_usage,
+				PARSE_OPT_STOP_AT_NON_OPTION);
+
+	if (argc > 0)
+		usage_msg_opt(_("requires 0 argument"),
+			      bisect_next_usage, options);
+
+	return bisect_next(prefix);
+}
+
 static enum bisect_error bisect_auto_next(const char *prefix)
 {
 	if (bisect_next_check(NULL)) {
@@ -652,8 +753,9 @@ static enum bisect_error bisect_auto_next(const char *prefix)
 	return bisect_next(prefix);
 }
 
-static enum bisect_error bisect_start(int argc, const char **argv)
+static int cmd_bisect_start(int argc, const char **argv, const char *prefix)
 {
+	struct strvec orig_argv = STRVEC_INIT;
 	int no_checkout = 0;
 	int first_parent_only = 0;
 	int i, has_double_dash = 0, must_write_terms = 0, bad_seen = 0;
@@ -665,66 +767,64 @@ static enum bisect_error bisect_start(int argc, const char **argv)
 	struct strbuf bisect_names = STRBUF_INIT;
 	struct object_id head_oid;
 	struct object_id oid;
-	const char *head;
+	const char *head, *term_good = NULL, *term_bad = NULL;
+	struct option options[] = {
+		OPT_BOOL(0, "no-checkout", &no_checkout,
+			 N_("do not update worktree")),
+		OPT_BOOL(0, "first-parent", &first_parent_only,
+			 N_("follow only first parent of merge commits")),
+		OPT_STRING(0, "term-good", &term_good, N_("term"),
+			   N_("use this term instead of 'good'")),
+		OPT_STRING(0, "term-bad", &term_bad, N_("term"),
+			   N_("use this term instead of 'bad'")),
+		OPT_STRING(0, "term-old", &term_good, N_("term"),
+			   N_("use this term instead of 'good'")),
+		OPT_STRING(0, "term-new", &term_bad, N_("term"),
+			   N_("use this term instead of 'bad'")),
+		OPT_END()
+	};
+
+	set_terms("bad", "good");
 
 	if (is_bare_repository())
 		no_checkout = 1;
 
-	/*
-	 * Check for one bad and then some good revisions
-	 */
-	for (i = 0; i < argc; i++) {
+	strvec_pushv(&orig_argv, argv); /* save the command-line for logging */
+	argc = parse_options(argc, argv, prefix, options, bisect_start_usage,
+			     PARSE_OPT_KEEP_DASHDASH);
+
+	if (term_good) {
+		free(terms.term_good);
+		terms.term_good = xstrdup(term_good);
+		must_write_terms = 1;
+	}
+
+	if (term_bad) {
+		free(terms.term_bad);
+		terms.term_bad = xstrdup(term_bad);
+		must_write_terms = 1;
+	}
+
+	for (i = 0; i < argc; i++)
 		if (!strcmp(argv[i], "--")) {
 			has_double_dash = 1;
 			break;
 		}
-	}
 
-	for (i = 0; i < argc; i++) {
-		const char *arg = argv[i];
-		if (!strcmp(argv[i], "--")) {
-			break;
-		} else if (!strcmp(arg, "--no-checkout")) {
-			no_checkout = 1;
-		} else if (!strcmp(arg, "--first-parent")) {
-			first_parent_only = 1;
-		} else if (!strcmp(arg, "--term-good") ||
-			 !strcmp(arg, "--term-old")) {
-			i++;
-			if (argc <= i)
-				return error(_("'' is not a valid term"));
-			must_write_terms = 1;
-			free((void *) terms.term_good);
-			terms.term_good = xstrdup(argv[i]);
-		} else if (skip_prefix(arg, "--term-good=", &arg) ||
-			   skip_prefix(arg, "--term-old=", &arg)) {
-			must_write_terms = 1;
-			free((void *) terms.term_good);
-			terms.term_good = xstrdup(arg);
-		} else if (!strcmp(arg, "--term-bad") ||
-			 !strcmp(arg, "--term-new")) {
-			i++;
-			if (argc <= i)
-				return error(_("'' is not a valid term"));
-			must_write_terms = 1;
-			free((void *) terms.term_bad);
-			terms.term_bad = xstrdup(argv[i]);
-		} else if (skip_prefix(arg, "--term-bad=", &arg) ||
-			   skip_prefix(arg, "--term-new=", &arg)) {
-			must_write_terms = 1;
-			free((void *) terms.term_bad);
-			terms.term_bad = xstrdup(arg);
-		} else if (starts_with(arg, "--")) {
-			return error(_("unrecognized option: '%s'"), arg);
-		} else if (!get_oidf(&oid, "%s^{commit}", arg)) {
+	/*
+	 * Check for one bad and then some good revisions
+	 */
+
+	for (i = 0; i < argc && strcmp(argv[i], "--"); i++)
+		if (!get_oidf(&oid, "%s^{commit}", argv[i])) {
 			string_list_append(&revs, oid_to_hex(&oid));
 		} else if (has_double_dash) {
 			die(_("'%s' does not appear to be a valid "
-			      "revision"), arg);
+			      "revision"), argv[i]);
 		} else {
 			break;
 		}
-	}
+
 	pathspec_pos = i;
 
 	/*
@@ -836,11 +936,13 @@ static enum bisect_error bisect_start(int argc, const char **argv)
 		goto finish;
 	}
 
-	res = bisect_append_log_quoted(argv);
+	res = bisect_append_log_quoted(orig_argv.v + 1);
 	if (res)
 		res = BISECT_FAILED;
 
 finish:
+	strvec_clear(&orig_argv);
+
 	string_list_clear(&revs, 0);
 	string_list_clear(&states, 0);
 	strbuf_release(&start_head);
@@ -848,7 +950,7 @@ finish:
 	if (res)
 		return res;
 
-	res = bisect_auto_next(NULL);
+	res = bisect_auto_next(prefix);
 	if (!is_bisect_success(res))
 		bisect_clean_state();
 	return res;
@@ -859,7 +961,7 @@ static inline int file_is_not_empty(const char *path)
 	return !is_empty_or_missing_file(path);
 }
 
-static int bisect_autostart(void)
+static int bisect_autostart(const char *prefix)
 {
 	int res;
 	const char *yesno;
@@ -881,12 +983,13 @@ static int bisect_autostart(void)
 	yesno = git_prompt(_("Do you want me to do it for you "
 			     "[Y/n]? "), PROMPT_ECHO);
 	res = tolower(*yesno) == 'n' ?
-		-1 : bisect_start(0, empty_strvec);
+		-1 : cmd_bisect_start(1, &yesno, prefix);
 
 	return res;
 }
 
-static enum bisect_error bisect_state(int argc, const char **argv)
+static enum bisect_error bisect_state(int argc, const char **argv,
+				      const char *prefix)
 {
 	const char *state;
 	int i, verify_expected = 1;
@@ -894,10 +997,8 @@ static enum bisect_error bisect_state(int argc, const char **argv)
 	struct strbuf buf = STRBUF_INIT;
 	struct oid_array revs = OID_ARRAY_INIT;
 
-	if (!argc)
-		return error(_("Please call `--bisect-state` with at least one argument"));
 
-	if (bisect_autostart())
+	if (bisect_autostart(prefix))
 		return BISECT_FAILED;
 
 	state = argv[0];
@@ -966,11 +1067,41 @@ static enum bisect_error bisect_state(int argc, const char **argv)
 	return bisect_auto_next(NULL);
 }
 
-static enum bisect_error bisect_log(void)
+static int cmd_bisect_state(int argc, const char **argv,
+				const char *prefix)
 {
+	struct option options[] = {
+		OPT_END()
+	};
+
+	set_terms("bad", "good");
+	get_terms();
+
+	argc = parse_options(argc, argv, prefix, options,
+			     bisect_state_usage, PARSE_OPT_STOP_AT_NON_OPTION);
+
+	if (!argc)
+		usage_msg_opt(_("need at least one argument"),
+			      bisect_state_usage, options);
+
+	return bisect_state(argc, argv, prefix);
+}
+
+static int cmd_bisect_log(int argc, const char **argv, const char *prefix)
+{
+	struct option options[] = {
+		OPT_END()
+	};
 	int fd, status;
 	const char* filename = git_path_bisect_log();
 
+	argc = parse_options(argc, argv, prefix, options,
+			     bisect_log_usage, PARSE_OPT_STOP_AT_NON_OPTION);
+
+	if (argc > 0)
+		usage_msg_opt(_("require 0 argument"), bisect_log_usage,
+			      options);
+
 	if (is_empty_or_missing_file(filename))
 		return error(_("We are not bisecting."));
 
@@ -983,7 +1114,7 @@ static enum bisect_error bisect_log(void)
 	return status ? BISECT_FAILED : BISECT_OK;
 }
 
-static int process_replay_line(struct strbuf *line)
+static int process_replay_line(struct strbuf *line, const char *prefix)
 {
 	const char *p = line->buf + strspn(line->buf, " \t");
 	char *word_end, *rev;
@@ -1004,8 +1135,10 @@ static int process_replay_line(struct strbuf *line)
 	if (!strcmp(p, "start")) {
 		struct strvec argv = STRVEC_INIT;
 		int res;
+
+		strvec_push(&argv, p);
 		sq_dequote_to_strvec(rev, &argv);
-		res = bisect_start(argv.nr, argv.v);
+		res = cmd_bisect_start(argv.nr, argv.v, prefix);
 		strvec_clear(&argv);
 		return res;
 	}
@@ -1017,8 +1150,11 @@ static int process_replay_line(struct strbuf *line)
 	if (!strcmp(p, "terms")) {
 		struct strvec argv = STRVEC_INIT;
 		int res;
+
+		strvec_push(&argv, p);
 		sq_dequote_to_strvec(rev, &argv);
-		res = bisect_terms(argv.nr == 1 ? argv.v[0] : NULL);
+		res = cmd_bisect_terms(argv.nr, argv.v, NULL);
+
 		strvec_clear(&argv);
 		return res;
 	}
@@ -1027,12 +1163,25 @@ static int process_replay_line(struct strbuf *line)
 	return -1;
 }
 
-static enum bisect_error bisect_replay(const char *filename)
+static int cmd_bisect_replay(int argc, const char **argv, const char *prefix)
 {
+	struct option options[] = {
+		OPT_END()
+	};
+	const char *filename;
 	FILE *fp = NULL;
 	enum bisect_error res = BISECT_OK;
 	struct strbuf line = STRBUF_INIT;
 
+	set_terms("bad", "good");
+	argc = parse_options(argc, argv, prefix, options,
+			     bisect_reset_usage, PARSE_OPT_STOP_AT_NON_OPTION);
+
+	if (argc != 1)
+		usage_msg_opt(_("no logfile given"), bisect_replay_usage,
+			      options);
+
+	filename = argv[0];
 	if (is_empty_or_missing_file(filename))
 		return error(_("cannot read file '%s' for replaying"), filename);
 
@@ -1044,7 +1193,7 @@ static enum bisect_error bisect_replay(const char *filename)
 		return BISECT_FAILED;
 
 	while ((strbuf_getline(&line, fp) != EOF) && !res)
-		res = process_replay_line(&line);
+		res = process_replay_line(&line, prefix);
 
 	strbuf_release(&line);
 	fclose(fp);
@@ -1055,12 +1204,20 @@ static enum bisect_error bisect_replay(const char *filename)
 	return bisect_auto_next(NULL);
 }
 
-static enum bisect_error bisect_skip(int argc, const char **argv)
+static int cmd_bisect_skip(int argc, const char **argv, const char *prefix)
 {
+	struct option options[] = {
+		OPT_END()
+	};
 	int i;
 	enum bisect_error res;
 	struct strvec argv_state = STRVEC_INIT;
 
+	set_terms("bad", "good");
+	get_terms();
+	argc = parse_options(argc, argv, prefix, options,
+			     bisect_skip_usage, PARSE_OPT_STOP_AT_NON_OPTION);
+
 	strvec_push(&argv_state, "skip");
 
 	for (i = 0; i < argc; i++) {
@@ -1085,18 +1242,28 @@ static enum bisect_error bisect_skip(int argc, const char **argv)
 			strvec_push(&argv_state, argv[i]);
 		}
 	}
-	res = bisect_state(argv_state.nr, argv_state.v);
+	res = bisect_state(argv_state.nr, argv_state.v, prefix);
 
 	strvec_clear(&argv_state);
 	return res;
 }
 
-static int bisect_visualize(int argc, const char **argv)
+static int cmd_bisect_visualize(int argc, const char **argv, const char *prefix)
 {
+	struct option options[] = {
+		OPT_END()
+	};
 	struct strvec args = STRVEC_INIT;
 	int flags = RUN_COMMAND_NO_STDIN, res = 0;
 	struct strbuf sb = STRBUF_INIT;
 
+	set_terms("bad", "good");
+	get_terms();
+	argc = parse_options(argc, argv, prefix, options,
+			     bisect_visualize_usage,
+			     PARSE_OPT_KEEP_DASHDASH |
+			     PARSE_OPT_KEEP_UNKNOWN_OPT);
+
 	if (bisect_next_check(NULL) != 0)
 		return BISECT_FAILED;
 
@@ -1166,8 +1333,11 @@ static int verify_good(const char **quoted_argv)
 	return rc;
 }
 
-static int bisect_run(int argc, const char **argv)
+static int cmd_bisect_run(int argc, const char **argv, const char *prefix)
 {
+	struct option options[] = {
+		OPT_END()
+	};
 	int res = BISECT_OK;
 	struct strbuf command = STRBUF_INIT;
 	struct strvec run_args = STRVEC_INIT;
@@ -1175,15 +1345,18 @@ static int bisect_run(int argc, const char **argv)
 	int temporary_stdout_fd, saved_stdout;
 	int is_first_run = 1;
 
+	get_terms();
+	argc = parse_options(argc, argv, prefix, options,
+			     bisect_run_usage, PARSE_OPT_STOP_AT_NON_OPTION);
+
 	if (bisect_next_check(NULL))
 		return BISECT_FAILED;
 
 	if (argc)
 		sq_quote_argv(&command, argv);
-	else {
-		error(_("bisect run failed: no command provided."));
-		return BISECT_FAILED;
-	}
+	else
+		usage_msg_opt(_("bisect run failed: no command provided."),
+			      bisect_run_usage, options);
 
 	strvec_push(&run_args, command.buf);
 
@@ -1239,7 +1412,7 @@ static int bisect_run(int argc, const char **argv)
 		saved_stdout = dup(1);
 		dup2(temporary_stdout_fd, 1);
 
-		res = bisect_state(1, &new_state);
+		res = bisect_state(1, &new_state, prefix);
 
 		fflush(stdout);
 		dup2(saved_stdout, 1);
@@ -1272,105 +1445,26 @@ static int bisect_run(int argc, const char **argv)
 
 int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 {
-	enum {
-		BISECT_RESET = 1,
-		BISECT_TERMS,
-		BISECT_START,
-		BISECT_NEXT,
-		BISECT_STATE,
-		BISECT_LOG,
-		BISECT_REPLAY,
-		BISECT_SKIP,
-		BISECT_VISUALIZE,
-		BISECT_RUN,
-	} cmdmode = 0;
+	parse_opt_subcommand_fn *fn = NULL;
 	int res = 0;
 	struct option options[] = {
-		OPT_CMDMODE(0, "bisect-reset", &cmdmode,
-			 N_("reset the bisection state"), BISECT_RESET),
-		OPT_CMDMODE(0, "bisect-terms", &cmdmode,
-			 N_("print out the bisect terms"), BISECT_TERMS),
-		OPT_CMDMODE(0, "bisect-start", &cmdmode,
-			 N_("start the bisect session"), BISECT_START),
-		OPT_CMDMODE(0, "bisect-next", &cmdmode,
-			 N_("find the next bisection commit"), BISECT_NEXT),
-		OPT_CMDMODE(0, "bisect-state", &cmdmode,
-			 N_("mark the state of ref (or refs)"), BISECT_STATE),
-		OPT_CMDMODE(0, "bisect-log", &cmdmode,
-			 N_("list the bisection steps so far"), BISECT_LOG),
-		OPT_CMDMODE(0, "bisect-replay", &cmdmode,
-			 N_("replay the bisection process from the given file"), BISECT_REPLAY),
-		OPT_CMDMODE(0, "bisect-skip", &cmdmode,
-			 N_("skip some commits for checkout"), BISECT_SKIP),
-		OPT_CMDMODE(0, "bisect-visualize", &cmdmode,
-			 N_("visualize the bisection"), BISECT_VISUALIZE),
-		OPT_CMDMODE(0, "bisect-run", &cmdmode,
-			 N_("use <cmd>... to automatically bisect"), BISECT_RUN),
+		OPT_SUBCOMMAND("reset", &fn, cmd_bisect_reset),
+		OPT_SUBCOMMAND("terms", &fn, cmd_bisect_terms),
+		OPT_SUBCOMMAND("start", &fn, cmd_bisect_start),
+		OPT_SUBCOMMAND("next", &fn, cmd_bisect_next),
+		OPT_SUBCOMMAND("state", &fn, cmd_bisect_state),
+		OPT_SUBCOMMAND("log", &fn, cmd_bisect_log),
+		OPT_SUBCOMMAND("replay", &fn, cmd_bisect_replay),
+		OPT_SUBCOMMAND("skip", &fn, cmd_bisect_skip),
+		OPT_SUBCOMMAND("visualize", &fn, cmd_bisect_visualize),
+		OPT_SUBCOMMAND("run", &fn, cmd_bisect_run),
 		OPT_END()
 	};
 
 	argc = parse_options(argc, argv, prefix, options,
-			     git_bisect_helper_usage,
-			     PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN_OPT);
-
-	if (!cmdmode)
-		usage_with_options(git_bisect_helper_usage, options);
+			     bisect_usage, 0);
 
-	switch (cmdmode) {
-	case BISECT_RESET:
-		if (argc > 1)
-			return error(_("--bisect-reset requires either no argument or a commit"));
-		res = bisect_reset(argc ? argv[0] : NULL);
-		break;
-	case BISECT_TERMS:
-		if (argc > 1)
-			return error(_("--bisect-terms requires 0 or 1 argument"));
-		res = bisect_terms(argc == 1 ? argv[0] : NULL);
-		break;
-	case BISECT_START:
-		set_terms("bad", "good");
-		res = bisect_start(argc, argv);
-		break;
-	case BISECT_NEXT:
-		if (argc)
-			return error(_("--bisect-next requires 0 arguments"));
-		get_terms();
-		res = bisect_next(prefix);
-		break;
-	case BISECT_STATE:
-		set_terms("bad", "good");
-		get_terms();
-		res = bisect_state(argc, argv);
-		break;
-	case BISECT_LOG:
-		if (argc)
-			return error(_("--bisect-log requires 0 arguments"));
-		res = bisect_log();
-		break;
-	case BISECT_REPLAY:
-		if (argc != 1)
-			return error(_("no logfile given"));
-		set_terms("bad", "good");
-		res = bisect_replay(argv[0]);
-		break;
-	case BISECT_SKIP:
-		set_terms("bad", "good");
-		get_terms();
-		res = bisect_skip(argc, argv);
-		break;
-	case BISECT_VISUALIZE:
-		get_terms();
-		res = bisect_visualize(argc, argv);
-		break;
-	case BISECT_RUN:
-		if (!argc)
-			return error(_("bisect run failed: no command provided."));
-		get_terms();
-		res = bisect_run(argc, argv);
-		break;
-	default:
-		BUG("unknown subcommand %d", cmdmode);
-	}
+	res = fn(argc, argv, prefix);
 	free_terms();
 
 	return is_bisect_success(res) ? 0 : -res;
diff --git a/git-bisect.sh b/git-bisect.sh
index 405cf76f2a3..e19847eba0d 100755
--- a/git-bisect.sh
+++ b/git-bisect.sh
@@ -58,26 +58,26 @@ case "$#" in
 	help)
 		git bisect -h ;;
 	start)
-		git bisect--helper --bisect-start "$@" ;;
+		git bisect--helper start "$@" ;;
 	bad|good|new|old|"$TERM_BAD"|"$TERM_GOOD")
-		git bisect--helper --bisect-state "$cmd" "$@" ;;
+		git bisect--helper state "$cmd" "$@" ;;
 	skip)
-		git bisect--helper --bisect-skip "$@" || exit;;
+		git bisect--helper skip "$@" || exit;;
 	next)
 		# Not sure we want "next" at the UI level anymore.
-		git bisect--helper --bisect-next "$@" || exit ;;
+		git bisect--helper next "$@" || exit ;;
 	visualize|view)
-		git bisect--helper --bisect-visualize "$@" || exit;;
+		git bisect--helper visualize "$@" || exit;;
 	reset)
-		git bisect--helper --bisect-reset "$@" ;;
+		git bisect--helper reset "$@" ;;
 	replay)
-		git bisect--helper --bisect-replay "$@" || exit;;
+		git bisect--helper replay "$@" || exit;;
 	log)
-		git bisect--helper --bisect-log || exit ;;
+		git bisect--helper log || exit ;;
 	run)
-		git bisect--helper --bisect-run "$@" || exit;;
+		git bisect--helper run "$@" || exit;;
 	terms)
-		git bisect--helper --bisect-terms "$@" || exit;;
+		git bisect--helper terms "$@" || exit;;
 	*)
 		usage ;;
 	esac
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH v6 08/16] bisect: verify that a bogus option won't try to start a bisection
  2022-08-30 18:50         ` [PATCH v6 00/16] Finish converting git bisect into a built-in Johannes Schindelin via GitGitGadget
                             ` (6 preceding siblings ...)
  2022-08-30 18:50           ` [PATCH v6 07/16] bisect--helper: migrate to OPT_SUBCOMMAND() Johannes Schindelin via GitGitGadget
@ 2022-08-30 18:50           ` Johannes Schindelin via GitGitGadget
  2022-08-30 18:50           ` [PATCH v6 09/16] bisect run: fix the error message Johannes Schindelin via GitGitGadget
                             ` (8 subsequent siblings)
  16 siblings, 0 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-08-30 18:50 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Bagas Sanjaya, Junio C Hamano, Johannes Schindelin,
	Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

We do not want `git bisect --bogus-option` to start a bisection. To
verify that, we look for the tell-tale error message `You need to start
by "git bisect start"` and fail if it was found.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 t/t6030-bisect-porcelain.sh | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh
index 83931d482fb..6d6e72276ae 100755
--- a/t/t6030-bisect-porcelain.sh
+++ b/t/t6030-bisect-porcelain.sh
@@ -900,6 +900,16 @@ test_expect_success 'bisect start with one term1 and term2' '
 	git bisect reset
 '
 
+test_expect_success 'bogus command does not start bisect' '
+	git bisect reset &&
+	test_must_fail git bisect --bisect-terms 1 2 2>out &&
+	! grep "You need to start" out &&
+	test_must_fail git bisect --bisect-terms 2>out &&
+	! grep "You need to start" out &&
+	grep "git bisect.*visualize" out &&
+	git bisect reset
+'
+
 test_expect_success 'bisect replay with term1 and term2' '
 	git bisect replay log_to_replay.txt >bisect_result &&
 	grep "$HASH2 is the first term1 commit" bisect_result &&
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH v6 09/16] bisect run: fix the error message
  2022-08-30 18:50         ` [PATCH v6 00/16] Finish converting git bisect into a built-in Johannes Schindelin via GitGitGadget
                             ` (7 preceding siblings ...)
  2022-08-30 18:50           ` [PATCH v6 08/16] bisect: verify that a bogus option won't try to start a bisection Johannes Schindelin via GitGitGadget
@ 2022-08-30 18:50           ` Johannes Schindelin via GitGitGadget
  2022-08-30 18:50           ` [PATCH v6 10/16] bisect: avoid double-quoting when printing the failed command Johannes Schindelin via GitGitGadget
                             ` (7 subsequent siblings)
  16 siblings, 0 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-08-30 18:50 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Bagas Sanjaya, Junio C Hamano, Johannes Schindelin,
	Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

In d1bbbe45df8 (bisect--helper: reimplement `bisect_run` shell function
in C, 2021-09-13), we ported the `bisect run` subcommand to C, including
the part that prints out an error message when the implicit `git bisect
bad` or `git bisect good` failed.

However, the error message was supposed to print out whether the state
was "good" or "bad", but used a bogus (because non-populated) `args`
variable for it. This was fixed in 80c2e9657f2 (bisect--helper: report
actual bisect_state() argument on error, 2022-01-18), but the error
message still talks about `bisect--helper`, which is an implementation
detail that should not concern end users.

Fix that, and add a regression test to ensure that the intended form of
the error message.

Helped-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/bisect--helper.c    |  2 +-
 t/t6030-bisect-porcelain.sh | 10 ++++++++++
 2 files changed, 11 insertions(+), 1 deletion(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 56d900c3d3c..ba4aa8059cb 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1430,7 +1430,7 @@ static int cmd_bisect_run(int argc, const char **argv, const char *prefix)
 			printf(_("bisect found first bad commit"));
 			res = BISECT_OK;
 		} else if (res) {
-			error(_("bisect run failed: 'git bisect--helper --bisect-state"
+			error(_("bisect run failed: 'git bisect"
 			" %s' exited with error code %d"), new_state, res);
 		} else {
 			continue;
diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh
index 6d6e72276ae..7a76f204083 100755
--- a/t/t6030-bisect-porcelain.sh
+++ b/t/t6030-bisect-porcelain.sh
@@ -1063,4 +1063,14 @@ test_expect_success 'bisect state output with bad commit' '
 	grep -F "waiting for good commit(s), bad commit known" output
 '
 
+test_expect_success 'verify correct error message' '
+	git bisect reset &&
+	git bisect start $HASH4 $HASH1 &&
+	write_script test_script.sh <<-\EOF &&
+	rm .git/BISECT*
+	EOF
+	test_must_fail git bisect run ./test_script.sh 2>error &&
+	grep "git bisect good.*exited with error code" error
+'
+
 test_done
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH v6 10/16] bisect: avoid double-quoting when printing the failed command
  2022-08-30 18:50         ` [PATCH v6 00/16] Finish converting git bisect into a built-in Johannes Schindelin via GitGitGadget
                             ` (8 preceding siblings ...)
  2022-08-30 18:50           ` [PATCH v6 09/16] bisect run: fix the error message Johannes Schindelin via GitGitGadget
@ 2022-08-30 18:50           ` Johannes Schindelin via GitGitGadget
  2022-08-30 18:50           ` [PATCH v6 11/16] bisect--helper: calling `bisect_state()` without an argument is a bug Johannes Schindelin via GitGitGadget
                             ` (6 subsequent siblings)
  16 siblings, 0 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-08-30 18:50 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Bagas Sanjaya, Junio C Hamano, Johannes Schindelin,
	Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

We already quote the command via `sq_quote_argv()`, no need to enclose
the result in an extraneous pair of single-quotes.

Pointed out by Elijah Newren.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/bisect--helper.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index ba4aa8059cb..05fe619c47c 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1390,7 +1390,7 @@ static int cmd_bisect_run(int argc, const char **argv, const char *prefix)
 
 		if (res < 0 || 128 <= res) {
 			error(_("bisect run failed: exit code %d from"
-				" '%s' is < 0 or >= 128"), res, command.buf);
+				" %s is < 0 or >= 128"), res, command.buf);
 			break;
 		}
 
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH v6 11/16] bisect--helper: calling `bisect_state()` without an argument is a bug
  2022-08-30 18:50         ` [PATCH v6 00/16] Finish converting git bisect into a built-in Johannes Schindelin via GitGitGadget
                             ` (9 preceding siblings ...)
  2022-08-30 18:50           ` [PATCH v6 10/16] bisect: avoid double-quoting when printing the failed command Johannes Schindelin via GitGitGadget
@ 2022-08-30 18:50           ` Johannes Schindelin via GitGitGadget
  2022-08-30 18:50           ` [PATCH v6 12/16] bisect--helper: make `state` optional Johannes Schindelin via GitGitGadget
                             ` (5 subsequent siblings)
  16 siblings, 0 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-08-30 18:50 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Bagas Sanjaya, Junio C Hamano, Johannes Schindelin,
	Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

The `bisect_state()` function is now a purely internal function and must
be called with a valid state, everything else is a bug.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/bisect--helper.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 05fe619c47c..ac3b2e5b61c 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -997,6 +997,8 @@ static enum bisect_error bisect_state(int argc, const char **argv,
 	struct strbuf buf = STRBUF_INIT;
 	struct oid_array revs = OID_ARRAY_INIT;
 
+	if (!argc)
+		BUG("bisect_state() called without argument");
 
 	if (bisect_autostart(prefix))
 		return BISECT_FAILED;
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH v6 12/16] bisect--helper: make `state` optional
  2022-08-30 18:50         ` [PATCH v6 00/16] Finish converting git bisect into a built-in Johannes Schindelin via GitGitGadget
                             ` (10 preceding siblings ...)
  2022-08-30 18:50           ` [PATCH v6 11/16] bisect--helper: calling `bisect_state()` without an argument is a bug Johannes Schindelin via GitGitGadget
@ 2022-08-30 18:50           ` Johannes Schindelin via GitGitGadget
  2022-08-30 18:50           ` [PATCH v6 13/16] bisect: move even the command-line parsing to `bisect--helper` Johannes Schindelin via GitGitGadget
                             ` (4 subsequent siblings)
  16 siblings, 0 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-08-30 18:50 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Bagas Sanjaya, Junio C Hamano, Johannes Schindelin,
	Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

In preparation for making `git bisect` a real built-in, let's prepare
the `bisect--helper` built-in to handle `git bisect--helper good` and
`git bisect--helper bad`, i.e. do not require the `state` subcommand to
be passed explicitly.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/bisect--helper.c | 22 +++++++++++++++++++++-
 git-bisect.sh            |  2 +-
 2 files changed, 22 insertions(+), 2 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index ac3b2e5b61c..61e819e4efc 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1447,6 +1447,7 @@ static int cmd_bisect_run(int argc, const char **argv, const char *prefix)
 
 int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 {
+	struct strvec args = STRVEC_INIT;
 	parse_opt_subcommand_fn *fn = NULL;
 	int res = 0;
 	struct option options[] = {
@@ -1464,10 +1465,29 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 	};
 
 	argc = parse_options(argc, argv, prefix, options,
-			     bisect_usage, 0);
+			     bisect_usage, PARSE_OPT_SUBCOMMAND_OPTIONAL);
+
+	if (!fn) {
+		if (!argc)
+			usage_msg_opt(_("need a command"), bisect_usage,
+				      options);
+
+		set_terms("bad", "good");
+		get_terms();
+		if (check_and_set_terms(argv[0]))
+			usage_msg_optf(_("unknown command: '%s'"), bisect_usage,
+				       options, argv[0]);
+
+		strvec_push(&args, "state");
+		strvec_pushv(&args, argv);
+		argc = args.nr;
+		argv = args.v;
+		fn = cmd_bisect_state;
+	}
 
 	res = fn(argc, argv, prefix);
 	free_terms();
+	strvec_clear(&args);
 
 	return is_bisect_success(res) ? 0 : -res;
 }
diff --git a/git-bisect.sh b/git-bisect.sh
index e19847eba0d..f4df8709d84 100755
--- a/git-bisect.sh
+++ b/git-bisect.sh
@@ -60,7 +60,7 @@ case "$#" in
 	start)
 		git bisect--helper start "$@" ;;
 	bad|good|new|old|"$TERM_BAD"|"$TERM_GOOD")
-		git bisect--helper state "$cmd" "$@" ;;
+		git bisect--helper "$cmd" "$@" ;;
 	skip)
 		git bisect--helper skip "$@" || exit;;
 	next)
-- 
gitgitgadget


^ permalink raw reply related	[flat|nested] 147+ messages in thread

* [PATCH v6 13/16] bisect: move even the command-line parsing to `bisect--helper`
  2022-08-30 18:50         ` [PATCH v6 00/16] Finish converting git bisect into a built-in Johannes Schindelin via GitGitGadget
                             ` (11 preceding siblings ...)
  2022-08-30 18:50           ` [PATCH v6 12/16] bisect--helper: make `state` optional Johannes Schindelin via GitGitGadget
@ 2022-08-30 18:50           ` Johannes Schindelin via GitGitGadget
  2022-08-30 18:50           ` [PATCH v6 14/16] Turn `git bisect` into a full built-in Johannes Schindelin via GitGitGadget
                             ` (3 subsequent siblings)
  16 siblings, 0 replies; 147+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2022-08-30 18:50 UTC (permalink / raw)
  To: git
  Cc: Pranit Bauva, Tanushree Tumane, Miriam Rubio,
	Ævar Arnfjörð Bjarmason, Elijah Newren,
	Bagas Sanjaya, Junio C Hamano, Johannes Schindelin,
	Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

On our journey to a fully built-in `git bisect`, this is the
last step.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/bisect--helper.c |  1 -
 git-bisect.sh            | 49 +---------------------------------------
 2 files changed, 1 insertion(+), 49 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 61e819e4efc..6bcf16d9f62 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1455,7 +1455,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 		OPT_SUBCOMMAND("terms", &fn, cmd_bisect_terms),
 		OPT_SUBCOMMAND("start", &fn, cmd_bisect_start),
 		OPT_SUBCOMMAND("next", &fn, cmd_bisect_next),
-		OPT_SUBCOMMAND("state", &fn, cmd_bisect_state),
 		OPT_SUBCOMMAND("log", &fn, cmd_bisect_log),
 		OPT_SUBCOMMAND("replay", &fn, cmd_bisect_replay),
 		OPT_SUBCOMMAND("skip", &fn, cmd_bisect_skip),
diff --git a/git-bisect.sh b/git-bisect.sh
index f4df8709d84..028d39cd9ce 100755
--- a/git-bisect.sh
+++ b/git-bisect.sh
@@ -34,51 +34,4 @@ Please use "git help bisect" to get the full man page.'
 OPTIONS_SPEC=
 . git-sh-setup
 
-TERM_BAD=bad
-TERM_GOOD=good
-
-get_terms () {
-	if test -s "$GIT_DIR/BISECT_TERMS"
-	then
-		{
-		read TERM_BAD
-		read TERM_GOOD
-		} <"$GIT_DIR/BISECT_TERMS"
-	fi
-}
-
-case "$#" in
-0)
-	usage ;;
-*)
-	cmd="$1"
-	get_terms
-	shift
-	case "$cmd" in
-	help)
-		git bisect -h ;;
-	start)
-		git bisect--helper start "$@" ;;
-	bad|good|new|o