Subject: [PATCH 04/11] config-batch: create 'help' command

From: "Derrick Stolee via GitGitGadget" <[email-masked]>
Date: Wed, 04 Feb 2026 14:19:56 +0000

From: Derrick Stolee <[email-masked]>

Tools that use the 'git config-batch' tool will want to know which commands
are available in the current Git version. Having a 'help' command assists
greatly to give a clear set of available commands and their versions.

Signed-off-by: Derrick Stolee <[email-masked]>
---
 Documentation/git-config-batch.adoc | 17 +++++++++++++++
 builtin/config-batch.c              | 32 +++++++++++++++++++++++++++++
 t/t1312-config-batch.sh             | 13 ++++++++++++
 3 files changed, 62 insertions(+)

diff --git a/Documentation/git-config-batch.adoc b/Documentation/git-config-batch.adoc
index 31dd42f481..1fff68a13c 100644
--- a/Documentation/git-config-batch.adoc
+++ b/Documentation/git-config-batch.adoc
@@ -38,6 +38,23 @@ unknown_command LF
 
 These are the commands that are currently understood:
 
+`help` version 1::
+	The `help` command lists the currently-available commands in
+	this version of Git. The output is multi-line, but the first
+	line provides the count of possible commands via `help count <N>`.
+	The next `<N>` lines are of the form `help <command> <version>`
+	to state that this Git version supports that `<command>` at
+	version `<version>`. Note that the same command may have multiple
+	available versions.
++
+Here is the currentl output of the help text at the latest version:
++
+------------
+help 1 count 2
+help 1 help 1
+help 1 get 1
+------------
+
 `get` version 1::
 	The `get` command searches the config key-value pairs within a
 	given `<scope>` for values that match the fixed `<key>` and
diff --git a/builtin/config-batch.c b/builtin/config-batch.c
index 5782004080..1c19e4889f 100644
--- a/builtin/config-batch.c
+++ b/builtin/config-batch.c
@@ -12,6 +12,7 @@ static const char *const builtin_config_batch_usage[] = {
 };
 
 #define UNKNOWN_COMMAND "unknown_command"
+#define HELP_COMMAND "help"
 #define GET_COMMAND "get"
 #define COMMAND_PARSE_ERROR "command_parse_error"
 
@@ -104,6 +105,9 @@ static size_t parse_token(char **data, size_t *data_len,
 	return parse_whitespace_token(data, data_len, token, err);
 }
 
+static int help_command_1(struct repository *repo,
+			  char *data, size_t data_len);
+
 enum value_match_mode {
 	MATCH_ALL,
 	MATCH_EXACT,
@@ -302,6 +306,11 @@ struct command {
 };
 
 static struct command commands[] = {
+	{
+		.name = HELP_COMMAND,
+		.fn = help_command_1,
+		.version = 1,
+	},
 	{
 		.name = GET_COMMAND,
 		.fn = get_command_1,
@@ -316,6 +325,29 @@ static struct command commands[] = {
 
 #define COMMAND_COUNT ((size_t)(sizeof(commands) / sizeof(*commands)))
 
+static int help_command_1(struct repository *repo UNUSED,
+			  char *data UNUSED, size_t data_len UNUSED)
+{
+	struct strbuf fmt_str = STRBUF_INIT;
+
+	strbuf_addf(&fmt_str, "%"PRIu32, (uint32_t)(COMMAND_COUNT - 1));
+	emit_response(HELP_COMMAND, "1", "count", fmt_str.buf, NULL);
+	strbuf_reset(&fmt_str);
+
+	for (size_t i = 0; i < COMMAND_COUNT; i++) {
+		/* Halt at unknown command. */
+		if (!commands[i].name[0])
+			break;
+
+		strbuf_addf(&fmt_str, "%d", commands[i].version);
+		emit_response(HELP_COMMAND, "1", commands[i].name, fmt_str.buf, NULL);
+		strbuf_reset(&fmt_str);
+	}
+
+	strbuf_release(&fmt_str);
+	return 0;
+}
+
 /**
  * Process a single line from stdin and process the command.
  *
diff --git a/t/t1312-config-batch.sh b/t/t1312-config-batch.sh
index e638b54d13..6b550a0e76 100755
--- a/t/t1312-config-batch.sh
+++ b/t/t1312-config-batch.sh
@@ -23,6 +23,19 @@ test_expect_success 'completely broken input' '
 	test_grep "an unrecoverable error occurred during command execution" err
 '
 
+test_expect_success 'help command' '
+	echo "help 1" >in &&
+
+	cat >expect <<-\EOF &&
+	help 1 count 2
+	help 1 help 1
+	help 1 get 1
+	EOF
+
+	git config-batch >out <in &&
+	test_cmp expect out
+'
+
 test_expect_success 'failed to parse version' '
 	echo "bogus BAD_VERSION line of tokens" >in &&
 	test_must_fail git config-batch 2>err <in &&
-- 
gitgitgadget