git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
* "git bisect run" strips "--log" from the list of arguments
@ 2022-11-04  6:31 Lukáš Doktor
  2022-11-04  9:45 ` Jeff King
                   ` (2 more replies)
  0 siblings, 3 replies; 106+ messages in thread
From: Lukáš Doktor @ 2022-11-04  6:31 UTC (permalink / raw)
  To: git


[-- Attachment #1.1.1: Type: text/plain, Size: 746 bytes --]

Hello folks,

recently I noticed a change of behavior in "git bisect run" and since git-2.34.1-1.fc35.x86_64 it's stripping "--log" arguments of my to-be-executed script.

Steps to Reproduce:

1. git bisect start BAD GOOD
2. git bisect run ./myscript arg1 --log arg2 --log -- arg3 --log arg4

Results with 2.34.1:

    running  './myscript' 'arg1' 'arg2' '--' 'arg3' '--log' 'arg4'

Results with 2.33.0:

    running ./myscript arg1 --log arg2 --log -- arg3 --log arg4

Is this expected? In https://bugzilla.redhat.com/show_bug.cgi?id=2139883 Todd suggested it might be related to

    d1bbbe45df (bisect--helper: reimplement `bisect_run` shell function in C, 2021-09-13) 

but I haven't tried it myself.

Regards,
Lukáš

[-- Attachment #1.1.2: OpenPGP public key --]
[-- Type: application/pgp-keys, Size: 10599 bytes --]

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 495 bytes --]

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

* Re: "git bisect run" strips "--log" from the list of arguments
  2022-11-04  6:31 "git bisect run" strips "--log" from the list of arguments Lukáš Doktor
@ 2022-11-04  9:45 ` Jeff King
  2022-11-04 11:10   ` Đoàn Trần Công Danh
                     ` (2 more replies)
  2022-11-04 11:40 ` [PATCH 0/3] Convert git-bisect--helper to OPT_SUBCOMMAND Đoàn Trần Công Danh
  2022-11-04 13:22 ` [PATCH 00/13] bisect: v2.30.0 "run" regressions + make it built-in Ævar Arnfjörð Bjarmason
  2 siblings, 3 replies; 106+ messages in thread
From: Jeff King @ 2022-11-04  9:45 UTC (permalink / raw)
  To: Lukáš Doktor; +Cc: Christian Couder, git

On Fri, Nov 04, 2022 at 07:31:26AM +0100, Lukáš Doktor wrote:

> Steps to Reproduce:
> 
> 1. git bisect start BAD GOOD
> 2. git bisect run ./myscript arg1 --log arg2 --log -- arg3 --log arg4
> 
> Results with 2.34.1:
> 
>     running  './myscript' 'arg1' 'arg2' '--' 'arg3' '--log' 'arg4'
> 
> Results with 2.33.0:
> 
>     running ./myscript arg1 --log arg2 --log -- arg3 --log arg4

Thanks for an easy reproduction recipe. I used this as an easy-to-see
test case, which works in any repo:

  git bisect start HEAD HEAD~2 >/dev/null 2>&1
  git bisect bisect run echo --log 2>&1 | grep running

> Is this expected? In https://bugzilla.redhat.com/show_bug.cgi?id=2139883 Todd suggested it might be related to
> 
>     d1bbbe45df (bisect--helper: reimplement `bisect_run` shell function in C, 2021-09-13) 
> 
> but I haven't tried it myself.

Yes, it bisects to that commit. +cc Christian, who mentored this gsoc
project.

I think the problem is that we are now feeding the arguments to
parse_options() in git bisect--helper, and it doesn't realize that it
needs to stop after seeing that we are in "run" mode.  And because
"--log" is an option to git-bisect--helper (it is the opposite of
"--no-log"), it is consumed there.

As you noticed, the "--" stops parsing, so the one between "arg3" and
"arg4" is preserved.

It feels like the invocation of bisect--helper ought to be passing "--"
itself to indicate the end of options, like:

diff --git a/git-bisect.sh b/git-bisect.sh
index 405cf76f2a..bd69e8d389 100755
--- a/git-bisect.sh
+++ b/git-bisect.sh
@@ -75,7 +75,7 @@ case "$#" in
 	log)
 		git bisect--helper --bisect-log || exit ;;
 	run)
-		git bisect--helper --bisect-run "$@" || exit;;
+		git bisect--helper --bisect-run -- "$@" || exit;;
 	terms)
 		git bisect--helper --bisect-terms "$@" || exit;;
 	*)

but there are two oddities:

  1. We use PARSE_OPT_KEEP_DASHDASH, so it ends up in the final command.
     We might be able to drop that; it goes back to 06f5608c14
     (bisect--helper: `bisect_start` shell function partially in C,
     2019-01-02), but I'm not sure which other modes might be relying on
     it.

  2. We are forwarding "$@" from the user. I'm not sure if they would
     ever use "--" themselves to signal end of options. We might be OK
     because "bisect run" does not take any other options (as far as I
     know), so nobody would ever need to do that. I.e., I don't think
     anybody would do:

       git bisect run -- mycommand

     because it will treat the "--" literally as a command name.

So we could possibly just add it in the script as above, and then
unconditionally eat it in the C program. I.e., add this hunk:

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 28ef7ec2a4..2d6c77df2e 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1377,6 +1377,11 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 		res = bisect_visualize(&terms, argv, argc);
 		break;
 	case BISECT_RUN:
+		/* consume "--" added by git-bisect.sh, but left by parse-options */
+		if (argc) {
+			argc--;
+			argv++;
+		}
 		if (!argc)
 			return error(_("bisect run failed: no command provided."));
 		get_terms(&terms);

It feels a bit hacky, but I think it would work, and there's no
possibility of disrupting the other modes.

The other option is probably an elaborate parse-options callback, like
the diff below. But it's pretty horrible, too.

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 28ef7ec2a4..16f71fd59c 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1277,22 +1277,49 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
 	return res;
 }
 
+enum bisect_cmdmode {
+	BISECT_RESET = 1,
+	BISECT_NEXT_CHECK,
+	BISECT_TERMS,
+	BISECT_START,
+	BISECT_AUTOSTART,
+	BISECT_NEXT,
+	BISECT_STATE,
+	BISECT_LOG,
+	BISECT_REPLAY,
+	BISECT_SKIP,
+	BISECT_VISUALIZE,
+	BISECT_RUN,
+};
+
+static int run_argc;
+static const char **run_argv;
+
+static int parse_opt_bisect_run(struct parse_opt_ctx_t *ctx,
+				const struct option *opt,
+				const char *arg, int unset)
+{
+	enum bisect_cmdmode *cmdmode = opt->value;
+
+	BUG_ON_OPT_ARG(arg);
+	BUG_ON_OPT_NEG(unset);
+
+	*cmdmode = BISECT_RUN;
+	/*
+	 * Yuck, parse-options has no way to say "done, and stop parsing";
+	 * it will keep going if we still have any argc left. So we have to
+	 * stash the rest of the options ourselves.
+	 */
+	run_argc = ctx->argc - 1;
+	run_argv = ctx->argv + 1;
+	ctx->argc = 1;
+
+	return 0;
+}
+
 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,
-		BISECT_NEXT,
-		BISECT_STATE,
-		BISECT_LOG,
-		BISECT_REPLAY,
-		BISECT_SKIP,
-		BISECT_VISUALIZE,
-		BISECT_RUN,
-	} cmdmode = 0;
+	enum bisect_cmdmode cmdmode = 0;
 	int res = 0, nolog = 0;
 	struct option options[] = {
 		OPT_CMDMODE(0, "bisect-reset", &cmdmode,
@@ -1315,8 +1342,10 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 			 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),
+		{OPTION_LOWLEVEL_CALLBACK, 0, "bisect-run", &cmdmode, NULL,
+			 N_("use <cmd>... to automatically bisect"),
+			 PARSE_OPT_NOARG|PARSE_OPT_NONEG,
+			 NULL, 0, parse_opt_bisect_run},
 		OPT_BOOL(0, "no-log", &nolog,
 			 N_("no log for BISECT_WRITE")),
 		OPT_END()
@@ -1377,10 +1406,10 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 		res = bisect_visualize(&terms, argv, argc);
 		break;
 	case BISECT_RUN:
-		if (!argc)
+		if (!run_argc)
 			return error(_("bisect run failed: no command provided."));
 		get_terms(&terms);
-		res = bisect_run(&terms, argv, argc);
+		res = bisect_run(&terms, run_argv, run_argc);
 		break;
 	default:
 		BUG("unknown subcommand %d", cmdmode);

-Peff

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

* Re: "git bisect run" strips "--log" from the list of arguments
  2022-11-04  9:45 ` Jeff King
@ 2022-11-04 11:10   ` Đoàn Trần Công Danh
  2022-11-04 12:51     ` Jeff King
  2022-11-04 11:36   ` Ævar Arnfjörð Bjarmason
  2022-11-04 12:37   ` SZEDER Gábor
  2 siblings, 1 reply; 106+ messages in thread
From: Đoàn Trần Công Danh @ 2022-11-04 11:10 UTC (permalink / raw)
  To: Jeff King; +Cc: Lukáš Doktor, Christian Couder, git

On 2022-11-04 05:45:52-0400, Jeff King <peff@peff.net> wrote:
> On Fri, Nov 04, 2022 at 07:31:26AM +0100, Lukáš Doktor wrote:
> 
> > Steps to Reproduce:
> > 
> > 1. git bisect start BAD GOOD
> > 2. git bisect run ./myscript arg1 --log arg2 --log -- arg3 --log arg4
> > 
> > Results with 2.34.1:
> > 
> >     running  './myscript' 'arg1' 'arg2' '--' 'arg3' '--log' 'arg4'
> > 
> > Results with 2.33.0:
> > 
> >     running ./myscript arg1 --log arg2 --log -- arg3 --log arg4
> 
> Thanks for an easy reproduction recipe. I used this as an easy-to-see
> test case, which works in any repo:
> 
>   git bisect start HEAD HEAD~2 >/dev/null 2>&1
>   git bisect bisect run echo --log 2>&1 | grep running
> 
> > Is this expected? In https://bugzilla.redhat.com/show_bug.cgi?id=2139883 Todd suggested it might be related to
> > 
> >     d1bbbe45df (bisect--helper: reimplement `bisect_run` shell function in C, 2021-09-13) 
> > 
> > but I haven't tried it myself.
> 
> Yes, it bisects to that commit. +cc Christian, who mentored this gsoc
> project.
> 
> I think the problem is that we are now feeding the arguments to
> parse_options() in git bisect--helper, and it doesn't realize that it
> needs to stop after seeing that we are in "run" mode.  And because
> "--log" is an option to git-bisect--helper (it is the opposite of
> "--no-log"), it is consumed there.
> 
> As you noticed, the "--" stops parsing, so the one between "arg3" and
> "arg4" is preserved.
> 
> It feels like the invocation of bisect--helper ought to be passing "--"
> itself to indicate the end of options, like:

I think we should use OPT_SUBCOMMAND to parse bisect--helper
subcommand instead, which would pave ways for easier converting to
built-int git-bisect. This huge patch, which could be splited into
2 patches can fix the problem:
---- 8< ----

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 1d2ce8a0e1..fe8aea7240 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1279,115 +1279,119 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
 	return res;
 }
 
+static int cmd_bisect__reset(int argc, const char **argv, const char *prefix UNUSED)
+{
+	if (argc > 1)
+		return error(_("--bisect-reset requires either no argument or a commit"));
+	return bisect_reset(argc ? argv[0] : NULL);
+}
+
+static int cmd_bisect__terms(int argc, const char **argv, const char *prefix UNUSED)
+{
+	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
+
+	if (argc > 1)
+		return error(_("--bisect-terms requires 0 or 1 argument"));
+	return bisect_terms(&terms, argc == 1 ? argv[0] : NULL);
+}
+
+static int cmd_bisect__start(int argc, const char **argv, const char *prefix UNUSED)
+{
+	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
+
+	set_terms(&terms, "bad", "good");
+	return bisect_start(&terms, argv, argc);
+}
+
+static int cmd_bisect__next(int argc, const char **argv UNUSED, const char *prefix)
+{
+	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
+
+	if (argc)
+		return error(_("--bisect-next requires 0 arguments"));
+	get_terms(&terms);
+	return bisect_next(&terms, prefix);
+}
+
+static int cmd_bisect__state(int argc, const char **argv, const char *prefix UNUSED)
+{
+	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
+
+	set_terms(&terms, "bad", "good");
+	get_terms(&terms);
+	return bisect_state(&terms, argv, argc);
+}
+
+static int cmd_bisect__log(int argc, const char **argv UNUSED, const char *prefix UNUSED)
+{
+	if (argc)
+		return error(_("--bisect-log requires 0 arguments"));
+	return bisect_log();
+}
+
+static int cmd_bisect__replay(int argc, const char **argv, const char *prefix UNUSED)
+{
+	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
+
+	if (argc != 1)
+		return error(_("no logfile given"));
+	set_terms(&terms, "bad", "good");
+	return bisect_replay(&terms, argv[0]);
+}
+
+static int cmd_bisect__skip(int argc, const char **argv, const char *prefix UNUSED)
+{
+	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
+
+	set_terms(&terms, "bad", "good");
+	get_terms(&terms);
+	return bisect_skip(&terms, argv, argc);
+}
+
+static int cmd_bisect__visualize(int argc, const char **argv, const char *prefix UNUSED)
+{
+	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
+
+	get_terms(&terms);
+	return bisect_visualize(&terms, argv, argc);
+}
+
+static int cmd_bisect__run(int argc, const char **argv, const char *prefix UNUSED)
+{
+	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
+
+	if (!argc)
+		return error(_("bisect run failed: no command provided."));
+	get_terms(&terms);
+	return bisect_run(&terms, argv, argc);
+}
+
 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,
-		BISECT_NEXT,
-		BISECT_STATE,
-		BISECT_LOG,
-		BISECT_REPLAY,
-		BISECT_SKIP,
-		BISECT_VISUALIZE,
-		BISECT_RUN,
-	} cmdmode = 0;
-	int res = 0, nolog = 0;
+	int res = 0;
+	parse_opt_subcommand_fn *fn = NULL;
 	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,
-			 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_BOOL(0, "no-log", &nolog,
-			 N_("no log for BISECT_WRITE")),
+		OPT_SUBCOMMAND("bisect-reset", &fn, cmd_bisect__reset),
+		OPT_SUBCOMMAND("bisect-terms", &fn, cmd_bisect__terms),
+		OPT_SUBCOMMAND("bisect-start", &fn, cmd_bisect__start),
+		OPT_SUBCOMMAND("bisect-next", &fn, cmd_bisect__next),
+		OPT_SUBCOMMAND("bisect-state", &fn, cmd_bisect__state),
+		OPT_SUBCOMMAND("bisect-log", &fn, cmd_bisect__log),
+		OPT_SUBCOMMAND("bisect-replay", &fn, cmd_bisect__replay),
+		OPT_SUBCOMMAND("bisect-skip", &fn, cmd_bisect__skip),
+		OPT_SUBCOMMAND("bisect-visualize", &fn, cmd_bisect__visualize),
+		OPT_SUBCOMMAND("bisect-run", &fn, cmd_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,
-			     PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN_OPT);
+			     git_bisect_helper_usage, 0);
 
-	if (!cmdmode)
+	if (!fn)
 		usage_with_options(git_bisect_helper_usage, options);
+	argc--;
+	argv++;
 
-	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(&terms, argc == 1 ? argv[0] : NULL);
-		break;
-	case BISECT_START:
-		set_terms(&terms, "bad", "good");
-		res = bisect_start(&terms, argv, argc);
-		break;
-	case BISECT_NEXT:
-		if (argc)
-			return error(_("--bisect-next requires 0 arguments"));
-		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);
-		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(&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);
-		break;
-	case BISECT_RUN:
-		if (!argc)
-			return error(_("bisect run failed: no command provided."));
-		get_terms(&terms);
-		res = bisect_run(&terms, argv, argc);
-		break;
-	default:
-		BUG("unknown subcommand %d", cmdmode);
-	}
-	free_terms(&terms);
+	res = fn(argc, argv, prefix);
 
 	/*
 	 * Handle early success
diff --git a/git-bisect.sh b/git-bisect.sh
index 405cf76f2a..07a7257be4 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 bisect-start "$@" ;;
 	bad|good|new|old|"$TERM_BAD"|"$TERM_GOOD")
-		git bisect--helper --bisect-state "$cmd" "$@" ;;
+		git bisect--helper bisect-state "$cmd" "$@" ;;
 	skip)
-		git bisect--helper --bisect-skip "$@" || exit;;
+		git bisect--helper bisect-skip "$@" || exit;;
 	next)
 		# Not sure we want "next" at the UI level anymore.
-		git bisect--helper --bisect-next "$@" || exit ;;
+		git bisect--helper bisect-next "$@" || exit ;;
 	visualize|view)
-		git bisect--helper --bisect-visualize "$@" || exit;;
+		git bisect--helper bisect-visualize "$@" || exit;;
 	reset)
-		git bisect--helper --bisect-reset "$@" ;;
+		git bisect--helper bisect-reset "$@" ;;
 	replay)
-		git bisect--helper --bisect-replay "$@" || exit;;
+		git bisect--helper bisect-replay "$@" || exit;;
 	log)
-		git bisect--helper --bisect-log || exit ;;
+		git bisect--helper bisect-log || exit ;;
 	run)
-		git bisect--helper --bisect-run "$@" || exit;;
+		git bisect--helper bisect-run "$@" || exit;;
 	terms)
-		git bisect--helper --bisect-terms "$@" || exit;;
+		git bisect--helper bisect-terms "$@" || exit;;
 	*)
 		usage ;;
 	esac
diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh
index 83931d482f..e957772b05 100755
--- a/t/t6030-bisect-porcelain.sh
+++ b/t/t6030-bisect-porcelain.sh
@@ -266,6 +266,17 @@ test_expect_success '"git bisect run" simple case' '
 	git bisect reset
 '
 
+# We want to automatically find the commit that
+# added "Another" into hello. We also want to make sure --log is not eaten
+test_expect_success '"git bisect run" simple case' '
+	git bisect start &&
+	git bisect good $HASH1 &&
+	git bisect bad $HASH4 &&
+	git bisect run printf "%s\n" --log >my_bisect_log.txt &&
+	grep -e --log my_bisect_log.txt &&
+	git bisect reset
+'
+
 # We want to automatically find the commit that
 # added "Ciao" into hello.
 test_expect_success '"git bisect run" with more complex "git bisect start"' '
----- >8 -----

I can turn this into 2 patches series if you thinks this is the right
direction.

-- 
Danh

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

* Re: "git bisect run" strips "--log" from the list of arguments
  2022-11-04  9:45 ` Jeff King
  2022-11-04 11:10   ` Đoàn Trần Công Danh
@ 2022-11-04 11:36   ` Ævar Arnfjörð Bjarmason
  2022-11-04 12:45     ` Jeff King
  2022-11-04 12:37   ` SZEDER Gábor
  2 siblings, 1 reply; 106+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-04 11:36 UTC (permalink / raw)
  To: Jeff King; +Cc: Lukáš Doktor, Christian Couder, git


On Fri, Nov 04 2022, Jeff King wrote:

> On Fri, Nov 04, 2022 at 07:31:26AM +0100, Lukáš Doktor wrote:
>
>> Steps to Reproduce:
>> 
>> 1. git bisect start BAD GOOD
>> 2. git bisect run ./myscript arg1 --log arg2 --log -- arg3 --log arg4
>> 
>> Results with 2.34.1:
>> 
>>     running  './myscript' 'arg1' 'arg2' '--' 'arg3' '--log' 'arg4'
>> 
>> Results with 2.33.0:
>> 
>>     running ./myscript arg1 --log arg2 --log -- arg3 --log arg4
>
> Thanks for an easy reproduction recipe. I used this as an easy-to-see
> test case, which works in any repo:
>
>   git bisect start HEAD HEAD~2 >/dev/null 2>&1
>   git bisect bisect run echo --log 2>&1 | grep running
>
>> Is this expected? In https://bugzilla.redhat.com/show_bug.cgi?id=2139883 Todd suggested it might be related to
>> 
>>     d1bbbe45df (bisect--helper: reimplement `bisect_run` shell function in C, 2021-09-13) 
>> 
>> but I haven't tried it myself.
>
> Yes, it bisects to that commit. +cc Christian, who mentored this gsoc
> project.
>
> I think the problem is that we are now feeding the arguments to
> parse_options() in git bisect--helper, and it doesn't realize that it
> needs to stop after seeing that we are in "run" mode.  And because
> "--log" is an option to git-bisect--helper (it is the opposite of
> "--no-log"), it is consumed there.
>
> As you noticed, the "--" stops parsing, so the one between "arg3" and
> "arg4" is preserved.
>
> It feels like the invocation of bisect--helper ought to be passing "--"
> itself to indicate the end of options, like:

Normally you'd be righ, but there's a much easier way to do it in this
case: cherry-pick
https://lore.kernel.org/git/05262b6a7d1b20a0d2f2ca2090be284ffb8c679c.1661885419.git.gitgitgadget@gmail.com/

I.e. we're eating "--log" in particular, but could just stop
understanding that option.

I'll submit alternate fixes for this soon, I've been poking at various
"bisect" behavior changes, and the commit that rewrote "run" introduced
a few other regressions....

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

* [PATCH 0/3] Convert git-bisect--helper to OPT_SUBCOMMAND
  2022-11-04  6:31 "git bisect run" strips "--log" from the list of arguments Lukáš Doktor
  2022-11-04  9:45 ` Jeff King
@ 2022-11-04 11:40 ` Đoàn Trần Công Danh
  2022-11-04 11:40   ` [PATCH 1/3] bisect--helper: remove unused options Đoàn Trần Công Danh
                     ` (5 more replies)
  2022-11-04 13:22 ` [PATCH 00/13] bisect: v2.30.0 "run" regressions + make it built-in Ævar Arnfjörð Bjarmason
  2 siblings, 6 replies; 106+ messages in thread
From: Đoàn Trần Công Danh @ 2022-11-04 11:40 UTC (permalink / raw)
  To: git
  Cc: Đoàn Trần Công Danh, Lukáš Doktor,
	Jeff King, Christian Couder


This series aims to fix the problem that bisect--helper incorrectly consumes
"--log" when running:

	git bisect run cmd --log

This also clears a way for turning git-bisect into a built-in in a later day.

Đoàn Trần Công Danh (3):
  bisect--helper: remove unused options
  bisect--helper: move all subcommands into their own functions
  bisect--helper: parse subcommand with OPT_SUBCOMMAND

 builtin/bisect--helper.c    | 228 ++++++++++++++++++++----------------
 git-bisect.sh               |  20 ++--
 t/t6030-bisect-porcelain.sh |  10 ++
 3 files changed, 148 insertions(+), 110 deletions(-)

-- 
2.38.1.157.gedabe22e0a


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

* [PATCH 1/3] bisect--helper: remove unused options
  2022-11-04 11:40 ` [PATCH 0/3] Convert git-bisect--helper to OPT_SUBCOMMAND Đoàn Trần Công Danh
@ 2022-11-04 11:40   ` Đoàn Trần Công Danh
  2022-11-04 12:53     ` Jeff King
  2022-11-04 11:40   ` [PATCH 2/3] bisect--helper: move all subcommands into their own functions Đoàn Trần Công Danh
                     ` (4 subsequent siblings)
  5 siblings, 1 reply; 106+ messages in thread
From: Đoàn Trần Công Danh @ 2022-11-04 11:40 UTC (permalink / raw)
  To: git
  Cc: Đoàn Trần Công Danh, Lukáš Doktor,
	Jeff King, Christian Couder

Signed-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>
---
 builtin/bisect--helper.c | 7 +------
 1 file changed, 1 insertion(+), 6 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 1d2ce8a0e1..5ec2e67f59 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1283,7 +1283,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,
@@ -1295,12 +1294,10 @@ 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),
-		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,
@@ -1319,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 };
-- 
2.38.1.157.gedabe22e0a


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

* [PATCH 2/3] bisect--helper: move all subcommands into their own functions
  2022-11-04 11:40 ` [PATCH 0/3] Convert git-bisect--helper to OPT_SUBCOMMAND Đoàn Trần Công Danh
  2022-11-04 11:40   ` [PATCH 1/3] bisect--helper: remove unused options Đoàn Trần Công Danh
@ 2022-11-04 11:40   ` Đoàn Trần Công Danh
  2022-11-04 12:55     ` Jeff King
  2022-11-04 13:32     ` Ævar Arnfjörð Bjarmason
  2022-11-04 11:40   ` [PATCH 3/3] bisect--helper: parse subcommand with OPT_SUBCOMMAND Đoàn Trần Công Danh
                     ` (3 subsequent siblings)
  5 siblings, 2 replies; 106+ messages in thread
From: Đoàn Trần Công Danh @ 2022-11-04 11:40 UTC (permalink / raw)
  To: git
  Cc: Đoàn Trần Công Danh, Lukáš Doktor,
	Jeff King, Christian Couder

In a later change, we will use OPT_SUBCOMMAND to parse sub-commands to
avoid consuming non-option opts.

Since OPT_SUBCOMMAND needs a function pointer to operate,
let's move it now.

Signed-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>
---
 builtin/bisect--helper.c | 155 ++++++++++++++++++++++++++++++---------
 1 file changed, 121 insertions(+), 34 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 5ec2e67f59..292c6fd1dd 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1279,6 +1279,117 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
 	return res;
 }
 
+static int cmd_bisect__reset(int argc, const char **argv, const char *prefix UNUSED)
+{
+	if (argc > 1)
+		return error(_("--bisect-reset requires either no argument or a commit"));
+	return bisect_reset(argc ? argv[0] : NULL);
+}
+
+static int cmd_bisect__terms(int argc, const char **argv, const char *prefix UNUSED)
+{
+	int res;
+	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
+
+	if (argc > 1)
+		return error(_("--bisect-terms requires 0 or 1 argument"));
+	res = bisect_terms(&terms, argc == 1 ? argv[0] : NULL);
+	free_terms(&terms);
+	return res;
+}
+
+static int cmd_bisect__start(int argc, const char **argv, const char *prefix UNUSED)
+{
+	int res;
+	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
+
+	set_terms(&terms, "bad", "good");
+	res = bisect_start(&terms, argv, argc);
+	free_terms(&terms);
+	return res;
+}
+
+static int cmd_bisect__next(int argc, const char **argv UNUSED, const char *prefix)
+{
+	int res;
+	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
+
+	if (argc)
+		return error(_("--bisect-next requires 0 arguments"));
+	get_terms(&terms);
+	res = bisect_next(&terms, prefix);
+	free_terms(&terms);
+	return res;
+}
+
+static int cmd_bisect__state(int argc, const char **argv, const char *prefix UNUSED)
+{
+	int res;
+	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
+
+	set_terms(&terms, "bad", "good");
+	get_terms(&terms);
+	res = bisect_state(&terms, argv, argc);
+	free_terms(&terms);
+	return res;
+}
+
+static int cmd_bisect__log(int argc, const char **argv UNUSED, const char *prefix UNUSED)
+{
+	if (argc)
+		return error(_("--bisect-log requires 0 arguments"));
+	return bisect_log();
+}
+
+static int cmd_bisect__replay(int argc, const char **argv, const char *prefix UNUSED)
+{
+	int res;
+	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
+
+	if (argc != 1)
+		return error(_("no logfile given"));
+	set_terms(&terms, "bad", "good");
+	res = bisect_replay(&terms, argv[0]);
+	free_terms(&terms);
+	return res;
+}
+
+static int cmd_bisect__skip(int argc, const char **argv, const char *prefix UNUSED)
+{
+	int res;
+	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
+
+	set_terms(&terms, "bad", "good");
+	get_terms(&terms);
+	res = bisect_skip(&terms, argv, argc);
+	free_terms(&terms);
+	return res;
+}
+
+static int cmd_bisect__visualize(int argc, const char **argv, const char *prefix UNUSED)
+{
+	int res;
+	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
+
+	get_terms(&terms);
+	res = bisect_visualize(&terms, argv, argc);
+	free_terms(&terms);
+	return res;
+}
+
+static int cmd_bisect__run(int argc, const char **argv, const char *prefix UNUSED)
+{
+	int res;
+	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
+
+	if (!argc)
+		return error(_("bisect run failed: no command provided."));
+	get_terms(&terms);
+	res = bisect_run(&terms, argv, argc);
+	free_terms(&terms);
+	return res;
+}
+
 int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 {
 	enum {
@@ -1318,8 +1429,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,
 			     PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN_OPT);
@@ -1329,60 +1438,38 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 
 	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);
+		res = cmd_bisect__reset(argc, argv, prefix);
 		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);
+		res = cmd_bisect__terms(argc, argv, prefix);
 		break;
 	case BISECT_START:
-		set_terms(&terms, "bad", "good");
-		res = bisect_start(&terms, argv, argc);
+		res = cmd_bisect__start(argc, argv, prefix);
 		break;
 	case BISECT_NEXT:
-		if (argc)
-			return error(_("--bisect-next requires 0 arguments"));
-		get_terms(&terms);
-		res = bisect_next(&terms, prefix);
+		res = cmd_bisect__next(argc, argv, prefix);
 		break;
 	case BISECT_STATE:
-		set_terms(&terms, "bad", "good");
-		get_terms(&terms);
-		res = bisect_state(&terms, argv, argc);
+		res = cmd_bisect__state(argc, argv, prefix);
 		break;
 	case BISECT_LOG:
-		if (argc)
-			return error(_("--bisect-log requires 0 arguments"));
-		res = bisect_log();
+		res = cmd_bisect__log(argc, argv, prefix);
 		break;
 	case BISECT_REPLAY:
-		if (argc != 1)
-			return error(_("no logfile given"));
-		set_terms(&terms, "bad", "good");
-		res = bisect_replay(&terms, argv[0]);
+		res = cmd_bisect__replay(argc, argv, prefix);
 		break;
 	case BISECT_SKIP:
-		set_terms(&terms, "bad", "good");
-		get_terms(&terms);
-		res = bisect_skip(&terms, argv, argc);
+		res = cmd_bisect__skip(argc, argv, prefix);
 		break;
 	case BISECT_VISUALIZE:
-		get_terms(&terms);
-		res = bisect_visualize(&terms, argv, argc);
+		res = cmd_bisect__visualize(argc, argv, prefix);
 		break;
 	case BISECT_RUN:
-		if (!argc)
-			return error(_("bisect run failed: no command provided."));
-		get_terms(&terms);
-		res = bisect_run(&terms, argv, argc);
+		res = cmd_bisect__run(argc, argv, prefix);
 		break;
 	default:
 		BUG("unknown subcommand %d", cmdmode);
 	}
-	free_terms(&terms);
 
 	/*
 	 * Handle early success
-- 
2.38.1.157.gedabe22e0a


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

* [PATCH 3/3] bisect--helper: parse subcommand with OPT_SUBCOMMAND
  2022-11-04 11:40 ` [PATCH 0/3] Convert git-bisect--helper to OPT_SUBCOMMAND Đoàn Trần Công Danh
  2022-11-04 11:40   ` [PATCH 1/3] bisect--helper: remove unused options Đoàn Trần Công Danh
  2022-11-04 11:40   ` [PATCH 2/3] bisect--helper: move all subcommands into their own functions Đoàn Trần Công Danh
@ 2022-11-04 11:40   ` Đoàn Trần Công Danh
  2022-11-04 13:00     ` Jeff King
  2022-11-04 13:46     ` Ævar Arnfjörð Bjarmason
  2022-11-04 13:55   ` [PATCH 0/3] Convert git-bisect--helper to OPT_SUBCOMMAND Ævar Arnfjörð Bjarmason
                     ` (2 subsequent siblings)
  5 siblings, 2 replies; 106+ messages in thread
From: Đoàn Trần Công Danh @ 2022-11-04 11:40 UTC (permalink / raw)
  To: git
  Cc: Đoàn Trần Công Danh, Lukáš Doktor,
	Jeff King, Christian Couder

As of it is, we're parsing subcommand with OPT_CMDMODE, which will
continue to parse more options even if the command has been found.

When we're running "git bisect run" with a command that expecting
a "--log" or "--no-log" arguments, or one of those "--bisect-..."
arguments, bisect--helper may mistakenly think those options are
bisect--helper's option.

We may fix those problems by passing "--" when calling from
git-bisect.sh, and skip that "--" in bisect--helper. However, it may
interfere with user's "--".

Let's parse subcommand with OPT_SUBCOMMAND since that API was born for
this specific use-case.

Reported-by: Lukáš Doktor <ldoktor@redhat.com>
Signed-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>
---
 builtin/bisect--helper.c    | 86 +++++++------------------------------
 git-bisect.sh               | 20 ++++-----
 t/t6030-bisect-porcelain.sh | 10 +++++
 3 files changed, 36 insertions(+), 80 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 292c6fd1dd..c37cb89a90 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1392,84 +1392,30 @@ static int cmd_bisect__run(int argc, const char **argv, const char *prefix UNUSE
 
 int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 {
-	enum {
-		BISECT_RESET = 1,
-		BISECT_TERMS,
-		BISECT_START,
-		BISECT_AUTOSTART,
-		BISECT_NEXT,
-		BISECT_STATE,
-		BISECT_LOG,
-		BISECT_REPLAY,
-		BISECT_SKIP,
-		BISECT_VISUALIZE,
-		BISECT_RUN,
-	} cmdmode = 0;
 	int res = 0;
+	parse_opt_subcommand_fn *fn = NULL;
 	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("bisect-reset", &fn, cmd_bisect__reset),
+		OPT_SUBCOMMAND("bisect-terms", &fn, cmd_bisect__terms),
+		OPT_SUBCOMMAND("bisect-start", &fn, cmd_bisect__start),
+		OPT_SUBCOMMAND("bisect-next", &fn, cmd_bisect__next),
+		OPT_SUBCOMMAND("bisect-state", &fn, cmd_bisect__state),
+		OPT_SUBCOMMAND("bisect-log", &fn, cmd_bisect__log),
+		OPT_SUBCOMMAND("bisect-replay", &fn, cmd_bisect__replay),
+		OPT_SUBCOMMAND("bisect-skip", &fn, cmd_bisect__skip),
+		OPT_SUBCOMMAND("bisect-visualize", &fn, cmd_bisect__visualize),
+		OPT_SUBCOMMAND("bisect-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);
+			     git_bisect_helper_usage, 0);
 
-	if (!cmdmode)
+	if (!fn)
 		usage_with_options(git_bisect_helper_usage, options);
+	argc--;
+	argv++;
 
-	switch (cmdmode) {
-	case BISECT_RESET:
-		res = cmd_bisect__reset(argc, argv, prefix);
-		break;
-	case BISECT_TERMS:
-		res = cmd_bisect__terms(argc, argv, prefix);
-		break;
-	case BISECT_START:
-		res = cmd_bisect__start(argc, argv, prefix);
-		break;
-	case BISECT_NEXT:
-		res = cmd_bisect__next(argc, argv, prefix);
-		break;
-	case BISECT_STATE:
-		res = cmd_bisect__state(argc, argv, prefix);
-		break;
-	case BISECT_LOG:
-		res = cmd_bisect__log(argc, argv, prefix);
-		break;
-	case BISECT_REPLAY:
-		res = cmd_bisect__replay(argc, argv, prefix);
-		break;
-	case BISECT_SKIP:
-		res = cmd_bisect__skip(argc, argv, prefix);
-		break;
-	case BISECT_VISUALIZE:
-		res = cmd_bisect__visualize(argc, argv, prefix);
-		break;
-	case BISECT_RUN:
-		res = cmd_bisect__run(argc, argv, prefix);
-		break;
-	default:
-		BUG("unknown subcommand %d", cmdmode);
-	}
+	res = fn(argc, argv, prefix);
 
 	/*
 	 * Handle early success
diff --git a/git-bisect.sh b/git-bisect.sh
index 405cf76f2a..07a7257be4 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 bisect-start "$@" ;;
 	bad|good|new|old|"$TERM_BAD"|"$TERM_GOOD")
-		git bisect--helper --bisect-state "$cmd" "$@" ;;
+		git bisect--helper bisect-state "$cmd" "$@" ;;
 	skip)
-		git bisect--helper --bisect-skip "$@" || exit;;
+		git bisect--helper bisect-skip "$@" || exit;;
 	next)
 		# Not sure we want "next" at the UI level anymore.
-		git bisect--helper --bisect-next "$@" || exit ;;
+		git bisect--helper bisect-next "$@" || exit ;;
 	visualize|view)
-		git bisect--helper --bisect-visualize "$@" || exit;;
+		git bisect--helper bisect-visualize "$@" || exit;;
 	reset)
-		git bisect--helper --bisect-reset "$@" ;;
+		git bisect--helper bisect-reset "$@" ;;
 	replay)
-		git bisect--helper --bisect-replay "$@" || exit;;
+		git bisect--helper bisect-replay "$@" || exit;;
 	log)
-		git bisect--helper --bisect-log || exit ;;
+		git bisect--helper bisect-log || exit ;;
 	run)
-		git bisect--helper --bisect-run "$@" || exit;;
+		git bisect--helper bisect-run "$@" || exit;;
 	terms)
-		git bisect--helper --bisect-terms "$@" || exit;;
+		git bisect--helper bisect-terms "$@" || exit;;
 	*)
 		usage ;;
 	esac
diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh
index 83931d482f..a17027d574 100755
--- a/t/t6030-bisect-porcelain.sh
+++ b/t/t6030-bisect-porcelain.sh
@@ -266,6 +266,16 @@ test_expect_success '"git bisect run" simple case' '
 	git bisect reset
 '
 
+# We want to make sure --log is not eaten
+test_expect_success '"git bisect run" simple case' '
+	git bisect start &&
+	git bisect good $HASH1 &&
+	git bisect bad $HASH4 &&
+	git bisect run printf "%s\n" --log >my_bisect_log.txt &&
+	grep -e --log my_bisect_log.txt &&
+	git bisect reset
+'
+
 # We want to automatically find the commit that
 # added "Ciao" into hello.
 test_expect_success '"git bisect run" with more complex "git bisect start"' '
-- 
2.38.1.157.gedabe22e0a


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

* Re: "git bisect run" strips "--log" from the list of arguments
  2022-11-04  9:45 ` Jeff King
  2022-11-04 11:10   ` Đoàn Trần Công Danh
  2022-11-04 11:36   ` Ævar Arnfjörð Bjarmason
@ 2022-11-04 12:37   ` SZEDER Gábor
  2022-11-04 12:44     ` Jeff King
  2 siblings, 1 reply; 106+ messages in thread
From: SZEDER Gábor @ 2022-11-04 12:37 UTC (permalink / raw)
  To: Jeff King; +Cc: Lukáš Doktor, Christian Couder, git

On Fri, Nov 04, 2022 at 05:45:52AM -0400, Jeff King wrote:
> On Fri, Nov 04, 2022 at 07:31:26AM +0100, Lukáš Doktor wrote:
> 
> > Steps to Reproduce:
> > 
> > 1. git bisect start BAD GOOD
> > 2. git bisect run ./myscript arg1 --log arg2 --log -- arg3 --log arg4
> > 
> > Results with 2.34.1:
> > 
> >     running  './myscript' 'arg1' 'arg2' '--' 'arg3' '--log' 'arg4'
> > 
> > Results with 2.33.0:
> > 
> >     running ./myscript arg1 --log arg2 --log -- arg3 --log arg4
> 
> Thanks for an easy reproduction recipe. I used this as an easy-to-see
> test case, which works in any repo:
> 
>   git bisect start HEAD HEAD~2 >/dev/null 2>&1
>   git bisect bisect run echo --log 2>&1 | grep running
> 
> > Is this expected? In https://bugzilla.redhat.com/show_bug.cgi?id=2139883 Todd suggested it might be related to
> > 
> >     d1bbbe45df (bisect--helper: reimplement `bisect_run` shell function in C, 2021-09-13) 
> > 
> > but I haven't tried it myself.
> 
> Yes, it bisects to that commit. +cc Christian, who mentored this gsoc
> project.

It might bisect to that commit, but I don't think that commit is the
real culprit here.

'git-bisect.sh' used to have a 'bisect_write' function (not
subcommand!), whose third positional parameter was a "nolog" flag.
This flag was only used when 'bisect_start' invoked it to write the
starting good and bad revisions.  Then 0f30233a11 (bisect--helper:
`bisect_write` shell function in C, 2019-01-02) ported it to C as a
command mode of 'bisect--helper', and:

  - Added the '--no-log' option, but since 'bisect--helper' has
    command modes not subcommands, all other command modes see and
    handle that option as well.
  - Converted all callsites of 'bisect_write' to invocations of 'git
    bisect--helper --bisect-write', but while doing so that one
    callsite in 'bisect_start' was misconverted, and instead of
    passing the '--no-log' option, it still passed 'nolog' as
    parameter.  Consequently, 'git bisect start' wrote a couple of
    extra lines to '.git/BISECT_LOG'.

This bogus state didn't last long, however, because in the same patch
series 06f5608c14 (bisect--helper: `bisect_start` shell function
partially in C, 2019-01-02) the C reimplementation of bisect_start()
started calling the bisect_write() C function, this time with the
right 'nolog' function parameter.  From then on there was no need for
the '--no-log' option in 'bisect--helper'.  Eventually all bisect
subcommands were ported to C as 'bisect--helper' command modes, each
calling the bisect_write() C function instead, but when the
'--bisect-write' command mode was removed in 68efed8c8a
(bisect--helper: retire `--bisect-write` subcommand, 2021-02-03) it
forgot to remove that '--no-log' option.



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

* Re: "git bisect run" strips "--log" from the list of arguments
  2022-11-04 12:37   ` SZEDER Gábor
@ 2022-11-04 12:44     ` Jeff King
  0 siblings, 0 replies; 106+ messages in thread
From: Jeff King @ 2022-11-04 12:44 UTC (permalink / raw)
  To: SZEDER Gábor; +Cc: Lukáš Doktor, Christian Couder, git

On Fri, Nov 04, 2022 at 01:37:22PM +0100, SZEDER Gábor wrote:

> This bogus state didn't last long, however, because in the same patch
> series 06f5608c14 (bisect--helper: `bisect_start` shell function
> partially in C, 2019-01-02) the C reimplementation of bisect_start()
> started calling the bisect_write() C function, this time with the
> right 'nolog' function parameter.  From then on there was no need for
> the '--no-log' option in 'bisect--helper'.  Eventually all bisect
> subcommands were ported to C as 'bisect--helper' command modes, each
> calling the bisect_write() C function instead, but when the
> '--bisect-write' command mode was removed in 68efed8c8a
> (bisect--helper: retire `--bisect-write` subcommand, 2021-02-03) it
> forgot to remove that '--no-log' option.

Yeah, but I don't think "--log" or "--no-log" is really the bug, is it?

The same thing happens if my command is "echo --bisect-run". Obviously
that's less likely, but the bug is still that we are parsing random
options out of the supposedly opaque command.

-Peff

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

* Re: "git bisect run" strips "--log" from the list of arguments
  2022-11-04 11:36   ` Ævar Arnfjörð Bjarmason
@ 2022-11-04 12:45     ` Jeff King
  2022-11-04 13:07       ` Ævar Arnfjörð Bjarmason
  0 siblings, 1 reply; 106+ messages in thread
From: Jeff King @ 2022-11-04 12:45 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: Lukáš Doktor, Christian Couder, git

On Fri, Nov 04, 2022 at 12:36:12PM +0100, Ævar Arnfjörð Bjarmason wrote:

> > It feels like the invocation of bisect--helper ought to be passing "--"
> > itself to indicate the end of options, like:
> 
> Normally you'd be righ, but there's a much easier way to do it in this
> case: cherry-pick
> https://lore.kernel.org/git/05262b6a7d1b20a0d2f2ca2090be284ffb8c679c.1661885419.git.gitgitgadget@gmail.com/
> 
> I.e. we're eating "--log" in particular, but could just stop
> understanding that option.

We're not eating "--log" in particular, though. We're eating anything
that parse_options() understands. It would eat "--bisect-start", too.
That's less likely than "--log", but the fundamental problem would still
remain.

-Peff

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

* Re: "git bisect run" strips "--log" from the list of arguments
  2022-11-04 11:10   ` Đoàn Trần Công Danh
@ 2022-11-04 12:51     ` Jeff King
  0 siblings, 0 replies; 106+ messages in thread
From: Jeff King @ 2022-11-04 12:51 UTC (permalink / raw)
  To: Đoàn Trần Công Danh
  Cc: Lukáš Doktor, Christian Couder, git

On Fri, Nov 04, 2022 at 06:10:02PM +0700, Đoàn Trần Công Danh wrote:

> I think we should use OPT_SUBCOMMAND to parse bisect--helper
> subcommand instead, which would pave ways for easier converting to
> built-int git-bisect. This huge patch, which could be splited into
> 2 patches can fix the problem:

Yeah, I haven't really dug into the subcommand stuff before, but I
noticed while poking at the low-level callback code that it may stop the
parsing.

If so, then yes, I think that fixes the problem. But does it break other
modes, that want to be parsing "--log"? It sounds from other responses
in the thread that no, nobody actually cares about the "--log" flag (and
that matches my reading of the code; nobody looks at the nolog variable
we set).

The other obvious problem with switching to subcommands is that it
changes the caller-visible name (to drop the "--"). But that should be
OK here, as we make no promises about what's in helper command like
bisect--helper.

So yeah, that does seem like a better path forward.

-Peff

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

* Re: [PATCH 1/3] bisect--helper: remove unused options
  2022-11-04 11:40   ` [PATCH 1/3] bisect--helper: remove unused options Đoàn Trần Công Danh
@ 2022-11-04 12:53     ` Jeff King
  0 siblings, 0 replies; 106+ messages in thread
From: Jeff King @ 2022-11-04 12:53 UTC (permalink / raw)
  To: Đoàn Trần Công Danh
  Cc: git, Lukáš Doktor, Christian Couder

On Fri, Nov 04, 2022 at 06:40:10PM +0700, Đoàn Trần Công Danh wrote:

> diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
> index 1d2ce8a0e1..5ec2e67f59 100644
> --- a/builtin/bisect--helper.c
> +++ b/builtin/bisect--helper.c
> @@ -1283,7 +1283,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,

OK, makes sense. It might be nice to mention in the commit message how
we got here. It looks like the callers that used this went away in
d1bbbe45df (bisect--helper: reimplement `bisect_run` shell function in
C, 2021-09-13) and 5e1f28d206 (bisect--helper: reimplement
`bisect_visualize()` shell function in C, 2021-09-13).

> @@ -1319,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")),

Likewise digging up the history here lets us see why removing is the
right thing (and the bug is not that it _should_ be used and isn't).
Gábor posted a summary of the history elsewhere in the thread.

-Peff

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

* Re: [PATCH 2/3] bisect--helper: move all subcommands into their own functions
  2022-11-04 11:40   ` [PATCH 2/3] bisect--helper: move all subcommands into their own functions Đoàn Trần Công Danh
@ 2022-11-04 12:55     ` Jeff King
  2022-11-04 13:32     ` Ævar Arnfjörð Bjarmason
  1 sibling, 0 replies; 106+ messages in thread
From: Jeff King @ 2022-11-04 12:55 UTC (permalink / raw)
  To: Đoàn Trần Công Danh
  Cc: git, Lukáš Doktor, Christian Couder

On Fri, Nov 04, 2022 at 06:40:11PM +0700, Đoàn Trần Công Danh wrote:

> In a later change, we will use OPT_SUBCOMMAND to parse sub-commands to
> avoid consuming non-option opts.
> 
> Since OPT_SUBCOMMAND needs a function pointer to operate,
> let's move it now.

Makes sense, and splitting this into its own step makes it easier to
verify.

> +static int cmd_bisect__reset(int argc, const char **argv, const char *prefix UNUSED)

Thank you very much for putting the UNUSED markers here. It will save me
the trouble of handling it on my topic. :)

-Peff

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

* Re: [PATCH 3/3] bisect--helper: parse subcommand with OPT_SUBCOMMAND
  2022-11-04 11:40   ` [PATCH 3/3] bisect--helper: parse subcommand with OPT_SUBCOMMAND Đoàn Trần Công Danh
@ 2022-11-04 13:00     ` Jeff King
  2022-11-04 13:46     ` Ævar Arnfjörð Bjarmason
  1 sibling, 0 replies; 106+ messages in thread
From: Jeff King @ 2022-11-04 13:00 UTC (permalink / raw)
  To: Đoàn Trần Công Danh
  Cc: git, Lukáš Doktor, Christian Couder

On Fri, Nov 04, 2022 at 06:40:12PM +0700, Đoàn Trần Công Danh wrote:

> As of it is, we're parsing subcommand with OPT_CMDMODE, which will
> continue to parse more options even if the command has been found.
> 
> When we're running "git bisect run" with a command that expecting
> a "--log" or "--no-log" arguments, or one of those "--bisect-..."
> arguments, bisect--helper may mistakenly think those options are
> bisect--helper's option.

Right.

> We may fix those problems by passing "--" when calling from
> git-bisect.sh, and skip that "--" in bisect--helper. However, it may
> interfere with user's "--".

I think it won't interfere. A user can't put "--" as a separator now; it
gets taken as part of the command. So if we consistently added one in
the caller and stripped it away in bisect--helper, that would work
correctly (and if the user did have one later in their command, it would
be preserved as it is now).

That said, I do think your solution is nicer, and is potentially fixing
similar problems in other subcommand modes, too.

> Let's parse subcommand with OPT_SUBCOMMAND since that API was born for
> this specific use-case.

The implication here being that OPT_SUBCOMMAND stops parsing as soon as
it hits a subcommand, I assume.

>  builtin/bisect--helper.c    | 86 +++++++------------------------------
>  git-bisect.sh               | 20 ++++-----

The patch here looks sensible, but...

> +# We want to make sure --log is not eaten
> +test_expect_success '"git bisect run" simple case' '
> +	git bisect start &&
> +	git bisect good $HASH1 &&
> +	git bisect bad $HASH4 &&
> +	git bisect run printf "%s\n" --log >my_bisect_log.txt &&
> +	grep -e --log my_bisect_log.txt &&
> +	git bisect reset
> +'

...since you removed --log in the first commit, I think this would pass
even before this patch. You'd need to use another option like
--bisect-reset to show the problem. Of course then it is trivial that
the patch fixes it, since "--bisect-reset" becomes "bisect-reset"
afterwards. So there are no options left to parse at that point. But it
would be the best we could do to demonstrate it.

-Peff

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

* Re: "git bisect run" strips "--log" from the list of arguments
  2022-11-04 12:45     ` Jeff King
@ 2022-11-04 13:07       ` Ævar Arnfjörð Bjarmason
  0 siblings, 0 replies; 106+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-04 13:07 UTC (permalink / raw)
  To: Jeff King; +Cc: Lukáš Doktor, Christian Couder, git


On Fri, Nov 04 2022, Jeff King wrote:

> On Fri, Nov 04, 2022 at 12:36:12PM +0100, Ævar Arnfjörð Bjarmason wrote:
>
>> > It feels like the invocation of bisect--helper ought to be passing "--"
>> > itself to indicate the end of options, like:
>> 
>> Normally you'd be righ, but there's a much easier way to do it in this
>> case: cherry-pick
>> https://lore.kernel.org/git/05262b6a7d1b20a0d2f2ca2090be284ffb8c679c.1661885419.git.gitgitgadget@gmail.com/
>> 
>> I.e. we're eating "--log" in particular, but could just stop
>> understanding that option.
>
> We're not eating "--log" in particular, though. We're eating anything
> that parse_options() understands. It would eat "--bisect-start", too.
> That's less likely than "--log", but the fundamental problem would still
> remain.

Right, I mean the regression's anyone's likely to care
about. I.e. that's an easy fix, I think run scripts using --bisect-*
options are probably unlikely to exist.

But yes, the ultimate fix is to use OPT_SUBCOMMAND(), but getting there
takes more time...

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

* [PATCH 00/13] bisect: v2.30.0 "run" regressions + make it built-in
  2022-11-04  6:31 "git bisect run" strips "--log" from the list of arguments Lukáš Doktor
  2022-11-04  9:45 ` Jeff King
  2022-11-04 11:40 ` [PATCH 0/3] Convert git-bisect--helper to OPT_SUBCOMMAND Đoàn Trần Công Danh
@ 2022-11-04 13:22 ` Ævar Arnfjörð Bjarmason
  2022-11-04 13:22   ` [PATCH 01/13] bisect tests: test for v2.30.0 "bisect run" regressions Ævar Arnfjörð Bjarmason
                     ` (14 more replies)
  2 siblings, 15 replies; 106+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-04 13:22 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Jeff King, Taylor Blau,
	Đoàn Trần Công Danh, SZEDER Gábor,
	Lukáš Doktor, Johannes Schindelin,
	Ævar Arnfjörð Bjarmason

This fixes the regression Lukáš Doktor reported in [1], and also gets
us the full way to a builtin/bisect.c and "git rm git-bisect.sh".

Only 1-4/13 here are needed to fix the "git bisect run <cmd> [...]
--log" regression Lukáš reported, but as Jeff points out we'd still
conflate "--bisect-*" with the user arguments. That's fixed in 11/13
here.

The 1-4/13 here also fixes other but probably more minor "git bisect
run" regressions in v2.30.0, we changed the output in a few ways
without intending it. 4/13 gets us mostly back to v2.29.0 behavior,
5/13 keeps the best of it and the current output.

I think for the v2.30.0 regressions we're better off with just
something like 1-4/13 here for now, and possibly 5/13 too.

But getting to the point of fixing the root cause of "--bisect-*"
being conflated is going to take quite a bit of churn. In the
side-thread Đoàn's diffstat is on the order of 1/2 of the size of this
series, and this gives us built-in "bisect".

The 6-13 here is something I had already for a couple of days, I was
seeing if I could distill Johannes's [2] down to something much
smaller, to just make a beeline towards a built-in bisect.

Johannes's refactors the "term" passing in [3], and Đoàn ends up
needing to do much the same in [4].

Here in 9/13 I instead just extend the OPT_SUBCOMMAND() API so it's
able to accept function callbacks with custom signatures, which
eliminates the need for most of that refactoring. 11/13 then makes use
of it.

1. https://lore.kernel.org/git/1cb1c033-0525-7e62-8c09-81019bf26060@redhat.com/
2. https://lore.kernel.org/git/pull.1132.v6.git.1661885419.gitgitgadget@gmail.com/
3. https://lore.kernel.org/git/92b3b116ef8f879192d9deb94d68b73e29d5dcd6.1661885419.git.gitgitgadget@gmail.com/
4. https://lore.kernel.org/git/081f3f7f9501012404fb9e59ab6d94f632180b53.1667561761.git.congdanhqx@gmail.com/

Johannes Schindelin (3):
  bisect--helper: remove dead --bisect-{next-check,autostart} code
  bisect--helper: make `state` optional
  Turn `git bisect` into a full built-in

Ævar Arnfjörð Bjarmason (10):
  bisect tests: test for v2.30.0 "bisect run" regressions
  bisect: refactor bisect_run() to match CodingGuidelines
  bisect: fix output regressions in v2.30.0
  bisect run: fix "--log" eating regression in v2.30.0
  bisect run: keep some of the post-v2.30.0 output
  bisect test: test exit codes on bad usage
  bisect--helper: emit usage for "git bisect"
  bisect--helper: have all functions take state, argc, argv, prefix
  parse-options API: don't restrict OPT_SUBCOMMAND() to one *_fn  type
  bisect--helper: convert to OPT_SUBCOMMAND_CB()

 Makefile                               |   3 +-
 builtin.h                              |   2 +-
 builtin/{bisect--helper.c => bisect.c} | 250 +++++++++++++------------
 git-bisect.sh                          |  84 ---------
 git.c                                  |   2 +-
 parse-options.c                        |   9 +-
 parse-options.h                        |  31 ++-
 t/t6030-bisect-porcelain.sh            | 109 +++++++++++
 8 files changed, 277 insertions(+), 213 deletions(-)
 rename builtin/{bisect--helper.c => bisect.c} (86%)
 delete mode 100755 git-bisect.sh

-- 
2.38.0.1452.g710f45c7951


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

* [PATCH 01/13] bisect tests: test for v2.30.0 "bisect run" regressions
  2022-11-04 13:22 ` [PATCH 00/13] bisect: v2.30.0 "run" regressions + make it built-in Ævar Arnfjörð Bjarmason
@ 2022-11-04 13:22   ` Ævar Arnfjörð Bjarmason
  2022-11-04 13:22   ` [PATCH 02/13] bisect: refactor bisect_run() to match CodingGuidelines Ævar Arnfjörð Bjarmason
                     ` (13 subsequent siblings)
  14 siblings, 0 replies; 106+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-04 13:22 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Jeff King, Taylor Blau,
	Đoàn Trần Công Danh, SZEDER Gábor,
	Lukáš Doktor, Johannes Schindelin,
	Ævar Arnfjörð Bjarmason

Add three failing tests which succeed on v2.29.0, but due to the topic
merged at [1] (specifically [2]) have been failing since then. We'll
address those regressions in subsequent commits.

There was also a "regression" where:

	git bisect run ./missing-script.sh

Would count a non-existing script as "good", as the shell would exit
with 127. That edge case is a bit too insane to preserve, so let's not
add it to these regression tests.

1. 0a4cb1f1f2f (Merge branch 'mr/bisect-in-c-4', 2021-09-23)
2. d1bbbe45df8 (bisect--helper: reimplement `bisect_run` shell
   function in C, 2021-09-13)

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 t/t6030-bisect-porcelain.sh | 79 +++++++++++++++++++++++++++++++++++++
 1 file changed, 79 insertions(+)

diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh
index 83931d482fb..478e74e1f0f 100755
--- a/t/t6030-bisect-porcelain.sh
+++ b/t/t6030-bisect-porcelain.sh
@@ -252,6 +252,85 @@ test_expect_success 'bisect skip: with commit both bad and skipped' '
 	grep $HASH4 my_bisect_log.txt
 '
 
+test_bisect_run_args () {
+	test_when_finished "rm -f run.sh actual" &&
+	>actual &&
+	cat >expect.args &&
+	cat <&6 >expect.out &&
+	cat <&7 >expect.err &&
+	write_script run.sh <<-\EOF &&
+	while test $# != 0
+	do
+		echo "<$1>" &&
+		shift
+	done >actual.args
+	EOF
+
+	test_when_finished "git bisect reset" &&
+	git bisect start &&
+	git bisect good $HASH1 &&
+	git bisect bad $HASH4 &&
+	git bisect run ./run.sh $@ >actual.out.raw 2>actual.err &&
+	# Prune just the log output
+	sed -n \
+		-e '/^Author:/d' \
+		-e '/^Date:/d' \
+		-e '/^$/d' \
+		-e '/^commit /d' \
+ 		-e '/^ /d' \
+		-e 'p' \
+		<actual.out.raw >actual.out &&
+	test_cmp expect.out actual.out &&
+	test_cmp expect.err actual.err &&
+	test_cmp expect.args actual.args
+}
+
+test_expect_failure 'git bisect run: args, stdout and stderr with no arguments' '
+	test_bisect_run_args <<-\EOF_ARGS 6<<-EOF_OUT 7<<-\EOF_ERR
+	EOF_ARGS
+	running ./run.sh
+	$HASH4 is the first bad commit
+	bisect run success
+	EOF_OUT
+	EOF_ERR
+'
+
+test_expect_failure 'git bisect run: args, stdout and stderr: "--" argument' '
+	test_bisect_run_args -- <<-\EOF_ARGS 6<<-EOF_OUT 7<<-\EOF_ERR
+	<-->
+	EOF_ARGS
+	running ./run.sh --
+	$HASH4 is the first bad commit
+	bisect run success
+	EOF_OUT
+	EOF_ERR
+'
+
+test_expect_failure 'git bisect run: args, stdout and stderr: "--log foo --no-log bar" arguments' '
+	test_bisect_run_args --log foo --no-log bar <<-\EOF_ARGS 6<<-EOF_OUT 7<<-\EOF_ERR
+	<--log>
+	<foo>
+	<--no-log>
+	<bar>
+	EOF_ARGS
+	running ./run.sh --log foo --no-log bar
+	$HASH4 is the first bad commit
+	bisect run success
+	EOF_OUT
+	EOF_ERR
+'
+
+test_expect_failure 'git bisect run: args, stdout and stderr: "--bisect-start" argument' '
+	test_bisect_run_args --bisect-start <<-\EOF_ARGS 6<<-EOF_OUT 7<<-\EOF_ERR
+	<--bisect-start>
+	EOF_ARGS
+	running ./run.sh --bisect-start
+	$HASH4 is the first bad commit
+	bisect run success
+	EOF_OUT
+	EOF_ERR
+'
+
 # We want to automatically find the commit that
 # added "Another" into hello.
 test_expect_success '"git bisect run" simple case' '
-- 
2.38.0.1452.g710f45c7951


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

* [PATCH 02/13] bisect: refactor bisect_run() to match CodingGuidelines
  2022-11-04 13:22 ` [PATCH 00/13] bisect: v2.30.0 "run" regressions + make it built-in Ævar Arnfjörð Bjarmason
  2022-11-04 13:22   ` [PATCH 01/13] bisect tests: test for v2.30.0 "bisect run" regressions Ævar Arnfjörð Bjarmason
@ 2022-11-04 13:22   ` Ævar Arnfjörð Bjarmason
  2022-11-04 13:22   ` [PATCH 03/13] bisect: fix output regressions in v2.30.0 Ævar Arnfjörð Bjarmason
                     ` (12 subsequent siblings)
  14 siblings, 0 replies; 106+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-04 13:22 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Jeff King, Taylor Blau,
	Đoàn Trần Công Danh, SZEDER Gábor,
	Lukáš Doktor, Johannes Schindelin,
	Ævar Arnfjörð Bjarmason

We didn't add "{}" to all "if/else" branches, and one "error" was
mis-indented. Let's fix that first, which makes subsequent commits
smaller. In the case of the "if" we can simply early return instead.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 builtin/bisect--helper.c | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 28ef7ec2a48..7dd90da72d3 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1185,13 +1185,12 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
 	if (bisect_next_check(terms, NULL))
 		return BISECT_FAILED;
 
-	if (argc)
-		sq_quote_argv(&command, argv);
-	else {
+	if (!argc) {
 		error(_("bisect run failed: no command provided."));
 		return BISECT_FAILED;
 	}
 
+	sq_quote_argv(&command, argv);
 	strvec_push(&run_args, command.buf);
 
 	while (1) {
@@ -1265,7 +1264,7 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
 			res = BISECT_OK;
 		} else if (res) {
 			error(_("bisect run failed: 'git bisect--helper --bisect-state"
-			" %s' exited with error code %d"), new_state, res);
+				" %s' exited with error code %d"), new_state, res);
 		} else {
 			continue;
 		}
-- 
2.38.0.1452.g710f45c7951


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

* [PATCH 03/13] bisect: fix output regressions in v2.30.0
  2022-11-04 13:22 ` [PATCH 00/13] bisect: v2.30.0 "run" regressions + make it built-in Ævar Arnfjörð Bjarmason
  2022-11-04 13:22   ` [PATCH 01/13] bisect tests: test for v2.30.0 "bisect run" regressions Ævar Arnfjörð Bjarmason
  2022-11-04 13:22   ` [PATCH 02/13] bisect: refactor bisect_run() to match CodingGuidelines Ævar Arnfjörð Bjarmason
@ 2022-11-04 13:22   ` Ævar Arnfjörð Bjarmason
  2022-11-04 13:22   ` [PATCH 04/13] bisect run: fix "--log" eating regression " Ævar Arnfjörð Bjarmason
                     ` (11 subsequent siblings)
  14 siblings, 0 replies; 106+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-04 13:22 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Jeff King, Taylor Blau,
	Đoàn Trần Công Danh, SZEDER Gábor,
	Lukáš Doktor, Johannes Schindelin,
	Ævar Arnfjörð Bjarmason

When d1bbbe45df8 (bisect--helper: reimplement `bisect_run` shell
function in C, 2021-09-13) reimplemented parts of "git bisect run" in
C it changed the output we emitted so that:

 - The "running ..." line was now quoted
 - We lost the \n after our output
 - We started saying "bisect found ..." instead of "bisect run success"

Arguably some of this is better now, but as d1bbbe45df8 did not
advocate for changing the output, let's revert this for now. It'll be
easy to change it back if that's what we'd prefer.

This does not change the one remaining use of "command.buf" to emit
the quoted argument, as that's new in d1bbbe45df8.

Some of these cases were not tested for in the tests added in the
preceding commit, I didn't have time to fleshen those out, but a look
at f1de981e8b6 will show that the other output being adjusted here is
now equivalent to what it was before d1bbbe45df8.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 builtin/bisect--helper.c    | 8 +++++---
 t/t6030-bisect-porcelain.sh | 4 ++--
 2 files changed, 7 insertions(+), 5 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 7dd90da72d3..ee1509c198a 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1192,6 +1192,8 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
 
 	sq_quote_argv(&command, argv);
 	strvec_push(&run_args, command.buf);
+	strbuf_reset(&command);
+	strbuf_join_argv(&command, argc, argv, ' ');
 
 	while (1) {
 		printf(_("running %s\n"), command.buf);
@@ -1257,13 +1259,13 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
 		if (res == BISECT_ONLY_SKIPPED_LEFT)
 			error(_("bisect run cannot continue any more"));
 		else if (res == BISECT_INTERNAL_SUCCESS_MERGE_BASE) {
-			printf(_("bisect run success"));
+			puts(_("bisect run success"));
 			res = BISECT_OK;
 		} else if (res == BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND) {
-			printf(_("bisect found first bad commit"));
+			puts(_("bisect run success"));
 			res = BISECT_OK;
 		} else if (res) {
-			error(_("bisect run failed: 'git bisect--helper --bisect-state"
+			error(_("bisect run failed: 'bisect-state"
 				" %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 478e74e1f0f..30124b6f059 100755
--- a/t/t6030-bisect-porcelain.sh
+++ b/t/t6030-bisect-porcelain.sh
@@ -285,7 +285,7 @@ test_bisect_run_args () {
 	test_cmp expect.args actual.args
 }
 
-test_expect_failure 'git bisect run: args, stdout and stderr with no arguments' '
+test_expect_success 'git bisect run: args, stdout and stderr with no arguments' '
 	test_bisect_run_args <<-\EOF_ARGS 6<<-EOF_OUT 7<<-\EOF_ERR
 	EOF_ARGS
 	running ./run.sh
@@ -295,7 +295,7 @@ test_expect_failure 'git bisect run: args, stdout and stderr with no arguments'
 	EOF_ERR
 '
 
-test_expect_failure 'git bisect run: args, stdout and stderr: "--" argument' '
+test_expect_success 'git bisect run: args, stdout and stderr: "--" argument' '
 	test_bisect_run_args -- <<-\EOF_ARGS 6<<-EOF_OUT 7<<-\EOF_ERR
 	<-->
 	EOF_ARGS
-- 
2.38.0.1452.g710f45c7951


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

* [PATCH 04/13] bisect run: fix "--log" eating regression in v2.30.0
  2022-11-04 13:22 ` [PATCH 00/13] bisect: v2.30.0 "run" regressions + make it built-in Ævar Arnfjörð Bjarmason
                     ` (2 preceding siblings ...)
  2022-11-04 13:22   ` [PATCH 03/13] bisect: fix output regressions in v2.30.0 Ævar Arnfjörð Bjarmason
@ 2022-11-04 13:22   ` Ævar Arnfjörð Bjarmason
  2022-11-04 13:22   ` [PATCH 05/13] bisect run: keep some of the post-v2.30.0 output Ævar Arnfjörð Bjarmason
                     ` (10 subsequent siblings)
  14 siblings, 0 replies; 106+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-04 13:22 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Jeff King, Taylor Blau,
	Đoàn Trần Công Danh, SZEDER Gábor,
	Lukáš Doktor, Johannes Schindelin,
	Ævar Arnfjörð Bjarmason, Johannes Schindelin

When d1bbbe45df8 (bisect--helper: reimplement `bisect_run` shell
function in C, 2021-09-13) reimplemented parts of "git bisect run" in
C we started parsing the command line that we'd pass to "run" with
cmd_bisect__helper().

Unfortunately this meant that we started eating "--log" and "--no-log"
on the command-line.

In the general case the fix for this would be more involved, but
luckily we don't support any other option here (well, the other
CMDMODE options, but that edge case is too obscure to worry about).

As noted in [1] we can simply remove the "--no-log" option. It was
added in 0f30233a11f (bisect--helper: `bisect_write` shell function in
C, 2019-01-02), but has never been used.

Reported-by: Lukáš Doktor <ldoktor@redhat.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 builtin/bisect--helper.c    | 4 +---
 t/t6030-bisect-porcelain.sh | 2 +-
 2 files changed, 2 insertions(+), 4 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index ee1509c198a..eb66ad491cd 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1294,7 +1294,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),
@@ -1318,8 +1318,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 };
diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh
index 30124b6f059..dc83034f036 100755
--- a/t/t6030-bisect-porcelain.sh
+++ b/t/t6030-bisect-porcelain.sh
@@ -306,7 +306,7 @@ test_expect_success 'git bisect run: args, stdout and stderr: "--" argument' '
 	EOF_ERR
 '
 
-test_expect_failure 'git bisect run: args, stdout and stderr: "--log foo --no-log bar" arguments' '
+test_expect_success 'git bisect run: args, stdout and stderr: "--log foo --no-log bar" arguments' '
 	test_bisect_run_args --log foo --no-log bar <<-\EOF_ARGS 6<<-EOF_OUT 7<<-\EOF_ERR
 	<--log>
 	<foo>
-- 
2.38.0.1452.g710f45c7951


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

* [PATCH 05/13] bisect run: keep some of the post-v2.30.0 output
  2022-11-04 13:22 ` [PATCH 00/13] bisect: v2.30.0 "run" regressions + make it built-in Ævar Arnfjörð Bjarmason
                     ` (3 preceding siblings ...)
  2022-11-04 13:22   ` [PATCH 04/13] bisect run: fix "--log" eating regression " Ævar Arnfjörð Bjarmason
@ 2022-11-04 13:22   ` Ævar Arnfjörð Bjarmason
  2022-11-04 13:22   ` [PATCH 06/13] bisect test: test exit codes on bad usage Ævar Arnfjörð Bjarmason
                     ` (9 subsequent siblings)
  14 siblings, 0 replies; 106+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-04 13:22 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Jeff King, Taylor Blau,
	Đoàn Trần Công Danh, SZEDER Gábor,
	Lukáš Doktor, Johannes Schindelin,
	Ævar Arnfjörð Bjarmason

Preceding commits fixed output and behavior regressions in
d1bbbe45df8 (bisect--helper: reimplement `bisect_run` shell function
in C, 2021-09-13), which did not claim to be changing the output of
"git bisect run".

But some of the output it emitted was subjectively better, so once
we've asserted that we're back on v2.29.0 behavior, let's change some
of it back:

- We now quote the arguments again, but omit the first " " when
  printing the "running" line.
- Ditto for other cases where we emitted the argument
- We say "found first bad commit" again, not just "run success"

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 builtin/bisect--helper.c    |  6 +++---
 t/t6030-bisect-porcelain.sh | 16 ++++++++--------
 2 files changed, 11 insertions(+), 11 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index eb66ad491cd..5c0572d0672 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1192,8 +1192,8 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
 
 	sq_quote_argv(&command, argv);
 	strvec_push(&run_args, command.buf);
-	strbuf_reset(&command);
-	strbuf_join_argv(&command, argc, argv, ' ');
+	/* Quoted, but skip initial " " */
+	strbuf_ltrim(&command);
 
 	while (1) {
 		printf(_("running %s\n"), command.buf);
@@ -1262,7 +1262,7 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
 			puts(_("bisect run success"));
 			res = BISECT_OK;
 		} else if (res == BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND) {
-			puts(_("bisect run success"));
+			puts(_("bisect found first bad commit"));
 			res = BISECT_OK;
 		} else if (res) {
 			error(_("bisect run failed: 'bisect-state"
diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh
index dc83034f036..69fad3f94f6 100755
--- a/t/t6030-bisect-porcelain.sh
+++ b/t/t6030-bisect-porcelain.sh
@@ -288,9 +288,9 @@ test_bisect_run_args () {
 test_expect_success 'git bisect run: args, stdout and stderr with no arguments' '
 	test_bisect_run_args <<-\EOF_ARGS 6<<-EOF_OUT 7<<-\EOF_ERR
 	EOF_ARGS
-	running ./run.sh
+	running '\''./run.sh'\''
 	$HASH4 is the first bad commit
-	bisect run success
+	bisect found first bad commit
 	EOF_OUT
 	EOF_ERR
 '
@@ -299,9 +299,9 @@ test_expect_success 'git bisect run: args, stdout and stderr: "--" argument' '
 	test_bisect_run_args -- <<-\EOF_ARGS 6<<-EOF_OUT 7<<-\EOF_ERR
 	<-->
 	EOF_ARGS
-	running ./run.sh --
+	running '\''./run.sh'\'' '\''--'\''
 	$HASH4 is the first bad commit
-	bisect run success
+	bisect found first bad commit
 	EOF_OUT
 	EOF_ERR
 '
@@ -313,9 +313,9 @@ test_expect_success 'git bisect run: args, stdout and stderr: "--log foo --no-lo
 	<--no-log>
 	<bar>
 	EOF_ARGS
-	running ./run.sh --log foo --no-log bar
+	running '\''./run.sh'\'' '\''--log'\'' '\''foo'\'' '\''--no-log'\'' '\''bar'\''
 	$HASH4 is the first bad commit
-	bisect run success
+	bisect found first bad commit
 	EOF_OUT
 	EOF_ERR
 '
@@ -324,9 +324,9 @@ test_expect_failure 'git bisect run: args, stdout and stderr: "--bisect-start" a
 	test_bisect_run_args --bisect-start <<-\EOF_ARGS 6<<-EOF_OUT 7<<-\EOF_ERR
 	<--bisect-start>
 	EOF_ARGS
-	running ./run.sh --bisect-start
+	running '\''./run.sh'\'' '\''--bisect-start'\''
 	$HASH4 is the first bad commit
-	bisect run success
+	bisect found first bad commit
 	EOF_OUT
 	EOF_ERR
 '
-- 
2.38.0.1452.g710f45c7951


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

* [PATCH 06/13] bisect test: test exit codes on bad usage
  2022-11-04 13:22 ` [PATCH 00/13] bisect: v2.30.0 "run" regressions + make it built-in Ævar Arnfjörð Bjarmason
                     ` (4 preceding siblings ...)
  2022-11-04 13:22   ` [PATCH 05/13] bisect run: keep some of the post-v2.30.0 output Ævar Arnfjörð Bjarmason
@ 2022-11-04 13:22   ` Ævar Arnfjörð Bjarmason
  2022-11-04 13:22   ` [PATCH 07/13] bisect--helper: emit usage for "git bisect" Ævar Arnfjörð Bjarmason
                     ` (8 subsequent siblings)
  14 siblings, 0 replies; 106+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-04 13:22 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Jeff King, Taylor Blau,
	Đoàn Trần Công Danh, SZEDER Gábor,
	Lukáš Doktor, Johannes Schindelin,
	Ævar Arnfjörð Bjarmason

Address a test blindspot, the "log" command is the odd one out because
"git-bisect.sh" ignores any arguments it receives. Let's test both the
exit codes we expect, and the stderr and stdout we're emitting.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 t/t6030-bisect-porcelain.sh | 30 ++++++++++++++++++++++++++++++
 1 file changed, 30 insertions(+)

diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh
index 69fad3f94f6..eace0af637e 100755
--- a/t/t6030-bisect-porcelain.sh
+++ b/t/t6030-bisect-porcelain.sh
@@ -34,6 +34,36 @@ HASH2=
 HASH3=
 HASH4=
 
+test_bisect_usage () {
+	local code="$1" &&
+	shift &&
+	cat >expect &&
+	test_expect_code $code "$@" >out 2>actual &&
+	test_must_be_empty out &&
+	test_cmp expect actual
+}
+
+test_expect_success 'bisect usage' '
+	test_bisect_usage 255 git bisect reset extra1 extra2 <<-\EOF &&
+	error: --bisect-reset requires either no argument or a commit
+	EOF
+	test_bisect_usage 255 git bisect terms extra1 extra2 <<-\EOF &&
+	error: --bisect-terms requires 0 or 1 argument
+	EOF
+	test_bisect_usage 255 git bisect next extra1 <<-\EOF &&
+	error: --bisect-next requires 0 arguments
+	EOF
+	test_bisect_usage 1 git bisect log extra1 <<-\EOF &&
+	error: We are not bisecting.
+	EOF
+	test_bisect_usage 255 git bisect replay <<-\EOF &&
+	error: no logfile given
+	EOF
+	test_bisect_usage 255 git bisect run <<-\EOF
+	error: bisect run failed: no command provided.
+	EOF
+'
+
 test_expect_success 'set up basic repo with 1 file (hello) and 4 commits' '
      add_line_into_file "1: Hello World" hello &&
      HASH1=$(git rev-parse --verify HEAD) &&
-- 
2.38.0.1452.g710f45c7951


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

* [PATCH 07/13] bisect--helper: emit usage for "git bisect"
  2022-11-04 13:22 ` [PATCH 00/13] bisect: v2.30.0 "run" regressions + make it built-in Ævar Arnfjörð Bjarmason
                     ` (5 preceding siblings ...)
  2022-11-04 13:22   ` [PATCH 06/13] bisect test: test exit codes on bad usage Ævar Arnfjörð Bjarmason
@ 2022-11-04 13:22   ` Ævar Arnfjörð Bjarmason
  2022-11-04 13:22   ` [PATCH 08/13] bisect--helper: have all functions take state, argc, argv, prefix Ævar Arnfjörð Bjarmason
                     ` (7 subsequent siblings)
  14 siblings, 0 replies; 106+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-04 13:22 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Jeff King, Taylor Blau,
	Đoàn Trần Công Danh, SZEDER Gábor,
	Lukáš Doktor, Johannes Schindelin,
	Ævar Arnfjörð Bjarmason

In subsequent commits we'll be removing "git-bisect.sh" in favor of
promoting "bisect--helper" to a "bisect" built-in.

In doing that we'll first need to have it support "git bisect--helper
<cmd>" rather than "git bisect--helper --<cmd>", and then finally have
its "-h" output claim to be "bisect" rather than "bisect--helper".

Instead of suffering that churn let's start claiming to be "git
bisect" now. In just a few commits this will be true, and in the
meantime emitting the "wrong" usage information from the helper is a
small price to pay to avoid the churn.

Let's also declare "BUILTIN_*" macros, when we eventually migrate the
sub-commands themselves to parse_options() we'll be able to re-use the
strings. See 0afd556b2e1 (worktree: define subcommand -h in terms of
command -h, 2022-10-13) for a recent example.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 builtin/bisect--helper.c | 51 ++++++++++++++++++++++++++++------------
 1 file changed, 36 insertions(+), 15 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 5c0572d0672..b10ecee64cc 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -20,18 +20,40 @@ 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>..."),
+#define BUILTIN_GIT_BISECT_START_USAGE \
+	N_("git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>]" \
+	   "    [--no-checkout] [--first-parent] [<bad> [<good>...]] [--]" \
+	   "    [<pathspec>...]")
+#define BUILTIN_GIT_BISECT_STATE_USAGE \
+	N_("git bisect (good|bad) [<rev>...]")
+#define BUILTIN_GIT_BISECT_TERMS_USAGE \
+	"git bisect terms [--term-good | --term-bad]"
+#define BUILTIN_GIT_BISECT_SKIP_USAGE \
+	N_("git bisect skip [(<rev>|<range>)...]")
+#define BUILTIN_GIT_BISECT_NEXT_USAGE \
+	"git bisect next"
+#define BUILTIN_GIT_BISECT_RESET_USAGE \
+	N_("git bisect reset [<commit>]")
+#define BUILTIN_GIT_BISECT_VISUALIZE_USAGE \
+	"git bisect visualize"
+#define BUILTIN_GIT_BISECT_REPLAY_USAGE \
+	N_("git bisect replay <logfile>")
+#define BUILTIN_GIT_BISECT_LOG_USAGE \
+	"git bisect log"
+#define BUILTIN_GIT_BISECT_RUN_USAGE \
+	N_("git bisect run <cmd>...")
+
+static const char * const git_bisect_usage[] = {
+	BUILTIN_GIT_BISECT_START_USAGE,
+	BUILTIN_GIT_BISECT_STATE_USAGE,
+	BUILTIN_GIT_BISECT_TERMS_USAGE,
+	BUILTIN_GIT_BISECT_SKIP_USAGE,
+	BUILTIN_GIT_BISECT_NEXT_USAGE,
+	BUILTIN_GIT_BISECT_RESET_USAGE,
+	BUILTIN_GIT_BISECT_VISUALIZE_USAGE,
+	BUILTIN_GIT_BISECT_REPLAY_USAGE,
+	BUILTIN_GIT_BISECT_LOG_USAGE,
+	BUILTIN_GIT_BISECT_RUN_USAGE,
 	NULL
 };
 
@@ -1322,12 +1344,11 @@ 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,
+	argc = parse_options(argc, argv, prefix, options, git_bisect_usage,
 			     PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN_OPT);
 
 	if (!cmdmode)
-		usage_with_options(git_bisect_helper_usage, options);
+		usage_with_options(git_bisect_usage, options);
 
 	switch (cmdmode) {
 	case BISECT_RESET:
-- 
2.38.0.1452.g710f45c7951


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

* [PATCH 08/13] bisect--helper: have all functions take state, argc, argv, prefix
  2022-11-04 13:22 ` [PATCH 00/13] bisect: v2.30.0 "run" regressions + make it built-in Ævar Arnfjörð Bjarmason
                     ` (6 preceding siblings ...)
  2022-11-04 13:22   ` [PATCH 07/13] bisect--helper: emit usage for "git bisect" Ævar Arnfjörð Bjarmason
@ 2022-11-04 13:22   ` Ævar Arnfjörð Bjarmason
  2022-11-04 13:22   ` [PATCH 09/13] parse-options API: don't restrict OPT_SUBCOMMAND() to one *_fn type Ævar Arnfjörð Bjarmason
                     ` (6 subsequent siblings)
  14 siblings, 0 replies; 106+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-04 13:22 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Jeff King, Taylor Blau,
	Đoàn Trần Công Danh, SZEDER Gábor,
	Lukáš Doktor, Johannes Schindelin,
	Ævar Arnfjörð Bjarmason

In order to use the OPT_SUBCOMMAND() API in a subsequent commit give
all of the bisect_*() functions a consistent prototype we'll be able
to use.

The "prefix" parameter is only used by bisect_next(), bisect_log()
doesn't need any of them, etc. The UNUSED attribute helps us to sanity
check the current use.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 builtin/bisect--helper.c | 70 ++++++++++++++++++++++++----------------
 1 file changed, 42 insertions(+), 28 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index b10ecee64cc..32e427fa878 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -223,8 +223,10 @@ static int write_terms(const char *bad, const char *good)
 	return res;
 }
 
-static int bisect_reset(const char *commit)
+static int bisect_reset(struct bisect_terms *terms UNUSED, int argc, const char **argv,
+			const char *prefix UNUSED)
 {
+	const char *commit = argc ? argv[0] : NULL;
 	struct strbuf branch = STRBUF_INIT;
 
 	if (!commit) {
@@ -492,8 +494,10 @@ static int get_terms(struct bisect_terms *terms)
 	return res;
 }
 
-static int bisect_terms(struct bisect_terms *terms, const char *option)
+static int bisect_terms(struct bisect_terms *terms,  int argc, const char **argv,
+			const char *prefix UNUSED)
 {
+	const char *option = argc ? argv[0] : NULL;
 	if (get_terms(terms))
 		return error(_("no terms defined"));
 
@@ -646,7 +650,8 @@ static int bisect_successful(struct bisect_terms *terms)
 	return res;
 }
 
-static enum bisect_error bisect_next(struct bisect_terms *terms, const char *prefix)
+static int bisect_next(struct bisect_terms *terms, int argc UNUSED,
+		       const char **argv UNUSED, const char *prefix)
 {
 	enum bisect_error res;
 
@@ -676,10 +681,11 @@ static enum bisect_error bisect_auto_next(struct bisect_terms *terms, const char
 		return BISECT_OK;
 	}
 
-	return bisect_next(terms, prefix);
+	return bisect_next(terms, 0, empty_strvec, prefix);
 }
 
-static enum bisect_error bisect_start(struct bisect_terms *terms, const char **argv, int argc)
+static int bisect_start(struct bisect_terms *terms, int argc,
+			const char **argv, const char *prefix UNUSED)
 {
 	int no_checkout = 0;
 	int first_parent_only = 0;
@@ -907,13 +913,13 @@ 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(terms, 0, empty_strvec, NULL);
 
 	return res;
 }
 
-static enum bisect_error bisect_state(struct bisect_terms *terms, const char **argv,
-				      int argc)
+static int bisect_state(struct bisect_terms *terms, int argc,
+			const char **argv, const char *prefix UNUSED)
 {
 	const char *state;
 	int i, verify_expected = 1;
@@ -993,7 +999,9 @@ static enum bisect_error bisect_state(struct bisect_terms *terms, const char **a
 	return bisect_auto_next(terms, NULL);
 }
 
-static enum bisect_error bisect_log(void)
+static int bisect_log(struct bisect_terms *terms UNUSED,
+		      int argc UNUSED, const char **argv UNUSED,
+		      const char *prefix UNUSED)
 {
 	int fd, status;
 	const char* filename = git_path_bisect_log();
@@ -1032,7 +1040,7 @@ static int process_replay_line(struct bisect_terms *terms, struct strbuf *line)
 		struct strvec argv = STRVEC_INIT;
 		int res;
 		sq_dequote_to_strvec(rev, &argv);
-		res = bisect_start(terms, argv.v, argv.nr);
+		res = bisect_start(terms, argv.nr, argv.v, NULL);
 		strvec_clear(&argv);
 		return res;
 	}
@@ -1045,7 +1053,7 @@ static int process_replay_line(struct bisect_terms *terms, struct strbuf *line)
 		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(terms, argv.nr, argv.v, NULL);
 		strvec_clear(&argv);
 		return res;
 	}
@@ -1054,8 +1062,10 @@ 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 int bisect_replay(struct bisect_terms *terms, int argc UNUSED,
+			 const char **argv, const char *prefix UNUSED)
 {
+	const char *filename = argv[0];
 	FILE *fp = NULL;
 	enum bisect_error res = BISECT_OK;
 	struct strbuf line = STRBUF_INIT;
@@ -1063,7 +1073,7 @@ static enum bisect_error bisect_replay(struct bisect_terms *terms, const char *f
 	if (is_empty_or_missing_file(filename))
 		return error(_("cannot read file '%s' for replaying"), filename);
 
-	if (bisect_reset(NULL))
+	if (bisect_reset(NULL, 0, empty_strvec, NULL))
 		return BISECT_FAILED;
 
 	fp = fopen(filename, "r");
@@ -1082,7 +1092,9 @@ static enum bisect_error bisect_replay(struct bisect_terms *terms, const char *f
 	return bisect_auto_next(terms, NULL);
 }
 
-static enum bisect_error bisect_skip(struct bisect_terms *terms, const char **argv, int argc)
+static enum bisect_error bisect_skip(struct bisect_terms *terms,  int argc,
+				     const char **argv,
+				     const char *prefix UNUSED)
 {
 	int i;
 	enum bisect_error res;
@@ -1112,13 +1124,14 @@ 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(terms, argv_state.nr, argv_state.v, NULL);
 
 	strvec_clear(&argv_state);
 	return res;
 }
 
-static int bisect_visualize(struct bisect_terms *terms, const char **argv, int argc)
+static int bisect_visualize(struct bisect_terms *terms, int argc,
+			    const char **argv, const char *prefix UNUSED)
 {
 	struct strvec args = STRVEC_INIT;
 	int flags = RUN_COMMAND_NO_STDIN, res = 0;
@@ -1195,7 +1208,8 @@ 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(struct bisect_terms *terms,  int argc,
+		      const char **argv, const char *prefix UNUSED)
 {
 	int res = BISECT_OK;
 	struct strbuf command = STRBUF_INIT;
@@ -1269,7 +1283,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(terms, 1, &new_state, NULL);
 
 		fflush(stdout);
 		dup2(saved_stdout, 1);
@@ -1354,53 +1368,53 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 	case BISECT_RESET:
 		if (argc > 1)
 			return error(_("--bisect-reset requires either no argument or a commit"));
-		res = bisect_reset(argc ? argv[0] : NULL);
+		res = bisect_reset(&terms, argc, argv, prefix);
 		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);
+		res = bisect_terms(&terms, argc, argv, prefix);
 		break;
 	case BISECT_START:
 		set_terms(&terms, "bad", "good");
-		res = bisect_start(&terms, argv, argc);
+		res = bisect_start(&terms, argc, argv, prefix);
 		break;
 	case BISECT_NEXT:
 		if (argc)
 			return error(_("--bisect-next requires 0 arguments"));
 		get_terms(&terms);
-		res = bisect_next(&terms, prefix);
+		res = bisect_next(&terms, argc, argv, prefix);
 		break;
 	case BISECT_STATE:
 		set_terms(&terms, "bad", "good");
 		get_terms(&terms);
-		res = bisect_state(&terms, argv, argc);
+		res = bisect_state(&terms, argc, argv, prefix);
 		break;
 	case BISECT_LOG:
 		if (argc)
 			return error(_("--bisect-log requires 0 arguments"));
-		res = bisect_log();
+		res = bisect_log(&terms, argc, argv, prefix);
 		break;
 	case BISECT_REPLAY:
 		if (argc != 1)
 			return error(_("no logfile given"));
 		set_terms(&terms, "bad", "good");
-		res = bisect_replay(&terms, argv[0]);
+		res = bisect_replay(&terms, argc, argv, prefix);
 		break;
 	case BISECT_SKIP:
 		set_terms(&terms, "bad", "good");
 		get_terms(&terms);
-		res = bisect_skip(&terms, argv, argc);
+		res = bisect_skip(&terms, argc, argv, prefix);
 		break;
 	case BISECT_VISUALIZE:
 		get_terms(&terms);
-		res = bisect_visualize(&terms, argv, argc);
+		res = bisect_visualize(&terms, argc, argv, prefix);
 		break;
 	case BISECT_RUN:
 		if (!argc)
 			return error(_("bisect run failed: no command provided."));
 		get_terms(&terms);
-		res = bisect_run(&terms, argv, argc);
+		res = bisect_run(&terms, argc, argv, prefix);
 		break;
 	default:
 		BUG("unknown subcommand %d", cmdmode);
-- 
2.38.0.1452.g710f45c7951


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

* [PATCH 09/13] parse-options API: don't restrict OPT_SUBCOMMAND() to one *_fn  type
  2022-11-04 13:22 ` [PATCH 00/13] bisect: v2.30.0 "run" regressions + make it built-in Ævar Arnfjörð Bjarmason
                     ` (7 preceding siblings ...)
  2022-11-04 13:22   ` [PATCH 08/13] bisect--helper: have all functions take state, argc, argv, prefix Ævar Arnfjörð Bjarmason
@ 2022-11-04 13:22   ` Ævar Arnfjörð Bjarmason
  2022-11-05  8:32     ` René Scharfe
  2022-11-04 13:22   ` [PATCH 10/13] bisect--helper: remove dead --bisect-{next-check,autostart} code Ævar Arnfjörð Bjarmason
                     ` (5 subsequent siblings)
  14 siblings, 1 reply; 106+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-04 13:22 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Jeff King, Taylor Blau,
	Đoàn Trần Công Danh, SZEDER Gábor,
	Lukáš Doktor, Johannes Schindelin,
	Ævar Arnfjörð Bjarmason

When the OPT_SUBCOMMAND() API was implemented in [1] it did so by
adding a new "subcommand_fn" member to "struct option", rather than
allowing the user of the API to pick the type of the function.

An advantage of mandating that "parse_opt_subcommand_fn" must be used
is that we'll get type checking for the function we're passing in, a
disadvantage is that we can't convert e.g. "builtin/bisect--helper.c"
easily to it, as its callbacks need their own argument.

Let's generalize this interface, while leaving in place a small hack
to give the existing API users their type safety. We assign to
"typecheck_subcommand_fn", but don't subsequently use it for
anything. Instead we use the "defval" and "value" members.

A subsequent commit will add a OPT_SUBCOMMAND() variant where the
"callback" isn't our default "parse_options_pick_subcommand" (and that
caller won't be able to use the type checking).

1. fa83cc834da (parse-options: add support for parsing subcommands,
   2022-08-19)

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 parse-options.c |  9 ++++++---
 parse-options.h | 25 +++++++++++++++++++++----
 2 files changed, 27 insertions(+), 7 deletions(-)

diff --git a/parse-options.c b/parse-options.c
index a1ec932f0f9..1d9e46c9dc7 100644
--- a/parse-options.c
+++ b/parse-options.c
@@ -427,7 +427,8 @@ static enum parse_opt_result parse_subcommand(const char *arg,
 	for (; options->type != OPTION_END; options++)
 		if (options->type == OPTION_SUBCOMMAND &&
 		    !strcmp(options->long_name, arg)) {
-			*(parse_opt_subcommand_fn **)options->value = options->subcommand_fn;
+			if (options->callback(options, arg, 0))
+				BUG("OPT_SUBCOMMAND callback returning non-zero");
 			return PARSE_OPT_SUBCOMMAND;
 		}
 
@@ -506,8 +507,10 @@ static void parse_options_check(const struct option *opts)
 			       "That case is not supported yet.");
 			break;
 		case OPTION_SUBCOMMAND:
-			if (!opts->value || !opts->subcommand_fn)
-				optbug(opts, "OPTION_SUBCOMMAND needs a value and a subcommand function");
+			if (!opts->value || !opts->callback)
+				optbug(opts, "OPTION_SUBCOMMAND needs a value and a callback function");
+			if (opts->ll_callback)
+				optbug(opts, "OPTION_SUBCOMMAND uses callback, not ll_callback");
 			if (!subcommand_value)
 				subcommand_value = opts->value;
 			else if (subcommand_value != opts->value)
diff --git a/parse-options.h b/parse-options.h
index b6ef86e0d15..61e3016c3fc 100644
--- a/parse-options.h
+++ b/parse-options.h
@@ -128,19 +128,24 @@ typedef int parse_opt_subcommand_fn(int argc, const char **argv,
  *			 the option takes optional argument.
  *
  * `callback`::
- *   pointer to the callback to use for OPTION_CALLBACK
+ *   pointer to the callback to use for OPTION_CALLBACK and OPTION_SUBCOMMAND.
  *
  * `defval`::
  *   default value to fill (*->value) with for PARSE_OPT_OPTARG.
  *   OPTION_{BIT,SET_INT} store the {mask,integer} to put in the value when met.
+ *   OPTION_SUBCOMMAND stores the pointer the function selected for
+ *   the subcommand.
+ *
  *   CALLBACKS can use it like they want.
  *
  * `ll_callback`::
  *   pointer to the callback to use for OPTION_LOWLEVEL_CALLBACK
  *
  * `subcommand_fn`::
- *   pointer to a function to use for OPTION_SUBCOMMAND.
- *   It will be put in value when the subcommand is given on the command line.
+ *   pointer to the callback used with OPT_SUBCOMMAND() and
+ *   OPT_SUBCOMMAND_F(). Internally we store the same value in
+ *   `defval`. This is only here to give the OPT_SUBCOMMAND{,_F}()
+ *   common case type safety.
  */
 struct option {
 	enum parse_opt_type type;
@@ -217,12 +222,24 @@ struct option {
 #define OPT_ALIAS(s, l, source_long_name) \
 	{ OPTION_ALIAS, (s), (l), (source_long_name) }
 
+static inline int parse_options_pick_subcommand_cb(const struct option *option,
+						   const char *arg UNUSED,
+						   int unset UNUSED)
+{
+	parse_opt_subcommand_fn *fn = (parse_opt_subcommand_fn *)option->defval;
+	*(parse_opt_subcommand_fn **)option->value = fn;
+	return 0;
+}
+
 #define OPT_SUBCOMMAND_F(l, v, fn, f) { \
 	.type = OPTION_SUBCOMMAND, \
 	.long_name = (l), \
 	.value = (v), \
 	.flags = (f), \
-	.subcommand_fn = (fn) }
+	.defval = (intptr_t)(fn), \
+	.subcommand_fn = (fn), \
+	.callback = parse_options_pick_subcommand_cb, \
+}
 #define OPT_SUBCOMMAND(l, v, fn)    OPT_SUBCOMMAND_F((l), (v), (fn), 0)
 
 /*
-- 
2.38.0.1452.g710f45c7951


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

* [PATCH 10/13] bisect--helper: remove dead --bisect-{next-check,autostart} code
  2022-11-04 13:22 ` [PATCH 00/13] bisect: v2.30.0 "run" regressions + make it built-in Ævar Arnfjörð Bjarmason
                     ` (8 preceding siblings ...)
  2022-11-04 13:22   ` [PATCH 09/13] parse-options API: don't restrict OPT_SUBCOMMAND() to one *_fn type Ævar Arnfjörð Bjarmason
@ 2022-11-04 13:22   ` Ævar Arnfjörð Bjarmason
  2022-11-04 13:22   ` [PATCH 11/13] bisect--helper: convert to OPT_SUBCOMMAND_CB() Ævar Arnfjörð Bjarmason
                     ` (4 subsequent siblings)
  14 siblings, 0 replies; 106+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-04 13:22 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Jeff King, Taylor Blau,
	Đoàn Trần Công Danh, SZEDER Gábor,
	Lukáš Doktor, Johannes Schindelin, Johannes Schindelin,
	Ævar Arnfjörð Bjarmason

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.

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>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 builtin/bisect--helper.c | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 32e427fa878..e13c60d54b2 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1318,10 +1318,8 @@ 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,
 		BISECT_NEXT,
 		BISECT_STATE,
 		BISECT_LOG,
@@ -1334,8 +1332,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,
-- 
2.38.0.1452.g710f45c7951


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

* [PATCH 11/13] bisect--helper: convert to OPT_SUBCOMMAND_CB()
  2022-11-04 13:22 ` [PATCH 00/13] bisect: v2.30.0 "run" regressions + make it built-in Ævar Arnfjörð Bjarmason
                     ` (9 preceding siblings ...)
  2022-11-04 13:22   ` [PATCH 10/13] bisect--helper: remove dead --bisect-{next-check,autostart} code Ævar Arnfjörð Bjarmason
@ 2022-11-04 13:22   ` Ævar Arnfjörð Bjarmason
  2022-11-04 13:22   ` [PATCH 12/13] bisect--helper: make `state` optional Ævar Arnfjörð Bjarmason
                     ` (3 subsequent siblings)
  14 siblings, 0 replies; 106+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-04 13:22 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Jeff King, Taylor Blau,
	Đoàn Trần Công Danh, SZEDER Gábor,
	Lukáš Doktor, Johannes Schindelin,
	Ævar Arnfjörð Bjarmason

Have the "bisect--helper" take arguments like "log" instead of "--log"
by using a new OPT_SUBCOMMAND_CB() variant of OPT_SUBCOMMAND(). As
discussed in a preceding commit this allows for using OPT_SUBCOMMAND()
with custom function signatures.

It would be nice to also convert all of the callbacks to use
parse_options(), [1] does. But due to using the new
OPT_SUBCOMMAND_CB() here we can punt on that for now.

Note that we're intentionally leaving the errors which mention
"--bisect-terms", as opposed to "terms". We've been showing that bad
usage information to users for a while now, and don't need to further
enlarge this change now by changing all of "--bisect-" to "" (which
also occurs outside of this context).

This finally fixes the last obscure regression in "git bisect run" in
v2.30.0. We'd previously addressed it eating the "--log" and
"--no-log" options, but d1bbbe45df8 (bisect--helper: reimplement
`bisect_run` shell function in C, 2021-09-13) also had us conflate the
internal-only "--bisect-*" options with user arguments.

1. https://lore.kernel.org/git/e97e187bbec93b47f35e3dd42b4831f1c1d8658d.1661885419.git.gitgitgadget@gmail.com/

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 builtin/bisect--helper.c    | 110 ++++++++++++++----------------------
 git-bisect.sh               |  20 +++----
 parse-options.h             |   8 ++-
 t/t6030-bisect-porcelain.sh |   2 +-
 4 files changed, 59 insertions(+), 81 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index e13c60d54b2..b62d3f4d418 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1314,107 +1314,79 @@ static int bisect_run(struct bisect_terms *terms,  int argc,
 	return res;
 }
 
+typedef int bisect_fn(struct bisect_terms *terms, int argc, const char **argv,
+		      const char *prefix);
+
+static int pick_subcommand_cb(const struct option *option,
+			      const char *arg UNUSED, int unset UNUSED)
+{
+	bisect_fn *fn = (bisect_fn *)option->defval;
+	*(bisect_fn **)option->value = fn;
+	return 0;
+}
+
 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;
+	bisect_fn *fn = NULL;
 	int res = 0;
+#define OPT_BISECT_SUBCMD(l, v, fn) \
+	OPT_SUBCOMMAND_CB((l), (v), (fn), pick_subcommand_cb)
 	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_BISECT_SUBCMD("reset", &fn, bisect_reset),
+		OPT_BISECT_SUBCMD("terms", &fn, bisect_terms),
+		OPT_BISECT_SUBCMD("start", &fn, bisect_start),
+		OPT_BISECT_SUBCMD("next", &fn, bisect_next),
+		OPT_BISECT_SUBCMD("state", &fn, bisect_state),
+		OPT_BISECT_SUBCMD("log", &fn, bisect_log),
+		OPT_BISECT_SUBCMD("replay", &fn, bisect_replay),
+		OPT_BISECT_SUBCMD("skip", &fn, bisect_skip),
+		OPT_BISECT_SUBCMD("visualize", &fn, bisect_visualize),
+		OPT_BISECT_SUBCMD("run", &fn, bisect_run),
 		OPT_END()
 	};
+#undef OPT_BISECT_SUBCMD
 	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
 
 	argc = parse_options(argc, argv, prefix, options, git_bisect_usage,
-			     PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN_OPT);
+			     0);
 
-	if (!cmdmode)
-		usage_with_options(git_bisect_usage, options);
+	argc--;
+	argv++;
 
-	switch (cmdmode) {
-	case BISECT_RESET:
+	if (fn == bisect_reset) {
 		if (argc > 1)
 			return error(_("--bisect-reset requires either no argument or a commit"));
-		res = bisect_reset(&terms, argc, argv, prefix);
-		break;
-	case BISECT_TERMS:
+	} else if (fn == bisect_terms) {
 		if (argc > 1)
 			return error(_("--bisect-terms requires 0 or 1 argument"));
-		res = bisect_terms(&terms, argc, argv, prefix);
-		break;
-	case BISECT_START:
+	} else if (fn == bisect_start) {
 		set_terms(&terms, "bad", "good");
-		res = bisect_start(&terms, argc, argv, prefix);
-		break;
-	case BISECT_NEXT:
+	} else if (fn == bisect_next) {
+		get_terms(&terms);
 		if (argc)
 			return error(_("--bisect-next requires 0 arguments"));
-		get_terms(&terms);
-		res = bisect_next(&terms, argc, argv, prefix);
-		break;
-	case BISECT_STATE:
+	} else if (fn == bisect_state) {
 		set_terms(&terms, "bad", "good");
 		get_terms(&terms);
-		res = bisect_state(&terms, argc, argv, prefix);
-		break;
-	case BISECT_LOG:
+	} else if (fn == bisect_log) {
 		if (argc)
 			return error(_("--bisect-log requires 0 arguments"));
-		res = bisect_log(&terms, argc, argv, prefix);
-		break;
-	case BISECT_REPLAY:
+	} else if (fn == bisect_replay) {
 		if (argc != 1)
 			return error(_("no logfile given"));
 		set_terms(&terms, "bad", "good");
-		res = bisect_replay(&terms, argc, argv, prefix);
-		break;
-	case BISECT_SKIP:
+	} else if (fn == bisect_skip) {
 		set_terms(&terms, "bad", "good");
 		get_terms(&terms);
-		res = bisect_skip(&terms, argc, argv, prefix);
-		break;
-	case BISECT_VISUALIZE:
+	} else if (fn == bisect_visualize) {
 		get_terms(&terms);
-		res = bisect_visualize(&terms, argc, argv, prefix);
-		break;
-	case BISECT_RUN:
+	} else if (fn == bisect_run) {
 		if (!argc)
 			return error(_("bisect run failed: no command provided."));
 		get_terms(&terms);
-		res = bisect_run(&terms, argc, argv, prefix);
-		break;
-	default:
-		BUG("unknown subcommand %d", cmdmode);
 	}
+
+	res = fn(&terms, argc, argv, prefix);
 	free_terms(&terms);
 
 	/*
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
diff --git a/parse-options.h b/parse-options.h
index 61e3016c3fc..4e32b557174 100644
--- a/parse-options.h
+++ b/parse-options.h
@@ -237,10 +237,16 @@ static inline int parse_options_pick_subcommand_cb(const struct option *option,
 	.value = (v), \
 	.flags = (f), \
 	.defval = (intptr_t)(fn), \
-	.subcommand_fn = (fn), \
 	.callback = parse_options_pick_subcommand_cb, \
 }
 #define OPT_SUBCOMMAND(l, v, fn)    OPT_SUBCOMMAND_F((l), (v), (fn), 0)
+#define OPT_SUBCOMMAND_CB(l, v, fn, cb) { \
+	.type = OPTION_SUBCOMMAND, \
+	.long_name = (l), \
+	.value = (v), \
+	.defval = (intptr_t)(fn), \
+	.callback = (cb), \
+}
 
 /*
  * parse_options() will filter out the processed options and leave the
diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh
index eace0af637e..de47c87a6ff 100755
--- a/t/t6030-bisect-porcelain.sh
+++ b/t/t6030-bisect-porcelain.sh
@@ -350,7 +350,7 @@ test_expect_success 'git bisect run: args, stdout and stderr: "--log foo --no-lo
 	EOF_ERR
 '
 
-test_expect_failure 'git bisect run: args, stdout and stderr: "--bisect-start" argument' '
+test_expect_success 'git bisect run: args, stdout and stderr: "--bisect-start" argument' '
 	test_bisect_run_args --bisect-start <<-\EOF_ARGS 6<<-EOF_OUT 7<<-\EOF_ERR
 	<--bisect-start>
 	EOF_ARGS
-- 
2.38.0.1452.g710f45c7951


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

* [PATCH 12/13] bisect--helper: make `state` optional
  2022-11-04 13:22 ` [PATCH 00/13] bisect: v2.30.0 "run" regressions + make it built-in Ævar Arnfjörð Bjarmason
                     ` (10 preceding siblings ...)
  2022-11-04 13:22   ` [PATCH 11/13] bisect--helper: convert to OPT_SUBCOMMAND_CB() Ævar Arnfjörð Bjarmason
@ 2022-11-04 13:22   ` Ævar Arnfjörð Bjarmason
  2022-11-04 13:22   ` [PATCH 13/13] Turn `git bisect` into a full built-in Ævar Arnfjörð Bjarmason
                     ` (2 subsequent siblings)
  14 siblings, 0 replies; 106+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-04 13:22 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Jeff King, Taylor Blau,
	Đoàn Trần Công Danh, SZEDER Gábor,
	Lukáš Doktor, Johannes Schindelin, Johannes Schindelin,
	Ævar Arnfjörð Bjarmason

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>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 builtin/bisect--helper.c | 21 ++++++++++++++++++---
 git-bisect.sh            | 17 +----------------
 2 files changed, 19 insertions(+), 19 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index b62d3f4d418..c92197b0ea5 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1348,10 +1348,12 @@ 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_usage,
-			     0);
+			     PARSE_OPT_SUBCOMMAND_OPTIONAL);
 
-	argc--;
-	argv++;
+	if (fn) {
+		argc--;
+		argv++;
+	}
 
 	if (fn == bisect_reset) {
 		if (argc > 1)
@@ -1386,6 +1388,19 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 		get_terms(&terms);
 	}
 
+	if (!fn) {
+		if (!argc)
+			usage_msg_opt(_("need a command"), git_bisect_usage,
+				      options);
+
+		set_terms(&terms, "bad", "good");
+		get_terms(&terms);
+		if (check_and_set_terms(&terms, argv[0]))
+			usage_msg_optf(_("unknown command: '%s'"),
+				       git_bisect_usage, options, argv[0]);
+		fn = bisect_state;
+	}
+
 	res = fn(&terms, argc, argv, prefix);
 	free_terms(&terms);
 
diff --git a/git-bisect.sh b/git-bisect.sh
index e19847eba0d..c6e12f60f83 100755
--- a/git-bisect.sh
+++ b/git-bisect.sh
@@ -34,33 +34,18 @@ 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 state "$cmd" "$@" ;;
 	skip)
 		git bisect--helper skip "$@" || exit;;
 	next)
@@ -79,6 +64,6 @@ case "$#" in
 	terms)
 		git bisect--helper terms "$@" || exit;;
 	*)
-		usage ;;
+		git bisect--helper "$cmd" "$@" ;;
 	esac
 esac
-- 
2.38.0.1452.g710f45c7951


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

* [PATCH 13/13] Turn `git bisect` into a full built-in
  2022-11-04 13:22 ` [PATCH 00/13] bisect: v2.30.0 "run" regressions + make it built-in Ævar Arnfjörð Bjarmason
                     ` (11 preceding siblings ...)
  2022-11-04 13:22   ` [PATCH 12/13] bisect--helper: make `state` optional Ævar Arnfjörð Bjarmason
@ 2022-11-04 13:22   ` Ævar Arnfjörð Bjarmason
  2022-11-05  0:13   ` [PATCH 00/13] bisect: v2.30.0 "run" regressions + make it built-in Taylor Blau
  2022-11-10 12:50   ` Johannes Schindelin
  14 siblings, 0 replies; 106+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-04 13:22 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Jeff King, Taylor Blau,
	Đoàn Trần Công Danh, SZEDER Gábor,
	Lukáš Doktor, 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>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 Makefile                               |  3 +-
 builtin.h                              |  2 +-
 builtin/{bisect--helper.c => bisect.c} |  5 +-
 git-bisect.sh                          | 69 --------------------------
 git.c                                  |  2 +-
 5 files changed, 4 insertions(+), 77 deletions(-)
 rename builtin/{bisect--helper.c => bisect.c} (99%)
 delete mode 100755 git-bisect.sh

diff --git a/Makefile b/Makefile
index 4927379184c..78785c6b843 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
@@ -1137,7 +1136,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 8901a34d6bf..aa955466b4e 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 c92197b0ea5..9d66da2148b 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect.c
@@ -1325,7 +1325,7 @@ static int pick_subcommand_cb(const struct option *option,
 	return 0;
 }
 
-int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
+int cmd_bisect(int argc, const char **argv, const char *prefix)
 {
 	bisect_fn *fn = NULL;
 	int res = 0;
@@ -1370,9 +1370,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 	} else if (fn == bisect_state) {
 		set_terms(&terms, "bad", "good");
 		get_terms(&terms);
-	} else if (fn == bisect_log) {
-		if (argc)
-			return error(_("--bisect-log requires 0 arguments"));
 	} else if (fn == bisect_replay) {
 		if (argc != 1)
 			return error(_("no logfile given"));
diff --git a/git-bisect.sh b/git-bisect.sh
deleted file mode 100755
index c6e12f60f83..00000000000
--- a/git-bisect.sh
+++ /dev/null
@@ -1,69 +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
-
-
-case "$#" in
-0)
-	usage ;;
-*)
-	cmd="$1"
-	shift
-	case "$cmd" in
-	help)
-		git bisect -h ;;
-	start)
-		git bisect--helper start "$@" ;;
-	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;;
-	*)
-		git bisect--helper "$cmd" "$@" ;;
-	esac
-esac
diff --git a/git.c b/git.c
index ee7758dcb0e..f18a5750313 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 },
-- 
2.38.0.1452.g710f45c7951


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

* Re: [PATCH 2/3] bisect--helper: move all subcommands into their own functions
  2022-11-04 11:40   ` [PATCH 2/3] bisect--helper: move all subcommands into their own functions Đoàn Trần Công Danh
  2022-11-04 12:55     ` Jeff King
@ 2022-11-04 13:32     ` Ævar Arnfjörð Bjarmason
  2022-11-04 14:03       ` Đoàn Trần Công Danh
  1 sibling, 1 reply; 106+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-04 13:32 UTC (permalink / raw)
  To: Đoàn Trần Công Danh
  Cc: git, Lukáš Doktor, Jeff King, Christian Couder


On Fri, Nov 04 2022, Đoàn Trần Công Danh wrote:

> In a later change, we will use OPT_SUBCOMMAND to parse sub-commands to
> avoid consuming non-option opts.
>
> Since OPT_SUBCOMMAND needs a function pointer to operate,
> let's move it now.

As shown in
https://lore.kernel.org/git/patch-11.13-d261c32ddd7-20221104T132117Z-avarab@gmail.com/
this can be much nicer in terms of avoiding these wrappers if we jsut
teach parse-options.c to take our custom signature'd callback, but...

> +static int cmd_bisect__reset(int argc, const char **argv, const char *prefix UNUSED)
> +static int cmd_bisect__terms(int argc, const char **argv, const char *prefix UNUSED)
> +static int cmd_bisect__start(int argc, const char **argv, const char *prefix UNUSED)
....

>  	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);
> +		res = cmd_bisect__reset(argc, argv, prefix);
>  		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);
> +		res = cmd_bisect__terms(argc, argv, prefix);
>  		break;
>  	case BISECT_START:
> -		set_terms(&terms, "bad", "good");
> -		res = bisect_start(&terms, argv, argc);
> +		res = cmd_bisect__start(argc, argv, prefix);

If we're not going to do that this isn't too bad actually. s noted in my
CL
(https://lore.kernel.org/git/cover-00.13-00000000000-20221104T132117Z-avarab@gmail.com/)
I started seeing if I could cut Johannes's built-in-bisect series down
to size so we could have it merged sooner than later.

It ended up refactoring every single user of "terms" to take the
file-global instead of the variable on the stack, but this shows that
that's not something we need, even without a new parse-options.c API.

B.t.w. you can cut down more on the verbosity by doing:

	struct bisect_terms terms = { 0 };

Which is the same as "{ .term_good = NULL, .term_bad = NULL }". I left
it in place in my version because I'm explicitly trying to avoid
touching anything we don't need to for a bisect built-in, but if we're
refactoring this anyway...

I also think this could be further reduced in size a lot if we go for
your approach, i.e. make a helper function that these call, like:

	if (have_err)
		return error(_(error_msg));
        if (set_terms)
		set_terms(&terms, "bad", "good");
	if (get_terms)
		get_terms(&terms);
	res = !strcmp(iam, "terms") ? bisect_terms(&terms, argc == 1 ? argv[0] : NULL) :
        	!strcmp(iam, "start") ? bisect_start(&terms, argv, argc) :
                [...];
	free_terms(&terms);
	return res;

Then e.g. the body of "terms" is just:

	return that_helper(argc, argv, prefix, "terms", /* iam */
        		  argc > 1, /* have err */ N_("--bisect-terms requires 0 or 1 argument"), /* err msg */
                          0, 0, /* get terms and set terms */);

Etc., I think that might be worth it, as almost all of the contents of
these functions is just copy/pasted...

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

* Re: [PATCH 3/3] bisect--helper: parse subcommand with OPT_SUBCOMMAND
  2022-11-04 11:40   ` [PATCH 3/3] bisect--helper: parse subcommand with OPT_SUBCOMMAND Đoàn Trần Công Danh
  2022-11-04 13:00     ` Jeff King
@ 2022-11-04 13:46     ` Ævar Arnfjörð Bjarmason
  2022-11-04 14:07       ` Đoàn Trần Công Danh
  1 sibling, 1 reply; 106+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-04 13:46 UTC (permalink / raw)
  To: Đoàn Trần Công Danh
  Cc: git, Lukáš Doktor, Jeff King, Christian Couder


On Fri, Nov 04 2022, Đoàn Trần Công Danh wrote:

> As of it is, we're parsing subcommand with OPT_CMDMODE, which will
> continue to parse more options even if the command has been found.
>
> When we're running "git bisect run" with a command that expecting
> a "--log" or "--no-log" arguments, or one of those "--bisect-..."
> arguments, bisect--helper may mistakenly think those options are
> bisect--helper's option.
>
> We may fix those problems by passing "--" when calling from
> git-bisect.sh, and skip that "--" in bisect--helper. However, it may
> interfere with user's "--".
>
> Let's parse subcommand with OPT_SUBCOMMAND since that API was born for
> this specific use-case.

If we go for this approch over my series, let's pretty please...

> +		OPT_SUBCOMMAND("bisect-reset", &fn, cmd_bisect__reset),
> +		OPT_SUBCOMMAND("bisect-terms", &fn, cmd_bisect__terms),

Not call this "bisect-reset" etc, but just "reset", the whole point of
the greater problem here is...

> -		git bisect--helper --bisect-start "$@" ;;
> +		git bisect--helper bisect-start "$@" ;;

...to be able to eventually remove this shimmy layer completely,
which...

>  	bad|good|new|old|"$TERM_BAD"|"$TERM_GOOD")
> -		git bisect--helper --bisect-state "$cmd" "$@" ;;
> +		git bisect--helper bisect-state "$cmd" "$@" ;;

...as you can see in my
https://lore.kernel.org/git/patch-12.13-13745e3f18f-20221104T132118Z-avarab@gmail.com/
we still need to handle this special snowflake, but...


>  	skip)
> -		git bisect--helper --bisect-skip "$@" || exit;;
> +		git bisect--helper bisect-skip "$@" || exit;;
>  	next)
>  		# Not sure we want "next" at the UI level anymore.
> -		git bisect--helper --bisect-next "$@" || exit ;;
> +		git bisect--helper bisect-next "$@" || exit ;;
>  	visualize|view)
> -		git bisect--helper --bisect-visualize "$@" || exit;;
> +		git bisect--helper bisect-visualize "$@" || exit;;
>  	reset)
> -		git bisect--helper --bisect-reset "$@" ;;
> +		git bisect--helper bisect-reset "$@" ;;
>  	replay)
> -		git bisect--helper --bisect-replay "$@" || exit;;
> +		git bisect--helper bisect-replay "$@" || exit;;

...instead of doing all of this, get rid of most of this case statement, and just do:

	bad|good|...)
		[...]
	*)
		git bisect--helper "$cmd" "$@" 
                ;;

>  	log)
> -		git bisect--helper --bisect-log || exit ;;
> +		git bisect--helper bisect-log || exit ;;

But note that there are subtle behavior differences in some,
e.g. because we do the "|| exit" we'll eat the exit code, and this one
also doesn't get parameters, so it should be left out of such a list
(see tests in my topic for a regression check for that, we're currently
flying blind in that area).

> +# We want to make sure --log is not eaten
> +test_expect_success '"git bisect run" simple case' '
> +	git bisect start &&
> +	git bisect good $HASH1 &&
> +	git bisect bad $HASH4 &&
> +	git bisect run printf "%s\n" --log >my_bisect_log.txt &&
> +	grep -e --log my_bisect_log.txt &&
> +	git bisect reset
> +'

Check out my 1/13 to see all the cases you missed:
https://lore.kernel.org/git/patch-01.13-beb1ea22a27-20221104T132117Z-avarab@gmail.com/
:)

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

* Re: [PATCH 0/3] Convert git-bisect--helper to OPT_SUBCOMMAND
  2022-11-04 11:40 ` [PATCH 0/3] Convert git-bisect--helper to OPT_SUBCOMMAND Đoàn Trần Công Danh
                     ` (2 preceding siblings ...)
  2022-11-04 11:40   ` [PATCH 3/3] bisect--helper: parse subcommand with OPT_SUBCOMMAND Đoàn Trần Công Danh
@ 2022-11-04 13:55   ` Ævar Arnfjörð Bjarmason
  2022-11-05 17:03   ` [PATCH v2 " Đoàn Trần Công Danh
  2022-11-10 16:36   ` [PATCH v3 " Đoàn Trần Công Danh
  5 siblings, 0 replies; 106+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-04 13:55 UTC (permalink / raw)
  To: Đoàn Trần Công Danh
  Cc: git, Lukáš Doktor, Jeff King, Christian Couder


On Fri, Nov 04 2022, Đoàn Trần Công Danh wrote:

> This series aims to fix the problem that bisect--helper incorrectly consumes
> "--log" when running:
>
> 	git bisect run cmd --log

I looked this over, and even though I'm obviously biased towards my own
shiny toy I really like where the progression & end state here is going.

> This also clears a way for turning git-bisect into a built-in in a later day.

Yes, but it would be much appreciated if you could take mine and/or
Johannes's conversion series, locally rebase it on what you have, and
check that any assumptions you've made here check out once we get to
that end goal.

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

* Re: [PATCH 2/3] bisect--helper: move all subcommands into their own functions
  2022-11-04 13:32     ` Ævar Arnfjörð Bjarmason
@ 2022-11-04 14:03       ` Đoàn Trần Công Danh
  0 siblings, 0 replies; 106+ messages in thread
From: Đoàn Trần Công Danh @ 2022-11-04 14:03 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: git, Lukáš Doktor, Jeff King, Christian Couder

On 2022-11-04 14:32:34+0100, Ævar Arnfjörð Bjarmason <avarab@gmail.com> wrote:
> 
> On Fri, Nov 04 2022, Đoàn Trần Công Danh wrote:
> 
> > In a later change, we will use OPT_SUBCOMMAND to parse sub-commands to
> > avoid consuming non-option opts.
> >
> > Since OPT_SUBCOMMAND needs a function pointer to operate,
> > let's move it now.
> 
> As shown in
> https://lore.kernel.org/git/patch-11.13-d261c32ddd7-20221104T132117Z-avarab@gmail.com/
> this can be much nicer in terms of avoiding these wrappers if we jsut
> teach parse-options.c to take our custom signature'd callback, but...
> 
> > +static int cmd_bisect__reset(int argc, const char **argv, const char *prefix UNUSED)
> > +static int cmd_bisect__terms(int argc, const char **argv, const char *prefix UNUSED)
> > +static int cmd_bisect__start(int argc, const char **argv, const char *prefix UNUSED)
> ....
> 
> >  	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);
> > +		res = cmd_bisect__reset(argc, argv, prefix);
> >  		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);
> > +		res = cmd_bisect__terms(argc, argv, prefix);
> >  		break;
> >  	case BISECT_START:
> > -		set_terms(&terms, "bad", "good");
> > -		res = bisect_start(&terms, argv, argc);
> > +		res = cmd_bisect__start(argc, argv, prefix);
> 
> If we're not going to do that this isn't too bad actually. s noted in my
> CL
> (https://lore.kernel.org/git/cover-00.13-00000000000-20221104T132117Z-avarab@gmail.com/)
> I started seeing if I could cut Johannes's built-in-bisect series down
> to size so we could have it merged sooner than later.
> 
> It ended up refactoring every single user of "terms" to take the
> file-global instead of the variable on the stack, but this shows that
> that's not something we need, even without a new parse-options.c API.

Yes, I saw your patches, but I think adding a whole new
parse-options.c API is a lot (taking a side the type-safety the new
API introduced). If I were doing the new parse-options API without the
type safety, I probably make an API like:

	int (*subcommand_fn)(int argc, const char **argv, const char *prefix, void *ctx)

We would still have a non-safe 4th argument, but we won't need a new
typedef and picking_fn in every source file.

> B.t.w. you can cut down more on the verbosity by doing:
> 
> 	struct bisect_terms terms = { 0 };
> Which is the same as "{ .term_good = NULL, .term_bad = NULL }". I left
> it in place in my version because I'm explicitly trying to avoid
> touching anything we don't need to for a bisect built-in, but if we're
> refactoring this anyway...

Sure. I'll see which direction is favourable by other people.
Yes, the free_terms is the one that increase the size of this patch,


> I also think this could be further reduced in size a lot if we go for
> your approach, i.e. make a helper function that these call, like:
> 
> 	if (have_err)
> 		return error(_(error_msg));
>         if (set_terms)
> 		set_terms(&terms, "bad", "good");
> 	if (get_terms)
> 		get_terms(&terms);
> 	res = !strcmp(iam, "terms") ? bisect_terms(&terms, argc == 1 ? argv[0] : NULL) :
>         	!strcmp(iam, "start") ? bisect_start(&terms, argv, argc) :

However, if we're doing this, aren't we getting back to step 1:
strcmp to a list of subcommand instead of using OPT_SUBCOMMAND?

>                 [...];
> 	free_terms(&terms);
> 	return res;
> 
> Then e.g. the body of "terms" is just:
> 
> 	return that_helper(argc, argv, prefix, "terms", /* iam */
>         		  argc > 1, /* have err */ N_("--bisect-terms requires 0 or 1 argument"), /* err msg */
>                           0, 0, /* get terms and set terms */);
> 
> Etc., I think that might be worth it, as almost all of the contents of
> these functions is just copy/pasted...

-- 
Danh

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

* Re: [PATCH 3/3] bisect--helper: parse subcommand with OPT_SUBCOMMAND
  2022-11-04 13:46     ` Ævar Arnfjörð Bjarmason
@ 2022-11-04 14:07       ` Đoàn Trần Công Danh
  0 siblings, 0 replies; 106+ messages in thread
From: Đoàn Trần Công Danh @ 2022-11-04 14:07 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: git, Lukáš Doktor, Jeff King, Christian Couder

On 2022-11-04 14:46:18+0100, Ævar Arnfjörð Bjarmason <avarab@gmail.com> wrote:
> 
> On Fri, Nov 04 2022, Đoàn Trần Công Danh wrote:
> 
> > As of it is, we're parsing subcommand with OPT_CMDMODE, which will
> > continue to parse more options even if the command has been found.
> >
> > When we're running "git bisect run" with a command that expecting
> > a "--log" or "--no-log" arguments, or one of those "--bisect-..."
> > arguments, bisect--helper may mistakenly think those options are
> > bisect--helper's option.
> >
> > We may fix those problems by passing "--" when calling from
> > git-bisect.sh, and skip that "--" in bisect--helper. However, it may
> > interfere with user's "--".
> >
> > Let's parse subcommand with OPT_SUBCOMMAND since that API was born for
> > this specific use-case.
> 
> If we go for this approch over my series, let's pretty please...
> 
> > +		OPT_SUBCOMMAND("bisect-reset", &fn, cmd_bisect__reset),
> > +		OPT_SUBCOMMAND("bisect-terms", &fn, cmd_bisect__terms),
> 
> Not call this "bisect-reset" etc, but just "reset", the whole point of
> the greater problem here is...

Yes, we should strip "bisect-" from those sub-commands.

> 
> > -		git bisect--helper --bisect-start "$@" ;;
> > +		git bisect--helper bisect-start "$@" ;;
> 
> ...to be able to eventually remove this shimmy layer completely,
> which...
> 
> >  	bad|good|new|old|"$TERM_BAD"|"$TERM_GOOD")
> > -		git bisect--helper --bisect-state "$cmd" "$@" ;;
> > +		git bisect--helper bisect-state "$cmd" "$@" ;;
> 
> ...as you can see in my
> https://lore.kernel.org/git/patch-12.13-13745e3f18f-20221104T132118Z-avarab@gmail.com/
> we still need to handle this special snowflake, but...
> 
> 
> >  	skip)
> > -		git bisect--helper --bisect-skip "$@" || exit;;
> > +		git bisect--helper bisect-skip "$@" || exit;;
> >  	next)
> >  		# Not sure we want "next" at the UI level anymore.
> > -		git bisect--helper --bisect-next "$@" || exit ;;
> > +		git bisect--helper bisect-next "$@" || exit ;;
> >  	visualize|view)
> > -		git bisect--helper --bisect-visualize "$@" || exit;;
> > +		git bisect--helper bisect-visualize "$@" || exit;;
> >  	reset)
> > -		git bisect--helper --bisect-reset "$@" ;;
> > +		git bisect--helper bisect-reset "$@" ;;
> >  	replay)
> > -		git bisect--helper --bisect-replay "$@" || exit;;
> > +		git bisect--helper bisect-replay "$@" || exit;;
> 
> ...instead of doing all of this, get rid of most of this case statement, and just do:
> 
> 	bad|good|...)
> 		[...]
> 	*)
> 		git bisect--helper "$cmd" "$@" 
>                 ;;
> 
> >  	log)
> > -		git bisect--helper --bisect-log || exit ;;
> > +		git bisect--helper bisect-log || exit ;;
> 
> But note that there are subtle behavior differences in some,
> e.g. because we do the "|| exit" we'll eat the exit code, and this one

No, there're nothing different between "|| exit" and simply run the
command, since "|| exit" will exit with old exit status code.
I don't think there're any other different.

> also doesn't get parameters, so it should be left out of such a list
> (see tests in my topic for a regression check for that, we're currently
> flying blind in that area).
> 
> > +# We want to make sure --log is not eaten
> > +test_expect_success '"git bisect run" simple case' '
> > +	git bisect start &&
> > +	git bisect good $HASH1 &&
> > +	git bisect bad $HASH4 &&
> > +	git bisect run printf "%s\n" --log >my_bisect_log.txt &&
> > +	grep -e --log my_bisect_log.txt &&
> > +	git bisect reset
> > +'
> 
> Check out my 1/13 to see all the cases you missed:
> https://lore.kernel.org/git/patch-01.13-beb1ea22a27-20221104T132117Z-avarab@gmail.com/
> :)

-- 
Danh

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

* Re: [PATCH 00/13] bisect: v2.30.0 "run" regressions + make it built-in
  2022-11-04 13:22 ` [PATCH 00/13] bisect: v2.30.0 "run" regressions + make it built-in Ævar Arnfjörð Bjarmason
                     ` (12 preceding siblings ...)
  2022-11-04 13:22   ` [PATCH 13/13] Turn `git bisect` into a full built-in Ævar Arnfjörð Bjarmason
@ 2022-11-05  0:13   ` Taylor Blau
  2022-11-10 12:50   ` Johannes Schindelin
  14 siblings, 0 replies; 106+ messages in thread
From: Taylor Blau @ 2022-11-05  0:13 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: git, Junio C Hamano, Jeff King, Taylor Blau,
	Đoàn Trần Công Danh, SZEDER Gábor,
	Lukáš Doktor, Johannes Schindelin

On Fri, Nov 04, 2022 at 02:22:37PM +0100, Ævar Arnfjörð Bjarmason wrote:
> This fixes the regression Lukáš Doktor reported in [1], and also gets
> us the full way to a builtin/bisect.c and "git rm git-bisect.sh".

Can you and Đoàn work together to find a way that your two series can
work together? Reading both, this is definitely a "one or the other"
situation currently, and I would much rather pick up a more targeted fix
in the short-term.

Thanks,
Taylor

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

* Re: [PATCH 09/13] parse-options API: don't restrict OPT_SUBCOMMAND() to one *_fn type
  2022-11-04 13:22   ` [PATCH 09/13] parse-options API: don't restrict OPT_SUBCOMMAND() to one *_fn type Ævar Arnfjörð Bjarmason
@ 2022-11-05  8:32     ` René Scharfe
  2022-11-05 11:34       ` Đoàn Trần Công Danh
  2022-11-05 13:52       ` Ævar Arnfjörð Bjarmason
  0 siblings, 2 replies; 106+ messages in thread
From: René Scharfe @ 2022-11-05  8:32 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason, git
  Cc: Junio C Hamano, Jeff King, Taylor Blau,
	Đoàn Trần Công Danh, SZEDER Gábor,
	Lukáš Doktor, Johannes Schindelin

Am 04.11.22 um 14:22 schrieb Ævar Arnfjörð Bjarmason:
> When the OPT_SUBCOMMAND() API was implemented in [1] it did so by
> adding a new "subcommand_fn" member to "struct option", rather than
> allowing the user of the API to pick the type of the function.
>
> An advantage of mandating that "parse_opt_subcommand_fn" must be used
> is that we'll get type checking for the function we're passing in, a
> disadvantage is that we can't convert e.g. "builtin/bisect--helper.c"
> easily to it, as its callbacks need their own argument.
>
> Let's generalize this interface, while leaving in place a small hack
> to give the existing API users their type safety. We assign to
> "typecheck_subcommand_fn", but don't subsequently use it for
> anything. Instead we use the "defval" and "value" members.
>
> A subsequent commit will add a OPT_SUBCOMMAND() variant where the
> "callback" isn't our default "parse_options_pick_subcommand" (and that
> caller won't be able to use the type checking).
>
> 1. fa83cc834da (parse-options: add support for parsing subcommands,
>    2022-08-19)
>
> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
> ---
>  parse-options.c |  9 ++++++---
>  parse-options.h | 25 +++++++++++++++++++++----
>  2 files changed, 27 insertions(+), 7 deletions(-)
>
> diff --git a/parse-options.c b/parse-options.c
> index a1ec932f0f9..1d9e46c9dc7 100644
> --- a/parse-options.c
> +++ b/parse-options.c
> @@ -427,7 +427,8 @@ static enum parse_opt_result parse_subcommand(const char *arg,
>  	for (; options->type != OPTION_END; options++)
>  		if (options->type == OPTION_SUBCOMMAND &&
>  		    !strcmp(options->long_name, arg)) {
> -			*(parse_opt_subcommand_fn **)options->value = options->subcommand_fn;
> +			if (options->callback(options, arg, 0))
> +				BUG("OPT_SUBCOMMAND callback returning non-zero");
>  			return PARSE_OPT_SUBCOMMAND;
>  		}
>
> @@ -506,8 +507,10 @@ static void parse_options_check(const struct option *opts)
>  			       "That case is not supported yet.");
>  			break;
>  		case OPTION_SUBCOMMAND:
> -			if (!opts->value || !opts->subcommand_fn)
> -				optbug(opts, "OPTION_SUBCOMMAND needs a value and a subcommand function");
> +			if (!opts->value || !opts->callback)
> +				optbug(opts, "OPTION_SUBCOMMAND needs a value and a callback function");
> +			if (opts->ll_callback)
> +				optbug(opts, "OPTION_SUBCOMMAND uses callback, not ll_callback");
>  			if (!subcommand_value)
>  				subcommand_value = opts->value;
>  			else if (subcommand_value != opts->value)
> diff --git a/parse-options.h b/parse-options.h
> index b6ef86e0d15..61e3016c3fc 100644
> --- a/parse-options.h
> +++ b/parse-options.h
> @@ -128,19 +128,24 @@ typedef int parse_opt_subcommand_fn(int argc, const char **argv,
>   *			 the option takes optional argument.
>   *
>   * `callback`::
> - *   pointer to the callback to use for OPTION_CALLBACK
> + *   pointer to the callback to use for OPTION_CALLBACK and OPTION_SUBCOMMAND.
>   *
>   * `defval`::
>   *   default value to fill (*->value) with for PARSE_OPT_OPTARG.
>   *   OPTION_{BIT,SET_INT} store the {mask,integer} to put in the value when met.
> + *   OPTION_SUBCOMMAND stores the pointer the function selected for
> + *   the subcommand.
> + *
>   *   CALLBACKS can use it like they want.
>   *
>   * `ll_callback`::
>   *   pointer to the callback to use for OPTION_LOWLEVEL_CALLBACK
>   *
>   * `subcommand_fn`::
> - *   pointer to a function to use for OPTION_SUBCOMMAND.
> - *   It will be put in value when the subcommand is given on the command line.
> + *   pointer to the callback used with OPT_SUBCOMMAND() and
> + *   OPT_SUBCOMMAND_F(). Internally we store the same value in
> + *   `defval`. This is only here to give the OPT_SUBCOMMAND{,_F}()
> + *   common case type safety.
>   */
>  struct option {
>  	enum parse_opt_type type;
> @@ -217,12 +222,24 @@ struct option {
>  #define OPT_ALIAS(s, l, source_long_name) \
>  	{ OPTION_ALIAS, (s), (l), (source_long_name) }
>
> +static inline int parse_options_pick_subcommand_cb(const struct option *option,
> +						   const char *arg UNUSED,
> +						   int unset UNUSED)
> +{
> +	parse_opt_subcommand_fn *fn = (parse_opt_subcommand_fn *)option->defval;
> +	*(parse_opt_subcommand_fn **)option->value = fn;

->defval is of type intptr_t and ->value is a void pointer.  The result
of converting a void pointer value to an intptr_t and back is a void
pointer equal to the original pointer if I read 6.3.2.3 (Pointers,
paragraphs 5 and 6) and 7.18.1.4 (Integer types capable of holding
object pointers) in C99 correctly.

6.3.2.3 paragraph 8 says that casting between function pointers of
different type is OK and you can get your original function pointer
back and use it in a call if you convert it back to the right type.

Casting between a function pointer and an object pointer is undefined,
though.  They don't have to be of the same size, so a function pointer
doesn't have to fit into an intptr_t.  I wouldn't be surprised if CHERI
(https://www.cl.cam.ac.uk/research/security/ctsrd/cheri/) was an actual
example of that.

Why is this trickery needed?  Above you write that callbacks in
builtin/bisect--helper.c can't use subcommand_fn because they need
their own argument.  Can we extend subcommand_fn or use a global
variable to pass that extra thing instead?  The latter may be ugly, but
at least it's valid C..

> +	return 0;
> +}
> +
>  #define OPT_SUBCOMMAND_F(l, v, fn, f) { \
>  	.type = OPTION_SUBCOMMAND, \
>  	.long_name = (l), \
>  	.value = (v), \
>  	.flags = (f), \
> -	.subcommand_fn = (fn) }
> +	.defval = (intptr_t)(fn), \
> +	.subcommand_fn = (fn), \
> +	.callback = parse_options_pick_subcommand_cb, \

Getting the address of an inline function feels weird, but the compiler
is free to emit to ignore that keyword and will provide an addressable
function object here.

> +}
>  #define OPT_SUBCOMMAND(l, v, fn)    OPT_SUBCOMMAND_F((l), (v), (fn), 0)
>
>  /*


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

* Re: [PATCH 09/13] parse-options API: don't restrict OPT_SUBCOMMAND() to one *_fn type
  2022-11-05  8:32     ` René Scharfe
@ 2022-11-05 11:34       ` Đoàn Trần Công Danh
  2022-11-05 21:32         ` Phillip Wood
  2022-11-05 13:52       ` Ævar Arnfjörð Bjarmason
  1 sibling, 1 reply; 106+ messages in thread
From: Đoàn Trần Công Danh @ 2022-11-05 11:34 UTC (permalink / raw)
  To: René Scharfe
  Cc: Ævar Arnfjörð Bjarmason, git, Junio C Hamano,
	Jeff King, Taylor Blau, SZEDER Gábor, Lukáš Doktor,
	Johannes Schindelin

 
On 2022-11-05 09:32:44+0100, René Scharfe <l.s.r@web.de> wrote:
> > diff --git a/parse-options.h b/parse-options.h
> > index b6ef86e0d15..61e3016c3fc 100644
> > --- a/parse-options.h
> > +++ b/parse-options.h
> > @@ -128,19 +128,24 @@ typedef int parse_opt_subcommand_fn(int argc, const char **argv,
> >   *			 the option takes optional argument.
> >   *
> >   * `callback`::
> > - *   pointer to the callback to use for OPTION_CALLBACK
> > + *   pointer to the callback to use for OPTION_CALLBACK and OPTION_SUBCOMMAND.
> >   *
> >   * `defval`::
> >   *   default value to fill (*->value) with for PARSE_OPT_OPTARG.
> >   *   OPTION_{BIT,SET_INT} store the {mask,integer} to put in the value when met.
> > + *   OPTION_SUBCOMMAND stores the pointer the function selected for
> > + *   the subcommand.
> > + *
> >   *   CALLBACKS can use it like they want.
> >   *
> >   * `ll_callback`::
> >   *   pointer to the callback to use for OPTION_LOWLEVEL_CALLBACK
> >   *
> >   * `subcommand_fn`::
> > - *   pointer to a function to use for OPTION_SUBCOMMAND.
> > - *   It will be put in value when the subcommand is given on the command line.
> > + *   pointer to the callback used with OPT_SUBCOMMAND() and
> > + *   OPT_SUBCOMMAND_F(). Internally we store the same value in
> > + *   `defval`. This is only here to give the OPT_SUBCOMMAND{,_F}()
> > + *   common case type safety.
> >   */
> >  struct option {
> >  	enum parse_opt_type type;
> > @@ -217,12 +222,24 @@ struct option {
> >  #define OPT_ALIAS(s, l, source_long_name) \
> >  	{ OPTION_ALIAS, (s), (l), (source_long_name) }
> >
> > +static inline int parse_options_pick_subcommand_cb(const struct option *option,
> > +						   const char *arg UNUSED,
> > +						   int unset UNUSED)
> > +{
> > +	parse_opt_subcommand_fn *fn = (parse_opt_subcommand_fn *)option->defval;
> > +	*(parse_opt_subcommand_fn **)option->value = fn;
> 
> ->defval is of type intptr_t and ->value is a void pointer.  The result
> of converting a void pointer value to an intptr_t and back is a void
> pointer equal to the original pointer if I read 6.3.2.3 (Pointers,
> paragraphs 5 and 6) and 7.18.1.4 (Integer types capable of holding
> object pointers) in C99 correctly.
> 
> 6.3.2.3 paragraph 8 says that casting between function pointers of
> different type is OK and you can get your original function pointer
> back and use it in a call if you convert it back to the right type.
> 
> Casting between a function pointer and an object pointer is undefined,
> though.  They don't have to be of the same size, so a function pointer
> doesn't have to fit into an intptr_t.  I wouldn't be surprised if CHERI
> (https://www.cl.cam.ac.uk/research/security/ctsrd/cheri/) was an actual
> example of that.
> 
> Why is this trickery needed?  Above you write that callbacks in
> builtin/bisect--helper.c can't use subcommand_fn because they need
> their own argument.  Can we extend subcommand_fn or use a global
> variable to pass that extra thing instead?  The latter may be ugly, but
> at least it's valid C..

Not the author, but I fully agree with you, I think instead of adding new API
for some arbitrary subcommand_fn, I would change the subcommand_fn to
type:

	int (*)(int argc, const char **argv, const char *prefix, void *context)

The last argument would be an object pointer, which will be casted to
the correct type inside the callback.

Let me cherry-picking this series on top of mine to see how things
would progress.

> > +	return 0;
> > +}
> > +
> >  #define OPT_SUBCOMMAND_F(l, v, fn, f) { \
> >  	.type = OPTION_SUBCOMMAND, \
> >  	.long_name = (l), \
> >  	.value = (v), \
> >  	.flags = (f), \
> > -	.subcommand_fn = (fn) }
> > +	.defval = (intptr_t)(fn), \
> > +	.subcommand_fn = (fn), \
> > +	.callback = parse_options_pick_subcommand_cb, \
> 
> Getting the address of an inline function feels weird, but the compiler
> is free to emit to ignore that keyword and will provide an addressable
> function object here.
> 
> > +}
> >  #define OPT_SUBCOMMAND(l, v, fn)    OPT_SUBCOMMAND_F((l), (v), (fn), 0)
> >
> >  /*
> 

-- 
Danh

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

* Re: [PATCH 09/13] parse-options API: don't restrict OPT_SUBCOMMAND() to one *_fn type
  2022-11-05  8:32     ` René Scharfe
  2022-11-05 11:34       ` Đoàn Trần Công Danh
@ 2022-11-05 13:52       ` Ævar Arnfjörð Bjarmason
  2022-11-05 16:36         ` Phillip Wood
  2022-11-05 17:26         ` René Scharfe
  1 sibling, 2 replies; 106+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-05 13:52 UTC (permalink / raw)
  To: René Scharfe
  Cc: git, Junio C Hamano, Jeff King, Taylor Blau,
	Đoàn Trần Công Danh, SZEDER Gábor,
	Lukáš Doktor, Johannes Schindelin


On Sat, Nov 05 2022, René Scharfe wrote:

> Am 04.11.22 um 14:22 schrieb Ævar Arnfjörð Bjarmason:
>> When the OPT_SUBCOMMAND() API was implemented in [1] it did so by
>> adding a new "subcommand_fn" member to "struct option", rather than
>> allowing the user of the API to pick the type of the function.
>>
>> An advantage of mandating that "parse_opt_subcommand_fn" must be used
>> is that we'll get type checking for the function we're passing in, a
>> disadvantage is that we can't convert e.g. "builtin/bisect--helper.c"
>> easily to it, as its callbacks need their own argument.
>>
>> Let's generalize this interface, while leaving in place a small hack
>> to give the existing API users their type safety. We assign to
>> "typecheck_subcommand_fn", but don't subsequently use it for
>> anything. Instead we use the "defval" and "value" members.
>>
>> A subsequent commit will add a OPT_SUBCOMMAND() variant where the
>> "callback" isn't our default "parse_options_pick_subcommand" (and that
>> caller won't be able to use the type checking).
>>
>> 1. fa83cc834da (parse-options: add support for parsing subcommands,
>>    2022-08-19)
>>
>> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
>> ---
>>  parse-options.c |  9 ++++++---
>>  parse-options.h | 25 +++++++++++++++++++++----
>>  2 files changed, 27 insertions(+), 7 deletions(-)
>>
>> diff --git a/parse-options.c b/parse-options.c
>> index a1ec932f0f9..1d9e46c9dc7 100644
>> --- a/parse-options.c
>> +++ b/parse-options.c
>> @@ -427,7 +427,8 @@ static enum parse_opt_result parse_subcommand(const char *arg,
>>  	for (; options->type != OPTION_END; options++)
>>  		if (options->type == OPTION_SUBCOMMAND &&
>>  		    !strcmp(options->long_name, arg)) {
>> -			*(parse_opt_subcommand_fn **)options->value = options->subcommand_fn;
>> +			if (options->callback(options, arg, 0))
>> +				BUG("OPT_SUBCOMMAND callback returning non-zero");
>>  			return PARSE_OPT_SUBCOMMAND;
>>  		}
>>
>> @@ -506,8 +507,10 @@ static void parse_options_check(const struct option *opts)
>>  			       "That case is not supported yet.");
>>  			break;
>>  		case OPTION_SUBCOMMAND:
>> -			if (!opts->value || !opts->subcommand_fn)
>> -				optbug(opts, "OPTION_SUBCOMMAND needs a value and a subcommand function");
>> +			if (!opts->value || !opts->callback)
>> +				optbug(opts, "OPTION_SUBCOMMAND needs a value and a callback function");
>> +			if (opts->ll_callback)
>> +				optbug(opts, "OPTION_SUBCOMMAND uses callback, not ll_callback");
>>  			if (!subcommand_value)
>>  				subcommand_value = opts->value;
>>  			else if (subcommand_value != opts->value)
>> diff --git a/parse-options.h b/parse-options.h
>> index b6ef86e0d15..61e3016c3fc 100644
>> --- a/parse-options.h
>> +++ b/parse-options.h
>> @@ -128,19 +128,24 @@ typedef int parse_opt_subcommand_fn(int argc, const char **argv,
>>   *			 the option takes optional argument.
>>   *
>>   * `callback`::
>> - *   pointer to the callback to use for OPTION_CALLBACK
>> + *   pointer to the callback to use for OPTION_CALLBACK and OPTION_SUBCOMMAND.
>>   *
>>   * `defval`::
>>   *   default value to fill (*->value) with for PARSE_OPT_OPTARG.
>>   *   OPTION_{BIT,SET_INT} store the {mask,integer} to put in the value when met.
>> + *   OPTION_SUBCOMMAND stores the pointer the function selected for
>> + *   the subcommand.
>> + *
>>   *   CALLBACKS can use it like they want.
>>   *
>>   * `ll_callback`::
>>   *   pointer to the callback to use for OPTION_LOWLEVEL_CALLBACK
>>   *
>>   * `subcommand_fn`::
>> - *   pointer to a function to use for OPTION_SUBCOMMAND.
>> - *   It will be put in value when the subcommand is given on the command line.
>> + *   pointer to the callback used with OPT_SUBCOMMAND() and
>> + *   OPT_SUBCOMMAND_F(). Internally we store the same value in
>> + *   `defval`. This is only here to give the OPT_SUBCOMMAND{,_F}()
>> + *   common case type safety.
>>   */
>>  struct option {
>>  	enum parse_opt_type type;
>> @@ -217,12 +222,24 @@ struct option {
>>  #define OPT_ALIAS(s, l, source_long_name) \
>>  	{ OPTION_ALIAS, (s), (l), (source_long_name) }
>>
>> +static inline int parse_options_pick_subcommand_cb(const struct option *option,
>> +						   const char *arg UNUSED,
>> +						   int unset UNUSED)
>> +{
>> +	parse_opt_subcommand_fn *fn = (parse_opt_subcommand_fn *)option->defval;
>> +	*(parse_opt_subcommand_fn **)option->value = fn;
>
> ->defval is of type intptr_t and ->value is a void pointer.  The result
> of converting a void pointer value to an intptr_t and back is a void
> pointer equal to the original pointer if I read 6.3.2.3 (Pointers,
> paragraphs 5 and 6) and 7.18.1.4 (Integer types capable of holding
> object pointers) in C99 correctly.
>
> 6.3.2.3 paragraph 8 says that casting between function pointers of
> different type is OK and you can get your original function pointer
> back and use it in a call if you convert it back to the right type.
>
> Casting between a function pointer and an object pointer is undefined,
> though.  They don't have to be of the same size, so a function pointer
> doesn't have to fit into an intptr_t.  I wouldn't be surprised if CHERI
> (https://www.cl.cam.ac.uk/research/security/ctsrd/cheri/) was an actual
> example of that.

I should have called this out explicitly. I think you're right as far as
what you're summarizing goes.

To elaborate on it, paragraph 8 of 6.3.2.3 says:

	A pointer to a function of one type may be converted to a
	pointer to a function of another type and back again; the result
	shall compare equal to the original pointer. If a converted
	pointer is used to call a function whose type is not compatible
	with the pointed-to type, the behavior is undefined.

And 7.18.1.4 says, when discussing (among other things) "intptr_t"
("[such" added for clarity:

	[...]any valid [such] pointer to void can be converted to this
	type, then converted back to pointer to void, and the result
	will compare equal to the original pointer:

But as you point out that doesn't say anything about whether a pointer
to a function is a "valid .. pointer to void".

I think that's an "unportable" extension covered in "J.5 Common
extensions", specifically "J.5.7 Function pointer casts":

	A pointer to an object or to void may be cast to a pointer to a
	function, allowing data to be invoked as a function

Thus, since the standard already establishes that valid "void *" and
"intptr_t" pointers can be cast'd back & forth, the J.5.7 bridges the
gap between the two saying a function pointer can be converted to
either.

Now, I may be missing something here, but I was under the impression
that "intptr_t" wasn't special in any way here, and that any casting of
a function pointer to either it or a "void *" was what was made portable
by "J.5.7". We're only discussing "intptr_t" here, so it's just a point
of clarification.

Anyway, like ssize_t and a few other things this is extended upon and
made standard by POSIX. I.e. we're basically talking about whether this
passes:

	assert(sizeof(void (*)(void)) == sizeof(void*))

And per POSIX
(https://pubs.opengroup.org/onlinepubs/9699919799/functions/dlsym.html):

	Note that conversion from a void * pointer to a function pointer
	as in:

		fptr = (int (*)(int))dlsym(handle, "my_function");

	is not defined by the ISO C standard. This standard requires
	this conversion to work correctly on conforming implementations.

So I think aside from other concerns this should be safe to use, as
real-world data backing that up we've had a intptr_t converted to a
function pointer since v2.35.0: 5cb28270a1f (pack-objects: lazily set up
"struct rev_info", don't leak, 2022-03-28).

> Why is this trickery needed?  Above you write that callbacks in
> builtin/bisect--helper.c can't use subcommand_fn because they need
> their own argument.  Can we extend subcommand_fn or use a global
> variable to pass that extra thing instead?  The latter may be ugly, but
> at least it's valid C..

Yeah, there's ways around it. Less uglier in this case would probably be
to just have the callback set a function pointer in your own custom
struct (which we'd point to with "defval).

I.e. if our callabck is the one to populate the "fn" even without J.5.7
there's no portability issue, and that's just a convenience.

>> +	return 0;
>> +}
>> +
>>  #define OPT_SUBCOMMAND_F(l, v, fn, f) { \
>>  	.type = OPTION_SUBCOMMAND, \
>>  	.long_name = (l), \
>>  	.value = (v), \
>>  	.flags = (f), \
>> -	.subcommand_fn = (fn) }
>> +	.defval = (intptr_t)(fn), \
>> +	.subcommand_fn = (fn), \
>> +	.callback = parse_options_pick_subcommand_cb, \
>
> Getting the address of an inline function feels weird, but the compiler
> is free to emit to ignore that keyword and will provide an addressable
> function object here.

*nod*, I thought about adding this to parse-options-cb.c, but it seemed
 small enough...

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

* Re: [PATCH 09/13] parse-options API: don't restrict OPT_SUBCOMMAND() to one *_fn type
  2022-11-05 13:52       ` Ævar Arnfjörð Bjarmason
@ 2022-11-05 16:36         ` Phillip Wood
  2022-11-05 21:59           ` Ævar Arnfjörð Bjarmason
  2022-11-05 17:26         ` René Scharfe
  1 sibling, 1 reply; 106+ messages in thread
From: Phillip Wood @ 2022-11-05 16:36 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason, René Scharfe
  Cc: git, Junio C Hamano, Jeff King, Taylor Blau,
	Đoàn Trần Công Danh, SZEDER Gábor,
	Lukáš Doktor, Johannes Schindelin

On 05/11/2022 13:52, Ævar Arnfjörð Bjarmason wrote:
> 
> On Sat, Nov 05 2022, René Scharfe wrote:
> 
>> Am 04.11.22 um 14:22 schrieb Ævar Arnfjörð Bjarmason:
>>> diff --git a/parse-options.h b/parse-options.h
>>> index b6ef86e0d15..61e3016c3fc 100644
>>> --- a/parse-options.h
>>> +++ b/parse-options.h
>>> @@ -128,19 +128,24 @@ typedef int parse_opt_subcommand_fn(int argc, const char **argv,
>>>    *			 the option takes optional argument.
>>>    *
>>>    * `callback`::
>>> - *   pointer to the callback to use for OPTION_CALLBACK
>>> + *   pointer to the callback to use for OPTION_CALLBACK and OPTION_SUBCOMMAND.
>>>    *
>>>    * `defval`::
>>>    *   default value to fill (*->value) with for PARSE_OPT_OPTARG.
>>>    *   OPTION_{BIT,SET_INT} store the {mask,integer} to put in the value when met.
>>> + *   OPTION_SUBCOMMAND stores the pointer the function selected for
>>> + *   the subcommand.
>>> + *
>>>    *   CALLBACKS can use it like they want.
>>>    *
>>>    * `ll_callback`::
>>>    *   pointer to the callback to use for OPTION_LOWLEVEL_CALLBACK
>>>    *
>>>    * `subcommand_fn`::
>>> - *   pointer to a function to use for OPTION_SUBCOMMAND.
>>> - *   It will be put in value when the subcommand is given on the command line.
>>> + *   pointer to the callback used with OPT_SUBCOMMAND() and
>>> + *   OPT_SUBCOMMAND_F(). Internally we store the same value in
>>> + *   `defval`. This is only here to give the OPT_SUBCOMMAND{,_F}()
>>> + *   common case type safety.
>>>    */
>>>   struct option {
>>>   	enum parse_opt_type type;
>>> @@ -217,12 +222,24 @@ struct option {
>>>   #define OPT_ALIAS(s, l, source_long_name) \
>>>   	{ OPTION_ALIAS, (s), (l), (source_long_name) }
>>>
>>> +static inline int parse_options_pick_subcommand_cb(const struct option *option,
>>> +						   const char *arg UNUSED,
>>> +						   int unset UNUSED)
>>> +{
>>> +	parse_opt_subcommand_fn *fn = (parse_opt_subcommand_fn *)option->defval;
>>> +	*(parse_opt_subcommand_fn **)option->value = fn;
>>
>> ->defval is of type intptr_t and ->value is a void pointer.  The result
>> of converting a void pointer value to an intptr_t and back is a void
>> pointer equal to the original pointer if I read 6.3.2.3 (Pointers,
>> paragraphs 5 and 6) and 7.18.1.4 (Integer types capable of holding
>> object pointers) in C99 correctly.
>>
>> 6.3.2.3 paragraph 8 says that casting between function pointers of
>> different type is OK and you can get your original function pointer
>> back and use it in a call if you convert it back to the right type.
>>
>> Casting between a function pointer and an object pointer is undefined,
>> though.  They don't have to be of the same size, so a function pointer
>> doesn't have to fit into an intptr_t.  I wouldn't be surprised if CHERI
>> (https://www.cl.cam.ac.uk/research/security/ctsrd/cheri/) was an actual
>> example of that.
> 
> I should have called this out explicitly. I think you're right as far as
> what you're summarizing goes.
> 
> To elaborate on it, paragraph 8 of 6.3.2.3 says:
> 
> 	A pointer to a function of one type may be converted to a
> 	pointer to a function of another type and back again; the result
> 	shall compare equal to the original pointer. If a converted
> 	pointer is used to call a function whose type is not compatible
> 	with the pointed-to type, the behavior is undefined.
> 
> And 7.18.1.4 says, when discussing (among other things) "intptr_t"
> ("[such" added for clarity:
> 
> 	[...]any valid [such] pointer to void can be converted to this
> 	type, then converted back to pointer to void, and the result
> 	will compare equal to the original pointer:
> 
> But as you point out that doesn't say anything about whether a pointer
> to a function is a "valid .. pointer to void".
> 
> I think that's an "unportable" extension covered in "J.5 Common
> extensions", specifically "J.5.7 Function pointer casts":
> 
> 	A pointer to an object or to void may be cast to a pointer to a
> 	function, allowing data to be invoked as a function

This is a common extension, it is _not_ guaranteed by the standard and 
so still undefined behavior unless your compiler happens to have 
implemented that extension.

> Thus, since the standard already establishes that valid "void *" and
> "intptr_t" pointers can be cast'd back & forth, the J.5.7 bridges the
> gap between the two saying a function pointer can be converted to
> either.

How does J.5.7 bridge the gap when compilers are not required to 
implement it?

> Now, I may be missing something here, but I was under the impression
> that "intptr_t" wasn't special in any way here, and that any casting of
> a function pointer to either it or a "void *" was what was made portable
> by "J.5.7"

How is it made portable by an "unportable" extension?

> So I think aside from other concerns this should be safe to use, as
> real-world data backing that up we've had a intptr_t converted to a
> function pointer since v2.35.0: 5cb28270a1f (pack-objects: lazily set up
> "struct rev_info", don't leak, 2022-03-28).

Saying "it works so it is fine" is not a convincing argument that it is 
compliant with the standard. If it is undefined then it may work now but 
not in a future compiler.

>> Why is this trickery needed?  Above you write that callbacks in
>> builtin/bisect--helper.c can't use subcommand_fn because they need
>> their own argument.  Can we extend subcommand_fn or use a global
>> variable to pass that extra thing instead?  The latter may be ugly, but
>> at least it's valid C..

Unfortunately the current code relies on being able to cast function 
pointers to void* so it is not just this patch that is relying on 
undefined behavior.

Best Wishes

Phillip

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

* [PATCH v2 0/3] Convert git-bisect--helper to OPT_SUBCOMMAND
  2022-11-04 11:40 ` [PATCH 0/3] Convert git-bisect--helper to OPT_SUBCOMMAND Đoàn Trần Công Danh
                     ` (3 preceding siblings ...)
  2022-11-04 13:55   ` [PATCH 0/3] Convert git-bisect--helper to OPT_SUBCOMMAND Ævar Arnfjörð Bjarmason
@ 2022-11-05 17:03   ` Đoàn Trần Công Danh
  2022-11-05 17:03     ` [PATCH v2 1/3] bisect--helper: remove unused options Đoàn Trần Công Danh
                       ` (4 more replies)
  2022-11-10 16:36   ` [PATCH v3 " Đoàn Trần Công Danh
  5 siblings, 5 replies; 106+ messages in thread
From: Đoàn Trần Công Danh @ 2022-11-05 17:03 UTC (permalink / raw)
  To: git
  Cc: Đoàn Trần Công Danh, Lukáš Doktor,
	Jeff King, Christian Couder,
	Ævar Arnfjörð Bjarmason

This series aims to fix the problem that bisect--helper incorrectly consumes
"--log" when running:

	git bisect run cmd --log

This also clears a way for turning git-bisect into a built-in in a later day.

The series that convert git-bisect to builtin will be posted later as a reply
to this series

Đoàn Trần Công Danh (3):
  bisect--helper: remove unused options
  bisect--helper: move all subcommands into their own functions
  bisect--helper: parse subcommand with OPT_SUBCOMMAND

 builtin/bisect--helper.c    | 229 ++++++++++++++++++++----------------
 git-bisect.sh               |  23 +---
 t/t6030-bisect-porcelain.sh |  10 ++
 3 files changed, 142 insertions(+), 120 deletions(-)

Range-diff against v1:
1:  abe480d1c9 ! 1:  6b80fd9398 bisect--helper: remove unused options
    @@ Metadata
      ## Commit message ##
         bisect--helper: remove unused options
     
    +    'git-bisect.sh' used to have a 'bisect_next_check' to check if we have
    +    both good/bad, old/new terms set or not.  In commit 129a6cf344
    +    (bisect--helper: `bisect_next_check` shell function in C, 2019-01-02),
    +    a subcommand for bisect--helper was introduced to port the check to C.
    +    Since d1bbbe45df (bisect--helper: reimplement `bisect_run` shell
    +    function in C, 2021-09-13), all users of 'bisect_next_check' was
    +    re-implemented in C, this subcommand was no longer used but we forgot
    +    to remove '--bisect-next-check'.
    +
    +    'git-bisect.sh' also used to have a 'bisect_write' function, whose
    +    third positional parameter was a "nolog" flag.  This flag was only used
    +    when 'bisect_start' invoked 'bisect_write' to write the starting good
    +    and bad revisions.  Then 0f30233a11 (bisect--helper: `bisect_write`
    +    shell function in C, 2019-01-02) ported it to C as a command mode of
    +    'bisect--helper', which (incorrectly) added the '--no-log' option,
    +    and convert the only place ('bisect_start') that call 'bisect_write'
    +    with 'nolog' to 'git bisect--helper --bisect-write' with 'nolog'
    +    instead of '--no-log', since 'bisect--helper' has command modes not
    +    subcommands, all other command modes see and handle that option as well.
    +    This bogus state didn't last long, however, because in the same patch
    +    series 06f5608c14 (bisect--helper: `bisect_start` shell function
    +    partially in C, 2019-01-02) the C reimplementation of bisect_start()
    +    started calling the bisect_write() C function, this time with the
    +    right 'nolog' function parameter. From then on there was no need for
    +    the '--no-log' option in 'bisect--helper'. Eventually all bisect
    +    subcommands were ported to C as 'bisect--helper' command modes, each
    +    calling the bisect_write() C function instead, but when the
    +    '--bisect-write' command mode was removed in 68efed8c8a
    +    (bisect--helper: retire `--bisect-write` subcommand, 2021-02-03) it
    +    forgot to remove that '--no-log' option.
    +    '--no-log' option had never been used and it's unused now.
    +
    +    Let's remove --bisect-next-check and --no-log from option parsing.
    +
         Signed-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>
     
      ## builtin/bisect--helper.c ##
2:  94ac8cb999 = 2:  9d8a3cdd7a bisect--helper: move all subcommands into their own functions
3:  ae967cacd3 ! 3:  a62ac72e24 bisect--helper: parse subcommand with OPT_SUBCOMMAND
    @@ builtin/bisect--helper.c: static int cmd_bisect__run(int argc, const char **argv
     -			 N_("visualize the bisection"), BISECT_VISUALIZE),
     -		OPT_CMDMODE(0, "bisect-run", &cmdmode,
     -			 N_("use <cmd>... to automatically bisect"), BISECT_RUN),
    -+		OPT_SUBCOMMAND("bisect-reset", &fn, cmd_bisect__reset),
    -+		OPT_SUBCOMMAND("bisect-terms", &fn, cmd_bisect__terms),
    -+		OPT_SUBCOMMAND("bisect-start", &fn, cmd_bisect__start),
    -+		OPT_SUBCOMMAND("bisect-next", &fn, cmd_bisect__next),
    -+		OPT_SUBCOMMAND("bisect-state", &fn, cmd_bisect__state),
    -+		OPT_SUBCOMMAND("bisect-log", &fn, cmd_bisect__log),
    -+		OPT_SUBCOMMAND("bisect-replay", &fn, cmd_bisect__replay),
    -+		OPT_SUBCOMMAND("bisect-skip", &fn, cmd_bisect__skip),
    -+		OPT_SUBCOMMAND("bisect-visualize", &fn, cmd_bisect__visualize),
    -+		OPT_SUBCOMMAND("bisect-run", &fn, cmd_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("view", &fn, cmd_bisect__visualize),
    ++		OPT_SUBCOMMAND("run", &fn, cmd_bisect__run),
      		OPT_END()
      	};
      	argc = parse_options(argc, argv, prefix, options,
    @@ builtin/bisect--helper.c: static int cmd_bisect__run(int argc, const char **argv
     
      ## git-bisect.sh ##
     @@ git-bisect.sh: case "$#" in
    + 	case "$cmd" in
      	help)
      		git bisect -h ;;
    - 	start)
    +-	start)
     -		git bisect--helper --bisect-start "$@" ;;
    -+		git bisect--helper bisect-start "$@" ;;
      	bad|good|new|old|"$TERM_BAD"|"$TERM_GOOD")
     -		git bisect--helper --bisect-state "$cmd" "$@" ;;
    -+		git bisect--helper bisect-state "$cmd" "$@" ;;
    - 	skip)
    +-	skip)
     -		git bisect--helper --bisect-skip "$@" || exit;;
    -+		git bisect--helper bisect-skip "$@" || exit;;
    - 	next)
    - 		# Not sure we want "next" at the UI level anymore.
    +-	next)
    +-		# Not sure we want "next" at the UI level anymore.
     -		git bisect--helper --bisect-next "$@" || exit ;;
    -+		git bisect--helper bisect-next "$@" || exit ;;
    - 	visualize|view)
    +-	visualize|view)
     -		git bisect--helper --bisect-visualize "$@" || exit;;
    -+		git bisect--helper bisect-visualize "$@" || exit;;
    - 	reset)
    +-	reset)
     -		git bisect--helper --bisect-reset "$@" ;;
    -+		git bisect--helper bisect-reset "$@" ;;
    - 	replay)
    +-	replay)
     -		git bisect--helper --bisect-replay "$@" || exit;;
    -+		git bisect--helper bisect-replay "$@" || exit;;
    ++		git bisect--helper state "$cmd" "$@" ;;
      	log)
     -		git bisect--helper --bisect-log || exit ;;
    -+		git bisect--helper bisect-log || exit ;;
    - 	run)
    +-	run)
     -		git bisect--helper --bisect-run "$@" || exit;;
    -+		git bisect--helper bisect-run "$@" || exit;;
    - 	terms)
    +-	terms)
     -		git bisect--helper --bisect-terms "$@" || exit;;
    -+		git bisect--helper bisect-terms "$@" || exit;;
    ++		git bisect--helper log || exit ;;
      	*)
    - 		usage ;;
    +-		usage ;;
    ++		git bisect--helper "$cmd" "$@" ;;
      	esac
    + esac
     
      ## t/t6030-bisect-porcelain.sh ##
     @@ t/t6030-bisect-porcelain.sh: test_expect_success '"git bisect run" simple case' '
      	git bisect reset
      '
      
    -+# We want to make sure --log is not eaten
    ++# We want to make sure no arguments has been eaten
     +test_expect_success '"git bisect run" simple case' '
     +	git bisect start &&
     +	git bisect good $HASH1 &&
     +	git bisect bad $HASH4 &&
    -+	git bisect run printf "%s\n" --log >my_bisect_log.txt &&
    -+	grep -e --log my_bisect_log.txt &&
    ++	git bisect run printf "%s %s\n" reset --bisect-skip >my_bisect_log.txt &&
    ++	grep -e "reset --bisect-skip" my_bisect_log.txt &&
     +	git bisect reset
     +'
     +
-- 
2.38.1.157.gedabe22e0a


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

* [PATCH v2 1/3] bisect--helper: remove unused options
  2022-11-05 17:03   ` [PATCH v2 " Đoàn Trần Công Danh
@ 2022-11-05 17:03     ` Đoàn Trần Công Danh
  2022-11-05 17:03     ` [PATCH v2 2/3] bisect--helper: move all subcommands into their own functions Đoàn Trần Công Danh
                       ` (3 subsequent siblings)
  4 siblings, 0 replies; 106+ messages in thread
From: Đoàn Trần Công Danh @ 2022-11-05 17:03 UTC (permalink / raw)
  To: git
  Cc: Đoàn Trần Công Danh, Lukáš Doktor,
	Jeff King, Christian Couder,
	Ævar Arnfjörð Bjarmason, SZEDER Gábor

'git-bisect.sh' used to have a 'bisect_next_check' to check if we have
both good/bad, old/new terms set or not.  In commit 129a6cf344
(bisect--helper: `bisect_next_check` shell function in C, 2019-01-02),
a subcommand for bisect--helper was introduced to port the check to C.
Since d1bbbe45df (bisect--helper: reimplement `bisect_run` shell
function in C, 2021-09-13), all users of 'bisect_next_check' was
re-implemented in C, this subcommand was no longer used but we forgot
to remove '--bisect-next-check'.

'git-bisect.sh' also used to have a 'bisect_write' function, whose
third positional parameter was a "nolog" flag.  This flag was only used
when 'bisect_start' invoked 'bisect_write' to write the starting good
and bad revisions.  Then 0f30233a11 (bisect--helper: `bisect_write`
shell function in C, 2019-01-02) ported it to C as a command mode of
'bisect--helper', which (incorrectly) added the '--no-log' option,
and convert the only place ('bisect_start') that call 'bisect_write'
with 'nolog' to 'git bisect--helper --bisect-write' with 'nolog'
instead of '--no-log', since 'bisect--helper' has command modes not
subcommands, all other command modes see and handle that option as well.
This bogus state didn't last long, however, because in the same patch
series 06f5608c14 (bisect--helper: `bisect_start` shell function
partially in C, 2019-01-02) the C reimplementation of bisect_start()
started calling the bisect_write() C function, this time with the
right 'nolog' function parameter. From then on there was no need for
the '--no-log' option in 'bisect--helper'. Eventually all bisect
subcommands were ported to C as 'bisect--helper' command modes, each
calling the bisect_write() C function instead, but when the
'--bisect-write' command mode was removed in 68efed8c8a
(bisect--helper: retire `--bisect-write` subcommand, 2021-02-03) it
forgot to remove that '--no-log' option.
'--no-log' option had never been used and it's unused now.

Let's remove --bisect-next-check and --no-log from option parsing.

Helped-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>
---
 builtin/bisect--helper.c | 7 +------
 1 file changed, 1 insertion(+), 6 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 1d2ce8a0e1..5ec2e67f59 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1283,7 +1283,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,
@@ -1295,12 +1294,10 @@ 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),
-		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,
@@ -1319,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 };
-- 
2.38.1.157.gedabe22e0a


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

* [PATCH v2 2/3] bisect--helper: move all subcommands into their own functions
  2022-11-05 17:03   ` [PATCH v2 " Đoàn Trần Công Danh
  2022-11-05 17:03     ` [PATCH v2 1/3] bisect--helper: remove unused options Đoàn Trần Công Danh
@ 2022-11-05 17:03     ` Đoàn Trần Công Danh
  2022-11-05 17:13       ` Đoàn Trần Công Danh
  2022-11-05 17:03     ` [PATCH v2 3/3] bisect--helper: parse subcommand with OPT_SUBCOMMAND Đoàn Trần Công Danh
                       ` (2 subsequent siblings)
  4 siblings, 1 reply; 106+ messages in thread
From: Đoàn Trần Công Danh @ 2022-11-05 17:03 UTC (permalink / raw)
  To: git
  Cc: Đoàn Trần Công Danh, Lukáš Doktor,
	Jeff King, Christian Couder,
	Ævar Arnfjörð Bjarmason

In a later change, we will use OPT_SUBCOMMAND to parse sub-commands to
avoid consuming non-option opts.

Since OPT_SUBCOMMAND needs a function pointer to operate,
let's move it now.

Signed-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>
---
 builtin/bisect--helper.c | 155 ++++++++++++++++++++++++++++++---------
 1 file changed, 121 insertions(+), 34 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 5ec2e67f59..292c6fd1dd 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1279,6 +1279,117 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
 	return res;
 }
 
+static int cmd_bisect__reset(int argc, const char **argv, const char *prefix UNUSED)
+{
+	if (argc > 1)
+		return error(_("--bisect-reset requires either no argument or a commit"));
+	return bisect_reset(argc ? argv[0] : NULL);
+}
+
+static int cmd_bisect__terms(int argc, const char **argv, const char *prefix UNUSED)
+{
+	int res;
+	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
+
+	if (argc > 1)
+		return error(_("--bisect-terms requires 0 or 1 argument"));
+	res = bisect_terms(&terms, argc == 1 ? argv[0] : NULL);
+	free_terms(&terms);
+	return res;
+}
+
+static int cmd_bisect__start(int argc, const char **argv, const char *prefix UNUSED)
+{
+	int res;
+	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
+
+	set_terms(&terms, "bad", "good");
+	res = bisect_start(&terms, argv, argc);
+	free_terms(&terms);
+	return res;
+}
+
+static int cmd_bisect__next(int argc, const char **argv UNUSED, const char *prefix)
+{
+	int res;
+	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
+
+	if (argc)
+		return error(_("--bisect-next requires 0 arguments"));
+	get_terms(&terms);
+	res = bisect_next(&terms, prefix);
+	free_terms(&terms);
+	return res;
+}
+
+static int cmd_bisect__state(int argc, const char **argv, const char *prefix UNUSED)
+{
+	int res;
+	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
+
+	set_terms(&terms, "bad", "good");
+	get_terms(&terms);
+	res = bisect_state(&terms, argv, argc);
+	free_terms(&terms);
+	return res;
+}
+
+static int cmd_bisect__log(int argc, const char **argv UNUSED, const char *prefix UNUSED)
+{
+	if (argc)
+		return error(_("--bisect-log requires 0 arguments"));
+	return bisect_log();
+}
+
+static int cmd_bisect__replay(int argc, const char **argv, const char *prefix UNUSED)
+{
+	int res;
+	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
+
+	if (argc != 1)
+		return error(_("no logfile given"));
+	set_terms(&terms, "bad", "good");
+	res = bisect_replay(&terms, argv[0]);
+	free_terms(&terms);
+	return res;
+}
+
+static int cmd_bisect__skip(int argc, const char **argv, const char *prefix UNUSED)
+{
+	int res;
+	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
+
+	set_terms(&terms, "bad", "good");
+	get_terms(&terms);
+	res = bisect_skip(&terms, argv, argc);
+	free_terms(&terms);
+	return res;
+}
+
+static int cmd_bisect__visualize(int argc, const char **argv, const char *prefix UNUSED)
+{
+	int res;
+	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
+
+	get_terms(&terms);
+	res = bisect_visualize(&terms, argv, argc);
+	free_terms(&terms);
+	return res;
+}
+
+static int cmd_bisect__run(int argc, const char **argv, const char *prefix UNUSED)
+{
+	int res;
+	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
+
+	if (!argc)
+		return error(_("bisect run failed: no command provided."));
+	get_terms(&terms);
+	res = bisect_run(&terms, argv, argc);
+	free_terms(&terms);
+	return res;
+}
+
 int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 {
 	enum {
@@ -1318,8 +1429,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,
 			     PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN_OPT);
@@ -1329,60 +1438,38 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 
 	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);
+		res = cmd_bisect__reset(argc, argv, prefix);
 		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);
+		res = cmd_bisect__terms(argc, argv, prefix);
 		break;
 	case BISECT_START:
-		set_terms(&terms, "bad", "good");
-		res = bisect_start(&terms, argv, argc);
+		res = cmd_bisect__start(argc, argv, prefix);
 		break;
 	case BISECT_NEXT:
-		if (argc)
-			return error(_("--bisect-next requires 0 arguments"));
-		get_terms(&terms);
-		res = bisect_next(&terms, prefix);
+		res = cmd_bisect__next(argc, argv, prefix);
 		break;
 	case BISECT_STATE:
-		set_terms(&terms, "bad", "good");
-		get_terms(&terms);
-		res = bisect_state(&terms, argv, argc);
+		res = cmd_bisect__state(argc, argv, prefix);
 		break;
 	case BISECT_LOG:
-		if (argc)
-			return error(_("--bisect-log requires 0 arguments"));
-		res = bisect_log();
+		res = cmd_bisect__log(argc, argv, prefix);
 		break;
 	case BISECT_REPLAY:
-		if (argc != 1)
-			return error(_("no logfile given"));
-		set_terms(&terms, "bad", "good");
-		res = bisect_replay(&terms, argv[0]);
+		res = cmd_bisect__replay(argc, argv, prefix);
 		break;
 	case BISECT_SKIP:
-		set_terms(&terms, "bad", "good");
-		get_terms(&terms);
-		res = bisect_skip(&terms, argv, argc);
+		res = cmd_bisect__skip(argc, argv, prefix);
 		break;
 	case BISECT_VISUALIZE:
-		get_terms(&terms);
-		res = bisect_visualize(&terms, argv, argc);
+		res = cmd_bisect__visualize(argc, argv, prefix);
 		break;
 	case BISECT_RUN:
-		if (!argc)
-			return error(_("bisect run failed: no command provided."));
-		get_terms(&terms);
-		res = bisect_run(&terms, argv, argc);
+		res = cmd_bisect__run(argc, argv, prefix);
 		break;
 	default:
 		BUG("unknown subcommand %d", cmdmode);
 	}
-	free_terms(&terms);
 
 	/*
 	 * Handle early success
-- 
2.38.1.157.gedabe22e0a


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

* [PATCH v2 3/3] bisect--helper: parse subcommand with OPT_SUBCOMMAND
  2022-11-05 17:03   ` [PATCH v2 " Đoàn Trần Công Danh
  2022-11-05 17:03     ` [PATCH v2 1/3] bisect--helper: remove unused options Đoàn Trần Công Danh
  2022-11-05 17:03     ` [PATCH v2 2/3] bisect--helper: move all subcommands into their own functions Đoàn Trần Công Danh
@ 2022-11-05 17:03     ` Đoàn Trần Công Danh
  2022-11-05 17:07     ` [PATCH 00/13] Turn git-bisect to be builtin Đoàn Trần Công Danh
  2022-11-05 23:18     ` [PATCH v2 0/3] Convert git-bisect--helper to OPT_SUBCOMMAND Taylor Blau
  4 siblings, 0 replies; 106+ messages in thread
From: Đoàn Trần Công Danh @ 2022-11-05 17:03 UTC (permalink / raw)
  To: git
  Cc: Đoàn Trần Công Danh, Lukáš Doktor,
	Jeff King, Christian Couder,
	Ævar Arnfjörð Bjarmason

As of it is, we're parsing subcommand with OPT_CMDMODE, which will
continue to parse more options even if the command has been found.

When we're running "git bisect run" with a command that expecting
a "--log" or "--no-log" arguments, or one of those "--bisect-..."
arguments, bisect--helper may mistakenly think those options are
bisect--helper's option.

We may fix those problems by passing "--" when calling from
git-bisect.sh, and skip that "--" in bisect--helper. However, it may
interfere with user's "--".

Let's parse subcommand with OPT_SUBCOMMAND since that API was born for
this specific use-case.

Reported-by: Lukáš Doktor <ldoktor@redhat.com>
Signed-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>
---
 builtin/bisect--helper.c    | 87 ++++++++-----------------------------
 git-bisect.sh               | 23 ++--------
 t/t6030-bisect-porcelain.sh | 10 +++++
 3 files changed, 30 insertions(+), 90 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 292c6fd1dd..d4d813ebfc 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1392,84 +1392,31 @@ static int cmd_bisect__run(int argc, const char **argv, const char *prefix UNUSE
 
 int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 {
-	enum {
-		BISECT_RESET = 1,
-		BISECT_TERMS,
-		BISECT_START,
-		BISECT_AUTOSTART,
-		BISECT_NEXT,
-		BISECT_STATE,
-		BISECT_LOG,
-		BISECT_REPLAY,
-		BISECT_SKIP,
-		BISECT_VISUALIZE,
-		BISECT_RUN,
-	} cmdmode = 0;
 	int res = 0;
+	parse_opt_subcommand_fn *fn = NULL;
 	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("view", &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);
+			     git_bisect_helper_usage, 0);
 
-	if (!cmdmode)
+	if (!fn)
 		usage_with_options(git_bisect_helper_usage, options);
+	argc--;
+	argv++;
 
-	switch (cmdmode) {
-	case BISECT_RESET:
-		res = cmd_bisect__reset(argc, argv, prefix);
-		break;
-	case BISECT_TERMS:
-		res = cmd_bisect__terms(argc, argv, prefix);
-		break;
-	case BISECT_START:
-		res = cmd_bisect__start(argc, argv, prefix);
-		break;
-	case BISECT_NEXT:
-		res = cmd_bisect__next(argc, argv, prefix);
-		break;
-	case BISECT_STATE:
-		res = cmd_bisect__state(argc, argv, prefix);
-		break;
-	case BISECT_LOG:
-		res = cmd_bisect__log(argc, argv, prefix);
-		break;
-	case BISECT_REPLAY:
-		res = cmd_bisect__replay(argc, argv, prefix);
-		break;
-	case BISECT_SKIP:
-		res = cmd_bisect__skip(argc, argv, prefix);
-		break;
-	case BISECT_VISUALIZE:
-		res = cmd_bisect__visualize(argc, argv, prefix);
-		break;
-	case BISECT_RUN:
-		res = cmd_bisect__run(argc, argv, prefix);
-		break;
-	default:
-		BUG("unknown subcommand %d", cmdmode);
-	}
+	res = fn(argc, argv, prefix);
 
 	/*
 	 * Handle early success
diff --git a/git-bisect.sh b/git-bisect.sh
index 405cf76f2a..dfce4b4f44 100755
--- a/git-bisect.sh
+++ b/git-bisect.sh
@@ -57,28 +57,11 @@ 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;;
+		git bisect--helper state "$cmd" "$@" ;;
 	log)
-		git bisect--helper --bisect-log || exit ;;
-	run)
-		git bisect--helper --bisect-run "$@" || exit;;
-	terms)
-		git bisect--helper --bisect-terms "$@" || exit;;
+		git bisect--helper log || exit ;;
 	*)
-		usage ;;
+		git bisect--helper "$cmd" "$@" ;;
 	esac
 esac
diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh
index 83931d482f..6dbbe62eb2 100755
--- a/t/t6030-bisect-porcelain.sh
+++ b/t/t6030-bisect-porcelain.sh
@@ -266,6 +266,16 @@ test_expect_success '"git bisect run" simple case' '
 	git bisect reset
 '
 
+# We want to make sure no arguments has been eaten
+test_expect_success '"git bisect run" simple case' '
+	git bisect start &&
+	git bisect good $HASH1 &&
+	git bisect bad $HASH4 &&
+	git bisect run printf "%s %s\n" reset --bisect-skip >my_bisect_log.txt &&
+	grep -e "reset --bisect-skip" my_bisect_log.txt &&
+	git bisect reset
+'
+
 # We want to automatically find the commit that
 # added "Ciao" into hello.
 test_expect_success '"git bisect run" with more complex "git bisect start"' '
-- 
2.38.1.157.gedabe22e0a


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

* [PATCH 00/13] Turn git-bisect to be builtin
  2022-11-05 17:03   ` [PATCH v2 " Đoàn Trần Công Danh
                       ` (2 preceding siblings ...)
  2022-11-05 17:03     ` [PATCH v2 3/3] bisect--helper: parse subcommand with OPT_SUBCOMMAND Đoàn Trần Công Danh
@ 2022-11-05 17:07     ` Đoàn Trần Công Danh
  2022-11-05 17:07       ` [PATCH 01/13] bisect tests: test for v2.30.0 "bisect run" regressions Đoàn Trần Công Danh
                         ` (12 more replies)
  2022-11-05 23:18     ` [PATCH v2 0/3] Convert git-bisect--helper to OPT_SUBCOMMAND Taylor Blau
  4 siblings, 13 replies; 106+ messages in thread
From: Đoàn Trần Công Danh @ 2022-11-05 17:07 UTC (permalink / raw)
  To: git
  Cc: Đoàn Trần Công Danh, Taylor Blau, Jeff King,
	Christian Couder, Ævar Arnfjörð Bjarmason

This series finish the git-bisect porting from shell script into a C builtin.

This series can't be applied cleaned on master, it needs to be applied on top
of the series posted at:
https://lore.kernel.org/git/cover.1667667058.git.congdanhqx@gmail.com/
AND the series rs/no-more-run-command-v, which has been integrated to next.

There're two commits which were made by me, one of them is the reversal of the
other, which I don't really like it but it's there to restore old behaviour
until we justify the change of behaviours.

Johannes Schindelin (2):
  bisect--helper: make `state` optional
  Turn `git bisect` into a full built-in

Ævar Arnfjörð Bjarmason (6):
  bisect tests: test for v2.30.0 "bisect run" regressions
  bisect: refactor bisect_run() to match CodingGuidelines
  bisect: fix output regressions in v2.30.0
  bisect run: keep some of the post-v2.30.0 output
  bisect test: test exit codes on bad usage
  bisect--helper: emit usage for "git bisect"

Đoàn Trần Công Danh (5):
  bisect--helper: pass arg[cv] down to do_bisect_run
  bisect--helper: remove unused arguments from do_bisect_run
  bisect--helper: pretend we're real bisect when report error
  bisect--helper: remove subcommand state
  bisect--helper: log: allow arbitrary number of arguments

 Makefile                               |   3 +-
 builtin.h                              |   2 +-
 builtin/{bisect--helper.c => bisect.c} | 124 +++++++++++++++----------
 git-bisect.sh                          |   4 -
 git.c                                  |   2 +-
 t/t6030-bisect-porcelain.sh            | 109 ++++++++++++++++++++++
 6 files changed, 186 insertions(+), 58 deletions(-)
 rename builtin/{bisect--helper.c => bisect.c} (92%)

-- 
2.38.1.157.gedabe22e0a


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

* [PATCH 01/13] bisect tests: test for v2.30.0 "bisect run" regressions
  2022-11-05 17:07     ` [PATCH 00/13] Turn git-bisect to be builtin Đoàn Trần Công Danh
@ 2022-11-05 17:07       ` Đoàn Trần Công Danh
  2022-11-07 21:31         ` Ævar Arnfjörð Bjarmason
  2022-11-05 17:07       ` [PATCH 02/13] bisect: refactor bisect_run() to match CodingGuidelines Đoàn Trần Công Danh
                         ` (11 subsequent siblings)
  12 siblings, 1 reply; 106+ messages in thread
From: Đoàn Trần Công Danh @ 2022-11-05 17:07 UTC (permalink / raw)
  To: git
  Cc: Ævar Arnfjörð Bjarmason, Taylor Blau, Jeff King,
	Christian Couder, Đoàn Trần Công Danh

From: Ævar Arnfjörð Bjarmason <avarab@gmail.com>

Add three failing tests which succeed on v2.29.0, but due to the topic
merged at [1] (specifically [2]) have been failing since then. We'll
address those regressions in subsequent commits.

There was also a "regression" where:

	git bisect run ./missing-script.sh

Would count a non-existing script as "good", as the shell would exit
with 127. That edge case is a bit too insane to preserve, so let's not
add it to these regression tests.

1. 0a4cb1f1f2f (Merge branch 'mr/bisect-in-c-4', 2021-09-23)
2. d1bbbe45df8 (bisect--helper: reimplement `bisect_run` shell
   function in C, 2021-09-13)

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>
---
 t/t6030-bisect-porcelain.sh | 79 +++++++++++++++++++++++++++++++++++++
 1 file changed, 79 insertions(+)

diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh
index 6dbbe62eb2..6901bbd202 100755
--- a/t/t6030-bisect-porcelain.sh
+++ b/t/t6030-bisect-porcelain.sh
@@ -252,6 +252,85 @@ test_expect_success 'bisect skip: with commit both bad and skipped' '
 	grep $HASH4 my_bisect_log.txt
 '
 
+test_bisect_run_args () {
+	test_when_finished "rm -f run.sh actual" &&
+	>actual &&
+	cat >expect.args &&
+	cat <&6 >expect.out &&
+	cat <&7 >expect.err &&
+	write_script run.sh <<-\EOF &&
+	while test $# != 0
+	do
+		echo "<$1>" &&
+		shift
+	done >actual.args
+	EOF
+
+	test_when_finished "git bisect reset" &&
+	git bisect start &&
+	git bisect good $HASH1 &&
+	git bisect bad $HASH4 &&
+	git bisect run ./run.sh $@ >actual.out.raw 2>actual.err &&
+	# Prune just the log output
+	sed -n \
+		-e '/^Author:/d' \
+		-e '/^Date:/d' \
+		-e '/^$/d' \
+		-e '/^commit /d' \
+		-e '/^ /d' \
+		-e 'p' \
+		<actual.out.raw >actual.out &&
+	test_cmp expect.out actual.out &&
+	test_cmp expect.err actual.err &&
+	test_cmp expect.args actual.args
+}
+
+test_expect_failure 'git bisect run: args, stdout and stderr with no arguments' '
+	test_bisect_run_args <<-\EOF_ARGS 6<<-EOF_OUT 7<<-\EOF_ERR
+	EOF_ARGS
+	running ./run.sh
+	$HASH4 is the first bad commit
+	bisect run success
+	EOF_OUT
+	EOF_ERR
+'
+
+test_expect_failure 'git bisect run: args, stdout and stderr: "--" argument' '
+	test_bisect_run_args -- <<-\EOF_ARGS 6<<-EOF_OUT 7<<-\EOF_ERR
+	<-->
+	EOF_ARGS
+	running ./run.sh --
+	$HASH4 is the first bad commit
+	bisect run success
+	EOF_OUT
+	EOF_ERR
+'
+
+test_expect_failure 'git bisect run: args, stdout and stderr: "--log foo --no-log bar" arguments' '
+	test_bisect_run_args --log foo --no-log bar <<-\EOF_ARGS 6<<-EOF_OUT 7<<-\EOF_ERR
+	<--log>
+	<foo>
+	<--no-log>
+	<bar>
+	EOF_ARGS
+	running ./run.sh --log foo --no-log bar
+	$HASH4 is the first bad commit
+	bisect run success
+	EOF_OUT
+	EOF_ERR
+'
+
+test_expect_failure 'git bisect run: args, stdout and stderr: "--bisect-start" argument' '
+	test_bisect_run_args --bisect-start <<-\EOF_ARGS 6<<-EOF_OUT 7<<-\EOF_ERR
+	<--bisect-start>
+	EOF_ARGS
+	running ./run.sh --bisect-start
+	$HASH4 is the first bad commit
+	bisect run success
+	EOF_OUT
+	EOF_ERR
+'
+
 # We want to automatically find the commit that
 # added "Another" into hello.
 test_expect_success '"git bisect run" simple case' '
-- 
2.38.1.157.gedabe22e0a


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

* [PATCH 02/13] bisect: refactor bisect_run() to match CodingGuidelines
  2022-11-05 17:07     ` [PATCH 00/13] Turn git-bisect to be builtin Đoàn Trần Công Danh
  2022-11-05 17:07       ` [PATCH 01/13] bisect tests: test for v2.30.0 "bisect run" regressions Đoàn Trần Công Danh
@ 2022-11-05 17:07       ` Đoàn Trần Công Danh
  2022-11-05 17:07       ` [PATCH 03/13] bisect--helper: pass arg[cv] down to do_bisect_run Đoàn Trần Công Danh
                         ` (10 subsequent siblings)
  12 siblings, 0 replies; 106+ messages in thread
From: Đoàn Trần Công Danh @ 2022-11-05 17:07 UTC (permalink / raw)
  To: git
  Cc: Ævar Arnfjörð Bjarmason, Taylor Blau, Jeff King,
	Christian Couder, Đoàn Trần Công Danh

From: Ævar Arnfjörð Bjarmason <avarab@gmail.com>

We didn't add "{}" to all "if/else" branches, and one "error" was
mis-indented. Let's fix that first, which makes subsequent commits
smaller. In the case of the "if" we can simply early return instead.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>
---
 builtin/bisect--helper.c | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index d4d813ebfc..ee1197c8b2 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1191,13 +1191,12 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
 	if (bisect_next_check(terms, NULL))
 		return BISECT_FAILED;
 
-	if (argc)
-		sq_quote_argv(&command, argv);
-	else {
+	if (!argc) {
 		error(_("bisect run failed: no command provided."));
 		return BISECT_FAILED;
 	}
 
+	sq_quote_argv(&command, argv);
 	while (1) {
 		res = do_bisect_run(command.buf);
 
@@ -1268,7 +1267,7 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
 			res = BISECT_OK;
 		} else if (res) {
 			error(_("bisect run failed: 'git bisect--helper --bisect-state"
-			" %s' exited with error code %d"), new_state, res);
+				" %s' exited with error code %d"), new_state, res);
 		} else {
 			continue;
 		}
-- 
2.38.1.157.gedabe22e0a


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

* [PATCH 03/13] bisect--helper: pass arg[cv] down to do_bisect_run
  2022-11-05 17:07     ` [PATCH 00/13] Turn git-bisect to be builtin Đoàn Trần Công Danh
  2022-11-05 17:07       ` [PATCH 01/13] bisect tests: test for v2.30.0 "bisect run" regressions Đoàn Trần Công Danh
  2022-11-05 17:07       ` [PATCH 02/13] bisect: refactor bisect_run() to match CodingGuidelines Đoàn Trần Công Danh
@ 2022-11-05 17:07       ` Đoàn Trần Công Danh
  2022-11-05 17:07       ` [PATCH 04/13] bisect: fix output regressions in v2.30.0 Đoàn Trần Công Danh
                         ` (9 subsequent siblings)
  12 siblings, 0 replies; 106+ messages in thread
From: Đoàn Trần Công Danh @ 2022-11-05 17:07 UTC (permalink / raw)
  To: git
  Cc: Đoàn Trần Công Danh, Taylor Blau, Jeff King,
	Christian Couder, Ævar Arnfjörð Bjarmason

Commit d1bbbe45df8 (bisect--helper: reimplement `bisect_run` shell
function in C, 2021-09-13) has changed the logging of bisect-run by
adding one more space before argv[0], and single-quoting all arguments.

In a later change, we would like to restore the old behaviours,
which would need information regarding argc and argv.

Let's pass them down, now.

Signed-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>
---
 builtin/bisect--helper.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index ee1197c8b2..35e5dc4bbf 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1141,7 +1141,7 @@ static int get_first_good(const char *refname UNUSED,
 	return 1;
 }
 
-static int do_bisect_run(const char *command)
+static int do_bisect_run(const char *command, int argc UNUSED, const char **argv UNUSED)
 {
 	struct child_process cmd = CHILD_PROCESS_INIT;
 
@@ -1151,7 +1151,7 @@ static int do_bisect_run(const char *command)
 	return run_command(&cmd);
 }
 
-static int verify_good(const struct bisect_terms *terms, const char *command)
+static int verify_good(const struct bisect_terms *terms, const char *command, int argc, const char **argv)
 {
 	int rc;
 	enum bisect_error res;
@@ -1171,7 +1171,7 @@ static int verify_good(const struct bisect_terms *terms, const char *command)
 	if (res != BISECT_OK)
 		return -1;
 
-	rc = do_bisect_run(command);
+	rc = do_bisect_run(command, argc, argv);
 
 	res = bisect_checkout(&current_rev, no_checkout);
 	if (res != BISECT_OK)
@@ -1198,7 +1198,7 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
 
 	sq_quote_argv(&command, argv);
 	while (1) {
-		res = do_bisect_run(command.buf);
+		res = do_bisect_run(command.buf, argc, argv);
 
 		/*
 		 * Exit code 126 and 127 can either come from the shell
@@ -1208,7 +1208,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, command.buf);
+			int rc = verify_good(terms, command.buf, argc, argv);
 			is_first_run = 0;
 			if (rc < 0) {
 				error(_("unable to verify '%s' on good"
-- 
2.38.1.157.gedabe22e0a


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

* [PATCH 04/13] bisect: fix output regressions in v2.30.0
  2022-11-05 17:07     ` [PATCH 00/13] Turn git-bisect to be builtin Đoàn Trần Công Danh
                         ` (2 preceding siblings ...)
  2022-11-05 17:07       ` [PATCH 03/13] bisect--helper: pass arg[cv] down to do_bisect_run Đoàn Trần Công Danh
@ 2022-11-05 17:07       ` Đoàn Trần Công Danh
  2022-11-05 17:07       ` [PATCH 05/13] bisect run: keep some of the post-v2.30.0 output Đoàn Trần Công Danh
                         ` (8 subsequent siblings)
  12 siblings, 0 replies; 106+ messages in thread
From: Đoàn Trần Công Danh @ 2022-11-05 17:07 UTC (permalink / raw)
  To: git
  Cc: Ævar Arnfjörð Bjarmason, Taylor Blau, Jeff King,
	Christian Couder, Đoàn Trần Công Danh

From: Ævar Arnfjörð Bjarmason <avarab@gmail.com>

When d1bbbe45df8 (bisect--helper: reimplement `bisect_run` shell
function in C, 2021-09-13) reimplemented parts of "git bisect run" in
C it changed the output we emitted so that:

 - The "running ..." line was now quoted
 - We lost the \n after our output
 - We started saying "bisect found ..." instead of "bisect run success"

Arguably some of this is better now, but as d1bbbe45df8 did not
advocate for changing the output, let's revert this for now. It'll be
easy to change it back if that's what we'd prefer.

This does not change the one remaining use of "command.buf" to emit
the quoted argument, as that's new in d1bbbe45df8.

Some of these cases were not tested for in the tests added in the
preceding commit, I didn't have time to fleshen those out, but a look
at f1de981e8b6 will show that the other output being adjusted here is
now equivalent to what it was before d1bbbe45df8.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>
---
 builtin/bisect--helper.c    | 13 ++++++++-----
 t/t6030-bisect-porcelain.sh |  8 ++++----
 2 files changed, 12 insertions(+), 9 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 35e5dc4bbf..7416283d07 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1141,11 +1141,14 @@ static int get_first_good(const char *refname UNUSED,
 	return 1;
 }
 
-static int do_bisect_run(const char *command, int argc UNUSED, const char **argv UNUSED)
+static int do_bisect_run(const char *command, int argc, const char **argv)
 {
 	struct child_process cmd = CHILD_PROCESS_INIT;
+	struct strbuf buf = STRBUF_INIT;
 
-	printf(_("running %s\n"), command);
+	strbuf_join_argv(&buf, argc, argv, ' ');
+	printf(_("running %s\n"), buf.buf);
+	strbuf_release(&buf);
 	cmd.use_shell = 1;
 	strvec_push(&cmd.args, command);
 	return run_command(&cmd);
@@ -1260,13 +1263,13 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
 		if (res == BISECT_ONLY_SKIPPED_LEFT)
 			error(_("bisect run cannot continue any more"));
 		else if (res == BISECT_INTERNAL_SUCCESS_MERGE_BASE) {
-			printf(_("bisect run success"));
+			puts(_("bisect run success"));
 			res = BISECT_OK;
 		} else if (res == BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND) {
-			printf(_("bisect found first bad commit"));
+			puts(_("bisect run success"));
 			res = BISECT_OK;
 		} else if (res) {
-			error(_("bisect run failed: 'git bisect--helper --bisect-state"
+			error(_("bisect run failed: 'bisect-state"
 				" %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 6901bbd202..914ea564b9 100755
--- a/t/t6030-bisect-porcelain.sh
+++ b/t/t6030-bisect-porcelain.sh
@@ -285,7 +285,7 @@ test_bisect_run_args () {
 	test_cmp expect.args actual.args
 }
 
-test_expect_failure 'git bisect run: args, stdout and stderr with no arguments' '
+test_expect_success 'git bisect run: args, stdout and stderr with no arguments' '
 	test_bisect_run_args <<-\EOF_ARGS 6<<-EOF_OUT 7<<-\EOF_ERR
 	EOF_ARGS
 	running ./run.sh
@@ -295,7 +295,7 @@ test_expect_failure 'git bisect run: args, stdout and stderr with no arguments'
 	EOF_ERR
 '
 
-test_expect_failure 'git bisect run: args, stdout and stderr: "--" argument' '
+test_expect_success 'git bisect run: args, stdout and stderr: "--" argument' '
 	test_bisect_run_args -- <<-\EOF_ARGS 6<<-EOF_OUT 7<<-\EOF_ERR
 	<-->
 	EOF_ARGS
@@ -306,7 +306,7 @@ test_expect_failure 'git bisect run: args, stdout and stderr: "--" argument' '
 	EOF_ERR
 '
 
-test_expect_failure 'git bisect run: args, stdout and stderr: "--log foo --no-log bar" arguments' '
+test_expect_success 'git bisect run: args, stdout and stderr: "--log foo --no-log bar" arguments' '
 	test_bisect_run_args --log foo --no-log bar <<-\EOF_ARGS 6<<-EOF_OUT 7<<-\EOF_ERR
 	<--log>
 	<foo>
@@ -320,7 +320,7 @@ test_expect_failure 'git bisect run: args, stdout and stderr: "--log foo --no-lo
 	EOF_ERR
 '
 
-test_expect_failure 'git bisect run: args, stdout and stderr: "--bisect-start" argument' '
+test_expect_success 'git bisect run: args, stdout and stderr: "--bisect-start" argument' '
 	test_bisect_run_args --bisect-start <<-\EOF_ARGS 6<<-EOF_OUT 7<<-\EOF_ERR
 	<--bisect-start>
 	EOF_ARGS
-- 
2.38.1.157.gedabe22e0a


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

* [PATCH 05/13] bisect run: keep some of the post-v2.30.0 output
  2022-11-05 17:07     ` [PATCH 00/13] Turn git-bisect to be builtin Đoàn Trần Công Danh
                         ` (3 preceding siblings ...)
  2022-11-05 17:07       ` [PATCH 04/13] bisect: fix output regressions in v2.30.0 Đoàn Trần Công Danh
@ 2022-11-05 17:07       ` Đoàn Trần Công Danh
  2022-11-07 21:40         ` Ævar Arnfjörð Bjarmason
  2022-11-05 17:07       ` [PATCH 06/13] bisect--helper: remove unused arguments from do_bisect_run Đoàn Trần Công Danh
                         ` (7 subsequent siblings)
  12 siblings, 1 reply; 106+ messages in thread
From: Đoàn Trần Công Danh @ 2022-11-05 17:07 UTC (permalink / raw)
  To: git
  Cc: Ævar Arnfjörð Bjarmason, Taylor Blau, Jeff King,
	Christian Couder, Đoàn Trần Công Danh

From: Ævar Arnfjörð Bjarmason <avarab@gmail.com>

Preceding commits fixed output and behavior regressions in
d1bbbe45df8 (bisect--helper: reimplement `bisect_run` shell function
in C, 2021-09-13), which did not claim to be changing the output of
"git bisect run".

But some of the output it emitted was subjectively better, so once
we've asserted that we're back on v2.29.0 behavior, let's change some
of it back:

- We now quote the arguments again, but omit the first " " when
  printing the "running" line.
- Ditto for other cases where we emitted the argument
- We say "found first bad commit" again, not just "run success"

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>
---
 builtin/bisect--helper.c    | 12 ++++++------
 t/t6030-bisect-porcelain.sh | 16 ++++++++--------
 2 files changed, 14 insertions(+), 14 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 7416283d07..f16b9df8fd 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1141,14 +1141,14 @@ static int get_first_good(const char *refname UNUSED,
 	return 1;
 }
 
-static int do_bisect_run(const char *command, int argc, const char **argv)
+static int do_bisect_run(const char *command, int argc UNUSED, const char **argv UNUSED)
 {
 	struct child_process cmd = CHILD_PROCESS_INIT;
-	struct strbuf buf = STRBUF_INIT;
+	const char *trimed = command;
 
-	strbuf_join_argv(&buf, argc, argv, ' ');
-	printf(_("running %s\n"), buf.buf);
-	strbuf_release(&buf);
+	while (*trimed && isspace(*trimed))
+		trimed++;
+	printf(_("running %s\n"), trimed);
 	cmd.use_shell = 1;
 	strvec_push(&cmd.args, command);
 	return run_command(&cmd);
@@ -1266,7 +1266,7 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
 			puts(_("bisect run success"));
 			res = BISECT_OK;
 		} else if (res == BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND) {
-			puts(_("bisect run success"));
+			puts(_("bisect found first bad commit"));
 			res = BISECT_OK;
 		} else if (res) {
 			error(_("bisect run failed: 'bisect-state"
diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh
index 914ea564b9..9e14e1e836 100755
--- a/t/t6030-bisect-porcelain.sh
+++ b/t/t6030-bisect-porcelain.sh
@@ -288,9 +288,9 @@ test_bisect_run_args () {
 test_expect_success 'git bisect run: args, stdout and stderr with no arguments' '
 	test_bisect_run_args <<-\EOF_ARGS 6<<-EOF_OUT 7<<-\EOF_ERR
 	EOF_ARGS
-	running ./run.sh
+	running '\''./run.sh'\''
 	$HASH4 is the first bad commit
-	bisect run success
+	bisect found first bad commit
 	EOF_OUT
 	EOF_ERR
 '
@@ -299,9 +299,9 @@ test_expect_success 'git bisect run: args, stdout and stderr: "--" argument' '
 	test_bisect_run_args -- <<-\EOF_ARGS 6<<-EOF_OUT 7<<-\EOF_ERR
 	<-->
 	EOF_ARGS
-	running ./run.sh --
+	running '\''./run.sh'\'' '\''--'\''
 	$HASH4 is the first bad commit
-	bisect run success
+	bisect found first bad commit
 	EOF_OUT
 	EOF_ERR
 '
@@ -313,9 +313,9 @@ test_expect_success 'git bisect run: args, stdout and stderr: "--log foo --no-lo
 	<--no-log>
 	<bar>
 	EOF_ARGS
-	running ./run.sh --log foo --no-log bar
+	running '\''./run.sh'\'' '\''--log'\'' '\''foo'\'' '\''--no-log'\'' '\''bar'\''
 	$HASH4 is the first bad commit
-	bisect run success
+	bisect found first bad commit
 	EOF_OUT
 	EOF_ERR
 '
@@ -324,9 +324,9 @@ test_expect_success 'git bisect run: args, stdout and stderr: "--bisect-start" a
 	test_bisect_run_args --bisect-start <<-\EOF_ARGS 6<<-EOF_OUT 7<<-\EOF_ERR
 	<--bisect-start>
 	EOF_ARGS
-	running ./run.sh --bisect-start
+	running '\''./run.sh'\'' '\''--bisect-start'\''
 	$HASH4 is the first bad commit
-	bisect run success
+	bisect found first bad commit
 	EOF_OUT
 	EOF_ERR
 '
-- 
2.38.1.157.gedabe22e0a


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

* [PATCH 06/13] bisect--helper: remove unused arguments from do_bisect_run
  2022-11-05 17:07     ` [PATCH 00/13] Turn git-bisect to be builtin Đoàn Trần Công Danh
                         ` (4 preceding siblings ...)
  2022-11-05 17:07       ` [PATCH 05/13] bisect run: keep some of the post-v2.30.0 output Đoàn Trần Công Danh
@ 2022-11-05 17:07       ` Đoàn Trần Công Danh
  2022-11-05 17:07       ` [PATCH 07/13] bisect--helper: pretend we're real bisect when report error Đoàn Trần Công Danh
                         ` (6 subsequent siblings)
  12 siblings, 0 replies; 106+ messages in thread
From: Đoàn Trần Công Danh @ 2022-11-05 17:07 UTC (permalink / raw)
  To: git
  Cc: Đoàn Trần Công Danh, Taylor Blau, Jeff King,
	Christian Couder, Ævar Arnfjörð Bjarmason

Those arguments become unused with previous commit, let's remove them
now.  This effectively reverts commit HEAD~3.

Signed-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>
---
 builtin/bisect--helper.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index f16b9df8fd..b99cbb0dbe 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1141,7 +1141,7 @@ static int get_first_good(const char *refname UNUSED,
 	return 1;
 }
 
-static int do_bisect_run(const char *command, int argc UNUSED, const char **argv UNUSED)
+static int do_bisect_run(const char *command)
 {
 	struct child_process cmd = CHILD_PROCESS_INIT;
 	const char *trimed = command;
@@ -1154,7 +1154,7 @@ static int do_bisect_run(const char *command, int argc UNUSED, const char **argv
 	return run_command(&cmd);
 }
 
-static int verify_good(const struct bisect_terms *terms, const char *command, int argc, const char **argv)
+static int verify_good(const struct bisect_terms *terms, const char *command)
 {
 	int rc;
 	enum bisect_error res;
@@ -1174,7 +1174,7 @@ static int verify_good(const struct bisect_terms *terms, const char *command, in
 	if (res != BISECT_OK)
 		return -1;
 
-	rc = do_bisect_run(command, argc, argv);
+	rc = do_bisect_run(command);
 
 	res = bisect_checkout(&current_rev, no_checkout);
 	if (res != BISECT_OK)
@@ -1201,7 +1201,7 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
 
 	sq_quote_argv(&command, argv);
 	while (1) {
-		res = do_bisect_run(command.buf, argc, argv);
+		res = do_bisect_run(command.buf);
 
 		/*
 		 * Exit code 126 and 127 can either come from the shell
@@ -1211,7 +1211,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, command.buf, argc, argv);
+			int rc = verify_good(terms, command.buf);
 			is_first_run = 0;
 			if (rc < 0) {
 				error(_("unable to verify '%s' on good"
-- 
2.38.1.157.gedabe22e0a


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

* [PATCH 07/13] bisect--helper: pretend we're real bisect when report error
  2022-11-05 17:07     ` [PATCH 00/13] Turn git-bisect to be builtin Đoàn Trần Công Danh
                         ` (5 preceding siblings ...)
  2022-11-05 17:07       ` [PATCH 06/13] bisect--helper: remove unused arguments from do_bisect_run Đoàn Trần Công Danh
@ 2022-11-05 17:07       ` Đoàn Trần Công Danh
  2022-11-07 21:29         ` Ævar Arnfjörð Bjarmason
  2022-11-05 17:07       ` [PATCH 08/13] bisect test: test exit codes on bad usage Đoàn Trần Công Danh
                         ` (5 subsequent siblings)
  12 siblings, 1 reply; 106+ messages in thread
From: Đoàn Trần Công Danh @ 2022-11-05 17:07 UTC (permalink / raw)
  To: git
  Cc: Đoàn Trần Công Danh, Taylor Blau, Jeff King,
	Christian Couder, Ævar Arnfjörð Bjarmason

In a later change, we will convert the bisect--helper to be builtin
bisect. Let's start by pretending it's the real bisect when reporting
error.

Signed-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>
---
 builtin/bisect--helper.c | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index b99cbb0dbe..6be4d8861e 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1284,7 +1284,8 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
 static int cmd_bisect__reset(int argc, const char **argv, const char *prefix UNUSED)
 {
 	if (argc > 1)
-		return error(_("--bisect-reset requires either no argument or a commit"));
+		return error(_("'%s' requires either no argument or a commit"),
+			     "git bisect reset");
 	return bisect_reset(argc ? argv[0] : NULL);
 }
 
@@ -1294,7 +1295,8 @@ static int cmd_bisect__terms(int argc, const char **argv, const char *prefix UNU
 	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
 
 	if (argc > 1)
-		return error(_("--bisect-terms requires 0 or 1 argument"));
+		return error(_("'%s' requires 0 or 1 argument"),
+			     "git bisect terms");
 	res = bisect_terms(&terms, argc == 1 ? argv[0] : NULL);
 	free_terms(&terms);
 	return res;
@@ -1317,7 +1319,8 @@ static int cmd_bisect__next(int argc, const char **argv UNUSED, const char *pref
 	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
 
 	if (argc)
-		return error(_("--bisect-next requires 0 arguments"));
+		return error(_("'%s' requires 0 arguments"),
+			     "git bisect next");
 	get_terms(&terms);
 	res = bisect_next(&terms, prefix);
 	free_terms(&terms);
@@ -1339,7 +1342,7 @@ static int cmd_bisect__state(int argc, const char **argv, const char *prefix UNU
 static int cmd_bisect__log(int argc, const char **argv UNUSED, const char *prefix UNUSED)
 {
 	if (argc)
-		return error(_("--bisect-log requires 0 arguments"));
+		return error(_("'%s' requires 0 arguments"), "git bisect log");
 	return bisect_log();
 }
 
@@ -1385,7 +1388,7 @@ static int cmd_bisect__run(int argc, const char **argv, const char *prefix UNUSE
 	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
 
 	if (!argc)
-		return error(_("bisect run failed: no command provided."));
+		return error(_("'%s' failed: no command provided."), "git bisect run");
 	get_terms(&terms);
 	res = bisect_run(&terms, argv, argc);
 	free_terms(&terms);
-- 
2.38.1.157.gedabe22e0a


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

* [PATCH 08/13] bisect test: test exit codes on bad usage
  2022-11-05 17:07     ` [PATCH 00/13] Turn git-bisect to be builtin Đoàn Trần Công Danh
                         ` (6 preceding siblings ...)
  2022-11-05 17:07       ` [PATCH 07/13] bisect--helper: pretend we're real bisect when report error Đoàn Trần Công Danh
@ 2022-11-05 17:07       ` Đoàn Trần Công Danh
  2022-11-05 17:07       ` [PATCH 09/13] bisect--helper: emit usage for "git bisect" Đoàn Trần Công Danh
                         ` (4 subsequent siblings)
  12 siblings, 0 replies; 106+ messages in thread
From: Đoàn Trần Công Danh @ 2022-11-05 17:07 UTC (permalink / raw)
  To: git
  Cc: Ævar Arnfjörð Bjarmason, Taylor Blau, Jeff King,
	Christian Couder, Đoàn Trần Công Danh

From: Ævar Arnfjörð Bjarmason <avarab@gmail.com>

Address a test blindspot, the "log" command is the odd one out because
"git-bisect.sh" ignores any arguments it receives. Let's test both the
exit codes we expect, and the stderr and stdout we're emitting.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>
---
 t/t6030-bisect-porcelain.sh | 30 ++++++++++++++++++++++++++++++
 1 file changed, 30 insertions(+)

diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh
index 9e14e1e836..01eaa368d9 100755
--- a/t/t6030-bisect-porcelain.sh
+++ b/t/t6030-bisect-porcelain.sh
@@ -34,6 +34,36 @@ HASH2=
 HASH3=
 HASH4=
 
+test_bisect_usage () {
+	local code="$1" &&
+	shift &&
+	cat >expect &&
+	test_expect_code $code "$@" >out 2>actual &&
+	test_must_be_empty out &&
+	test_cmp expect actual
+}
+
+test_expect_success 'bisect usage' "
+	test_bisect_usage 1 git bisect reset extra1 extra2 <<-\EOF &&
+	error: 'git bisect reset' requires either no argument or a commit
+	EOF
+	test_bisect_usage 1 git bisect terms extra1 extra2 <<-\EOF &&
+	error: 'git bisect terms' requires 0 or 1 argument
+	EOF
+	test_bisect_usage 1 git bisect next extra1 <<-\EOF &&
+	error: 'git bisect next' requires 0 arguments
+	EOF
+	test_bisect_usage 1 git bisect log extra1 <<-\EOF &&
+	error: We are not bisecting.
+	EOF
+	test_bisect_usage 1 git bisect replay <<-\EOF &&
+	error: no logfile given
+	EOF
+	test_bisect_usage 1 git bisect run <<-\EOF
+	error: 'git bisect run' failed: no command provided.
+	EOF
+"
+
 test_expect_success 'set up basic repo with 1 file (hello) and 4 commits' '
      add_line_into_file "1: Hello World" hello &&
      HASH1=$(git rev-parse --verify HEAD) &&
-- 
2.38.1.157.gedabe22e0a


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

* [PATCH 09/13] bisect--helper: emit usage for "git bisect"
  2022-11-05 17:07     ` [PATCH 00/13] Turn git-bisect to be builtin Đoàn Trần Công Danh
                         ` (7 preceding siblings ...)
  2022-11-05 17:07       ` [PATCH 08/13] bisect test: test exit codes on bad usage Đoàn Trần Công Danh
@ 2022-11-05 17:07       ` Đoàn Trần Công Danh
  2022-11-05 17:07       ` [PATCH 10/13] bisect--helper: make `state` optional Đoàn Trần Công Danh
                         ` (3 subsequent siblings)
  12 siblings, 0 replies; 106+ messages in thread
From: Đoàn Trần Công Danh @ 2022-11-05 17:07 UTC (permalink / raw)
  To: git
  Cc: Ævar Arnfjörð Bjarmason, Taylor Blau, Jeff King,
	Christian Couder, Đoàn Trần Công Danh

From: Ævar Arnfjörð Bjarmason <avarab@gmail.com>

In subsequent commits we'll be removing "git-bisect.sh" in favor of
promoting "bisect--helper" to a "bisect" built-in.

In doing that we'll first need to have it support "git bisect--helper
<cmd>" rather than "git bisect--helper --<cmd>", and then finally have
its "-h" output claim to be "bisect" rather than "bisect--helper".

Instead of suffering that churn let's start claiming to be "git
bisect" now. In just a few commits this will be true, and in the
meantime emitting the "wrong" usage information from the helper is a
small price to pay to avoid the churn.

Let's also declare "BUILTIN_*" macros, when we eventually migrate the
sub-commands themselves to parse_options() we'll be able to re-use the
strings. See 0afd556b2e1 (worktree: define subcommand -h in terms of
command -h, 2022-10-13) for a recent example.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>
---
 builtin/bisect--helper.c | 51 ++++++++++++++++++++++++++++------------
 1 file changed, 36 insertions(+), 15 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 6be4d8861e..bfa160dbf2 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -20,18 +20,40 @@ 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>..."),
+#define BUILTIN_GIT_BISECT_START_USAGE \
+	N_("git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>]" \
+	   "    [--no-checkout] [--first-parent] [<bad> [<good>...]] [--]" \
+	   "    [<pathspec>...]")
+#define BUILTIN_GIT_BISECT_STATE_USAGE \
+	N_("git bisect (good|bad) [<rev>...]")
+#define BUILTIN_GIT_BISECT_TERMS_USAGE \
+	"git bisect terms [--term-good | --term-bad]"
+#define BUILTIN_GIT_BISECT_SKIP_USAGE \
+	N_("git bisect skip [(<rev>|<range>)...]")
+#define BUILTIN_GIT_BISECT_NEXT_USAGE \
+	"git bisect next"
+#define BUILTIN_GIT_BISECT_RESET_USAGE \
+	N_("git bisect reset [<commit>]")
+#define BUILTIN_GIT_BISECT_VISUALIZE_USAGE \
+	"git bisect visualize"
+#define BUILTIN_GIT_BISECT_REPLAY_USAGE \
+	N_("git bisect replay <logfile>")
+#define BUILTIN_GIT_BISECT_LOG_USAGE \
+	"git bisect log"
+#define BUILTIN_GIT_BISECT_RUN_USAGE \
+	N_("git bisect run <cmd>...")
+
+static const char * const git_bisect_usage[] = {
+	BUILTIN_GIT_BISECT_START_USAGE,
+	BUILTIN_GIT_BISECT_STATE_USAGE,
+	BUILTIN_GIT_BISECT_TERMS_USAGE,
+	BUILTIN_GIT_BISECT_SKIP_USAGE,
+	BUILTIN_GIT_BISECT_NEXT_USAGE,
+	BUILTIN_GIT_BISECT_RESET_USAGE,
+	BUILTIN_GIT_BISECT_VISUALIZE_USAGE,
+	BUILTIN_GIT_BISECT_REPLAY_USAGE,
+	BUILTIN_GIT_BISECT_LOG_USAGE,
+	BUILTIN_GIT_BISECT_RUN_USAGE,
 	NULL
 };
 
@@ -1413,11 +1435,10 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 		OPT_SUBCOMMAND("run", &fn, cmd_bisect__run),
 		OPT_END()
 	};
-	argc = parse_options(argc, argv, prefix, options,
-			     git_bisect_helper_usage, 0);
+	argc = parse_options(argc, argv, prefix, options, git_bisect_usage, 0);
 
 	if (!fn)
-		usage_with_options(git_bisect_helper_usage, options);
+		usage_with_options(git_bisect_usage, options);
 	argc--;
 	argv++;
 
-- 
2.38.1.157.gedabe22e0a


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

* [PATCH 10/13] bisect--helper: make `state` optional
  2022-11-05 17:07     ` [PATCH 00/13] Turn git-bisect to be builtin Đoàn Trần Công Danh
                         ` (8 preceding siblings ...)
  2022-11-05 17:07       ` [PATCH 09/13] bisect--helper: emit usage for "git bisect" Đoàn Trần Công Danh
@ 2022-11-05 17:07       ` Đoàn Trần Công Danh
  2022-11-05 17:07       ` [PATCH 11/13] bisect--helper: remove subcommand state Đoàn Trần Công Danh
                         ` (2 subsequent siblings)
  12 siblings, 0 replies; 106+ messages in thread
From: Đoàn Trần Công Danh @ 2022-11-05 17:07 UTC (permalink / raw)
  To: git
  Cc: Johannes Schindelin, Taylor Blau, Jeff King, Christian Couder,
	Ævar Arnfjörð Bjarmason,
	Đoàn Trần Công Danh

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>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>
---
 builtin/bisect--helper.c | 29 +++++++++++++++++++++--------
 git-bisect.sh            |  2 --
 2 files changed, 21 insertions(+), 10 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index bfa160dbf2..3c7a16355a 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1435,14 +1435,27 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 		OPT_SUBCOMMAND("run", &fn, cmd_bisect__run),
 		OPT_END()
 	};
-	argc = parse_options(argc, argv, prefix, options, git_bisect_usage, 0);
-
-	if (!fn)
-		usage_with_options(git_bisect_usage, options);
-	argc--;
-	argv++;
-
-	res = fn(argc, argv, prefix);
+	argc = parse_options(argc, argv, prefix, options, git_bisect_usage,
+			     PARSE_OPT_SUBCOMMAND_OPTIONAL);
+
+	if (!fn) {
+		struct bisect_terms terms = { 0 };
+
+		if (!argc)
+			usage_msg_opt(_("need a command"), git_bisect_usage, options);
+
+		set_terms(&terms, "bad", "good");
+		get_terms(&terms);
+		if (check_and_set_terms(&terms, argv[0]))
+			usage_msg_optf(_("unknown command: '%s'"), git_bisect_usage,
+				       options, argv[0]);
+		res = bisect_state(&terms, argv, argc);
+		free_terms(&terms);
+	} else {
+		argc--;
+		argv++;
+		res = fn(argc, argv, prefix);
+	}
 
 	/*
 	 * Handle early success
diff --git a/git-bisect.sh b/git-bisect.sh
index dfce4b4f44..9f6c8cc093 100755
--- a/git-bisect.sh
+++ b/git-bisect.sh
@@ -57,8 +57,6 @@ case "$#" in
 	case "$cmd" in
 	help)
 		git bisect -h ;;
-	bad|good|new|old|"$TERM_BAD"|"$TERM_GOOD")
-		git bisect--helper state "$cmd" "$@" ;;
 	log)
 		git bisect--helper log || exit ;;
 	*)
-- 
2.38.1.157.gedabe22e0a


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

* [PATCH 11/13] bisect--helper: remove subcommand state
  2022-11-05 17:07     ` [PATCH 00/13] Turn git-bisect to be builtin Đoàn Trần Công Danh
                         ` (9 preceding siblings ...)
  2022-11-05 17:07       ` [PATCH 10/13] bisect--helper: make `state` optional Đoàn Trần Công Danh
@ 2022-11-05 17:07       ` Đoàn Trần Công Danh
  2022-11-07 21:45         ` Ævar Arnfjörð Bjarmason
  2022-11-05 17:07       ` [PATCH 12/13] bisect--helper: log: allow arbitrary number of arguments Đoàn Trần Công Danh
  2022-11-05 17:07       ` [PATCH 13/13] Turn `git bisect` into a full built-in Đoàn Trần Công Danh
  12 siblings, 1 reply; 106+ messages in thread
From: Đoàn Trần Công Danh @ 2022-11-05 17:07 UTC (permalink / raw)
  To: git
  Cc: Đoàn Trần Công Danh, Taylor Blau, Jeff King,
	Christian Couder, Ævar Arnfjörð Bjarmason

In previous change, we've made 'state' optional, and replaced all of its
usage.

Let's remove it, now.

Signed-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>
---
 builtin/bisect--helper.c | 13 -------------
 1 file changed, 13 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 3c7a16355a..d645fe89dc 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1349,18 +1349,6 @@ static int cmd_bisect__next(int argc, const char **argv UNUSED, const char *pref
 	return res;
 }
 
-static int cmd_bisect__state(int argc, const char **argv, const char *prefix UNUSED)
-{
-	int res;
-	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
-
-	set_terms(&terms, "bad", "good");
-	get_terms(&terms);
-	res = bisect_state(&terms, argv, argc);
-	free_terms(&terms);
-	return res;
-}
-
 static int cmd_bisect__log(int argc, const char **argv UNUSED, const char *prefix UNUSED)
 {
 	if (argc)
@@ -1426,7 +1414,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),
-- 
2.38.1.157.gedabe22e0a


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

* [PATCH 12/13] bisect--helper: log: allow arbitrary number of arguments
  2022-11-05 17:07     ` [PATCH 00/13] Turn git-bisect to be builtin Đoàn Trần Công Danh
                         ` (10 preceding siblings ...)
  2022-11-05 17:07       ` [PATCH 11/13] bisect--helper: remove subcommand state Đoàn Trần Công Danh
@ 2022-11-05 17:07       ` Đoàn Trần Công Danh
  2022-11-05 17:07       ` [PATCH 13/13] Turn `git bisect` into a full built-in Đoàn Trần Công Danh
  12 siblings, 0 replies; 106+ messages in thread
From: Đoàn Trần Công Danh @ 2022-11-05 17:07 UTC (permalink / raw)
  To: git
  Cc: Đoàn Trần Công Danh, Taylor Blau, Jeff King,
	Christian Couder, Ævar Arnfjörð Bjarmason

In a later change, we would like to turn bisect into a builtin by
renaming bisect--helper.

However, there's an oddity that "git bisect log" accepts any number of
arguments and it will just ignore them all.

Let's prepare for the next step by ignoring any arguments passed to
"git bisect--helper log"

Signed-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>
---
 builtin/bisect--helper.c | 4 +---
 git-bisect.sh            | 2 --
 2 files changed, 1 insertion(+), 5 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index d645fe89dc..e61ce6556c 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1349,10 +1349,8 @@ static int cmd_bisect__next(int argc, const char **argv UNUSED, const char *pref
 	return res;
 }
 
-static int cmd_bisect__log(int argc, const char **argv UNUSED, const char *prefix UNUSED)
+static int cmd_bisect__log(int argc UNUSED, const char **argv UNUSED, const char *prefix UNUSED)
 {
-	if (argc)
-		return error(_("'%s' requires 0 arguments"), "git bisect log");
 	return bisect_log();
 }
 
diff --git a/git-bisect.sh b/git-bisect.sh
index 9f6c8cc093..f95b8103a9 100755
--- a/git-bisect.sh
+++ b/git-bisect.sh
@@ -57,8 +57,6 @@ case "$#" in
 	case "$cmd" in
 	help)
 		git bisect -h ;;
-	log)
-		git bisect--helper log || exit ;;
 	*)
 		git bisect--helper "$cmd" "$@" ;;
 	esac
-- 
2.38.1.157.gedabe22e0a


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

* [PATCH 13/13] Turn `git bisect` into a full built-in
  2022-11-05 17:07     ` [PATCH 00/13] Turn git-bisect to be builtin Đoàn Trần Công Danh
                         ` (11 preceding siblings ...)
  2022-11-05 17:07       ` [PATCH 12/13] bisect--helper: log: allow arbitrary number of arguments Đoàn Trần Công Danh
@ 2022-11-05 17:07       ` Đoàn Trần Công Danh
  12 siblings, 0 replies; 106+ messages in thread
From: Đoàn Trần Công Danh @ 2022-11-05 17:07 UTC (permalink / raw)
  To: git
  Cc: Johannes Schindelin, Taylor Blau, Jeff King, Christian Couder,
	Ævar Arnfjörð Bjarmason, Junio C Hamano,
	Đoàn Trần Công Danh

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>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>
---
 Makefile                               | 3 +--
 builtin.h                              | 2 +-
 builtin/{bisect--helper.c => bisect.c} | 2 +-
 git.c                                  | 2 +-
 4 files changed, 4 insertions(+), 5 deletions(-)
 rename builtin/{bisect--helper.c => bisect.c} (99%)

diff --git a/Makefile b/Makefile
index 4927379184..78785c6b84 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
@@ -1137,7 +1136,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 8901a34d6b..aa955466b4 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 e61ce6556c..fc13f683a1 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect.c
@@ -1403,7 +1403,7 @@ static int cmd_bisect__run(int argc, const char **argv, const char *prefix UNUSE
 	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;
 	parse_opt_subcommand_fn *fn = NULL;
diff --git a/git.c b/git.c
index 6662548986..a2deb15e46 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 },
-- 
2.38.1.157.gedabe22e0a


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

* Re: [PATCH v2 2/3] bisect--helper: move all subcommands into their own functions
  2022-11-05 17:03     ` [PATCH v2 2/3] bisect--helper: move all subcommands into their own functions Đoàn Trần Công Danh
@ 2022-11-05 17:13       ` Đoàn Trần Công Danh
  0 siblings, 0 replies; 106+ messages in thread
From: Đoàn Trần Công Danh @ 2022-11-05 17:13 UTC (permalink / raw)
  To: git
  Cc: Lukáš Doktor, Jeff King, Christian Couder,
	Ævar Arnfjörð Bjarmason

On 2022-11-06 00:03:35+0700, Đoàn Trần Công Danh <congdanhqx@gmail.com> wrote:
> In a later change, we will use OPT_SUBCOMMAND to parse sub-commands to
> avoid consuming non-option opts.
> 
> Since OPT_SUBCOMMAND needs a function pointer to operate,
> let's move it now.
> 
> Signed-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>
> ---
>  builtin/bisect--helper.c | 155 ++++++++++++++++++++++++++++++---------
>  1 file changed, 121 insertions(+), 34 deletions(-)
> 
> diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
> index 5ec2e67f59..292c6fd1dd 100644
> --- a/builtin/bisect--helper.c
> +++ b/builtin/bisect--helper.c
> @@ -1279,6 +1279,117 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
>  	return res;
>  }
>  
> +static int cmd_bisect__reset(int argc, const char **argv, const char *prefix UNUSED)
> +{
> +	if (argc > 1)
> +		return error(_("--bisect-reset requires either no argument or a commit"));
> +	return bisect_reset(argc ? argv[0] : NULL);
> +}
> +
> +static int cmd_bisect__terms(int argc, const char **argv, const char *prefix UNUSED)
> +{
> +	int res;
> +	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };

Note to self: I need to change this to

	struct bisect_terms terms = { 0 };

in the next revisions.


-- 
Danh

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

* Re: [PATCH 09/13] parse-options API: don't restrict OPT_SUBCOMMAND() to one *_fn type
  2022-11-05 13:52       ` Ævar Arnfjörð Bjarmason
  2022-11-05 16:36         ` Phillip Wood
@ 2022-11-05 17:26         ` René Scharfe
  2022-11-05 22:33           ` Ævar Arnfjörð Bjarmason
  1 sibling, 1 reply; 106+ messages in thread
From: René Scharfe @ 2022-11-05 17:26 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: git, Junio C Hamano, Jeff King, Taylor Blau,
	Đoàn Trần Công Danh, SZEDER Gábor,
	Lukáš Doktor, Johannes Schindelin

Am 05.11.22 um 14:52 schrieb Ævar Arnfjörð Bjarmason:
>
> I think that's an "unportable" extension covered in "J.5 Common
> extensions", specifically "J.5.7 Function pointer casts":
>
> 	A pointer to an object or to void may be cast to a pointer to a
> 	function, allowing data to be invoked as a function
>
> Thus, since the standard already establishes that valid "void *" and
> "intptr_t" pointers can be cast'd back & forth, the J.5.7 bridges the
> gap between the two saying a function pointer can be converted to
> either.
>
> Now, I may be missing something here, but I was under the impression
> that "intptr_t" wasn't special in any way here, and that any casting of
> a function pointer to either it or a "void *" was what was made portable
> by "J.5.7".

Do you mean "possible" or "workable" instead of "portable" here?  As you
write above, J.5.7 is an extension, not (fully) portable.

> Anyway, like ssize_t and a few other things this is extended upon and
> made standard by POSIX. I.e. we're basically talking about whether this
> passes:
>
> 	assert(sizeof(void (*)(void)) == sizeof(void*))
>
> And per POSIX
> (https://pubs.opengroup.org/onlinepubs/9699919799/functions/dlsym.html):
>
> 	Note that conversion from a void * pointer to a function pointer
> 	as in:
>
> 		fptr = (int (*)(int))dlsym(handle, "my_function");
>
> 	is not defined by the ISO C standard. This standard requires
> 	this conversion to work correctly on conforming implementations.

Conversion from object pointer to function pointer can still work if
function pointers are wider.

> So I think aside from other concerns this should be safe to use, as
> real-world data backing that up we've had a intptr_t converted to a
> function pointer since v2.35.0: 5cb28270a1f (pack-objects: lazily set up
> "struct rev_info", don't leak, 2022-03-28).

That may not have reached unusual architectures, yet.  Let's replace
that cast with something boring before someone gets hurt.  Something
like this?


diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index 573d0b20b7..9e6f1530c6 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -4154,14 +4154,15 @@ struct po_filter_data {
 	struct rev_info revs;
 };

-static struct list_objects_filter_options *po_filter_revs_init(void *value)
+static int list_objects_filter_cb(const struct option *opt,
+				  const char *arg, int unset)
 {
-	struct po_filter_data *data = value;
+	struct po_filter_data *data = opt->value;

 	repo_init_revisions(the_repository, &data->revs, NULL);
 	data->have_revs = 1;

-	return &data->revs.filter;
+	return opt_parse_list_objects_filter(&data->revs.filter, arg, unset);
 }

 int cmd_pack_objects(int argc, const char **argv, const char *prefix)
@@ -4265,7 +4266,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
 			      &write_bitmap_index,
 			      N_("write a bitmap index if possible"),
 			      WRITE_BITMAP_QUIET, PARSE_OPT_HIDDEN),
-		OPT_PARSE_LIST_OBJECTS_FILTER_INIT(&pfd, po_filter_revs_init),
+		OPT_PARSE_LIST_OBJECTS_FILTER_F(&pfd, list_objects_filter_cb),
 		OPT_CALLBACK_F(0, "missing", NULL, N_("action"),
 		  N_("handling for missing objects"), PARSE_OPT_NONEG,
 		  option_parse_missing_action),
diff --git a/list-objects-filter-options.c b/list-objects-filter-options.c
index 5339660238..2e560c2fdb 100644
--- a/list-objects-filter-options.c
+++ b/list-objects-filter-options.c
@@ -286,15 +286,9 @@ void parse_list_objects_filter(
 		die("%s", errbuf.buf);
 }

-int opt_parse_list_objects_filter(const struct option *opt,
+int opt_parse_list_objects_filter(struct list_objects_filter_options *filter_options,
 				  const char *arg, int unset)
 {
-	struct list_objects_filter_options *filter_options = opt->value;
-	opt_lof_init init = (opt_lof_init)opt->defval;
-
-	if (init)
-		filter_options = init(opt->value);
-
 	if (unset || !arg)
 		list_objects_filter_set_no_filter(filter_options);
 	else
@@ -302,6 +296,12 @@ int opt_parse_list_objects_filter(const struct option *opt,
 	return 0;
 }

+int opt_parse_list_objects_filter_cb(const struct option *opt,
+				     const char *arg, int unset)
+{
+	return opt_parse_list_objects_filter(opt->value, arg, unset);
+}
+
 const char *list_objects_filter_spec(struct list_objects_filter_options *filter)
 {
 	if (!filter->filter_spec.len)
diff --git a/list-objects-filter-options.h b/list-objects-filter-options.h
index 7eeadab2dd..fc6b4da06d 100644
--- a/list-objects-filter-options.h
+++ b/list-objects-filter-options.h
@@ -107,31 +107,26 @@ void parse_list_objects_filter(
 	struct list_objects_filter_options *filter_options,
 	const char *arg);

+int opt_parse_list_objects_filter(struct list_objects_filter_options *filter_options,
+				  const char *arg, int unset);
+
 /**
  * The opt->value to opt_parse_list_objects_filter() is either a
  * "struct list_objects_filter_option *" when using
  * OPT_PARSE_LIST_OBJECTS_FILTER().
  *
- * Or, if using no "struct option" field is used by the callback,
- * except the "defval" which is expected to be an "opt_lof_init"
- * function, which is called with the "opt->value" and must return a
- * pointer to the ""struct list_objects_filter_option *" to be used.
- *
- * The OPT_PARSE_LIST_OBJECTS_FILTER_INIT() can be used e.g. the
- * "struct list_objects_filter_option" is embedded in a "struct
- * rev_info", which the "defval" could be tasked with lazily
- * initializing. See cmd_pack_objects() for an example.
+ * Or, OPT_PARSE_LIST_OBJECTS_FILTER_F() can be used to specify a
+ * custom callback function that may expect a different type.
  */
-int opt_parse_list_objects_filter(const struct option *opt,
-				  const char *arg, int unset);
+int opt_parse_list_objects_filter_cb(const struct option *opt,
+				     const char *arg, int unset);
 typedef struct list_objects_filter_options *(*opt_lof_init)(void *);
-#define OPT_PARSE_LIST_OBJECTS_FILTER_INIT(fo, init) \
+#define OPT_PARSE_LIST_OBJECTS_FILTER_F(fo, fn) \
 	{ OPTION_CALLBACK, 0, "filter", (fo), N_("args"), \
-	  N_("object filtering"), 0, opt_parse_list_objects_filter, \
-	  (intptr_t)(init) }
+	  N_("object filtering"), 0, (fn) }

 #define OPT_PARSE_LIST_OBJECTS_FILTER(fo) \
-	OPT_PARSE_LIST_OBJECTS_FILTER_INIT((fo), NULL)
+	OPT_PARSE_LIST_OBJECTS_FILTER_F((fo), opt_parse_list_objects_filter_cb)

 /*
  * Translates abbreviated numbers in the filter's filter_spec into their

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

* Re: [PATCH 09/13] parse-options API: don't restrict OPT_SUBCOMMAND() to one *_fn type
  2022-11-05 11:34       ` Đoàn Trần Công Danh
@ 2022-11-05 21:32         ` Phillip Wood
  0 siblings, 0 replies; 106+ messages in thread
From: Phillip Wood @ 2022-11-05 21:32 UTC (permalink / raw)
  To: Đoàn Trần Công Danh, René Scharfe
  Cc: Ævar Arnfjörð Bjarmason, git, Junio C Hamano,
	Jeff King, Taylor Blau, SZEDER Gábor, Lukáš Doktor,
	Johannes Schindelin

Hi Đoàn

On 05/11/2022 11:34, Đoàn Trần Công Danh wrote:
>   
> On 2022-11-05 09:32:44+0100, René Scharfe <l.s.r@web.de> wrote:
>> Why is this trickery needed?  Above you write that callbacks in
>> builtin/bisect--helper.c can't use subcommand_fn because they need
>> their own argument.  Can we extend subcommand_fn or use a global
>> variable to pass that extra thing instead?  The latter may be ugly, but
>> at least it's valid C..
> 
> Not the author, but I fully agree with you, I think instead of adding new API
> for some arbitrary subcommand_fn, I would change the subcommand_fn to
> type:
> 
> 	int (*)(int argc, const char **argv, const char *prefix, void *context)
> 
> The last argument would be an object pointer, which will be casted to
> the correct type inside the callback.
> 
> Let me cherry-picking this series on top of mine to see how things
> would progress.

Unfortunately the current implementation of OPT_SUBCOMMAND relies on 
returning a function pointer though a void* variable which while widely 
supported is undefined behavior. I wonder if an API like

typedef int (*subcommand_fn)(int, char**, char*);
typedef int (*subcommand_ctk_fn)(int, char**, char*, void*);
struct subcommand; /* opaque */

OPT_SUBCOMMAND(name, value, func);
OPT_SUMCOMMAND_CTX(name, value, func, ctx);

int call_subcommand(struct subcommand* subcommand, int argc, char** 
argv, char* prefix);


which would be used as

int sub1_fn(int argc, char** argv, char* prefix, void* ctx)
{
	struct cmd_ctx cmd_ctx = ctx
	...
}

int sub2_fn(int argc, char** argv, char* prefix)
{
	...
}

int cmd_foo(int argc, char** argv, char* prefix)
{
	struct cmd_ctx ctx = ...
	struct subcommand cmd = { 0 };
	...
	struct option opts[] = {
		OPT_SUBCOMMAND_CTX("sub1", &cmd, sub_fn, &ctx);
		OPT_SUBCOMMAND("sub2", &cmd, sub2_fn);
	};
	argc = parse_options(argc, argv, prefix, &opts, usage, flags);
	return call_subcommand(&cmd, argc, argv, prefix);
}


would be an improvement. One can avoid having to mark the ctx parameter 
as UNUSED() if a subcommand does not need any context by using 
OPT_SUBCOMMAND() rather than OPT_SUBCOMMAND_CTX().


The implementation of call_subcommand() would look something like

struct subcommand {
         void* ctx;
         int has_ctx;
         union {
                 subcommand_fn fn;
                 subcommand_ctx_fn ctx_fn;
         };
};

int call_subcommand(struct subcommand* subcommand, int argc, char 
**argv, char* prefix)
{
         if (subcommand->has_ctx)
                 return subcommand->ctx_fn(argc, argv, prefix, 
subcommand->ctx);
         else
                 return subcommand->fn(argc, argv, prefix);
}


Best Wishes

Phillip

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

* Re: [PATCH 09/13] parse-options API: don't restrict OPT_SUBCOMMAND() to one *_fn type
  2022-11-05 16:36         ` Phillip Wood
@ 2022-11-05 21:59           ` Ævar Arnfjörð Bjarmason
  0 siblings, 0 replies; 106+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-05 21:59 UTC (permalink / raw)
  To: phillip.wood
  Cc: René Scharfe, git, Junio C Hamano, Jeff King, Taylor Blau,
	Đoàn Trần Công Danh, SZEDER Gábor,
	Lukáš Doktor, Johannes Schindelin


On Sat, Nov 05 2022, Phillip Wood wrote:

> On 05/11/2022 13:52, Ævar Arnfjörð Bjarmason wrote:
>> On Sat, Nov 05 2022, René Scharfe wrote:
>> 
>>> Am 04.11.22 um 14:22 schrieb Ævar Arnfjörð Bjarmason:
>>>> diff --git a/parse-options.h b/parse-options.h
>>>> index b6ef86e0d15..61e3016c3fc 100644
>>>> --- a/parse-options.h
>>>> +++ b/parse-options.h
>>>> @@ -128,19 +128,24 @@ typedef int parse_opt_subcommand_fn(int argc, const char **argv,
>>>>    *			 the option takes optional argument.
>>>>    *
>>>>    * `callback`::
>>>> - *   pointer to the callback to use for OPTION_CALLBACK
>>>> + *   pointer to the callback to use for OPTION_CALLBACK and OPTION_SUBCOMMAND.
>>>>    *
>>>>    * `defval`::
>>>>    *   default value to fill (*->value) with for PARSE_OPT_OPTARG.
>>>>    *   OPTION_{BIT,SET_INT} store the {mask,integer} to put in the value when met.
>>>> + *   OPTION_SUBCOMMAND stores the pointer the function selected for
>>>> + *   the subcommand.
>>>> + *
>>>>    *   CALLBACKS can use it like they want.
>>>>    *
>>>>    * `ll_callback`::
>>>>    *   pointer to the callback to use for OPTION_LOWLEVEL_CALLBACK
>>>>    *
>>>>    * `subcommand_fn`::
>>>> - *   pointer to a function to use for OPTION_SUBCOMMAND.
>>>> - *   It will be put in value when the subcommand is given on the command line.
>>>> + *   pointer to the callback used with OPT_SUBCOMMAND() and
>>>> + *   OPT_SUBCOMMAND_F(). Internally we store the same value in
>>>> + *   `defval`. This is only here to give the OPT_SUBCOMMAND{,_F}()
>>>> + *   common case type safety.
>>>>    */
>>>>   struct option {
>>>>   	enum parse_opt_type type;
>>>> @@ -217,12 +222,24 @@ struct option {
>>>>   #define OPT_ALIAS(s, l, source_long_name) \
>>>>   	{ OPTION_ALIAS, (s), (l), (source_long_name) }
>>>>
>>>> +static inline int parse_options_pick_subcommand_cb(const struct option *option,
>>>> +						   const char *arg UNUSED,
>>>> +						   int unset UNUSED)
>>>> +{
>>>> +	parse_opt_subcommand_fn *fn = (parse_opt_subcommand_fn *)option->defval;
>>>> +	*(parse_opt_subcommand_fn **)option->value = fn;
>>>
>>> ->defval is of type intptr_t and ->value is a void pointer.  The result
>>> of converting a void pointer value to an intptr_t and back is a void
>>> pointer equal to the original pointer if I read 6.3.2.3 (Pointers,
>>> paragraphs 5 and 6) and 7.18.1.4 (Integer types capable of holding
>>> object pointers) in C99 correctly.
>>>
>>> 6.3.2.3 paragraph 8 says that casting between function pointers of
>>> different type is OK and you can get your original function pointer
>>> back and use it in a call if you convert it back to the right type.
>>>
>>> Casting between a function pointer and an object pointer is undefined,
>>> though.  They don't have to be of the same size, so a function pointer
>>> doesn't have to fit into an intptr_t.  I wouldn't be surprised if CHERI
>>> (https://www.cl.cam.ac.uk/research/security/ctsrd/cheri/) was an actual
>>> example of that.
>> I should have called this out explicitly. I think you're right as
>> far as
>> what you're summarizing goes.
>> To elaborate on it, paragraph 8 of 6.3.2.3 says:
>> 	A pointer to a function of one type may be converted to a
>> 	pointer to a function of another type and back again; the result
>> 	shall compare equal to the original pointer. If a converted
>> 	pointer is used to call a function whose type is not compatible
>> 	with the pointed-to type, the behavior is undefined.
>> And 7.18.1.4 says, when discussing (among other things) "intptr_t"
>> ("[such" added for clarity:
>> 	[...]any valid [such] pointer to void can be converted to this
>> 	type, then converted back to pointer to void, and the result
>> 	will compare equal to the original pointer:
>> But as you point out that doesn't say anything about whether a
>> pointer
>> to a function is a "valid .. pointer to void".
>> I think that's an "unportable" extension covered in "J.5 Common
>> extensions", specifically "J.5.7 Function pointer casts":
>> 	A pointer to an object or to void may be cast to a pointer to
>> a
>> 	function, allowing data to be invoked as a function
>
> This is a common extension, it is _not_ guaranteed by the standard and
> so still undefined behavior unless your compiler happens to have 
> implemented that extension.

>> Thus, since the standard already establishes that valid "void *" and
>> "intptr_t" pointers can be cast'd back & forth, the J.5.7 bridges the
>> gap between the two saying a function pointer can be converted to
>> either.
>
> How does J.5.7 bridge the gap when compilers are not required to
> implement it?

I'm saying it bridges the gap in that explanation, i.e. reinforces that
the main standard body isn't referring to function pointer casts to void
* and intptr_t.

>> Now, I may be missing something here, but I was under the impression
>> that "intptr_t" wasn't special in any way here, and that any casting of
>> a function pointer to either it or a "void *" was what was made portable
>> by "J.5.7"
>
> How is it made portable by an "unportable" extension?

I'm just repeating the terminology the standard uses: "The following
extensions are widely used in many systems, but are not portable to all
implementations".

>> So I think aside from other concerns this should be safe to use, as
>> real-world data backing that up we've had a intptr_t converted to a
>> function pointer since v2.35.0: 5cb28270a1f (pack-objects: lazily set up
>> "struct rev_info", don't leak, 2022-03-28).
>
> Saying "it works so it is fine" is not a convincing argument that it
> is compliant with the standard. 

I was saying, among other things, that it's standardized by POSIX, so
it's in the same category as ssize_t, not some hypothetical "happens to
work" undefined behavior.

But we also make use of it already, so that gives us some real-world
data on potential issues.

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

* Re: [PATCH 09/13] parse-options API: don't restrict OPT_SUBCOMMAND() to one *_fn type
  2022-11-05 17:26         ` René Scharfe
@ 2022-11-05 22:33           ` Ævar Arnfjörð Bjarmason
  2022-11-06  8:25             ` René Scharfe
  0 siblings, 1 reply; 106+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-05 22:33 UTC (permalink / raw)
  To: René Scharfe
  Cc: git, Junio C Hamano, Jeff King, Taylor Blau,
	Đoàn Trần Công Danh, SZEDER Gábor,
	Lukáš Doktor, Johannes Schindelin


On Sat, Nov 05 2022, René Scharfe wrote:

> Am 05.11.22 um 14:52 schrieb Ævar Arnfjörð Bjarmason:
>>
>> I think that's an "unportable" extension covered in "J.5 Common
>> extensions", specifically "J.5.7 Function pointer casts":
>>
>> 	A pointer to an object or to void may be cast to a pointer to a
>> 	function, allowing data to be invoked as a function
>>
>> Thus, since the standard already establishes that valid "void *" and
>> "intptr_t" pointers can be cast'd back & forth, the J.5.7 bridges the
>> gap between the two saying a function pointer can be converted to
>> either.
>>
>> Now, I may be missing something here, but I was under the impression
>> that "intptr_t" wasn't special in any way here, and that any casting of
>> a function pointer to either it or a "void *" was what was made portable
>> by "J.5.7".
>
> Do you mean "possible" or "workable" instead of "portable" here?  As you
> write above, J.5.7 is an extension, not (fully) portable.

I think my just-sent in the side-thread should clarify this.

>> Anyway, like ssize_t and a few other things this is extended upon and
>> made standard by POSIX. I.e. we're basically talking about whether this
>> passes:
>>
>> 	assert(sizeof(void (*)(void)) == sizeof(void*))
>>
>> And per POSIX
>> (https://pubs.opengroup.org/onlinepubs/9699919799/functions/dlsym.html):
>>
>> 	Note that conversion from a void * pointer to a function pointer
>> 	as in:
>>
>> 		fptr = (int (*)(int))dlsym(handle, "my_function");
>>
>> 	is not defined by the ISO C standard. This standard requires
>> 	this conversion to work correctly on conforming implementations.
>
> Conversion from object pointer to function pointer can still work if
> function pointers are wider.
>
>> So I think aside from other concerns this should be safe to use, as
>> real-world data backing that up we've had a intptr_t converted to a
>> function pointer since v2.35.0: 5cb28270a1f (pack-objects: lazily set up
>> "struct rev_info", don't leak, 2022-03-28).
>
> That may not have reached unusual architectures, yet.  Let's replace
> that cast with something boring before someone gets hurt.  Something
> like this?
>
>
> diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
> index 573d0b20b7..9e6f1530c6 100644
> --- a/builtin/pack-objects.c
> +++ b/builtin/pack-objects.c
> @@ -4154,14 +4154,15 @@ struct po_filter_data {
>  	struct rev_info revs;
>  };
>
> -static struct list_objects_filter_options *po_filter_revs_init(void *value)
> +static int list_objects_filter_cb(const struct option *opt,
> +				  const char *arg, int unset)
>  {
> -	struct po_filter_data *data = value;
> +	struct po_filter_data *data = opt->value;
>
>  	repo_init_revisions(the_repository, &data->revs, NULL);
>  	data->have_revs = 1;
>
> -	return &data->revs.filter;
> +	return opt_parse_list_objects_filter(&data->revs.filter, arg, unset);
>  }
>
>  int cmd_pack_objects(int argc, const char **argv, const char *prefix)
> @@ -4265,7 +4266,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
>  			      &write_bitmap_index,
>  			      N_("write a bitmap index if possible"),
>  			      WRITE_BITMAP_QUIET, PARSE_OPT_HIDDEN),
> -		OPT_PARSE_LIST_OBJECTS_FILTER_INIT(&pfd, po_filter_revs_init),
> +		OPT_PARSE_LIST_OBJECTS_FILTER_F(&pfd, list_objects_filter_cb),
>  		OPT_CALLBACK_F(0, "missing", NULL, N_("action"),
>  		  N_("handling for missing objects"), PARSE_OPT_NONEG,
>  		  option_parse_missing_action),
> diff --git a/list-objects-filter-options.c b/list-objects-filter-options.c
> index 5339660238..2e560c2fdb 100644
> --- a/list-objects-filter-options.c
> +++ b/list-objects-filter-options.c
> @@ -286,15 +286,9 @@ void parse_list_objects_filter(
>  		die("%s", errbuf.buf);
>  }
>
> -int opt_parse_list_objects_filter(const struct option *opt,
> +int opt_parse_list_objects_filter(struct list_objects_filter_options *filter_options,
>  				  const char *arg, int unset)
>  {
> -	struct list_objects_filter_options *filter_options = opt->value;
> -	opt_lof_init init = (opt_lof_init)opt->defval;
> -
> -	if (init)
> -		filter_options = init(opt->value);
> -
>  	if (unset || !arg)
>  		list_objects_filter_set_no_filter(filter_options);
>  	else
> @@ -302,6 +296,12 @@ int opt_parse_list_objects_filter(const struct option *opt,
>  	return 0;
>  }
>
> +int opt_parse_list_objects_filter_cb(const struct option *opt,
> +				     const char *arg, int unset)
> +{
> +	return opt_parse_list_objects_filter(opt->value, arg, unset);
> +}
> +
>  const char *list_objects_filter_spec(struct list_objects_filter_options *filter)
>  {
>  	if (!filter->filter_spec.len)
> diff --git a/list-objects-filter-options.h b/list-objects-filter-options.h
> index 7eeadab2dd..fc6b4da06d 100644
> --- a/list-objects-filter-options.h
> +++ b/list-objects-filter-options.h
> @@ -107,31 +107,26 @@ void parse_list_objects_filter(
>  	struct list_objects_filter_options *filter_options,
>  	const char *arg);
>
> +int opt_parse_list_objects_filter(struct list_objects_filter_options *filter_options,
> +				  const char *arg, int unset);
> +
>  /**
>   * The opt->value to opt_parse_list_objects_filter() is either a
>   * "struct list_objects_filter_option *" when using
>   * OPT_PARSE_LIST_OBJECTS_FILTER().
>   *
> - * Or, if using no "struct option" field is used by the callback,
> - * except the "defval" which is expected to be an "opt_lof_init"
> - * function, which is called with the "opt->value" and must return a
> - * pointer to the ""struct list_objects_filter_option *" to be used.
> - *
> - * The OPT_PARSE_LIST_OBJECTS_FILTER_INIT() can be used e.g. the
> - * "struct list_objects_filter_option" is embedded in a "struct
> - * rev_info", which the "defval" could be tasked with lazily
> - * initializing. See cmd_pack_objects() for an example.
> + * Or, OPT_PARSE_LIST_OBJECTS_FILTER_F() can be used to specify a
> + * custom callback function that may expect a different type.
>   */
> -int opt_parse_list_objects_filter(const struct option *opt,
> -				  const char *arg, int unset);
> +int opt_parse_list_objects_filter_cb(const struct option *opt,
> +				     const char *arg, int unset);
>  typedef struct list_objects_filter_options *(*opt_lof_init)(void *);
> -#define OPT_PARSE_LIST_OBJECTS_FILTER_INIT(fo, init) \
> +#define OPT_PARSE_LIST_OBJECTS_FILTER_F(fo, fn) \
>  	{ OPTION_CALLBACK, 0, "filter", (fo), N_("args"), \
> -	  N_("object filtering"), 0, opt_parse_list_objects_filter, \
> -	  (intptr_t)(init) }
> +	  N_("object filtering"), 0, (fn) }
>
>  #define OPT_PARSE_LIST_OBJECTS_FILTER(fo) \
> -	OPT_PARSE_LIST_OBJECTS_FILTER_INIT((fo), NULL)
> +	OPT_PARSE_LIST_OBJECTS_FILTER_F((fo), opt_parse_list_objects_filter_cb)
>
>  /*
>   * Translates abbreviated numbers in the filter's filter_spec into their

I think "just leave it, and see if anyone complains".

If you look over config.mak.uname you can see what we're likely to be
ported to (and some of that's probably dead). The list of potential
targets that:

 1) We know of ports to, or people would plausibly port git to
 2) Are updated so slow that they're on a release that's getting close
    to a year old.

Are small, and it's usually easy to look up their memory model etc. are
you concerned about any specific one?

I think if you're worried enough about it to push for the diff above:
Can we just hide it behind an "#ifdef", then if we find that nobody's
using it, we can consider it safe to use.

I don't think there's any great benefit to the extension in that
specific case, but there might be in the future (e.g. this topic would
be one small user), so since we already have an unintentional test
ballon, why not see if we can keep it safely?

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

* Re: [PATCH v2 0/3] Convert git-bisect--helper to OPT_SUBCOMMAND
  2022-11-05 17:03   ` [PATCH v2 " Đoàn Trần Công Danh
                       ` (3 preceding siblings ...)
  2022-11-05 17:07     ` [PATCH 00/13] Turn git-bisect to be builtin Đoàn Trần Công Danh
@ 2022-11-05 23:18     ` Taylor Blau
  4 siblings, 0 replies; 106+ messages in thread
From: Taylor Blau @ 2022-11-05 23:18 UTC (permalink / raw)
  To: Đoàn Trần Công Danh
  Cc: git, Lukáš Doktor, Jeff King, Christian Couder,
	Ævar Arnfjörð Bjarmason

On Sun, Nov 06, 2022 at 12:03:33AM +0700, Đoàn Trần Công Danh wrote:
>  builtin/bisect--helper.c    | 229 ++++++++++++++++++++----------------
>  git-bisect.sh               |  23 +---
>  t/t6030-bisect-porcelain.sh |  10 ++
>  3 files changed, 142 insertions(+), 120 deletions(-)

Thanks, this version looks good to me. Will queue.

Thanks,
Taylor

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

* Re: [PATCH 09/13] parse-options API: don't restrict OPT_SUBCOMMAND() to one *_fn type
  2022-11-05 22:33           ` Ævar Arnfjörð Bjarmason
@ 2022-11-06  8:25             ` René Scharfe
  2022-11-06 13:28               ` Ævar Arnfjörð Bjarmason
  0 siblings, 1 reply; 106+ messages in thread
From: René Scharfe @ 2022-11-06  8:25 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: git, Junio C Hamano, Jeff King, Taylor Blau,
	Đoàn Trần Công Danh, SZEDER Gábor,
	Lukáš Doktor, Johannes Schindelin

Am 05.11.22 um 23:33 schrieb Ævar Arnfjörð Bjarmason:
>
> On Sat, Nov 05 2022, René Scharfe wrote:
>
>> Am 05.11.22 um 14:52 schrieb Ævar Arnfjörð Bjarmason:
>>>
>>> I think that's an "unportable" extension covered in "J.5 Common
>>> extensions", specifically "J.5.7 Function pointer casts":
>>>
>>> 	A pointer to an object or to void may be cast to a pointer to a
>>> 	function, allowing data to be invoked as a function
>>>
>>> Thus, since the standard already establishes that valid "void *" and
>>> "intptr_t" pointers can be cast'd back & forth, the J.5.7 bridges the
>>> gap between the two saying a function pointer can be converted to
>>> either.
>>>
>>> Now, I may be missing something here, but I was under the impression
>>> that "intptr_t" wasn't special in any way here, and that any casting of
>>> a function pointer to either it or a "void *" was what was made portable
>>> by "J.5.7".
>>
>> Do you mean "possible" or "workable" instead of "portable" here?  As you
>> write above, J.5.7 is an extension, not (fully) portable.
>
> I think my just-sent in the side-thread should clarify this.

AFAIU you think that J.5.7 plus POSIX make conversions between object
pointers and function pointers portable.

>>> Anyway, like ssize_t and a few other things this is extended upon and
>>> made standard by POSIX. I.e. we're basically talking about whether this
>>> passes:
>>>
>>> 	assert(sizeof(void (*)(void)) == sizeof(void*))
>>>
>>> And per POSIX
>>> (https://pubs.opengroup.org/onlinepubs/9699919799/functions/dlsym.html):
>>>
>>> 	Note that conversion from a void * pointer to a function pointer
>>> 	as in:
>>>
>>> 		fptr = (int (*)(int))dlsym(handle, "my_function");
>>>
>>> 	is not defined by the ISO C standard. This standard requires
>>> 	this conversion to work correctly on conforming implementations.
>>
>> Conversion from object pointer to function pointer can still work if
>> function pointers are wider.

This means that a compliant implementation could lose bits when going
the other way, i.e. converting a function pointer to an object pointer.

>>> So I think aside from other concerns this should be safe to use, as
>>> real-world data backing that up we've had a intptr_t converted to a
>>> function pointer since v2.35.0: 5cb28270a1f (pack-objects: lazily set up
>>> "struct rev_info", don't leak, 2022-03-28).
>>
>> That may not have reached unusual architectures, yet.  Let's replace
>> that cast with something boring before someone gets hurt.  Something
>> like this?

[snip]

> I think "just leave it, and see if anyone complains".
>
> If you look over config.mak.uname you can see what we're likely to be
> ported to (and some of that's probably dead). The list of potential
> targets that:
>
>  1) We know of ports to, or people would plausibly port git to
>  2) Are updated so slow that they're on a release that's getting close
>     to a year old.
>
> Are small, and it's usually easy to look up their memory model etc. are
> you concerned about any specific one?

Using implementation-defined behavior and requiring extensions when
standard code would work just as well makes no sense to me.

> I think if you're worried enough about it to push for the diff above:
> Can we just hide it behind an "#ifdef", then if we find that nobody's
> using it, we can consider it safe to use.
>
> I don't think there's any great benefit to the extension in that
> specific case, but there might be in the future (e.g. this topic would
> be one small user), so since we already have an unintentional test
> ballon, why not see if we can keep it safely?

You can't certify safety with tests.  Undefined behavior may manifest
itself in weird ways and only under certain circumstances.  Future
architectures may add new failure modes.  It's not like a syntax
extension, to which nonsupporting compilers respond with an error,
i.e. a clear signal.

René

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

* Re: [PATCH 09/13] parse-options API: don't restrict OPT_SUBCOMMAND() to one *_fn type
  2022-11-06  8:25             ` René Scharfe
@ 2022-11-06 13:28               ` Ævar Arnfjörð Bjarmason
  2022-11-12 10:42                 ` René Scharfe
  0 siblings, 1 reply; 106+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-06 13:28 UTC (permalink / raw)
  To: René Scharfe
  Cc: git, Junio C Hamano, Jeff King, Taylor Blau,
	Đoàn Trần Công Danh, SZEDER Gábor,
	Lukáš Doktor, Johannes Schindelin


On Sun, Nov 06 2022, René Scharfe wrote:

> Am 05.11.22 um 23:33 schrieb Ævar Arnfjörð Bjarmason:
>>
>> On Sat, Nov 05 2022, René Scharfe wrote:
>>
>>> Am 05.11.22 um 14:52 schrieb Ævar Arnfjörð Bjarmason:
>>>>
>>>> I think that's an "unportable" extension covered in "J.5 Common
>>>> extensions", specifically "J.5.7 Function pointer casts":
>>>>
>>>> 	A pointer to an object or to void may be cast to a pointer to a
>>>> 	function, allowing data to be invoked as a function
>>>>
>>>> Thus, since the standard already establishes that valid "void *" and
>>>> "intptr_t" pointers can be cast'd back & forth, the J.5.7 bridges the
>>>> gap between the two saying a function pointer can be converted to
>>>> either.
>>>>
>>>> Now, I may be missing something here, but I was under the impression
>>>> that "intptr_t" wasn't special in any way here, and that any casting of
>>>> a function pointer to either it or a "void *" was what was made portable
>>>> by "J.5.7".
>>>
>>> Do you mean "possible" or "workable" instead of "portable" here?  As you
>>> write above, J.5.7 is an extension, not (fully) portable.
>>
>> I think my just-sent in the side-thread should clarify this.
>
> AFAIU you think that J.5.7 plus POSIX make conversions between object
> pointers and function pointers portable.

No, I think that:

1) J.5.7 does that on its own for C99
2) POSIX has orthagonally mandated this, seperate from C99.

In practice I think it's always worked for dlsym(), but there's
interesting changes in wording between v6 and v7 of POSIX:

   - https://pubs.opengroup.org/onlinepubs/009695399/functions/dlsym.html
   - https://pubs.opengroup.org/onlinepubs/9699919799/functions/dlsym.html

v6 claims that conforming C compilers are required to produce a warning
if this isn't supported (I haven't found the part of the standard
they're referencing), and notes that the behavior may be deprecated in
the future.

Whereas v7 says that POSIX "requires this conversion to work correctly
on conforming implementations".

Is your reading of any of that different?

In addition to that: This is widely supported on systems that didn't
aquire such support via optional C99 extensions, or POSIX. E.g. Win32.

I think this is one of those things that C has left deliberately
undefined for the benefit of embedded implementations, and others with
odd memory models.

>> I think "just leave it, and see if anyone complains".
>>
>> If you look over config.mak.uname you can see what we're likely to be
>> ported to (and some of that's probably dead). The list of potential
>> targets that:
>>
>>  1) We know of ports to, or people would plausibly port git to
>>  2) Are updated so slow that they're on a release that's getting close
>>     to a year old.
>>
>> Are small, and it's usually easy to look up their memory model etc. are
>> you concerned about any specific one?
>
> Using implementation-defined behavior and requiring extensions when
> standard code would work just as well makes no sense to me.

I think it's useful in itself to see what subset or superset of C we
actually need to concern ourselves with.

E.g. we have plenty of code that assumes ASCII, instead of catering to
EBCDIC, and assuming NULL is (void *)0, not (void *)123456 or whatever.

Yes, in this case the alternative is trivial, but perhaps we'd find a
use-case in the future.

All I'm saying is let's leave the current one in place, as there's no
indication that it's not supported by our targets.

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

* Re: [PATCH 07/13] bisect--helper: pretend we're real bisect when report error
  2022-11-05 17:07       ` [PATCH 07/13] bisect--helper: pretend we're real bisect when report error Đoàn Trần Công Danh
@ 2022-11-07 21:29         ` Ævar Arnfjörð Bjarmason
  0 siblings, 0 replies; 106+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-07 21:29 UTC (permalink / raw)
  To: Đoàn Trần Công Danh
  Cc: git, Taylor Blau, Jeff King, Christian Couder


On Sun, Nov 06 2022, Đoàn Trần Công Danh wrote:

> In a later change, we will convert the bisect--helper to be builtin
> bisect. Let's start by pretending it's the real bisect when reporting
> error.

It's good to have this in here, FWIW I left this out of my version
reasoning that it was broken before, so we could leave it with the
psot-cleanups.

I'm fine with having it in while we're at it, but just FWIW:

I don't think we're "pretending". We *are* the bisect command, the fact
that we're implementing it via a "helper" is really quite irrelevant,
just like we're not "pretending" if we say we're "git bisect" instead of
"git-bisect.sh" or whatever.

The only cases where we should have these helpers report that they are
the helper is for messages that aren't user-visible, e.g. the "-h"
output emitted when you invoke a helper-specific command that no user
should be invoking (although arguably, we should just BUG() out
there...).

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

* Re: [PATCH 01/13] bisect tests: test for v2.30.0 "bisect run" regressions
  2022-11-05 17:07       ` [PATCH 01/13] bisect tests: test for v2.30.0 "bisect run" regressions Đoàn Trần Công Danh
@ 2022-11-07 21:31         ` Ævar Arnfjörð Bjarmason
  2022-11-08  1:17           ` Đoàn Trần Công Danh
  0 siblings, 1 reply; 106+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-07 21:31 UTC (permalink / raw)
  To: Đoàn Trần Công Danh
  Cc: git, Taylor Blau, Jeff King, Christian Couder


On Sun, Nov 06 2022, Đoàn Trần Công Danh wrote:

> From: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
>
> Add three failing tests which succeed on v2.29.0, but due to the topic
> merged at [1] (specifically [2]) have been failing since then. We'll
> address those regressions in subsequent commits.
>
> There was also a "regression" where:
>
> 	git bisect run ./missing-script.sh
>
> Would count a non-existing script as "good", as the shell would exit
> with 127. That edge case is a bit too insane to preserve, so let's not
> add it to these regression tests.
>
> 1. 0a4cb1f1f2f (Merge branch 'mr/bisect-in-c-4', 2021-09-23)
> 2. d1bbbe45df8 (bisect--helper: reimplement `bisect_run` shell
>    function in C, 2021-09-13)
>
> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
> Signed-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>
> ---
>  t/t6030-bisect-porcelain.sh | 79 +++++++++++++++++++++++++++++++++++++
>  1 file changed, 79 insertions(+)

Looks good, if I do say so myself :) (unchanged from my topic)

But I wonder why your "fix the regression" base topic isn't starting
with this. I.e. our intial report was about that "--log" issue, but now
we know we altered the output in ways we didn't intend.

It's fine if we say "that's less important", but then ... something
should say that .. :)

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

* Re: [PATCH 05/13] bisect run: keep some of the post-v2.30.0 output
  2022-11-05 17:07       ` [PATCH 05/13] bisect run: keep some of the post-v2.30.0 output Đoàn Trần Công Danh
@ 2022-11-07 21:40         ` Ævar Arnfjörð Bjarmason
  2022-11-08  1:26           ` Đoàn Trần Công Danh
  0 siblings, 1 reply; 106+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-07 21:40 UTC (permalink / raw)
  To: Đoàn Trần Công Danh
  Cc: git, Taylor Blau, Jeff King, Christian Couder


On Sun, Nov 06 2022, Đoàn Trần Công Danh wrote:

> From: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
>
> Preceding commits fixed output and behavior regressions in
> d1bbbe45df8 (bisect--helper: reimplement `bisect_run` shell function
> in C, 2021-09-13), which did not claim to be changing the output of
> "git bisect run".
>
> But some of the output it emitted was subjectively better, so once
> we've asserted that we're back on v2.29.0 behavior, let's change some
> of it back:
>
> - We now quote the arguments again, but omit the first " " when
>   printing the "running" line.
> - Ditto for other cases where we emitted the argument
> - We say "found first bad commit" again, not just "run success"

So, something you refactored here was that there's now a
do_bisect_run(), and:

> -static int do_bisect_run(const char *command, int argc, const char **argv)
> +static int do_bisect_run(const char *command, int argc UNUSED, const char **argv UNUSED)
>  {
>  	struct child_process cmd = CHILD_PROCESS_INIT;
> -	struct strbuf buf = STRBUF_INIT;
> +	const char *trimed = command;
>  
> -	strbuf_join_argv(&buf, argc, argv, ' ');
> -	printf(_("running %s\n"), buf.buf);
> -	strbuf_release(&buf);
> +	while (*trimed && isspace(*trimed))
> +		trimed++;
> +	printf(_("running %s\n"), trimed);
>  	cmd.use_shell = 1;
>  	strvec_push(&cmd.args, command);
>  	return run_command(&cmd);

Instead of trimming with strbuf_ltrim() we're now using this loop, but
in any case, this has had the effect that you're only fixing one of many
of the output changes. We're still adding this leading whitespace to the
other messages we emit.

As note din the preceding commit you've carried here in 03/13 I didn't
have time to come up with tests for those.

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

* Re: [PATCH 11/13] bisect--helper: remove subcommand state
  2022-11-05 17:07       ` [PATCH 11/13] bisect--helper: remove subcommand state Đoàn Trần Công Danh
@ 2022-11-07 21:45         ` Ævar Arnfjörð Bjarmason
  2022-11-08  1:27           ` Đoàn Trần Công Danh
  0 siblings, 1 reply; 106+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-07 21:45 UTC (permalink / raw)
  To: Đoàn Trần Công Danh
  Cc: git, Taylor Blau, Jeff King, Christian Couder


On Sun, Nov 06 2022, Đoàn Trần Công Danh wrote:

> In previous change, we've made 'state' optional, and replaced all of its
> usage.
>
> Let's remove it, now.

Let's remove it then? I.e. let's squash this into 10/13. No reason not
to...

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

* Re: [PATCH 01/13] bisect tests: test for v2.30.0 "bisect run" regressions
  2022-11-07 21:31         ` Ævar Arnfjörð Bjarmason
@ 2022-11-08  1:17           ` Đoàn Trần Công Danh
  0 siblings, 0 replies; 106+ messages in thread
From: Đoàn Trần Công Danh @ 2022-11-08  1:17 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: git, Taylor Blau, Jeff King, Christian Couder

On 2022-11-07 22:31:50+0100, Ævar Arnfjörð Bjarmason <avarab@gmail.com> wrote:
> 
> On Sun, Nov 06 2022, Đoàn Trần Công Danh wrote:
> 
> > From: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
> >
> > Add three failing tests which succeed on v2.29.0, but due to the topic
> > merged at [1] (specifically [2]) have been failing since then. We'll
> > address those regressions in subsequent commits.
> >
> > There was also a "regression" where:
> >
> > 	git bisect run ./missing-script.sh
> >
> > Would count a non-existing script as "good", as the shell would exit
> > with 127. That edge case is a bit too insane to preserve, so let's not
> > add it to these regression tests.
> >
> > 1. 0a4cb1f1f2f (Merge branch 'mr/bisect-in-c-4', 2021-09-23)
> > 2. d1bbbe45df8 (bisect--helper: reimplement `bisect_run` shell
> >    function in C, 2021-09-13)
> >
> > Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
> > Signed-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>
> > ---
> >  t/t6030-bisect-porcelain.sh | 79 +++++++++++++++++++++++++++++++++++++
> >  1 file changed, 79 insertions(+)
> 
> Looks good, if I do say so myself :) (unchanged from my topic)
> 
> But I wonder why your "fix the regression" base topic isn't starting
> with this. I.e. our intial report was about that "--log" issue, but now
> we know we altered the output in ways we didn't intend.

Well, I would like to keep that topic as much short as possible to
have a higher chance of fixing real regression first. Those changes is
error/warning/log are less important as you said below ...
 
> It's fine if we say "that's less important", but then ... something
> should say that .. :)

Sure, I will add it in the next revision.


-- 
Danh

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

* Re: [PATCH 05/13] bisect run: keep some of the post-v2.30.0 output
  2022-11-07 21:40         ` Ævar Arnfjörð Bjarmason
@ 2022-11-08  1:26           ` Đoàn Trần Công Danh
  2022-11-08  3:11             ` Ævar Arnfjörð Bjarmason
  0 siblings, 1 reply; 106+ messages in thread
From: Đoàn Trần Công Danh @ 2022-11-08  1:26 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: git, Taylor Blau, Jeff King, Christian Couder

On 2022-11-07 22:40:33+0100, Ævar Arnfjörð Bjarmason <avarab@gmail.com> wrote:
> 
> On Sun, Nov 06 2022, Đoàn Trần Công Danh wrote:
> 
> > From: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
> >
> > Preceding commits fixed output and behavior regressions in
> > d1bbbe45df8 (bisect--helper: reimplement `bisect_run` shell function
> > in C, 2021-09-13), which did not claim to be changing the output of
> > "git bisect run".
> >
> > But some of the output it emitted was subjectively better, so once
> > we've asserted that we're back on v2.29.0 behavior, let's change some
> > of it back:
> >
> > - We now quote the arguments again, but omit the first " " when
> >   printing the "running" line.
> > - Ditto for other cases where we emitted the argument
> > - We say "found first bad commit" again, not just "run success"
> 
> So, something you refactored here was that there's now a
> do_bisect_run(), and:
> 
> > -static int do_bisect_run(const char *command, int argc, const char **argv)
> > +static int do_bisect_run(const char *command, int argc UNUSED, const char **argv UNUSED)
> >  {
> >  	struct child_process cmd = CHILD_PROCESS_INIT;
> > -	struct strbuf buf = STRBUF_INIT;
> > +	const char *trimed = command;
> >  
> > -	strbuf_join_argv(&buf, argc, argv, ' ');
> > -	printf(_("running %s\n"), buf.buf);
> > -	strbuf_release(&buf);
> > +	while (*trimed && isspace(*trimed))
> > +		trimed++;
> > +	printf(_("running %s\n"), trimed);
> >  	cmd.use_shell = 1;
> >  	strvec_push(&cmd.args, command);
> >  	return run_command(&cmd);
> 
> Instead of trimming with strbuf_ltrim() we're now using this loop, but
> in any case, this has had the effect that you're only fixing one of many
> of the output changes. We're still adding this leading whitespace to the
> other messages we emit.

Sorry, I can't follow, we're fixing in do_bisect_run, which meant we
fixed all of the output changes for leading whitespace, no?

'do_bisect_run' will be called from normal 'git bisect run' iteration
and also after receiving code 126/127 for the very first run.

Which is the other cases you're talking about?

> 
> As note din the preceding commit you've carried here in 03/13 I didn't
> have time to come up with tests for those.

-- 
Danh

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

* Re: [PATCH 11/13] bisect--helper: remove subcommand state
  2022-11-07 21:45         ` Ævar Arnfjörð Bjarmason
@ 2022-11-08  1:27           ` Đoàn Trần Công Danh
  0 siblings, 0 replies; 106+ messages in thread
From: Đoàn Trần Công Danh @ 2022-11-08  1:27 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: git, Taylor Blau, Jeff King, Christian Couder

On 2022-11-07 22:45:50+0100, Ævar Arnfjörð Bjarmason <avarab@gmail.com> wrote:
> 
> On Sun, Nov 06 2022, Đoàn Trần Công Danh wrote:
> 
> > In previous change, we've made 'state' optional, and replaced all of its
> > usage.
> >
> > Let's remove it, now.
> 
> Let's remove it then? I.e. let's squash this into 10/13. No reason not
> to...

I was following the existing (I think) practice of removing
a subcommand in a separated commit. Sure, I can meld it into 10/13

-- 
Danh

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

* Re: [PATCH 05/13] bisect run: keep some of the post-v2.30.0 output
  2022-11-08  1:26           ` Đoàn Trần Công Danh
@ 2022-11-08  3:11             ` Ævar Arnfjörð Bjarmason
  0 siblings, 0 replies; 106+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-08  3:11 UTC (permalink / raw)
  To: Đoàn Trần Công Danh
  Cc: git, Taylor Blau, Jeff King, Christian Couder


On Tue, Nov 08 2022, Đoàn Trần Công Danh wrote:

> On 2022-11-07 22:40:33+0100, Ævar Arnfjörð Bjarmason <avarab@gmail.com> wrote:
>> 
>> On Sun, Nov 06 2022, Đoàn Trần Công Danh wrote:
>> 
>> > From: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
>> >
>> > Preceding commits fixed output and behavior regressions in
>> > d1bbbe45df8 (bisect--helper: reimplement `bisect_run` shell function
>> > in C, 2021-09-13), which did not claim to be changing the output of
>> > "git bisect run".
>> >
>> > But some of the output it emitted was subjectively better, so once
>> > we've asserted that we're back on v2.29.0 behavior, let's change some
>> > of it back:
>> >
>> > - We now quote the arguments again, but omit the first " " when
>> >   printing the "running" line.
>> > - Ditto for other cases where we emitted the argument
>> > - We say "found first bad commit" again, not just "run success"
>> 
>> So, something you refactored here was that there's now a
>> do_bisect_run(), and:
>> 
>> > -static int do_bisect_run(const char *command, int argc, const char **argv)
>> > +static int do_bisect_run(const char *command, int argc UNUSED, const char **argv UNUSED)
>> >  {
>> >  	struct child_process cmd = CHILD_PROCESS_INIT;
>> > -	struct strbuf buf = STRBUF_INIT;
>> > +	const char *trimed = command;
>> >  
>> > -	strbuf_join_argv(&buf, argc, argv, ' ');
>> > -	printf(_("running %s\n"), buf.buf);
>> > -	strbuf_release(&buf);
>> > +	while (*trimed && isspace(*trimed))
>> > +		trimed++;
>> > +	printf(_("running %s\n"), trimed);
>> >  	cmd.use_shell = 1;
>> >  	strvec_push(&cmd.args, command);
>> >  	return run_command(&cmd);
>> 
>> Instead of trimming with strbuf_ltrim() we're now using this loop, but
>> in any case, this has had the effect that you're only fixing one of many
>> of the output changes. We're still adding this leading whitespace to the
>> other messages we emit.
>
> Sorry, I can't follow, we're fixing in do_bisect_run, which meant we
> fixed all of the output changes for leading whitespace, no?
>
> 'do_bisect_run' will be called from normal 'git bisect run' iteration
> and also after receiving code 126/127 for the very first run.
>
> Which is the other cases you're talking about?

The other uses of command.buf in my initial version, i.e. I did:
	
	-       strbuf_reset(&command);
	-       strbuf_join_argv(&command, argc, argv, ' ');
	+       /* Quoted, but skip initial " " */
	+       strbuf_ltrim(&command);

And the command.buf is then used by:

	printf(_("running %s\n"), command.buf);
	res = run_command_v_opt(run_args.v, RUN_USING_SHELL);

Which your version covers, but also this, in bisect_run() just a few
lines later:

	error(_("unable to verify '%s' on good"
	      " revision"), command.buf);

And, for:

	error(_("bisect run failed: exit code %d from"
	      " '%s' is < 0 or >= 128"), res, command.buf);

In the original *.sh version of this it used the same variable.

But yours deals with the refactored do_bisect_run() from René's
e8de018438e (bisect--helper: factor out do_bisect_run(), 2022-10-27).

So that first "running" takes place in its ownown do_bisect_run()
function, and you only skip past the whitespace in the "const char
*command" local to that function.

Thus you're only trimming the whitespace for 1/3 cases, the 2/3 being
noted in the 04/13 as the ones I didn't write a test for.

I think this squashed in should be functionally equivalent:
	
	diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
	index f16b9df8fd6..493e062e76d 100644
	--- a/builtin/bisect--helper.c
	+++ b/builtin/bisect--helper.c
	@@ -1141,20 +1141,17 @@ static int get_first_good(const char *refname UNUSED,
	 	return 1;
	 }
	 
	-static int do_bisect_run(const char *command, int argc UNUSED, const char **argv UNUSED)
	+static int do_bisect_run(const char *command, const char *trimmed)
	 {
	 	struct child_process cmd = CHILD_PROCESS_INIT;
	-	const char *trimed = command;
	 
	-	while (*trimed && isspace(*trimed))
	-		trimed++;
	-	printf(_("running %s\n"), trimed);
	+	printf(_("running %s\n"), trimmed);
	 	cmd.use_shell = 1;
	 	strvec_push(&cmd.args, command);
	 	return run_command(&cmd);
	 }
	 
	-static int verify_good(const struct bisect_terms *terms, const char *command, int argc, const char **argv)
	+static int verify_good(const struct bisect_terms *terms, const char *command, const char *trimmed)
	 {
	 	int rc;
	 	enum bisect_error res;
	@@ -1174,7 +1171,7 @@ static int verify_good(const struct bisect_terms *terms, const char *command, in
	 	if (res != BISECT_OK)
	 		return -1;
	 
	-	rc = do_bisect_run(command, argc, argv);
	+	rc = do_bisect_run(command, trimmed);
	 
	 	res = bisect_checkout(&current_rev, no_checkout);
	 	if (res != BISECT_OK)
	@@ -1187,6 +1184,7 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
	 {
	 	int res = BISECT_OK;
	 	struct strbuf command = STRBUF_INIT;
	+	struct strbuf trimmed = STRBUF_INIT;
	 	const char *new_state;
	 	int temporary_stdout_fd, saved_stdout;
	 	int is_first_run = 1;
	@@ -1200,8 +1198,10 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
	 	}
	 
	 	sq_quote_argv(&command, argv);
	+	strbuf_addbuf(&trimmed, &command);
	+	strbuf_ltrim(&trimmed);
	 	while (1) {
	-		res = do_bisect_run(command.buf, argc, argv);
	+		res = do_bisect_run(command.buf, trimmed.buf);
	 
	 		/*
	 		 * Exit code 126 and 127 can either come from the shell
	@@ -1211,7 +1211,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, command.buf, argc, argv);
	+			int rc = verify_good(terms, command.buf, trimmed.buf);
	 			is_first_run = 0;
	 			if (rc < 0) {
	 				error(_("unable to verify '%s' on good"

Some of that's a bit of a hassle with e8de018438e, but this way we use
the whitespace-prefixed for run_command(), but not for the output. Maybe
we can just always use the trimmed version, I didn't check.

This approach would also mean that you can drop your 03/13 and 06/13
surrounding this commit, in 03/13 you added that argv/argc because:

	[...]	
	In a later change, we would like to restore the old behaviours,
	which would need information regarding argc and argv.

That "later change" is your 04/13, then in 05/13 you're back to them
being UNUSED, before 06/13 finally drops them.

But if we just pass both trimmed & non-trimmed into do_bisect_run() to
begin with we don't need to go through all of that...

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

* Re: [PATCH 00/13] bisect: v2.30.0 "run" regressions + make it built-in
  2022-11-04 13:22 ` [PATCH 00/13] bisect: v2.30.0 "run" regressions + make it built-in Ævar Arnfjörð Bjarmason
                     ` (13 preceding siblings ...)
  2022-11-05  0:13   ` [PATCH 00/13] bisect: v2.30.0 "run" regressions + make it built-in Taylor Blau
@ 2022-11-10 12:50   ` Johannes Schindelin
  14 siblings, 0 replies; 106+ messages in thread
From: Johannes Schindelin @ 2022-11-10 12:50 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: git, Junio C Hamano, Jeff King, Taylor Blau,
	Đoàn Trần Công Danh, SZEDER Gábor,
	Lukáš Doktor

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

Hi Ævar,

I see you Cc:ed me on this, but I have to admit that I am not motivated to
review this patch series because it seems to be designed to interfere with
`js/bisect-in-c` instead of being an honest effort to help me get that
patch series over the finish line.

I'd much rather see you assist me in the most efficient/minimal way
possible to get `js/bisect-in-c` into a shape that can be integrated.

Ciao,
Johannes

On Fri, 4 Nov 2022, Ævar Arnfjörð Bjarmason wrote:

> This fixes the regression Lukáš Doktor reported in [1], and also gets
> us the full way to a builtin/bisect.c and "git rm git-bisect.sh".
>
> Only 1-4/13 here are needed to fix the "git bisect run <cmd> [...]
> --log" regression Lukáš reported, but as Jeff points out we'd still
> conflate "--bisect-*" with the user arguments. That's fixed in 11/13
> here.
>
> The 1-4/13 here also fixes other but probably more minor "git bisect
> run" regressions in v2.30.0, we changed the output in a few ways
> without intending it. 4/13 gets us mostly back to v2.29.0 behavior,
> 5/13 keeps the best of it and the current output.
>
> I think for the v2.30.0 regressions we're better off with just
> something like 1-4/13 here for now, and possibly 5/13 too.
>
> But getting to the point of fixing the root cause of "--bisect-*"
> being conflated is going to take quite a bit of churn. In the
> side-thread Đoàn's diffstat is on the order of 1/2 of the size of this
> series, and this gives us built-in "bisect".
>
> The 6-13 here is something I had already for a couple of days, I was
> seeing if I could distill Johannes's [2] down to something much
> smaller, to just make a beeline towards a built-in bisect.
>
> Johannes's refactors the "term" passing in [3], and Đoàn ends up
> needing to do much the same in [4].
>
> Here in 9/13 I instead just extend the OPT_SUBCOMMAND() API so it's
> able to accept function callbacks with custom signatures, which
> eliminates the need for most of that refactoring. 11/13 then makes use
> of it.
>
> 1. https://lore.kernel.org/git/1cb1c033-0525-7e62-8c09-81019bf26060@redhat.com/
> 2. https://lore.kernel.org/git/pull.1132.v6.git.1661885419.gitgitgadget@gmail.com/
> 3. https://lore.kernel.org/git/92b3b116ef8f879192d9deb94d68b73e29d5dcd6.1661885419.git.gitgitgadget@gmail.com/
> 4. https://lore.kernel.org/git/081f3f7f9501012404fb9e59ab6d94f632180b53.1667561761.git.congdanhqx@gmail.com/
>
> Johannes Schindelin (3):
>   bisect--helper: remove dead --bisect-{next-check,autostart} code
>   bisect--helper: make `state` optional
>   Turn `git bisect` into a full built-in
>
> Ævar Arnfjörð Bjarmason (10):
>   bisect tests: test for v2.30.0 "bisect run" regressions
>   bisect: refactor bisect_run() to match CodingGuidelines
>   bisect: fix output regressions in v2.30.0
>   bisect run: fix "--log" eating regression in v2.30.0
>   bisect run: keep some of the post-v2.30.0 output
>   bisect test: test exit codes on bad usage
>   bisect--helper: emit usage for "git bisect"
>   bisect--helper: have all functions take state, argc, argv, prefix
>   parse-options API: don't restrict OPT_SUBCOMMAND() to one *_fn  type
>   bisect--helper: convert to OPT_SUBCOMMAND_CB()
>
>  Makefile                               |   3 +-
>  builtin.h                              |   2 +-
>  builtin/{bisect--helper.c => bisect.c} | 250 +++++++++++++------------
>  git-bisect.sh                          |  84 ---------
>  git.c                                  |   2 +-
>  parse-options.c                        |   9 +-
>  parse-options.h                        |  31 ++-
>  t/t6030-bisect-porcelain.sh            | 109 +++++++++++
>  8 files changed, 277 insertions(+), 213 deletions(-)
>  rename builtin/{bisect--helper.c => bisect.c} (86%)
>  delete mode 100755 git-bisect.sh
>
> --
> 2.38.0.1452.g710f45c7951
>
>

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

* [PATCH v3 0/3] Convert git-bisect--helper to OPT_SUBCOMMAND
  2022-11-04 11:40 ` [PATCH 0/3] Convert git-bisect--helper to OPT_SUBCOMMAND Đoàn Trần Công Danh
                     ` (4 preceding siblings ...)
  2022-11-05 17:03   ` [PATCH v2 " Đoàn Trần Công Danh
@ 2022-11-10 16:36   ` Đoàn Trần Công Danh
  2022-11-10 16:36     ` [PATCH v3 1/3] bisect--helper: remove unused options Đoàn Trần Công Danh
                       ` (4 more replies)
  5 siblings, 5 replies; 106+ messages in thread
From: Đoàn Trần Công Danh @ 2022-11-10 16:36 UTC (permalink / raw)
  To: git
  Cc: Đoàn Trần Công Danh, Lukáš Doktor,
	Jeff King, Christian Couder, Taylor Blau,
	Ævar Arnfjörð Bjarmason

Despite this series has been merged into next.
I'm sending this because Taylor said he wanted a (combined) reroll?
<Y2riRSL+NprJt278@nand.local>

Change from v2 is only about cosmetic things, (structure zero-initialization)

This series aims to fix the problem that bisect--helper incorrectly consumes
"--log" when running:

	git bisect run cmd --log

This also clears a way for turning git-bisect into a built-in in a later day.

The series that convert git-bisect to builtin will be posted later as a reply
to this series

Đoàn Trần Công Danh (3):
  bisect--helper: remove unused options
  bisect--helper: move all subcommands into their own functions
  bisect--helper: parse subcommand with OPT_SUBCOMMAND

 builtin/bisect--helper.c    | 229 ++++++++++++++++++++----------------
 git-bisect.sh               |  23 +---
 t/t6030-bisect-porcelain.sh |  10 ++
 3 files changed, 142 insertions(+), 120 deletions(-)

Range-diff against v2:
-:  ---------- > 1:  6b80fd9398 bisect--helper: remove unused options
1:  9d8a3cdd7a ! 2:  248ed392ea bisect--helper: move all subcommands into their own functions
    @@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, cons
     +static int cmd_bisect__terms(int argc, const char **argv, const char *prefix UNUSED)
     +{
     +	int res;
    -+	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
    ++	struct bisect_terms terms = { 0 };
     +
     +	if (argc > 1)
     +		return error(_("--bisect-terms requires 0 or 1 argument"));
    @@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, cons
     +static int cmd_bisect__start(int argc, const char **argv, const char *prefix UNUSED)
     +{
     +	int res;
    -+	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
    ++	struct bisect_terms terms = { 0 };
     +
     +	set_terms(&terms, "bad", "good");
     +	res = bisect_start(&terms, argv, argc);
    @@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, cons
     +static int cmd_bisect__next(int argc, const char **argv UNUSED, const char *prefix)
     +{
     +	int res;
    -+	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
    ++	struct bisect_terms terms = { 0 };
     +
     +	if (argc)
     +		return error(_("--bisect-next requires 0 arguments"));
    @@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, cons
     +static int cmd_bisect__state(int argc, const char **argv, const char *prefix UNUSED)
     +{
     +	int res;
    -+	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
    ++	struct bisect_terms terms = { 0 };
     +
     +	set_terms(&terms, "bad", "good");
     +	get_terms(&terms);
    @@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, cons
     +static int cmd_bisect__replay(int argc, const char **argv, const char *prefix UNUSED)
     +{
     +	int res;
    -+	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
    ++	struct bisect_terms terms = { 0 };
     +
     +	if (argc != 1)
     +		return error(_("no logfile given"));
    @@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, cons
     +static int cmd_bisect__skip(int argc, const char **argv, const char *prefix UNUSED)
     +{
     +	int res;
    -+	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
    ++	struct bisect_terms terms = { 0 };
     +
     +	set_terms(&terms, "bad", "good");
     +	get_terms(&terms);
    @@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, cons
     +static int cmd_bisect__visualize(int argc, const char **argv, const char *prefix UNUSED)
     +{
     +	int res;
    -+	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
    ++	struct bisect_terms terms = { 0 };
     +
     +	get_terms(&terms);
     +	res = bisect_visualize(&terms, argv, argc);
    @@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, cons
     +static int cmd_bisect__run(int argc, const char **argv, const char *prefix UNUSED)
     +{
     +	int res;
    -+	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
    ++	struct bisect_terms terms = { 0 };
     +
     +	if (!argc)
     +		return error(_("bisect run failed: no command provided."));
2:  a62ac72e24 = 3:  b67691f600 bisect--helper: parse subcommand with OPT_SUBCOMMAND
-- 
2.38.1.157.gedabe22e0a


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

* [PATCH v3 1/3] bisect--helper: remove unused options
  2022-11-10 16:36   ` [PATCH v3 " Đoàn Trần Công Danh
@ 2022-11-10 16:36     ` Đoàn Trần Công Danh
  2022-11-11 12:42       ` Ævar Arnfjörð Bjarmason
  2022-11-10 16:36     ` [PATCH v3 2/3] bisect--helper: move all subcommands into their own functions Đoàn Trần Công Danh
                       ` (3 subsequent siblings)
  4 siblings, 1 reply; 106+ messages in thread
From: Đoàn Trần Công Danh @ 2022-11-10 16:36 UTC (permalink / raw)
  To: git
  Cc: Đoàn Trần Công Danh, Lukáš Doktor,
	Jeff King, Christian Couder, Taylor Blau,
	Ævar Arnfjörð Bjarmason

'git-bisect.sh' used to have a 'bisect_next_check' to check if we have
both good/bad, old/new terms set or not.  In commit 129a6cf344
(bisect--helper: `bisect_next_check` shell function in C, 2019-01-02),
a subcommand for bisect--helper was introduced to port the check to C.
Since d1bbbe45df (bisect--helper: reimplement `bisect_run` shell
function in C, 2021-09-13), all users of 'bisect_next_check' was
re-implemented in C, this subcommand was no longer used but we forgot
to remove '--bisect-next-check'.

'git-bisect.sh' also used to have a 'bisect_write' function, whose
third positional parameter was a "nolog" flag.  This flag was only used
when 'bisect_start' invoked 'bisect_write' to write the starting good
and bad revisions.  Then 0f30233a11 (bisect--helper: `bisect_write`
shell function in C, 2019-01-02) ported it to C as a command mode of
'bisect--helper', which (incorrectly) added the '--no-log' option,
and convert the only place ('bisect_start') that call 'bisect_write'
with 'nolog' to 'git bisect--helper --bisect-write' with 'nolog'
instead of '--no-log', since 'bisect--helper' has command modes not
subcommands, all other command modes see and handle that option as well.
This bogus state didn't last long, however, because in the same patch
series 06f5608c14 (bisect--helper: `bisect_start` shell function
partially in C, 2019-01-02) the C reimplementation of bisect_start()
started calling the bisect_write() C function, this time with the
right 'nolog' function parameter. From then on there was no need for
the '--no-log' option in 'bisect--helper'. Eventually all bisect
subcommands were ported to C as 'bisect--helper' command modes, each
calling the bisect_write() C function instead, but when the
'--bisect-write' command mode was removed in 68efed8c8a
(bisect--helper: retire `--bisect-write` subcommand, 2021-02-03) it
forgot to remove that '--no-log' option.
'--no-log' option had never been used and it's unused now.

Let's remove --bisect-next-check and --no-log from option parsing.

Signed-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>
---
 builtin/bisect--helper.c | 7 +------
 1 file changed, 1 insertion(+), 6 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 1d2ce8a0e1..5ec2e67f59 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1283,7 +1283,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,
@@ -1295,12 +1294,10 @@ 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),
-		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,
@@ -1319,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 };
-- 
2.38.1.157.gedabe22e0a


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

* [PATCH v3 2/3] bisect--helper: move all subcommands into their own functions
  2022-11-10 16:36   ` [PATCH v3 " Đoàn Trần Công Danh
  2022-11-10 16:36     ` [PATCH v3 1/3] bisect--helper: remove unused options Đoàn Trần Công Danh
@ 2022-11-10 16:36     ` Đoàn Trần Công Danh
  2022-11-11 13:51       ` Ævar Arnfjörð Bjarmason
  2022-11-10 16:36     ` [PATCH v3 3/3] bisect--helper: parse subcommand with OPT_SUBCOMMAND Đoàn Trần Công Danh
                       ` (2 subsequent siblings)
  4 siblings, 1 reply; 106+ messages in thread
From: Đoàn Trần Công Danh @ 2022-11-10 16:36 UTC (permalink / raw)
  To: git
  Cc: Đoàn Trần Công Danh, Lukáš Doktor,
	Jeff King, Christian Couder, Taylor Blau,
	Ævar Arnfjörð Bjarmason

In a later change, we will use OPT_SUBCOMMAND to parse sub-commands to
avoid consuming non-option opts.

Since OPT_SUBCOMMAND needs a function pointer to operate,
let's move it now.

Signed-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>
---
 builtin/bisect--helper.c | 155 ++++++++++++++++++++++++++++++---------
 1 file changed, 121 insertions(+), 34 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 5ec2e67f59..d425555d1f 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1279,6 +1279,117 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
 	return res;
 }
 
+static int cmd_bisect__reset(int argc, const char **argv, const char *prefix UNUSED)
+{
+	if (argc > 1)
+		return error(_("--bisect-reset requires either no argument or a commit"));
+	return bisect_reset(argc ? argv[0] : NULL);
+}
+
+static int cmd_bisect__terms(int argc, const char **argv, const char *prefix UNUSED)
+{
+	int res;
+	struct bisect_terms terms = { 0 };
+
+	if (argc > 1)
+		return error(_("--bisect-terms requires 0 or 1 argument"));
+	res = bisect_terms(&terms, argc == 1 ? argv[0] : NULL);
+	free_terms(&terms);
+	return res;
+}
+
+static int cmd_bisect__start(int argc, const char **argv, const char *prefix UNUSED)
+{
+	int res;
+	struct bisect_terms terms = { 0 };
+
+	set_terms(&terms, "bad", "good");
+	res = bisect_start(&terms, argv, argc);
+	free_terms(&terms);
+	return res;
+}
+
+static int cmd_bisect__next(int argc, const char **argv UNUSED, const char *prefix)
+{
+	int res;
+	struct bisect_terms terms = { 0 };
+
+	if (argc)
+		return error(_("--bisect-next requires 0 arguments"));
+	get_terms(&terms);
+	res = bisect_next(&terms, prefix);
+	free_terms(&terms);
+	return res;
+}
+
+static int cmd_bisect__state(int argc, const char **argv, const char *prefix UNUSED)
+{
+	int res;
+	struct bisect_terms terms = { 0 };
+
+	set_terms(&terms, "bad", "good");
+	get_terms(&terms);
+	res = bisect_state(&terms, argv, argc);
+	free_terms(&terms);
+	return res;
+}
+
+static int cmd_bisect__log(int argc, const char **argv UNUSED, const char *prefix UNUSED)
+{
+	if (argc)
+		return error(_("--bisect-log requires 0 arguments"));
+	return bisect_log();
+}
+
+static int cmd_bisect__replay(int argc, const char **argv, const char *prefix UNUSED)
+{
+	int res;
+	struct bisect_terms terms = { 0 };
+
+	if (argc != 1)
+		return error(_("no logfile given"));
+	set_terms(&terms, "bad", "good");
+	res = bisect_replay(&terms, argv[0]);
+	free_terms(&terms);
+	return res;
+}
+
+static int cmd_bisect__skip(int argc, const char **argv, const char *prefix UNUSED)
+{
+	int res;
+	struct bisect_terms terms = { 0 };
+
+	set_terms(&terms, "bad", "good");
+	get_terms(&terms);
+	res = bisect_skip(&terms, argv, argc);
+	free_terms(&terms);
+	return res;
+}
+
+static int cmd_bisect__visualize(int argc, const char **argv, const char *prefix UNUSED)
+{
+	int res;
+	struct bisect_terms terms = { 0 };
+
+	get_terms(&terms);
+	res = bisect_visualize(&terms, argv, argc);
+	free_terms(&terms);
+	return res;
+}
+
+static int cmd_bisect__run(int argc, const char **argv, const char *prefix UNUSED)
+{
+	int res;
+	struct bisect_terms terms = { 0 };
+
+	if (!argc)
+		return error(_("bisect run failed: no command provided."));
+	get_terms(&terms);
+	res = bisect_run(&terms, argv, argc);
+	free_terms(&terms);
+	return res;
+}
+
 int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 {
 	enum {
@@ -1318,8 +1429,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,
 			     PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN_OPT);
@@ -1329,60 +1438,38 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 
 	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);
+		res = cmd_bisect__reset(argc, argv, prefix);
 		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);
+		res = cmd_bisect__terms(argc, argv, prefix);
 		break;
 	case BISECT_START:
-		set_terms(&terms, "bad", "good");
-		res = bisect_start(&terms, argv, argc);
+		res = cmd_bisect__start(argc, argv, prefix);
 		break;
 	case BISECT_NEXT:
-		if (argc)
-			return error(_("--bisect-next requires 0 arguments"));
-		get_terms(&terms);
-		res = bisect_next(&terms, prefix);
+		res = cmd_bisect__next(argc, argv, prefix);
 		break;
 	case BISECT_STATE:
-		set_terms(&terms, "bad", "good");
-		get_terms(&terms);
-		res = bisect_state(&terms, argv, argc);
+		res = cmd_bisect__state(argc, argv, prefix);
 		break;
 	case BISECT_LOG:
-		if (argc)
-			return error(_("--bisect-log requires 0 arguments"));
-		res = bisect_log();
+		res = cmd_bisect__log(argc, argv, prefix);
 		break;
 	case BISECT_REPLAY:
-		if (argc != 1)
-			return error(_("no logfile given"));
-		set_terms(&terms, "bad", "good");
-		res = bisect_replay(&terms, argv[0]);
+		res = cmd_bisect__replay(argc, argv, prefix);
 		break;
 	case BISECT_SKIP:
-		set_terms(&terms, "bad", "good");
-		get_terms(&terms);
-		res = bisect_skip(&terms, argv, argc);
+		res = cmd_bisect__skip(argc, argv, prefix);
 		break;
 	case BISECT_VISUALIZE:
-		get_terms(&terms);
-		res = bisect_visualize(&terms, argv, argc);
+		res = cmd_bisect__visualize(argc, argv, prefix);
 		break;
 	case BISECT_RUN:
-		if (!argc)
-			return error(_("bisect run failed: no command provided."));
-		get_terms(&terms);
-		res = bisect_run(&terms, argv, argc);
+		res = cmd_bisect__run(argc, argv, prefix);
 		break;
 	default:
 		BUG("unknown subcommand %d", cmdmode);
 	}
-	free_terms(&terms);
 
 	/*
 	 * Handle early success
-- 
2.38.1.157.gedabe22e0a


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

* [PATCH v3 3/3] bisect--helper: parse subcommand with OPT_SUBCOMMAND
  2022-11-10 16:36   ` [PATCH v3 " Đoàn Trần Công Danh
  2022-11-10 16:36     ` [PATCH v3 1/3] bisect--helper: remove unused options Đoàn Trần Công Danh
  2022-11-10 16:36     ` [PATCH v3 2/3] bisect--helper: move all subcommands into their own functions Đoàn Trần Công Danh
@ 2022-11-10 16:36     ` Đoàn Trần Công Danh
  2022-11-10 16:36     ` [PATCH v2 00/11] Turn git-bisect to be builtin Đoàn Trần Công Danh
  2022-11-11 12:32     ` [PATCH v3 0/3] Convert git-bisect--helper to OPT_SUBCOMMAND Ævar Arnfjörð Bjarmason
  4 siblings, 0 replies; 106+ messages in thread
From: Đoàn Trần Công Danh @ 2022-11-10 16:36 UTC (permalink / raw)
  To: git
  Cc: Đoàn Trần Công Danh, Lukáš Doktor,
	Jeff King, Christian Couder, Taylor Blau,
	Ævar Arnfjörð Bjarmason

As of it is, we're parsing subcommand with OPT_CMDMODE, which will
continue to parse more options even if the command has been found.

When we're running "git bisect run" with a command that expecting
a "--log" or "--no-log" arguments, or one of those "--bisect-..."
arguments, bisect--helper may mistakenly think those options are
bisect--helper's option.

We may fix those problems by passing "--" when calling from
git-bisect.sh, and skip that "--" in bisect--helper. However, it may
interfere with user's "--".

Let's parse subcommand with OPT_SUBCOMMAND since that API was born for
this specific use-case.

Reported-by: Lukáš Doktor <ldoktor@redhat.com>
Signed-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>
---
 builtin/bisect--helper.c    | 87 ++++++++-----------------------------
 git-bisect.sh               | 23 ++--------
 t/t6030-bisect-porcelain.sh | 10 +++++
 3 files changed, 30 insertions(+), 90 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index d425555d1f..6e41cbdb2d 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1392,84 +1392,31 @@ static int cmd_bisect__run(int argc, const char **argv, const char *prefix UNUSE
 
 int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 {
-	enum {
-		BISECT_RESET = 1,
-		BISECT_TERMS,
-		BISECT_START,
-		BISECT_AUTOSTART,
-		BISECT_NEXT,
-		BISECT_STATE,
-		BISECT_LOG,
-		BISECT_REPLAY,
-		BISECT_SKIP,
-		BISECT_VISUALIZE,
-		BISECT_RUN,
-	} cmdmode = 0;
 	int res = 0;
+	parse_opt_subcommand_fn *fn = NULL;
 	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("view", &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);
+			     git_bisect_helper_usage, 0);
 
-	if (!cmdmode)
+	if (!fn)
 		usage_with_options(git_bisect_helper_usage, options);
+	argc--;
+	argv++;
 
-	switch (cmdmode) {
-	case BISECT_RESET:
-		res = cmd_bisect__reset(argc, argv, prefix);
-		break;
-	case BISECT_TERMS:
-		res = cmd_bisect__terms(argc, argv, prefix);
-		break;
-	case BISECT_START:
-		res = cmd_bisect__start(argc, argv, prefix);
-		break;
-	case BISECT_NEXT:
-		res = cmd_bisect__next(argc, argv, prefix);
-		break;
-	case BISECT_STATE:
-		res = cmd_bisect__state(argc, argv, prefix);
-		break;
-	case BISECT_LOG:
-		res = cmd_bisect__log(argc, argv, prefix);
-		break;
-	case BISECT_REPLAY:
-		res = cmd_bisect__replay(argc, argv, prefix);
-		break;
-	case BISECT_SKIP:
-		res = cmd_bisect__skip(argc, argv, prefix);
-		break;
-	case BISECT_VISUALIZE:
-		res = cmd_bisect__visualize(argc, argv, prefix);
-		break;
-	case BISECT_RUN:
-		res = cmd_bisect__run(argc, argv, prefix);
-		break;
-	default:
-		BUG("unknown subcommand %d", cmdmode);
-	}
+	res = fn(argc, argv, prefix);
 
 	/*
 	 * Handle early success
diff --git a/git-bisect.sh b/git-bisect.sh
index 405cf76f2a..dfce4b4f44 100755
--- a/git-bisect.sh
+++ b/git-bisect.sh
@@ -57,28 +57,11 @@ 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;;
+		git bisect--helper state "$cmd" "$@" ;;
 	log)
-		git bisect--helper --bisect-log || exit ;;
-	run)
-		git bisect--helper --bisect-run "$@" || exit;;
-	terms)
-		git bisect--helper --bisect-terms "$@" || exit;;
+		git bisect--helper log || exit ;;
 	*)
-		usage ;;
+		git bisect--helper "$cmd" "$@" ;;
 	esac
 esac
diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh
index 83931d482f..6dbbe62eb2 100755
--- a/t/t6030-bisect-porcelain.sh
+++ b/t/t6030-bisect-porcelain.sh
@@ -266,6 +266,16 @@ test_expect_success '"git bisect run" simple case' '
 	git bisect reset
 '
 
+# We want to make sure no arguments has been eaten
+test_expect_success '"git bisect run" simple case' '
+	git bisect start &&
+	git bisect good $HASH1 &&
+	git bisect bad $HASH4 &&
+	git bisect run printf "%s %s\n" reset --bisect-skip >my_bisect_log.txt &&
+	grep -e "reset --bisect-skip" my_bisect_log.txt &&
+	git bisect reset
+'
+
 # We want to automatically find the commit that
 # added "Ciao" into hello.
 test_expect_success '"git bisect run" with more complex "git bisect start"' '
-- 
2.38.1.157.gedabe22e0a


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

* [PATCH v2 00/11] Turn git-bisect to be builtin
  2022-11-10 16:36   ` [PATCH v3 " Đoàn Trần Công Danh
                       ` (2 preceding siblings ...)
  2022-11-10 16:36     ` [PATCH v3 3/3] bisect--helper: parse subcommand with OPT_SUBCOMMAND Đoàn Trần Công Danh
@ 2022-11-10 16:36     ` Đoàn Trần Công Danh
  2022-11-10 16:36       ` [PATCH v2 01/11] bisect tests: test for v2.30.0 "bisect run" regressions Đoàn Trần Công Danh
                         ` (11 more replies)
  2022-11-11 12:32     ` [PATCH v3 0/3] Convert git-bisect--helper to OPT_SUBCOMMAND Ævar Arnfjörð Bjarmason
  4 siblings, 12 replies; 106+ messages in thread
From: Đoàn Trần Công Danh @ 2022-11-10 16:36 UTC (permalink / raw)
  To: git
  Cc: Đoàn Trần Công Danh, Taylor Blau, Jeff King,
	Christian Couder, Ævar Arnfjörð Bjarmason

This series finish the git-bisect porting from shell script into a C builtin.

This series can't be applied cleaned on master, it needs to be applied on top
of the series posted at:
https://lore.kernel.org/git/cover.1668097286.git.congdanhqx@gmail.com/
AND the series rs/no-more-run-command-v, which has been integrated to next.

Johannes Schindelin (2):
  bisect--helper: handle states directly
  Turn `git bisect` into a full built-in

Ævar Arnfjörð Bjarmason (4):
  bisect tests: test for v2.30.0 "bisect run" regressions
  bisect: refactor bisect_run() to match CodingGuidelines
  bisect test: test exit codes on bad usage
  bisect--helper: emit usage for "git bisect"

Đoàn Trần Công Danh (5):
  bisect: fix output regressions in v2.30.0
  bisect run: keep some of the post-v2.30.0 output
  bisect-run: verify_good: account for non-negative exit status
  bisect--helper: identify as bisect when report error
  bisect--helper: log: allow arbitrary number of arguments

 Makefile                               |   3 +-
 builtin.h                              |   2 +-
 builtin/{bisect--helper.c => bisect.c} | 126 ++++++++++++---------
 git-bisect.sh                          |   4 -
 git.c                                  |   2 +-
 t/t6030-bisect-porcelain.sh            | 148 +++++++++++++++++++++++++
 6 files changed, 225 insertions(+), 60 deletions(-)
 rename builtin/{bisect--helper.c => bisect.c} (92%)

Range-diff against v1:
 1:  5571bc36b8 !  1:  b6fd4ecd66 bisect tests: test for v2.30.0 "bisect run" regressions
    @@ Commit message
         with 127. That edge case is a bit too insane to preserve, so let's not
         add it to these regression tests.
     
    +    There was another regression that 'git bisect' consumed some options
    +    that was meant to passed down to program run with 'git bisect run'.
    +    Since that regression is breaking user's expectation, it has been fixed
    +    earlier without this patch queued.
    +
         1. 0a4cb1f1f2f (Merge branch 'mr/bisect-in-c-4', 2021-09-23)
         2. d1bbbe45df8 (bisect--helper: reimplement `bisect_run` shell
            function in C, 2021-09-13)
    @@ t/t6030-bisect-porcelain.sh: test_expect_success 'bisect skip: with commit both
     +	test_cmp expect.args actual.args
     +}
     +
    -+test_expect_failure 'git bisect run: args, stdout and stderr with no arguments' '
    -+	test_bisect_run_args <<-\EOF_ARGS 6<<-EOF_OUT 7<<-\EOF_ERR
    ++test_expect_failure 'git bisect run: args, stdout and stderr with no arguments' "
    ++	test_bisect_run_args <<-'EOF_ARGS' 6<<-EOF_OUT 7<<-'EOF_ERR'
     +	EOF_ARGS
     +	running ./run.sh
     +	$HASH4 is the first bad commit
     +	bisect run success
     +	EOF_OUT
     +	EOF_ERR
    -+'
    ++"
     +
    -+test_expect_failure 'git bisect run: args, stdout and stderr: "--" argument' '
    -+	test_bisect_run_args -- <<-\EOF_ARGS 6<<-EOF_OUT 7<<-\EOF_ERR
    ++test_expect_failure 'git bisect run: args, stdout and stderr: "--" argument' "
    ++	test_bisect_run_args -- <<-'EOF_ARGS' 6<<-EOF_OUT 7<<-'EOF_ERR'
     +	<-->
     +	EOF_ARGS
     +	running ./run.sh --
    @@ t/t6030-bisect-porcelain.sh: test_expect_success 'bisect skip: with commit both
     +	bisect run success
     +	EOF_OUT
     +	EOF_ERR
    -+'
    ++"
     +
    -+test_expect_failure 'git bisect run: args, stdout and stderr: "--log foo --no-log bar" arguments' '
    -+	test_bisect_run_args --log foo --no-log bar <<-\EOF_ARGS 6<<-EOF_OUT 7<<-\EOF_ERR
    ++test_expect_failure 'git bisect run: args, stdout and stderr: "--log foo --no-log bar" arguments' "
    ++	test_bisect_run_args --log foo --no-log bar <<-'EOF_ARGS' 6<<-EOF_OUT 7<<-'EOF_ERR'
     +	<--log>
     +	<foo>
     +	<--no-log>
    @@ t/t6030-bisect-porcelain.sh: test_expect_success 'bisect skip: with commit both
     +	bisect run success
     +	EOF_OUT
     +	EOF_ERR
    -+'
    ++"
     +
    -+test_expect_failure 'git bisect run: args, stdout and stderr: "--bisect-start" argument' '
    -+	test_bisect_run_args --bisect-start <<-\EOF_ARGS 6<<-EOF_OUT 7<<-\EOF_ERR
    ++test_expect_failure 'git bisect run: args, stdout and stderr: "--bisect-start" argument' "
    ++	test_bisect_run_args --bisect-start <<-'EOF_ARGS' 6<<-EOF_OUT 7<<-'EOF_ERR'
     +	<--bisect-start>
     +	EOF_ARGS
     +	running ./run.sh --bisect-start
    @@ t/t6030-bisect-porcelain.sh: test_expect_success 'bisect skip: with commit both
     +	bisect run success
     +	EOF_OUT
     +	EOF_ERR
    -+'
    ++"
     +
      # We want to automatically find the commit that
      # added "Another" into hello.
 2:  dc6ed4c453 =  2:  d82c7eaabf bisect: refactor bisect_run() to match CodingGuidelines
 3:  8a815e2311 <  -:  ---------- bisect--helper: pass arg[cv] down to do_bisect_run
 4:  31cd78f538 <  -:  ---------- bisect: fix output regressions in v2.30.0
 5:  5ba3bafdd4 <  -:  ---------- bisect run: keep some of the post-v2.30.0 output
 6:  32ad47ddc5 <  -:  ---------- bisect--helper: remove unused arguments from do_bisect_run
 -:  ---------- >  3:  912f32ceda bisect: fix output regressions in v2.30.0
 -:  ---------- >  4:  17bef3e951 bisect run: keep some of the post-v2.30.0 output
 -:  ---------- >  5:  d6c57af9cc bisect-run: verify_good: account for non-negative exit status
 7:  f212e64288 !  6:  8039b010c8 bisect--helper: pretend we're real bisect when report error
    @@ Metadata
     Author: Đoàn Trần Công Danh <congdanhqx@gmail.com>
     
      ## Commit message ##
    -    bisect--helper: pretend we're real bisect when report error
    +    bisect--helper: identify as bisect when report error
     
         In a later change, we will convert the bisect--helper to be builtin
    -    bisect. Let's start by pretending it's the real bisect when reporting
    +    bisect. Let's start by self-identifying it's the real bisect when reporting
         error.
     
    +    This change is safe since 'git bisect--helper' is an implementation
    +    detail, users aren't expected to call 'git bisect--helper'.
    +
         Signed-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>
     
      ## builtin/bisect--helper.c ##
    @@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, cons
      }
      
     @@ builtin/bisect--helper.c: static int cmd_bisect__terms(int argc, const char **argv, const char *prefix UNU
    - 	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
    + 	struct bisect_terms terms = { 0 };
      
      	if (argc > 1)
     -		return error(_("--bisect-terms requires 0 or 1 argument"));
    @@ builtin/bisect--helper.c: static int cmd_bisect__terms(int argc, const char **ar
      	free_terms(&terms);
      	return res;
     @@ builtin/bisect--helper.c: static int cmd_bisect__next(int argc, const char **argv UNUSED, const char *pref
    - 	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
    + 	struct bisect_terms terms = { 0 };
      
      	if (argc)
     -		return error(_("--bisect-next requires 0 arguments"));
    @@ builtin/bisect--helper.c: static int cmd_bisect__state(int argc, const char **ar
      }
      
     @@ builtin/bisect--helper.c: static int cmd_bisect__run(int argc, const char **argv, const char *prefix UNUSE
    - 	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
    + 	struct bisect_terms terms = { 0 };
      
      	if (!argc)
     -		return error(_("bisect run failed: no command provided."));
 8:  4c1beb8bf8 =  7:  7c43abfcef bisect test: test exit codes on bad usage
 9:  b494a4cf4e =  8:  4500867d56 bisect--helper: emit usage for "git bisect"
10:  a53e0c61ca !  9:  3752c0348b bisect--helper: make `state` optional
    @@ Metadata
     Author: Johannes Schindelin <Johannes.Schindelin@gmx.de>
     
      ## Commit message ##
    -    bisect--helper: make `state` optional
    +    bisect--helper: handle states directly
     
         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.
    +    `git bisect--helper bad`, i.e. eliminate the need of `state` subcommand.
     
         Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
     
      ## builtin/bisect--helper.c ##
    +@@ builtin/bisect--helper.c: static int cmd_bisect__next(int argc, const char **argv UNUSED, const char *pref
    + 	return res;
    + }
    + 
    +-static int cmd_bisect__state(int argc, const char **argv, const char *prefix UNUSED)
    +-{
    +-	int res;
    +-	struct bisect_terms terms = { 0 };
    +-
    +-	set_terms(&terms, "bad", "good");
    +-	get_terms(&terms);
    +-	res = bisect_state(&terms, argv, argc);
    +-	free_terms(&terms);
    +-	return res;
    +-}
    +-
    + static int cmd_bisect__log(int argc, const char **argv UNUSED, const char *prefix UNUSED)
    + {
    + 	if (argc)
    +@@ 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),
     @@ builtin/bisect--helper.c: int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
      		OPT_SUBCOMMAND("run", &fn, cmd_bisect__run),
      		OPT_END()
11:  8037667da0 <  -:  ---------- bisect--helper: remove subcommand state
12:  3b13350977 = 10:  de3075eff9 bisect--helper: log: allow arbitrary number of arguments
13:  0441cf2554 = 11:  dadca7adbe Turn `git bisect` into a full built-in
-- 
2.38.1.157.gedabe22e0a


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

* [PATCH v2 01/11] bisect tests: test for v2.30.0 "bisect run" regressions
  2022-11-10 16:36     ` [PATCH v2 00/11] Turn git-bisect to be builtin Đoàn Trần Công Danh
@ 2022-11-10 16:36       ` Đoàn Trần Công Danh
  2022-11-10 16:36       ` [PATCH v2 02/11] bisect: refactor bisect_run() to match CodingGuidelines Đoàn Trần Công Danh
                         ` (10 subsequent siblings)
  11 siblings, 0 replies; 106+ messages in thread
From: Đoàn Trần Công Danh @ 2022-11-10 16:36 UTC (permalink / raw)
  To: git
  Cc: Ævar Arnfjörð Bjarmason, Taylor Blau, Jeff King,
	Christian Couder, Đoàn Trần Công Danh

From: Ævar Arnfjörð Bjarmason <avarab@gmail.com>

Add three failing tests which succeed on v2.29.0, but due to the topic
merged at [1] (specifically [2]) have been failing since then. We'll
address those regressions in subsequent commits.

There was also a "regression" where:

	git bisect run ./missing-script.sh

Would count a non-existing script as "good", as the shell would exit
with 127. That edge case is a bit too insane to preserve, so let's not
add it to these regression tests.

There was another regression that 'git bisect' consumed some options
that was meant to passed down to program run with 'git bisect run'.
Since that regression is breaking user's expectation, it has been fixed
earlier without this patch queued.

1. 0a4cb1f1f2f (Merge branch 'mr/bisect-in-c-4', 2021-09-23)
2. d1bbbe45df8 (bisect--helper: reimplement `bisect_run` shell
   function in C, 2021-09-13)

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>
---
 t/t6030-bisect-porcelain.sh | 79 +++++++++++++++++++++++++++++++++++++
 1 file changed, 79 insertions(+)

diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh
index 6dbbe62eb2..6c2c57cadf 100755
--- a/t/t6030-bisect-porcelain.sh
+++ b/t/t6030-bisect-porcelain.sh
@@ -252,6 +252,85 @@ test_expect_success 'bisect skip: with commit both bad and skipped' '
 	grep $HASH4 my_bisect_log.txt
 '
 
+test_bisect_run_args () {
+	test_when_finished "rm -f run.sh actual" &&
+	>actual &&
+	cat >expect.args &&
+	cat <&6 >expect.out &&
+	cat <&7 >expect.err &&
+	write_script run.sh <<-\EOF &&
+	while test $# != 0
+	do
+		echo "<$1>" &&
+		shift
+	done >actual.args
+	EOF
+
+	test_when_finished "git bisect reset" &&
+	git bisect start &&
+	git bisect good $HASH1 &&
+	git bisect bad $HASH4 &&
+	git bisect run ./run.sh $@ >actual.out.raw 2>actual.err &&
+	# Prune just the log output
+	sed -n \
+		-e '/^Author:/d' \
+		-e '/^Date:/d' \
+		-e '/^$/d' \
+		-e '/^commit /d' \
+		-e '/^ /d' \
+		-e 'p' \
+		<actual.out.raw >actual.out &&
+	test_cmp expect.out actual.out &&
+	test_cmp expect.err actual.err &&
+	test_cmp expect.args actual.args
+}
+
+test_expect_failure 'git bisect run: args, stdout and stderr with no arguments' "
+	test_bisect_run_args <<-'EOF_ARGS' 6<<-EOF_OUT 7<<-'EOF_ERR'
+	EOF_ARGS
+	running ./run.sh
+	$HASH4 is the first bad commit
+	bisect run success
+	EOF_OUT
+	EOF_ERR
+"
+
+test_expect_failure 'git bisect run: args, stdout and stderr: "--" argument' "
+	test_bisect_run_args -- <<-'EOF_ARGS' 6<<-EOF_OUT 7<<-'EOF_ERR'
+	<-->
+	EOF_ARGS
+	running ./run.sh --
+	$HASH4 is the first bad commit
+	bisect run success
+	EOF_OUT
+	EOF_ERR
+"
+
+test_expect_failure 'git bisect run: args, stdout and stderr: "--log foo --no-log bar" arguments' "
+	test_bisect_run_args --log foo --no-log bar <<-'EOF_ARGS' 6<<-EOF_OUT 7<<-'EOF_ERR'
+	<--log>
+	<foo>
+	<--no-log>
+	<bar>
+	EOF_ARGS
+	running ./run.sh --log foo --no-log bar
+	$HASH4 is the first bad commit
+	bisect run success
+	EOF_OUT
+	EOF_ERR
+"
+
+test_expect_failure 'git bisect run: args, stdout and stderr: "--bisect-start" argument' "
+	test_bisect_run_args --bisect-start <<-'EOF_ARGS' 6<<-EOF_OUT 7<<-'EOF_ERR'
+	<--bisect-start>
+	EOF_ARGS
+	running ./run.sh --bisect-start
+	$HASH4 is the first bad commit
+	bisect run success
+	EOF_OUT
+	EOF_ERR
+"
+
 # We want to automatically find the commit that
 # added "Another" into hello.
 test_expect_success '"git bisect run" simple case' '
-- 
2.38.1.157.gedabe22e0a


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

* [PATCH v2 02/11] bisect: refactor bisect_run() to match CodingGuidelines
  2022-11-10 16:36     ` [PATCH v2 00/11] Turn git-bisect to be builtin Đoàn Trần Công Danh
  2022-11-10 16:36       ` [PATCH v2 01/11] bisect tests: test for v2.30.0 "bisect run" regressions Đoàn Trần Công Danh
@ 2022-11-10 16:36       ` Đoàn Trần Công Danh
  2022-11-10 16:36       ` [PATCH v2 03/11] bisect: fix output regressions in v2.30.0 Đoàn Trần Công Danh
                         ` (9 subsequent siblings)
  11 siblings, 0 replies; 106+ messages in thread
From: Đoàn Trần Công Danh @ 2022-11-10 16:36 UTC (permalink / raw)
  To: git
  Cc: Ævar Arnfjörð Bjarmason, Taylor Blau, Jeff King,
	Christian Couder, Đoàn Trần Công Danh

From: Ævar Arnfjörð Bjarmason <avarab@gmail.com>

We didn't add "{}" to all "if/else" branches, and one "error" was
mis-indented. Let's fix that first, which makes subsequent commits
smaller. In the case of the "if" we can simply early return instead.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>
---
 builtin/bisect--helper.c | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 6e41cbdb2d..08d83e6867 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1191,13 +1191,12 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
 	if (bisect_next_check(terms, NULL))
 		return BISECT_FAILED;
 
-	if (argc)
-		sq_quote_argv(&command, argv);
-	else {
+	if (!argc) {
 		error(_("bisect run failed: no command provided."));
 		return BISECT_FAILED;
 	}
 
+	sq_quote_argv(&command, argv);
 	while (1) {
 		res = do_bisect_run(command.buf);
 
@@ -1268,7 +1267,7 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
 			res = BISECT_OK;
 		} else if (res) {
 			error(_("bisect run failed: 'git bisect--helper --bisect-state"
-			" %s' exited with error code %d"), new_state, res);
+				" %s' exited with error code %d"), new_state, res);
 		} else {
 			continue;
 		}
-- 
2.38.1.157.gedabe22e0a


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

* [PATCH v2 03/11] bisect: fix output regressions in v2.30.0
  2022-11-10 16:36     ` [PATCH v2 00/11] Turn git-bisect to be builtin Đoàn Trần Công Danh
  2022-11-10 16:36       ` [PATCH v2 01/11] bisect tests: test for v2.30.0 "bisect run" regressions Đoàn Trần Công Danh
  2022-11-10 16:36       ` [PATCH v2 02/11] bisect: refactor bisect_run() to match CodingGuidelines Đoàn Trần Công Danh
@ 2022-11-10 16:36       ` Đoàn Trần Công Danh
  2022-11-10 16:36       ` [PATCH v2 04/11] bisect run: keep some of the post-v2.30.0 output Đoàn Trần Công Danh
                         ` (8 subsequent siblings)
  11 siblings, 0 replies; 106+ messages in thread
From: Đoàn Trần Công Danh @ 2022-11-10 16:36 UTC (permalink / raw)
  To: git
  Cc: Đoàn Trần Công Danh, Taylor Blau, Jeff King,
	Christian Couder, Ævar Arnfjörð Bjarmason

When d1bbbe45df8 (bisect--helper: reimplement `bisect_run` shell
function in C, 2021-09-13) reimplemented parts of "git bisect run" in
C it changed the output we emitted so that:

 - The "running ..." line was now quoted
 - We lost the \n after our output
 - We started saying "bisect found ..." instead of "bisect run success"

Arguably some of this is better now, but as d1bbbe45df8 did not
advocate for changing the output, let's revert this for now. It'll be
easy to change it back if that's what we'd prefer.

This does not change the one remaining use of "command.buf" to emit
the quoted argument, as that's new in d1bbbe45df8.

Some of these cases were not tested for in the tests added in the
preceding commit, I didn't have time to fleshen those out, but a look
at f1de981e8b6 will show that the other output being adjusted here is
now equivalent to what it was before d1bbbe45df8.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>
---
 builtin/bisect--helper.c    | 27 +++++++++++++++------------
 t/t6030-bisect-porcelain.sh |  8 ++++----
 2 files changed, 19 insertions(+), 16 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 08d83e6867..05cab468e3 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1141,17 +1141,17 @@ static int get_first_good(const char *refname UNUSED,
 	return 1;
 }
 
-static int do_bisect_run(const char *command)
+static int do_bisect_run(const char *command, const char *unquoted_cmd)
 {
 	struct child_process cmd = CHILD_PROCESS_INIT;
 
-	printf(_("running %s\n"), command);
+	printf(_("running %s\n"), unquoted_cmd);
 	cmd.use_shell = 1;
 	strvec_push(&cmd.args, command);
 	return run_command(&cmd);
 }
 
-static int verify_good(const struct bisect_terms *terms, const char *command)
+static int verify_good(const struct bisect_terms *terms, const char *command, const char *unquoted_cmd)
 {
 	int rc;
 	enum bisect_error res;
@@ -1171,7 +1171,7 @@ static int verify_good(const struct bisect_terms *terms, const char *command)
 	if (res != BISECT_OK)
 		return -1;
 
-	rc = do_bisect_run(command);
+	rc = do_bisect_run(command, unquoted_cmd);
 
 	res = bisect_checkout(&current_rev, no_checkout);
 	if (res != BISECT_OK)
@@ -1184,6 +1184,7 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
 {
 	int res = BISECT_OK;
 	struct strbuf command = STRBUF_INIT;
+	struct strbuf unquoted = STRBUF_INIT;
 	const char *new_state;
 	int temporary_stdout_fd, saved_stdout;
 	int is_first_run = 1;
@@ -1197,8 +1198,9 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
 	}
 
 	sq_quote_argv(&command, argv);
+	strbuf_join_argv(&unquoted, argc, argv,' ');
 	while (1) {
-		res = do_bisect_run(command.buf);
+		res = do_bisect_run(command.buf, unquoted.buf);
 
 		/*
 		 * Exit code 126 and 127 can either come from the shell
@@ -1208,11 +1210,11 @@ 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, command.buf);
+			int rc = verify_good(terms, command.buf, unquoted.buf);
 			is_first_run = 0;
 			if (rc < 0) {
 				error(_("unable to verify '%s' on good"
-					" revision"), command.buf);
+					" revision"), unquoted.buf);
 				res = BISECT_FAILED;
 				break;
 			}
@@ -1226,7 +1228,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, unquoted.buf);
 			break;
 		}
 
@@ -1260,20 +1262,21 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
 		if (res == BISECT_ONLY_SKIPPED_LEFT)
 			error(_("bisect run cannot continue any more"));
 		else if (res == BISECT_INTERNAL_SUCCESS_MERGE_BASE) {
-			printf(_("bisect run success"));
+			puts(_("bisect run success"));
 			res = BISECT_OK;
 		} else if (res == BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND) {
-			printf(_("bisect found first bad commit"));
+			puts(_("bisect run success"));
 			res = BISECT_OK;
 		} else if (res) {
-			error(_("bisect run failed: 'git bisect--helper --bisect-state"
-				" %s' exited with error code %d"), new_state, res);
+			error(_("bisect run failed: 'bisect-state %s'"
+				" exited with error code %d"), new_state, res);
 		} else {
 			continue;
 		}
 		break;
 	}
 
+	strbuf_release(&unquoted);
 	strbuf_release(&command);
 	return res;
 }
diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh
index 6c2c57cadf..a3dc5c8140 100755
--- a/t/t6030-bisect-porcelain.sh
+++ b/t/t6030-bisect-porcelain.sh
@@ -285,7 +285,7 @@ test_bisect_run_args () {
 	test_cmp expect.args actual.args
 }
 
-test_expect_failure 'git bisect run: args, stdout and stderr with no arguments' "
+test_expect_success 'git bisect run: args, stdout and stderr with no arguments' "
 	test_bisect_run_args <<-'EOF_ARGS' 6<<-EOF_OUT 7<<-'EOF_ERR'
 	EOF_ARGS
 	running ./run.sh
@@ -295,7 +295,7 @@ test_expect_failure 'git bisect run: args, stdout and stderr with no arguments'
 	EOF_ERR
 "
 
-test_expect_failure 'git bisect run: args, stdout and stderr: "--" argument' "
+test_expect_success 'git bisect run: args, stdout and stderr: "--" argument' "
 	test_bisect_run_args -- <<-'EOF_ARGS' 6<<-EOF_OUT 7<<-'EOF_ERR'
 	<-->
 	EOF_ARGS
@@ -306,7 +306,7 @@ test_expect_failure 'git bisect run: args, stdout and stderr: "--" argument' "
 	EOF_ERR
 "
 
-test_expect_failure 'git bisect run: args, stdout and stderr: "--log foo --no-log bar" arguments' "
+test_expect_success 'git bisect run: args, stdout and stderr: "--log foo --no-log bar" arguments' "
 	test_bisect_run_args --log foo --no-log bar <<-'EOF_ARGS' 6<<-EOF_OUT 7<<-'EOF_ERR'
 	<--log>
 	<foo>
@@ -320,7 +320,7 @@ test_expect_failure 'git bisect run: args, stdout and stderr: "--log foo --no-lo
 	EOF_ERR
 "
 
-test_expect_failure 'git bisect run: args, stdout and stderr: "--bisect-start" argument' "
+test_expect_success 'git bisect run: args, stdout and stderr: "--bisect-start" argument' "
 	test_bisect_run_args --bisect-start <<-'EOF_ARGS' 6<<-EOF_OUT 7<<-'EOF_ERR'
 	<--bisect-start>
 	EOF_ARGS
-- 
2.38.1.157.gedabe22e0a


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

* [PATCH v2 04/11] bisect run: keep some of the post-v2.30.0 output
  2022-11-10 16:36     ` [PATCH v2 00/11] Turn git-bisect to be builtin Đoàn Trần Công Danh
                         ` (2 preceding siblings ...)
  2022-11-10 16:36       ` [PATCH v2 03/11] bisect: fix output regressions in v2.30.0 Đoàn Trần Công Danh
@ 2022-11-10 16:36       ` Đoàn Trần Công Danh
  2022-11-10 16:36       ` [PATCH v2 05/11] bisect-run: verify_good: account for non-negative exit status Đoàn Trần Công Danh
                         ` (7 subsequent siblings)
  11 siblings, 0 replies; 106+ messages in thread
From: Đoàn Trần Công Danh @ 2022-11-10 16:36 UTC (permalink / raw)
  To: git
  Cc: Đoàn Trần Công Danh, Taylor Blau, Jeff King,
	Christian Couder, Ævar Arnfjörð Bjarmason

Preceding commits fixed output and behavior regressions in
d1bbbe45df8 (bisect--helper: reimplement `bisect_run` shell function
in C, 2021-09-13), which did not claim to be changing the output of
"git bisect run".

But some of the output it emitted was subjectively better, so once
we've asserted that we're back on v2.29.0 behavior, let's change some
of it back:

- We now quote the arguments again, but omit the first " " when
  printing the "running" line.
- Ditto for other cases where we emitted the argument
- We say "found first bad commit" again, not just "run success"

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Based-on-patch-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>
---
 builtin/bisect--helper.c    | 24 ++++++++--------
 t/t6030-bisect-porcelain.sh | 55 +++++++++++++++++++++++++++++++------
 2 files changed, 58 insertions(+), 21 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 05cab468e3..180c2faa7f 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1141,17 +1141,17 @@ static int get_first_good(const char *refname UNUSED,
 	return 1;
 }
 
-static int do_bisect_run(const char *command, const char *unquoted_cmd)
+static int do_bisect_run(const char *command)
 {
 	struct child_process cmd = CHILD_PROCESS_INIT;
 
-	printf(_("running %s\n"), unquoted_cmd);
+	printf(_("running %s\n"), command);
 	cmd.use_shell = 1;
 	strvec_push(&cmd.args, command);
 	return run_command(&cmd);
 }
 
-static int verify_good(const struct bisect_terms *terms, const char *command, const char *unquoted_cmd)
+static int verify_good(const struct bisect_terms *terms, const char *command)
 {
 	int rc;
 	enum bisect_error res;
@@ -1171,7 +1171,7 @@ static int verify_good(const struct bisect_terms *terms, const char *command, co
 	if (res != BISECT_OK)
 		return -1;
 
-	rc = do_bisect_run(command, unquoted_cmd);
+	rc = do_bisect_run(command);
 
 	res = bisect_checkout(&current_rev, no_checkout);
 	if (res != BISECT_OK)
@@ -1184,7 +1184,6 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
 {
 	int res = BISECT_OK;
 	struct strbuf command = STRBUF_INIT;
-	struct strbuf unquoted = STRBUF_INIT;
 	const char *new_state;
 	int temporary_stdout_fd, saved_stdout;
 	int is_first_run = 1;
@@ -1198,9 +1197,9 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
 	}
 
 	sq_quote_argv(&command, argv);
-	strbuf_join_argv(&unquoted, argc, argv,' ');
+	strbuf_ltrim(&command);
 	while (1) {
-		res = do_bisect_run(command.buf, unquoted.buf);
+		res = do_bisect_run(command.buf);
 
 		/*
 		 * Exit code 126 and 127 can either come from the shell
@@ -1210,11 +1209,11 @@ 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, command.buf, unquoted.buf);
+			int rc = verify_good(terms, command.buf);
 			is_first_run = 0;
 			if (rc < 0) {
-				error(_("unable to verify '%s' on good"
-					" revision"), unquoted.buf);
+				error(_("unable to verify %s on good"
+					" revision"), command.buf);
 				res = BISECT_FAILED;
 				break;
 			}
@@ -1228,7 +1227,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, unquoted.buf);
+				" %s is < 0 or >= 128"), res, command.buf);
 			break;
 		}
 
@@ -1265,7 +1264,7 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
 			puts(_("bisect run success"));
 			res = BISECT_OK;
 		} else if (res == BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND) {
-			puts(_("bisect run success"));
+			puts(_("bisect found first bad commit"));
 			res = BISECT_OK;
 		} else if (res) {
 			error(_("bisect run failed: 'bisect-state %s'"
@@ -1276,7 +1275,6 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
 		break;
 	}
 
-	strbuf_release(&unquoted);
 	strbuf_release(&command);
 	return res;
 }
diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh
index a3dc5c8140..34fd45a48e 100755
--- a/t/t6030-bisect-porcelain.sh
+++ b/t/t6030-bisect-porcelain.sh
@@ -288,9 +288,9 @@ test_bisect_run_args () {
 test_expect_success 'git bisect run: args, stdout and stderr with no arguments' "
 	test_bisect_run_args <<-'EOF_ARGS' 6<<-EOF_OUT 7<<-'EOF_ERR'
 	EOF_ARGS
-	running ./run.sh
+	running './run.sh'
 	$HASH4 is the first bad commit
-	bisect run success
+	bisect found first bad commit
 	EOF_OUT
 	EOF_ERR
 "
@@ -299,9 +299,9 @@ test_expect_success 'git bisect run: args, stdout and stderr: "--" argument' "
 	test_bisect_run_args -- <<-'EOF_ARGS' 6<<-EOF_OUT 7<<-'EOF_ERR'
 	<-->
 	EOF_ARGS
-	running ./run.sh --
+	running './run.sh' '--'
 	$HASH4 is the first bad commit
-	bisect run success
+	bisect found first bad commit
 	EOF_OUT
 	EOF_ERR
 "
@@ -313,9 +313,9 @@ test_expect_success 'git bisect run: args, stdout and stderr: "--log foo --no-lo
 	<--no-log>
 	<bar>
 	EOF_ARGS
-	running ./run.sh --log foo --no-log bar
+	running './run.sh' '--log' 'foo' '--no-log' 'bar'
 	$HASH4 is the first bad commit
-	bisect run success
+	bisect found first bad commit
 	EOF_OUT
 	EOF_ERR
 "
@@ -324,13 +324,52 @@ test_expect_success 'git bisect run: args, stdout and stderr: "--bisect-start" a
 	test_bisect_run_args --bisect-start <<-'EOF_ARGS' 6<<-EOF_OUT 7<<-'EOF_ERR'
 	<--bisect-start>
 	EOF_ARGS
-	running ./run.sh --bisect-start
+	running './run.sh' '--bisect-start'
 	$HASH4 is the first bad commit
-	bisect run success
+	bisect found first bad commit
 	EOF_OUT
 	EOF_ERR
 "
 
+test_expect_success 'git bisect run: negative exit code' "
+	write_script fail.sh <<-'EOF' &&
+	exit 255
+	EOF
+	cat <<-'EOF' >expect &&
+	bisect run failed: exit code -1 from './fail.sh' is < 0 or >= 128
+	EOF
+	test_when_finished 'git bisect reset' &&
+	git bisect start &&
+	git bisect good $HASH1 &&
+	git bisect bad $HASH4 &&
+	! git bisect run ./fail.sh 2>err &&
+	sed -En 's/.*(bisect.*code) (-?[0-9]+) (from.*)/\1 -1 \3/p' err >actual &&
+	test_cmp expect actual
+"
+
+test_expect_failure 'git bisect run: unable to verify on good' "
+	write_script fail.sh <<-'EOF' &&
+	head=\$(git rev-parse --verify HEAD)
+	good=\$(git rev-parse --verify $HASH1)
+	if test "\$head" = "\$good"
+	then
+		exit 255
+	else
+		exit 127
+	fi
+	EOF
+	cat <<-'EOF' >expect &&
+	unable to verify './fail.sh' on good revision
+	EOF
+	test_when_finished 'git bisect reset' &&
+	git bisect start &&
+	git bisect good $HASH1 &&
+	git bisect bad $HASH4 &&
+	! git bisect run ./fail.sh 2>err &&
+	sed -n 's/.*\(unable to verify.*\)/\1/p' err >actual &&
+	test_cmp expect actual
+"
+
 # We want to automatically find the commit that
 # added "Another" into hello.
 test_expect_success '"git bisect run" simple case' '
-- 
2.38.1.157.gedabe22e0a


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

* [PATCH v2 05/11] bisect-run: verify_good: account for non-negative exit status
  2022-11-10 16:36     ` [PATCH v2 00/11] Turn git-bisect to be builtin Đoàn Trần Công Danh
                         ` (3 preceding siblings ...)
  2022-11-10 16:36       ` [PATCH v2 04/11] bisect run: keep some of the post-v2.30.0 output Đoàn Trần Công Danh
@ 2022-11-10 16:36       ` Đoàn Trần Công Danh
  2022-11-10 16:36       ` [PATCH v2 06/11] bisect--helper: identify as bisect when report error Đoàn Trần Công Danh
                         ` (6 subsequent siblings)
  11 siblings, 0 replies; 106+ messages in thread
From: Đoàn Trần Công Danh @ 2022-11-10 16:36 UTC (permalink / raw)
  To: git
  Cc: Đoàn Trần Công Danh, Taylor Blau, Jeff King,
	Christian Couder, Ævar Arnfjörð Bjarmason

Some system never reports negative exit code at all, they reports them
as bigger-than-128 instead.  We take extra care for those systems in the
later check for normal 'do_bisect_run' loop.

Let's check it here, too.

Signed-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>
---
 builtin/bisect--helper.c    | 2 +-
 t/t6030-bisect-porcelain.sh | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 180c2faa7f..e214190599 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1211,7 +1211,7 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
 		if (is_first_run && (res == 126 || res == 127)) {
 			int rc = verify_good(terms, command.buf);
 			is_first_run = 0;
-			if (rc < 0) {
+			if (rc < 0 || 128 <= rc) {
 				error(_("unable to verify %s on good"
 					" revision"), command.buf);
 				res = BISECT_FAILED;
diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh
index 34fd45a48e..03d99b22f1 100755
--- a/t/t6030-bisect-porcelain.sh
+++ b/t/t6030-bisect-porcelain.sh
@@ -347,7 +347,7 @@ test_expect_success 'git bisect run: negative exit code' "
 	test_cmp expect actual
 "
 
-test_expect_failure 'git bisect run: unable to verify on good' "
+test_expect_success 'git bisect run: unable to verify on good' "
 	write_script fail.sh <<-'EOF' &&
 	head=\$(git rev-parse --verify HEAD)
 	good=\$(git rev-parse --verify $HASH1)
-- 
2.38.1.157.gedabe22e0a


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

* [PATCH v2 06/11] bisect--helper: identify as bisect when report error
  2022-11-10 16:36     ` [PATCH v2 00/11] Turn git-bisect to be builtin Đoàn Trần Công Danh
                         ` (4 preceding siblings ...)
  2022-11-10 16:36       ` [PATCH v2 05/11] bisect-run: verify_good: account for non-negative exit status Đoàn Trần Công Danh
@ 2022-11-10 16:36       ` Đoàn Trần Công Danh
  2022-11-10 16:36       ` [PATCH v2 07/11] bisect test: test exit codes on bad usage Đoàn Trần Công Danh
                         ` (5 subsequent siblings)
  11 siblings, 0 replies; 106+ messages in thread
From: Đoàn Trần Công Danh @ 2022-11-10 16:36 UTC (permalink / raw)
  To: git
  Cc: Đoàn Trần Công Danh, Taylor Blau, Jeff King,
	Christian Couder, Ævar Arnfjörð Bjarmason

In a later change, we will convert the bisect--helper to be builtin
bisect. Let's start by self-identifying it's the real bisect when reporting
error.

This change is safe since 'git bisect--helper' is an implementation
detail, users aren't expected to call 'git bisect--helper'.

Signed-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>
---
 builtin/bisect--helper.c | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index e214190599..f28bedac6a 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1282,7 +1282,8 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
 static int cmd_bisect__reset(int argc, const char **argv, const char *prefix UNUSED)
 {
 	if (argc > 1)
-		return error(_("--bisect-reset requires either no argument or a commit"));
+		return error(_("'%s' requires either no argument or a commit"),
+			     "git bisect reset");
 	return bisect_reset(argc ? argv[0] : NULL);
 }
 
@@ -1292,7 +1293,8 @@ static int cmd_bisect__terms(int argc, const char **argv, const char *prefix UNU
 	struct bisect_terms terms = { 0 };
 
 	if (argc > 1)
-		return error(_("--bisect-terms requires 0 or 1 argument"));
+		return error(_("'%s' requires 0 or 1 argument"),
+			     "git bisect terms");
 	res = bisect_terms(&terms, argc == 1 ? argv[0] : NULL);
 	free_terms(&terms);
 	return res;
@@ -1315,7 +1317,8 @@ static int cmd_bisect__next(int argc, const char **argv UNUSED, const char *pref
 	struct bisect_terms terms = { 0 };
 
 	if (argc)
-		return error(_("--bisect-next requires 0 arguments"));
+		return error(_("'%s' requires 0 arguments"),
+			     "git bisect next");
 	get_terms(&terms);
 	res = bisect_next(&terms, prefix);
 	free_terms(&terms);
@@ -1337,7 +1340,7 @@ static int cmd_bisect__state(int argc, const char **argv, const char *prefix UNU
 static int cmd_bisect__log(int argc, const char **argv UNUSED, const char *prefix UNUSED)
 {
 	if (argc)
-		return error(_("--bisect-log requires 0 arguments"));
+		return error(_("'%s' requires 0 arguments"), "git bisect log");
 	return bisect_log();
 }
 
@@ -1383,7 +1386,7 @@ static int cmd_bisect__run(int argc, const char **argv, const char *prefix UNUSE
 	struct bisect_terms terms = { 0 };
 
 	if (!argc)
-		return error(_("bisect run failed: no command provided."));
+		return error(_("'%s' failed: no command provided."), "git bisect run");
 	get_terms(&terms);
 	res = bisect_run(&terms, argv, argc);
 	free_terms(&terms);
-- 
2.38.1.157.gedabe22e0a


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

* [PATCH v2 07/11] bisect test: test exit codes on bad usage
  2022-11-10 16:36     ` [PATCH v2 00/11] Turn git-bisect to be builtin Đoàn Trần Công Danh
                         ` (5 preceding siblings ...)
  2022-11-10 16:36       ` [PATCH v2 06/11] bisect--helper: identify as bisect when report error Đoàn Trần Công Danh
@ 2022-11-10 16:36       ` Đoàn Trần Công Danh
  2022-11-10 16:36       ` [PATCH v2 08/11] bisect--helper: emit usage for "git bisect" Đoàn Trần Công Danh
                         ` (4 subsequent siblings)
  11 siblings, 0 replies; 106+ messages in thread
From: Đoàn Trần Công Danh @ 2022-11-10 16:36 UTC (permalink / raw)
  To: git
  Cc: Ævar Arnfjörð Bjarmason, Taylor Blau, Jeff King,
	Christian Couder, Đoàn Trần Công Danh

From: Ævar Arnfjörð Bjarmason <avarab@gmail.com>

Address a test blindspot, the "log" command is the odd one out because
"git-bisect.sh" ignores any arguments it receives. Let's test both the
exit codes we expect, and the stderr and stdout we're emitting.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>
---
 t/t6030-bisect-porcelain.sh | 30 ++++++++++++++++++++++++++++++
 1 file changed, 30 insertions(+)

diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh
index 03d99b22f1..98a72ff78a 100755
--- a/t/t6030-bisect-porcelain.sh
+++ b/t/t6030-bisect-porcelain.sh
@@ -34,6 +34,36 @@ HASH2=
 HASH3=
 HASH4=
 
+test_bisect_usage () {
+	local code="$1" &&
+	shift &&
+	cat >expect &&
+	test_expect_code $code "$@" >out 2>actual &&
+	test_must_be_empty out &&
+	test_cmp expect actual
+}
+
+test_expect_success 'bisect usage' "
+	test_bisect_usage 1 git bisect reset extra1 extra2 <<-\EOF &&
+	error: 'git bisect reset' requires either no argument or a commit
+	EOF
+	test_bisect_usage 1 git bisect terms extra1 extra2 <<-\EOF &&
+	error: 'git bisect terms' requires 0 or 1 argument
+	EOF
+	test_bisect_usage 1 git bisect next extra1 <<-\EOF &&
+	error: 'git bisect next' requires 0 arguments
+	EOF
+	test_bisect_usage 1 git bisect log extra1 <<-\EOF &&
+	error: We are not bisecting.
+	EOF
+	test_bisect_usage 1 git bisect replay <<-\EOF &&
+	error: no logfile given
+	EOF
+	test_bisect_usage 1 git bisect run <<-\EOF
+	error: 'git bisect run' failed: no command provided.
+	EOF
+"
+
 test_expect_success 'set up basic repo with 1 file (hello) and 4 commits' '
      add_line_into_file "1: Hello World" hello &&
      HASH1=$(git rev-parse --verify HEAD) &&
-- 
2.38.1.157.gedabe22e0a


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

* [PATCH v2 08/11] bisect--helper: emit usage for "git bisect"
  2022-11-10 16:36     ` [PATCH v2 00/11] Turn git-bisect to be builtin Đoàn Trần Công Danh
                         ` (6 preceding siblings ...)
  2022-11-10 16:36       ` [PATCH v2 07/11] bisect test: test exit codes on bad usage Đoàn Trần Công Danh
@ 2022-11-10 16:36       ` Đoàn Trần Công Danh
  2022-11-10 16:36       ` [PATCH v2 09/11] bisect--helper: handle states directly Đoàn Trần Công Danh
                         ` (3 subsequent siblings)
  11 siblings, 0 replies; 106+ messages in thread
From: Đoàn Trần Công Danh @ 2022-11-10 16:36 UTC (permalink / raw)
  To: git
  Cc: Ævar Arnfjörð Bjarmason, Taylor Blau, Jeff King,
	Christian Couder, Đoàn Trần Công Danh

From: Ævar Arnfjörð Bjarmason <avarab@gmail.com>

In subsequent commits we'll be removing "git-bisect.sh" in favor of
promoting "bisect--helper" to a "bisect" built-in.

In doing that we'll first need to have it support "git bisect--helper
<cmd>" rather than "git bisect--helper --<cmd>", and then finally have
its "-h" output claim to be "bisect" rather than "bisect--helper".

Instead of suffering that churn let's start claiming to be "git
bisect" now. In just a few commits this will be true, and in the
meantime emitting the "wrong" usage information from the helper is a
small price to pay to avoid the churn.

Let's also declare "BUILTIN_*" macros, when we eventually migrate the
sub-commands themselves to parse_options() we'll be able to re-use the
strings. See 0afd556b2e1 (worktree: define subcommand -h in terms of
command -h, 2022-10-13) for a recent example.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>
---
 builtin/bisect--helper.c | 51 ++++++++++++++++++++++++++++------------
 1 file changed, 36 insertions(+), 15 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index f28bedac6a..1ff2d4ea3f 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -20,18 +20,40 @@ 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>..."),
+#define BUILTIN_GIT_BISECT_START_USAGE \
+	N_("git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>]" \
+	   "    [--no-checkout] [--first-parent] [<bad> [<good>...]] [--]" \
+	   "    [<pathspec>...]")
+#define BUILTIN_GIT_BISECT_STATE_USAGE \
+	N_("git bisect (good|bad) [<rev>...]")
+#define BUILTIN_GIT_BISECT_TERMS_USAGE \
+	"git bisect terms [--term-good | --term-bad]"
+#define BUILTIN_GIT_BISECT_SKIP_USAGE \
+	N_("git bisect skip [(<rev>|<range>)...]")
+#define BUILTIN_GIT_BISECT_NEXT_USAGE \
+	"git bisect next"
+#define BUILTIN_GIT_BISECT_RESET_USAGE \
+	N_("git bisect reset [<commit>]")
+#define BUILTIN_GIT_BISECT_VISUALIZE_USAGE \
+	"git bisect visualize"
+#define BUILTIN_GIT_BISECT_REPLAY_USAGE \
+	N_("git bisect replay <logfile>")
+#define BUILTIN_GIT_BISECT_LOG_USAGE \
+	"git bisect log"
+#define BUILTIN_GIT_BISECT_RUN_USAGE \
+	N_("git bisect run <cmd>...")
+
+static const char * const git_bisect_usage[] = {
+	BUILTIN_GIT_BISECT_START_USAGE,
+	BUILTIN_GIT_BISECT_STATE_USAGE,
+	BUILTIN_GIT_BISECT_TERMS_USAGE,
+	BUILTIN_GIT_BISECT_SKIP_USAGE,
+	BUILTIN_GIT_BISECT_NEXT_USAGE,
+	BUILTIN_GIT_BISECT_RESET_USAGE,
+	BUILTIN_GIT_BISECT_VISUALIZE_USAGE,
+	BUILTIN_GIT_BISECT_REPLAY_USAGE,
+	BUILTIN_GIT_BISECT_LOG_USAGE,
+	BUILTIN_GIT_BISECT_RUN_USAGE,
 	NULL
 };
 
@@ -1411,11 +1433,10 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 		OPT_SUBCOMMAND("run", &fn, cmd_bisect__run),
 		OPT_END()
 	};
-	argc = parse_options(argc, argv, prefix, options,
-			     git_bisect_helper_usage, 0);
+	argc = parse_options(argc, argv, prefix, options, git_bisect_usage, 0);
 
 	if (!fn)
-		usage_with_options(git_bisect_helper_usage, options);
+		usage_with_options(git_bisect_usage, options);
 	argc--;
 	argv++;
 
-- 
2.38.1.157.gedabe22e0a


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

* [PATCH v2 09/11] bisect--helper: handle states directly
  2022-11-10 16:36     ` [PATCH v2 00/11] Turn git-bisect to be builtin Đoàn Trần Công Danh
                         ` (7 preceding siblings ...)
  2022-11-10 16:36       ` [PATCH v2 08/11] bisect--helper: emit usage for "git bisect" Đoàn Trần Công Danh
@ 2022-11-10 16:36       ` Đoàn Trần Công Danh
  2022-11-10 16:36       ` [PATCH v2 10/11] bisect--helper: log: allow arbitrary number of arguments Đoàn Trần Công Danh
                         ` (2 subsequent siblings)
  11 siblings, 0 replies; 106+ messages in thread
From: Đoàn Trần Công Danh @ 2022-11-10 16:36 UTC (permalink / raw)
  To: git
  Cc: Johannes Schindelin, Taylor Blau, Jeff King, Christian Couder,
	Ævar Arnfjörð Bjarmason,
	Đoàn Trần Công Danh

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. eliminate the need of `state` subcommand.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>
---
 builtin/bisect--helper.c | 42 ++++++++++++++++++++--------------------
 git-bisect.sh            |  2 --
 2 files changed, 21 insertions(+), 23 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 1ff2d4ea3f..29d5a26c64 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1347,18 +1347,6 @@ static int cmd_bisect__next(int argc, const char **argv UNUSED, const char *pref
 	return res;
 }
 
-static int cmd_bisect__state(int argc, const char **argv, const char *prefix UNUSED)
-{
-	int res;
-	struct bisect_terms terms = { 0 };
-
-	set_terms(&terms, "bad", "good");
-	get_terms(&terms);
-	res = bisect_state(&terms, argv, argc);
-	free_terms(&terms);
-	return res;
-}
-
 static int cmd_bisect__log(int argc, const char **argv UNUSED, const char *prefix UNUSED)
 {
 	if (argc)
@@ -1424,7 +1412,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),
@@ -1433,14 +1420,27 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 		OPT_SUBCOMMAND("run", &fn, cmd_bisect__run),
 		OPT_END()
 	};
-	argc = parse_options(argc, argv, prefix, options, git_bisect_usage, 0);
-
-	if (!fn)
-		usage_with_options(git_bisect_usage, options);
-	argc--;
-	argv++;
-
-	res = fn(argc, argv, prefix);
+	argc = parse_options(argc, argv, prefix, options, git_bisect_usage,
+			     PARSE_OPT_SUBCOMMAND_OPTIONAL);
+
+	if (!fn) {
+		struct bisect_terms terms = { 0 };
+
+		if (!argc)
+			usage_msg_opt(_("need a command"), git_bisect_usage, options);
+
+		set_terms(&terms, "bad", "good");
+		get_terms(&terms);
+		if (check_and_set_terms(&terms, argv[0]))
+			usage_msg_optf(_("unknown command: '%s'"), git_bisect_usage,
+				       options, argv[0]);
+		res = bisect_state(&terms, argv, argc);
+		free_terms(&terms);
+	} else {
+		argc--;
+		argv++;
+		res = fn(argc, argv, prefix);
+	}
 
 	/*
 	 * Handle early success
diff --git a/git-bisect.sh b/git-bisect.sh
index dfce4b4f44..9f6c8cc093 100755
--- a/git-bisect.sh
+++ b/git-bisect.sh
@@ -57,8 +57,6 @@ case "$#" in
 	case "$cmd" in
 	help)
 		git bisect -h ;;
-	bad|good|new|old|"$TERM_BAD"|"$TERM_GOOD")
-		git bisect--helper state "$cmd" "$@" ;;
 	log)
 		git bisect--helper log || exit ;;
 	*)
-- 
2.38.1.157.gedabe22e0a


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

* [PATCH v2 10/11] bisect--helper: log: allow arbitrary number of arguments
  2022-11-10 16:36     ` [PATCH v2 00/11] Turn git-bisect to be builtin Đoàn Trần Công Danh
                         ` (8 preceding siblings ...)
  2022-11-10 16:36       ` [PATCH v2 09/11] bisect--helper: handle states directly Đoàn Trần Công Danh
@ 2022-11-10 16:36       ` Đoàn Trần Công Danh
  2022-11-11 14:01         ` Ævar Arnfjörð Bjarmason
  2022-11-10 16:36       ` [PATCH v2 11/11] Turn `git bisect` into a full built-in Đoàn Trần Công Danh
  2022-11-11 22:07       ` [PATCH v2 00/11] Turn git-bisect to be builtin Taylor Blau
  11 siblings, 1 reply; 106+ messages in thread
From: Đoàn Trần Công Danh @ 2022-11-10 16:36 UTC (permalink / raw)
  To: git
  Cc: Đoàn Trần Công Danh, Taylor Blau, Jeff King,
	Christian Couder, Ævar Arnfjörð Bjarmason

In a later change, we would like to turn bisect into a builtin by
renaming bisect--helper.

However, there's an oddity that "git bisect log" accepts any number of
arguments and it will just ignore them all.

Let's prepare for the next step by ignoring any arguments passed to
"git bisect--helper log"

Signed-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>
---
 builtin/bisect--helper.c | 4 +---
 git-bisect.sh            | 2 --
 2 files changed, 1 insertion(+), 5 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 29d5a26c64..6066f553fd 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1347,10 +1347,8 @@ static int cmd_bisect__next(int argc, const char **argv UNUSED, const char *pref
 	return res;
 }
 
-static int cmd_bisect__log(int argc, const char **argv UNUSED, const char *prefix UNUSED)
+static int cmd_bisect__log(int argc UNUSED, const char **argv UNUSED, const char *prefix UNUSED)
 {
-	if (argc)
-		return error(_("'%s' requires 0 arguments"), "git bisect log");
 	return bisect_log();
 }
 
diff --git a/git-bisect.sh b/git-bisect.sh
index 9f6c8cc093..f95b8103a9 100755
--- a/git-bisect.sh
+++ b/git-bisect.sh
@@ -57,8 +57,6 @@ case "$#" in
 	case "$cmd" in
 	help)
 		git bisect -h ;;
-	log)
-		git bisect--helper log || exit ;;
 	*)
 		git bisect--helper "$cmd" "$@" ;;
 	esac
-- 
2.38.1.157.gedabe22e0a


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

* [PATCH v2 11/11] Turn `git bisect` into a full built-in
  2022-11-10 16:36     ` [PATCH v2 00/11] Turn git-bisect to be builtin Đoàn Trần Công Danh
                         ` (9 preceding siblings ...)
  2022-11-10 16:36       ` [PATCH v2 10/11] bisect--helper: log: allow arbitrary number of arguments Đoàn Trần Công Danh
@ 2022-11-10 16:36       ` Đoàn Trần Công Danh
  2022-11-11 13:53         ` Ævar Arnfjörð Bjarmason
  2022-11-11 22:07       ` [PATCH v2 00/11] Turn git-bisect to be builtin Taylor Blau
  11 siblings, 1 reply; 106+ messages in thread
From: Đoàn Trần Công Danh @ 2022-11-10 16:36 UTC (permalink / raw)
  To: git
  Cc: Johannes Schindelin, Taylor Blau, Jeff King, Christian Couder,
	Ævar Arnfjörð Bjarmason, Junio C Hamano,
	Đoàn Trần Công Danh

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>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>
---
 Makefile                               | 3 +--
 builtin.h                              | 2 +-
 builtin/{bisect--helper.c => bisect.c} | 2 +-
 git.c                                  | 2 +-
 4 files changed, 4 insertions(+), 5 deletions(-)
 rename builtin/{bisect--helper.c => bisect.c} (99%)

diff --git a/Makefile b/Makefile
index 4927379184..78785c6b84 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
@@ -1137,7 +1136,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 8901a34d6b..aa955466b4 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 6066f553fd..cc9483e851 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect.c
@@ -1401,7 +1401,7 @@ static int cmd_bisect__run(int argc, const char **argv, const char *prefix UNUSE
 	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;
 	parse_opt_subcommand_fn *fn = NULL;
diff --git a/git.c b/git.c
index 6662548986..a2deb15e46 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 },
-- 
2.38.1.157.gedabe22e0a


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

* Re: [PATCH v3 0/3] Convert git-bisect--helper to OPT_SUBCOMMAND
  2022-11-10 16:36   ` [PATCH v3 " Đoàn Trần Công Danh
                       ` (3 preceding siblings ...)
  2022-11-10 16:36     ` [PATCH v2 00/11] Turn git-bisect to be builtin Đoàn Trần Công Danh
@ 2022-11-11 12:32     ` Ævar Arnfjörð Bjarmason
  4 siblings, 0 replies; 106+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-11 12:32 UTC (permalink / raw)
  To: Đoàn Trần Công Danh
  Cc: git, Lukáš Doktor, Jeff King, Christian Couder,
	Taylor Blau


On Thu, Nov 10 2022, Đoàn Trần Công Danh wrote:

> Despite this series has been merged into next.
> I'm sending this because Taylor said he wanted a (combined) reroll?
> <Y2riRSL+NprJt278@nand.local>

Since Taylor hasn't chimed in: I think that "combined reroll" was
referring to whether we could combine the version I sent out, and the
one you sent out.

I think we should (obviously) go for your version, and thanks for
picking this up and running with it. But at the time in that "What's
Cooking" the branch name was "dd/git-bisect-builtin" (i.e. your
version), but the note was still saying the source was
"<cover-00.13-00000000000-20221104T132117Z-avarab@gmail.com>" (i.e. my
version).

In any case, the patches you're re-rolling in this 1-3 are already in
next, so a "what it would have looked like" isn't going to be useful to
apply at this point. So I think just...

> Range-diff against v2:
> -:  ---------- > 1:  6b80fd9398 bisect--helper: remove unused options
> 1:  9d8a3cdd7a ! 2:  248ed392ea bisect--helper: move all subcommands into their own functions
>     @@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, cons
>      +static int cmd_bisect__terms(int argc, const char **argv, const char *prefix UNUSED)
>      +{
>      +	int res;
>     -+	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
>     ++	struct bisect_terms terms = { 0 };
>      +
>      +	if (argc > 1)
>      +		return error(_("--bisect-terms requires 0 or 1 argument"));
>     @@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, cons
>      +static int cmd_bisect__start(int argc, const char **argv, const char *prefix UNUSED)
>      +{
>      +	int res;
>     -+	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
>     ++	struct bisect_terms terms = { 0 };
>      +
>      +	set_terms(&terms, "bad", "good");
>      +	res = bisect_start(&terms, argv, argc);
>     @@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, cons
>      +static int cmd_bisect__next(int argc, const char **argv UNUSED, const char *prefix)
>      +{
>      +	int res;
>     -+	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
>     ++	struct bisect_terms terms = { 0 };
>      +
>      +	if (argc)
>      +		return error(_("--bisect-next requires 0 arguments"));
>     @@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, cons
>      +static int cmd_bisect__state(int argc, const char **argv, const char *prefix UNUSED)
>      +{
>      +	int res;
>     -+	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
>     ++	struct bisect_terms terms = { 0 };
>      +
>      +	set_terms(&terms, "bad", "good");
>      +	get_terms(&terms);
>     @@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, cons
>      +static int cmd_bisect__replay(int argc, const char **argv, const char *prefix UNUSED)
>      +{
>      +	int res;
>     -+	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
>     ++	struct bisect_terms terms = { 0 };
>      +
>      +	if (argc != 1)
>      +		return error(_("no logfile given"));
>     @@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, cons
>      +static int cmd_bisect__skip(int argc, const char **argv, const char *prefix UNUSED)
>      +{
>      +	int res;
>     -+	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
>     ++	struct bisect_terms terms = { 0 };
>      +
>      +	set_terms(&terms, "bad", "good");
>      +	get_terms(&terms);
>     @@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, cons
>      +static int cmd_bisect__visualize(int argc, const char **argv, const char *prefix UNUSED)
>      +{
>      +	int res;
>     -+	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
>     ++	struct bisect_terms terms = { 0 };
>      +
>      +	get_terms(&terms);
>      +	res = bisect_visualize(&terms, argv, argc);
>     @@ builtin/bisect--helper.c: static int bisect_run(struct bisect_terms *terms, cons
>      +static int cmd_bisect__run(int argc, const char **argv, const char *prefix UNUSED)
>      +{
>      +	int res;
>     -+	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
>     ++	struct bisect_terms terms = { 0 };
>      +
>      +	if (!argc)
>      +		return error(_("bisect run failed: no command provided."));

...a stand-alone two-patch series with these (and possibly tying any
other loose ends) would be nice, I think (but haven't looked carefully)
that it could probably be done in such a way that it applies
concurrently with the migration to builtin/bisect.c, i.e. to the extent
that the hunks don't conflict textually or semantically.

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

* Re: [PATCH v3 1/3] bisect--helper: remove unused options
  2022-11-10 16:36     ` [PATCH v3 1/3] bisect--helper: remove unused options Đoàn Trần Công Danh
@ 2022-11-11 12:42       ` Ævar Arnfjörð Bjarmason
  0 siblings, 0 replies; 106+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-11 12:42 UTC (permalink / raw)
  To: Đoàn Trần Công Danh
  Cc: git, Lukáš Doktor, Jeff King, Christian Couder,
	Taylor Blau


On Thu, Nov 10 2022, Đoàn Trần Công Danh wrote:

> 'git-bisect.sh' used to have a 'bisect_next_check' to check if we have
> both good/bad, old/new terms set or not.  In commit 129a6cf344
> (bisect--helper: `bisect_next_check` shell function in C, 2019-01-02),
> a subcommand for bisect--helper was introduced to port the check to C.
> Since d1bbbe45df (bisect--helper: reimplement `bisect_run` shell
> function in C, 2021-09-13), all users of 'bisect_next_check' was
> re-implemented in C, this subcommand was no longer used but we forgot
> to remove '--bisect-next-check'.



> 'git-bisect.sh' also used to have a 'bisect_write' function, whose
> third positional parameter was a "nolog" flag.  This flag was only used
> when 'bisect_start' invoked 'bisect_write' to write the starting good
> and bad revisions.  Then 0f30233a11 (bisect--helper: `bisect_write`
> shell function in C, 2019-01-02) ported it to C as a command mode of
> 'bisect--helper', which (incorrectly) added the '--no-log' option,
> and convert the only place ('bisect_start') that call 'bisect_write'
> with 'nolog' to 'git bisect--helper --bisect-write' with 'nolog'
> instead of '--no-log', since 'bisect--helper' has command modes not
> subcommands, all other command modes see and handle that option as well.
> This bogus state didn't last long, however, because in the same patch
> series 06f5608c14 (bisect--helper: `bisect_start` shell function
> partially in C, 2019-01-02) the C reimplementation of bisect_start()
> started calling the bisect_write() C function, this time with the
> right 'nolog' function parameter. From then on there was no need for
> the '--no-log' option in 'bisect--helper'. Eventually all bisect
> subcommands were ported to C as 'bisect--helper' command modes, each
> calling the bisect_write() C function instead, but when the
> '--bisect-write' command mode was removed in 68efed8c8a
> (bisect--helper: retire `--bisect-write` subcommand, 2021-02-03) it
> forgot to remove that '--no-log' option.
> '--no-log' option had never been used and it's unused now.

FWIW I think this very long backstory can be condensed to just (mainly
trying to get some paragraph breaks in there):

	The "--no-log" option has never been used. It was added in
	0f30233a11f (bisect--helper: `bisect_write` shell function in C,
	2019-01-02).

        In that commit bisect_write() was also changed to take a
	"no_log" function parameter, with nothing providing the
	"--no-log" option, and "bisect--helper --bisect-write" being
	given an unused "nolog" parameter.

        Then, later in the same series 06f5608c14e (bisect--helper:
        `bisect_start` shell function partially in C, 2019-01-02) the
        code passing the unused "nolog" parameter went away, while
        leaving us with this unused "--no-log" code.

> Signed-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>
> ---
>  builtin/bisect--helper.c | 7 +------
>  1 file changed, 1 insertion(+), 6 deletions(-)
>
> diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
> index 1d2ce8a0e1..5ec2e67f59 100644
> --- a/builtin/bisect--helper.c
> +++ b/builtin/bisect--helper.c
> @@ -1283,7 +1283,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,
> @@ -1295,12 +1294,10 @@ 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),
> -		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,
> @@ -1319,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 };

This looks good. Is it your original work, or did the signed-off-by's go
missing along the way? I.e. in the greater history of this topic this
comes from Johannes's:

	https://lore.kernel.org/git/1e43148864a52ffe05b5075bd0e449c0e056f078.1661885419.git.gitgitgadget@gmail.com/
	https://lore.kernel.org/git/05262b6a7d1b20a0d2f2ca2090be284ffb8c679c.1661885419.git.gitgitgadget@gmail.com/

Which, when I re-rolled it I carried forward as:

	https://lore.kernel.org/git/patch-04.13-b10deee4827-20221104T132117Z-avarab@gmail.com/

So I assumed you went back and looked at the original topic...

In any case, if you are doing a "misc little cleanups" series, I think
lifting some more from Johannes's original topic might be useful> I
dropped some in my 13 patch re-roll to keep it more focused on just the
"bisect built-in" goal, e.g. there's:

	https://lore.kernel.org/git/f2132b61ff7d7959fd8efcd9d416736b154718f0.1661885419.git.gitgitgadget@gmail.com/
	https://lore.kernel.org/git/4f93692e071cf316fd391344b5dbbc995c162232.1661885419.git.gitgitgadget@gmail.com/

But maybe those are better left out/or submitted as *another* topic,
just pointing them out in case you missed them...

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

* Re: [PATCH v3 2/3] bisect--helper: move all subcommands into their own functions
  2022-11-10 16:36     ` [PATCH v3 2/3] bisect--helper: move all subcommands into their own functions Đoàn Trần Công Danh
@ 2022-11-11 13:51       ` Ævar Arnfjörð Bjarmason
  0 siblings, 0 replies; 106+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-11 13:51 UTC (permalink / raw)
  To: Đoàn Trần Công Danh
  Cc: git, Lukáš Doktor, Jeff King, Christian Couder,
	Taylor Blau


On Thu, Nov 10 2022, Đoàn Trần Công Danh wrote:

> In a later change, we will use OPT_SUBCOMMAND to parse sub-commands to
> avoid consuming non-option opts.
>
> Since OPT_SUBCOMMAND needs a function pointer to operate,
> let's move it now.
>
> Signed-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>
> ---
>  builtin/bisect--helper.c | 155 ++++++++++++++++++++++++++++++---------
>  1 file changed, 121 insertions(+), 34 deletions(-)
>
> diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
> index 5ec2e67f59..d425555d1f 100644
> --- a/builtin/bisect--helper.c
> +++ b/builtin/bisect--helper.c
> @@ -1279,6 +1279,117 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
>  	return res;
>  }
>  
> +static int cmd_bisect__reset(int argc, const char **argv, const char *prefix UNUSED)
> +{
> +	if (argc > 1)
> +		return error(_("--bisect-reset requires either no argument or a commit"));
> +	return bisect_reset(argc ? argv[0] : NULL);
> +}
> +
> +static int cmd_bisect__terms(int argc, const char **argv, const char *prefix UNUSED)
> +{
> +	int res;
> +	struct bisect_terms terms = { 0 };
> +
> +	if (argc > 1)
> +		return error(_("--bisect-terms requires 0 or 1 argument"));
> +	res = bisect_terms(&terms, argc == 1 ? argv[0] : NULL);
> +	free_terms(&terms);
> +	return res;
> +}
> +
> +static int cmd_bisect__start(int argc, const char **argv, const char *prefix UNUSED)
> +{
> +	int res;
> +	struct bisect_terms terms = { 0 };
> +
> +	set_terms(&terms, "bad", "good");
> +	res = bisect_start(&terms, argv, argc);
> +	free_terms(&terms);
> +	return res;
> +}
> +
> +static int cmd_bisect__next(int argc, const char **argv UNUSED, const char *prefix)
> +{
> +	int res;
> +	struct bisect_terms terms = { 0 };
> +
> +	if (argc)
> +		return error(_("--bisect-next requires 0 arguments"));
> +	get_terms(&terms);
> +	res = bisect_next(&terms, prefix);
> +	free_terms(&terms);
> +	return res;
> +}
> +
> +static int cmd_bisect__state(int argc, const char **argv, const char *prefix UNUSED)
> +{
> +	int res;
> +	struct bisect_terms terms = { 0 };
> +
> +	set_terms(&terms, "bad", "good");
> +	get_terms(&terms);
> +	res = bisect_state(&terms, argv, argc);
> +	free_terms(&terms);
> +	return res;
> +}
> +
> +static int cmd_bisect__log(int argc, const char **argv UNUSED, const char *prefix UNUSED)
> +{
> +	if (argc)
> +		return error(_("--bisect-log requires 0 arguments"));
> +	return bisect_log();
> +}
> +
> +static int cmd_bisect__replay(int argc, const char **argv, const char *prefix UNUSED)
> +{
> +	int res;
> +	struct bisect_terms terms = { 0 };
> +
> +	if (argc != 1)
> +		return error(_("no logfile given"));
> +	set_terms(&terms, "bad", "good");
> +	res = bisect_replay(&terms, argv[0]);
> +	free_terms(&terms);
> +	return res;
> +}
> +
> +static int cmd_bisect__skip(int argc, const char **argv, const char *prefix UNUSED)
> +{
> +	int res;
> +	struct bisect_terms terms = { 0 };
> +
> +	set_terms(&terms, "bad", "good");
> +	get_terms(&terms);
> +	res = bisect_skip(&terms, argv, argc);
> +	free_terms(&terms);
> +	return res;
> +}
> +
> +static int cmd_bisect__visualize(int argc, const char **argv, const char *prefix UNUSED)
> +{
> +	int res;
> +	struct bisect_terms terms = { 0 };
> +
> +	get_terms(&terms);
> +	res = bisect_visualize(&terms, argv, argc);
> +	free_terms(&terms);
> +	return res;
> +}
> +
> +static int cmd_bisect__run(int argc, const char **argv, const char *prefix UNUSED)
> +{
> +	int res;
> +	struct bisect_terms terms = { 0 };
> +
> +	if (!argc)
> +		return error(_("bisect run failed: no command provided."));
> +	get_terms(&terms);
> +	res = bisect_run(&terms, argv, argc);
> +	free_terms(&terms);
> +	return res;
> +}
> +
>  int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
>  {
>  	enum {
> @@ -1318,8 +1429,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,
>  			     PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN_OPT);
> @@ -1329,60 +1438,38 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
>  
>  	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);
> +		res = cmd_bisect__reset(argc, argv, prefix);
>  		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);
> +		res = cmd_bisect__terms(argc, argv, prefix);
>  		break;
>  	case BISECT_START:
> -		set_terms(&terms, "bad", "good");
> -		res = bisect_start(&terms, argv, argc);
> +		res = cmd_bisect__start(argc, argv, prefix);
>  		break;
>  	case BISECT_NEXT:
> -		if (argc)
> -			return error(_("--bisect-next requires 0 arguments"));
> -		get_terms(&terms);
> -		res = bisect_next(&terms, prefix);
> +		res = cmd_bisect__next(argc, argv, prefix);
>  		break;
>  	case BISECT_STATE:
> -		set_terms(&terms, "bad", "good");
> -		get_terms(&terms);
> -		res = bisect_state(&terms, argv, argc);
> +		res = cmd_bisect__state(argc, argv, prefix);
>  		break;
>  	case BISECT_LOG:
> -		if (argc)
> -			return error(_("--bisect-log requires 0 arguments"));
> -		res = bisect_log();
> +		res = cmd_bisect__log(argc, argv, prefix);
>  		break;
>  	case BISECT_REPLAY:
> -		if (argc != 1)
> -			return error(_("no logfile given"));
> -		set_terms(&terms, "bad", "good");
> -		res = bisect_replay(&terms, argv[0]);
> +		res = cmd_bisect__replay(argc, argv, prefix);
>  		break;
>  	case BISECT_SKIP:
> -		set_terms(&terms, "bad", "good");
> -		get_terms(&terms);
> -		res = bisect_skip(&terms, argv, argc);
> +		res = cmd_bisect__skip(argc, argv, prefix);
>  		break;
>  	case BISECT_VISUALIZE:
> -		get_terms(&terms);
> -		res = bisect_visualize(&terms, argv, argc);
> +		res = cmd_bisect__visualize(argc, argv, prefix);
>  		break;
>  	case BISECT_RUN:
> -		if (!argc)
> -			return error(_("bisect run failed: no command provided."));
> -		get_terms(&terms);
> -		res = bisect_run(&terms, argv, argc);
> +		res = cmd_bisect__run(argc, argv, prefix);
>  		break;
>  	default:
>  		BUG("unknown subcommand %d", cmdmode);
>  	}
> -	free_terms(&terms);
>  
>  	/*
>  	 * Handle early success

FWIW I tried my suggestion in an earlier review of factoring this into a
function, I don't know if it's worth it, but it is a net reduction in
lines. Some of the error messages are changed as a result.

If you think the end result looks better, feel free to pick it up /
adapt it etc with my Signed-off-by.

 builtin/bisect--helper.c | 109 +++++++++++++++++++----------------------------
 1 file changed, 43 insertions(+), 66 deletions(-)

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index d4d813ebfce..e5a5261f9f2 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -469,8 +469,11 @@ static int get_terms(struct bisect_terms *terms)
 	return res;
 }
 
-static int bisect_terms(struct bisect_terms *terms, const char *option)
+static int bisect_terms(struct bisect_terms *terms, const char **argv,
+			int argc)
 {
+	const char *option = argc == 1 ? argv[0] : NULL;
+
 	if (get_terms(terms))
 		return error(_("no terms defined"));
 
@@ -1024,7 +1027,7 @@ static int process_replay_line(struct bisect_terms *terms, struct strbuf *line)
 		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(terms, argv.v, argv.nr);
 		strvec_clear(&argv);
 		return res;
 	}
@@ -1033,8 +1036,10 @@ 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 int bisect_replay(struct bisect_terms *terms, const char **argv,
+			int argc)
 {
+	const char *filename = argv[0];
 	FILE *fp = NULL;
 	enum bisect_error res = BISECT_OK;
 	struct strbuf line = STRBUF_INIT;
@@ -1279,6 +1284,24 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
 	return res;
 }
 
+typedef int (*cmd_bisect_fn_t)(struct bisect_terms *terms, const char **argv, int argc);
+static int terms_cmd(int argc, const char **argv, const char *prefix UNUSED,
+		     cmd_bisect_fn_t fn, int set, int errcond,
+		     const char *errmsg, const char *errcmd)
+{
+	int res;
+	struct bisect_terms terms = { 0 };
+
+	if (errcond)
+		return error(_(errmsg), errcmd);
+	if (set)
+		set_terms(&terms, "bad", "good");
+	get_terms(&terms);
+	res = fn(&terms, argv, argc);
+	free_terms(&terms);
+	return res;
+}
+
 static int cmd_bisect__reset(int argc, const char **argv, const char *prefix UNUSED)
 {
 	if (argc > 1)
@@ -1286,27 +1309,15 @@ static int cmd_bisect__reset(int argc, const char **argv, const char *prefix UNU
 	return bisect_reset(argc ? argv[0] : NULL);
 }
 
-static int cmd_bisect__terms(int argc, const char **argv, const char *prefix UNUSED)
+static int cmd_bisect__terms(int argc, const char **argv, const char *prefix)
 {
-	int res;
-	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
-
-	if (argc > 1)
-		return error(_("--bisect-terms requires 0 or 1 argument"));
-	res = bisect_terms(&terms, argc == 1 ? argv[0] : NULL);
-	free_terms(&terms);
-	return res;
+	return terms_cmd(argc, argv, prefix, bisect_terms, 0, argc > 1,
+			 N_("'bisect %s' requires 0 or 1 argument"), "terms");
 }
 
-static int cmd_bisect__start(int argc, const char **argv, const char *prefix UNUSED)
+static int cmd_bisect__start(int argc, const char **argv, const char *prefix)
 {
-	int res;
-	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
-
-	set_terms(&terms, "bad", "good");
-	res = bisect_start(&terms, argv, argc);
-	free_terms(&terms);
-	return res;
+	return terms_cmd(argc, argv, prefix, bisect_start, 1, 0, NULL, NULL);
 }
 
 static int cmd_bisect__next(int argc, const char **argv UNUSED, const char *prefix)
@@ -1322,16 +1333,9 @@ static int cmd_bisect__next(int argc, const char **argv UNUSED, const char *pref
 	return res;
 }
 
-static int cmd_bisect__state(int argc, const char **argv, const char *prefix UNUSED)
+static int cmd_bisect__state(int argc, const char **argv, const char *prefix)
 {
-	int res;
-	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
-
-	set_terms(&terms, "bad", "good");
-	get_terms(&terms);
-	res = bisect_state(&terms, argv, argc);
-	free_terms(&terms);
-	return res;
+	return terms_cmd(argc, argv, prefix, bisect_state, 1, 0, NULL, NULL);
 }
 
 static int cmd_bisect__log(int argc, const char **argv UNUSED, const char *prefix UNUSED)
@@ -1341,53 +1345,26 @@ static int cmd_bisect__log(int argc, const char **argv UNUSED, const char *prefi
 	return bisect_log();
 }
 
-static int cmd_bisect__replay(int argc, const char **argv, const char *prefix UNUSED)
+static int cmd_bisect__replay(int argc, const char **argv, const char *prefix)
 {
-	int res;
-	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
-
-	if (argc != 1)
-		return error(_("no logfile given"));
-	set_terms(&terms, "bad", "good");
-	res = bisect_replay(&terms, argv[0]);
-	free_terms(&terms);
-	return res;
+	return terms_cmd(argc, argv, prefix, bisect_replay, 1, argc != 1,
+			 N_("'bisect %s': no logfile given"), "replay");
 }
 
-static int cmd_bisect__skip(int argc, const char **argv, const char *prefix UNUSED)
+static int cmd_bisect__skip(int argc, const char **argv, const char *prefix)
 {
-	int res;
-	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
-
-	set_terms(&terms, "bad", "good");
-	get_terms(&terms);
-	res = bisect_skip(&terms, argv, argc);
-	free_terms(&terms);
-	return res;
+	return terms_cmd(argc, argv, prefix, bisect_skip, 1, 0, NULL, NULL);
 }
 
-static int cmd_bisect__visualize(int argc, const char **argv, const char *prefix UNUSED)
+static int cmd_bisect__visualize(int argc, const char **argv, const char *prefix)
 {
-	int res;
-	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
-
-	get_terms(&terms);
-	res = bisect_visualize(&terms, argv, argc);
-	free_terms(&terms);
-	return res;
+	return terms_cmd(argc, argv, prefix, bisect_visualize, 0, 0, NULL, NULL);
 }
 
-static int cmd_bisect__run(int argc, const char **argv, const char *prefix UNUSED)
+static int cmd_bisect__run(int argc, const char **argv, const char *prefix)
 {
-	int res;
-	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
-
-	if (!argc)
-		return error(_("bisect run failed: no command provided."));
-	get_terms(&terms);
-	res = bisect_run(&terms, argv, argc);
-	free_terms(&terms);
-	return res;
+	return terms_cmd(argc, argv, prefix, bisect_run, 0, !argc,
+			 N_("bisect %s failed: no command provided."), "run");
 }
 
 int cmd_bisect__helper(int argc, const char **argv, const char *prefix)

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

* Re: [PATCH v2 11/11] Turn `git bisect` into a full built-in
  2022-11-10 16:36       ` [PATCH v2 11/11] Turn `git bisect` into a full built-in Đoàn Trần Công Danh
@ 2022-11-11 13:53         ` Ævar Arnfjörð Bjarmason
  2022-11-11 15:37           ` Jeff King
  0 siblings, 1 reply; 106+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-11 13:53 UTC (permalink / raw)
  To: Đoàn Trần Công Danh
  Cc: git, Johannes Schindelin, Taylor Blau, Jeff King,
	Christian Couder, Junio C Hamano


On Thu, Nov 10 2022, Đoàn Trần Công Danh 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>
> Signed-off-by: Junio C Hamano <gitster@pobox.com>
> Signed-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>
> ---
>  Makefile                               | 3 +--
>  builtin.h                              | 2 +-
>  builtin/{bisect--helper.c => bisect.c} | 2 +-
>  git.c                                  | 2 +-
>  4 files changed, 4 insertions(+), 5 deletions(-)
>  rename builtin/{bisect--helper.c => bisect.c} (99%)
>
> diff --git a/Makefile b/Makefile
> index 4927379184..78785c6b84 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

This is missing a "git rm git-bisect.sh", which should be part of this
commit.

Do we have a test for at least the exit code of "git bisect -h"? I think
not, because before this it would have been (from skimming
git-sh-setup.sh) 1, but 129 after.

The new exit code is better, but let's test that. For some exitsing tests:

	git grep 'test_expect_code 129 .*-h'

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

* Re: [PATCH v2 10/11] bisect--helper: log: allow arbitrary number of arguments
  2022-11-10 16:36       ` [PATCH v2 10/11] bisect--helper: log: allow arbitrary number of arguments Đoàn Trần Công Danh
@ 2022-11-11 14:01         ` Ævar Arnfjörð Bjarmason
  0 siblings, 0 replies; 106+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-11 14:01 UTC (permalink / raw)
  To: Đoàn Trần Công Danh
  Cc: git, Taylor Blau, Jeff King, Christian Couder


On Thu, Nov 10 2022, Đoàn Trần Công Danh wrote:

> In a later change, we would like to turn bisect into a builtin by
> renaming bisect--helper.
>
> However, there's an oddity that "git bisect log" accepts any number of
> arguments and it will just ignore them all.
>
> Let's prepare for the next step by ignoring any arguments passed to
> "git bisect--helper log"
>
> Signed-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>
> ---
>  builtin/bisect--helper.c | 4 +---
>  git-bisect.sh            | 2 --
>  2 files changed, 1 insertion(+), 5 deletions(-)
>
> diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
> index 29d5a26c64..6066f553fd 100644
> --- a/builtin/bisect--helper.c
> +++ b/builtin/bisect--helper.c
> @@ -1347,10 +1347,8 @@ static int cmd_bisect__next(int argc, const char **argv UNUSED, const char *pref
>  	return res;
>  }
>  
> -static int cmd_bisect__log(int argc, const char **argv UNUSED, const char *prefix UNUSED)
> +static int cmd_bisect__log(int argc UNUSED, const char **argv UNUSED, const char *prefix UNUSED)
>  {
> -	if (argc)
> -		return error(_("'%s' requires 0 arguments"), "git bisect log");
>  	return bisect_log();
>  }
>  
> diff --git a/git-bisect.sh b/git-bisect.sh
> index 9f6c8cc093..f95b8103a9 100755
> --- a/git-bisect.sh
> +++ b/git-bisect.sh
> @@ -57,8 +57,6 @@ case "$#" in
>  	case "$cmd" in
>  	help)
>  		git bisect -h ;;
> -	log)
> -		git bisect--helper log || exit ;;
>  	*)
>  		git bisect--helper "$cmd" "$@" ;;
>  	esac

I'm agnostic on whether we keep this oddity, or just say we're fixing it
as we're converting things. We could also go for some in-between and
issue a warning(), if we suspect users in the wild are relying on this
for whatever reason.

I'd be fine with just making it error. E.g. in my upcoming (and already
aired on the list as an RFC) series to migrate git-submodule.sh to a
built-in I *do* change some behavior, because some of it's too insane to
carry forward in a bug-for-bug compatible way.

But I when doing so I add tests for it, explain why etc.

So, I think whatever we do here, we should be adding tests for this. If
it's worth preserving it's worth testing.

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

* Re: [PATCH v2 11/11] Turn `git bisect` into a full built-in
  2022-11-11 13:53         ` Ævar Arnfjörð Bjarmason
@ 2022-11-11 15:37           ` Jeff King
  2022-11-11 21:09             ` Ævar Arnfjörð Bjarmason
  0 siblings, 1 reply; 106+ messages in thread
From: Jeff King @ 2022-11-11 15:37 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: Đoàn Trần Công Danh, git,
	Johannes Schindelin, Taylor Blau, Christian Couder,
	Junio C Hamano

On Fri, Nov 11, 2022 at 02:53:19PM +0100, Ævar Arnfjörð Bjarmason wrote:

> Do we have a test for at least the exit code of "git bisect -h"? I think
> not, because before this it would have been (from skimming
> git-sh-setup.sh) 1, but 129 after.
> 
> The new exit code is better, but let's test that. For some exitsing tests:
> 
> 	git grep 'test_expect_code 129 .*-h'

It should be covered by t0012 automatically once it becomes a builtin
(and checking out the tip of dd/git-bisect-builtin, that seems to be the
case).

-Peff

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

* Re: [PATCH v2 11/11] Turn `git bisect` into a full built-in
  2022-11-11 15:37           ` Jeff King
@ 2022-11-11 21:09             ` Ævar Arnfjörð Bjarmason
  0 siblings, 0 replies; 106+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-11 21:09 UTC (permalink / raw)
  To: Jeff King
  Cc: Đoàn Trần Công Danh, git,
	Johannes Schindelin, Taylor Blau, Christian Couder,
	Junio C Hamano


On Fri, Nov 11 2022, Jeff King wrote:

> On Fri, Nov 11, 2022 at 02:53:19PM +0100, Ævar Arnfjörð Bjarmason wrote:
>
>> Do we have a test for at least the exit code of "git bisect -h"? I think
>> not, because before this it would have been (from skimming
>> git-sh-setup.sh) 1, but 129 after.
>> 
>> The new exit code is better, but let's test that. For some exitsing tests:
>> 
>> 	git grep 'test_expect_code 129 .*-h'
>
> It should be covered by t0012 automatically once it becomes a builtin
> (and checking out the tip of dd/git-bisect-builtin, that seems to be the
> case).

Yes, you're right. I forgot about those. So, there's nothing to do here
then...

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

* Re: [PATCH v2 00/11] Turn git-bisect to be builtin
  2022-11-10 16:36     ` [PATCH v2 00/11] Turn git-bisect to be builtin Đoàn Trần Công Danh
                         ` (10 preceding siblings ...)
  2022-11-10 16:36       ` [PATCH v2 11/11] Turn `git bisect` into a full built-in Đoàn Trần Công Danh
@ 2022-11-11 22:07       ` Taylor Blau
  2022-11-15 19:18         ` Taylor Blau
  11 siblings, 1 reply; 106+ messages in thread
From: Taylor Blau @ 2022-11-11 22:07 UTC (permalink / raw)
  To: Đoàn Trần Công Danh
  Cc: git, Taylor Blau, Jeff King, Christian Couder,
	Ævar Arnfjörð Bjarmason

On Thu, Nov 10, 2022 at 11:36:35PM +0700, Đoàn Trần Công Danh wrote:
> This series finish the git-bisect porting from shell script into a C builtin.
>
> This series can't be applied cleaned on master, it needs to be applied on top
> of the series posted at:
> https://lore.kernel.org/git/cover.1668097286.git.congdanhqx@gmail.com/
> AND the series rs/no-more-run-command-v, which has been integrated to next.

Thanks, having both was helpful. Note that 'rs/no-more-run-command-v' was
merged into 'master' via be4ac3b197 (Merge branch
'rs/no-more-run-command-v', 2022-11-08), so picking up these new patches
only needed a merge of the other series.

> Johannes Schindelin (2):
>   bisect--helper: handle states directly
>   Turn `git bisect` into a full built-in
>
> Ævar Arnfjörð Bjarmason (4):
>   bisect tests: test for v2.30.0 "bisect run" regressions
>   bisect: refactor bisect_run() to match CodingGuidelines
>   bisect test: test exit codes on bad usage
>   bisect--helper: emit usage for "git bisect"
>
> Đoàn Trần Công Danh (5):
>   bisect: fix output regressions in v2.30.0
>   bisect run: keep some of the post-v2.30.0 output
>   bisect-run: verify_good: account for non-negative exit status
>   bisect--helper: identify as bisect when report error
>   bisect--helper: log: allow arbitrary number of arguments

Looking good to me. Is everybody happy to start merging these two down?

Thanks,
Taylor

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

* Re: [PATCH 09/13] parse-options API: don't restrict OPT_SUBCOMMAND() to one *_fn type
  2022-11-06 13:28               ` Ævar Arnfjörð Bjarmason
@ 2022-11-12 10:42                 ` René Scharfe
  2022-11-12 16:34                   ` Jeff King
  0 siblings, 1 reply; 106+ messages in thread
From: René Scharfe @ 2022-11-12 10:42 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: git, Junio C Hamano, Jeff King, Taylor Blau,
	Đoàn Trần Công Danh, SZEDER Gábor,
	Lukáš Doktor, Johannes Schindelin

Am 06.11.22 um 14:28 schrieb Ævar Arnfjörð Bjarmason:
>
> No, I think that:
>
> 1) J.5.7 does that on its own for C99

An extension is not part of the standard, by definition.  Section J is
informative, not normative.  J.5.7 just says that there are systems out
there which allow casts from function pointers to object pointers and/or
back, which is not portable.

> 2) POSIX has orthagonally mandated this, seperate from C99.

It only requires dlsym(3) to work.  That's a narrow case.  A conforming
implementation could have function pointers wider than object pointers,
making conversions in the other direction lossy.  Or have function
pointers narrower than object pointers and let dlopen(3) place symbols
only in the range addressable by those.

> In practice I think it's always worked for dlsym(), but there's
> interesting changes in wording between v6 and v7 of POSIX:
>
>    - https://pubs.opengroup.org/onlinepubs/009695399/functions/dlsym.html
>    - https://pubs.opengroup.org/onlinepubs/9699919799/functions/dlsym.html
>
> v6 claims that conforming C compilers are required to produce a warning
> if this isn't supported (I haven't found the part of the standard
> they're referencing), and notes that the behavior may be deprecated in
> the future.
>
> Whereas v7 says that POSIX "requires this conversion to work correctly
> on conforming implementations".

From the second link: "The dlsym() function is moved from the XSI option
to the Base."  So dynamic libraries are no longer optional on POSIX
systems.  That means you can use dlsym(3) on any compliant system.  You
can also safely store its return value in an intptr_t IIUC.  But that
doesn't generalize to all function pointers.

> I think it's useful in itself to see what subset or superset of C we
> actually need to concern ourselves with.
>
> E.g. we have plenty of code that assumes ASCII, instead of catering to
> EBCDIC, and assuming NULL is (void *)0, not (void *)123456 or whatever.

NULL is defined as "0" or "(void *)0" by C99 6.3.2.3 Pointers paragraph
3 and 7.17 Common definitions <stddef.h> paragraph 3.

> Yes, in this case the alternative is trivial, but perhaps we'd find a
> use-case in the future.
>
> All I'm saying is let's leave the current one in place, as there's no
> indication that it's not supported by our targets.

Leaving undefined behavior in the code in the hope that we may come up
with a compelling use case for it later is a bad idea.  I really hope
we never find one.

René

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

* Re: [PATCH 09/13] parse-options API: don't restrict OPT_SUBCOMMAND() to one *_fn type
  2022-11-12 10:42                 ` René Scharfe
@ 2022-11-12 16:34                   ` Jeff King
  2022-11-12 16:55                     ` Ævar Arnfjörð Bjarmason
  0 siblings, 1 reply; 106+ messages in thread
From: Jeff King @ 2022-11-12 16:34 UTC (permalink / raw)
  To: René Scharfe
  Cc: Ævar Arnfjörð Bjarmason, git, Junio C Hamano,
	Taylor Blau, Đoàn Trần Công Danh,
	SZEDER Gábor, Lukáš Doktor, Johannes Schindelin

On Sat, Nov 12, 2022 at 11:42:09AM +0100, René Scharfe wrote:

> > E.g. we have plenty of code that assumes ASCII, instead of catering to
> > EBCDIC, and assuming NULL is (void *)0, not (void *)123456 or whatever.
> 
> NULL is defined as "0" or "(void *)0" by C99 6.3.2.3 Pointers paragraph
> 3 and 7.17 Common definitions <stddef.h> paragraph 3.

I think he is alluding to the fact that while the standard requires that
a "0" constant refers to a NULL pointer, the representation does not
have to be all-bits-zero. So:

  char *foo = 0;

is fine, but:

  char *foo;
  memset(foo, 0, sizeof(&foo));

is not. And we absolutely do the latter in our code base anyway, because
it's convenient and unlikely to be a problem on practical platforms. And
I think it has always been our attitude in this community to let
engineering practicality trump strict adherence to the standard. But
"practicality" there should be measuring the tradeoff of how useful
something is versus how likely it is to bite us.

In the case under discussion, my gut feeling agrees with you, though.
I'm skeptical that equivalence of object and function pointers is all
that useful in practice. And your mention of CHERI seems like a
plausible way it could bite us.

-Peff

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

* Re: [PATCH 09/13] parse-options API: don't restrict OPT_SUBCOMMAND() to one *_fn type
  2022-11-12 16:34                   ` Jeff King
@ 2022-11-12 16:55                     ` Ævar Arnfjörð Bjarmason
  2022-11-13 17:31                       ` René Scharfe
  0 siblings, 1 reply; 106+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-12 16:55 UTC (permalink / raw)
  To: Jeff King
  Cc: René Scharfe, git, Junio C Hamano, Taylor Blau,
	Đoàn Trần Công Danh, SZEDER Gábor,
	Lukáš Doktor, Johannes Schindelin


On Sat, Nov 12 2022, Jeff King wrote:

> On Sat, Nov 12, 2022 at 11:42:09AM +0100, René Scharfe wrote:
>
>> > E.g. we have plenty of code that assumes ASCII, instead of catering to
>> > EBCDIC, and assuming NULL is (void *)0, not (void *)123456 or whatever.
>> 
>> NULL is defined as "0" or "(void *)0" by C99 6.3.2.3 Pointers paragraph
>> 3 and 7.17 Common definitions <stddef.h> paragraph 3.
>
> I think he is alluding to the fact that while the standard requires that
> a "0" constant refers to a NULL pointer, the representation does not
> have to be all-bits-zero. So:
>
>   char *foo = 0;
>
> is fine, but:
>
>   char *foo;
>   memset(foo, 0, sizeof(&foo));

Yes, to elaborate: the "null pointer constant" referred to in 6.3.2.3
deliberately leaves room for the representation being unequal to the
"all zero bits". And as you point out the former example is portable,
but not the latter.

> is not. And we absolutely do the latter in our code base anyway, because
> it's convenient and unlikely to be a problem on practical platforms. And
> I think it has always been our attitude in this community to let
> engineering practicality trump strict adherence to the standard. But
> "practicality" there should be measuring the tradeoff of how useful
> something is versus how likely it is to bite us.

All I've been trying to get across in this sub-thread is that there's an
interesting empirical question here: Are we in fact targeting an
architecture where J.5.7 isn't implemented, or likely to have one sneak
up on us?

I don't think so, and timing-wise deciding to be paranoid about this
particular thing would leave that question unanswered, when all we have
to do is wait a bit (some of the slower platforms tend to be a few
releases behind).

The argument for the change[1] (further articulated upthread) hasn't
answered the "do we target such an arch?", but seems to just fall back
to general standards paranoia.

Which isn't an invalid argument in itself. But doesn't really address
why we'd be worried about *this* particular thing, but not e.g. those
sort of memsets, assuming ASCII ordering for 'A'..'z' etc.

> In the case under discussion, my gut feeling agrees with you, though.
> I'm skeptical that equivalence of object and function pointers is all
> that useful in practice. And your mention of CHERI seems like a
> plausible way it could bite us.

I think the post-image of [1] looks nicer when reviewed stand-alone, so
I'm not against the change per-se, I actually like it.

And I don't have a use-case for using that feature further, in a way
that isn't easy to do differently.

But e.g. now we're having a parallel discussion about using some 3rd
party bitmap library. We might e.g. want to incorporate some 3rd party
JIT or whatever in the future. If we run into this question again it
would be nice to have it answered already.

And if we didn't have this J.5.7 reliance in that code already I don't
think it would be worth the effort to introduce one as a test
balloon. I'm only saying this in the context that we already have one.

1. https://lore.kernel.org/git/c64e4fa5-62c2-2a93-a4ef-bd84407ea570@web.de/

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

* Re: [PATCH 09/13] parse-options API: don't restrict OPT_SUBCOMMAND() to one *_fn type
  2022-11-12 16:55                     ` Ævar Arnfjörð Bjarmason
@ 2022-11-13 17:31                       ` René Scharfe
  0 siblings, 0 replies; 106+ messages in thread
From: René Scharfe @ 2022-11-13 17:31 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason, Jeff King
  Cc: git, Junio C Hamano, Taylor Blau,
	Đoàn Trần Công Danh, SZEDER Gábor,
	Lukáš Doktor, Johannes Schindelin

Am 12.11.22 um 17:55 schrieb Ævar Arnfjörð Bjarmason:
>
> On Sat, Nov 12 2022, Jeff King wrote:
>
>> On Sat, Nov 12, 2022 at 11:42:09AM +0100, René Scharfe wrote:
>>
>>>> E.g. we have plenty of code that assumes ASCII, instead of catering to
>>>> EBCDIC, and assuming NULL is (void *)0, not (void *)123456 or whatever.
>>>
>>> NULL is defined as "0" or "(void *)0" by C99 6.3.2.3 Pointers paragraph
>>> 3 and 7.17 Common definitions <stddef.h> paragraph 3.
>>
>> I think he is alluding to the fact that while the standard requires that
>> a "0" constant refers to a NULL pointer, the representation does not
>> have to be all-bits-zero. So:
>>
>>   char *foo = 0;
>>
>> is fine, but:
>>
>>   char *foo;
>>   memset(foo, 0, sizeof(&foo));
>
> Yes, to elaborate: the "null pointer constant" referred to in 6.3.2.3
> deliberately leaves room for the representation being unequal to the
> "all zero bits". And as you point out the former example is portable,
> but not the latter.
>
>> is not. And we absolutely do the latter in our code base anyway, because
>> it's convenient and unlikely to be a problem on practical platforms. And
>> I think it has always been our attitude in this community to let
>> engineering practicality trump strict adherence to the standard. But
>> "practicality" there should be measuring the tradeoff of how useful
>> something is versus how likely it is to bite us.

For me the usefulness so far is negative: The code is more complicated
than necessary.  Adding a context pointer to the callback function
signature here and keeping the extra code outside the callback function
in builtin/pack-objects.c is simpler.

> All I've been trying to get across in this sub-thread is that there's an
> interesting empirical question here: Are we in fact targeting an
> architecture where J.5.7 isn't implemented, or likely to have one sneak
> up on us?

How would you measure this?  Undefined behavior can manifest itself
differently e.g. based on compiler version and options, or in this
case pointer value and perhaps even function calling convention.  And
of course in the form of the famous nasal demons..

> I don't think so, and timing-wise deciding to be paranoid about this
> particular thing would leave that question unanswered, when all we have
> to do is wait a bit (some of the slower platforms tend to be a few
> releases behind).
>
> The argument for the change[1] (further articulated upthread) hasn't
> answered the "do we target such an arch?", but seems to just fall back
> to general standards paranoia.

I mentioned CHERI (Arm Morello) as a candidate, but can't tell you for
sure.

> Which isn't an invalid argument in itself. But doesn't really address
> why we'd be worried about *this* particular thing, but not e.g. those
> sort of memsets, assuming ASCII ordering for 'A'..'z' etc.

You can keep worrying about them if you like.  Replacing memset calls
with _INIT macros has been going on for while already.  Using isalpha()
instead of character range comparisons etc. is probably a good idea
anyway.

>> In the case under discussion, my gut feeling agrees with you, though.
>> I'm skeptical that equivalence of object and function pointers is all
>> that useful in practice. And your mention of CHERI seems like a
>> plausible way it could bite us.
>
> I think the post-image of [1] looks nicer when reviewed stand-alone, so
> I'm not against the change per-se, I actually like it.
>
> And I don't have a use-case for using that feature further, in a way
> that isn't easy to do differently.
>
> But e.g. now we're having a parallel discussion about using some 3rd
> party bitmap library. We might e.g. want to incorporate some 3rd party
> JIT or whatever in the future. If we run into this question again it
> would be nice to have it answered already.

Why would a bitmap library require function pointer casts?

A JIT library probably comes with a list of supported systems and
requires a fallback for anyone else.  I'd expect the system-specific
parts to be encapsulated in that library.

> And if we didn't have this J.5.7 reliance in that code already I don't
> think it would be worth the effort to introduce one as a test
> balloon. I'm only saying this in the context that we already have one.
>
> 1. https://lore.kernel.org/git/c64e4fa5-62c2-2a93-a4ef-bd84407ea570@web.de/

If it's not worth adding then it's probably not worth keeping.

René

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

* Re: [PATCH v2 00/11] Turn git-bisect to be builtin
  2022-11-11 22:07       ` [PATCH v2 00/11] Turn git-bisect to be builtin Taylor Blau
@ 2022-11-15 19:18         ` Taylor Blau
  2022-11-15 19:36           ` Jeff King
  0 siblings, 1 reply; 106+ messages in thread
From: Taylor Blau @ 2022-11-15 19:18 UTC (permalink / raw)
  To: Đoàn Trần Công Danh
  Cc: git, Jeff King, Christian Couder,
	Ævar Arnfjörð Bjarmason

On Fri, Nov 11, 2022 at 05:07:42PM -0500, Taylor Blau wrote:
> On Thu, Nov 10, 2022 at 11:36:35PM +0700, Đoàn Trần Công Danh wrote:
> > This series finish the git-bisect porting from shell script into a C builtin.
> >
> > This series can't be applied cleaned on master, it needs to be applied on top
> > of the series posted at:
> > https://lore.kernel.org/git/cover.1668097286.git.congdanhqx@gmail.com/
> > AND the series rs/no-more-run-command-v, which has been integrated to next.
>
> Thanks, having both was helpful. Note that 'rs/no-more-run-command-v' was
> merged into 'master' via be4ac3b197 (Merge branch
> 'rs/no-more-run-command-v', 2022-11-08), so picking up these new patches
> only needed a merge of the other series.
>
> > Johannes Schindelin (2):
> >   bisect--helper: handle states directly
> >   Turn `git bisect` into a full built-in
> >
> > Ævar Arnfjörð Bjarmason (4):
> >   bisect tests: test for v2.30.0 "bisect run" regressions
> >   bisect: refactor bisect_run() to match CodingGuidelines
> >   bisect test: test exit codes on bad usage
> >   bisect--helper: emit usage for "git bisect"
> >
> > Đoàn Trần Công Danh (5):
> >   bisect: fix output regressions in v2.30.0
> >   bisect run: keep some of the post-v2.30.0 output
> >   bisect-run: verify_good: account for non-negative exit status
> >   bisect--helper: identify as bisect when report error
> >   bisect--helper: log: allow arbitrary number of arguments
>
> Looking good to me. Is everybody happy to start merging these two down?

Hmm. Looks like there is a small breakage in the last commit "Turn `git
bisect` into a full built-in":

    $ make check-builtins
    ./check-builtins.sh
    bisect is builtin but git-bisect.sh still exists
    make: *** [Makefile:3561: check-builtins] Error 1

Seeing that this is on 'next', it would be nice to see a fix in the near
future, certainly before we graduate this down to 'master'. Am I correct
in assuming that there is no reason to keep git-bisect.sh around after
that commit?

Thanks,
Taylor

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

* Re: [PATCH v2 00/11] Turn git-bisect to be builtin
  2022-11-15 19:18         ` Taylor Blau
@ 2022-11-15 19:36           ` Jeff King
  2022-11-15 19:40             ` Taylor Blau
  0 siblings, 1 reply; 106+ messages in thread
From: Jeff King @ 2022-11-15 19:36 UTC (permalink / raw)
  To: Taylor Blau
  Cc: Đoàn Trần Công Danh, git, Christian Couder,
	Ævar Arnfjörð Bjarmason

On Tue, Nov 15, 2022 at 02:18:24PM -0500, Taylor Blau wrote:

> Hmm. Looks like there is a small breakage in the last commit "Turn `git
> bisect` into a full built-in":
> 
>     $ make check-builtins
>     ./check-builtins.sh
>     bisect is builtin but git-bisect.sh still exists
>     make: *** [Makefile:3561: check-builtins] Error 1
> 
> Seeing that this is on 'next', it would be nice to see a fix in the near
> future, certainly before we graduate this down to 'master'. Am I correct
> in assuming that there is no reason to keep git-bisect.sh around after
> that commit?

Yeah, see:

  https://lore.kernel.org/git/patch-1.1-7be23b6faa0-20221115T093130Z-avarab@gmail.com/

-Peff

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

* Re: [PATCH v2 00/11] Turn git-bisect to be builtin
  2022-11-15 19:36           ` Jeff King
@ 2022-11-15 19:40             ` Taylor Blau
  0 siblings, 0 replies; 106+ messages in thread
From: Taylor Blau @ 2022-11-15 19:40 UTC (permalink / raw)
  To: Jeff King
  Cc: Taylor Blau, Đoàn Trần Công Danh, git,
	Christian Couder, Ævar Arnfjörð Bjarmason

On Tue, Nov 15, 2022 at 02:36:12PM -0500, Jeff King wrote:
> On Tue, Nov 15, 2022 at 02:18:24PM -0500, Taylor Blau wrote:
>
> > Hmm. Looks like there is a small breakage in the last commit "Turn `git
> > bisect` into a full built-in":
> >
> >     $ make check-builtins
> >     ./check-builtins.sh
> >     bisect is builtin but git-bisect.sh still exists
> >     make: *** [Makefile:3561: check-builtins] Error 1
> >
> > Seeing that this is on 'next', it would be nice to see a fix in the near
> > future, certainly before we graduate this down to 'master'. Am I correct
> > in assuming that there is no reason to keep git-bisect.sh around after
> > that commit?
>
> Yeah, see:
>
>   https://lore.kernel.org/git/patch-1.1-7be23b6faa0-20221115T093130Z-avarab@gmail.com/

Ack, thanks.

Thanks,
Taylor

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

end of thread, other threads:[~2022-11-15 19:40 UTC | newest]

Thread overview: 106+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-11-04  6:31 "git bisect run" strips "--log" from the list of arguments Lukáš Doktor
2022-11-04  9:45 ` Jeff King
2022-11-04 11:10   ` Đoàn Trần Công Danh
2022-11-04 12:51     ` Jeff King
2022-11-04 11:36   ` Ævar Arnfjörð Bjarmason
2022-11-04 12:45     ` Jeff King
2022-11-04 13:07       ` Ævar Arnfjörð Bjarmason
2022-11-04 12:37   ` SZEDER Gábor
2022-11-04 12:44     ` Jeff King
2022-11-04 11:40 ` [PATCH 0/3] Convert git-bisect--helper to OPT_SUBCOMMAND Đoàn Trần Công Danh
2022-11-04 11:40   ` [PATCH 1/3] bisect--helper: remove unused options Đoàn Trần Công Danh
2022-11-04 12:53     ` Jeff King
2022-11-04 11:40   ` [PATCH 2/3] bisect--helper: move all subcommands into their own functions Đoàn Trần Công Danh
2022-11-04 12:55     ` Jeff King
2022-11-04 13:32     ` Ævar Arnfjörð Bjarmason
2022-11-04 14:03       ` Đoàn Trần Công Danh
2022-11-04 11:40   ` [PATCH 3/3] bisect--helper: parse subcommand with OPT_SUBCOMMAND Đoàn Trần Công Danh
2022-11-04 13:00     ` Jeff King
2022-11-04 13:46     ` Ævar Arnfjörð Bjarmason
2022-11-04 14:07       ` Đoàn Trần Công Danh
2022-11-04 13:55   ` [PATCH 0/3] Convert git-bisect--helper to OPT_SUBCOMMAND Ævar Arnfjörð Bjarmason
2022-11-05 17:03   ` [PATCH v2 " Đoàn Trần Công Danh
2022-11-05 17:03     ` [PATCH v2 1/3] bisect--helper: remove unused options Đoàn Trần Công Danh
2022-11-05 17:03     ` [PATCH v2 2/3] bisect--helper: move all subcommands into their own functions Đoàn Trần Công Danh
2022-11-05 17:13       ` Đoàn Trần Công Danh
2022-11-05 17:03     ` [PATCH v2 3/3] bisect--helper: parse subcommand with OPT_SUBCOMMAND Đoàn Trần Công Danh
2022-11-05 17:07     ` [PATCH 00/13] Turn git-bisect to be builtin Đoàn Trần Công Danh
2022-11-05 17:07       ` [PATCH 01/13] bisect tests: test for v2.30.0 "bisect run" regressions Đoàn Trần Công Danh
2022-11-07 21:31         ` Ævar Arnfjörð Bjarmason
2022-11-08  1:17           ` Đoàn Trần Công Danh
2022-11-05 17:07       ` [PATCH 02/13] bisect: refactor bisect_run() to match CodingGuidelines Đoàn Trần Công Danh
2022-11-05 17:07       ` [PATCH 03/13] bisect--helper: pass arg[cv] down to do_bisect_run Đoàn Trần Công Danh
2022-11-05 17:07       ` [PATCH 04/13] bisect: fix output regressions in v2.30.0 Đoàn Trần Công Danh
2022-11-05 17:07       ` [PATCH 05/13] bisect run: keep some of the post-v2.30.0 output Đoàn Trần Công Danh
2022-11-07 21:40         ` Ævar Arnfjörð Bjarmason
2022-11-08  1:26           ` Đoàn Trần Công Danh
2022-11-08  3:11             ` Ævar Arnfjörð Bjarmason
2022-11-05 17:07       ` [PATCH 06/13] bisect--helper: remove unused arguments from do_bisect_run Đoàn Trần Công Danh
2022-11-05 17:07       ` [PATCH 07/13] bisect--helper: pretend we're real bisect when report error Đoàn Trần Công Danh
2022-11-07 21:29         ` Ævar Arnfjörð Bjarmason
2022-11-05 17:07       ` [PATCH 08/13] bisect test: test exit codes on bad usage Đoàn Trần Công Danh
2022-11-05 17:07       ` [PATCH 09/13] bisect--helper: emit usage for "git bisect" Đoàn Trần Công Danh
2022-11-05 17:07       ` [PATCH 10/13] bisect--helper: make `state` optional Đoàn Trần Công Danh
2022-11-05 17:07       ` [PATCH 11/13] bisect--helper: remove subcommand state Đoàn Trần Công Danh
2022-11-07 21:45         ` Ævar Arnfjörð Bjarmason
2022-11-08  1:27           ` Đoàn Trần Công Danh
2022-11-05 17:07       ` [PATCH 12/13] bisect--helper: log: allow arbitrary number of arguments Đoàn Trần Công Danh
2022-11-05 17:07       ` [PATCH 13/13] Turn `git bisect` into a full built-in Đoàn Trần Công Danh
2022-11-05 23:18     ` [PATCH v2 0/3] Convert git-bisect--helper to OPT_SUBCOMMAND Taylor Blau
2022-11-10 16:36   ` [PATCH v3 " Đoàn Trần Công Danh
2022-11-10 16:36     ` [PATCH v3 1/3] bisect--helper: remove unused options Đoàn Trần Công Danh
2022-11-11 12:42       ` Ævar Arnfjörð Bjarmason
2022-11-10 16:36     ` [PATCH v3 2/3] bisect--helper: move all subcommands into their own functions Đoàn Trần Công Danh
2022-11-11 13:51       ` Ævar Arnfjörð Bjarmason
2022-11-10 16:36     ` [PATCH v3 3/3] bisect--helper: parse subcommand with OPT_SUBCOMMAND Đoàn Trần Công Danh
2022-11-10 16:36     ` [PATCH v2 00/11] Turn git-bisect to be builtin Đoàn Trần Công Danh
2022-11-10 16:36       ` [PATCH v2 01/11] bisect tests: test for v2.30.0 "bisect run" regressions Đoàn Trần Công Danh
2022-11-10 16:36       ` [PATCH v2 02/11] bisect: refactor bisect_run() to match CodingGuidelines Đoàn Trần Công Danh
2022-11-10 16:36       ` [PATCH v2 03/11] bisect: fix output regressions in v2.30.0 Đoàn Trần Công Danh
2022-11-10 16:36       ` [PATCH v2 04/11] bisect run: keep some of the post-v2.30.0 output Đoàn Trần Công Danh
2022-11-10 16:36       ` [PATCH v2 05/11] bisect-run: verify_good: account for non-negative exit status Đoàn Trần Công Danh
2022-11-10 16:36       ` [PATCH v2 06/11] bisect--helper: identify as bisect when report error Đoàn Trần Công Danh
2022-11-10 16:36       ` [PATCH v2 07/11] bisect test: test exit codes on bad usage Đoàn Trần Công Danh
2022-11-10 16:36       ` [PATCH v2 08/11] bisect--helper: emit usage for "git bisect" Đoàn Trần Công Danh
2022-11-10 16:36       ` [PATCH v2 09/11] bisect--helper: handle states directly Đoàn Trần Công Danh
2022-11-10 16:36       ` [PATCH v2 10/11] bisect--helper: log: allow arbitrary number of arguments Đoàn Trần Công Danh
2022-11-11 14:01         ` Ævar Arnfjörð Bjarmason
2022-11-10 16:36       ` [PATCH v2 11/11] Turn `git bisect` into a full built-in Đoàn Trần Công Danh
2022-11-11 13:53         ` Ævar Arnfjörð Bjarmason
2022-11-11 15:37           ` Jeff King
2022-11-11 21:09             ` Ævar Arnfjörð Bjarmason
2022-11-11 22:07       ` [PATCH v2 00/11] Turn git-bisect to be builtin Taylor Blau
2022-11-15 19:18         ` Taylor Blau
2022-11-15 19:36           ` Jeff King
2022-11-15 19:40             ` Taylor Blau
2022-11-11 12:32     ` [PATCH v3 0/3] Convert git-bisect--helper to OPT_SUBCOMMAND Ævar Arnfjörð Bjarmason
2022-11-04 13:22 ` [PATCH 00/13] bisect: v2.30.0 "run" regressions + make it built-in Ævar Arnfjörð Bjarmason
2022-11-04 13:22   ` [PATCH 01/13] bisect tests: test for v2.30.0 "bisect run" regressions Ævar Arnfjörð Bjarmason
2022-11-04 13:22   ` [PATCH 02/13] bisect: refactor bisect_run() to match CodingGuidelines Ævar Arnfjörð Bjarmason
2022-11-04 13:22   ` [PATCH 03/13] bisect: fix output regressions in v2.30.0 Ævar Arnfjörð Bjarmason
2022-11-04 13:22   ` [PATCH 04/13] bisect run: fix "--log" eating regression " Ævar Arnfjörð Bjarmason
2022-11-04 13:22   ` [PATCH 05/13] bisect run: keep some of the post-v2.30.0 output Ævar Arnfjörð Bjarmason
2022-11-04 13:22   ` [PATCH 06/13] bisect test: test exit codes on bad usage Ævar Arnfjörð Bjarmason
2022-11-04 13:22   ` [PATCH 07/13] bisect--helper: emit usage for "git bisect" Ævar Arnfjörð Bjarmason
2022-11-04 13:22   ` [PATCH 08/13] bisect--helper: have all functions take state, argc, argv, prefix Ævar Arnfjörð Bjarmason
2022-11-04 13:22   ` [PATCH 09/13] parse-options API: don't restrict OPT_SUBCOMMAND() to one *_fn type Ævar Arnfjörð Bjarmason
2022-11-05  8:32     ` René Scharfe
2022-11-05 11:34       ` Đoàn Trần Công Danh
2022-11-05 21:32         ` Phillip Wood
2022-11-05 13:52       ` Ævar Arnfjörð Bjarmason
2022-11-05 16:36         ` Phillip Wood
2022-11-05 21:59           ` Ævar Arnfjörð Bjarmason
2022-11-05 17:26         ` René Scharfe
2022-11-05 22:33           ` Ævar Arnfjörð Bjarmason
2022-11-06  8:25             ` René Scharfe
2022-11-06 13:28               ` Ævar Arnfjörð Bjarmason
2022-11-12 10:42                 ` René Scharfe
2022-11-12 16:34                   ` Jeff King
2022-11-12 16:55                     ` Ævar Arnfjörð Bjarmason
2022-11-13 17:31                       ` René Scharfe
2022-11-04 13:22   ` [PATCH 10/13] bisect--helper: remove dead --bisect-{next-check,autostart} code Ævar Arnfjörð Bjarmason
2022-11-04 13:22   ` [PATCH 11/13] bisect--helper: convert to OPT_SUBCOMMAND_CB() Ævar Arnfjörð Bjarmason
2022-11-04 13:22   ` [PATCH 12/13] bisect--helper: make `state` optional Ævar Arnfjörð Bjarmason
2022-11-04 13:22   ` [PATCH 13/13] Turn `git bisect` into a full built-in Ævar Arnfjörð Bjarmason
2022-11-05  0:13   ` [PATCH 00/13] bisect: v2.30.0 "run" regressions + make it built-in Taylor Blau
2022-11-10 12:50   ` Johannes Schindelin

Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).