* [GSoC RFC PATCH 0/5] repo-info: add new command for retrieving repository info
@ 2025-06-10 15:21 Lucas Seiki Oshiro
  2025-06-10 15:21 ` [GSoC RFC PATCH 1/5] repo-info: declare the repo-info command Lucas Seiki Oshiro
                   ` (17 more replies)
  0 siblings, 18 replies; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-06-10 15:21 UTC (permalink / raw)
  To: git; +Cc: ps, karthik.188, Lucas Seiki Oshiro
Hi!
This is the first RFC for my GSoC project: the new command `repo-info`.
## Motivation
Currently, `git rev-parse` covers a wide range of functionality not directly
related to parsing revisions, as its name says. Over time, many features like
parsing datestrings, options, paths, and others were added to it because
there wasn't a more appropriated command to place them.
This way, many of these features would be better placed in new and dedicated
commands. This kind of movement had other precedents in Git, for example, `git
switch` and `git restore` were created after `git checkout` became too
overloaded.
## Proposal
This patchset introduces a new command `git repo-info`. Its goal is to bring the
functionality of retrieving repository-related information currently returned by
`rev-parse`, displaying them in machine-readable formats (like JSON or plaintext).
Under `rev-parse`, these information is retrieved by using these flags
(described in the section "Options for Files" of `rev-parse`'s documentation):
- `--show-object-format`: the hashing algorithm (i.e. `sha1` or `sha256`)
- `--git-dir`: The Git directory of the repository
- `--git-common-dir`: The common Git directory
- `--show-toplevel`: the top level directory of the repository
- `--show-ref-format`: the reference database format (`files` or `reftable`),
- `--show-superproject-working-tree`: the absolute path of the superproject
- `--is-bare-repository`: whether this is a bare repository
- `--is-shallow-repository` whether this is a shallow repository
## Command design
The retrieved data will be presented as in a JSON format, like this:
~~~
$ git repo-info
{
  "objects": {
    "format": "sha1"
  },
  "references": {
    "format": "files"
  },
  "path": {
    "git-dir": "/git/dir"
    "git-commom-dir": "/git/common-dir",
    "toplevel": "/git/toplevel",
    "superproject-working-tree": "/super/working/tree",
  }
  "layout": {
    "bare": false,
    "shallow": false
  }
}
~~~
Or in a plaintext format, like this:
~~~
$ git repo-info --format=plaintext
sha1
files
/git/dir
/git/common-dir
/git/toplevel
/super/working/tree
false
false
~~~
It will also allow the user to get only the desired fields, like this:
~~~
$ git repo-info --format=plaintext objects.format references.format
sha1
files
~~~
or:
~~~
$ git repo-info objects.format references.format
{
  "objects": {
    "format": "sha1"
  },
  "references": {
    "format": "files"
  }
}
~~~
Currently this RFC only implements "objects.format", "layout.bare" and
"layout.shallow", but I'm making it flexible to add other fields, following
this format.
## Feedback
I would like to ask for your feedback on this proprosal, specially:
- on deciding if the JSON and linewise plaintext formats are the really the best,
  or if I should consider others (e.g. gitconfig syntax, NUL-terminated, etc)
- on deciding how the fields will be specified. This "<category>.<format>" was
  a first idea based on the JSON structure
- about the JSON schema
- about information that may be nice to include in the output of this command,
  even if they are not currently retrieved by `rev-parse`
Thanks!
Lucas Seiki Oshiro (5):
  repo-info: declare the repo-info command
  repo-info: add the --format flag
  repo-info: add the field references.format
  repo-info: add field layout.bare
  repo-info: add field layout.shallow
 .gitignore           |   1 +
 Makefile             |   1 +
 builtin.h            |   1 +
 builtin/repo-info.c  | 233 +++++++++++++++++++++++++++++++++++++++++++
 git.c                |   1 +
 meson.build          |   1 +
 t/meson.build        |   1 +
 t/t1518-repo-info.sh | 123 +++++++++++++++++++++++
 8 files changed, 362 insertions(+)
 create mode 100644 builtin/repo-info.c
 create mode 100755 t/t1518-repo-info.sh
-- 
2.39.5 (Apple Git-154)
^ permalink raw reply	[flat|nested] 226+ messages in thread
* [GSoC RFC PATCH 1/5] repo-info: declare the repo-info command
  2025-06-10 15:21 [GSoC RFC PATCH 0/5] repo-info: add new command for retrieving repository info Lucas Seiki Oshiro
@ 2025-06-10 15:21 ` Lucas Seiki Oshiro
  2025-06-11  8:59   ` Karthik Nayak
  2025-06-10 15:21 ` [GSoC RFC PATCH 2/5] repo-info: add the --format flag Lucas Seiki Oshiro
                   ` (16 subsequent siblings)
  17 siblings, 1 reply; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-06-10 15:21 UTC (permalink / raw)
  To: git; +Cc: ps, karthik.188, Lucas Seiki Oshiro
Create a new Git subcommand called repo-info. `git repo-info` will query
metadata from the current repository and outputs it as JSON or plaintext.
Also add entries for this new command in:
- the build files (Makefile and meson.build)
- builtin.h
- git.c
- .gitignore
Mentored-by: Karthik Nayak <karthik.188@gmail.com>
Mentored-by Patrick Steinhardt <ps@pks.im>
Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
---
 .gitignore          |  1 +
 Makefile            |  1 +
 builtin.h           |  1 +
 builtin/repo-info.c | 22 ++++++++++++++++++++++
 git.c               |  1 +
 meson.build         |  1 +
 6 files changed, 27 insertions(+)
 create mode 100644 builtin/repo-info.c
diff --git a/.gitignore b/.gitignore
index 04c444404e..b2f3fb0047 100644
--- a/.gitignore
+++ b/.gitignore
@@ -139,6 +139,7 @@
 /git-repack
 /git-replace
 /git-replay
+/git-repo-info
 /git-request-pull
 /git-rerere
 /git-reset
diff --git a/Makefile b/Makefile
index 70d1543b6b..50e3a3cbcc 100644
--- a/Makefile
+++ b/Makefile
@@ -1308,6 +1308,7 @@ BUILTIN_OBJS += builtin/remote.o
 BUILTIN_OBJS += builtin/repack.o
 BUILTIN_OBJS += builtin/replace.o
 BUILTIN_OBJS += builtin/replay.o
+BUILTIN_OBJS += builtin/repo-info.o
 BUILTIN_OBJS += builtin/rerere.o
 BUILTIN_OBJS += builtin/reset.o
 BUILTIN_OBJS += builtin/rev-list.o
diff --git a/builtin.h b/builtin.h
index bff13e3069..cc6bc95962 100644
--- a/builtin.h
+++ b/builtin.h
@@ -216,6 +216,7 @@ int cmd_remote_ext(int argc, const char **argv, const char *prefix, struct repos
 int cmd_remote_fd(int argc, const char **argv, const char *prefix, struct repository *repo);
 int cmd_repack(int argc, const char **argv, const char *prefix, struct repository *repo);
 int cmd_replay(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_repo_info(int argc, const char **argv, const char *prefix, struct repository *repo);
 int cmd_rerere(int argc, const char **argv, const char *prefix, struct repository *repo);
 int cmd_reset(int argc, const char **argv, const char *prefix, struct repository *repo);
 int cmd_restore(int argc, const char **argv, const char *prefix, struct repository *repo);
diff --git a/builtin/repo-info.c b/builtin/repo-info.c
new file mode 100644
index 0000000000..4615b988d8
--- /dev/null
+++ b/builtin/repo-info.c
@@ -0,0 +1,22 @@
+#include "builtin.h"
+#include "parse-options.h"
+
+int cmd_repo_info(
+	int argc,
+	const char **argv,
+	const char *prefix,
+	struct repository *repo UNUSED
+	)
+{
+	const char *const repo_info_usage[] = {
+		"git repo-info",
+		NULL
+	};
+	struct option options[] = {
+		OPT_END()
+	};
+
+	argc = parse_options(argc, argv, prefix, options, repo_info_usage, 0);
+
+	return 0;
+}
diff --git a/git.c b/git.c
index 7c37872a88..d1774de82f 100644
--- a/git.c
+++ b/git.c
@@ -611,6 +611,7 @@ static struct cmd_struct commands[] = {
 	{ "repack", cmd_repack, RUN_SETUP },
 	{ "replace", cmd_replace, RUN_SETUP },
 	{ "replay", cmd_replay, RUN_SETUP },
+	{ "repo-info", cmd_repo_info, RUN_SETUP },
 	{ "rerere", cmd_rerere, RUN_SETUP },
 	{ "reset", cmd_reset, RUN_SETUP },
 	{ "restore", cmd_restore, RUN_SETUP | NEED_WORK_TREE },
diff --git a/meson.build b/meson.build
index 7fea4a34d6..06f2f647ba 100644
--- a/meson.build
+++ b/meson.build
@@ -645,6 +645,7 @@ builtin_sources = [
   'builtin/repack.c',
   'builtin/replace.c',
   'builtin/replay.c',
+  'builtin/repo-info.c',
   'builtin/rerere.c',
   'builtin/reset.c',
   'builtin/rev-list.c',
-- 
2.39.5 (Apple Git-154)
^ permalink raw reply related	[flat|nested] 226+ messages in thread
* [GSoC RFC PATCH 2/5] repo-info: add the --format flag
  2025-06-10 15:21 [GSoC RFC PATCH 0/5] repo-info: add new command for retrieving repository info Lucas Seiki Oshiro
  2025-06-10 15:21 ` [GSoC RFC PATCH 1/5] repo-info: declare the repo-info command Lucas Seiki Oshiro
@ 2025-06-10 15:21 ` Lucas Seiki Oshiro
  2025-06-11  9:30   ` Karthik Nayak
  2025-06-10 15:21 ` [GSoC RFC PATCH 3/5] repo-info: add the field references.format Lucas Seiki Oshiro
                   ` (15 subsequent siblings)
  17 siblings, 1 reply; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-06-10 15:21 UTC (permalink / raw)
  To: git; +Cc: ps, karthik.188, Lucas Seiki Oshiro
Add the --format flag to the repo-info command, allowing the user to
choose betwen the 'json' and 'plaintext' formats as output.
Also add a flag --allow-empty, which will force the output data to be
empty when no field is requested.
Mentored-by: Karthik Nayak <karthik.188@gmail.com>
Mentored-by Patrick Steinhardt <ps@pks.im>
Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
---
 builtin/repo-info.c  | 79 ++++++++++++++++++++++++++++++++++++++++++--
 t/meson.build        |  1 +
 t/t1518-repo-info.sh | 49 +++++++++++++++++++++++++++
 3 files changed, 127 insertions(+), 2 deletions(-)
 create mode 100755 t/t1518-repo-info.sh
diff --git a/builtin/repo-info.c b/builtin/repo-info.c
index 4615b988d8..4d539a17fb 100644
--- a/builtin/repo-info.c
+++ b/builtin/repo-info.c
@@ -1,22 +1,97 @@
 #include "builtin.h"
+#include "hash.h"
+#include "json-writer.h"
 #include "parse-options.h"
+#include "refs.h"
+
+enum output_format {
+	FORMAT_PLAINTEXT,
+	FORMAT_JSON
+};
+
+struct repo_info {
+	struct repository *repo;
+	enum output_format format;
+};
+
+static void repo_info_init(struct repo_info *repo_info,
+			   struct repository *repo,
+			   char *format,
+			   int allow_empty UNUSED,
+			   int argc UNUSED,
+			   const char **argv UNUSED
+			   ) {
+	repo_info->repo = repo;
+
+	if (format == NULL || !strcmp(format, "json"))
+		repo_info->format = FORMAT_JSON;
+	else if (!strcmp(format, "plaintext"))
+		repo_info->format = FORMAT_PLAINTEXT;
+	else
+		die("invalid format %s", format);
+}
+
+static void repo_info_print_plaintext(struct repo_info *repo_info UNUSED) {
+}
+
+static void repo_info_print_json(struct repo_info *repo_info UNUSED)
+{
+	struct json_writer jw;
+
+	jw_init(&jw);
+
+	jw_object_begin(&jw, 1);
+	jw_end(&jw);
+
+	puts(jw.json.buf);
+	jw_release(&jw);
+}
+
+static void repo_info_print(struct repo_info *repo_info)
+{
+	enum output_format format = repo_info->format;
+
+	switch (format) {
+	case FORMAT_PLAINTEXT:
+		repo_info_print_plaintext(repo_info);
+		break;
+	case FORMAT_JSON:
+		repo_info_print_json(repo_info);
+		break;
+	}
+}
 
 int cmd_repo_info(
 	int argc,
 	const char **argv,
 	const char *prefix,
-	struct repository *repo UNUSED
+	struct repository *repo
 	)
 {
 	const char *const repo_info_usage[] = {
 		"git repo-info",
 		NULL
 	};
+	struct repo_info repo_info;
+	char *format = NULL;
+	int allow_empty = 0;
 	struct option options[] = {
+		OPT_STRING(0,
+			     "format",
+			     &format,
+			     N_("format"),
+			     N_("output format")),
+		OPT_BOOL(0,
+			 "allow-empty",
+			 &allow_empty,
+			 "when set, it will use an empty set of fields if no field is requested"),
 		OPT_END()
 	};
 
-	argc = parse_options(argc, argv, prefix, options, repo_info_usage, 0);
+	argc = parse_options(argc, argv, prefix, options, repo_info_usage,
+			     PARSE_OPT_KEEP_UNKNOWN_OPT);
+	repo_info_init(&repo_info, repo, format, allow_empty, argc, argv);
+	repo_info_print(&repo_info);
 
 	return 0;
 }
diff --git a/t/meson.build b/t/meson.build
index 50e89e764a..c24e197c60 100644
--- a/t/meson.build
+++ b/t/meson.build
@@ -241,6 +241,7 @@ integration_tests = [
   't1514-rev-parse-push.sh',
   't1515-rev-parse-outside-repo.sh',
   't1517-outside-repo.sh',
+  't1518-repo-info.sh',
   't1600-index.sh',
   't1601-index-bogus.sh',
   't1700-split-index.sh',
diff --git a/t/t1518-repo-info.sh b/t/t1518-repo-info.sh
new file mode 100755
index 0000000000..2e1a6f0c34
--- /dev/null
+++ b/t/t1518-repo-info.sh
@@ -0,0 +1,49 @@
+#!/bin/sh
+
+test_description='test git repo-info'
+GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
+export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+
+. ./test-lib.sh
+
+parse_json () {
+	tr '\n' ' ' | "$PERL_PATH" "$TEST_DIRECTORY/t0019/parse_json.perl"
+}
+
+test_repo_info () {
+	label=$1
+	init_args=$2
+	key=$3
+	expected_value=$4
+
+	test_expect_success "json: $label" "
+		test_when_finished 'rm -rf repo' &&
+		git init $init_args repo &&
+		cd repo &&
+		echo '$expected_value' >expect &&
+		git repo-info '$key'| parse_json >output &&
+		grep -F 'row[0].$key' output | cut -d ' ' -f 2 >actual &&
+		test_cmp expect actual
+	"
+
+	test_expect_success "plaintext: $label" "
+		test_when_finished 'rm -rf repo' &&
+		git init $init_args repo &&
+		cd repo &&
+		echo '$expected_value' >expect &&
+		git repo-info --format=plaintext '$key' >actual &&
+		test_cmp expect actual
+	"
+}
+
+test_expect_success 'json: returns empty output with allow-empty' '
+	git repo-info --allow-empty --format=json >output &&
+	test_line_count = 2 output
+'
+
+test_expect_success 'plaintext: returns empty output with allow-empty' '
+	git repo-info --allow-empty --format=plaintext >output &&
+	test_line_count = 0 output
+'
+
+test_done
-- 
2.39.5 (Apple Git-154)
^ permalink raw reply related	[flat|nested] 226+ messages in thread
* [GSoC RFC PATCH 3/5] repo-info: add the field references.format
  2025-06-10 15:21 [GSoC RFC PATCH 0/5] repo-info: add new command for retrieving repository info Lucas Seiki Oshiro
  2025-06-10 15:21 ` [GSoC RFC PATCH 1/5] repo-info: declare the repo-info command Lucas Seiki Oshiro
  2025-06-10 15:21 ` [GSoC RFC PATCH 2/5] repo-info: add the --format flag Lucas Seiki Oshiro
@ 2025-06-10 15:21 ` Lucas Seiki Oshiro
  2025-06-11 12:59   ` Karthik Nayak
  2025-06-10 15:21 ` [GSoC RFC PATCH 4/5] repo-info: add field layout.bare Lucas Seiki Oshiro
                   ` (14 subsequent siblings)
  17 siblings, 1 reply; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-06-10 15:21 UTC (permalink / raw)
  To: git; +Cc: ps, karthik.188, Lucas Seiki Oshiro
Add the field references.format to the repo-info command. The data
retrieved in this field is the same that currently is obtained by
running `git rev-parse --show-ref-format`.
Mentored-by: Karthik Nayak <karthik.188@gmail.com>
Mentored-by Patrick Steinhardt <ps@pks.im>
Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
---
 builtin/repo-info.c  | 97 +++++++++++++++++++++++++++++++++++++++++---
 t/t1518-repo-info.sh | 20 +++++++++
 2 files changed, 112 insertions(+), 5 deletions(-)
diff --git a/builtin/repo-info.c b/builtin/repo-info.c
index 4d539a17fb..a1c9d3942e 100644
--- a/builtin/repo-info.c
+++ b/builtin/repo-info.c
@@ -9,18 +9,40 @@ enum output_format {
 	FORMAT_JSON
 };
 
+enum repo_info_category {
+	CATEGORY_REFERENCES = 1
+};
+
+enum repo_info_references_field {
+	FIELD_REFERENCES_FORMAT = 1
+};
+
+struct repo_info_field {
+	enum repo_info_category category;
+	union {
+		enum repo_info_references_field references;
+	} field;
+};
+
 struct repo_info {
 	struct repository *repo;
 	enum output_format format;
+	int n_fields;
+	struct repo_info_field *fields;
+};
+
+const char *default_fields[] = {
+	"references.format",
 };
 
 static void repo_info_init(struct repo_info *repo_info,
 			   struct repository *repo,
 			   char *format,
-			   int allow_empty UNUSED,
-			   int argc UNUSED,
-			   const char **argv UNUSED
+			   int allow_empty,
+			   int argc,
+			   const char **argv
 			   ) {
+	int i;
 	repo_info->repo = repo;
 
 	if (format == NULL || !strcmp(format, "json"))
@@ -29,18 +51,82 @@ static void repo_info_init(struct repo_info *repo_info,
 		repo_info->format = FORMAT_PLAINTEXT;
 	else
 		die("invalid format %s", format);
+
+	if (argc == 0 && !allow_empty) {
+		argc = ARRAY_SIZE(default_fields);
+		argv = default_fields;
+	}
+
+	repo_info->n_fields = argc;
+	repo_info->fields = xmalloc(argc * sizeof(struct repo_info_field));
+
+	for (i = 0; i < argc; i++) {
+		const char *arg = argv[i];
+		struct repo_info_field *field = repo_info->fields + i;
+
+		if (!strcmp(arg, "references.format")) {
+			field->category = CATEGORY_REFERENCES;
+			field->field.references = FIELD_REFERENCES_FORMAT;
+		}
+		else {
+			die("invalid field '%s'", arg);
+		}
+	}
+}
+
+static void repo_info_release(struct repo_info *repo_info) {
+	free(repo_info->fields);
 }
 
-static void repo_info_print_plaintext(struct repo_info *repo_info UNUSED) {
+static void repo_info_print_plaintext(struct repo_info *repo_info) {
+	struct repository *repo = repo_info->repo;
+	int i;
+	for (i = 0; i < repo_info->n_fields; i++) {
+		struct repo_info_field *field = &repo_info->fields[i];
+		switch (field->category) {
+		case CATEGORY_REFERENCES:
+			switch (field->field.references) {
+			case FIELD_REFERENCES_FORMAT:
+				puts(ref_storage_format_to_name(
+					repo->ref_storage_format));
+				break;
+			}
+			break;
+		}
+	}
 }
 
-static void repo_info_print_json(struct repo_info *repo_info UNUSED)
+static void repo_info_print_json(struct repo_info *repo_info)
 {
 	struct json_writer jw;
+	int i;
+	unsigned int categories = 0;
+	unsigned int references_fields = 0;
+	struct repository *repo = repo_info->repo;
+
+	for (i = 0; i < repo_info->n_fields; i++) {
+		struct repo_info_field *field = repo_info->fields + i;
+		categories |= field->category;
+		switch (field->category) {
+		case CATEGORY_REFERENCES:
+			references_fields |= field->field.references;
+			break;
+		}
+	}
 
 	jw_init(&jw);
 
 	jw_object_begin(&jw, 1);
+
+	if (categories & CATEGORY_REFERENCES) {
+		jw_object_inline_begin_object(&jw, "references");
+		if (references_fields & FIELD_REFERENCES_FORMAT) {
+			const char *format_name = ref_storage_format_to_name(
+				repo->ref_storage_format);
+			jw_object_string(&jw, "format", format_name);
+		}
+		jw_end(&jw);
+	}
 	jw_end(&jw);
 
 	puts(jw.json.buf);
@@ -92,6 +178,7 @@ int cmd_repo_info(
 			     PARSE_OPT_KEEP_UNKNOWN_OPT);
 	repo_info_init(&repo_info, repo, format, allow_empty, argc, argv);
 	repo_info_print(&repo_info);
+	repo_info_release(&repo_info);
 
 	return 0;
 }
diff --git a/t/t1518-repo-info.sh b/t/t1518-repo-info.sh
index 2e1a6f0c34..a99198b0f6 100755
--- a/t/t1518-repo-info.sh
+++ b/t/t1518-repo-info.sh
@@ -6,6 +6,8 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
 . ./test-lib.sh
 
+DEFAULT_NUMBER_OF_FIELDS=1
+
 parse_json () {
 	tr '\n' ' ' | "$PERL_PATH" "$TEST_DIRECTORY/t0019/parse_json.perl"
 }
@@ -46,4 +48,22 @@ test_expect_success 'plaintext: returns empty output with allow-empty' '
 	test_line_count = 0 output
 '
 
+test_repo_info 'ref format files is retrieved correctly' \
+	'' \
+	'references.format' 'files'
+
+test_repo_info 'ref format reftable is retrieved correctly' \
+	'--ref-format=reftable' \
+	'references.format' 'reftable'
+
+test_expect_success 'plaintext: output all default fields' "
+	git repo-info --format=plaintext >actual &&
+	test_line_count = $DEFAULT_NUMBER_OF_FIELDS actual
+"
+
+test_expect_success 'json: output all default fields' "
+	git repo-info --format=json | parse_json | grep '.*\..*\..*' >actual &&
+	test_line_count = $DEFAULT_NUMBER_OF_FIELDS actual
+"
+
 test_done
-- 
2.39.5 (Apple Git-154)
^ permalink raw reply related	[flat|nested] 226+ messages in thread
* [GSoC RFC PATCH 4/5] repo-info: add field layout.bare
  2025-06-10 15:21 [GSoC RFC PATCH 0/5] repo-info: add new command for retrieving repository info Lucas Seiki Oshiro
                   ` (2 preceding siblings ...)
  2025-06-10 15:21 ` [GSoC RFC PATCH 3/5] repo-info: add the field references.format Lucas Seiki Oshiro
@ 2025-06-10 15:21 ` Lucas Seiki Oshiro
  2025-06-11 13:13   ` Karthik Nayak
  2025-06-10 15:21 ` [GSoC RFC PATCH 5/5] repo-info: add field layout.shallow Lucas Seiki Oshiro
                   ` (13 subsequent siblings)
  17 siblings, 1 reply; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-06-10 15:21 UTC (permalink / raw)
  To: git; +Cc: ps, karthik.188, Lucas Seiki Oshiro
Add the field layout.bare to the repo-info command. The data
retrieved in this field is the same that currently is obtained by
running `git rev-parse --is-bare-repository`.
Mentored-by: Karthik Nayak <karthik.188@gmail.com>
Mentored-by Patrick Steinhardt <ps@pks.im>
Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
---
 builtin/repo-info.c  | 35 ++++++++++++++++++++++++++++++++++-
 t/t1518-repo-info.sh | 12 ++++++++++--
 2 files changed, 44 insertions(+), 3 deletions(-)
diff --git a/builtin/repo-info.c b/builtin/repo-info.c
index a1c9d3942e..bc25a0809f 100644
--- a/builtin/repo-info.c
+++ b/builtin/repo-info.c
@@ -1,4 +1,7 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
 #include "builtin.h"
+#include "environment.h"
 #include "hash.h"
 #include "json-writer.h"
 #include "parse-options.h"
@@ -10,17 +13,22 @@ enum output_format {
 };
 
 enum repo_info_category {
-	CATEGORY_REFERENCES = 1
+	CATEGORY_REFERENCES = 1,
+	CATEGORY_LAYOUT = 1 << 1
 };
 
 enum repo_info_references_field {
 	FIELD_REFERENCES_FORMAT = 1
 };
 
+enum repo_info_layout_field { FIELD_LAYOUT_BARE = 1
+};
+
 struct repo_info_field {
 	enum repo_info_category category;
 	union {
 		enum repo_info_references_field references;
+		enum repo_info_layout_field layout;
 	} field;
 };
 
@@ -33,6 +41,7 @@ struct repo_info {
 
 const char *default_fields[] = {
 	"references.format",
+	"layout.bare"
 };
 
 static void repo_info_init(struct repo_info *repo_info,
@@ -68,6 +77,10 @@ static void repo_info_init(struct repo_info *repo_info,
 			field->category = CATEGORY_REFERENCES;
 			field->field.references = FIELD_REFERENCES_FORMAT;
 		}
+		else if (!strcmp(arg, "layout.bare")) {
+			field->category = CATEGORY_LAYOUT;
+			field->field.layout = FIELD_LAYOUT_BARE;
+		}
 		else {
 			die("invalid field '%s'", arg);
 		}
@@ -92,6 +105,13 @@ static void repo_info_print_plaintext(struct repo_info *repo_info) {
 				break;
 			}
 			break;
+		case CATEGORY_LAYOUT:
+			switch (field->field.layout) {
+			case FIELD_LAYOUT_BARE:
+				puts(is_bare_repository() ? "true" : "false");
+				break;
+			}
+			break;
 		}
 	}
 }
@@ -102,6 +122,7 @@ static void repo_info_print_json(struct repo_info *repo_info)
 	int i;
 	unsigned int categories = 0;
 	unsigned int references_fields = 0;
+	unsigned int layout_fields = 0;
 	struct repository *repo = repo_info->repo;
 
 	for (i = 0; i < repo_info->n_fields; i++) {
@@ -111,6 +132,9 @@ static void repo_info_print_json(struct repo_info *repo_info)
 		case CATEGORY_REFERENCES:
 			references_fields |= field->field.references;
 			break;
+		case CATEGORY_LAYOUT:
+			layout_fields |= field->field.layout;
+			break;
 		}
 	}
 
@@ -127,6 +151,15 @@ static void repo_info_print_json(struct repo_info *repo_info)
 		}
 		jw_end(&jw);
 	}
+
+	if (categories & CATEGORY_LAYOUT) {
+		jw_object_inline_begin_object(&jw, "layout");
+		if (layout_fields & FIELD_LAYOUT_BARE) {
+			jw_object_bool(&jw, "bare",
+				       is_bare_repository());
+		}
+		jw_end(&jw);
+	}
 	jw_end(&jw);
 
 	puts(jw.json.buf);
diff --git a/t/t1518-repo-info.sh b/t/t1518-repo-info.sh
index a99198b0f6..1831b74551 100755
--- a/t/t1518-repo-info.sh
+++ b/t/t1518-repo-info.sh
@@ -6,7 +6,7 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
 . ./test-lib.sh
 
-DEFAULT_NUMBER_OF_FIELDS=1
+DEFAULT_NUMBER_OF_FIELDS=2
 
 parse_json () {
 	tr '\n' ' ' | "$PERL_PATH" "$TEST_DIRECTORY/t0019/parse_json.perl"
@@ -22,7 +22,7 @@ test_repo_info () {
 		test_when_finished 'rm -rf repo' &&
 		git init $init_args repo &&
 		cd repo &&
-		echo '$expected_value' >expect &&
+		echo '$expected_value' | sed 's/^false$/0/' | sed 's/^true$/1/' >expect &&
 		git repo-info '$key'| parse_json >output &&
 		grep -F 'row[0].$key' output | cut -d ' ' -f 2 >actual &&
 		test_cmp expect actual
@@ -56,6 +56,14 @@ test_repo_info 'ref format reftable is retrieved correctly' \
 	'--ref-format=reftable' \
 	'references.format' 'reftable'
 
+test_repo_info 'bare repository = false is retrieved correctly' \
+	'' \
+	'layout.bare' 'false'
+
+test_repo_info 'bare repository = true is retrieved correctly' \
+	'--bare' \
+	'layout.bare' 'true'
+
 test_expect_success 'plaintext: output all default fields' "
 	git repo-info --format=plaintext >actual &&
 	test_line_count = $DEFAULT_NUMBER_OF_FIELDS actual
-- 
2.39.5 (Apple Git-154)
^ permalink raw reply related	[flat|nested] 226+ messages in thread
* [GSoC RFC PATCH 5/5] repo-info: add field layout.shallow
  2025-06-10 15:21 [GSoC RFC PATCH 0/5] repo-info: add new command for retrieving repository info Lucas Seiki Oshiro
                   ` (3 preceding siblings ...)
  2025-06-10 15:21 ` [GSoC RFC PATCH 4/5] repo-info: add field layout.bare Lucas Seiki Oshiro
@ 2025-06-10 15:21 ` Lucas Seiki Oshiro
  2025-06-10 16:39 ` [GSoC RFC PATCH 0/5] repo-info: add new command for retrieving repository info Kristoffer Haugsbakk
                   ` (12 subsequent siblings)
  17 siblings, 0 replies; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-06-10 15:21 UTC (permalink / raw)
  To: git; +Cc: ps, karthik.188, Lucas Seiki Oshiro
Add the field layout.shallow to the repo-info command. The data
retrieved in this field is the same that currently is obtained by
running `git rev-parse --is-shallow-repository`.
Mentored-by: Karthik Nayak <karthik.188@gmail.com>
Mentored-by Patrick Steinhardt <ps@pks.im>
Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
---
 builtin/repo-info.c  | 20 ++++++++++++++++--
 t/t1518-repo-info.sh | 48 +++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 65 insertions(+), 3 deletions(-)
diff --git a/builtin/repo-info.c b/builtin/repo-info.c
index bc25a0809f..d821292d78 100644
--- a/builtin/repo-info.c
+++ b/builtin/repo-info.c
@@ -6,6 +6,7 @@
 #include "json-writer.h"
 #include "parse-options.h"
 #include "refs.h"
+#include "shallow.h"
 
 enum output_format {
 	FORMAT_PLAINTEXT,
@@ -21,7 +22,9 @@ enum repo_info_references_field {
 	FIELD_REFERENCES_FORMAT = 1
 };
 
-enum repo_info_layout_field { FIELD_LAYOUT_BARE = 1
+enum repo_info_layout_field {
+	FIELD_LAYOUT_BARE = 1,
+	FIELD_LAYOUT_SHALLOW = 1 << 1
 };
 
 struct repo_info_field {
@@ -41,7 +44,8 @@ struct repo_info {
 
 const char *default_fields[] = {
 	"references.format",
-	"layout.bare"
+	"layout.bare",
+	"layout.shallow"
 };
 
 static void repo_info_init(struct repo_info *repo_info,
@@ -81,6 +85,10 @@ static void repo_info_init(struct repo_info *repo_info,
 			field->category = CATEGORY_LAYOUT;
 			field->field.layout = FIELD_LAYOUT_BARE;
 		}
+		else if (!strcmp(arg, "layout.shallow")) {
+			field->category = CATEGORY_LAYOUT;
+			field->field.layout = FIELD_LAYOUT_SHALLOW;
+		}
 		else {
 			die("invalid field '%s'", arg);
 		}
@@ -110,6 +118,9 @@ static void repo_info_print_plaintext(struct repo_info *repo_info) {
 			case FIELD_LAYOUT_BARE:
 				puts(is_bare_repository() ? "true" : "false");
 				break;
+			case FIELD_LAYOUT_SHALLOW:
+				puts(is_repository_shallow(repo) ? "true" : "false");
+				break;
 			}
 			break;
 		}
@@ -158,6 +169,11 @@ static void repo_info_print_json(struct repo_info *repo_info)
 			jw_object_bool(&jw, "bare",
 				       is_bare_repository());
 		}
+
+		if (layout_fields & FIELD_LAYOUT_SHALLOW) {
+			jw_object_bool(&jw, "shallow",
+				       is_repository_shallow(repo));
+		}
 		jw_end(&jw);
 	}
 	jw_end(&jw);
diff --git a/t/t1518-repo-info.sh b/t/t1518-repo-info.sh
index 1831b74551..10de93219b 100755
--- a/t/t1518-repo-info.sh
+++ b/t/t1518-repo-info.sh
@@ -6,7 +6,7 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
 . ./test-lib.sh
 
-DEFAULT_NUMBER_OF_FIELDS=2
+DEFAULT_NUMBER_OF_FIELDS=3
 
 parse_json () {
 	tr '\n' ' ' | "$PERL_PATH" "$TEST_DIRECTORY/t0019/parse_json.perl"
@@ -64,6 +64,51 @@ test_repo_info 'bare repository = true is retrieved correctly' \
 	'--bare' \
 	'layout.bare' 'true'
 
+test_repo_info 'shallow repository = false is retrieved correctly' \
+	'' \
+	'layout.shallow' 'false'
+
+test_expect_success 'json: shallow repository = true is retrieved correctly' '
+	test_when_finished "rm -rf repo" &&
+	git init repo &&
+	cd repo &&
+	echo x >x &&
+	git add x &&
+	git commit -m x &&
+	git clone --depth 1 "file://$PWD" cloned &&
+	cd cloned &&
+	echo 1 >expect &&
+	git repo-info "layout.shallow" | parse_json >output &&
+	grep -F "row[0].layout.shallow" output | cut -d " " -f 2 >actual &&
+	cat actual > /dev/ttys001 &&
+	test_cmp expect actual
+'
+
+test_expect_success 'plaintext: shallow repository = true is retrieved correctly' '
+	test_when_finished "rm -rf repo" &&
+	git init repo &&
+	cd repo &&
+	echo x >x &&
+	git add x &&
+	git commit -m x &&
+	test_commit "commit" &&
+	git clone --depth=1 "file://$PWD" cloned &&
+	cd cloned &&
+       	echo true >expect &&
+       	git repo-info --format=plaintext "layout.shallow" >actual &&
+       	test_cmp expect actual
+'
+
+test_expect_success 'plaintext: output all default fields' "
+	git repo-info --format=plaintext >actual &&
+	test_line_count = $DEFAULT_NUMBER_OF_FIELDS actual
+"
+
+test_expect_success 'json: output all default fields' "
+	git repo-info --format=json | parse_json | grep '.*\..*\..*' >actual &&
+	test_line_count = $DEFAULT_NUMBER_OF_FIELDS actual
+"
+
 test_expect_success 'plaintext: output all default fields' "
 	git repo-info --format=plaintext >actual &&
 	test_line_count = $DEFAULT_NUMBER_OF_FIELDS actual
@@ -74,4 +119,5 @@ test_expect_success 'json: output all default fields' "
 	test_line_count = $DEFAULT_NUMBER_OF_FIELDS actual
 "
 
+
 test_done
-- 
2.39.5 (Apple Git-154)
^ permalink raw reply related	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH 0/5] repo-info: add new command for retrieving repository info
  2025-06-10 15:21 [GSoC RFC PATCH 0/5] repo-info: add new command for retrieving repository info Lucas Seiki Oshiro
                   ` (4 preceding siblings ...)
  2025-06-10 15:21 ` [GSoC RFC PATCH 5/5] repo-info: add field layout.shallow Lucas Seiki Oshiro
@ 2025-06-10 16:39 ` Kristoffer Haugsbakk
  2025-06-10 16:40 ` Junio C Hamano
                   ` (11 subsequent siblings)
  17 siblings, 0 replies; 226+ messages in thread
From: Kristoffer Haugsbakk @ 2025-06-10 16:39 UTC (permalink / raw)
  To: Lucas Seiki Oshiro, git; +Cc: Patrick Steinhardt, Karthik Nayak
On Tue, Jun 10, 2025, at 17:21, Lucas Seiki Oshiro wrote:
> ## Motivation
>
> Currently, `git rev-parse` covers a wide range of functionality not directly
> related to parsing revisions, as its name says. Over time, many features like
> parsing datestrings, options, paths, and others were added to it because
> there wasn't a more appropriated command to place them.
>
> This way, many of these features would be better placed in new and dedicated
> commands. This kind of movement had other precedents in Git, for example, `git
> switch` and `git restore` were created after `git checkout` became too
> overloaded.
This is something I’ve wanted.  Thanks for starting the work.
-- 
Kristoffer Haugsbakk
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH 0/5] repo-info: add new command for retrieving repository info
  2025-06-10 15:21 [GSoC RFC PATCH 0/5] repo-info: add new command for retrieving repository info Lucas Seiki Oshiro
                   ` (5 preceding siblings ...)
  2025-06-10 16:39 ` [GSoC RFC PATCH 0/5] repo-info: add new command for retrieving repository info Kristoffer Haugsbakk
@ 2025-06-10 16:40 ` Junio C Hamano
  2025-06-12 20:25   ` Lucas Seiki Oshiro
  2025-06-11 13:17 ` Karthik Nayak
                   ` (10 subsequent siblings)
  17 siblings, 1 reply; 226+ messages in thread
From: Junio C Hamano @ 2025-06-10 16:40 UTC (permalink / raw)
  To: Lucas Seiki Oshiro; +Cc: git, ps, karthik.188
Lucas Seiki Oshiro <lucasseikioshiro@gmail.com> writes:
> $ git repo-info
> {
>   "objects": {
>     "format": "sha1"
>   },
>   "references": {
>     "format": "files"
>   },
>   "path": {
>     "git-dir": "/git/dir"
>     "git-commom-dir": "/git/common-dir",
>     "toplevel": "/git/toplevel",
>     "superproject-working-tree": "/super/working/tree",
>   }
>   "layout": {
>     "bare": false,
>     "shallow": false
>   }
> }
> ~~~
OK, that's understandable, other than that handling of trailing
commas looks somewhat inconsistent.
> Or in a plaintext format, like this:
>
> ~~~
> $ git repo-info --format=plaintext
> sha1
> files
> /git/dir
> /git/common-dir
> /git/toplevel
> /super/working/tree
> false
> false
> ~~~
This one is a bit questionable.
Is it safe to assume that we will never have to deal with payload
controllable by the end-user that can have arbitrary byte values?
It would be uncommon but possible for LF to be in one of these
pathnames, breaking one-line-per-item assumption you seem to be
making.  If one-line-per-item can be assumed, you can certainly
claim that this format is easy for consumers to handle, but the fact
is that this format is cumbersome to use safely if we have to deal
with end-user controllable arbitrary byte sequences, and if the set
of info pieces the repo-info needs to deal with changes over time.
> It will also allow the user to get only the desired fields, like this:
>
> ~~~
> $ git repo-info --format=plaintext objects.format references.format
> sha1
> files
> ~~~
If the user asked for only one item, this is probably OK, but for
more than one items, the same comment applies as above (except that
the number of and order of info pieces are known in this case).
> or:
>
> ~~~
> $ git repo-info objects.format references.format
> {
>   "objects": {
>     "format": "sha1"
>   },
>   "references": {
>     "format": "files"
>   }
> }
> ~~~
This one is OK.
> - on deciding if the JSON and linewise plaintext formats are the really the best,
>   or if I should consider others (e.g. gitconfig syntax, NUL-terminated, etc)
"git config list" and "git config get" may be weaker in handling
arbitrary bytes than we would wish them to be.  As much as I loath
JSON, the format is widely recognised and supported, so as the
initial cut, it may be sufficient to nail down the schema first and
then worry about emitting the same information in other formats
later.
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH 1/5] repo-info: declare the repo-info command
  2025-06-10 15:21 ` [GSoC RFC PATCH 1/5] repo-info: declare the repo-info command Lucas Seiki Oshiro
@ 2025-06-11  8:59   ` Karthik Nayak
  0 siblings, 0 replies; 226+ messages in thread
From: Karthik Nayak @ 2025-06-11  8:59 UTC (permalink / raw)
  To: Lucas Seiki Oshiro, git; +Cc: ps
[-- Attachment #1: Type: text/plain, Size: 446 bytes --]
Lucas Seiki Oshiro <lucasseikioshiro@gmail.com> writes:
> Create a new Git subcommand called repo-info. `git repo-info` will query
> metadata from the current repository and outputs it as JSON or plaintext.
>
> Also add entries for this new command in:
>
> - the build files (Makefile and meson.build)
> - builtin.h
> - git.c
> - .gitignore
>
We should also add documentation for this new command in
'Documentation/git-repo-info.adoc'.
[snip]
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 690 bytes --]
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH 2/5] repo-info: add the --format flag
  2025-06-10 15:21 ` [GSoC RFC PATCH 2/5] repo-info: add the --format flag Lucas Seiki Oshiro
@ 2025-06-11  9:30   ` Karthik Nayak
  2025-06-12 17:56     ` Lucas Seiki Oshiro
  0 siblings, 1 reply; 226+ messages in thread
From: Karthik Nayak @ 2025-06-11  9:30 UTC (permalink / raw)
  To: Lucas Seiki Oshiro, git; +Cc: ps
[-- Attachment #1: Type: text/plain, Size: 6741 bytes --]
Lucas Seiki Oshiro <lucasseikioshiro@gmail.com> writes:
> Add the --format flag to the repo-info command, allowing the user to
> choose betwen the 'json' and 'plaintext' formats as output.
>
s/betwen/between
> Also add a flag --allow-empty, which will force the output data to be
> empty when no field is requested.
>
Why do you suppose we need this, I'm not against it, but it would be
nice to state why this is necessary. The idea is to have a default
output when a user runs `git repo-info`, so I'm missing why this would
be useful.
> Mentored-by: Karthik Nayak <karthik.188@gmail.com>
> Mentored-by Patrick Steinhardt <ps@pks.im>
> Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
> ---
>  builtin/repo-info.c  | 79 ++++++++++++++++++++++++++++++++++++++++++--
>  t/meson.build        |  1 +
>  t/t1518-repo-info.sh | 49 +++++++++++++++++++++++++++
>  3 files changed, 127 insertions(+), 2 deletions(-)
>  create mode 100755 t/t1518-repo-info.sh
>
> diff --git a/builtin/repo-info.c b/builtin/repo-info.c
> index 4615b988d8..4d539a17fb 100644
> --- a/builtin/repo-info.c
> +++ b/builtin/repo-info.c
> @@ -1,22 +1,97 @@
>  #include "builtin.h"
> +#include "hash.h"
This header doesn't seem to be required for compiling this patch.
> +#include "json-writer.h"
>  #include "parse-options.h"
> +#include "refs.h"
Similar, this header too doesn't seem to be required.
> +
> +enum output_format {
> +	FORMAT_PLAINTEXT,
> +	FORMAT_JSON
> +};
> +
> +struct repo_info {
> +	struct repository *repo;
> +	enum output_format format;
> +};
> +
> +static void repo_info_init(struct repo_info *repo_info,
> +			   struct repository *repo,
> +			   char *format,
> +			   int allow_empty UNUSED,
So allow_empty isn't even used in this patch, let's separate it out to a
patch of itself then.
> +			   int argc UNUSED,
> +			   const char **argv UNUSED
> +			   ) {
> +	repo_info->repo = repo;
> +
> +	if (format == NULL || !strcmp(format, "json"))
> +		repo_info->format = FORMAT_JSON;
> +	else if (!strcmp(format, "plaintext"))
> +		repo_info->format = FORMAT_PLAINTEXT;
> +	else
> +		die("invalid format %s", format);
> +}
> +
> +static void repo_info_print_plaintext(struct repo_info *repo_info UNUSED) {
> +}
Since we don't implement this in this patch, perhaps we can only
introduce the json formatting in this patch? That also allows us to
completely skip the 'plaintext' formatting for now and implement it in
the future.
> +static void repo_info_print_json(struct repo_info *repo_info UNUSED)
> +{
> +	struct json_writer jw;
> +
> +	jw_init(&jw);
> +
> +	jw_object_begin(&jw, 1);
> +	jw_end(&jw);
> +
> +	puts(jw.json.buf);
> +	jw_release(&jw);
> +}
> +
> +static void repo_info_print(struct repo_info *repo_info)
> +{
> +	enum output_format format = repo_info->format;
> +
> +	switch (format) {
> +	case FORMAT_PLAINTEXT:
> +		repo_info_print_plaintext(repo_info);
> +		break;
> +	case FORMAT_JSON:
> +		repo_info_print_json(repo_info);
> +		break;
> +	}
> +}
>
>  int cmd_repo_info(
>  	int argc,
>  	const char **argv,
>  	const char *prefix,
> -	struct repository *repo UNUSED
> +	struct repository *repo
>  	)
>  {
>  	const char *const repo_info_usage[] = {
>  		"git repo-info",
>  		NULL
>  	};
> +	struct repo_info repo_info;
> +	char *format = NULL;
> +	int allow_empty = 0;
>  	struct option options[] = {
> +		OPT_STRING(0,
> +			     "format",
> +			     &format,
> +			     N_("format"),
> +			     N_("output format")),
> +		OPT_BOOL(0,
> +			 "allow-empty",
> +			 &allow_empty,
> +			 "when set, it will use an empty set of fields if no field is requested"),
>  		OPT_END()
>  	};
>
> -	argc = parse_options(argc, argv, prefix, options, repo_info_usage, 0);
> +	argc = parse_options(argc, argv, prefix, options, repo_info_usage,
> +			     PARSE_OPT_KEEP_UNKNOWN_OPT);
I think I understand why we use 'PARSE_OPT_KEEP_UNKNOWN_OPT', this is to
allow users to provide custom fields to print. But this doesn't seem to
be mentioned in the commit message or used in this patch, could we do
either?
[snip]
> diff --git a/t/t1518-repo-info.sh b/t/t1518-repo-info.sh
> new file mode 100755
> index 0000000000..2e1a6f0c34
> --- /dev/null
> +++ b/t/t1518-repo-info.sh
> @@ -0,0 +1,49 @@
> +#!/bin/sh
> +
> +test_description='test git repo-info'
> +GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
> +export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
> +
> +. ./test-lib.sh
> +
> +parse_json () {
> +	tr '\n' ' ' | "$PERL_PATH" "$TEST_DIRECTORY/t0019/parse_json.perl"
> +}
> +
If I recall correctly, in our previous internal review, it was mentioned
that since we use perl here, we should add a PERL pre-requisite. Similar
to the one in 't/t0019-json-writer.sh'.
> +test_repo_info () {
Nit: would be nice to have some documentation on this function,
regarding:
1. Its purpose and use case
2. The fields and what they mean
You can take some hints from 'test_migration' in
't/t1460-refs-migrate.sh'.
> +	label=$1
> +	init_args=$2
> +	key=$3
> +	expected_value=$4
> +
> +	test_expect_success "json: $label" "
> +		test_when_finished 'rm -rf repo' &&
> +		git init $init_args repo &&
> +		cd repo &&
> +		echo '$expected_value' >expect &&
> +		git repo-info '$key'| parse_json >output &&
> +		grep -F 'row[0].$key' output | cut -d ' ' -f 2 >actual &&
> +		test_cmp expect actual
> +	"
> +
> +	test_expect_success "plaintext: $label" "
> +		test_when_finished 'rm -rf repo' &&
> +		git init $init_args repo &&
> +		cd repo &&
> +		echo '$expected_value' >expect &&
> +		git repo-info --format=plaintext '$key' >actual &&
> +		test_cmp expect actual
> +	"
> +}
> +
> +test_expect_success 'json: returns empty output with allow-empty' '
> +	git repo-info --allow-empty --format=json >output &&
> +	test_line_count = 2 output
> +'
> +
As of this patch,
  $ ~/code/git/build/bin-wrappers/git repo-info
  {
  }
  $ ~/code/git/build/bin-wrappers/git repo-info --allow-empty
  {
  }
So what differentiates the former from the latter?
> +test_expect_success 'plaintext: returns empty output with allow-empty' '
> +	git repo-info --allow-empty --format=plaintext >output &&
> +	test_line_count = 0 output
> +'
>
This is because we didn't implement plainttext no?
> +
> +test_done
> --
> 2.39.5 (Apple Git-154)
Overall, I think the changes here make sense to me. But the commit
can be broken up and divided into individual bits:
1. Commit to introduce the --format=json flag
2. Commit to introduce the --format=plaintext flag (can be done later as
   needed)
3. Commit to add '--allow-empty' flag (is this needed?).
This way the tests and code can also be split as per these commits, this
would make reviews much easier since the current patch has some dead
code which presumably will be used in upcoming patches.
- Karthik
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 690 bytes --]
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH 3/5] repo-info: add the field references.format
  2025-06-10 15:21 ` [GSoC RFC PATCH 3/5] repo-info: add the field references.format Lucas Seiki Oshiro
@ 2025-06-11 12:59   ` Karthik Nayak
  2025-06-12 15:01     ` Junio C Hamano
  0 siblings, 1 reply; 226+ messages in thread
From: Karthik Nayak @ 2025-06-11 12:59 UTC (permalink / raw)
  To: Lucas Seiki Oshiro, git; +Cc: ps
[-- Attachment #1: Type: text/plain, Size: 8118 bytes --]
Lucas Seiki Oshiro <lucasseikioshiro@gmail.com> writes:
> Add the field references.format to the repo-info command. The data
> retrieved in this field is the same that currently is obtained by
> running `git rev-parse --show-ref-format`.
>
> Mentored-by: Karthik Nayak <karthik.188@gmail.com>
> Mentored-by Patrick Steinhardt <ps@pks.im>
> Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
> ---
>  builtin/repo-info.c  | 97 +++++++++++++++++++++++++++++++++++++++++---
>  t/t1518-repo-info.sh | 20 +++++++++
>  2 files changed, 112 insertions(+), 5 deletions(-)
>
> diff --git a/builtin/repo-info.c b/builtin/repo-info.c
> index 4d539a17fb..a1c9d3942e 100644
> --- a/builtin/repo-info.c
> +++ b/builtin/repo-info.c
> @@ -9,18 +9,40 @@ enum output_format {
>  	FORMAT_JSON
>  };
>
> +enum repo_info_category {
> +	CATEGORY_REFERENCES = 1
> +};
> +
> +enum repo_info_references_field {
> +	FIELD_REFERENCES_FORMAT = 1
> +};
> +
> +struct repo_info_field {
> +	enum repo_info_category category;
> +	union {
> +		enum repo_info_references_field references;
> +	} field;
> +};
> +
>  struct repo_info {
>  	struct repository *repo;
>  	enum output_format format;
> +	int n_fields;
> +	struct repo_info_field *fields;
> +};
> +
> +const char *default_fields[] = {
> +	"references.format",
>  };
>
>  static void repo_info_init(struct repo_info *repo_info,
>  			   struct repository *repo,
>  			   char *format,
> -			   int allow_empty UNUSED,
> -			   int argc UNUSED,
> -			   const char **argv UNUSED
> +			   int allow_empty,
> +			   int argc,
> +			   const char **argv
>  			   ) {
>
Nit: we wrap to 80 chars generally, so you can put multiple arguments on
the same line.
> +	int i;
>  	repo_info->repo = repo;
>
>  	if (format == NULL || !strcmp(format, "json"))
> @@ -29,18 +51,82 @@ static void repo_info_init(struct repo_info *repo_info,
>  		repo_info->format = FORMAT_PLAINTEXT;
>  	else
>  		die("invalid format %s", format);
> +
> +	if (argc == 0 && !allow_empty) {
> +		argc = ARRAY_SIZE(default_fields);
> +		argv = default_fields;
> +	}
> +
> +	repo_info->n_fields = argc;
> +	repo_info->fields = xmalloc(argc * sizeof(struct repo_info_field));
> +
Nit: perhaps use ALLOC_ARRAY or family here?
> +	for (i = 0; i < argc; i++) {
> +		const char *arg = argv[i];
> +		struct repo_info_field *field = repo_info->fields + i;
> +
> +		if (!strcmp(arg, "references.format")) {
> +			field->category = CATEGORY_REFERENCES;
> +			field->field.references = FIELD_REFERENCES_FORMAT;
> +		}
Makes me wonder if the default fields can be defined as an array of
'repo_info_field' and avoid the strcmp since the information is
pre-defined. Perhaps something like:
  diff --git a/builtin/repo-info.c b/builtin/repo-info.c
  index a1c9d3942e..81c7b5f896 100644
  --- a/builtin/repo-info.c
  +++ b/builtin/repo-info.c
  @@ -31,8 +31,13 @@ struct repo_info {
   	struct repo_info_field *fields;
   };
  -const char *default_fields[] = {
  -	"references.format",
  +const struct repo_info_field default_fields[] = {
  +	{
  +		.category = CATEGORY_REFERENCES,
  +		.field = {
  +			.references = FIELD_REFERENCES_FORMAT
  +		},
  +	},
   };
   static void repo_info_init(struct repo_info *repo_info,
  @@ -53,8 +58,8 @@ static void repo_info_init(struct repo_info *repo_info,
   		die("invalid format %s", format);
   	if (argc == 0 && !allow_empty) {
  -		argc = ARRAY_SIZE(default_fields);
  -		argv = default_fields;
  +		repo_info->fields = (struct repo_info_field *)&default_fields;
  +		return;
   	}
   	repo_info->n_fields = argc;
> +		else {
> +			die("invalid field '%s'", arg);
> +		}
> +	}
> +}
> +
> +static void repo_info_release(struct repo_info *repo_info) {
> +	free(repo_info->fields);
>  }
>
> -static void repo_info_print_plaintext(struct repo_info *repo_info UNUSED) {
> +static void repo_info_print_plaintext(struct repo_info *repo_info) {
This should definitely go into its own commit or at least be mentioned in
the commit message.
> +	struct repository *repo = repo_info->repo;
> +	int i;
Nit: always nice to leave a newline between the variable declarations
and following code. Also we can move move `int i` declaration directly
inside the loop.
> +	for (i = 0; i < repo_info->n_fields; i++) {
> +		struct repo_info_field *field = &repo_info->fields[i];
> +		switch (field->category) {
> +		case CATEGORY_REFERENCES:
> +			switch (field->field.references) {
> +			case FIELD_REFERENCES_FORMAT:
> +				puts(ref_storage_format_to_name(
> +					repo->ref_storage_format));
> +				break;
> +			}
> +			break;
> +		}
> +	}
>  }
>
> -static void repo_info_print_json(struct repo_info *repo_info UNUSED)
> +static void repo_info_print_json(struct repo_info *repo_info)
>  {
>  	struct json_writer jw;
> +	int i;
> +	unsigned int categories = 0;
> +	unsigned int references_fields = 0;
> +	struct repository *repo = repo_info->repo;
> +
> +	for (i = 0; i < repo_info->n_fields; i++) {
> +		struct repo_info_field *field = repo_info->fields + i;
> +		categories |= field->category;
> +		switch (field->category) {
> +		case CATEGORY_REFERENCES:
> +			references_fields |= field->field.references;
> +			break;
> +		}
> +	}
>
>  	jw_init(&jw);
>
>  	jw_object_begin(&jw, 1);
> +
> +	if (categories & CATEGORY_REFERENCES) {
> +		jw_object_inline_begin_object(&jw, "references");
> +		if (references_fields & FIELD_REFERENCES_FORMAT) {
> +			const char *format_name = ref_storage_format_to_name(
> +				repo->ref_storage_format);
> +			jw_object_string(&jw, "format", format_name);
> +		}
> +		jw_end(&jw);
> +	}
>  	jw_end(&jw);
>
Doesn't this mean that each value of CATEGORY_REFERENCES and
FIELD_REFERENCES_FORMAT should have no common bits? Especially in the
former across different categories too.
I wonder if we can solve this in a easier way. We care about:
- Retaining the order of fields input by the user
- Having a default set of fields if no input received
But, for JSON formatting, order of fields doesn't matter as per the spec
[1]:
  An object is an unordered set of name/value pairs. An object begins
  with {left brace and ends with }right brace. Each name is followed by
  :colon and the name/value pairs are separated by ,comma.
So, do we really want to keep the order? Especially since one suggestion
is to only work with the JSON format for now.
If we don't care about the order, we can simply have a structure with
bit fields and work with that.
>  	puts(jw.json.buf);
> @@ -92,6 +178,7 @@ int cmd_repo_info(
>  			     PARSE_OPT_KEEP_UNKNOWN_OPT);
>  	repo_info_init(&repo_info, repo, format, allow_empty, argc, argv);
>  	repo_info_print(&repo_info);
> +	repo_info_release(&repo_info);
>
>  	return 0;
>  }
> diff --git a/t/t1518-repo-info.sh b/t/t1518-repo-info.sh
> index 2e1a6f0c34..a99198b0f6 100755
> --- a/t/t1518-repo-info.sh
> +++ b/t/t1518-repo-info.sh
> @@ -6,6 +6,8 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
>
>  . ./test-lib.sh
>
> +DEFAULT_NUMBER_OF_FIELDS=1
> +
>  parse_json () {
>  	tr '\n' ' ' | "$PERL_PATH" "$TEST_DIRECTORY/t0019/parse_json.perl"
>  }
> @@ -46,4 +48,22 @@ test_expect_success 'plaintext: returns empty output with allow-empty' '
>  	test_line_count = 0 output
>  '
>
> +test_repo_info 'ref format files is retrieved correctly' \
> +	'' \
> +	'references.format' 'files'
> +
This expects that the repository is created with the 'files' backend by
default, but that is defined by the 'GIT_TEST_DEFAULT_REF_FORMAT' env
variable. So wouldn't this fail when in the CI job for reftables?
> +test_repo_info 'ref format reftable is retrieved correctly' \
> +	'--ref-format=reftable' \
> +	'references.format' 'reftable'
> +
> +test_expect_success 'plaintext: output all default fields' "
> +	git repo-info --format=plaintext >actual &&
> +	test_line_count = $DEFAULT_NUMBER_OF_FIELDS actual
> +"
> +
> +test_expect_success 'json: output all default fields' "
> +	git repo-info --format=json | parse_json | grep '.*\..*\..*' >actual &&
> +	test_line_count = $DEFAULT_NUMBER_OF_FIELDS actual
> +"
> +
While line count is good, we should also check the default values, no?
>  test_done
> --
> 2.39.5 (Apple Git-154)
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 690 bytes --]
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH 4/5] repo-info: add field layout.bare
  2025-06-10 15:21 ` [GSoC RFC PATCH 4/5] repo-info: add field layout.bare Lucas Seiki Oshiro
@ 2025-06-11 13:13   ` Karthik Nayak
  2025-06-12 19:39     ` Lucas Seiki Oshiro
  0 siblings, 1 reply; 226+ messages in thread
From: Karthik Nayak @ 2025-06-11 13:13 UTC (permalink / raw)
  To: Lucas Seiki Oshiro, git; +Cc: ps
[-- Attachment #1: Type: text/plain, Size: 1566 bytes --]
Lucas Seiki Oshiro <lucasseikioshiro@gmail.com> writes:
> Add the field layout.bare to the repo-info command. The data
> retrieved in this field is the same that currently is obtained by
> running `git rev-parse --is-bare-repository`.
>
> Mentored-by: Karthik Nayak <karthik.188@gmail.com>
> Mentored-by Patrick Steinhardt <ps@pks.im>
> Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
> ---
>  builtin/repo-info.c  | 35 ++++++++++++++++++++++++++++++++++-
>  t/t1518-repo-info.sh | 12 ++++++++++--
>  2 files changed, 44 insertions(+), 3 deletions(-)
>
> diff --git a/builtin/repo-info.c b/builtin/repo-info.c
> index a1c9d3942e..bc25a0809f 100644
> --- a/builtin/repo-info.c
> +++ b/builtin/repo-info.c
> @@ -1,4 +1,7 @@
> +#define USE_THE_REPOSITORY_VARIABLE
> +
Ah! Seems like `is_bare_repository()` is responsible for this, it would
be nice to not introduce global dependency in a new command, but this
isn't part of your project, so it's okay here.
>  #include "builtin.h"
> +#include "environment.h"
>  #include "hash.h"
>  #include "json-writer.h"
>  #include "parse-options.h"
> @@ -10,17 +13,22 @@ enum output_format {
>  };
>
>  enum repo_info_category {
> -	CATEGORY_REFERENCES = 1
> +	CATEGORY_REFERENCES = 1,
> +	CATEGORY_LAYOUT = 1 << 1
Style: If we're doing this, then it also makes sense to use `1 << 0`.
>  };
>
>  enum repo_info_references_field {
>  	FIELD_REFERENCES_FORMAT = 1
>  };
>
> +enum repo_info_layout_field { FIELD_LAYOUT_BARE = 1
> +};
> +
Style: let's keep the styling consistent with the previous block.
[snip]
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 690 bytes --]
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH 0/5] repo-info: add new command for retrieving repository info
  2025-06-10 15:21 [GSoC RFC PATCH 0/5] repo-info: add new command for retrieving repository info Lucas Seiki Oshiro
                   ` (6 preceding siblings ...)
  2025-06-10 16:40 ` Junio C Hamano
@ 2025-06-11 13:17 ` Karthik Nayak
  2025-06-19 22:57 ` [GSoC RFC PATCH v2 0/7] " Lucas Seiki Oshiro
                   ` (9 subsequent siblings)
  17 siblings, 0 replies; 226+ messages in thread
From: Karthik Nayak @ 2025-06-11 13:17 UTC (permalink / raw)
  To: Lucas Seiki Oshiro, git; +Cc: ps
[-- Attachment #1: Type: text/plain, Size: 1130 bytes --]
Lucas Seiki Oshiro <lucasseikioshiro@gmail.com> writes:
[snip]
> ## Feedback
>
> I would like to ask for your feedback on this proprosal, specially:
>
> - on deciding if the JSON and linewise plaintext formats are the really the best,
>   or if I should consider others (e.g. gitconfig syntax, NUL-terminated, etc)
>
> - on deciding how the fields will be specified. This "<category>.<format>" was
>   a first idea based on the JSON structure
>
> - about the JSON schema
>
> - about information that may be nice to include in the output of this command,
>   even if they are not currently retrieved by `rev-parse`
>
One thing I'd also like to see is some thought/documentation of what
kind of information should go into this command and what shouldn't. For
e.g. should number of references in a repo be part of this command, or
the `git refs` command. More broadly, which subsystem information should
be exposed via `git repo-info` and how do we draw that line.
Mostly to not create a new `git rev-parse` alternative.
> Thanks!
>
I've also gone ahead and reviewed the patches individually and left some
comments.
- Karthik
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 690 bytes --]
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH 3/5] repo-info: add the field references.format
  2025-06-11 12:59   ` Karthik Nayak
@ 2025-06-12 15:01     ` Junio C Hamano
  0 siblings, 0 replies; 226+ messages in thread
From: Junio C Hamano @ 2025-06-12 15:01 UTC (permalink / raw)
  To: Karthik Nayak; +Cc: Lucas Seiki Oshiro, git, ps
Karthik Nayak <karthik.188@gmail.com> writes:
>>  static void repo_info_init(struct repo_info *repo_info,
>>  			   struct repository *repo,
>>  			   char *format,
>> -			   int allow_empty UNUSED,
>> -			   int argc UNUSED,
>> -			   const char **argv UNUSED
>> +			   int allow_empty,
>> +			   int argc,
>> +			   const char **argv
>>  			   ) {
>>
>
> Nit: we wrap to 80 chars generally, so you can put multiple arguments on
> the same line.
Good point.  It is worth pointing out that we also group related
arguments together, and make it easier to later add new things at
the end and still keep related things together, e.g.,
static void repo_info_init(struct repo_info *repo_info,
			   struct repository *repo,
                           int argc, const char **argv,
			   const char *format,
			   int allow_empty)
{
Obviously argc, argv belong to each other, so it is OK to have on
the same line, and unlike repo_info (i.e. the out argument), repo
(i.e. the primary thing that is inspected), format and allow_empty
are something you would want to later extend when you "enrich" the
interface and functionality.  You may even gain "int display_width"
argument to allow line-wrapped output, for example, and you would
have to insert in the middle if you want to keep related things
together, if you had (argc, argv) at the end. 
Also note that {opening and closing braces} around the function body
sits on their own lines.
Why is "format" a string?  Shouldn't the caller do all the argument
parsing and pass an enum or something to this function?  After all,
I presume that allow_empty is set in response to "--allow-empty" or
something that the user gave to the command, and that parsing is done
by the caller before it calls this function, no?  Why not do the
same for the output format?
I'll stop here for now.
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH 2/5] repo-info: add the --format flag
  2025-06-11  9:30   ` Karthik Nayak
@ 2025-06-12 17:56     ` Lucas Seiki Oshiro
  2025-06-13  7:31       ` Karthik Nayak
  0 siblings, 1 reply; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-06-12 17:56 UTC (permalink / raw)
  To: Karthik Nayak; +Cc: git, ps
>> Also add a flag --allow-empty, which will force the output data to be
>> empty when no field is requested.
>> 
> Why do you suppose we need this, I'm not against it, but it would be
> nice to state why this is necessary. The idea is to have a default
> output when a user runs `git repo-info`, so I'm missing why this would
> be useful.
I was thinking about use cases where repo-info is used inside scripts.
A simple (but kinda useless...) example: an application that is a GUI
for this command, where the fields are selected in a checkbox, calling
repo-info with them and then displaying their contents in a dialog.
In this example, if no field is selected and there's no validation in
the GUI side, the default set of data will be retrieved. With
git repo-info --allow-empty, we don't need to care about it.
But, yeah, I agree that we don't need to think about it by now...
> If I recall correctly, in our previous internal review, it was mentioned
> that since we use perl here, we should add a PERL pre-requisite. Similar
> to the one in 't/t0019-json-writer.sh'.
Do you mean to use a `test_lazy_prereq`? I'll take a look on that.
> As of this patch,
> 
>  $ ~/code/git/build/bin-wrappers/git repo-info
>  {
>  }
> 
>  $ ~/code/git/build/bin-wrappers/git repo-info --allow-empty
>  {
>  }
> 
> So what differentiates the former from the latter?
In this patch, nothing. I was only trying to keep the consistency
of each patch from 3 to 5 implementing only the code related to the
field, but it seems ok to me to squash this patch and the next one.
> This is because we didn't implement plainttext no?
Yes!
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH 4/5] repo-info: add field layout.bare
  2025-06-11 13:13   ` Karthik Nayak
@ 2025-06-12 19:39     ` Lucas Seiki Oshiro
  2025-06-12 19:53       ` Junio C Hamano
  0 siblings, 1 reply; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-06-12 19:39 UTC (permalink / raw)
  To: Karthik Nayak; +Cc: git, ps
>> +#define USE_THE_REPOSITORY_VARIABLE
>> 
> Ah! Seems like `is_bare_repository()` is responsible for this, it would
> be nice to not introduce global dependency in a new command, but this
> isn't part of your project, so it's okay here.
Yeah, to be honest I was reluctant to use this, and I tried to find if
I could easily drop this dependency. But this is `is_bare_repository`:
int is_bare_repository(void)
{
	/* if core.bare is not 'false', let's see if there is a work tree */
	return is_bare_repository_cfg && !repo_get_work_tree(the_repository);
}
But I couldn't find out what is the dependency of is_bare_repository_cfg
on the_repository yet, but I decided to keep for this RFC.
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH 4/5] repo-info: add field layout.bare
  2025-06-12 19:39     ` Lucas Seiki Oshiro
@ 2025-06-12 19:53       ` Junio C Hamano
  0 siblings, 0 replies; 226+ messages in thread
From: Junio C Hamano @ 2025-06-12 19:53 UTC (permalink / raw)
  To: Lucas Seiki Oshiro; +Cc: Karthik Nayak, git, ps
Lucas Seiki Oshiro <lucasseikioshiro@gmail.com> writes:
>>> +#define USE_THE_REPOSITORY_VARIABLE
>>> 
>> Ah! Seems like `is_bare_repository()` is responsible for this, it would
>> be nice to not introduce global dependency in a new command, but this
>> isn't part of your project, so it's okay here.
>
> Yeah, to be honest I was reluctant to use this, and I tried to find if
> I could easily drop this dependency. But this is `is_bare_repository`:
>
> int is_bare_repository(void)
> {
> 	/* if core.bare is not 'false', let's see if there is a work tree */
> 	return is_bare_repository_cfg && !repo_get_work_tree(the_repository);
> }
>
> But I couldn't find out what is the dependency of is_bare_repository_cfg
> on the_repository yet, but I decided to keep for this RFC.
I suspect that by the time setup_git_env() is called in the startup
sequence from setup_git_directory(), we know that the repository
knows if the repository is bare.  So one thing we could do is to add
is-bare-repository-cfg bit as a new member to the repo-settings
object of the_repository and record the bit before the
setup_git_directory() callchain returns.
Then you can teach is_bare_repository() to take a repo object from
its caller and the above may become something like
	int repository_is_bare(struct repository *r)
	{
		return (r->settings.is_bare_repository &&
			!repo_get_work_tree(r));
	}
perhaps.
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH 0/5] repo-info: add new command for retrieving repository info
  2025-06-10 16:40 ` Junio C Hamano
@ 2025-06-12 20:25   ` Lucas Seiki Oshiro
  2025-06-12 21:01     ` Junio C Hamano
  0 siblings, 1 reply; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-06-12 20:25 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, ps, karthik.188
> OK, that's understandable, other than that handling of trailing
> commas looks somewhat inconsistent.
Ooops, it was typo. I'm using the json_writer functions
>> Or in a plaintext format, like this:
>> 
>> ~~~
>> $ git repo-info --format=plaintext
>> sha1
>> files
>> /git/dir
>> /git/common-dir
>> /git/toplevel
>> /super/working/tree
>> false
>> false
>> ~~~
> 
> This one is a bit questionable.
> 
> Is it safe to assume that we will never have to deal with payload
> controllable by the end-user that can have arbitrary byte values?
I was trying to follow the behavior of rev-parse, where we can
do this:
git rev-parse --show-toplevel --is-bare-repository
and it prints both the top level repositority and whether it is
a bare repository.
> It would be uncommon but possible for LF to be in one of these
> pathnames
I tested here and this also happened with rev-parse:
$ git init 'my
  repo'
$ cd my\nrepo/
$ git rev-parse --show-toplevel
/tmp/my
repo
And this also happens passing other flags to rev-parse...
> This one is OK.
So, after reading your review, I though about other solution:
1. The user can provide only one field or no field
2. If the user provide only one field, repo-info will return
   only its contents
3. If the user don't provide any field, the default set of
   fields will be returned
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH 0/5] repo-info: add new command for retrieving repository info
  2025-06-12 20:25   ` Lucas Seiki Oshiro
@ 2025-06-12 21:01     ` Junio C Hamano
  2025-06-16 22:19       ` Lucas Seiki Oshiro
  0 siblings, 1 reply; 226+ messages in thread
From: Junio C Hamano @ 2025-06-12 21:01 UTC (permalink / raw)
  To: Lucas Seiki Oshiro; +Cc: git, ps, karthik.188
Lucas Seiki Oshiro <lucasseikioshiro@gmail.com> writes:
> I was trying to follow the behavior of rev-parse, where we can
> do this:
>
> git rev-parse --show-toplevel --is-bare-repository
As often said, an earlier mistake is not an excuse to pile more of
them on top.  Isn't the whole point of this new command to remove
these kitchen-sink options out of rev-parse and give them better
home?  Let's learn from our earlier mistakes and do it right in the
new incarnation.
> So, after reading your review, I though about other solution:
>
> 1. The user can provide only one field or no field
> 2. If the user provide only one field, repo-info will return
>    only its contents
> 3. If the user don't provide any field, the default set of
>    fields will be returned
Hmm.  Isn't
4. The output always comes out in JSON.  There should be plenty JSON
   reading libraries available to the GUI command or whatever that
   forks this command and reads from it, right?
an option?  If we want textual format, and assume that almost all
values are text, we could do something like
 1. In text mode, the values are shown one-item-per-line, even if
    the value has embedded LF in it.  At least we assume that the
    values do not contain a NUL byte.
 2. If a value does not have LF or double-quote in it, it is output
    literally.
 3. Otherwise, the value is shown with quote_c_style().
The implication of which is that a loosely written program that does
not grok funny values (namely, a string that contains a double-quote
or a line-feed) can be written loosely without having to worry about
quoting and assume one-line-per-item.  They may show a wrong value,
but at least because one-line-per-item assumption holds, their
input/request and value they receive from the program will not go
out of sync.  And a more carefully written program can of course
check the first byte to see if it is a double-quote, in which case
they have to unquote the whole line (which may yield a multi-line
value if the quoted string had embedded "\n"s).
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH 2/5] repo-info: add the --format flag
  2025-06-12 17:56     ` Lucas Seiki Oshiro
@ 2025-06-13  7:31       ` Karthik Nayak
  0 siblings, 0 replies; 226+ messages in thread
From: Karthik Nayak @ 2025-06-13  7:31 UTC (permalink / raw)
  To: Lucas Seiki Oshiro; +Cc: git, ps
[-- Attachment #1: Type: text/plain, Size: 1754 bytes --]
Lucas Seiki Oshiro <lucasseikioshiro@gmail.com> writes:
>>> Also add a flag --allow-empty, which will force the output data to be
>>> empty when no field is requested.
>>>
>> Why do you suppose we need this, I'm not against it, but it would be
>> nice to state why this is necessary. The idea is to have a default
>> output when a user runs `git repo-info`, so I'm missing why this would
>> be useful.
>
> I was thinking about use cases where repo-info is used inside scripts.
> A simple (but kinda useless...) example: an application that is a GUI
> for this command, where the fields are selected in a checkbox, calling
> repo-info with them and then displaying their contents in a dialog.
>
> In this example, if no field is selected and there's no validation in
> the GUI side, the default set of data will be retrieved. With
> git repo-info --allow-empty, we don't need to care about it.
>
> But, yeah, I agree that we don't need to think about it by now...
>
>> If I recall correctly, in our previous internal review, it was mentioned
>> that since we use perl here, we should add a PERL pre-requisite. Similar
>> to the one in 't/t0019-json-writer.sh'.
>
> Do you mean to use a `test_lazy_prereq`? I'll take a look on that.
>
Yes, that's the one.
>> As of this patch,
>>
>>  $ ~/code/git/build/bin-wrappers/git repo-info
>>  {
>>  }
>>
>>  $ ~/code/git/build/bin-wrappers/git repo-info --allow-empty
>>  {
>>  }
>>
>> So what differentiates the former from the latter?
>
> In this patch, nothing. I was only trying to keep the consistency
> of each patch from 3 to 5 implementing only the code related to the
> field, but it seems ok to me to squash this patch and the next one.
>
>> This is because we didn't implement plainttext no?
>
> Yes!
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 690 bytes --]
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH 0/5] repo-info: add new command for retrieving repository info
  2025-06-12 21:01     ` Junio C Hamano
@ 2025-06-16 22:19       ` Lucas Seiki Oshiro
  2025-06-16 22:40         ` Junio C Hamano
  0 siblings, 1 reply; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-06-16 22:19 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, ps, karthik.188
> Let's learn from our earlier mistakes and do it right in the
> new incarnation.
Ok, fair!
> 1. In text mode, the values are shown one-item-per-line, even if
>    the value has embedded LF in it.  At least we assume that the
>    values do not contain a NUL byte.
> 
> 2. If a value does not have LF or double-quote in it, it is output
>    literally.
> 
> 3. Otherwise, the value is shown with quote_c_style().
Hmmm, ok. So, I if I understood it correctly, is your idea to keep
the same functionality but using quote_c_style to keep one field
per line?
> The implication of which is that a loosely written program that does
> not grok funny values (namely, a string that contains a double-quote
> or a line-feed) can be written loosely without having to worry about
> quoting and assume one-line-per-item.  They may show a wrong value,
> but at least because one-line-per-item assumption holds, their
> input/request and value they receive from the program will not go
> out of sync.  And a more carefully written program can of course
> check the first byte to see if it is a double-quote, in which case
> they have to unquote the whole line (which may yield a multi-line
> value if the quoted string had embedded "\n"s).
Thanks again, Junio! 
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH 0/5] repo-info: add new command for retrieving repository info
  2025-06-16 22:19       ` Lucas Seiki Oshiro
@ 2025-06-16 22:40         ` Junio C Hamano
  2025-06-19  1:44           ` Lucas Seiki Oshiro
  0 siblings, 1 reply; 226+ messages in thread
From: Junio C Hamano @ 2025-06-16 22:40 UTC (permalink / raw)
  To: Lucas Seiki Oshiro; +Cc: git, ps, karthik.188
Lucas Seiki Oshiro <lucasseikioshiro@gmail.com> writes:
>> Let's learn from our earlier mistakes and do it right in the
>> new incarnation.
>
> Ok, fair!
>
>> 1. In text mode, the values are shown one-item-per-line, even if
>>    the value has embedded LF in it.  At least we assume that the
>>    values do not contain a NUL byte.
>> 
>> 2. If a value does not have LF or double-quote in it, it is output
>>    literally.
>> 
>> 3. Otherwise, the value is shown with quote_c_style().
>
> Hmmm, ok. So, I if I understood it correctly, is your idea to keep
> the same functionality but using quote_c_style to keep one field
> per line?
I am not sure what you are comparing against with "the same" here,
but the idea is that not many items have problematic characters in
them anyway, and a simple-minded broken output parser can be written
in 5 minutes and would happen to work correctly in more than 80% of
repositories ;-)  A production quality tool needs to be aware of the
possibility that they may need to unquote when they see a double-quote
at the beginning of a line.
By the way, somebody wondered in a nearby message why we do not have
the "key" and only "value" in the textual output, and I share the
same sentiment.  Where JSON may say
  "path": {
    "git-dir": "/git/dir"
    ...
text format may want to say
  path.git-dir=/git/dir
instead of just
  /git/dir
But I dunno.  When asking a single item from the command line, it is
perfectly fine to respond with a single value, but when you are
showing multiple items (especially without any "give me this and
that item and nothing else" specified on the command line, in which
case nobody knows in what order the value is given), I think the
calling script almost always wants to get key-value pairs.
Also are you planning on later adding a long-running server mode
like "cat-file --batch-command"?
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH 0/5] repo-info: add new command for retrieving repository info
  2025-06-16 22:40         ` Junio C Hamano
@ 2025-06-19  1:44           ` Lucas Seiki Oshiro
  0 siblings, 0 replies; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-06-19  1:44 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, ps, karthik.188
> But I dunno.  When asking a single item from the command line, it is
> perfectly fine to respond with a single value, but when you are
> showing multiple items (especially without any "give me this and
> that item and nothing else" specified on the command line, in which
> case nobody knows in what order the value is given), I think the
> calling script almost always wants to get key-value pairs.
Ok! I'm polishing my v2 and I expect to sent it soon. I already changed the
output to that format.
> Also are you planning on later adding a long-running server mode
> like "cat-file --batch-command"?
To be honest, I didn't know about that feature of cat-file until your comment.
It seems to be a nice feature to add, entering the keys and printing the
corresponding values.
I'm adding a --batch-command feature and the removal of the dependency on
the_repository to a todo list to be considered in a future iteration on this
command, after delivering its basic functionality.
Thanks!
^ permalink raw reply	[flat|nested] 226+ messages in thread
* [GSoC RFC PATCH v2 0/7] repo-info: add new command for retrieving repository info
  2025-06-10 15:21 [GSoC RFC PATCH 0/5] repo-info: add new command for retrieving repository info Lucas Seiki Oshiro
                   ` (7 preceding siblings ...)
  2025-06-11 13:17 ` Karthik Nayak
@ 2025-06-19 22:57 ` Lucas Seiki Oshiro
  2025-06-19 22:57   ` [GSoC RFC PATCH v2 1/7] repo-info: declare the repo-info command Lucas Seiki Oshiro
                     ` (7 more replies)
  2025-07-06 23:19 ` [GSoC RFC PATCH v3 0/5] " Lucas Seiki Oshiro
                   ` (8 subsequent siblings)
  17 siblings, 8 replies; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-06-19 22:57 UTC (permalink / raw)
  To: git; +Cc: ps, karthik.188, ben.knoble, gitster, Lucas Seiki Oshiro
Hi!
This is the second version of the repo-info RFC, and these are the main changes
introduced since v1:
- The plaintext format now returns its fields in a key=value format
- The tests were renumbered to t1900, since it's a new command (the previous was
  t1518, following the numbering of rev-parse)
- The test function 'test_repo_info' now has a docstring, and it is more flexible
  for using more complex repository initializations
- The flag --allow-empty is now introduced in its own commit
- The plaintext and the JSON formats are now introduced in their own commits
- The JSON format tests, which depends on the Perl's JSON module, are now marked
  with the PERLJSON lazy prereq, being skipped in environments that don't have
  that module installed
Some things pointed in the last review weren't implemented as I prefer to do
them in another iteration of repo-info after having its basic functionality
working:
- Remove the dependency on 'the_repository' when calling 'is_bare_repository'
- Add a --batch-command mode, based on the --bath-command flag of cat-file,
  introduced in 440c705ea6 (cat-file: add --batch-command mode, 2022-02-18)
- Use the category as key instead of only accepting category.key. In the current
  patchset, `git repo-info layout` would equivalent to
  `git repo-info layout.bare layout.shallow`
I'm cc'ing my mentors and everyone that answered me in v1 and my GSoC blog. I'm
still open to any suggestions, requests and questions that you may have!
Here's the range-diff of this v2:
1:  20a3d131c3 ! 1:  102b5ce90a repo-info: declare the repo-info command
    @@ Commit message
         - git.c
         - .gitignore
    +    In option parsing, use PARSE_OPT_KEEP_UNKNOWN_OPT to allow the users
    +    specify after the flags the information that they want to retrieve.
    +
         Mentored-by: Karthik Nayak <karthik.188@gmail.com>
         Mentored-by Patrick Steinhardt <ps@pks.im>
         Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
    @@ builtin/repo-info.c (new)
     +#include "builtin.h"
     +#include "parse-options.h"
     +
    -+int cmd_repo_info(
    -+	int argc,
    -+	const char **argv,
    -+	const char *prefix,
    -+	struct repository *repo UNUSED
    -+	)
    ++int cmd_repo_info(int argc,
    ++		  const char **argv,
    ++		  const char *prefix,
    ++		  struct repository *repo UNUSED)
     +{
     +	const char *const repo_info_usage[] = {
     +		"git repo-info",
    @@ builtin/repo-info.c (new)
     +		OPT_END()
     +	};
     +
    -+	argc = parse_options(argc, argv, prefix, options, repo_info_usage, 0);
    ++	argc = parse_options(argc, argv, prefix, options, repo_info_usage,
    ++			     PARSE_OPT_KEEP_UNKNOWN_OPT);
     +
     +	return 0;
     +}
2:  f78058c25a < -:  ---------- repo-info: add the --format flag
3:  3b2f534a69 < -:  ---------- repo-info: add the field references.format
-:  ---------- > 2:  1cc1184663 repo-info: add the --format flag
-:  ---------- > 3:  a329825387 repo-info: add plaintext as an output format
-:  ---------- > 4:  3b6c27b68d repo-info: add the --allow-empty flag
-:  ---------- > 5:  441b010175 repo-info: add the field references.format
4:  5ad7e79f83 ! 6:  f39086ea86 repo-info: add field layout.bare
    @@ builtin/repo-info.c
     +
      #include "builtin.h"
     +#include "environment.h"
    - #include "hash.h"
    ++#include "hash.h"
      #include "json-writer.h"
      #include "parse-options.h"
    +-#include "refs.h"
    + #include "quote.h"
    ++#include "refs.h"
    +
    + enum output_format {
    + 	FORMAT_JSON,
     @@ builtin/repo-info.c: enum output_format {
      };
      enum repo_info_category {
    --	CATEGORY_REFERENCES = 1
    -+	CATEGORY_REFERENCES = 1,
    +-	CATEGORY_REFERENCES = 1 << 0
    ++	CATEGORY_REFERENCES = 1 << 0,
     +	CATEGORY_LAYOUT = 1 << 1
      };
      enum repo_info_references_field {
    - 	FIELD_REFERENCES_FORMAT = 1
    + 	FIELD_REFERENCES_FORMAT = 1 << 0
      };
    -+enum repo_info_layout_field { FIELD_LAYOUT_BARE = 1
    ++enum repo_info_layout_field {
    ++	FIELD_LAYOUT_BARE = 1 << 0
     +};
     +
      struct repo_info_field {
    @@ builtin/repo-info.c: enum output_format {
      	} field;
      };
    -@@ builtin/repo-info.c: struct repo_info {
    -
    - const char *default_fields[] = {
    - 	"references.format",
    -+	"layout.bare"
    +@@ builtin/repo-info.c: static struct repo_info_field default_fields[] = {
    + 	{
    + 		.category = CATEGORY_REFERENCES,
    + 		.field.references = FIELD_REFERENCES_FORMAT
    ++	},
    ++	{
    ++		.category = CATEGORY_LAYOUT,
    ++		.field.layout = FIELD_LAYOUT_BARE
    + 	}
      };
    - static void repo_info_init(struct repo_info *repo_info,
     @@ builtin/repo-info.c: static void repo_info_init(struct repo_info *repo_info,
    - 			field->category = CATEGORY_REFERENCES;
    - 			field->field.references = FIELD_REFERENCES_FORMAT;
    - 		}
    -+		else if (!strcmp(arg, "layout.bare")) {
    -+			field->category = CATEGORY_LAYOUT;
    -+			field->field.layout = FIELD_LAYOUT_BARE;
    -+		}
    - 		else {
    - 			die("invalid field '%s'", arg);
    - 		}
    + 			if (!strcmp(arg, "references.format")) {
    + 				field->category = CATEGORY_REFERENCES;
    + 				field->field.references = FIELD_REFERENCES_FORMAT;
    ++			} else if (!strcmp(arg, "layout.bare")) {
    ++				field->category = CATEGORY_LAYOUT;
    ++				field->field.layout = FIELD_LAYOUT_BARE;
    + 			} else {
    + 				die("invalid field '%s'", arg);
    + 			}
     @@ builtin/repo-info.c: static void repo_info_print_plaintext(struct repo_info *repo_info) {
      				break;
      			}
    @@ builtin/repo-info.c: static void repo_info_print_plaintext(struct repo_info *rep
     +		case CATEGORY_LAYOUT:
     +			switch (field->field.layout) {
     +			case FIELD_LAYOUT_BARE:
    -+				puts(is_bare_repository() ? "true" : "false");
    ++				print_key_value("layout.bare",
    ++						is_bare_repository() ?
    ++							"true" : "false");
     +				break;
     +			}
     +			break;
    @@ builtin/repo-info.c: static void repo_info_print_json(struct repo_info *repo_inf
      	puts(jw.json.buf);
    - ## t/t1518-repo-info.sh ##
    -@@ t/t1518-repo-info.sh: export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
    + ## t/t1900-repo-info.sh ##
    +@@ t/t1900-repo-info.sh: export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
      . ./test-lib.sh
    @@ t/t1518-repo-info.sh: export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
      parse_json () {
      	tr '\n' ' ' | "$PERL_PATH" "$TEST_DIRECTORY/t0019/parse_json.perl"
    -@@ t/t1518-repo-info.sh: test_repo_info () {
    - 		test_when_finished 'rm -rf repo' &&
    - 		git init $init_args repo &&
    - 		cd repo &&
    --		echo '$expected_value' >expect &&
    -+		echo '$expected_value' | sed 's/^false$/0/' | sed 's/^true$/1/' >expect &&
    - 		git repo-info '$key'| parse_json >output &&
    - 		grep -F 'row[0].$key' output | cut -d ' ' -f 2 >actual &&
    - 		test_cmp expect actual
    -@@ t/t1518-repo-info.sh: test_repo_info 'ref format reftable is retrieved correctly' \
    - 	'--ref-format=reftable' \
    - 	'references.format' 'reftable'
    +@@ t/t1900-repo-info.sh: test_repo_info 'ref format files is retrieved correctly' '
    + test_repo_info 'ref format reftable is retrieved correctly' '
    + 	git init --ref-format=reftable repo' 'references.format' 'reftable'
    -+test_repo_info 'bare repository = false is retrieved correctly' \
    -+	'' \
    -+	'layout.bare' 'false'
    ++test_repo_info 'bare repository = false is retrieved correctly' '
    ++	git init repo' 'layout.bare' 'false'
     +
    -+test_repo_info 'bare repository = true is retrieved correctly' \
    -+	'--bare' \
    -+	'layout.bare' 'true'
    ++test_repo_info 'bare repository = true is retrieved correctly' '
    ++	git init --bare repo' 'layout.bare' 'true'
     +
      test_expect_success 'plaintext: output all default fields' "
      	git repo-info --format=plaintext >actual &&
5:  0295c19951 < -:  ---------- repo-info: add field layout.shallow
-:  ---------- > 7:  219b84f032 repo-info: add field layout.shallow
Lucas Seiki Oshiro (7):
  repo-info: declare the repo-info command
  repo-info: add the --format flag
  repo-info: add plaintext as an output format
  repo-info: add the --allow-empty flag
  repo-info: add the field references.format
  repo-info: add field layout.bare
  repo-info: add field layout.shallow
 .gitignore           |   1 +
 Makefile             |   1 +
 builtin.h            |   1 +
 builtin/repo-info.c  | 244 +++++++++++++++++++++++++++++++++++++++++++
 git.c                |   1 +
 meson.build          |   1 +
 t/meson.build        |   1 +
 t/t1900-repo-info.sh | 105 +++++++++++++++++++
 8 files changed, 355 insertions(+)
 create mode 100644 builtin/repo-info.c
 create mode 100755 t/t1900-repo-info.sh
-- 
2.39.5 (Apple Git-154)
^ permalink raw reply	[flat|nested] 226+ messages in thread
* [GSoC RFC PATCH v2 1/7] repo-info: declare the repo-info command
  2025-06-19 22:57 ` [GSoC RFC PATCH v2 0/7] " Lucas Seiki Oshiro
@ 2025-06-19 22:57   ` Lucas Seiki Oshiro
  2025-06-20  7:36     ` Karthik Nayak
                       ` (3 more replies)
  2025-06-19 22:57   ` [GSoC RFC PATCH v2 2/7] repo-info: add the --format flag Lucas Seiki Oshiro
                     ` (6 subsequent siblings)
  7 siblings, 4 replies; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-06-19 22:57 UTC (permalink / raw)
  To: git; +Cc: ps, karthik.188, ben.knoble, gitster, Lucas Seiki Oshiro
Create a new Git subcommand called repo-info. `git repo-info` will query
metadata from the current repository and outputs it as JSON or plaintext.
Also add entries for this new command in:
- the build files (Makefile and meson.build)
- builtin.h
- git.c
- .gitignore
In option parsing, use PARSE_OPT_KEEP_UNKNOWN_OPT to allow the users
specify after the flags the information that they want to retrieve.
Mentored-by: Karthik Nayak <karthik.188@gmail.com>
Mentored-by Patrick Steinhardt <ps@pks.im>
Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
---
 .gitignore          |  1 +
 Makefile            |  1 +
 builtin.h           |  1 +
 builtin/repo-info.c | 21 +++++++++++++++++++++
 git.c               |  1 +
 meson.build         |  1 +
 6 files changed, 26 insertions(+)
 create mode 100644 builtin/repo-info.c
diff --git a/.gitignore b/.gitignore
index 04c444404e..b2f3fb0047 100644
--- a/.gitignore
+++ b/.gitignore
@@ -139,6 +139,7 @@
 /git-repack
 /git-replace
 /git-replay
+/git-repo-info
 /git-request-pull
 /git-rerere
 /git-reset
diff --git a/Makefile b/Makefile
index 70d1543b6b..50e3a3cbcc 100644
--- a/Makefile
+++ b/Makefile
@@ -1308,6 +1308,7 @@ BUILTIN_OBJS += builtin/remote.o
 BUILTIN_OBJS += builtin/repack.o
 BUILTIN_OBJS += builtin/replace.o
 BUILTIN_OBJS += builtin/replay.o
+BUILTIN_OBJS += builtin/repo-info.o
 BUILTIN_OBJS += builtin/rerere.o
 BUILTIN_OBJS += builtin/reset.o
 BUILTIN_OBJS += builtin/rev-list.o
diff --git a/builtin.h b/builtin.h
index bff13e3069..cc6bc95962 100644
--- a/builtin.h
+++ b/builtin.h
@@ -216,6 +216,7 @@ int cmd_remote_ext(int argc, const char **argv, const char *prefix, struct repos
 int cmd_remote_fd(int argc, const char **argv, const char *prefix, struct repository *repo);
 int cmd_repack(int argc, const char **argv, const char *prefix, struct repository *repo);
 int cmd_replay(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_repo_info(int argc, const char **argv, const char *prefix, struct repository *repo);
 int cmd_rerere(int argc, const char **argv, const char *prefix, struct repository *repo);
 int cmd_reset(int argc, const char **argv, const char *prefix, struct repository *repo);
 int cmd_restore(int argc, const char **argv, const char *prefix, struct repository *repo);
diff --git a/builtin/repo-info.c b/builtin/repo-info.c
new file mode 100644
index 0000000000..a5c43e253f
--- /dev/null
+++ b/builtin/repo-info.c
@@ -0,0 +1,21 @@
+#include "builtin.h"
+#include "parse-options.h"
+
+int cmd_repo_info(int argc,
+		  const char **argv,
+		  const char *prefix,
+		  struct repository *repo UNUSED)
+{
+	const char *const repo_info_usage[] = {
+		"git repo-info",
+		NULL
+	};
+	struct option options[] = {
+		OPT_END()
+	};
+
+	argc = parse_options(argc, argv, prefix, options, repo_info_usage,
+			     PARSE_OPT_KEEP_UNKNOWN_OPT);
+
+	return 0;
+}
diff --git a/git.c b/git.c
index 07a5fe39fb..27a2b3569b 100644
--- a/git.c
+++ b/git.c
@@ -611,6 +611,7 @@ static struct cmd_struct commands[] = {
 	{ "repack", cmd_repack, RUN_SETUP },
 	{ "replace", cmd_replace, RUN_SETUP },
 	{ "replay", cmd_replay, RUN_SETUP },
+	{ "repo-info", cmd_repo_info, RUN_SETUP },
 	{ "rerere", cmd_rerere, RUN_SETUP },
 	{ "reset", cmd_reset, RUN_SETUP },
 	{ "restore", cmd_restore, RUN_SETUP | NEED_WORK_TREE },
diff --git a/meson.build b/meson.build
index 7fea4a34d6..06f2f647ba 100644
--- a/meson.build
+++ b/meson.build
@@ -645,6 +645,7 @@ builtin_sources = [
   'builtin/repack.c',
   'builtin/replace.c',
   'builtin/replay.c',
+  'builtin/repo-info.c',
   'builtin/rerere.c',
   'builtin/reset.c',
   'builtin/rev-list.c',
-- 
2.39.5 (Apple Git-154)
^ permalink raw reply related	[flat|nested] 226+ messages in thread
* [GSoC RFC PATCH v2 2/7] repo-info: add the --format flag
  2025-06-19 22:57 ` [GSoC RFC PATCH v2 0/7] " Lucas Seiki Oshiro
  2025-06-19 22:57   ` [GSoC RFC PATCH v2 1/7] repo-info: declare the repo-info command Lucas Seiki Oshiro
@ 2025-06-19 22:57   ` Lucas Seiki Oshiro
  2025-06-20  8:06     ` Karthik Nayak
                       ` (2 more replies)
  2025-06-19 22:57   ` [GSoC RFC PATCH v2 3/7] repo-info: add plaintext as an output format Lucas Seiki Oshiro
                     ` (5 subsequent siblings)
  7 siblings, 3 replies; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-06-19 22:57 UTC (permalink / raw)
  To: git; +Cc: ps, karthik.188, ben.knoble, gitster, Lucas Seiki Oshiro
Add the --format flag to the repo-info command, allowing the user to
choose between output formats. Use 'json' by default.
Mentored-by: Karthik Nayak <karthik.188@gmail.com>
Mentored-by Patrick Steinhardt <ps@pks.im>
Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
---
 builtin/repo-info.c  | 54 +++++++++++++++++++++++++++++++++++++++++++-
 t/meson.build        |  1 +
 t/t1900-repo-info.sh | 22 ++++++++++++++++++
 3 files changed, 76 insertions(+), 1 deletion(-)
 create mode 100755 t/t1900-repo-info.sh
diff --git a/builtin/repo-info.c b/builtin/repo-info.c
index a5c43e253f..cbe1475e30 100644
--- a/builtin/repo-info.c
+++ b/builtin/repo-info.c
@@ -1,21 +1,73 @@
 #include "builtin.h"
+#include "json-writer.h"
 #include "parse-options.h"
 
+enum output_format {
+	FORMAT_JSON
+};
+
+struct repo_info {
+	struct repository *repo;
+	enum output_format format;
+};
+
+static void repo_info_init(struct repo_info *repo_info,
+			   struct repository *repo,
+			   char *format)
+{
+	repo_info->repo = repo;
+
+	if (format == NULL || !strcmp(format, "json"))
+		repo_info->format = FORMAT_JSON;
+	else
+		die("invalid format %s", format);
+}
+
+static void repo_info_print_json(struct repo_info *repo_info UNUSED)
+{
+	struct json_writer jw;
+
+	jw_init(&jw);
+
+	jw_object_begin(&jw, 1);
+	jw_end(&jw);
+
+	puts(jw.json.buf);
+	jw_release(&jw);
+}
+
+static void repo_info_print(struct repo_info *repo_info)
+{
+	enum output_format format = repo_info->format;
+
+	switch (format) {
+	case FORMAT_JSON:
+		repo_info_print_json(repo_info);
+		break;
+	}
+}
+
 int cmd_repo_info(int argc,
 		  const char **argv,
 		  const char *prefix,
-		  struct repository *repo UNUSED)
+		  struct repository *repo)
 {
 	const char *const repo_info_usage[] = {
 		"git repo-info",
 		NULL
 	};
+	struct repo_info repo_info;
+	char *format = NULL;
 	struct option options[] = {
+		OPT_STRING(0, "format", &format, N_("format"),
+			   N_("output format")),
 		OPT_END()
 	};
 
 	argc = parse_options(argc, argv, prefix, options, repo_info_usage,
 			     PARSE_OPT_KEEP_UNKNOWN_OPT);
+	repo_info_init(&repo_info, repo, format);
+	repo_info_print(&repo_info);
 
 	return 0;
 }
diff --git a/t/meson.build b/t/meson.build
index 50e89e764a..d9ecaba3b7 100644
--- a/t/meson.build
+++ b/t/meson.build
@@ -246,6 +246,7 @@ integration_tests = [
   't1700-split-index.sh',
   't1701-racy-split-index.sh',
   't1800-hook.sh',
+  't1900-repo-info.sh',
   't2000-conflict-when-checking-files-out.sh',
   't2002-checkout-cache-u.sh',
   't2003-checkout-cache-mkdir.sh',
diff --git a/t/t1900-repo-info.sh b/t/t1900-repo-info.sh
new file mode 100755
index 0000000000..f634e1a285
--- /dev/null
+++ b/t/t1900-repo-info.sh
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+test_description='test git repo-info'
+GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
+export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+
+. ./test-lib.sh
+
+parse_json () {
+	tr '\n' ' ' | "$PERL_PATH" "$TEST_DIRECTORY/t0019/parse_json.perl"
+}
+
+test_lazy_prereq PERLJSON '
+	perl -MJSON -e "exit 0"
+'
+
+test_expect_success PERLJSON 'json: returns empty output with allow-empty' '
+	git repo-info --format=json >output &&
+	test_line_count = 2 output
+'
+
+test_done
-- 
2.39.5 (Apple Git-154)
^ permalink raw reply related	[flat|nested] 226+ messages in thread
* [GSoC RFC PATCH v2 3/7] repo-info: add plaintext as an output format
  2025-06-19 22:57 ` [GSoC RFC PATCH v2 0/7] " Lucas Seiki Oshiro
  2025-06-19 22:57   ` [GSoC RFC PATCH v2 1/7] repo-info: declare the repo-info command Lucas Seiki Oshiro
  2025-06-19 22:57   ` [GSoC RFC PATCH v2 2/7] repo-info: add the --format flag Lucas Seiki Oshiro
@ 2025-06-19 22:57   ` Lucas Seiki Oshiro
  2025-06-20 21:37     ` Junio C Hamano
  2025-07-03 11:32     ` Patrick Steinhardt
  2025-06-19 22:57   ` [GSoC RFC PATCH v2 4/7] repo-info: add the --allow-empty flag Lucas Seiki Oshiro
                     ` (4 subsequent siblings)
  7 siblings, 2 replies; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-06-19 22:57 UTC (permalink / raw)
  To: git; +Cc: ps, karthik.188, ben.knoble, gitster, Lucas Seiki Oshiro
Add 'plaintext' as an output format of repo-info. This output format is
composed zero or more key=value pairs, one per line.
Mentored-by: Karthik Nayak <karthik.188@gmail.com>
Mentored-by Patrick Steinhardt <ps@pks.im>
Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
---
 builtin/repo-info.c  | 12 +++++++++++-
 t/t1900-repo-info.sh |  4 ++++
 2 files changed, 15 insertions(+), 1 deletion(-)
diff --git a/builtin/repo-info.c b/builtin/repo-info.c
index cbe1475e30..cd7c110f47 100644
--- a/builtin/repo-info.c
+++ b/builtin/repo-info.c
@@ -3,7 +3,8 @@
 #include "parse-options.h"
 
 enum output_format {
-	FORMAT_JSON
+	FORMAT_JSON,
+	FORMAT_PLAINTEXT
 };
 
 struct repo_info {
@@ -19,10 +20,16 @@ static void repo_info_init(struct repo_info *repo_info,
 
 	if (format == NULL || !strcmp(format, "json"))
 		repo_info->format = FORMAT_JSON;
+	else if (!strcmp(format, "plaintext"))
+		repo_info->format = FORMAT_PLAINTEXT;
 	else
 		die("invalid format %s", format);
 }
 
+static void repo_info_print_plaintext(struct repo_info *repo_info UNUSED)
+{
+}
+
 static void repo_info_print_json(struct repo_info *repo_info UNUSED)
 {
 	struct json_writer jw;
@@ -44,6 +51,9 @@ static void repo_info_print(struct repo_info *repo_info)
 	case FORMAT_JSON:
 		repo_info_print_json(repo_info);
 		break;
+	case FORMAT_PLAINTEXT:
+		repo_info_print_plaintext(repo_info);
+		break;
 	}
 }
 
diff --git a/t/t1900-repo-info.sh b/t/t1900-repo-info.sh
index f634e1a285..998c835795 100755
--- a/t/t1900-repo-info.sh
+++ b/t/t1900-repo-info.sh
@@ -18,5 +18,9 @@ test_expect_success PERLJSON 'json: returns empty output with allow-empty' '
 	git repo-info --format=json >output &&
 	test_line_count = 2 output
 '
+test_expect_success 'plaintext: returns empty output with allow-empty' '
+	git repo-info --format=plaintext >output &&
+	test_line_count = 0 output
+'
 
 test_done
-- 
2.39.5 (Apple Git-154)
^ permalink raw reply related	[flat|nested] 226+ messages in thread
* [GSoC RFC PATCH v2 4/7] repo-info: add the --allow-empty flag
  2025-06-19 22:57 ` [GSoC RFC PATCH v2 0/7] " Lucas Seiki Oshiro
                     ` (2 preceding siblings ...)
  2025-06-19 22:57   ` [GSoC RFC PATCH v2 3/7] repo-info: add plaintext as an output format Lucas Seiki Oshiro
@ 2025-06-19 22:57   ` Lucas Seiki Oshiro
  2025-06-20  9:54     ` Karthik Nayak
  2025-06-20 21:39     ` Junio C Hamano
  2025-06-19 22:57   ` [GSoC RFC PATCH v2 5/7] repo-info: add the field references.format Lucas Seiki Oshiro
                     ` (3 subsequent siblings)
  7 siblings, 2 replies; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-06-19 22:57 UTC (permalink / raw)
  To: git; +Cc: ps, karthik.188, ben.knoble, gitster, Lucas Seiki Oshiro
Add a flag --allow-empty, which will force the output data to be empty
when no field is requested.
Mentored-by: Karthik Nayak <karthik.188@gmail.com>
Mentored-by Patrick Steinhardt <ps@pks.im>
Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
---
 builtin/repo-info.c  | 3 +++
 t/t1900-repo-info.sh | 5 +++--
 2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/builtin/repo-info.c b/builtin/repo-info.c
index cd7c110f47..6499be0eae 100644
--- a/builtin/repo-info.c
+++ b/builtin/repo-info.c
@@ -68,9 +68,12 @@ int cmd_repo_info(int argc,
 	};
 	struct repo_info repo_info;
 	char *format = NULL;
+	int allow_empty = 0;
 	struct option options[] = {
 		OPT_STRING(0, "format", &format, N_("format"),
 			   N_("output format")),
+		OPT_BOOL(0, "allow-empty", &allow_empty,
+			 "when set, it will use an empty set of fields if no field is requested"),
 		OPT_END()
 	};
 
diff --git a/t/t1900-repo-info.sh b/t/t1900-repo-info.sh
index 998c835795..db4a6aad17 100755
--- a/t/t1900-repo-info.sh
+++ b/t/t1900-repo-info.sh
@@ -15,11 +15,12 @@ test_lazy_prereq PERLJSON '
 '
 
 test_expect_success PERLJSON 'json: returns empty output with allow-empty' '
-	git repo-info --format=json >output &&
+	git repo-info --allow-empty --format=json >output &&
 	test_line_count = 2 output
 '
+
 test_expect_success 'plaintext: returns empty output with allow-empty' '
-	git repo-info --format=plaintext >output &&
+	git repo-info --allow-empty --format=plaintext >output &&
 	test_line_count = 0 output
 '
 
-- 
2.39.5 (Apple Git-154)
^ permalink raw reply related	[flat|nested] 226+ messages in thread
* [GSoC RFC PATCH v2 5/7] repo-info: add the field references.format
  2025-06-19 22:57 ` [GSoC RFC PATCH v2 0/7] " Lucas Seiki Oshiro
                     ` (3 preceding siblings ...)
  2025-06-19 22:57   ` [GSoC RFC PATCH v2 4/7] repo-info: add the --allow-empty flag Lucas Seiki Oshiro
@ 2025-06-19 22:57   ` Lucas Seiki Oshiro
  2025-06-20 22:26     ` Junio C Hamano
                       ` (2 more replies)
  2025-06-19 22:57   ` [GSoC RFC PATCH v2 6/7] repo-info: add field layout.bare Lucas Seiki Oshiro
                     ` (2 subsequent siblings)
  7 siblings, 3 replies; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-06-19 22:57 UTC (permalink / raw)
  To: git; +Cc: ps, karthik.188, ben.knoble, gitster, Lucas Seiki Oshiro
Add the field references.format to the repo-info command. The data
retrieved in this field is the same that currently is obtained by
running `git rev-parse --show-ref-format`.
Mentored-by: Karthik Nayak <karthik.188@gmail.com>
Mentored-by Patrick Steinhardt <ps@pks.im>
Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
---
 builtin/repo-info.c  | 108 +++++++++++++++++++++++++++++++++++++++++--
 t/t1900-repo-info.sh |  58 +++++++++++++++++++++++
 2 files changed, 162 insertions(+), 4 deletions(-)
diff --git a/builtin/repo-info.c b/builtin/repo-info.c
index 6499be0eae..6ce3e6134f 100644
--- a/builtin/repo-info.c
+++ b/builtin/repo-info.c
@@ -1,21 +1,56 @@
 #include "builtin.h"
 #include "json-writer.h"
 #include "parse-options.h"
+#include "quote.h"
+#include "refs.h"
 
 enum output_format {
 	FORMAT_JSON,
 	FORMAT_PLAINTEXT
 };
 
+enum repo_info_category {
+	CATEGORY_REFERENCES = 1 << 0
+};
+
+enum repo_info_references_field {
+	FIELD_REFERENCES_FORMAT = 1 << 0
+};
+
+struct repo_info_field {
+	enum repo_info_category category;
+	union {
+		enum repo_info_references_field references;
+	} field;
+};
+
 struct repo_info {
 	struct repository *repo;
 	enum output_format format;
+	int n_fields;
+	struct repo_info_field *fields;
 };
 
+static struct repo_info_field default_fields[] = {
+	{
+		.category = CATEGORY_REFERENCES,
+		.field.references = FIELD_REFERENCES_FORMAT
+	}
+};
+
+static void print_key_value(const char *key, const char *value) {
+	printf("%s=", key);
+	quote_c_style(value, NULL, stdout, 0);
+	putchar('\n');
+}
+
 static void repo_info_init(struct repo_info *repo_info,
 			   struct repository *repo,
-			   char *format)
+			   char *format,
+			   int allow_empty,
+			   int argc, const char **argv)
 {
+	int i;
 	repo_info->repo = repo;
 
 	if (format == NULL || !strcmp(format, "json"))
@@ -24,19 +59,83 @@ static void repo_info_init(struct repo_info *repo_info,
 		repo_info->format = FORMAT_PLAINTEXT;
 	else
 		die("invalid format %s", format);
+
+	if (argc == 0 && !allow_empty) {
+		repo_info->n_fields = ARRAY_SIZE(default_fields);
+		repo_info->fields = default_fields;
+	} else {
+		repo_info->n_fields = argc;
+		ALLOC_ARRAY(repo_info->fields, argc);
+
+		for (i = 0; i < argc; i++) {
+			const char *arg = argv[i];
+			struct repo_info_field *field = repo_info->fields + i;
+
+			if (!strcmp(arg, "references.format")) {
+				field->category = CATEGORY_REFERENCES;
+				field->field.references = FIELD_REFERENCES_FORMAT;
+			} else {
+				die("invalid field '%s'", arg);
+			}
+		}
+	}
 }
 
-static void repo_info_print_plaintext(struct repo_info *repo_info UNUSED)
+static void repo_info_release(struct repo_info *repo_info)
 {
+	if (repo_info->fields != default_fields) free(repo_info->fields);
 }
 
-static void repo_info_print_json(struct repo_info *repo_info UNUSED)
+static void repo_info_print_plaintext(struct repo_info *repo_info) {
+	struct repository *repo = repo_info->repo;
+	int i;
+	for (i = 0; i < repo_info->n_fields; i++) {
+		struct repo_info_field *field = &repo_info->fields[i];
+		switch (field->category) {
+		case CATEGORY_REFERENCES:
+			switch (field->field.references) {
+			case FIELD_REFERENCES_FORMAT:
+				print_key_value("references.format",
+						ref_storage_format_to_name(
+							repo->ref_storage_format));
+				break;
+			}
+			break;
+		}
+	}
+}
+
+static void repo_info_print_json(struct repo_info *repo_info)
 {
 	struct json_writer jw;
+	int i;
+	unsigned int categories = 0;
+	unsigned int references_fields = 0;
+	struct repository *repo = repo_info->repo;
+
+	for (i = 0; i < repo_info->n_fields; i++) {
+		struct repo_info_field *field = repo_info->fields + i;
+		categories |= field->category;
+		switch (field->category) {
+		case CATEGORY_REFERENCES:
+			references_fields |= field->field.references;
+			break;
+		}
+	}
 
 	jw_init(&jw);
 
 	jw_object_begin(&jw, 1);
+
+	if (categories & CATEGORY_REFERENCES) {
+		jw_object_inline_begin_object(&jw, "references");
+		if (references_fields & FIELD_REFERENCES_FORMAT) {
+			const char *format_name = ref_storage_format_to_name(
+				repo->ref_storage_format);
+			jw_object_string(&jw, "format", format_name);
+		}
+		jw_end(&jw);
+	}
 	jw_end(&jw);
 
 	puts(jw.json.buf);
@@ -79,8 +178,9 @@ int cmd_repo_info(int argc,
 
 	argc = parse_options(argc, argv, prefix, options, repo_info_usage,
 			     PARSE_OPT_KEEP_UNKNOWN_OPT);
-	repo_info_init(&repo_info, repo, format);
+	repo_info_init(&repo_info, repo, format, allow_empty, argc, argv);
 	repo_info_print(&repo_info);
+	repo_info_release(&repo_info);
 
 	return 0;
 }
diff --git a/t/t1900-repo-info.sh b/t/t1900-repo-info.sh
index db4a6aad17..d6e6f6ed1d 100755
--- a/t/t1900-repo-info.sh
+++ b/t/t1900-repo-info.sh
@@ -6,6 +6,8 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
 . ./test-lib.sh
 
+DEFAULT_NUMBER_OF_FIELDS=1
+
 parse_json () {
 	tr '\n' ' ' | "$PERL_PATH" "$TEST_DIRECTORY/t0019/parse_json.perl"
 }
@@ -14,6 +16,45 @@ test_lazy_prereq PERLJSON '
 	perl -MJSON -e "exit 0"
 '
 
+# Test if a field is correctly returned in both plaintext and json formats.
+#
+# Usage: test_repo_info <label> <init command> <key> <expected value>
+#
+# Arguments:
+#   label: the label of the test
+#   init command: a command that creates a repository called 'repo', configured
+#      accordingly to what is being tested
+#   key: the key of the field that is being tested
+#   expected value: the value that the field should contain
+test_repo_info () {
+        label=$1
+        init_command=$2
+        key=$3
+        expected_value=$4
+
+        test_expect_success PERLJSON "json: $label" "
+                test_when_finished 'rm -rf repo' &&
+                '$SHELL_PATH' -c '$init_command' &&
+                cd repo &&
+                echo '$expected_value' >expect &&
+                git repo-info '$key' >output &&
+                cat output | parse_json >parsed &&
+                grep -F 'row[0].$key' parsed | cut -d ' ' -f 2 >value &&
+                cat value | sed 's/^0$/false/' | sed 's/^1$/true/' >actual &&
+                test_cmp expect actual
+        "
+
+        test_expect_success "plaintext: $label" "
+                test_when_finished 'rm -rf repo' &&
+                '$SHELL_PATH' -c '$init_command' &&
+                cd repo &&
+                echo '$expected_value' >expect &&
+                git repo-info --format=plaintext '$key' >output &&
+                cat output | cut -d '=' -f 2 >actual &&
+                test_cmp expect actual
+        "
+}
+
 test_expect_success PERLJSON 'json: returns empty output with allow-empty' '
 	git repo-info --allow-empty --format=json >output &&
 	test_line_count = 2 output
@@ -24,4 +65,21 @@ test_expect_success 'plaintext: returns empty output with allow-empty' '
 	test_line_count = 0 output
 '
 
+test_repo_info 'ref format files is retrieved correctly' '
+	git init --ref-format=files repo' 'references.format' 'files'
+
+test_repo_info 'ref format reftable is retrieved correctly' '
+	git init --ref-format=reftable repo' 'references.format' 'reftable'
+
+test_expect_success 'plaintext: output all default fields' "
+	git repo-info --format=plaintext >actual &&
+	test_line_count = $DEFAULT_NUMBER_OF_FIELDS actual
+"
+
+test_expect_success PERLJSON 'json: output all default fields' "
+	git repo-info --format=json > output &&
+	cat output | parse_json | grep '.*\..*\..*' >actual &&
+	test_line_count = $DEFAULT_NUMBER_OF_FIELDS actual
+"
+
 test_done
-- 
2.39.5 (Apple Git-154)
^ permalink raw reply related	[flat|nested] 226+ messages in thread
* [GSoC RFC PATCH v2 6/7] repo-info: add field layout.bare
  2025-06-19 22:57 ` [GSoC RFC PATCH v2 0/7] " Lucas Seiki Oshiro
                     ` (4 preceding siblings ...)
  2025-06-19 22:57   ` [GSoC RFC PATCH v2 5/7] repo-info: add the field references.format Lucas Seiki Oshiro
@ 2025-06-19 22:57   ` Lucas Seiki Oshiro
  2025-07-03 11:32     ` Patrick Steinhardt
  2025-06-19 22:57   ` [GSoC RFC PATCH v2 7/7] repo-info: add field layout.shallow Lucas Seiki Oshiro
  2025-06-23 13:42   ` [GSoC RFC PATCH v2 0/7] repo-info: add new command for retrieving repository info Phillip Wood
  7 siblings, 1 reply; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-06-19 22:57 UTC (permalink / raw)
  To: git; +Cc: ps, karthik.188, ben.knoble, gitster, Lucas Seiki Oshiro
Add the field layout.bare to the repo-info command. The data
retrieved in this field is the same that currently is obtained by
running `git rev-parse --is-bare-repository`.
Mentored-by: Karthik Nayak <karthik.188@gmail.com>
Mentored-by Patrick Steinhardt <ps@pks.im>
Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
---
 builtin/repo-info.c  | 41 ++++++++++++++++++++++++++++++++++++++++-
 t/t1900-repo-info.sh |  8 +++++++-
 2 files changed, 47 insertions(+), 2 deletions(-)
diff --git a/builtin/repo-info.c b/builtin/repo-info.c
index 6ce3e6134f..1650d3595c 100644
--- a/builtin/repo-info.c
+++ b/builtin/repo-info.c
@@ -1,4 +1,8 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
 #include "builtin.h"
+#include "environment.h"
+#include "hash.h"
 #include "json-writer.h"
 #include "parse-options.h"
 #include "quote.h"
@@ -10,17 +14,23 @@ enum output_format {
 };
 
 enum repo_info_category {
-	CATEGORY_REFERENCES = 1 << 0
+	CATEGORY_REFERENCES = 1 << 0,
+	CATEGORY_LAYOUT = 1 << 1
 };
 
 enum repo_info_references_field {
 	FIELD_REFERENCES_FORMAT = 1 << 0
 };
 
+enum repo_info_layout_field {
+	FIELD_LAYOUT_BARE = 1 << 0
+};
+
 struct repo_info_field {
 	enum repo_info_category category;
 	union {
 		enum repo_info_references_field references;
+		enum repo_info_layout_field layout;
 	} field;
 };
 
@@ -35,6 +45,10 @@ static struct repo_info_field default_fields[] = {
 	{
 		.category = CATEGORY_REFERENCES,
 		.field.references = FIELD_REFERENCES_FORMAT
+	},
+	{
+		.category = CATEGORY_LAYOUT,
+		.field.layout = FIELD_LAYOUT_BARE
 	}
 };
 
@@ -74,6 +88,9 @@ static void repo_info_init(struct repo_info *repo_info,
 			if (!strcmp(arg, "references.format")) {
 				field->category = CATEGORY_REFERENCES;
 				field->field.references = FIELD_REFERENCES_FORMAT;
+			} else if (!strcmp(arg, "layout.bare")) {
+				field->category = CATEGORY_LAYOUT;
+				field->field.layout = FIELD_LAYOUT_BARE;
 			} else {
 				die("invalid field '%s'", arg);
 			}
@@ -101,6 +118,15 @@ static void repo_info_print_plaintext(struct repo_info *repo_info) {
 				break;
 			}
 			break;
+		case CATEGORY_LAYOUT:
+			switch (field->field.layout) {
+			case FIELD_LAYOUT_BARE:
+				print_key_value("layout.bare",
+						is_bare_repository() ?
+							"true" : "false");
+				break;
+			}
+			break;
 		}
 	}
 }
@@ -111,6 +137,7 @@ static void repo_info_print_json(struct repo_info *repo_info)
 	int i;
 	unsigned int categories = 0;
 	unsigned int references_fields = 0;
+	unsigned int layout_fields = 0;
 	struct repository *repo = repo_info->repo;
 
 	for (i = 0; i < repo_info->n_fields; i++) {
@@ -120,6 +147,9 @@ static void repo_info_print_json(struct repo_info *repo_info)
 		case CATEGORY_REFERENCES:
 			references_fields |= field->field.references;
 			break;
+		case CATEGORY_LAYOUT:
+			layout_fields |= field->field.layout;
+			break;
 		}
 	}
 
@@ -136,6 +166,15 @@ static void repo_info_print_json(struct repo_info *repo_info)
 		}
 		jw_end(&jw);
 	}
+
+	if (categories & CATEGORY_LAYOUT) {
+		jw_object_inline_begin_object(&jw, "layout");
+		if (layout_fields & FIELD_LAYOUT_BARE) {
+			jw_object_bool(&jw, "bare",
+				       is_bare_repository());
+		}
+		jw_end(&jw);
+	}
 	jw_end(&jw);
 
 	puts(jw.json.buf);
diff --git a/t/t1900-repo-info.sh b/t/t1900-repo-info.sh
index d6e6f6ed1d..0d1096b40b 100755
--- a/t/t1900-repo-info.sh
+++ b/t/t1900-repo-info.sh
@@ -6,7 +6,7 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
 . ./test-lib.sh
 
-DEFAULT_NUMBER_OF_FIELDS=1
+DEFAULT_NUMBER_OF_FIELDS=2
 
 parse_json () {
 	tr '\n' ' ' | "$PERL_PATH" "$TEST_DIRECTORY/t0019/parse_json.perl"
@@ -71,6 +71,12 @@ test_repo_info 'ref format files is retrieved correctly' '
 test_repo_info 'ref format reftable is retrieved correctly' '
 	git init --ref-format=reftable repo' 'references.format' 'reftable'
 
+test_repo_info 'bare repository = false is retrieved correctly' '
+	git init repo' 'layout.bare' 'false'
+
+test_repo_info 'bare repository = true is retrieved correctly' '
+	git init --bare repo' 'layout.bare' 'true'
+
 test_expect_success 'plaintext: output all default fields' "
 	git repo-info --format=plaintext >actual &&
 	test_line_count = $DEFAULT_NUMBER_OF_FIELDS actual
-- 
2.39.5 (Apple Git-154)
^ permalink raw reply related	[flat|nested] 226+ messages in thread
* [GSoC RFC PATCH v2 7/7] repo-info: add field layout.shallow
  2025-06-19 22:57 ` [GSoC RFC PATCH v2 0/7] " Lucas Seiki Oshiro
                     ` (5 preceding siblings ...)
  2025-06-19 22:57   ` [GSoC RFC PATCH v2 6/7] repo-info: add field layout.bare Lucas Seiki Oshiro
@ 2025-06-19 22:57   ` Lucas Seiki Oshiro
  2025-06-23 13:42   ` [GSoC RFC PATCH v2 0/7] repo-info: add new command for retrieving repository info Phillip Wood
  7 siblings, 0 replies; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-06-19 22:57 UTC (permalink / raw)
  To: git; +Cc: ps, karthik.188, ben.knoble, gitster, Lucas Seiki Oshiro
Add the field layout.shallow to the repo-info command. The data
retrieved in this field is the same that currently is obtained by
running `git rev-parse --is-shallow-repository`.
Mentored-by: Karthik Nayak <karthik.188@gmail.com>
Mentored-by Patrick Steinhardt <ps@pks.im>
Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
---
 builtin/repo-info.c  | 21 ++++++++++++++++++++-
 t/t1900-repo-info.sh | 16 +++++++++++++++-
 2 files changed, 35 insertions(+), 2 deletions(-)
diff --git a/builtin/repo-info.c b/builtin/repo-info.c
index 1650d3595c..4c265c05fa 100644
--- a/builtin/repo-info.c
+++ b/builtin/repo-info.c
@@ -7,6 +7,7 @@
 #include "parse-options.h"
 #include "quote.h"
 #include "refs.h"
+#include "shallow.h"
 
 enum output_format {
 	FORMAT_JSON,
@@ -23,7 +24,8 @@ enum repo_info_references_field {
 };
 
 enum repo_info_layout_field {
-	FIELD_LAYOUT_BARE = 1 << 0
+	FIELD_LAYOUT_BARE = 1 << 0,
+	FIELD_LAYOUT_SHALLOW = 1 << 1
 };
 
 struct repo_info_field {
@@ -49,6 +51,10 @@ static struct repo_info_field default_fields[] = {
 	{
 		.category = CATEGORY_LAYOUT,
 		.field.layout = FIELD_LAYOUT_BARE
+	},
+	{
+		.category = CATEGORY_LAYOUT,
+		.field.layout = FIELD_LAYOUT_SHALLOW
 	}
 };
 
@@ -91,6 +97,9 @@ static void repo_info_init(struct repo_info *repo_info,
 			} else if (!strcmp(arg, "layout.bare")) {
 				field->category = CATEGORY_LAYOUT;
 				field->field.layout = FIELD_LAYOUT_BARE;
+			} else if (!strcmp(arg, "layout.shallow")) {
+				field->category = CATEGORY_LAYOUT;
+				field->field.layout = FIELD_LAYOUT_SHALLOW;
 			} else {
 				die("invalid field '%s'", arg);
 			}
@@ -125,6 +134,11 @@ static void repo_info_print_plaintext(struct repo_info *repo_info) {
 						is_bare_repository() ?
 							"true" : "false");
 				break;
+			case FIELD_LAYOUT_SHALLOW:
+				print_key_value("layout.shallow",
+						is_repository_shallow(repo) ?
+							"true" : "false");
+				break;
 			}
 			break;
 		}
@@ -173,6 +187,11 @@ static void repo_info_print_json(struct repo_info *repo_info)
 			jw_object_bool(&jw, "bare",
 				       is_bare_repository());
 		}
+
+		if (layout_fields & FIELD_LAYOUT_SHALLOW) {
+			jw_object_bool(&jw, "shallow",
+				       is_repository_shallow(repo));
+		}
 		jw_end(&jw);
 	}
 	jw_end(&jw);
diff --git a/t/t1900-repo-info.sh b/t/t1900-repo-info.sh
index 0d1096b40b..5cd2f8d187 100755
--- a/t/t1900-repo-info.sh
+++ b/t/t1900-repo-info.sh
@@ -6,7 +6,7 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
 . ./test-lib.sh
 
-DEFAULT_NUMBER_OF_FIELDS=2
+DEFAULT_NUMBER_OF_FIELDS=3
 
 parse_json () {
 	tr '\n' ' ' | "$PERL_PATH" "$TEST_DIRECTORY/t0019/parse_json.perl"
@@ -77,6 +77,20 @@ test_repo_info 'bare repository = false is retrieved correctly' '
 test_repo_info 'bare repository = true is retrieved correctly' '
 	git init --bare repo' 'layout.bare' 'true'
 
+test_repo_info 'shallow repository = false is retrieved correctly' '
+	git init repo' 'layout.shallow' 'false'
+
+test_repo_info 'shallow repository = true is retrieved correctly' '
+	git init remote &&
+	cd remote &&
+	echo x >x &&
+	git add x &&
+	git commit -m x &&
+	cd .. &&
+	git clone --depth 1 "file://$PWD/remote" repo &&
+	rm -rf remote
+	' 'layout.shallow' 'true'
+
 test_expect_success 'plaintext: output all default fields' "
 	git repo-info --format=plaintext >actual &&
 	test_line_count = $DEFAULT_NUMBER_OF_FIELDS actual
-- 
2.39.5 (Apple Git-154)
^ permalink raw reply related	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH v2 1/7] repo-info: declare the repo-info command
  2025-06-19 22:57   ` [GSoC RFC PATCH v2 1/7] repo-info: declare the repo-info command Lucas Seiki Oshiro
@ 2025-06-20  7:36     ` Karthik Nayak
  2025-06-20 23:55       ` Junio C Hamano
  2025-06-23 19:04       ` Lucas Seiki Oshiro
  2025-06-20  7:56     ` Karthik Nayak
                       ` (2 subsequent siblings)
  3 siblings, 2 replies; 226+ messages in thread
From: Karthik Nayak @ 2025-06-20  7:36 UTC (permalink / raw)
  To: Lucas Seiki Oshiro, git; +Cc: ps, ben.knoble, gitster
[-- Attachment #1: Type: text/plain, Size: 1162 bytes --]
Lucas Seiki Oshiro <lucasseikioshiro@gmail.com> writes:
> Create a new Git subcommand called repo-info. `git repo-info` will query
> metadata from the current repository and outputs it as JSON or plaintext.
>
> Also add entries for this new command in:
>
> - the build files (Makefile and meson.build)
> - builtin.h
> - git.c
> - .gitignore
>
> In option parsing, use PARSE_OPT_KEEP_UNKNOWN_OPT to allow the users
> specify after the flags the information that they want to retrieve.
>
> Mentored-by: Karthik Nayak <karthik.188@gmail.com>
> Mentored-by Patrick Steinhardt <ps@pks.im>
> Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
> ---
>  .gitignore          |  1 +
>  Makefile            |  1 +
>  builtin.h           |  1 +
>  builtin/repo-info.c | 21 +++++++++++++++++++++
>  git.c               |  1 +
>  meson.build         |  1 +
>  6 files changed, 26 insertions(+)
>  create mode 100644 builtin/repo-info.c
>
Something I mentioned in the previous review, but hasn't been addressed
is the addition of documentation for the new command. With each patch
modifying the command, it would be also nice to add the respective
documentation.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 690 bytes --]
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH v2 1/7] repo-info: declare the repo-info command
  2025-06-19 22:57   ` [GSoC RFC PATCH v2 1/7] repo-info: declare the repo-info command Lucas Seiki Oshiro
  2025-06-20  7:36     ` Karthik Nayak
@ 2025-06-20  7:56     ` Karthik Nayak
  2025-06-24 14:03     ` Phillip Wood
  2025-07-03 11:31     ` Patrick Steinhardt
  3 siblings, 0 replies; 226+ messages in thread
From: Karthik Nayak @ 2025-06-20  7:56 UTC (permalink / raw)
  To: Lucas Seiki Oshiro, git; +Cc: ps, ben.knoble, gitster
[-- Attachment #1: Type: text/plain, Size: 907 bytes --]
Lucas Seiki Oshiro <lucasseikioshiro@gmail.com> writes:
> Create a new Git subcommand called repo-info. `git repo-info` will query
> metadata from the current repository and outputs it as JSON or plaintext.
>
> Also add entries for this new command in:
>
> - the build files (Makefile and meson.build)
> - builtin.h
> - git.c
> - .gitignore
>
> In option parsing, use PARSE_OPT_KEEP_UNKNOWN_OPT to allow the users
> specify after the flags the information that they want to retrieve.
>
Something I would really recommend in all the commits is to be a lot
more descriptive about _why_ are we even making these changes.
In this case, it would be great to mention about 'git-rev-parse(1)' and
the motivation of adding this new command. That would provide some much
needed context about why we are even adding this new command. Also worth
mentioning is why we plan to output in JSON or plaintext.
- Karthik
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 690 bytes --]
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH v2 2/7] repo-info: add the --format flag
  2025-06-19 22:57   ` [GSoC RFC PATCH v2 2/7] repo-info: add the --format flag Lucas Seiki Oshiro
@ 2025-06-20  8:06     ` Karthik Nayak
  2025-06-20 21:31     ` Junio C Hamano
  2025-07-03 11:31     ` Patrick Steinhardt
  2 siblings, 0 replies; 226+ messages in thread
From: Karthik Nayak @ 2025-06-20  8:06 UTC (permalink / raw)
  To: Lucas Seiki Oshiro, git; +Cc: ps, ben.knoble, gitster
[-- Attachment #1: Type: text/plain, Size: 1444 bytes --]
Lucas Seiki Oshiro <lucasseikioshiro@gmail.com> writes:
> Add the --format flag to the repo-info command, allowing the user to
> choose between output formats. Use 'json' by default.
Similarly here, it would be nice to mention why we add 'json' formatting
and why it is the default.
[snip]
> diff --git a/t/meson.build b/t/meson.build
> index 50e89e764a..d9ecaba3b7 100644
> --- a/t/meson.build
> +++ b/t/meson.build
> @@ -246,6 +246,7 @@ integration_tests = [
>    't1700-split-index.sh',
>    't1701-racy-split-index.sh',
>    't1800-hook.sh',
> +  't1900-repo-info.sh',
>    't2000-conflict-when-checking-files-out.sh',
>    't2002-checkout-cache-u.sh',
>    't2003-checkout-cache-mkdir.sh',
> diff --git a/t/t1900-repo-info.sh b/t/t1900-repo-info.sh
> new file mode 100755
> index 0000000000..f634e1a285
> --- /dev/null
> +++ b/t/t1900-repo-info.sh
> @@ -0,0 +1,22 @@
> +#!/bin/sh
> +
> +test_description='test git repo-info'
> +GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
> +export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
> +
> +. ./test-lib.sh
> +
> +parse_json () {
> +	tr '\n' ' ' | "$PERL_PATH" "$TEST_DIRECTORY/t0019/parse_json.perl"
> +}
> +
> +test_lazy_prereq PERLJSON '
> +	perl -MJSON -e "exit 0"
> +'
> +
> +test_expect_success PERLJSON 'json: returns empty output with allow-empty' '
Huh. Where is allow-empty being used? and why in this patch?
> +	git repo-info --format=json >output &&
> +	test_line_count = 2 output
> +'
>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 690 bytes --]
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH v2 4/7] repo-info: add the --allow-empty flag
  2025-06-19 22:57   ` [GSoC RFC PATCH v2 4/7] repo-info: add the --allow-empty flag Lucas Seiki Oshiro
@ 2025-06-20  9:54     ` Karthik Nayak
  2025-06-23  2:39       ` Lucas Seiki Oshiro
  2025-06-20 21:39     ` Junio C Hamano
  1 sibling, 1 reply; 226+ messages in thread
From: Karthik Nayak @ 2025-06-20  9:54 UTC (permalink / raw)
  To: Lucas Seiki Oshiro, git; +Cc: ps, ben.knoble, gitster
[-- Attachment #1: Type: text/plain, Size: 1278 bytes --]
Lucas Seiki Oshiro <lucasseikioshiro@gmail.com> writes:
> Add a flag --allow-empty, which will force the output data to be empty
> when no field is requested.
>
While you did reply to my previous question about this flag. This patch
doesn't sell the need for it in anyway.
So we need:
1. More description in the commit messages about why we need this flag
and how it is useful.
2. Documentation around the same.
I still think this is early for this, and we should add this flag later
if the need arises.
[snip]
> diff --git a/t/t1900-repo-info.sh b/t/t1900-repo-info.sh
> index 998c835795..db4a6aad17 100755
> --- a/t/t1900-repo-info.sh
> +++ b/t/t1900-repo-info.sh
> @@ -15,11 +15,12 @@ test_lazy_prereq PERLJSON '
>  '
>
>  test_expect_success PERLJSON 'json: returns empty output with allow-empty' '
> -	git repo-info --format=json >output &&
> +	git repo-info --allow-empty --format=json >output &&
>  	test_line_count = 2 output
>  '
> +
>  test_expect_success 'plaintext: returns empty output with allow-empty' '
> -	git repo-info --format=plaintext >output &&
> +	git repo-info --allow-empty --format=plaintext >output &&
>  	test_line_count = 0 output
>  '
The earlier patches reference allow-empty without really talking about
it. Which feels odd and misplaced.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 690 bytes --]
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH v2 2/7] repo-info: add the --format flag
  2025-06-19 22:57   ` [GSoC RFC PATCH v2 2/7] repo-info: add the --format flag Lucas Seiki Oshiro
  2025-06-20  8:06     ` Karthik Nayak
@ 2025-06-20 21:31     ` Junio C Hamano
  2025-07-03 11:31     ` Patrick Steinhardt
  2 siblings, 0 replies; 226+ messages in thread
From: Junio C Hamano @ 2025-06-20 21:31 UTC (permalink / raw)
  To: Lucas Seiki Oshiro; +Cc: git, ps, karthik.188, ben.knoble
Lucas Seiki Oshiro <lucasseikioshiro@gmail.com> writes:
> Add the --format flag to the repo-info command, allowing the user to
> choose between output formats. Use 'json' by default.
>
> Mentored-by: Karthik Nayak <karthik.188@gmail.com>
> Mentored-by Patrick Steinhardt <ps@pks.im>
> Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
> ---
>  builtin/repo-info.c  | 54 +++++++++++++++++++++++++++++++++++++++++++-
>  t/meson.build        |  1 +
>  t/t1900-repo-info.sh | 22 ++++++++++++++++++
>  3 files changed, 76 insertions(+), 1 deletion(-)
>  create mode 100755 t/t1900-repo-info.sh
>
> diff --git a/builtin/repo-info.c b/builtin/repo-info.c
> index a5c43e253f..cbe1475e30 100644
> --- a/builtin/repo-info.c
> +++ b/builtin/repo-info.c
> @@ -1,21 +1,73 @@
>  #include "builtin.h"
> +#include "json-writer.h"
>  #include "parse-options.h"
>  
> +enum output_format {
> +	FORMAT_JSON
> +};
If you give a trailing comma after FORMAT_JSON here, then a future
step that adds other values to the enum would not have to touch this
line, e.g. instead of
     enum output_format {
    -    FORMAT_JSON
    +    FORMAT_JSON,
    +    FORMAT_FOO
     };
you can do this
     enum output_format {
         FORMAT_JSON,
    +    FORMAT_FOO,
     };
when you add a new value "FOO" to enum.
cf. Documentation/CodingGuidelines
   . since early 2012 with e1327023ea, we have been using an enum
     definition whose last element is followed by a comma.  This, like
     an array initializer that ends with a trailing comma, can be used
     to reduce the patch noise when adding a new identifier at the end.
> +struct repo_info {
> +	struct repository *repo;
> +	enum output_format format;
> +};
> +
> +static void repo_info_init(struct repo_info *repo_info,
> +			   struct repository *repo,
> +			   char *format)
> +{
> +	repo_info->repo = repo;
> +
> +	if (format == NULL || !strcmp(format, "json"))
> +		repo_info->format = FORMAT_JSON;
> +	else
> +		die("invalid format %s", format);
> +}
> +
> +static void repo_info_print_json(struct repo_info *repo_info UNUSED)
> +{
> +	struct json_writer jw;
> +
> +	jw_init(&jw);
> +
> +	jw_object_begin(&jw, 1);
> +	jw_end(&jw);
> +
> +	puts(jw.json.buf);
> +	jw_release(&jw);
> +}
> +
> +static void repo_info_print(struct repo_info *repo_info)
> +{
> +	enum output_format format = repo_info->format;
> +
> +	switch (format) {
> +	case FORMAT_JSON:
> +		repo_info_print_json(repo_info);
> +		break;
> +	}
> +}
> +
>  int cmd_repo_info(int argc,
>  		  const char **argv,
>  		  const char *prefix,
> -		  struct repository *repo UNUSED)
> +		  struct repository *repo)
>  {
>  	const char *const repo_info_usage[] = {
>  		"git repo-info",
>  		NULL
>  	};
> +	struct repo_info repo_info;
> +	char *format = NULL;
>  	struct option options[] = {
> +		OPT_STRING(0, "format", &format, N_("format"),
> +			   N_("output format")),
>  		OPT_END()
>  	};
>  
>  	argc = parse_options(argc, argv, prefix, options, repo_info_usage,
>  			     PARSE_OPT_KEEP_UNKNOWN_OPT);
> +	repo_info_init(&repo_info, repo, format);
> +	repo_info_print(&repo_info);
>  
>  	return 0;
>  }
> diff --git a/t/meson.build b/t/meson.build
> index 50e89e764a..d9ecaba3b7 100644
> --- a/t/meson.build
> +++ b/t/meson.build
> @@ -246,6 +246,7 @@ integration_tests = [
>    't1700-split-index.sh',
>    't1701-racy-split-index.sh',
>    't1800-hook.sh',
> +  't1900-repo-info.sh',
>    't2000-conflict-when-checking-files-out.sh',
>    't2002-checkout-cache-u.sh',
>    't2003-checkout-cache-mkdir.sh',
> diff --git a/t/t1900-repo-info.sh b/t/t1900-repo-info.sh
> new file mode 100755
> index 0000000000..f634e1a285
> --- /dev/null
> +++ b/t/t1900-repo-info.sh
> @@ -0,0 +1,22 @@
> +#!/bin/sh
> +
> +test_description='test git repo-info'
> +GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
> +export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
> +
> +. ./test-lib.sh
> +
> +parse_json () {
> +	tr '\n' ' ' | "$PERL_PATH" "$TEST_DIRECTORY/t0019/parse_json.perl"
> +}
> +
> +test_lazy_prereq PERLJSON '
> +	perl -MJSON -e "exit 0"
> +'
> +
> +test_expect_success PERLJSON 'json: returns empty output with allow-empty' '
Allow-empty?
Instead of "if no command line args, list everything, or show only
the ones specified on the command line", wouldn't it be far easier
to explain if you made it "we show only the ones specified on the
command line, but giving '--all' on the command line behaves as if
you listed all the ones known to us on the command line"?
> +	git repo-info --format=json >output &&
> +	test_line_count = 2 output
> +'
> +
> +test_done
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH v2 3/7] repo-info: add plaintext as an output format
  2025-06-19 22:57   ` [GSoC RFC PATCH v2 3/7] repo-info: add plaintext as an output format Lucas Seiki Oshiro
@ 2025-06-20 21:37     ` Junio C Hamano
  2025-07-03 11:32     ` Patrick Steinhardt
  1 sibling, 0 replies; 226+ messages in thread
From: Junio C Hamano @ 2025-06-20 21:37 UTC (permalink / raw)
  To: Lucas Seiki Oshiro; +Cc: git, ps, karthik.188, ben.knoble
Lucas Seiki Oshiro <lucasseikioshiro@gmail.com> writes:
> Add 'plaintext' as an output format of repo-info. This output format is
> composed zero or more key=value pairs, one per line.
>
> Mentored-by: Karthik Nayak <karthik.188@gmail.com>
> Mentored-by Patrick Steinhardt <ps@pks.im>
> Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
> ---
>  builtin/repo-info.c  | 12 +++++++++++-
>  t/t1900-repo-info.sh |  4 ++++
>  2 files changed, 15 insertions(+), 1 deletion(-)
>
> diff --git a/builtin/repo-info.c b/builtin/repo-info.c
> index cbe1475e30..cd7c110f47 100644
> --- a/builtin/repo-info.c
> +++ b/builtin/repo-info.c
> @@ -3,7 +3,8 @@
>  #include "parse-options.h"
>  
>  enum output_format {
> -	FORMAT_JSON
> +	FORMAT_JSON,
> +	FORMAT_PLAINTEXT
>  };
Give a trailing comma after "_PLAINTEXT".
>  struct repo_info {
> @@ -19,10 +20,16 @@ static void repo_info_init(struct repo_info *repo_info,
>  
>  	if (format == NULL || !strcmp(format, "json"))
>  		repo_info->format = FORMAT_JSON;
It is somewhat strange for this helper function deciding/hardcoding
what the default format is.  Would it make it easier to understand
if you lost "if given NULL, use JSON" from here, and instead
initialize the local variable format to "json" in cmd_repo_info()?
> +	else if (!strcmp(format, "plaintext"))
> +		repo_info->format = FORMAT_PLAINTEXT;
>  	else
>  		die("invalid format %s", format);
>  }
>  
> +static void repo_info_print_plaintext(struct repo_info *repo_info UNUSED)
> +{
> +}
> +
>  static void repo_info_print_json(struct repo_info *repo_info UNUSED)
>  {
>  	struct json_writer jw;
> @@ -44,6 +51,9 @@ static void repo_info_print(struct repo_info *repo_info)
>  	case FORMAT_JSON:
>  		repo_info_print_json(repo_info);
>  		break;
> +	case FORMAT_PLAINTEXT:
> +		repo_info_print_plaintext(repo_info);
> +		break;
>  	}
>  }
>  
> diff --git a/t/t1900-repo-info.sh b/t/t1900-repo-info.sh
> index f634e1a285..998c835795 100755
> --- a/t/t1900-repo-info.sh
> +++ b/t/t1900-repo-info.sh
> @@ -18,5 +18,9 @@ test_expect_success PERLJSON 'json: returns empty output with allow-empty' '
>  	git repo-info --format=json >output &&
>  	test_line_count = 2 output
>  '
> +test_expect_success 'plaintext: returns empty output with allow-empty' '
allow-empty?
> +	git repo-info --format=plaintext >output &&
> +	test_line_count = 0 output
> +'
In any case, I do not know if it makes sense to add this test before
you have a single line of repo_info_print_plaintext() implemented.
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH v2 4/7] repo-info: add the --allow-empty flag
  2025-06-19 22:57   ` [GSoC RFC PATCH v2 4/7] repo-info: add the --allow-empty flag Lucas Seiki Oshiro
  2025-06-20  9:54     ` Karthik Nayak
@ 2025-06-20 21:39     ` Junio C Hamano
  2025-06-23  9:26       ` Karthik Nayak
  1 sibling, 1 reply; 226+ messages in thread
From: Junio C Hamano @ 2025-06-20 21:39 UTC (permalink / raw)
  To: Lucas Seiki Oshiro; +Cc: git, ps, karthik.188, ben.knoble
Lucas Seiki Oshiro <lucasseikioshiro@gmail.com> writes:
> Add a flag --allow-empty, which will force the output data to be empty
> when no field is requested.
I still think we should flip the polarity of the option and give "--all"
to iterate over all variables, and by default show nothing.
> Mentored-by: Karthik Nayak <karthik.188@gmail.com>
> Mentored-by Patrick Steinhardt <ps@pks.im>
> Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
> ---
>  builtin/repo-info.c  | 3 +++
>  t/t1900-repo-info.sh | 5 +++--
>  2 files changed, 6 insertions(+), 2 deletions(-)
>
> diff --git a/builtin/repo-info.c b/builtin/repo-info.c
> index cd7c110f47..6499be0eae 100644
> --- a/builtin/repo-info.c
> +++ b/builtin/repo-info.c
> @@ -68,9 +68,12 @@ int cmd_repo_info(int argc,
>  	};
>  	struct repo_info repo_info;
>  	char *format = NULL;
> +	int allow_empty = 0;
>  	struct option options[] = {
>  		OPT_STRING(0, "format", &format, N_("format"),
>  			   N_("output format")),
> +		OPT_BOOL(0, "allow-empty", &allow_empty,
> +			 "when set, it will use an empty set of fields if no field is requested"),
>  		OPT_END()
>  	};
>  
> diff --git a/t/t1900-repo-info.sh b/t/t1900-repo-info.sh
> index 998c835795..db4a6aad17 100755
> --- a/t/t1900-repo-info.sh
> +++ b/t/t1900-repo-info.sh
> @@ -15,11 +15,12 @@ test_lazy_prereq PERLJSON '
>  '
>  
>  test_expect_success PERLJSON 'json: returns empty output with allow-empty' '
> -	git repo-info --format=json >output &&
> +	git repo-info --allow-empty --format=json >output &&
>  	test_line_count = 2 output
>  '
> +
>  test_expect_success 'plaintext: returns empty output with allow-empty' '
> -	git repo-info --format=plaintext >output &&
> +	git repo-info --allow-empty --format=plaintext >output &&
>  	test_line_count = 0 output
>  '
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH v2 5/7] repo-info: add the field references.format
  2025-06-19 22:57   ` [GSoC RFC PATCH v2 5/7] repo-info: add the field references.format Lucas Seiki Oshiro
@ 2025-06-20 22:26     ` Junio C Hamano
  2025-06-24 14:03     ` Phillip Wood
  2025-07-03 11:32     ` Patrick Steinhardt
  2 siblings, 0 replies; 226+ messages in thread
From: Junio C Hamano @ 2025-06-20 22:26 UTC (permalink / raw)
  To: Lucas Seiki Oshiro; +Cc: git, ps, karthik.188, ben.knoble
Lucas Seiki Oshiro <lucasseikioshiro@gmail.com> writes:
> Add the field references.format to the repo-info command. The data
> retrieved in this field is the same that currently is obtained by
> running `git rev-parse --show-ref-format`.
>
> Mentored-by: Karthik Nayak <karthik.188@gmail.com>
> Mentored-by Patrick Steinhardt <ps@pks.im>
> Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
> ---
>  builtin/repo-info.c  | 108 +++++++++++++++++++++++++++++++++++++++++--
>  t/t1900-repo-info.sh |  58 +++++++++++++++++++++++
>  2 files changed, 162 insertions(+), 4 deletions(-)
>
> diff --git a/builtin/repo-info.c b/builtin/repo-info.c
> index 6499be0eae..6ce3e6134f 100644
> --- a/builtin/repo-info.c
> +++ b/builtin/repo-info.c
> @@ -1,21 +1,56 @@
>  #include "builtin.h"
>  #include "json-writer.h"
>  #include "parse-options.h"
> +#include "quote.h"
> +#include "refs.h"
>  
>  enum output_format {
>  	FORMAT_JSON,
>  	FORMAT_PLAINTEXT
>  };
>  
> +enum repo_info_category {
> +	CATEGORY_REFERENCES = 1 << 0
> +};
> +
> +enum repo_info_references_field {
> +	FIELD_REFERENCES_FORMAT = 1 << 0
> +};
> +
> +struct repo_info_field {
> +	enum repo_info_category category;
> +	union {
> +		enum repo_info_references_field references;
> +	} field;
> +};
Are we going to gain more than one union in this struct?  If not,
name the union simply 'u', so that the accesses look like
"info.u.references" instead of "info.field.references".  In that
construct, a long name ".field" does not add much information value
anyway---the member in the union, like "references", is where all
the information value is.
>  struct repo_info {
>  	struct repository *repo;
>  	enum output_format format;
> +	int n_fields;
> +	struct repo_info_field *fields;
>  };
>  
> +static struct repo_info_field default_fields[] = {
> +	{
> +		.category = CATEGORY_REFERENCES,
> +		.field.references = FIELD_REFERENCES_FORMAT
> +	}
> +};
> +
> +static void print_key_value(const char *key, const char *value) {
> +	printf("%s=", key);
> +	quote_c_style(value, NULL, stdout, 0);
> +	putchar('\n');
> +}
> +
>  static void repo_info_init(struct repo_info *repo_info,
>  			   struct repository *repo,
> -			   char *format)
> +			   char *format,
> +			   int allow_empty,
> +			   int argc, const char **argv)
>  {
> +	int i;
>  	repo_info->repo = repo;
>  
>  	if (format == NULL || !strcmp(format, "json"))
> @@ -24,19 +59,83 @@ static void repo_info_init(struct repo_info *repo_info,
>  		repo_info->format = FORMAT_PLAINTEXT;
>  	else
>  		die("invalid format %s", format);
> +
> +	if (argc == 0 && !allow_empty) {
> +		repo_info->n_fields = ARRAY_SIZE(default_fields);
> +		repo_info->fields = default_fields;
> +	} else {
> +		repo_info->n_fields = argc;
> +		ALLOC_ARRAY(repo_info->fields, argc);
> +
> +		for (i = 0; i < argc; i++) {
> +			const char *arg = argv[i];
> +			struct repo_info_field *field = repo_info->fields + i;
> +
> +			if (!strcmp(arg, "references.format")) {
> +				field->category = CATEGORY_REFERENCES;
> +				field->field.references = FIELD_REFERENCES_FORMAT;
Are we going to have duplicate information between this
if/elseif/... cascade and the default_fields[] array?
There needs a catalog of "everything we support" somewhere, which
can be used to determine what "--all" should show, whose entry can
be looked up with the textual name (like "references.format") for
the purpose of command line parsing.  Once you have such a
"everything we support" table, this parser loop and "--all" handling
can become more table-driven.
> -static void repo_info_print_plaintext(struct repo_info *repo_info UNUSED)
> +static void repo_info_release(struct repo_info *repo_info)
>  {
> +	if (repo_info->fields != default_fields) free(repo_info->fields);
Do not write if() and its body on the same line.
>  }
>  
> -static void repo_info_print_json(struct repo_info *repo_info UNUSED)
> +static void repo_info_print_plaintext(struct repo_info *repo_info) {
> +	struct repository *repo = repo_info->repo;
> +	int i;
> +	for (i = 0; i < repo_info->n_fields; i++) {
> +		struct repo_info_field *field = &repo_info->fields[i];
> +		switch (field->category) {
> +		case CATEGORY_REFERENCES:
> +			switch (field->field.references) {
> +			case FIELD_REFERENCES_FORMAT:
> +				print_key_value("references.format",
> +						ref_storage_format_to_name(
> +							repo->ref_storage_format));
> +				break;
> +			}
> +			break;
> +		}
Can't this also be made more table driven, by having a callback
function pointer in the "everything we support" table?  That way,
this deeply nested loop does not have to be here and you do not have
to chomp a line that is overly deeply nested in the middle just to
go under 80-column limit.
IOW, the above code may become something like:
	for (int i = 0; i < repo_info->n_fields; i++) {
		struct repo_info_field *f = &repo_info->fields[i];
                f->show(repo_info, f);
	}
and the repo_info_field structure may have a pointer to the
implementation of "show" method for that particular type, which may
look like
        static void show_references_format(struct repo_info *i,
                                           struct repo_info_field *f)
        {
                struct repository *repo = i->repo;
                enum ref_storage_format fmt = repo->ref_storage_format;
                const char *name = ref_storage_format_to_name(fmt); 
                print_key_value("references.format", name);
        }
Hmm?
I'll stop here for now.
Thanks.
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH v2 1/7] repo-info: declare the repo-info command
  2025-06-20  7:36     ` Karthik Nayak
@ 2025-06-20 23:55       ` Junio C Hamano
  2025-06-23  9:19         ` Karthik Nayak
  2025-06-23 19:04       ` Lucas Seiki Oshiro
  1 sibling, 1 reply; 226+ messages in thread
From: Junio C Hamano @ 2025-06-20 23:55 UTC (permalink / raw)
  To: Karthik Nayak; +Cc: Lucas Seiki Oshiro, git, ps, ben.knoble
Karthik Nayak <karthik.188@gmail.com> writes:
>>  .gitignore          |  1 +
>>  Makefile            |  1 +
>>  builtin.h           |  1 +
>>  builtin/repo-info.c | 21 +++++++++++++++++++++
>>  git.c               |  1 +
>>  meson.build         |  1 +
>>  6 files changed, 26 insertions(+)
>>  create mode 100644 builtin/repo-info.c
>>
>
> Something I mentioned in the previous review, but hasn't been addressed
> is the addition of documentation for the new command. With each patch
> modifying the command, it would be also nice to add the respective
> documentation.
Bsdies, the lack of Documentation/repo-info.adoc causes "make check-docs"
fail.
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH v2 4/7] repo-info: add the --allow-empty flag
  2025-06-20  9:54     ` Karthik Nayak
@ 2025-06-23  2:39       ` Lucas Seiki Oshiro
  0 siblings, 0 replies; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-06-23  2:39 UTC (permalink / raw)
  To: Karthik Nayak; +Cc: git, ps, ben.knoble, gitster
> I still think this is early for this, and we should add this flag later
> if the need arises.
Ok! I'll remove it in the next version.
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH v2 1/7] repo-info: declare the repo-info command
  2025-06-20 23:55       ` Junio C Hamano
@ 2025-06-23  9:19         ` Karthik Nayak
  0 siblings, 0 replies; 226+ messages in thread
From: Karthik Nayak @ 2025-06-23  9:19 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Lucas Seiki Oshiro, git, ps, ben.knoble
[-- Attachment #1: Type: text/plain, Size: 818 bytes --]
Junio C Hamano <gitster@pobox.com> writes:
> Karthik Nayak <karthik.188@gmail.com> writes:
>
>>>  .gitignore          |  1 +
>>>  Makefile            |  1 +
>>>  builtin.h           |  1 +
>>>  builtin/repo-info.c | 21 +++++++++++++++++++++
>>>  git.c               |  1 +
>>>  meson.build         |  1 +
>>>  6 files changed, 26 insertions(+)
>>>  create mode 100644 builtin/repo-info.c
>>>
>>
>> Something I mentioned in the previous review, but hasn't been addressed
>> is the addition of documentation for the new command. With each patch
>> modifying the command, it would be also nice to add the respective
>> documentation.
>
> Bsdies, the lack of Documentation/repo-info.adoc causes "make check-docs"
> fail.
More so the reason, I didn't know the target also checks for missing
documentation. That is great!
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 690 bytes --]
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH v2 4/7] repo-info: add the --allow-empty flag
  2025-06-20 21:39     ` Junio C Hamano
@ 2025-06-23  9:26       ` Karthik Nayak
  2025-06-23 20:28         ` Lucas Seiki Oshiro
  0 siblings, 1 reply; 226+ messages in thread
From: Karthik Nayak @ 2025-06-23  9:26 UTC (permalink / raw)
  To: Junio C Hamano, Lucas Seiki Oshiro; +Cc: git, ps, ben.knoble
[-- Attachment #1: Type: text/plain, Size: 1063 bytes --]
Junio C Hamano <gitster@pobox.com> writes:
> Lucas Seiki Oshiro <lucasseikioshiro@gmail.com> writes:
>
>> Add a flag --allow-empty, which will force the output data to be empty
>> when no field is requested.
>
> I still think we should flip the polarity of the option and give "--all"
> to iterate over all variables, and by default show nothing.
>
I thought the idea was that we would show a subset of the fields by
default when no user input is provided. Which would mean we have the
following:
  * `git repo-info` which would show a subset of all fields, giving
    important repository information.
  * `git repo-info --all` which would show all available fields.
  * `git repo-info <fields>` which would only show the requested fields.
With this context, I'm not entirely sure where '--allow-empty' fits in.
If this is/not the case, it would be nice to talk about this in more
detail in the cover message and also in the individual patches.
This is also a good time to think about if we should make the default to
not show anything as Junio mentioned.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 690 bytes --]
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH v2 0/7] repo-info: add new command for retrieving repository info
  2025-06-19 22:57 ` [GSoC RFC PATCH v2 0/7] " Lucas Seiki Oshiro
                     ` (6 preceding siblings ...)
  2025-06-19 22:57   ` [GSoC RFC PATCH v2 7/7] repo-info: add field layout.shallow Lucas Seiki Oshiro
@ 2025-06-23 13:42   ` Phillip Wood
  2025-06-23 18:49     ` Lucas Seiki Oshiro
  7 siblings, 1 reply; 226+ messages in thread
From: Phillip Wood @ 2025-06-23 13:42 UTC (permalink / raw)
  To: Lucas Seiki Oshiro, git; +Cc: ps, karthik.188, ben.knoble, gitster
Hi Lucas
On 19/06/2025 23:57, Lucas Seiki Oshiro wrote:
> Hi!
> 
> This is the second version of the repo-info RFC, and these are the main changes
> introduced since v1:
> 
> - The plaintext format now returns its fields in a key=value format
I think that is a good idea. It also now quotes values that contain 
control characters. In my experience quoting paths works well when one 
is processing the output of one git command and feeding into the stdin 
of another git command. In cases where the script itself wants to use 
the path having to unquote them is a pain and it is much more convenient 
to to read NUL terminated input "lines" that are not quoted. I think the 
output from this command falls into that latter category and so I'm not 
convinced that a LF terminated output is particularly useful. I think 
using an output format generated by 'printf("%s\n%s\0", key, value)' 
would be easier to parse. This format matches that used by 'git config 
--list -z'.
As this is a plumbing command I think it would be clearer if the caller 
was required to specify the output format and the information that they 
require with an "--all" option for "show me everything" as Junio 
suggested. If we were to set defaults for the format and keys now we 
would be stuck with them forever.
I've not seen any discussion of how paths are going to be encoded in the 
JSON output. As I understand it some JSON decoders only accept utf8 
input but the paths reported by git are arbitrary NUL terminated byte 
sequences. How is one expected to parse the output for a non utf8 
encoded path using rust's JSON decoding for example?
On the subject of paths do you plan to support the equivalent of "git 
rev-parse --git-path"? That is very useful in scripts as the script 
author does not have to worry about the details of where exactly each 
file lives and for paths like "index" or "hooks" it takes the relevant 
environment variable or config setting into account. We should design 
the output format so that it can accommodate keys with the requested 
path. I think it would be reasonable to reject requests for paths 
containing newlines which would be compatible with the output format 
suggested above.
I'm not sure what the future plans for this command are but when I'm 
scripting around git it would be nice to be able to a single process 
that I could query for the things currently returned by "git rev-parse", 
"git var" and "git config"
Best Wishes
Phillip
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH v2 0/7] repo-info: add new command for retrieving repository info
  2025-06-23 13:42   ` [GSoC RFC PATCH v2 0/7] repo-info: add new command for retrieving repository info Phillip Wood
@ 2025-06-23 18:49     ` Lucas Seiki Oshiro
  2025-06-24 13:03       ` Phillip Wood
  0 siblings, 1 reply; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-06-23 18:49 UTC (permalink / raw)
  To: phillip.wood; +Cc: git, ps, karthik.188, ben.knoble, gitster
> Hi Lucas
Hi, Phillip, thanks for joining this discussion!
> I think using an output format generated by 'printf("%s\n%s\0", key,
> value)' would be easier to parse. This format matches that used by 'git
> config --list -z'.
Thanks for your suggestion! However, this still breaks in the corner case 
mentioned by Junio in 
https://lore.kernel.org/git/xmqqikl3mtx2.fsf@gitster.g/:
when a value contains a LF, which would be possible to have in the (yet to be
implemented) path values.
> I've not seen any discussion of how paths are going to be encoded in the
> JSON output. As I understand it some JSON decoders only accept utf8 input
> but the paths reported by git are arbitrary NUL terminated byte sequences.
> How is one expected to parse the output for a non utf8 encoded path using
> rust's JSON decoding for example?
By now, I'm directly using the jw_* functions, which format strings using the
function append_quoted_string, introduced in 75459410ed (json_writer: new
routines to create JSON data, 2018-07-13). It was also discussed when that
function was introduced:
"""
    We say "JSON-like" because we do not enforce the Unicode (usually UTF-8)
    requirement on string fields.  Internally, Git does not necessarily have
    Unicode/UTF-8 data for most fields, so it is currently unclear the best
    way to enforce that requirement.  For example, on Linux pathnames can
    contain arbitrary 8-bit character data, so a command like "status" would
    not know how to encode the reported pathnames.  We may want to revisit
    this (or double encode such strings) in the future.
"""
So, it looks like that "the future" is soon :-). In this RFC, I'm not handling
paths yet, and I can't propose a proper solution by now as I honestly know
very little about UTF-8 encoding... 
The first solution that I can think of is to check if the sequence is a valid
UTF-8 bytestring, aborting the entire command if it's not, which would be
better than just guess the charset and re-encode it as UTF-8. However,
I don't know how hard it would be to do.
> On the subject of paths do you plan to support the equivalent of "git
> rev-parse --git-path"?
Hmmmm... In the way that it works under rev-parse, no, as it may bloat this
command with other things that aren't exactly metadata.
> I'm not sure what the future plans for this command are but when I'm
> scripting around git it would be nice to be able to a single process that I
> could query for the things currently returned by "git rev-parse", "git var"
> and "git config"
My concern here is that this main motivation for this new command is that
rev-parse has too many responsibilities. Giving too many responsibilities to
this new command may turn it into a new rev-parse and create a XKCD 927 [1]
situation
> 
> Best Wishes
> 
> Phillip
> 
Thanks again for bringing more light to this discussion! These first patches
are only outputting hardcoded strings from Git, and dealing with Unicode is
something that I'll really need to think about how to solve.
[1] https://xkcd.com/927/
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH v2 1/7] repo-info: declare the repo-info command
  2025-06-20  7:36     ` Karthik Nayak
  2025-06-20 23:55       ` Junio C Hamano
@ 2025-06-23 19:04       ` Lucas Seiki Oshiro
  1 sibling, 0 replies; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-06-23 19:04 UTC (permalink / raw)
  To: Karthik Nayak; +Cc: git, ps, ben.knoble, gitster
Hi!
> Something I mentioned in the previous review, but hasn't been addressed
> is the addition of documentation for the new command.
I haven't wrote a documentation because I thought it would be too early
as this command is still under discussion, but it looks like it is time
to starting working on it.
I'll include that in v3.
Thanks!
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH v2 4/7] repo-info: add the --allow-empty flag
  2025-06-23  9:26       ` Karthik Nayak
@ 2025-06-23 20:28         ` Lucas Seiki Oshiro
  0 siblings, 0 replies; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-06-23 20:28 UTC (permalink / raw)
  To: Karthik Nayak; +Cc: Junio C Hamano, git, ps, ben.knoble
> I thought the idea was that we would show a subset of the fields by
> default when no user input is provided. Which would mean we have the
> following:
> 
>  * `git repo-info` which would show a subset of all fields, giving
>    important repository information.
>  * `git repo-info --all` which would show all available fields.
>  * `git repo-info <fields>` which would only show the requested fields.
> 
> 
> This is also a good time to think about if we should make the default to
> not show anything as Junio mentioned.
After this review, I'm starting to think that leaving it empty by default
would be better. Specially after the review by Phillip Wood [1], who
has a good argument for it:
"""
  As this is a plumbing command I think it would be clearer if the caller 
  was required to specify the output format and the information that they 
  require with an "--all" option for "show me everything" as Junio 
  suggested. If we were to set defaults for the format and keys now we 
  would be stuck with them forever.
"""
[1] https://lore.kernel.org/git/af27af92-73d5-4f0a-84f4-9c91de6ab6e6@gmail.com/
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH v2 0/7] repo-info: add new command for retrieving repository info
  2025-06-23 18:49     ` Lucas Seiki Oshiro
@ 2025-06-24 13:03       ` Phillip Wood
  2025-06-24 13:43         ` Junio C Hamano
  2025-07-01 22:18         ` Lucas Seiki Oshiro
  0 siblings, 2 replies; 226+ messages in thread
From: Phillip Wood @ 2025-06-24 13:03 UTC (permalink / raw)
  To: Lucas Seiki Oshiro, phillip.wood
  Cc: git, ps, karthik.188, ben.knoble, gitster
Hi Lucas
On 23/06/2025 19:49, Lucas Seiki Oshiro wrote:
> 
>> I think using an output format generated by 'printf("%s\n%s\0", key,
>> value)' would be easier to parse. This format matches that used by 'git
>> config --list -z'.
> 
> Thanks for your suggestion! However, this still breaks in the corner case
> mentioned by Junio in
> https://lore.kernel.org/git/xmqqikl3mtx2.fsf@gitster.g/:
> when a value contains a LF, which would be possible to have in the (yet to be
> implemented) path values.
The reason git uses NUL termination for other commands is to prevent 
breaking the output when values contain newlines. The output format I'm 
suggesting is
     <key><LF><value><NUL>
so the output for "path.git-dir" written as a C string would be
     "path.git-dir\n/home/phil/src/git/.git\0"
The value can safely contain newlines because it is terminated by '\0'. 
The reason that "git config --list -z" exists is to provide an 
unambiguous output format as config values can contain newlines.
>> I've not seen any discussion of how paths are going to be encoded in the
>> JSON output. As I understand it some JSON decoders only accept utf8 input
>> but the paths reported by git are arbitrary NUL terminated byte sequences.
>> How is one expected to parse the output for a non utf8 encoded path using
>> rust's JSON decoding for example?
> 
> [...]>
> The first solution that I can think of is to check if the sequence is a valid
> UTF-8 bytestring, aborting the entire command if it's not, which would be
> better than just guess the charset and re-encode it as UTF-8. However,
> I don't know how hard it would be to do.
I'm far from an expert but I think the normal solution is to base64 
encode bytestrings so the caller can get the original bytes back. We'd 
need to do this for all paths. Even if we could reliably guess the 
encoding (which I'm not sure we can) and re-encode it as utf-8 the 
caller wouldn't know if the path was really utf-8 or if it had been 
re-encoded and they needed to convert it back to the original encoding 
to use it.
>> On the subject of paths do you plan to support the equivalent of "git
>> rev-parse --git-path"?
> 
> Hmmmm... In the way that it works under rev-parse, no, as it may bloat this
> command with other things that aren't exactly metadata.
That's a shame as I think it we should be encouraging users to use "git 
rev-parse --git-path" rather than building their own paths using "git 
rev-parse --git-dir". The latter is easy to get wrong for example 
assuming the index resides at "$GIT_DIR/index" when "$GIT_INDEX_FILE" is 
set or running a command from a worktree and assuming the path is under 
"$GIT_DIR" when it actually resides under "$GIT_COMMON_DIR". If this 
command is going to return "$GIT_DIR" and "$GIT_WORK_TREE" then I don't 
see why it should not be able to provide other paths.
>> I'm not sure what the future plans for this command are but when I'm
>> scripting around git it would be nice to be able to a single process that I
>> could query for the things currently returned by "git rev-parse", "git var"
>> and "git config"
> 
> My concern here is that this main motivation for this new command is that
> rev-parse has too many responsibilities. Giving too many responsibilities to
> this new command may turn it into a new rev-parse and create a XKCD 927 [1]
> situation
I should have been clearer that I was talking about the path and 
repository information options of "git rev-parse". Those combined with 
"git var" and "git config" are all repository settings. Having a unified 
interface to them would be an improvement on the status quo where users 
have to know which command to call to query different settings. There 
would be a clear focus on returning repository settings, which I think 
is very different from "git rev-parse" that combines revision parsing, 
command line parsing, shell quoting and repository information. I don't 
think you necessarily need to implement them as part of this project but 
we should design the input and output formats so that the command can be 
extended in the future.
Best Wishes
Phillip
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH v2 0/7] repo-info: add new command for retrieving repository info
  2025-06-24 13:03       ` Phillip Wood
@ 2025-06-24 13:43         ` Junio C Hamano
  2025-07-01 22:18         ` Lucas Seiki Oshiro
  1 sibling, 0 replies; 226+ messages in thread
From: Junio C Hamano @ 2025-06-24 13:43 UTC (permalink / raw)
  To: Phillip Wood
  Cc: Lucas Seiki Oshiro, phillip.wood, git, ps, karthik.188,
	ben.knoble
Phillip Wood <phillip.wood123@gmail.com> writes:
> The reason git uses NUL termination for other commands is to prevent
> breaking the output when values contain newlines. The output format
> I'm suggesting is
>
>     <key><LF><value><NUL>
>
> so the output for "path.git-dir" written as a C string would be
>
>     "path.git-dir\n/home/phil/src/git/.git\0"
>
> The value can safely contain newlines because it is terminated by
> '\0'. The reason that "git config --list -z" exists is to provide an
> unambiguous output format as config values can contain newlines.
For Lukas's purpose, I presume we are in full control of keys, and
can assume that keys do not have any LF in them, so it is safe to
treat everything after the first LF up to the NUL as its value.  
Similarly, even though "config" allows essentially any byte value in
its second level component name in three component variable names,
we do not allow LF or NUL in it, so we are safe there too.
Thanks.
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH v2 5/7] repo-info: add the field references.format
  2025-06-19 22:57   ` [GSoC RFC PATCH v2 5/7] repo-info: add the field references.format Lucas Seiki Oshiro
  2025-06-20 22:26     ` Junio C Hamano
@ 2025-06-24 14:03     ` Phillip Wood
  2025-06-24 15:25       ` Junio C Hamano
  2025-07-03 11:32     ` Patrick Steinhardt
  2 siblings, 1 reply; 226+ messages in thread
From: Phillip Wood @ 2025-06-24 14:03 UTC (permalink / raw)
  To: Lucas Seiki Oshiro, git; +Cc: ps, karthik.188, ben.knoble, gitster
Hi Lucas
On 19/06/2025 23:57, Lucas Seiki Oshiro wrote:
> Add the field references.format to the repo-info command. The data
> retrieved in this field is the same that currently is obtained by
> running `git rev-parse --show-ref-format`.
> 
> Mentored-by: Karthik Nayak <karthik.188@gmail.com>
> Mentored-by Patrick Steinhardt <ps@pks.im>
> Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
I've concentrated my comments on the tests as others have commented on 
the code itself. In general test bodies should be wrapped in single 
quotes rather than double quotes and one should prefer test_cmp() over 
test_line_count().
> +# Test if a field is correctly returned in both plaintext and json formats.
> +#
> +# Usage: test_repo_info <label> <init command> <key> <expected value>
> +#
> +# Arguments:
> +#   label: the label of the test
> +#   init command: a command that creates a repository called 'repo', configured
> +#      accordingly to what is being tested
> +#   key: the key of the field that is being tested
> +#   expected value: the value that the field should contain
> +test_repo_info () {
> +        label=$1
> +        init_command=$2
> +        key=$3
> +        expected_value=$4
> +
> +        test_expect_success PERLJSON "json: $label" "
This double quote should be a single quote. Unlike the test test title, 
the body is passed to eval so there is no need to use double quotes to 
expand shell variables. Indeed doing so is counter productive as it 
means we pass the result of the variable expansion to eval rather that 
the variable name.
> +                test_when_finished 'rm -rf repo' &&
> +                '$SHELL_PATH' -c '$init_command' &&
There is no need to fork a separate shell process here, you can use
     eval "$init_command"
instead.
> +                cd repo &&
If you change directory in a test then you must do so in a subshell so 
that we return to the original directory when the test finishes. In this 
case you're only running a single command in repo so you can use
     git -C repo repo-info ...
instead and avoid using "cd" all together.
> +                echo '$expected_value' >expect &&
> +                git repo-info '$key' >output &&
> +                cat output | parse_json >parsed &&
> +                grep -F 'row[0].$key' parsed | cut -d ' ' -f 2 >value &&
> +                cat value | sed 's/^0$/false/' | sed 's/^1$/true/' >actual &&
sed accepts filenames so there is no need to use "cat" here. It also 
accepts multiple expressions so you only need a single command
     sed "s/^0\$/false/; s/^1\$/true/" value >actual &&
> +                test_cmp expect actual
> +        "
Putting all of the above together the test looks like
	test_expect_success PERLJSON "json: $label" '
		test_when_finished "rm -rf repo" &&
		eval "$init_command" &&
		echo "$expected_value" >expect &&
		git -C repo repo-info "$key" >output &&
		cat output | parse_json >parsed &&
		grep -F "row[0].$key" parsed | cut -d " " -f 2 >value &&
		sed "s/^0\$/false/; s/^1\$/true/" value >actual &&
		test_cmp expect actual
	'
> +        test_expect_success "plaintext: $label" "
> +                test_when_finished 'rm -rf repo' &&
> +                '$SHELL_PATH' -c '$init_command' &&
> +                cd repo &&
> +                echo '$expected_value' >expect &&
> +                git repo-info --format=plaintext '$key' >output &&
> +                cat output | cut -d '=' -f 2 >actual &&
> +                test_cmp expect actual
> +        "
My comments above apply here as well.
> [...]
> +test_expect_success 'plaintext: output all default fields' "
The body should be single quoted as it is eval'd
> +	git repo-info --format=plaintext >actual &&
> +	test_line_count = $DEFAULT_NUMBER_OF_FIELDS actual
test_line_count is a pretty weak assertion. It would be better to use 
test_cmp()
	git repo-info --format=plaintext >actual &&
	sort actual >actual.sorted &&
	cat >expect <<-\EOF &&
	<EXPECTED OUTPUT>
	EOF
	test_cmp expect actual.sorted
> +"
> +
> +test_expect_success PERLJSON 'json: output all default fields' "
> +	git repo-info --format=json > output &&
> +	cat output | parse_json | grep '.*\..*\..*' >actual &&
You do not need to use "cat" here as you can redirect the standard input 
when you run parse_json.
	parse_json <output | grep ...
> +	test_line_count = $DEFAULT_NUMBER_OF_FIELDS actual
This is an even weaker assertion as the number of lines in a json file 
is not related to its content. Ideally we should normalize the json 
output into a standard format and use test_cmp. I don't know how 
practical that is.
Best Wishes
Phillip
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH v2 1/7] repo-info: declare the repo-info command
  2025-06-19 22:57   ` [GSoC RFC PATCH v2 1/7] repo-info: declare the repo-info command Lucas Seiki Oshiro
  2025-06-20  7:36     ` Karthik Nayak
  2025-06-20  7:56     ` Karthik Nayak
@ 2025-06-24 14:03     ` Phillip Wood
  2025-07-03 11:31     ` Patrick Steinhardt
  3 siblings, 0 replies; 226+ messages in thread
From: Phillip Wood @ 2025-06-24 14:03 UTC (permalink / raw)
  To: Lucas Seiki Oshiro, git; +Cc: ps, karthik.188, ben.knoble, gitster
Hi Lucas
On 19/06/2025 23:57, Lucas Seiki Oshiro wrote:
> Create a new Git subcommand called repo-info. `git repo-info` will query
> metadata from the current repository and outputs it as JSON or plaintext.
> 
> Also add entries for this new command in:
> 
> - the build files (Makefile and meson.build)
> - builtin.h
> - git.c
> - .gitignore
> 
> In option parsing, use PARSE_OPT_KEEP_UNKNOWN_OPT to allow the users
> specify after the flags the information that they want to retrieve.
That should not necessary, the option parser will keep any arguments 
that do not begin with "-" without this flag. Using 
PARSE_OPT_KEEP_UNKNOWN_OPT is intended for accepting options that are 
passed to another command and prevents the option parser from 
complaining about unknown options which is not what we want here.
Best Wishes
Phillip
> 
> Mentored-by: Karthik Nayak <karthik.188@gmail.com>
> Mentored-by Patrick Steinhardt <ps@pks.im>
> Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
> ---
>   .gitignore          |  1 +
>   Makefile            |  1 +
>   builtin.h           |  1 +
>   builtin/repo-info.c | 21 +++++++++++++++++++++
>   git.c               |  1 +
>   meson.build         |  1 +
>   6 files changed, 26 insertions(+)
>   create mode 100644 builtin/repo-info.c
> 
> diff --git a/.gitignore b/.gitignore
> index 04c444404e..b2f3fb0047 100644
> --- a/.gitignore
> +++ b/.gitignore
> @@ -139,6 +139,7 @@
>   /git-repack
>   /git-replace
>   /git-replay
> +/git-repo-info
>   /git-request-pull
>   /git-rerere
>   /git-reset
> diff --git a/Makefile b/Makefile
> index 70d1543b6b..50e3a3cbcc 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -1308,6 +1308,7 @@ BUILTIN_OBJS += builtin/remote.o
>   BUILTIN_OBJS += builtin/repack.o
>   BUILTIN_OBJS += builtin/replace.o
>   BUILTIN_OBJS += builtin/replay.o
> +BUILTIN_OBJS += builtin/repo-info.o
>   BUILTIN_OBJS += builtin/rerere.o
>   BUILTIN_OBJS += builtin/reset.o
>   BUILTIN_OBJS += builtin/rev-list.o
> diff --git a/builtin.h b/builtin.h
> index bff13e3069..cc6bc95962 100644
> --- a/builtin.h
> +++ b/builtin.h
> @@ -216,6 +216,7 @@ int cmd_remote_ext(int argc, const char **argv, const char *prefix, struct repos
>   int cmd_remote_fd(int argc, const char **argv, const char *prefix, struct repository *repo);
>   int cmd_repack(int argc, const char **argv, const char *prefix, struct repository *repo);
>   int cmd_replay(int argc, const char **argv, const char *prefix, struct repository *repo);
> +int cmd_repo_info(int argc, const char **argv, const char *prefix, struct repository *repo);
>   int cmd_rerere(int argc, const char **argv, const char *prefix, struct repository *repo);
>   int cmd_reset(int argc, const char **argv, const char *prefix, struct repository *repo);
>   int cmd_restore(int argc, const char **argv, const char *prefix, struct repository *repo);
> diff --git a/builtin/repo-info.c b/builtin/repo-info.c
> new file mode 100644
> index 0000000000..a5c43e253f
> --- /dev/null
> +++ b/builtin/repo-info.c
> @@ -0,0 +1,21 @@
> +#include "builtin.h"
> +#include "parse-options.h"
> +
> +int cmd_repo_info(int argc,
> +		  const char **argv,
> +		  const char *prefix,
> +		  struct repository *repo UNUSED)
> +{
> +	const char *const repo_info_usage[] = {
> +		"git repo-info",
> +		NULL
> +	};
> +	struct option options[] = {
> +		OPT_END()
> +	};
> +
> +	argc = parse_options(argc, argv, prefix, options, repo_info_usage,
> +			     PARSE_OPT_KEEP_UNKNOWN_OPT);
> +
> +	return 0;
> +}
> diff --git a/git.c b/git.c
> index 07a5fe39fb..27a2b3569b 100644
> --- a/git.c
> +++ b/git.c
> @@ -611,6 +611,7 @@ static struct cmd_struct commands[] = {
>   	{ "repack", cmd_repack, RUN_SETUP },
>   	{ "replace", cmd_replace, RUN_SETUP },
>   	{ "replay", cmd_replay, RUN_SETUP },
> +	{ "repo-info", cmd_repo_info, RUN_SETUP },
>   	{ "rerere", cmd_rerere, RUN_SETUP },
>   	{ "reset", cmd_reset, RUN_SETUP },
>   	{ "restore", cmd_restore, RUN_SETUP | NEED_WORK_TREE },
> diff --git a/meson.build b/meson.build
> index 7fea4a34d6..06f2f647ba 100644
> --- a/meson.build
> +++ b/meson.build
> @@ -645,6 +645,7 @@ builtin_sources = [
>     'builtin/repack.c',
>     'builtin/replace.c',
>     'builtin/replay.c',
> +  'builtin/repo-info.c',
>     'builtin/rerere.c',
>     'builtin/reset.c',
>     'builtin/rev-list.c',
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH v2 5/7] repo-info: add the field references.format
  2025-06-24 14:03     ` Phillip Wood
@ 2025-06-24 15:25       ` Junio C Hamano
  2025-06-25  8:40         ` Phillip Wood
  0 siblings, 1 reply; 226+ messages in thread
From: Junio C Hamano @ 2025-06-24 15:25 UTC (permalink / raw)
  To: Phillip Wood; +Cc: Lucas Seiki Oshiro, git, ps, karthik.188, ben.knoble
Phillip Wood <phillip.wood123@gmail.com> writes:
> I've concentrated my comments on the tests as others have commented on
> the code itself. In general test bodies should be wrapped in single
> quotes rather than double quotes and one should prefer test_cmp() over
> test_line_count().
>> +                echo '$expected_value' >expect &&
>> +                git repo-info '$key' >output &&
>> +                cat output | parse_json >parsed &&
Running "cat" on a single file and piping it to anything is an
anti-pattern.  The fact that you can pipe output into the downstream
command means that the downstream command is prepared to read from
its standard input, so
	parse_json <output >parsed &&
should be sufficient, right?
>> +                grep -F 'row[0].$key' parsed | cut -d ' ' -f 2 >value &&
>> +                cat value | sed 's/^0$/false/' | sed 's/^1$/true/' >actual &&
>
> sed accepts filenames so there is no need to use "cat" here. It also
> accepts multiple expressions so you only need a single command
>
>     sed "s/^0\$/false/; s/^1\$/true/" value >actual &&
And you probably do not even need grep piped into cut either, as sed
is a powerful enough language.  We can also cheat a bit by taking
advantage of the fact that the characters used in keys are fairly
tightly controlled, so perhaps something along this line?
	sed -n -e "/row[0].$key/{
		s/^[^ ]* //
                s/^1\$/true/
		s/^0\$/false/
                p;
	}" parsed >actual &&
> Best Wishes
>
> Phillip
Thanks.
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH v2 5/7] repo-info: add the field references.format
  2025-06-24 15:25       ` Junio C Hamano
@ 2025-06-25  8:40         ` Phillip Wood
  0 siblings, 0 replies; 226+ messages in thread
From: Phillip Wood @ 2025-06-25  8:40 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Lucas Seiki Oshiro, git, ps, karthik.188, ben.knoble
On 24/06/2025 16:25, Junio C Hamano wrote:
 > >>> +                echo '$expected_value' >expect &&
>>> +                git repo-info '$key' >output &&
>>> +                cat output | parse_json >parsed &&
> 
> Running "cat" on a single file and piping it to anything is an
> anti-pattern.  The fact that you can pipe output into the downstream
> command means that the downstream command is prepared to read from
> its standard input, so
> 
> 	parse_json <output >parsed &&
> 
> should be sufficient, right?
Good catch, I commented on this in a test below this one but missed it here.
>>> +                grep -F 'row[0].$key' parsed | cut -d ' ' -f 2 >value &&
>>> +                cat value | sed 's/^0$/false/' | sed 's/^1$/true/' >actual &&
>>
>> sed accepts filenames so there is no need to use "cat" here. It also
>> accepts multiple expressions so you only need a single command
>>
>>      sed "s/^0\$/false/; s/^1\$/true/" value >actual &&
> 
> And you probably do not even need grep piped into cut either, as sed
> is a powerful enough language.  We can also cheat a bit by taking
> advantage of the fact that the characters used in keys are fairly
> tightly controlled, so perhaps something along this line?
> 
> 	sed -n -e "/row[0].$key/{
> 		s/^[^ ]* //
>                  s/^1\$/true/
> 		s/^0\$/false/
>                  p;
> 	}" parsed >actual &&
Nice, as well as saving a couple of processes this avoids truncating 
values that contain a space.
Thanks
Phillip
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH v2 0/7] repo-info: add new command for retrieving repository info
  2025-06-24 13:03       ` Phillip Wood
  2025-06-24 13:43         ` Junio C Hamano
@ 2025-07-01 22:18         ` Lucas Seiki Oshiro
  2025-07-02  9:10           ` phillip.wood123
  1 sibling, 1 reply; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-07-01 22:18 UTC (permalink / raw)
  To: phillip.wood; +Cc: git, ps, karthik.188, ben.knoble, gitster
> The reason git uses NUL termination for other commands is to prevent breaking the output when values contain newlines. The output format I'm suggesting is
> 
>    <key><LF><value><NUL>
> 
> so the output for "path.git-dir" written as a C string would be
> 
>    "path.git-dir\n/home/phil/src/git/.git\0"
> 
> The value can safely contain newlines because it is terminated by '\0'. The reason that "git config --list -z" exists is to provide an unambiguous output format as config values can contain newlines.
OK!
I can't see any downsides in this format. I'll use it in v3!
> If this command is going to return "$GIT_DIR" and "$GIT_WORK_TREE" then I don't see why it should not be able to provide other paths.
Hmmm... I never used `git rev-parse --git-path`, but after inspecting it,
it seems to have special cases for:
- grafts file
- index file
- objects directory
- hooks directory
What about adding them all to the `git repo-info` under the `path` category?
Currently, these are the fields that I plan to add:
- git-dir
- common-dir
- toplevel-dir
- superproject-working-tree
> Those combined with "git var" and "git config" are all repository settings. Having a unified interface to them would be an improvement on the status quo where users have to know which command to call to query different settings.
Fair! By now, I'm focusing on rev-parse, but it seems to make sense.
> Best Wishes
Thanks again for your extensive review!
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH v2 0/7] repo-info: add new command for retrieving repository info
  2025-07-01 22:18         ` Lucas Seiki Oshiro
@ 2025-07-02  9:10           ` phillip.wood123
  0 siblings, 0 replies; 226+ messages in thread
From: phillip.wood123 @ 2025-07-02  9:10 UTC (permalink / raw)
  To: Lucas Seiki Oshiro, phillip.wood
  Cc: git, ps, karthik.188, ben.knoble, gitster
Hi Lucas
On 01/07/2025 23:18, Lucas Seiki Oshiro wrote:
> 
>> The reason git uses NUL termination for other commands is to prevent breaking the output when values contain newlines. The output format I'm suggesting is
>>
>>     <key><LF><value><NUL>
>>
>> so the output for "path.git-dir" written as a C string would be
>>
>>     "path.git-dir\n/home/phil/src/git/.git\0"
>>
>> The value can safely contain newlines because it is terminated by '\0'. The reason that "git config --list -z" exists is to provide an unambiguous output format as config values can contain newlines.
> 
> I can't see any downsides in this format. I'll use it in v3!
That's great
> Hmmm... I never used `git rev-parse --git-path`, but after inspecting it,
> it seems to have special cases for:
> 
> - grafts file
> - index file
> - objects directory
> - hooks directory
and all the paths that are adjusted by update_common_dir() as well.
> What about adding them all to the `git repo-info` under the `path` category?
That means keeping a list of paths that are special cased in two 
separate places which means they'll almost certainly get out of sync at 
some point in the future. It also means that instead of querying a whole 
path of a hook the script author has to remember to look up the hooks 
path and then append the hook name to that which makes it more of a faff 
to use. Letting the user just query the path they are interested in is a 
much nicer interface and makes it much easier to deal with the paths 
that reside under $GIT_COMMON_DIR.
> Currently, these are the fields that I plan to add:
> 
> - git-dir
> - common-dir
> - toplevel-dir
> - superproject-working-tree
git-prefix would be useful as well I think.
Thanks
Phillip
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH v2 2/7] repo-info: add the --format flag
  2025-06-19 22:57   ` [GSoC RFC PATCH v2 2/7] repo-info: add the --format flag Lucas Seiki Oshiro
  2025-06-20  8:06     ` Karthik Nayak
  2025-06-20 21:31     ` Junio C Hamano
@ 2025-07-03 11:31     ` Patrick Steinhardt
  2 siblings, 0 replies; 226+ messages in thread
From: Patrick Steinhardt @ 2025-07-03 11:31 UTC (permalink / raw)
  To: Lucas Seiki Oshiro; +Cc: git, karthik.188, ben.knoble, gitster
On Thu, Jun 19, 2025 at 07:57:46PM -0300, Lucas Seiki Oshiro wrote:
> diff --git a/builtin/repo-info.c b/builtin/repo-info.c
> index a5c43e253f..cbe1475e30 100644
> --- a/builtin/repo-info.c
> +++ b/builtin/repo-info.c
> @@ -1,21 +1,73 @@
>  #include "builtin.h"
> +#include "json-writer.h"
>  #include "parse-options.h"
>  
> +enum output_format {
> +	FORMAT_JSON
> +};
> +
> +struct repo_info {
> +	struct repository *repo;
> +	enum output_format format;
> +};
> +
> +static void repo_info_init(struct repo_info *repo_info,
> +			   struct repository *repo,
> +			   char *format)
> +{
> +	repo_info->repo = repo;
> +
> +	if (format == NULL || !strcmp(format, "json"))
Nit: we typically don't compare to NULL explicitly.
	if (!format || !strcmp(format, "json"))
> +		repo_info->format = FORMAT_JSON;
> +	else
> +		die("invalid format %s", format);
> +}
> +
> +static void repo_info_print_json(struct repo_info *repo_info UNUSED)
> +{
> +	struct json_writer jw;
> +
> +	jw_init(&jw);
> +
> +	jw_object_begin(&jw, 1);
> +	jw_end(&jw);
> +
> +	puts(jw.json.buf);
> +	jw_release(&jw);
> +}
> +
> +static void repo_info_print(struct repo_info *repo_info)
> +{
> +	enum output_format format = repo_info->format;
This variable indirection feels a bit pointless.
> +	switch (format) {
> +	case FORMAT_JSON:
> +		repo_info_print_json(repo_info);
> +		break;
We should probably `BUG()` in case there's any other unknown format
value stored in `repo_info`.
> +	}
> +}
> +
>  int cmd_repo_info(int argc,
>  		  const char **argv,
>  		  const char *prefix,
> -		  struct repository *repo UNUSED)
> +		  struct repository *repo)
>  {
>  	const char *const repo_info_usage[] = {
>  		"git repo-info",
>  		NULL
>  	};
> +	struct repo_info repo_info;
> +	char *format = NULL;
This should be const.
>  	struct option options[] = {
> +		OPT_STRING(0, "format", &format, N_("format"),
> +			   N_("output format")),
>  		OPT_END()
>  	};
>  
>  	argc = parse_options(argc, argv, prefix, options, repo_info_usage,
>  			     PARSE_OPT_KEEP_UNKNOWN_OPT);
> +	repo_info_init(&repo_info, repo, format);
> +	repo_info_print(&repo_info);
>  
>  	return 0;
>  }
> diff --git a/t/t1900-repo-info.sh b/t/t1900-repo-info.sh
> new file mode 100755
> index 0000000000..f634e1a285
> --- /dev/null
> +++ b/t/t1900-repo-info.sh
> @@ -0,0 +1,22 @@
> +#!/bin/sh
> +
> +test_description='test git repo-info'
> +GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
> +export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
We should avoid setting the default initial branch name in new tests.
The variable really only exists for legacy tests where we assume that
the branch has a specific name.
> +. ./test-lib.sh
> +
> +parse_json () {
> +	tr '\n' ' ' | "$PERL_PATH" "$TEST_DIRECTORY/t0019/parse_json.perl"
> +}
> +
> +test_lazy_prereq PERLJSON '
> +	perl -MJSON -e "exit 0"
> +'
> +
> +test_expect_success PERLJSON 'json: returns empty output with allow-empty' '
> +	git repo-info --format=json >output &&
> +	test_line_count = 2 output
This test doesn't really test much. In any case, two lines of output
certainly isn't empty output from my perspective. We should verify that
the generated output really is the empty JSON object.
Patrick
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH v2 1/7] repo-info: declare the repo-info command
  2025-06-19 22:57   ` [GSoC RFC PATCH v2 1/7] repo-info: declare the repo-info command Lucas Seiki Oshiro
                       ` (2 preceding siblings ...)
  2025-06-24 14:03     ` Phillip Wood
@ 2025-07-03 11:31     ` Patrick Steinhardt
  2025-07-04 21:40       ` Lucas Seiki Oshiro
  3 siblings, 1 reply; 226+ messages in thread
From: Patrick Steinhardt @ 2025-07-03 11:31 UTC (permalink / raw)
  To: Lucas Seiki Oshiro
  Cc: git, karthik.188, ben.knoble, gitster, Justin Tobler,
	Derrick Stolee
On Thu, Jun 19, 2025 at 07:57:45PM -0300, Lucas Seiki Oshiro wrote:
> Create a new Git subcommand called repo-info. `git repo-info` will query
> metadata from the current repository and outputs it as JSON or plaintext.
One thing I wondered: Justin is currently iterating on git-survey(1),
which is the command Stolee proposed a while ago to gather repository
metrics. Would it make sense to maybe have such whole-repo commands
grouped together in a `git repo` top-level command? E.g. `git repo info`
for your command, `git repo size` to gather information about the repo
size.
> Also add entries for this new command in:
> 
> - the build files (Makefile and meson.build)
> - builtin.h
> - git.c
> - .gitignore
> 
> In option parsing, use PARSE_OPT_KEEP_UNKNOWN_OPT to allow the users
> specify after the flags the information that they want to retrieve.
> 
> Mentored-by: Karthik Nayak <karthik.188@gmail.com>
> Mentored-by Patrick Steinhardt <ps@pks.im>
Nit: missing colon. It's also present in subsequent patches.
Patrick
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH v2 3/7] repo-info: add plaintext as an output format
  2025-06-19 22:57   ` [GSoC RFC PATCH v2 3/7] repo-info: add plaintext as an output format Lucas Seiki Oshiro
  2025-06-20 21:37     ` Junio C Hamano
@ 2025-07-03 11:32     ` Patrick Steinhardt
  1 sibling, 0 replies; 226+ messages in thread
From: Patrick Steinhardt @ 2025-07-03 11:32 UTC (permalink / raw)
  To: Lucas Seiki Oshiro; +Cc: git, karthik.188, ben.knoble, gitster
On Thu, Jun 19, 2025 at 07:57:47PM -0300, Lucas Seiki Oshiro wrote:
> diff --git a/t/t1900-repo-info.sh b/t/t1900-repo-info.sh
> index f634e1a285..998c835795 100755
> --- a/t/t1900-repo-info.sh
> +++ b/t/t1900-repo-info.sh
> @@ -18,5 +18,9 @@ test_expect_success PERLJSON 'json: returns empty output with allow-empty' '
>  	git repo-info --format=json >output &&
>  	test_line_count = 2 output
>  '
Tests should be separated from one another by an empty line.
> +test_expect_success 'plaintext: returns empty output with allow-empty' '
> +	git repo-info --format=plaintext >output &&
> +	test_line_count = 0 output
> +'
Patrick
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH v2 5/7] repo-info: add the field references.format
  2025-06-19 22:57   ` [GSoC RFC PATCH v2 5/7] repo-info: add the field references.format Lucas Seiki Oshiro
  2025-06-20 22:26     ` Junio C Hamano
  2025-06-24 14:03     ` Phillip Wood
@ 2025-07-03 11:32     ` Patrick Steinhardt
  2025-07-04 21:11       ` Lucas Seiki Oshiro
  2 siblings, 1 reply; 226+ messages in thread
From: Patrick Steinhardt @ 2025-07-03 11:32 UTC (permalink / raw)
  To: Lucas Seiki Oshiro; +Cc: git, karthik.188, ben.knoble, gitster
On Thu, Jun 19, 2025 at 07:57:49PM -0300, Lucas Seiki Oshiro wrote:
> diff --git a/builtin/repo-info.c b/builtin/repo-info.c
> index 6499be0eae..6ce3e6134f 100644
> --- a/builtin/repo-info.c
> +++ b/builtin/repo-info.c
> @@ -1,21 +1,56 @@
>  #include "builtin.h"
>  #include "json-writer.h"
>  #include "parse-options.h"
> +#include "quote.h"
> +#include "refs.h"
>  
>  enum output_format {
>  	FORMAT_JSON,
>  	FORMAT_PLAINTEXT
>  };
>  
> +enum repo_info_category {
> +	CATEGORY_REFERENCES = 1 << 0
> +};
> +
> +enum repo_info_references_field {
> +	FIELD_REFERENCES_FORMAT = 1 << 0
> +};
Missing commas after both enum values.
> +struct repo_info_field {
> +	enum repo_info_category category;
> +	union {
> +		enum repo_info_references_field references;
> +	} field;
> +};
Hm, okay. I guess later patches will add separate enums for each
category, so this saves us a couple bytes as the number of categories
grows.
>  struct repo_info {
>  	struct repository *repo;
>  	enum output_format format;
> +	int n_fields;
This should be `size_t`. Also, it's typical in our code base to call
this `fields_nr`.
> +	struct repo_info_field *fields;
>  };
>  
> +static struct repo_info_field default_fields[] = {
> +	{
> +		.category = CATEGORY_REFERENCES,
> +		.field.references = FIELD_REFERENCES_FORMAT
> +	}
Missing comma.
> +};
> +
> +static void print_key_value(const char *key, const char *value) {
Formatting: the curly brace should sit on its own line.
> +	printf("%s=", key);
> +	quote_c_style(value, NULL, stdout, 0);
> +	putchar('\n');
> +}
> +
>  static void repo_info_init(struct repo_info *repo_info,
>  			   struct repository *repo,
> -			   char *format)
> +			   char *format,
> +			   int allow_empty,
> +			   int argc, const char **argv)
>  {
> +	int i;
This variable can be declared in the loop itself:
    for (int i = 0; ...)
>  	repo_info->repo = repo;
>  
>  	if (format == NULL || !strcmp(format, "json"))
> @@ -24,19 +59,83 @@ static void repo_info_init(struct repo_info *repo_info,
>  		repo_info->format = FORMAT_PLAINTEXT;
>  	else
>  		die("invalid format %s", format);
> +
> +	if (argc == 0 && !allow_empty) {
> +		repo_info->n_fields = ARRAY_SIZE(default_fields);
> +		repo_info->fields = default_fields;
> +	} else {
> +		repo_info->n_fields = argc;
> +		ALLOC_ARRAY(repo_info->fields, argc);
> +
> +		for (i = 0; i < argc; i++) {
> +			const char *arg = argv[i];
> +			struct repo_info_field *field = repo_info->fields + i;
> +
> +			if (!strcmp(arg, "references.format")) {
> +				field->category = CATEGORY_REFERENCES;
> +				field->field.references = FIELD_REFERENCES_FORMAT;
> +			} else {
> +				die("invalid field '%s'", arg);
> +			}
> +		}
> +	}
>  }
>  
> -static void repo_info_print_plaintext(struct repo_info *repo_info UNUSED)
> +static void repo_info_release(struct repo_info *repo_info)
>  {
> +	if (repo_info->fields != default_fields) free(repo_info->fields);
>  }
>  
> -static void repo_info_print_json(struct repo_info *repo_info UNUSED)
> +static void repo_info_print_plaintext(struct repo_info *repo_info) {
Formatting.
> +	struct repository *repo = repo_info->repo;
> +	int i;
Variable can be declared in the loop.
> +	for (i = 0; i < repo_info->n_fields; i++) {
> +		struct repo_info_field *field = &repo_info->fields[i];
> +		switch (field->category) {
> +		case CATEGORY_REFERENCES:
> +			switch (field->field.references) {
I wonder a bit what it buys us that we have the difference between the
category and reference format. Right now it feels like it can cause more
errors that it prevents, as we now always have doubly-nested switches.
Wouldn't it make more sense to only only pass around the fields as
`repo_info_references_field`? We could then have two arrays that we
define globally:
    static const char const* name_by_field[] = {
        [FIELD_REFERENCES_FORMAT] = "references.format",
    };
    static repo_info_category category_by_field[] = {
        [FIELD_REFERENCES_FORMAT] = CATEGORY_REFERENCES,
    };
So `name_by_field[FIELD_REFERENCES_FORMAT]` would yield the name and
`category_by_field[CATEGORY_REFERENCES]` would yield its category. But
the benefit is that you only need to pass around the field enum from now
on, all other information is implicit.
The reverse information can also be obtained easily. To e.g. get all
fields of a reference you'd iterate through `category_by_field` and take
all array indices whose value matches the desired category.
> +			case FIELD_REFERENCES_FORMAT:
> +				print_key_value("references.format",
> +						ref_storage_format_to_name(
> +							repo->ref_storage_format));
> +				break;
> +			}
> +			break;
> +		}
> +	}
> +}
> +
> +static void repo_info_print_json(struct repo_info *repo_info)
>  {
>  	struct json_writer jw;
> +	int i;
Variable can be declared in the loop.
> +	unsigned int categories = 0;
> +	unsigned int references_fields = 0;
> +	struct repository *repo = repo_info->repo;
> +
> +	for (i = 0; i < repo_info->n_fields; i++) {
> +		struct repo_info_field *field = repo_info->fields + i;
> +		categories |= field->category;
> +		switch (field->category) {
> +		case CATEGORY_REFERENCES:
> +			references_fields |= field->field.references;
> +			break;
> +		}
> +	}
>  
>  	jw_init(&jw);
>  
>  	jw_object_begin(&jw, 1);
> +
> +	if (categories & CATEGORY_REFERENCES) {
> +		jw_object_inline_begin_object(&jw, "references");
> +		if (references_fields & FIELD_REFERENCES_FORMAT) {
> +			const char *format_name = ref_storage_format_to_name(
> +				repo->ref_storage_format);
> +			jw_object_string(&jw, "format", format_name);
> +		}
> +		jw_end(&jw);
> +	}
>  	jw_end(&jw);
>  
>  	puts(jw.json.buf);
Patrick
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH v2 6/7] repo-info: add field layout.bare
  2025-06-19 22:57   ` [GSoC RFC PATCH v2 6/7] repo-info: add field layout.bare Lucas Seiki Oshiro
@ 2025-07-03 11:32     ` Patrick Steinhardt
  2025-07-03 14:14       ` Lucas Seiki Oshiro
  0 siblings, 1 reply; 226+ messages in thread
From: Patrick Steinhardt @ 2025-07-03 11:32 UTC (permalink / raw)
  To: Lucas Seiki Oshiro; +Cc: git, karthik.188, ben.knoble, gitster
On Thu, Jun 19, 2025 at 07:57:50PM -0300, Lucas Seiki Oshiro wrote:
> diff --git a/builtin/repo-info.c b/builtin/repo-info.c
> index 6ce3e6134f..1650d3595c 100644
> --- a/builtin/repo-info.c
> +++ b/builtin/repo-info.c
> @@ -1,4 +1,8 @@
> +#define USE_THE_REPOSITORY_VARIABLE
Meh, `is_bare_repository()` strikes again :/
Patrick
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH v2 6/7] repo-info: add field layout.bare
  2025-07-03 11:32     ` Patrick Steinhardt
@ 2025-07-03 14:14       ` Lucas Seiki Oshiro
  2025-07-04  8:32         ` Phillip Wood
  0 siblings, 1 reply; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-07-03 14:14 UTC (permalink / raw)
  To: Patrick Steinhardt; +Cc: git, karthik.188, ben.knoble, gitster
> Meh, `is_bare_repository()` strikes again :/
Yeah... I tried to avoid it but removing that dependency is work for its own
patch...
I asked Ayush [1] about this as his GSoC project [2] is related to reduce the
dependency on `the_repository`.
[1] https://lore.kernel.org/git/CAE7as+bTKE5opov-Xn0P8R+cy+=-XRkX9Wpie_W0717XMF1b_w@mail.gmail.com/
[2] https://summerofcode.withgoogle.com/programs/2025/projects/no7dVMeG
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH v2 6/7] repo-info: add field layout.bare
  2025-07-03 14:14       ` Lucas Seiki Oshiro
@ 2025-07-04  8:32         ` Phillip Wood
  0 siblings, 0 replies; 226+ messages in thread
From: Phillip Wood @ 2025-07-04  8:32 UTC (permalink / raw)
  To: Lucas Seiki Oshiro, Patrick Steinhardt
  Cc: git, karthik.188, ben.knoble, gitster
Hi Lucas
On 03/07/2025 15:14, Lucas Seiki Oshiro wrote:
> 
>> Meh, `is_bare_repository()` strikes again :/
> 
> Yeah... I tried to avoid it but removing that dependency is work for its own
> patch...
I really wouldn't worry too much about using "the_repository" in code 
that lives under builtin/. The reason to avoid it is so that one git 
process can operate on multiple repositories but until our library code 
stops using "the_repository" and actually respects the repository passed 
to it there seems little point in worrying about using it in non-library 
code. As it is we're currently adding more instances of "the_repository" 
to our library code as a stepping stone to removing other global 
variables. Once our library code can operate on an arbitrary repository 
we can then think about which files under builtin/ want to operate on 
more than one repository and avoid "the_repository" in those. Until then 
worrying about using "the_repository" under builtin/ is a distraction 
from fixing the library code.
Thanks
Phillip
> I asked Ayush [1] about this as his GSoC project [2] is related to reduce the
> dependency on `the_repository`.
> 
> 
> [1] https://lore.kernel.org/git/CAE7as+bTKE5opov-Xn0P8R+cy+=-XRkX9Wpie_W0717XMF1b_w@mail.gmail.com/
> [2] https://summerofcode.withgoogle.com/programs/2025/projects/no7dVMeG
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH v2 5/7] repo-info: add the field references.format
  2025-07-03 11:32     ` Patrick Steinhardt
@ 2025-07-04 21:11       ` Lucas Seiki Oshiro
  0 siblings, 0 replies; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-07-04 21:11 UTC (permalink / raw)
  To: Patrick Steinhardt; +Cc: git, karthik.188, ben.knoble, gitster
> Hm, okay. I guess later patches will add separate enums for each
> category, so this saves us a couple bytes as the number of categories
> grows.
Yeah, that's the idea.
However, even though it saves some bytes (we don't need to keep several empty 
fields), I used a union here mostly because of what it means semantically. In
the print functions where I'm `switch`ing between values of one of those enums,
the compiler complains if I missed something :-).
> I wonder a bit what it buys us that we have the difference between the
> category and reference format. Right now it feels like it can cause more
> errors that it prevents, as we now always have doubly-nested switches.
I reckon that my solution was a little hacky bit, but I tried to solve two
things:
1. The plaintext/linewise/null-terminated format can return the values in the
order they were requested, like this:
```
$ git repo-info --format=plaintext layout.bare references.format layout.shallow
layout.bare=true
references.format=files
layout.shallow=false
```
2. The same is not applicable to the JSON format, where the order shouldn't
matter and we can't have the same key repeating. Then it works like this:
```
$ git repo-info --format=json layout.bare references.format layout.shallow
{
  "references": {
    "format": "files"
  },
  "layout": {
    "bare": false,
    "shallow": false
  }
}
```
but not like this:
```
$ git repo-info --format=json layout.bare references.format layout.shallow
{
  "layout": {
    "bare": false
  },
  "references": {
    "format": "files"
  },
  "layout": {
    "shallow": false
  }
}
```
.
I'm still open to changes here. Perhaps keeping the same order in 1. is not so
useful from this v2 as I'll always return the name of the keys (like, for
example, git-config but unlike git-rev-parse).
> Wouldn't it make more sense to only only pass around the fields as
> `repo_info_references_field`? We could then have two arrays that we
> define globally:
> 
>    static const char const* name_by_field[] = {
>        [FIELD_REFERENCES_FORMAT] = "references.format",
>    };
> 
>    static repo_info_category category_by_field[] = {
>        [FIELD_REFERENCES_FORMAT] = CATEGORY_REFERENCES,
>    };
> 
> So `name_by_field[FIELD_REFERENCES_FORMAT]` would yield the name and
> `category_by_field[CATEGORY_REFERENCES]` would yield its category. But
> the benefit is that you only need to pass around the field enum from now
> on, all other information is implicit.
> 
> The reverse information can also be obtained easily. To e.g. get all
> fields of a reference you'd iterate through `category_by_field` and take
> all array indices whose value matches the desired category.
A downside that I see is that it seems to be make the print_json function
too complex. Currently, the complexities of the printing functions are (if
I'm not missing something and ignoring the complexity of data the retrieval):
- plaintext: O(n_fields), as it only iterates over the fields
- json: O(n_fields + F), where F is number of possible fields that we can get,
  as we first fill the `<category>_fields` variables and then we iterate over
  each possible field to find if it was requested
In the plaintext format it wouldn't change too much, it would be still
O(n_fields). But in the json format, it seems that will be something like
(in pseudocode):
```
jw = json_writer
fields_to_print = array with F values set to false
for (field in repo_info->fields)
    fields_to_print[field] = true
for (category in all_categories)
    object_started = false
    for (field in all_fields)
        if (category_by_field[field] == category)
            if (!object_started)
                jw_object_inline_begin_object(&jw, category)
            jw_object(&jw, name_by_field[field], retrieve(field))
    
    if (object_started)
        jw_end(&jw)
```
which would be O(n_fields + n_categories * F). To be honest I'm not exactly
thinking about performance (which would be in fact negligible in this command),
but how complex the code would be. If I understood it correctly, I wwould be
trading nested `switch`es by nested `for`s.
But again, I'm still open to change everything again here!
Anyway, thank you for your time reviewing this patch, seeing what I did in the
past weeks and joining again the discussion! :-)
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH v2 1/7] repo-info: declare the repo-info command
  2025-07-03 11:31     ` Patrick Steinhardt
@ 2025-07-04 21:40       ` Lucas Seiki Oshiro
  2025-07-07  6:01         ` Patrick Steinhardt
  0 siblings, 1 reply; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-07-04 21:40 UTC (permalink / raw)
  To: Patrick Steinhardt
  Cc: git, karthik.188, ben.knoble, gitster, Justin Tobler,
	Derrick Stolee
> One thing I wondered: Justin is currently iterating on git-survey(1),
> which is the command Stolee proposed a while ago to gather repository
> metrics.
I didn't find it in the mailing list, but I remember seeing it in the
the GitLab's fork. Is it this unmerged MR? 
https://gitlab.com/gitlab-org/git/-/merge_requests/369
> Would it make sense to maybe have such whole-repo commands
> grouped together in a `git repo` top-level command? E.g. `git repo info`
> for your command, `git repo size` to gather information about the repo
> size.
It seems to be very nice for me! In fact, this being a home also for
statistics is something I considered while writing the first versions of
my GSoC proposal.
And what about merging the two codes into a single API? Something like:
```
git repo-info layout.bare references.format survey.commit-count
{
  "layout": {
    "bare": true
  },
  "references": {
    "format": "files"
  },
  "survey": {
    "commit-count": 42
  }
}
?
During our meetings, Karthik suggested (I'm planning to it later) to also
allow to request an entire category instead of only the fields. Then, this
would also be possible:
```
$ git repo-info survey
{
  "survey": {
    "commit-count": 42,
    "blob-count": 1234
}
```
But I don't know what are Justin's plans for git-survey, if it would be a
porcelain command for showing those stats to the user of if it is targeted
for being parsed like this `repo-info`.
I'm just brainstorming because I liked the idea :-)
> Nit: missing colon. It's also present in subsequent patches.
Oops
> Patrick
^ permalink raw reply	[flat|nested] 226+ messages in thread
* [GSoC RFC PATCH v3 0/5] repo-info: add new command for retrieving repository info
  2025-06-10 15:21 [GSoC RFC PATCH 0/5] repo-info: add new command for retrieving repository info Lucas Seiki Oshiro
                   ` (8 preceding siblings ...)
  2025-06-19 22:57 ` [GSoC RFC PATCH v2 0/7] " Lucas Seiki Oshiro
@ 2025-07-06 23:19 ` Lucas Seiki Oshiro
  2025-07-06 23:19   ` [GSoC RFC PATCH v3 1/5] repo-info: declare the repo-info command Lucas Seiki Oshiro
                     ` (6 more replies)
  2025-07-14 23:52 ` [GSoC RFC PATCH v4 0/4] repo: " Lucas Seiki Oshiro
                   ` (7 subsequent siblings)
  17 siblings, 7 replies; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-07-06 23:19 UTC (permalink / raw)
  To: git; +Cc: ps, karthik.188, ben.knoble, gitster, phillip.wood,
	Lucas Seiki Oshiro
Hi!
This is the third version of the patchset introducing the new Git command
called `repo-info`, which will return repository information currently stored
under git-rev-parse using machine-readable formats.
The main changes since v2 are:
- Documentation for git-repo-info has been added.
- The `--allow-empty` flag was removed. In this version, repo-info no longer
  returns a default set of data when called without parameters. However, an
  `--all` flag is planned for a future version.
- The `plaintext` format was replaced by a null-terminated format, following
  the syntax of `git config --list -z`.
Here is the rangediff from v2 to v3:
1:  102b5ce90a ! 1:  3f9ef00413 repo-info: declare the repo-info command
    @@ Metadata
      ## Commit message ##
         repo-info: declare the repo-info command
    -    Create a new Git subcommand called repo-info. `git repo-info` will query
    -    metadata from the current repository and outputs it as JSON or plaintext.
    +    Currently, `git rev-parse` covers a wide range of functionality not
    +    directly related to parsing revisions, as its name says. Over time,
    +    many features like parsing datestrings, options, paths, and others
    +    were added to it because there wasn't a more appropriated command
    +    to place them.
    +
    +    Create a new Git subcommand called `repo-info`. `git repo-info` will
    +    bring the functionality of retrieving repository-related information
    +    currently returned by `rev-parse`, displaying them in
    +    machine-readable formats (JSON or a null-terminated format).
         Also add entries for this new command in:
    -    - the build files (Makefile and meson.build)
    +    - the build files (Makefile, meson.build, Documentation/meson.build)
         - builtin.h
         - git.c
         - .gitignore
    +    - command-list.txt
    +    - Documentation
    -    In option parsing, use PARSE_OPT_KEEP_UNKNOWN_OPT to allow the users
    -    specify after the flags the information that they want to retrieve.
    -
    +    Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
    +    Helped-by: Junio C Hamano <gitster@pobox.com>
         Mentored-by: Karthik Nayak <karthik.188@gmail.com>
    -    Mentored-by Patrick Steinhardt <ps@pks.im>
    +    Mentored-by: Patrick Steinhardt <ps@pks.im>
         Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
      ## .gitignore ##
    @@ .gitignore
      /git-rerere
      /git-reset
    + ## Documentation/git-repo-info.adoc (new) ##
    +@@
    ++git-repo-info(1)
    ++================
    ++
    ++NAME
    ++----
    ++git-repo-info - Retrieve information about a repository
    ++
    ++SYNOPSIS
    ++--------
    ++[synopsis]
    ++git repo-info
    ++
    ++DESCRIPTION
    ++-----------
    ++Retrieve information about the current repository in a machine-readable format.
    ++
    ++`git repo-info` will be the primary tool to query repository-specific
    ++information, which currently can also be done by calling `git rev-parse` (see
    ++linkgit:git-rev-parse[1]). `git repo-info` doesn't query information unrelated
    ++to the current repository or that is already retrieved by a specialized command,
    ++for example, `git config` (see linkgit:git-config[1]) or `git var` (see
    ++linkgit:git-var[1]).
    ++
    ++THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOR MAY CHANGE.
    ++
    ++OPTIONS
    ++-------
    ++
    ++`<key>`::
    ++Key of the value that will be retrieved. It should be in the format
    ++`<category>.<field>`. See the "CATEGORIES AND FIELDS" section below.
    ++
    ++CATEGORIES AND FIELDS
    ++---------------------
    ++
    ++The set of data that `git repo-info` can return is divided into
    ++categories. Each category is composed by one or more fields.
    ++
    ++SEE ALSO
    ++--------
    ++linkgit:git-rev-parse[1]
    ++
    ++GIT
    ++---
    ++Part of the linkgit:git[1] suite
    +
    + ## Documentation/meson.build ##
    +@@ Documentation/meson.build: manpages = {
    +   'git-repack.adoc' : 1,
    +   'git-replace.adoc' : 1,
    +   'git-replay.adoc' : 1,
    ++  'git-repo-info.adoc' : 1,
    +   'git-request-pull.adoc' : 1,
    +   'git-rerere.adoc' : 1,
    +   'git-reset.adoc' : 1,
    +
      ## Makefile ##
     @@ Makefile: BUILTIN_OBJS += builtin/remote.o
      BUILTIN_OBJS += builtin/repack.o
    @@ builtin/repo-info.c (new)
     +	};
     +
     +	argc = parse_options(argc, argv, prefix, options, repo_info_usage,
    -+			     PARSE_OPT_KEEP_UNKNOWN_OPT);
    ++			     0);
     +
     +	return 0;
     +}
    + ## command-list.txt ##
    +@@ command-list.txt: git-remote                              ancillarymanipulators           complete
    + git-repack                              ancillarymanipulators           complete
    + git-replace                             ancillarymanipulators           complete
    + git-replay                              plumbingmanipulators
    ++git-repo-info                           plumbinginterrogators
    + git-request-pull                        foreignscminterface             complete
    + git-rerere                              ancillaryinterrogators
    + git-reset                               mainporcelain           history
    +
      ## git.c ##
     @@ git.c: static struct cmd_struct commands[] = {
      	{ "repack", cmd_repack, RUN_SETUP },
2:  1cc1184663 < -:  ---------- repo-info: add the --format flag
3:  a329825387 < -:  ---------- repo-info: add plaintext as an output format
4:  3b6c27b68d < -:  ---------- repo-info: add the --allow-empty flag
5:  4b1e99cac4 < -:  ---------- repo-info: add the field references.format
6:  0cd72e5ebf < -:  ---------- repo-info: add field layout.bare
7:  274dfbde86 < -:  ---------- repo-info: add field layout.shallow
-:  ---------- > 2:  33c3d5e665 repo-info: add the --format flag
-:  ---------- > 3:  e6331b18d4 repo-info: add the field references.format
-:  ---------- > 4:  6a6825c4df repo-info: add field layout.bare
-:  ---------- > 5:  938be682d2 repo-info: add field layout.shallow
Lucas Seiki Oshiro (5):
  repo-info: declare the repo-info command
  repo-info: add the --format flag
  repo-info: add the field references.format
  repo-info: add field layout.bare
  repo-info: add field layout.shallow
 .gitignore                       |   1 +
 Documentation/git-repo-info.adoc |  84 ++++++++++++
 Documentation/meson.build        |   1 +
 Makefile                         |   1 +
 builtin.h                        |   1 +
 builtin/repo-info.c              | 229 +++++++++++++++++++++++++++++++
 command-list.txt                 |   1 +
 git.c                            |   1 +
 meson.build                      |   1 +
 t/meson.build                    |   1 +
 t/t1900-repo-info.sh             |  84 ++++++++++++
 11 files changed, 405 insertions(+)
 create mode 100644 Documentation/git-repo-info.adoc
 create mode 100644 builtin/repo-info.c
 create mode 100755 t/t1900-repo-info.sh
-- 
2.39.5 (Apple Git-154)
^ permalink raw reply	[flat|nested] 226+ messages in thread
* [GSoC RFC PATCH v3 1/5] repo-info: declare the repo-info command
  2025-07-06 23:19 ` [GSoC RFC PATCH v3 0/5] " Lucas Seiki Oshiro
@ 2025-07-06 23:19   ` Lucas Seiki Oshiro
  2025-07-06 23:19   ` [GSoC RFC PATCH v3 2/5] repo-info: add the --format flag Lucas Seiki Oshiro
                     ` (5 subsequent siblings)
  6 siblings, 0 replies; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-07-06 23:19 UTC (permalink / raw)
  To: git; +Cc: ps, karthik.188, ben.knoble, gitster, phillip.wood,
	Lucas Seiki Oshiro
Currently, `git rev-parse` covers a wide range of functionality not
directly related to parsing revisions, as its name says. Over time,
many features like parsing datestrings, options, paths, and others
were added to it because there wasn't a more appropriated command
to place them.
Create a new Git subcommand called `repo-info`. `git repo-info` will
bring the functionality of retrieving repository-related information
currently returned by `rev-parse`, displaying them in
machine-readable formats (JSON or a null-terminated format).
Also add entries for this new command in:
- the build files (Makefile, meson.build, Documentation/meson.build)
- builtin.h
- git.c
- .gitignore
- command-list.txt
- Documentation
Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Helped-by: Junio C Hamano <gitster@pobox.com>
Mentored-by: Karthik Nayak <karthik.188@gmail.com>
Mentored-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
---
 .gitignore                       |  1 +
 Documentation/git-repo-info.adoc | 45 ++++++++++++++++++++++++++++++++
 Documentation/meson.build        |  1 +
 Makefile                         |  1 +
 builtin.h                        |  1 +
 builtin/repo-info.c              | 21 +++++++++++++++
 command-list.txt                 |  1 +
 git.c                            |  1 +
 meson.build                      |  1 +
 9 files changed, 73 insertions(+)
 create mode 100644 Documentation/git-repo-info.adoc
 create mode 100644 builtin/repo-info.c
diff --git a/.gitignore b/.gitignore
index 04c444404e..b2f3fb0047 100644
--- a/.gitignore
+++ b/.gitignore
@@ -139,6 +139,7 @@
 /git-repack
 /git-replace
 /git-replay
+/git-repo-info
 /git-request-pull
 /git-rerere
 /git-reset
diff --git a/Documentation/git-repo-info.adoc b/Documentation/git-repo-info.adoc
new file mode 100644
index 0000000000..d5f34fc46e
--- /dev/null
+++ b/Documentation/git-repo-info.adoc
@@ -0,0 +1,45 @@
+git-repo-info(1)
+================
+
+NAME
+----
+git-repo-info - Retrieve information about a repository
+
+SYNOPSIS
+--------
+[synopsis]
+git repo-info
+
+DESCRIPTION
+-----------
+Retrieve information about the current repository in a machine-readable format.
+
+`git repo-info` will be the primary tool to query repository-specific
+information, which currently can also be done by calling `git rev-parse` (see
+linkgit:git-rev-parse[1]). `git repo-info` doesn't query information unrelated
+to the current repository or that is already retrieved by a specialized command,
+for example, `git config` (see linkgit:git-config[1]) or `git var` (see
+linkgit:git-var[1]).
+
+THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOR MAY CHANGE.
+
+OPTIONS
+-------
+
+`<key>`::
+Key of the value that will be retrieved. It should be in the format
+`<category>.<field>`. See the "CATEGORIES AND FIELDS" section below.
+
+CATEGORIES AND FIELDS
+---------------------
+
+The set of data that `git repo-info` can return is divided into
+categories. Each category is composed by one or more fields.
+
+SEE ALSO
+--------
+linkgit:git-rev-parse[1]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/meson.build b/Documentation/meson.build
index 2fe1a1369d..1369523741 100644
--- a/Documentation/meson.build
+++ b/Documentation/meson.build
@@ -116,6 +116,7 @@ manpages = {
   'git-repack.adoc' : 1,
   'git-replace.adoc' : 1,
   'git-replay.adoc' : 1,
+  'git-repo-info.adoc' : 1,
   'git-request-pull.adoc' : 1,
   'git-rerere.adoc' : 1,
   'git-reset.adoc' : 1,
diff --git a/Makefile b/Makefile
index 70d1543b6b..50e3a3cbcc 100644
--- a/Makefile
+++ b/Makefile
@@ -1308,6 +1308,7 @@ BUILTIN_OBJS += builtin/remote.o
 BUILTIN_OBJS += builtin/repack.o
 BUILTIN_OBJS += builtin/replace.o
 BUILTIN_OBJS += builtin/replay.o
+BUILTIN_OBJS += builtin/repo-info.o
 BUILTIN_OBJS += builtin/rerere.o
 BUILTIN_OBJS += builtin/reset.o
 BUILTIN_OBJS += builtin/rev-list.o
diff --git a/builtin.h b/builtin.h
index bff13e3069..cc6bc95962 100644
--- a/builtin.h
+++ b/builtin.h
@@ -216,6 +216,7 @@ int cmd_remote_ext(int argc, const char **argv, const char *prefix, struct repos
 int cmd_remote_fd(int argc, const char **argv, const char *prefix, struct repository *repo);
 int cmd_repack(int argc, const char **argv, const char *prefix, struct repository *repo);
 int cmd_replay(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_repo_info(int argc, const char **argv, const char *prefix, struct repository *repo);
 int cmd_rerere(int argc, const char **argv, const char *prefix, struct repository *repo);
 int cmd_reset(int argc, const char **argv, const char *prefix, struct repository *repo);
 int cmd_restore(int argc, const char **argv, const char *prefix, struct repository *repo);
diff --git a/builtin/repo-info.c b/builtin/repo-info.c
new file mode 100644
index 0000000000..0180c89908
--- /dev/null
+++ b/builtin/repo-info.c
@@ -0,0 +1,21 @@
+#include "builtin.h"
+#include "parse-options.h"
+
+int cmd_repo_info(int argc,
+		  const char **argv,
+		  const char *prefix,
+		  struct repository *repo UNUSED)
+{
+	const char *const repo_info_usage[] = {
+		"git repo-info",
+		NULL
+	};
+	struct option options[] = {
+		OPT_END()
+	};
+
+	argc = parse_options(argc, argv, prefix, options, repo_info_usage,
+			     0);
+
+	return 0;
+}
diff --git a/command-list.txt b/command-list.txt
index b7ade3ab9f..197ac21706 100644
--- a/command-list.txt
+++ b/command-list.txt
@@ -164,6 +164,7 @@ git-remote                              ancillarymanipulators           complete
 git-repack                              ancillarymanipulators           complete
 git-replace                             ancillarymanipulators           complete
 git-replay                              plumbingmanipulators
+git-repo-info                           plumbinginterrogators
 git-request-pull                        foreignscminterface             complete
 git-rerere                              ancillaryinterrogators
 git-reset                               mainporcelain           history
diff --git a/git.c b/git.c
index 07a5fe39fb..27a2b3569b 100644
--- a/git.c
+++ b/git.c
@@ -611,6 +611,7 @@ static struct cmd_struct commands[] = {
 	{ "repack", cmd_repack, RUN_SETUP },
 	{ "replace", cmd_replace, RUN_SETUP },
 	{ "replay", cmd_replay, RUN_SETUP },
+	{ "repo-info", cmd_repo_info, RUN_SETUP },
 	{ "rerere", cmd_rerere, RUN_SETUP },
 	{ "reset", cmd_reset, RUN_SETUP },
 	{ "restore", cmd_restore, RUN_SETUP | NEED_WORK_TREE },
diff --git a/meson.build b/meson.build
index 7fea4a34d6..06f2f647ba 100644
--- a/meson.build
+++ b/meson.build
@@ -645,6 +645,7 @@ builtin_sources = [
   'builtin/repack.c',
   'builtin/replace.c',
   'builtin/replay.c',
+  'builtin/repo-info.c',
   'builtin/rerere.c',
   'builtin/reset.c',
   'builtin/rev-list.c',
-- 
2.39.5 (Apple Git-154)
^ permalink raw reply related	[flat|nested] 226+ messages in thread
* [GSoC RFC PATCH v3 2/5] repo-info: add the --format flag
  2025-07-06 23:19 ` [GSoC RFC PATCH v3 0/5] " Lucas Seiki Oshiro
  2025-07-06 23:19   ` [GSoC RFC PATCH v3 1/5] repo-info: declare the repo-info command Lucas Seiki Oshiro
@ 2025-07-06 23:19   ` Lucas Seiki Oshiro
  2025-07-06 23:19   ` [GSoC RFC PATCH v3 3/5] repo-info: add the field references.format Lucas Seiki Oshiro
                     ` (4 subsequent siblings)
  6 siblings, 0 replies; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-07-06 23:19 UTC (permalink / raw)
  To: git; +Cc: ps, karthik.188, ben.knoble, gitster, phillip.wood,
	Lucas Seiki Oshiro
Currently, git-rev-parse with the 'options for files' flags returns only
the requested values (e.g. `git rev-parse --show-toplevel
--show-ref-format` returns the top-level repository and the reference
storage format), dumping them only separated by line feeds.
However, from the perspective of a programmatic interface, this format
is not a good choice as, for example:
- it doesn't show the keys of the requested fields, meaning that the
  caller depends on the order of the requested fields for parsing them;
- there's no guarantee that each line contains the value of one field,
  for example, the returned values may contain line feeds.
This way, given that git-repo-info aims to produce a machine-readable
output, it needs to follow other formats that are better suited for
those means, for example:
- JSON, which is widely used as a data exchange format;
- null-terminated, composed zero or more <key><LF><value><NUL> entries.
Add the --format flag to the repo-info command, allowing the user to
choose between output formats. Add as options "json" and
"null-terminated", and use "json" as the default format.
Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Helped-by: Junio C Hamano <gitster@pobox.com>
Mentored-by: Karthik Nayak <karthik.188@gmail.com>
Mentored-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
---
 Documentation/git-repo-info.adoc | 32 ++++++++++++++++-
 builtin/repo-info.c              | 61 ++++++++++++++++++++++++++++++--
 2 files changed, 90 insertions(+), 3 deletions(-)
diff --git a/Documentation/git-repo-info.adoc b/Documentation/git-repo-info.adoc
index d5f34fc46e..bf1d391482 100644
--- a/Documentation/git-repo-info.adoc
+++ b/Documentation/git-repo-info.adoc
@@ -8,7 +8,7 @@ git-repo-info - Retrieve information about a repository
 SYNOPSIS
 --------
 [synopsis]
-git repo-info
+git repo-info [--format <format>] [<field>...]
 
 DESCRIPTION
 -----------
@@ -25,6 +25,36 @@ THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOR MAY CHANGE.
 
 OPTIONS
 -------
+`--format`::
+Specify the output format `<format>`. The valid values are:
++
+* `json`: output the data in JSON format, following this schema:
++
+----------------
+{
+  "category1": {
+    "field1": value1,
+    "field2": value2,
+    ...
+  },
+  "category2": {
+    "field3": value3,
+    ...
+  },
+  ...
+}
+----------------
+* `null-terminated`: output the data in a null-terminated format,
+following this syntax:
++
+----------------
+category1.field1<LF>value1<NUL>
+category1.field2<LF>value2<NUL>
+...
+----------------
++
+In this format, the fields will be returned in the same order they were
+requested.
 
 `<key>`::
 Key of the value that will be retrieved. It should be in the format
diff --git a/builtin/repo-info.c b/builtin/repo-info.c
index 0180c89908..cb4785169f 100644
--- a/builtin/repo-info.c
+++ b/builtin/repo-info.c
@@ -1,21 +1,78 @@
 #include "builtin.h"
+#include "json-writer.h"
 #include "parse-options.h"
 
+enum output_format {
+	FORMAT_JSON,
+	FORMAT_NULL_TERMINATED,
+};
+
+struct repo_info {
+	struct repository *repo;
+	enum output_format format;
+};
+
+static void repo_info_init(struct repo_info *repo_info,
+			   struct repository *repo,
+			   const char *format)
+{
+	repo_info->repo = repo;
+
+	if (!format || !strcmp(format, "json"))
+		repo_info->format = FORMAT_JSON;
+	else if (!strcmp(format, "null-terminated"))
+		repo_info->format = FORMAT_NULL_TERMINATED;
+	else
+		die("invalid format %s", format);
+}
+
+static void repo_info_print_json(struct repo_info *repo_info UNUSED)
+{
+	struct json_writer jw;
+
+	jw_init(&jw);
+
+	jw_object_begin(&jw, 1);
+	jw_end(&jw);
+
+	puts(jw.json.buf);
+	jw_release(&jw);
+}
+
+static void repo_info_print(struct repo_info *repo_info)
+{
+	switch (repo_info->format) {
+	case FORMAT_JSON:
+		repo_info_print_json(repo_info);
+		break;
+	case FORMAT_NULL_TERMINATED:
+		break;
+	default:
+		BUG("%d: not a valid repo-info format", repo_info->format);
+	}
+}
+
 int cmd_repo_info(int argc,
 		  const char **argv,
 		  const char *prefix,
-		  struct repository *repo UNUSED)
+		  struct repository *repo)
 {
 	const char *const repo_info_usage[] = {
-		"git repo-info",
+		"git repo-info [--format <format>] [<field>...]",
 		NULL
 	};
+	struct repo_info repo_info;
+	const char *format = NULL;
 	struct option options[] = {
+		OPT_STRING(0, "format", &format, N_("format"),
+			   N_("output format")),
 		OPT_END()
 	};
 
 	argc = parse_options(argc, argv, prefix, options, repo_info_usage,
 			     0);
+	repo_info_init(&repo_info, repo, format);
+	repo_info_print(&repo_info);
 
 	return 0;
 }
-- 
2.39.5 (Apple Git-154)
^ permalink raw reply related	[flat|nested] 226+ messages in thread
* [GSoC RFC PATCH v3 3/5] repo-info: add the field references.format
  2025-07-06 23:19 ` [GSoC RFC PATCH v3 0/5] " Lucas Seiki Oshiro
  2025-07-06 23:19   ` [GSoC RFC PATCH v3 1/5] repo-info: declare the repo-info command Lucas Seiki Oshiro
  2025-07-06 23:19   ` [GSoC RFC PATCH v3 2/5] repo-info: add the --format flag Lucas Seiki Oshiro
@ 2025-07-06 23:19   ` Lucas Seiki Oshiro
  2025-07-06 23:19   ` [GSoC RFC PATCH v3 4/5] repo-info: add field layout.bare Lucas Seiki Oshiro
                     ` (3 subsequent siblings)
  6 siblings, 0 replies; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-07-06 23:19 UTC (permalink / raw)
  To: git; +Cc: ps, karthik.188, ben.knoble, gitster, phillip.wood,
	Lucas Seiki Oshiro
This commit is part of the series that introduce the new command
git-repo-info.
The flag `--show-ref-format` from git-rev-parse is used for retrieving
the reference format (i.e. `files` or `reftable`). This way, it is
used for querying repository information, fitting in the purpose of
git-repo-info.
Then, add a new field `references.format` to the repo-info command
containing that information.
Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Helped-by: Junio C Hamano <gitster@pobox.com>
Mentored-by: Karthik Nayak <karthik.188@gmail.com>
Mentored-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
---
 Documentation/git-repo-info.adoc |   4 ++
 builtin/repo-info.c              | 105 ++++++++++++++++++++++++++++++-
 t/meson.build                    |   1 +
 t/t1900-repo-info.sh             |  64 +++++++++++++++++++
 4 files changed, 171 insertions(+), 3 deletions(-)
 create mode 100755 t/t1900-repo-info.sh
diff --git a/Documentation/git-repo-info.adoc b/Documentation/git-repo-info.adoc
index bf1d391482..dd221b236e 100644
--- a/Documentation/git-repo-info.adoc
+++ b/Documentation/git-repo-info.adoc
@@ -66,6 +66,10 @@ CATEGORIES AND FIELDS
 The set of data that `git repo-info` can return is divided into
 categories. Each category is composed by one or more fields.
 
+`references`::
+Reference-related data:
+* `format`: the reference storage format, either `files` or `reftable`.
+
 SEE ALSO
 --------
 linkgit:git-rev-parse[1]
diff --git a/builtin/repo-info.c b/builtin/repo-info.c
index cb4785169f..98a0d83d51 100644
--- a/builtin/repo-info.c
+++ b/builtin/repo-info.c
@@ -1,20 +1,39 @@
 #include "builtin.h"
 #include "json-writer.h"
 #include "parse-options.h"
+#include "refs.h"
 
 enum output_format {
 	FORMAT_JSON,
 	FORMAT_NULL_TERMINATED,
 };
 
+enum repo_info_category {
+	CATEGORY_REFERENCES = 1 << 0,
+};
+
+enum repo_info_references_field {
+	FIELD_REFERENCES_FORMAT = 1 << 0,
+};
+
+struct repo_info_field {
+	enum repo_info_category category;
+	union {
+		enum repo_info_references_field references;
+	} u;
+};
+
 struct repo_info {
 	struct repository *repo;
 	enum output_format format;
+	size_t fields_nr;
+	struct repo_info_field *fields;
 };
 
 static void repo_info_init(struct repo_info *repo_info,
 			   struct repository *repo,
-			   const char *format)
+			   const char *format,
+			   int argc, const char **argv)
 {
 	repo_info->repo = repo;
 
@@ -24,15 +43,93 @@ static void repo_info_init(struct repo_info *repo_info,
 		repo_info->format = FORMAT_NULL_TERMINATED;
 	else
 		die("invalid format %s", format);
+
+	repo_info->fields_nr = argc;
+	ALLOC_ARRAY(repo_info->fields, argc);
+
+	for (int i = 0; i < argc; i++) {
+		const char *arg = argv[i];
+		struct repo_info_field *field = repo_info->fields + i;
+		if (!strcmp(arg, "references.format")) {
+			field->category = CATEGORY_REFERENCES;
+			field->u.references = FIELD_REFERENCES_FORMAT;
+		} else {
+			die("invalid field '%s'", arg);
+		}
+	}
+}
+
+static void repo_info_release(struct repo_info *repo_info)
+{
+	free(repo_info->fields);
 }
 
-static void repo_info_print_json(struct repo_info *repo_info UNUSED)
+static void append_null_terminated_field(struct strbuf *buf,
+					 struct repo_info *repo_info,
+					 struct repo_info_field *field)
+{
+	struct repository *repo = repo_info->repo;
+
+	switch (field->category) {
+	case CATEGORY_REFERENCES:
+		strbuf_addstr(buf, "references.");
+		switch (field->u.references) {
+		case FIELD_REFERENCES_FORMAT:
+			strbuf_addstr(buf, "format\n");
+			strbuf_addstr(buf, ref_storage_format_to_name(
+						   repo->ref_storage_format));
+			break;
+		}
+		break;
+	}
+
+	strbuf_addch(buf, '\0');
+}
+
+static void repo_info_print_null_terminated(struct repo_info *repo_info)
+{
+	struct strbuf buf;
+
+	strbuf_init(&buf, 256);
+
+	for (size_t i = 0; i < repo_info->fields_nr; i++) {
+		struct repo_info_field *field = &repo_info->fields[i];
+		append_null_terminated_field(&buf, repo_info, field);
+	}
+
+	fwrite(buf.buf, 1, buf.len, stdout);
+	strbuf_release(&buf);
+}
+
+static void repo_info_print_json(struct repo_info *repo_info)
 {
 	struct json_writer jw;
+	unsigned int categories = 0;
+	unsigned int references_fields = 0;
+	struct repository *repo = repo_info->repo;
+
+	for (size_t i = 0; i < repo_info->fields_nr; i++) {
+		struct repo_info_field *field = repo_info->fields + i;
+		categories |= field->category;
+		switch (field->category) {
+		case CATEGORY_REFERENCES:
+			references_fields |= field->u.references;
+			break;
+		}
+	}
 
 	jw_init(&jw);
 
 	jw_object_begin(&jw, 1);
+	if (categories & CATEGORY_REFERENCES) {
+		jw_object_inline_begin_object(&jw, "references");
+		if (references_fields & FIELD_REFERENCES_FORMAT) {
+			const char *format_name = ref_storage_format_to_name(
+				repo->ref_storage_format);
+			jw_object_string(&jw, "format", format_name);
+		}
+		jw_end(&jw);
+	}
 	jw_end(&jw);
 
 	puts(jw.json.buf);
@@ -46,6 +143,7 @@ static void repo_info_print(struct repo_info *repo_info)
 		repo_info_print_json(repo_info);
 		break;
 	case FORMAT_NULL_TERMINATED:
+		repo_info_print_null_terminated(repo_info);
 		break;
 	default:
 		BUG("%d: not a valid repo-info format", repo_info->format);
@@ -71,8 +169,9 @@ int cmd_repo_info(int argc,
 
 	argc = parse_options(argc, argv, prefix, options, repo_info_usage,
 			     0);
-	repo_info_init(&repo_info, repo, format);
+	repo_info_init(&repo_info, repo, format, argc, argv);
 	repo_info_print(&repo_info);
+	repo_info_release(&repo_info);
 
 	return 0;
 }
diff --git a/t/meson.build b/t/meson.build
index 6d7fe6b117..e2c9393189 100644
--- a/t/meson.build
+++ b/t/meson.build
@@ -245,6 +245,7 @@ integration_tests = [
   't1700-split-index.sh',
   't1701-racy-split-index.sh',
   't1800-hook.sh',
+  't1900-repo-info.sh',
   't2000-conflict-when-checking-files-out.sh',
   't2002-checkout-cache-u.sh',
   't2003-checkout-cache-mkdir.sh',
diff --git a/t/t1900-repo-info.sh b/t/t1900-repo-info.sh
new file mode 100755
index 0000000000..2af9d1d9c3
--- /dev/null
+++ b/t/t1900-repo-info.sh
@@ -0,0 +1,64 @@
+#!/bin/sh
+
+test_description='test git repo-info'
+
+. ./test-lib.sh
+
+parse_json () {
+	tr '\n' ' ' | "$PERL_PATH" "$TEST_DIRECTORY/t0019/parse_json.perl"
+}
+
+test_lazy_prereq PERLJSON '
+	perl -MJSON -e "exit 0"
+'
+
+# Test if a field is correctly returned in both null-terminated and json formats.
+#
+# Usage: test_repo_info <label> <init command> <key> <expected value>
+#
+# Arguments:
+#   label: the label of the test
+#   init command: a command that creates a repository called 'repo', configured
+#      accordingly to what is being tested
+#   key: the key of the field that is being tested
+#   expected value: the value that the field should contain
+test_repo_info () {
+        label=$1
+        init_command=$2
+        key=$3
+        expected_value=$4
+
+        test_expect_success PERLJSON "json: $label" '
+		test_when_finished "rm -rf repo" &&
+		eval "$init_command" &&
+		echo "$expected_value" >expect &&
+		git -C repo repo-info "$key" >output &&
+		parse_json <output >parsed &&
+		grep -F "row[0].$key" parsed | cut -d " " -f 2 >value &&
+		sed -n -e "/row[0].$key/{
+			s/^[^ ]* //
+			s/^1\$/true/
+			s/^0\$/false/
+			p;
+			}" parsed >actual &&
+		sed "s/^0$/false/" <value| sed "s/^1$/true/" >actual &&
+		test_cmp expect actual
+        '
+
+        test_expect_success "null-terminated: $label" '
+		test_when_finished "rm -rf repo" &&
+		eval "$init_command" &&
+		echo "$expected_value" | lf_to_nul >expect &&
+		git -C repo repo-info --format=null-terminated "$key" >output &&
+		tail -n 1 output >actual &&
+		test_cmp expect actual
+	'
+}
+
+test_repo_info 'ref format files is retrieved correctly' '
+	git init --ref-format=files repo' 'references.format' 'files'
+
+test_repo_info 'ref format reftable is retrieved correctly' '
+	git init --ref-format=reftable repo' 'references.format' 'reftable'
+
+test_done
-- 
2.39.5 (Apple Git-154)
^ permalink raw reply related	[flat|nested] 226+ messages in thread
* [GSoC RFC PATCH v3 4/5] repo-info: add field layout.bare
  2025-07-06 23:19 ` [GSoC RFC PATCH v3 0/5] " Lucas Seiki Oshiro
                     ` (2 preceding siblings ...)
  2025-07-06 23:19   ` [GSoC RFC PATCH v3 3/5] repo-info: add the field references.format Lucas Seiki Oshiro
@ 2025-07-06 23:19   ` Lucas Seiki Oshiro
  2025-07-06 23:19   ` [GSoC RFC PATCH v3 5/5] repo-info: add field layout.shallow Lucas Seiki Oshiro
                     ` (2 subsequent siblings)
  6 siblings, 0 replies; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-07-06 23:19 UTC (permalink / raw)
  To: git; +Cc: ps, karthik.188, ben.knoble, gitster, phillip.wood,
	Lucas Seiki Oshiro
This commit is part of the series that introduces the new command
git-repo-info.
The flag --is-bare-repository from git-rev-parse is used for retrieving
whether the current repository is bare . This way, it is used for
querying repository information, fitting in the purpose of
git-repo-info.
Then, add a new field layout.bare to the git-repo-info command
containing that information.
Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Helped-by: Junio C Hamano <gitster@pobox.com>
Mentored-by: Karthik Nayak <karthik.188@gmail.com>
Mentored-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
---
 Documentation/git-repo-info.adoc |  4 ++++
 builtin/repo-info.c              | 37 ++++++++++++++++++++++++++++++++
 t/t1900-repo-info.sh             |  6 ++++++
 3 files changed, 47 insertions(+)
diff --git a/Documentation/git-repo-info.adoc b/Documentation/git-repo-info.adoc
index dd221b236e..67d19406ad 100644
--- a/Documentation/git-repo-info.adoc
+++ b/Documentation/git-repo-info.adoc
@@ -70,6 +70,10 @@ categories. Each category is composed by one or more fields.
 Reference-related data:
 * `format`: the reference storage format, either `files` or `reftable`.
 
+`layout`::
+Information about the how the current repository is represented:
+* `bare`: `true` if this is a bare repository, otherwise `false`.
+
 SEE ALSO
 --------
 linkgit:git-rev-parse[1]
diff --git a/builtin/repo-info.c b/builtin/repo-info.c
index 98a0d83d51..7e29ae8519 100644
--- a/builtin/repo-info.c
+++ b/builtin/repo-info.c
@@ -1,4 +1,8 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
 #include "builtin.h"
+#include "environment.h"
+#include "hash.h"
 #include "json-writer.h"
 #include "parse-options.h"
 #include "refs.h"
@@ -10,16 +14,22 @@ enum output_format {
 
 enum repo_info_category {
 	CATEGORY_REFERENCES = 1 << 0,
+	CATEGORY_LAYOUT = 1 << 1,
 };
 
 enum repo_info_references_field {
 	FIELD_REFERENCES_FORMAT = 1 << 0,
 };
 
+enum repo_info_layout_field {
+	FIELD_LAYOUT_BARE = 1 << 0,
+};
+
 struct repo_info_field {
 	enum repo_info_category category;
 	union {
 		enum repo_info_references_field references;
+		enum repo_info_layout_field layout;
 	} u;
 };
 
@@ -53,6 +63,9 @@ static void repo_info_init(struct repo_info *repo_info,
 		if (!strcmp(arg, "references.format")) {
 			field->category = CATEGORY_REFERENCES;
 			field->u.references = FIELD_REFERENCES_FORMAT;
+		} else if (!strcmp(arg, "layout.bare")) {
+			field->category = CATEGORY_LAYOUT;
+			field->u.layout = FIELD_LAYOUT_BARE;
 		} else {
 			die("invalid field '%s'", arg);
 		}
@@ -81,6 +94,17 @@ static void append_null_terminated_field(struct strbuf *buf,
 			break;
 		}
 		break;
+
+	case CATEGORY_LAYOUT:
+		strbuf_addstr(buf, "layout.");
+		switch (field->u.layout) {
+		case FIELD_LAYOUT_BARE:
+			strbuf_addstr(buf, "bare\n");
+			strbuf_addstr(buf, is_bare_repository() ? "true" :
+								  "false");
+			break;
+		}
+		break;
 	}
 
 	strbuf_addch(buf, '\0');
@@ -106,6 +130,7 @@ static void repo_info_print_json(struct repo_info *repo_info)
 	struct json_writer jw;
 	unsigned int categories = 0;
 	unsigned int references_fields = 0;
+	unsigned int layout_fields = 0;
 	struct repository *repo = repo_info->repo;
 
 	for (size_t i = 0; i < repo_info->fields_nr; i++) {
@@ -115,6 +140,9 @@ static void repo_info_print_json(struct repo_info *repo_info)
 		case CATEGORY_REFERENCES:
 			references_fields |= field->u.references;
 			break;
+		case CATEGORY_LAYOUT:
+			layout_fields |= field->u.layout;
+			break;
 		}
 	}
 
@@ -130,6 +158,15 @@ static void repo_info_print_json(struct repo_info *repo_info)
 		}
 		jw_end(&jw);
 	}
+
+	if (categories & CATEGORY_LAYOUT) {
+		jw_object_inline_begin_object(&jw, "layout");
+		if (layout_fields & FIELD_LAYOUT_BARE) {
+			jw_object_bool(&jw, "bare",
+				       is_bare_repository());
+		}
+		jw_end(&jw);
+	}
 	jw_end(&jw);
 
 	puts(jw.json.buf);
diff --git a/t/t1900-repo-info.sh b/t/t1900-repo-info.sh
index 2af9d1d9c3..246c4bc40c 100755
--- a/t/t1900-repo-info.sh
+++ b/t/t1900-repo-info.sh
@@ -61,4 +61,10 @@ test_repo_info 'ref format files is retrieved correctly' '
 test_repo_info 'ref format reftable is retrieved correctly' '
 	git init --ref-format=reftable repo' 'references.format' 'reftable'
 
+test_repo_info 'bare repository = false is retrieved correctly' '
+	git init repo' 'layout.bare' 'false'
+
+test_repo_info 'bare repository = true is retrieved correctly' '
+	git init --bare repo' 'layout.bare' 'true'
+
 test_done
-- 
2.39.5 (Apple Git-154)
^ permalink raw reply related	[flat|nested] 226+ messages in thread
* [GSoC RFC PATCH v3 5/5] repo-info: add field layout.shallow
  2025-07-06 23:19 ` [GSoC RFC PATCH v3 0/5] " Lucas Seiki Oshiro
                     ` (3 preceding siblings ...)
  2025-07-06 23:19   ` [GSoC RFC PATCH v3 4/5] repo-info: add field layout.bare Lucas Seiki Oshiro
@ 2025-07-06 23:19   ` Lucas Seiki Oshiro
  2025-07-08 10:11   ` [GSoC RFC PATCH v3 0/5] repo-info: add new command for retrieving repository info Phillip Wood
  2025-07-11 17:13   ` Lucas Seiki Oshiro
  6 siblings, 0 replies; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-07-06 23:19 UTC (permalink / raw)
  To: git; +Cc: ps, karthik.188, ben.knoble, gitster, phillip.wood,
	Lucas Seiki Oshiro
This commit is part of the series that introduces the new command
git-repo-info.
The flag `--is-shallow-repository` from git-rev-parse is used for
retrieving whether the repository is shallow. This way, it is used for
querying repository information, fitting in the purpose of
git-repo-info.
Then, add a new field `layout.shallow` to the git-repo-info command
containing that information.
Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Helped-by: Junio C Hamano <gitster@pobox.com>
Mentored-by: Karthik Nayak <karthik.188@gmail.com>
Mentored-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
---
 Documentation/git-repo-info.adoc |  1 +
 builtin/repo-info.c              | 15 +++++++++++++++
 t/t1900-repo-info.sh             | 14 ++++++++++++++
 3 files changed, 30 insertions(+)
diff --git a/Documentation/git-repo-info.adoc b/Documentation/git-repo-info.adoc
index 67d19406ad..3261cd97b5 100644
--- a/Documentation/git-repo-info.adoc
+++ b/Documentation/git-repo-info.adoc
@@ -73,6 +73,7 @@ Reference-related data:
 `layout`::
 Information about the how the current repository is represented:
 * `bare`: `true` if this is a bare repository, otherwise `false`.
+* `shallow`: `true` if this is a shallow repository, otherwise `false`.
 
 SEE ALSO
 --------
diff --git a/builtin/repo-info.c b/builtin/repo-info.c
index 7e29ae8519..2fa6544d15 100644
--- a/builtin/repo-info.c
+++ b/builtin/repo-info.c
@@ -6,6 +6,7 @@
 #include "json-writer.h"
 #include "parse-options.h"
 #include "refs.h"
+#include "shallow.h"
 
 enum output_format {
 	FORMAT_JSON,
@@ -23,6 +24,7 @@ enum repo_info_references_field {
 
 enum repo_info_layout_field {
 	FIELD_LAYOUT_BARE = 1 << 0,
+	FIELD_LAYOUT_SHALLOW = 1 << 1,
 };
 
 struct repo_info_field {
@@ -66,6 +68,9 @@ static void repo_info_init(struct repo_info *repo_info,
 		} else if (!strcmp(arg, "layout.bare")) {
 			field->category = CATEGORY_LAYOUT;
 			field->u.layout = FIELD_LAYOUT_BARE;
+		} else if (!strcmp(arg, "layout.shallow")) {
+			field->category = CATEGORY_LAYOUT;
+			field->u.layout = FIELD_LAYOUT_SHALLOW;
 		} else {
 			die("invalid field '%s'", arg);
 		}
@@ -103,6 +108,11 @@ static void append_null_terminated_field(struct strbuf *buf,
 			strbuf_addstr(buf, is_bare_repository() ? "true" :
 								  "false");
 			break;
+		case FIELD_LAYOUT_SHALLOW:
+			strbuf_addstr(buf, "shallow\n");
+			strbuf_addstr(buf, is_repository_shallow(repo) ? "true" :
+									 "false");
+			break;
 		}
 		break;
 	}
@@ -165,6 +175,11 @@ static void repo_info_print_json(struct repo_info *repo_info)
 			jw_object_bool(&jw, "bare",
 				       is_bare_repository());
 		}
+
+		if (layout_fields & FIELD_LAYOUT_SHALLOW) {
+			jw_object_bool(&jw, "shallow",
+				       is_repository_shallow(repo));
+		}
 		jw_end(&jw);
 	}
 	jw_end(&jw);
diff --git a/t/t1900-repo-info.sh b/t/t1900-repo-info.sh
index 246c4bc40c..fdbbfb42a0 100755
--- a/t/t1900-repo-info.sh
+++ b/t/t1900-repo-info.sh
@@ -67,4 +67,18 @@ test_repo_info 'bare repository = false is retrieved correctly' '
 test_repo_info 'bare repository = true is retrieved correctly' '
 	git init --bare repo' 'layout.bare' 'true'
 
+test_repo_info 'shallow repository = false is retrieved correctly' '
+	git init repo' 'layout.shallow' 'false'
+
+test_repo_info 'shallow repository = true is retrieved correctly' '
+	git init remote &&
+	cd remote &&
+	echo x >x &&
+	git add x &&
+	git commit -m x &&
+	cd .. &&
+	git clone --depth 1 "file://$PWD/remote" repo &&
+	rm -rf remote
+	' 'layout.shallow' 'true'
+
 test_done
-- 
2.39.5 (Apple Git-154)
^ permalink raw reply related	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH v2 1/7] repo-info: declare the repo-info command
  2025-07-04 21:40       ` Lucas Seiki Oshiro
@ 2025-07-07  6:01         ` Patrick Steinhardt
  2025-07-09 20:05           ` Justin Tobler
  0 siblings, 1 reply; 226+ messages in thread
From: Patrick Steinhardt @ 2025-07-07  6:01 UTC (permalink / raw)
  To: Lucas Seiki Oshiro
  Cc: git, karthik.188, ben.knoble, gitster, Justin Tobler,
	Derrick Stolee
On Fri, Jul 04, 2025 at 06:40:11PM -0300, Lucas Seiki Oshiro wrote:
> 
> > One thing I wondered: Justin is currently iterating on git-survey(1),
> > which is the command Stolee proposed a while ago to gather repository
> > metrics.
> 
> I didn't find it in the mailing list, but I remember seeing it in the
> the GitLab's fork. Is it this unmerged MR? 
> https://gitlab.com/gitlab-org/git/-/merge_requests/369
Yup. It's been posted to the mailing list as part of [1].
> > Would it make sense to maybe have such whole-repo commands
> > grouped together in a `git repo` top-level command? E.g. `git repo info`
> > for your command, `git repo size` to gather information about the repo
> > size.
> 
> It seems to be very nice for me! In fact, this being a home also for
> statistics is something I considered while writing the first versions of
> my GSoC proposal.
> 
> And what about merging the two codes into a single API? Something like:
> 
> ```
> git repo-info layout.bare references.format survey.commit-count
> {
>   "layout": {
>     "bare": true
>   },
>   "references": {
>     "format": "files"
>   },
>   "survey": {
>     "commit-count": 42
>   }
> }
> 
> ?
We could in theory do that. But there's two things we need to be
cautious about:
  1. We should be mindful about what specifically this tool is about. It
     shouldn't become the next tool that does way too many different
     things.
  2. One of the idea of git-survey(1) is to eventually replace
     git-sizer(1). This will require very specific presentation formats
     that aren't really compatible with any of the other information.
Out of these two I think the second item is the more important one why
git-survey(1) should exist as a standalone tool, either as a top-level
command or as a subcommand.
> During our meetings, Karthik suggested (I'm planning to it later) to also
> allow to request an entire category instead of only the fields. Then, this
> would also be possible:
> 
> ```
> $ git repo-info survey
> {
>   "survey": {
>     "commit-count": 42,
>     "blob-count": 1234
> }
> ```
It raises another question though: if we ever were to add `--all` we'll
need to step a bit careful about what kind of information we add to this
tool. All of the information proposed so far can be computed rather
trivially. But computing repository sizes has way higher computational
complexity and may easily take seconds, maybe even minutes in large
repositories.
That to me further points into the direction of giving those two tools a
common top-level command (`git repo info`, `git repo survey`), but to
not mix concerns too much with one another.
> But I don't know what are Justin's plans for git-survey, if it would be a
> porcelain command for showing those stats to the user of if it is targeted
> for being parsed like this `repo-info`.
> 
> I'm just brainstorming because I liked the idea :-)
I've already pinged him on this and he liked the idea of having a common
top-level command. I guess he'll respond later today or this week.
Patrick
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH v3 0/5] repo-info: add new command for retrieving repository info
  2025-07-06 23:19 ` [GSoC RFC PATCH v3 0/5] " Lucas Seiki Oshiro
                     ` (4 preceding siblings ...)
  2025-07-06 23:19   ` [GSoC RFC PATCH v3 5/5] repo-info: add field layout.shallow Lucas Seiki Oshiro
@ 2025-07-08 10:11   ` Phillip Wood
  2025-07-08 19:27     ` Lucas Seiki Oshiro
  2025-07-11 17:13   ` Lucas Seiki Oshiro
  6 siblings, 1 reply; 226+ messages in thread
From: Phillip Wood @ 2025-07-08 10:11 UTC (permalink / raw)
  To: Lucas Seiki Oshiro, git
  Cc: ps, karthik.188, ben.knoble, gitster, phillip.wood
Hi Lucas
On 07/07/2025 00:19, Lucas Seiki Oshiro wrote:
> Hi!
> 
> This is the third version of the patchset introducing the new Git command
> called `repo-info`, which will return repository information currently stored
> under git-rev-parse using machine-readable formats.
> The main changes since v2 are:
> 
> - Documentation for git-repo-info has been added.
> - The `--allow-empty` flag was removed. In this version, repo-info no longer
>    returns a default set of data when called without parameters. However, an
>    `--all` flag is planned for a future version.
> - The `plaintext` format was replaced by a null-terminated format, following
>    the syntax of `git config --list -z`.
These all look like good changes. Looking through this series I do think 
that it would be more readable and maintainable if you adopted the table 
drive approach suggested by Junio. That way we would avoid the nested 
switch statements and each piece of information only needs to be 
retrieved once rather that having to retrieve it separately for the JSON 
and plaintext output. Below is a sketch of might look. Each key is 
handled by a callback and we have a table that maps key names to 
callbacks. For the json output we use one json writer per category to 
build output for each category.
Best Wishes
Phillip
enum format {
	FORMAT_JSON,
	FORMAT_PLAINTEXT,
};
enum category {
	CATEGORY_LAYOUT,
};
static const char *category_name[] = {
	[CATEGORY_LAYOUT] = "layout",
}
struct context {
	struct json_writer *writer[ARRAY_SIZE(category_name)];
	enum format format;
};
static struct ensure_writer(struct context ctx, enum category cat)
{
	struct json_writer *writer = ctx.writer[cat];
	if (!writer) {
		writer = xmalloc(sizeof(*writer));
		jw_init(writer);
		jw_object_begin(writer, 1);
		ctx->writer[cat] = writer;
	}
	return writer;
}
static void handle_layout_bare(struct context ctx)
{
	int bare = ...;
	
	if (ctx->format == FORMAT_JSON) {
		struct json_writer *writer =
			ensure_writer(ctx, CATEGORY_LAYOUT);
		jw_object_bool(writer, "layout.bare", bare);
	} else {
		printf("%s\n%s\c", "layout.bare", bare ? "true", "false", '\0');
	}
}
static int cmd_repo_info(int argc, const char **argv, sturct repo *r)
{
	struct context = { 0 };
	struct {
		const char *key;
		void (*cb)(struct *ctx);
	} handler = {
		{ "layout.bare", handle_layout_bare, },
	};
	/* parse options */
	for (int i = 0; i < argc; i++) {
		/* TODO use bsearch()? */
		for (size_t j = 0; j < ARRAY_SIZE(handler); j++) {
			if (!strcmp(argv[i], handler[j].key) {
				handler[j].cb(&ctx);
				break;
			}
		}
	}
	if (ctx->format == JSON) {
		struct json_writer writer = JSON_WRITER_INIT;
		jw_object_begin(&writer, 1);
		for (size_t i = 0; i < ARRAY_SIZE(category); i++) {
			if (ctx.writer[i]) {
				jw_object_end(ctx.writer[i]);
				jw_object_sub_obj(&writer,
						  category_name[i],
						  ctx.writer[i]);
			}
		}
		jw_object_end(&writer);
		fputs(writer.buf.buf);
	}
	context_release(&ctx);
	
	return 0;
}
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH v3 0/5] repo-info: add new command for retrieving repository info
  2025-07-08 10:11   ` [GSoC RFC PATCH v3 0/5] repo-info: add new command for retrieving repository info Phillip Wood
@ 2025-07-08 19:27     ` Lucas Seiki Oshiro
  2025-07-10 13:15       ` Phillip Wood
  0 siblings, 1 reply; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-07-08 19:27 UTC (permalink / raw)
  To: Phillip Wood; +Cc: git, ps, karthik.188, ben.knoble, gitster, phillip.wood
> Hi Lucas
Hi, Phillip!
> These all look like good changes. Looking through this series I do think that
> it would be more readable and maintainable if you adopted the table drive
> approach suggested by Junio.
Today I had a meeting with my mentors (Karthik and Patrick), and yeah, this is
something that I'll change in v4.
Returning the keys in the same order as they were requested in the
null-terminated format is not so useful now that I'm keeping the keys in the
output. Dropping this assumption allows me to make this code simpler.
> That way we would avoid the nested switch statements and each piece of
> information only needs to be retrieved once rather that having to retrieve it
> separately for the JSON and plaintext output. Below is a sketch of might look.
> Each key is handled by a callback and we have a table that maps key names to
> callbacks. For the json output we use one json writer per category to build
> output for each category.
At first glance it looks good to me. It still seems to me that it needs to
somehow treat duplicated keys.
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH v2 1/7] repo-info: declare the repo-info command
  2025-07-07  6:01         ` Patrick Steinhardt
@ 2025-07-09 20:05           ` Justin Tobler
  0 siblings, 0 replies; 226+ messages in thread
From: Justin Tobler @ 2025-07-09 20:05 UTC (permalink / raw)
  To: Patrick Steinhardt
  Cc: Lucas Seiki Oshiro, git, karthik.188, ben.knoble, gitster,
	Derrick Stolee
On 25/07/07 08:01AM, Patrick Steinhardt wrote:
> On Fri, Jul 04, 2025 at 06:40:11PM -0300, Lucas Seiki Oshiro wrote:
> > > Would it make sense to maybe have such whole-repo commands
> > > grouped together in a `git repo` top-level command? E.g. `git repo info`
> > > for your command, `git repo size` to gather information about the repo
> > > size.
> > 
> > It seems to be very nice for me! In fact, this being a home also for
> > statistics is something I considered while writing the first versions of
> > my GSoC proposal.
> > 
> > And what about merging the two codes into a single API? Something like:
> > 
> > ```
> > git repo-info layout.bare references.format survey.commit-count
> > {
> >   "layout": {
> >     "bare": true
> >   },
> >   "references": {
> >     "format": "files"
> >   },
> >   "survey": {
> >     "commit-count": 42
> >   }
> > }
> > 
> > ?
> 
> We could in theory do that. But there's two things we need to be
> cautious about:
> 
>   1. We should be mindful about what specifically this tool is about. It
>      shouldn't become the next tool that does way too many different
>      things.
> 
>   2. One of the idea of git-survey(1) is to eventually replace
>      git-sizer(1). This will require very specific presentation formats
>      that aren't really compatible with any of the other information.
> 
> Out of these two I think the second item is the more important one why
> git-survey(1) should exist as a standalone tool, either as a top-level
> command or as a subcommand.
As Patrick mentioned, the focus for git-survey(1) is to be an eventual
substitute for git-sizer(1). For the initial implementation I was
imagining a simple plaintext format that outputs key/value pairs and
looks something like the following example:
  references.branches.count=15
  references.tags.count=2
  references.remotes.count=5
  references.others.count=1
  objects.commits.count=50
  objects.commits.total_size=1234567
  objects.commits.max_size.oid=1817dc08b8ea00fce4cd1fb6bc75713ad00a74d3
  objects.commits.max_size.size=1234
  objects.commits.max_parents.oid=1817dc08b8ea00fce4cd1fb6bc75713ad00a74d3
  objects.commits.max_parents.count=8
  objects.trees.count=100
  objects.trees.total_size=12345
  objects.trees.total_tree_entries=999
  objects.trees.max_tree_entries.oid=1817dc08b8ea00fce4cd1fb6bc75713ad00a74d3
  objects.trees.max_tree_entries.count=99
  objects.blobs.count=142
  objects.blobs.total_size=99999999
  objects.blobs.max_size.oid=1817dc08b8ea00fce4cd1fb6bc75713ad00a74d3
  objects.blobs.max_size.size=999999
  objects.tags.count=1
  repo.max_depth=999
  <etc...>
The command will also need to eventually support other output formats,
namely a more human friendly table format that provides something
similar to git-sizer(1). As layed out above, this looks like it could
also work well with the git-repo-info(1) JSON format. This makes me
wonder if we should add this functionality as a separate flag for
git-repo-info(1). Maybe something like `--stats` and append the info do
the output. If we want a more clear distiction though, we could
implement this as a separate subcommand.
For a more human-readable format, maybe we could still implement a
standalone git-survey(1) that is more of a porcelain command and uses
git-repo-info(1) under the hood. I think the other information such as
reference format and object format may be useful to provide in
git-survey(1) output.
> > During our meetings, Karthik suggested (I'm planning to it later) to also
> > allow to request an entire category instead of only the fields. Then, this
> > would also be possible:
> > 
> > ```
> > $ git repo-info survey
> > {
> >   "survey": {
> >     "commit-count": 42,
> >     "blob-count": 1234
> > }
> > ```
> 
> It raises another question though: if we ever were to add `--all` we'll
> need to step a bit careful about what kind of information we add to this
> tool. All of the information proposed so far can be computed rather
> trivially. But computing repository sizes has way higher computational
> complexity and may easily take seconds, maybe even minutes in large
> repositories.
> 
> That to me further points into the direction of giving those two tools a
> common top-level command (`git repo info`, `git repo survey`), but to
> not mix concerns too much with one another.
Getting the info for git-survey(1) is certainly more computationally
complex so there should be a way to run the command without performing
the more expensive checks if the user doesn't want them. At the same
time, I think it may be nice to have a way for a user to request a dump
of "interesting" repository info via a single command.
> > But I don't know what are Justin's plans for git-survey, if it would be a
> > porcelain command for showing those stats to the user of if it is targeted
> > for being parsed like this `repo-info`.
I think the intent for git-survey was to provide a more porcelain
command to display interesting repository stats to the user, but also
provide an option to print in a machine-parsable format. I like the idea
of computing everything as part of git-repo-info though. This could
allow a standalone git-survey to focus on just being a human-friendly
porcelain command. For scripted use-cases, users could then just use
git-repo-info.
-Justin
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH v3 0/5] repo-info: add new command for retrieving repository info
  2025-07-08 19:27     ` Lucas Seiki Oshiro
@ 2025-07-10 13:15       ` Phillip Wood
  0 siblings, 0 replies; 226+ messages in thread
From: Phillip Wood @ 2025-07-10 13:15 UTC (permalink / raw)
  To: Lucas Seiki Oshiro
  Cc: git, ps, karthik.188, ben.knoble, gitster, phillip.wood
Hi Lucas
On 08/07/2025 20:27, Lucas Seiki Oshiro wrote:
> 
>> These all look like good changes. Looking through this series I do think that
>> it would be more readable and maintainable if you adopted the table drive
>> approach suggested by Junio.
> 
> Today I had a meeting with my mentors (Karthik and Patrick), and yeah, this is
> something that I'll change in v4.
That's great
> Returning the keys in the same order as they were requested in the
> null-terminated format is not so useful now that I'm keeping the keys in the
> output. Dropping this assumption allows me to make this code simpler.
> 
>> That way we would avoid the nested switch statements and each piece of
>> information only needs to be retrieved once rather that having to retrieve it
>> separately for the JSON and plaintext output. Below is a sketch of might look.
>> Each key is handled by a callback and we have a table that maps key names to
>> callbacks. For the json output we use one json writer per category to build
>> output for each category.
> 
> At first glance it looks good to me. It still seems to me that it needs to
> somehow treat duplicated keys.
We can detect duplicate keys by adding an array
	char seen_key[ARRAY_SIZE(handle)];
and checking to see if we've already set `seen_key[j]` in the inner 
loop. We should also detect invalid keys which we can do by setting a 
flag when we find the key or by moving the declaration of `j` into the 
outer loop and checking that `j < ARRAY_SIZE(handle)` at the end of the 
inner loop.
Thanks
Phillip
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH v3 0/5] repo-info: add new command for retrieving repository info
  2025-07-06 23:19 ` [GSoC RFC PATCH v3 0/5] " Lucas Seiki Oshiro
                     ` (5 preceding siblings ...)
  2025-07-08 10:11   ` [GSoC RFC PATCH v3 0/5] repo-info: add new command for retrieving repository info Phillip Wood
@ 2025-07-11 17:13   ` Lucas Seiki Oshiro
  2025-07-11 17:37     ` Justin Tobler
  6 siblings, 1 reply; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-07-11 17:13 UTC (permalink / raw)
  To: git; +Cc: ps, karthik.188, ben.knoble, gitster, phillip.wood, Justin Tobler
Hello again!
I just had a meeting with Justin, especially focused on joining this `repo-info`
command and his `survey` command [1] under the same command (perhaps called 
`git repo`).
Some highlights of our discussion:
1. How would this integration be done? Making this `git repo` command only as a
   house for two different subcommands, or making it a common interface for our
   work. An argument for separated subcommands is that `repo-info` is a light
   command, while `survey` is more computationally expensive. An argument for
   having a common interface is having a standard format for requesting and
   retrieving data from both sources.
2. A solution for 1. would be keeping the idea of having `repo-info` and
   `survey` as two subcommands (perhaps `git repo info` and `git repo stats`),
   following the same output format. This would also make room for a third
   command which would return data from both commands. Then `git repo` would be
   a plumbing command (`git survey` is more porcelain-ish), and its machinery
   could be used by a separate porcelain command for formatting its output in a
   more human-readable way.
3. Justin asked me about "why JSON?". And yeah, to be honest I'm using JSON
   because it was listed in the GSoC idea of a machine-readable format that could
   be easily parsed by other applications. Given that this would be (as far as I
   remember) the only git command that outputs JSON, it would be out of place,
   while the other format (null-terminated) is easier to manipulate (e.g. JSON
   has Unicode issues mentioned by Phillip) and follows an already used syntax
   (the same as `git config --list -z`). This way, it seems to me that dropping
   JSON is the way to go.
To sum up, we'll end with a `git repo` command with two (or three) subcommands
that output their data in the same format (the null-terminated format).
Then, you can skip reviewing this v3. Instead, I would like to ask you for
comments about this new direction.
Thanks!
[1] https://gitlab.com/gitlab-org/git/-/issues/529#note_2585264408
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH v3 0/5] repo-info: add new command for retrieving repository info
  2025-07-11 17:13   ` Lucas Seiki Oshiro
@ 2025-07-11 17:37     ` Justin Tobler
  0 siblings, 0 replies; 226+ messages in thread
From: Justin Tobler @ 2025-07-11 17:37 UTC (permalink / raw)
  To: Lucas Seiki Oshiro
  Cc: git, ps, karthik.188, ben.knoble, gitster, phillip.wood
On 25/07/11 02:13PM, Lucas Seiki Oshiro wrote:
> 1. How would this integration be done? Making this `git repo` command only as a
>    house for two different subcommands, or making it a common interface for our
>    work. An argument for separated subcommands is that `repo-info` is a light
>    command, while `survey` is more computationally expensive. An argument for
>    having a common interface is having a standard format for requesting and
>    retrieving data from both sources.
> 
> 2. A solution for 1. would be keeping the idea of having `repo-info` and
>    `survey` as two subcommands (perhaps `git repo info` and `git repo stats`),
>    following the same output format. This would also make room for a third
>    command which would return data from both commands. Then `git repo` would be
>    a plumbing command (`git survey` is more porcelain-ish), and its machinery
>    could be used by a separate porcelain command for formatting its output in a
>    more human-readable way.
For some additional context, Stolee sent an RFC series[1] which proposed
the git-survey(1) command as a native tool to complement git-sizer(1) a
little while ago and I've been interested in pushing this topic forward.
As a first step, I think we could introduce as command, such as `git
repo stats`, which focuses on computing "interesting" stats about a
repository similar to git-sizer(1). The output format for this would be
simple key/value pairs for now similar to what Lucas has proposed in
git-repo-info(1).
As there are similarities in command scope with git-repo-info(1), I
think it would make sense to group these operations together under the
same top-level command.
-Justin
[1] 7d43a1634bbe2d2efa96a806e3de1f1fd480041b.1725935335.git.gitgitgadget@gmail.com
^ permalink raw reply	[flat|nested] 226+ messages in thread
* [GSoC RFC PATCH v4 0/4] repo: add new command for retrieving repository info
  2025-06-10 15:21 [GSoC RFC PATCH 0/5] repo-info: add new command for retrieving repository info Lucas Seiki Oshiro
                   ` (9 preceding siblings ...)
  2025-07-06 23:19 ` [GSoC RFC PATCH v3 0/5] " Lucas Seiki Oshiro
@ 2025-07-14 23:52 ` Lucas Seiki Oshiro
  2025-07-14 23:52   ` [GSoC RFC PATCH v4 1/4] repo: declare the repo command Lucas Seiki Oshiro
                     ` (5 more replies)
  2025-07-22  0:28 ` [GSoC PATCH v5 0/5] " Lucas Seiki Oshiro
                   ` (6 subsequent siblings)
  17 siblings, 6 replies; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-07-14 23:52 UTC (permalink / raw)
  To: git
  Cc: ps, karthik.188, ben.knoble, gitster, phillip.wood, jltobler,
	Lucas Seiki Oshiro
Hi again!
This fourth version is basically a re-write after the discussion with Patrick,
Karthik and Justin about a future plan of making git-repo-info and git-survey
[1] a single command with two subcommands.
The main difference between repo-info and survey is that repo-info retrieves
metadata while survey returns metrics about the repository. This means that
repo-info is really light compared to survey.
This patch, then:
- Renames the command to `repo` instead of `repo-info`. All the functionality
  of `repo-info` will now be under `repo info`. The functionality of `survey`
  will be moved to another subcommand of `git repo`.
- Removes the JSON support. Given that after the previous feedback we already
  have a nice machine-readable format for outputting this data, JSON would not
  be so useful as it seemed to be at first (when the "other format" was just
  returning the values without the keys). This makes the code far more simpler,
  as we don't need to deal with the details of both formats.
- Uses a simpler representation of the fields, based in their keys instead of
  declaring multiple enums and using nested switches. This new solution is
  based in a table mapping the keys and the callbacks for retrieving the data.
- Provide a simple infrastructure for extending with the second command.
Given that this v4 is almost a rewrite, I think it isn't worth to send a
range-diff.
Thanks!
[1] https://gitlab.com/gitlab-org/git/-/merge_requests/369
Lucas Seiki Oshiro (4):
  repo: declare the repo command
  repo: add the field references.format
  repo: add field layout.bare
  repo: add field layout.shallow
 .gitignore                  |   1 +
 Documentation/git-repo.adoc |  63 ++++++++++++++++
 Documentation/meson.build   |   1 +
 Makefile                    |   1 +
 builtin.h                   |   1 +
 builtin/repo.c              | 146 ++++++++++++++++++++++++++++++++++++
 command-list.txt            |   1 +
 git.c                       |   1 +
 meson.build                 |   1 +
 t/meson.build               |   1 +
 t/t1900-repo.sh             |  75 ++++++++++++++++++
 11 files changed, 292 insertions(+)
 create mode 100644 Documentation/git-repo.adoc
 create mode 100644 builtin/repo.c
 create mode 100755 t/t1900-repo.sh
-- 
2.39.5 (Apple Git-154)
^ permalink raw reply	[flat|nested] 226+ messages in thread
* [GSoC RFC PATCH v4 1/4] repo: declare the repo command
  2025-07-14 23:52 ` [GSoC RFC PATCH v4 0/4] repo: " Lucas Seiki Oshiro
@ 2025-07-14 23:52   ` Lucas Seiki Oshiro
  2025-07-15 11:52     ` Karthik Nayak
                       ` (2 more replies)
  2025-07-14 23:52   ` [GSoC RFC PATCH v4 2/4] repo: add the field references.format Lucas Seiki Oshiro
                     ` (4 subsequent siblings)
  5 siblings, 3 replies; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-07-14 23:52 UTC (permalink / raw)
  To: git
  Cc: ps, karthik.188, ben.knoble, gitster, phillip.wood, jltobler,
	Lucas Seiki Oshiro
Currently, `git rev-parse` covers a wide range of functionality not
directly related to parsing revisions, as its name says. Over time,
many features like parsing datestrings, options, paths, and others
were added to it because there wasn't a more appropriated command
to place them.
Create a new Git command called `repo`. `git repo` will be the main
command for obtaining the information about a repository (such as
metadata and metrics), returning them in a machine readable format
following the syntax "field<LF>value<NUL>".
Also declare a subcommand for `repo` called `info`. `git repo info`
will bring the functionality of retrieving repository-related
information currently returned by `rev-parse`.
Also add entries for this new command in:
- the build files (Makefile, meson.build, Documentation/meson.build)
- builtin.h
- git.c
- .gitignore
- command-list.txt
- Documentation
Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Helped-by: Junio C Hamano <gitster@pobox.com>
Helped-by: Justin Tobler <jltobler@gmail.com>
Mentored-by: Karthik Nayak <karthik.188@gmail.com>
Mentored-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
---
 .gitignore                  |  1 +
 Documentation/git-repo.adoc | 54 +++++++++++++++++++++++++++++++++++++
 Documentation/meson.build   |  1 +
 Makefile                    |  1 +
 builtin.h                   |  1 +
 builtin/repo.c              | 38 ++++++++++++++++++++++++++
 command-list.txt            |  1 +
 git.c                       |  1 +
 meson.build                 |  1 +
 9 files changed, 99 insertions(+)
 create mode 100644 Documentation/git-repo.adoc
 create mode 100644 builtin/repo.c
diff --git a/.gitignore b/.gitignore
index 04c444404e..1803023427 100644
--- a/.gitignore
+++ b/.gitignore
@@ -139,6 +139,7 @@
 /git-repack
 /git-replace
 /git-replay
+/git-repo
 /git-request-pull
 /git-rerere
 /git-reset
diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc
new file mode 100644
index 0000000000..6f8fe3f6ea
--- /dev/null
+++ b/Documentation/git-repo.adoc
@@ -0,0 +1,54 @@
+git-repo(1)
+===========
+
+NAME
+----
+git-repo - Retrieve information about a repository
+
+SYNOPSIS
+--------
+[synopsis]
+git repo info [<key>...]
+
+DESCRIPTION
+-----------
+Retrieve information about the current repository in a machine-readable format.
+
+`git repo` will be the primary tool to query repository-specific information,
+such as metadata that currently can also be done by calling `git rev-parse` (see
+linkgit:git-rev-parse[1]). `git repo` doesn't query information unrelated to the
+current repository or that is already retrieved by a specialized command, for
+example, `git config` (see linkgit:git-config[1]) or `git var` (see
+linkgit:git-var[1]).
+
+This command returns the retrieved data following a null-terminated format with
+this syntax:
++
+----------------
+key1<LF>value1<NUL>
+key2<LF>value2<NUL>
+...
+----------------
++
+THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOR MAY CHANGE.
+
+COMMANDS
+--------
+info [<key>...]::
+	Retrieve metadata-related information about the current repository. Only
+	the requested data will be returned based on their keys (see "INFO KEYS"
+	section below).
+
+INFO KEYS
+---------
+
+The set of data that `git repo` can return is grouped into the following
+categories:
+
+SEE ALSO
+--------
+linkgit:git-rev-parse[1]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/meson.build b/Documentation/meson.build
index 2fe1a1369d..1ebdd57789 100644
--- a/Documentation/meson.build
+++ b/Documentation/meson.build
@@ -116,6 +116,7 @@ manpages = {
   'git-repack.adoc' : 1,
   'git-replace.adoc' : 1,
   'git-replay.adoc' : 1,
+  'git-repo.adoc' : 1,
   'git-request-pull.adoc' : 1,
   'git-rerere.adoc' : 1,
   'git-reset.adoc' : 1,
diff --git a/Makefile b/Makefile
index 5f7dd79dfa..9dce446309 100644
--- a/Makefile
+++ b/Makefile
@@ -1306,6 +1306,7 @@ BUILTIN_OBJS += builtin/remote.o
 BUILTIN_OBJS += builtin/repack.o
 BUILTIN_OBJS += builtin/replace.o
 BUILTIN_OBJS += builtin/replay.o
+BUILTIN_OBJS += builtin/repo.o
 BUILTIN_OBJS += builtin/rerere.o
 BUILTIN_OBJS += builtin/reset.o
 BUILTIN_OBJS += builtin/rev-list.o
diff --git a/builtin.h b/builtin.h
index bff13e3069..e6458e6fb9 100644
--- a/builtin.h
+++ b/builtin.h
@@ -216,6 +216,7 @@ int cmd_remote_ext(int argc, const char **argv, const char *prefix, struct repos
 int cmd_remote_fd(int argc, const char **argv, const char *prefix, struct repository *repo);
 int cmd_repack(int argc, const char **argv, const char *prefix, struct repository *repo);
 int cmd_replay(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_repo(int argc, const char **argv, const char *prefix, struct repository *repo);
 int cmd_rerere(int argc, const char **argv, const char *prefix, struct repository *repo);
 int cmd_reset(int argc, const char **argv, const char *prefix, struct repository *repo);
 int cmd_restore(int argc, const char **argv, const char *prefix, struct repository *repo);
diff --git a/builtin/repo.c b/builtin/repo.c
new file mode 100644
index 0000000000..a1787a3cc5
--- /dev/null
+++ b/builtin/repo.c
@@ -0,0 +1,38 @@
+#include "builtin.h"
+#include "parse-options.h"
+
+static int repo_info(int argc UNUSED,
+		     const char **argv UNUSED,
+		     const char *prefix UNUSED,
+		     struct repository *repo UNUSED)
+{
+	return 0;
+}
+
+int cmd_repo(int argc,
+	     const char **argv,
+	     const char *prefix,
+	     struct repository *repo)
+{
+	parse_opt_subcommand_fn *fn = NULL;
+	const char *const repo_usage[] = {
+		"git repo info",
+		NULL
+	};
+	struct option options[] = {
+		OPT_SUBCOMMAND("info", &fn, repo_info),
+		OPT_END()
+	};
+
+	argc = parse_options(argc, argv, prefix, options, repo_usage, 0);
+
+	if (fn) {
+		return fn(argc, argv, prefix, repo);
+	} else {
+		if (argc) {
+			error(_("unknown subcommand: `%s'"), argv[0]);
+			usage_with_options(repo_usage, options);
+		}
+		return 1;
+	}
+}
diff --git a/command-list.txt b/command-list.txt
index b7ade3ab9f..1b0bdee00d 100644
--- a/command-list.txt
+++ b/command-list.txt
@@ -164,6 +164,7 @@ git-remote                              ancillarymanipulators           complete
 git-repack                              ancillarymanipulators           complete
 git-replace                             ancillarymanipulators           complete
 git-replay                              plumbingmanipulators
+git-repo                                plumbinginterrogators
 git-request-pull                        foreignscminterface             complete
 git-rerere                              ancillaryinterrogators
 git-reset                               mainporcelain           history
diff --git a/git.c b/git.c
index 07a5fe39fb..8290d8b8c8 100644
--- a/git.c
+++ b/git.c
@@ -611,6 +611,7 @@ static struct cmd_struct commands[] = {
 	{ "repack", cmd_repack, RUN_SETUP },
 	{ "replace", cmd_replace, RUN_SETUP },
 	{ "replay", cmd_replay, RUN_SETUP },
+	{ "repo", cmd_repo, RUN_SETUP },
 	{ "rerere", cmd_rerere, RUN_SETUP },
 	{ "reset", cmd_reset, RUN_SETUP },
 	{ "restore", cmd_restore, RUN_SETUP | NEED_WORK_TREE },
diff --git a/meson.build b/meson.build
index 9579377f3d..15d3e3701f 100644
--- a/meson.build
+++ b/meson.build
@@ -645,6 +645,7 @@ builtin_sources = [
   'builtin/repack.c',
   'builtin/replace.c',
   'builtin/replay.c',
+  'builtin/repo.c',
   'builtin/rerere.c',
   'builtin/reset.c',
   'builtin/rev-list.c',
-- 
2.39.5 (Apple Git-154)
^ permalink raw reply related	[flat|nested] 226+ messages in thread
* [GSoC RFC PATCH v4 2/4] repo: add the field references.format
  2025-07-14 23:52 ` [GSoC RFC PATCH v4 0/4] repo: " Lucas Seiki Oshiro
  2025-07-14 23:52   ` [GSoC RFC PATCH v4 1/4] repo: declare the repo command Lucas Seiki Oshiro
@ 2025-07-14 23:52   ` Lucas Seiki Oshiro
  2025-07-15 11:59     ` Patrick Steinhardt
                       ` (2 more replies)
  2025-07-14 23:52   ` [GSoC RFC PATCH v4 3/4] repo: add field layout.bare Lucas Seiki Oshiro
                     ` (3 subsequent siblings)
  5 siblings, 3 replies; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-07-14 23:52 UTC (permalink / raw)
  To: git
  Cc: ps, karthik.188, ben.knoble, gitster, phillip.wood, jltobler,
	Lucas Seiki Oshiro
This commit is part of the series that introduce the new subcommand
git-repo-info.
The flag `--show-ref-format` from git-rev-parse is used for retrieving
the reference format (i.e. `files` or `reftable`). This way, it is
used for querying repository metadata, fitting in the purpose of
git-repo-info.
Then, add a new field `references.format` to the repo-info subcommand
containing that information.
Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Helped-by: Junio C Hamano <gitster@pobox.com>
Helped-by: Justin Tobler <jltobler@gmail.com>
Mentored-by: Karthik Nayak <karthik.188@gmail.com>
Mentored-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
---
 Documentation/git-repo.adoc |  4 ++
 builtin/repo.c              | 92 +++++++++++++++++++++++++++++++++++--
 t/meson.build               |  1 +
 t/t1900-repo.sh             | 47 +++++++++++++++++++
 4 files changed, 140 insertions(+), 4 deletions(-)
 create mode 100755 t/t1900-repo.sh
diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc
index 6f8fe3f6ea..b7af6f45a4 100644
--- a/Documentation/git-repo.adoc
+++ b/Documentation/git-repo.adoc
@@ -45,6 +45,10 @@ INFO KEYS
 The set of data that `git repo` can return is grouped into the following
 categories:
 
+`references`::
+Reference-related data:
+* `format`: the reference storage format, either `files` or `reftable`.
+
 SEE ALSO
 --------
 linkgit:git-rev-parse[1]
diff --git a/builtin/repo.c b/builtin/repo.c
index a1787a3cc5..dcda0d6d61 100644
--- a/builtin/repo.c
+++ b/builtin/repo.c
@@ -1,11 +1,95 @@
 #include "builtin.h"
 #include "parse-options.h"
+#include "strbuf.h"
+#include "refs.h"
 
-static int repo_info(int argc UNUSED,
-		     const char **argv UNUSED,
+typedef void add_field_fn(struct strbuf *buf, struct repository *repo);
+
+struct field {
+	const char *key;
+	add_field_fn *add_field_callback;
+};
+
+static void add_string(struct strbuf *buf,
+		       const char *key, const char *value)
+{
+	strbuf_addf(buf, "%s\n%s%c", key, value, '\0');
+}
+
+static void add_references_format(struct strbuf *buf,
+				  struct repository *repo)
+{
+	add_string(buf, "references.format",
+		   ref_storage_format_to_name(repo->ref_storage_format));
+}
+
+// repo_info_fields keys should be in lexicographical order
+static const struct field repo_info_fields[] = {
+	{"references.format", add_references_format},
+};
+
+static int repo_info_fields_cmp(const void *va, const void *vb)
+{
+	const struct field *a = va;
+	const struct field *b = vb;
+
+	return strcmp(a->key, b->key);
+}
+
+static add_field_fn *get_append_callback(const char *key) {
+	const struct field search_key = {key, NULL};
+	const struct field *found = bsearch(&search_key, repo_info_fields,
+					    ARRAY_SIZE(repo_info_fields),
+					    sizeof(struct field),
+					    repo_info_fields_cmp);
+	return found ? found->add_field_callback : NULL;
+}
+
+static int qsort_strcmp(const void *va, const void *vb)
+{
+	const char *a = *(const char **)va;
+	const char *b = *(const char **)vb;
+
+	return strcmp(a, b);
+}
+
+static void print_fields(int argc, const char **argv, struct repository *repo) {
+	const char *last = "";
+	struct strbuf buf;
+	strbuf_init(&buf, 256);
+
+	QSORT(argv, argc, qsort_strcmp);
+
+	for (int i = 0; i < argc; i++) {
+		add_field_fn *callback;
+		const char *key = argv[i];
+
+		if (!strcmp(key, last))
+			continue;
+
+		callback = get_append_callback(key);
+
+		if (!callback) {
+			error("key %s not found", key);
+			strbuf_release(&buf);
+			exit(1);
+		}
+
+		callback(&buf, repo);
+		last = key;
+	}
+
+	fwrite(buf.buf, 1, buf.len, stdout);
+	strbuf_release(&buf);
+}
+
+static int repo_info(int argc,
+		     const char **argv,
 		     const char *prefix UNUSED,
-		     struct repository *repo UNUSED)
+		     struct repository *repo)
 {
+
+	print_fields(argc - 1 , argv + 1, repo);
 	return 0;
 }
 
@@ -16,7 +100,7 @@ int cmd_repo(int argc,
 {
 	parse_opt_subcommand_fn *fn = NULL;
 	const char *const repo_usage[] = {
-		"git repo info",
+		"git repo info [<key>...]",
 		NULL
 	};
 	struct option options[] = {
diff --git a/t/meson.build b/t/meson.build
index 1af289425d..8693e6abc4 100644
--- a/t/meson.build
+++ b/t/meson.build
@@ -245,6 +245,7 @@ integration_tests = [
   't1700-split-index.sh',
   't1701-racy-split-index.sh',
   't1800-hook.sh',
+  't1900-repo.sh',
   't2000-conflict-when-checking-files-out.sh',
   't2002-checkout-cache-u.sh',
   't2003-checkout-cache-mkdir.sh',
diff --git a/t/t1900-repo.sh b/t/t1900-repo.sh
new file mode 100755
index 0000000000..b80fc6b78b
--- /dev/null
+++ b/t/t1900-repo.sh
@@ -0,0 +1,47 @@
+#!/bin/sh
+
+test_description='test git repo-info'
+
+. ./test-lib.sh
+
+# Test if a field is correctly returned in the null-terminated format
+#
+# Usage: test_repo_info <label> <init command> <key> <expected value>
+#
+# Arguments:
+#   label: the label of the test
+#   init command: a command that creates a repository called 'repo', configured
+#      accordingly to what is being tested
+#   key: the key of the field that is being tested
+#   expected value: the value that the field should contain
+test_repo_info () {
+	label=$1
+	init_command=$2
+	key=$3
+	expected_value=$4
+
+	test_expect_success "$label" '
+		test_when_finished "rm -rf repo" &&
+		eval "$init_command" &&
+		echo "$expected_value" | lf_to_nul >expected &&
+		git -C repo repo info "$key" >output &&
+		tail -n 1 output >actual &&
+		test_cmp expected actual
+	'
+}
+
+test_repo_info 'ref format files is retrieved correctly' '
+	git init --ref-format=files repo' 'references.format' 'files'
+
+test_repo_info 'ref format reftable is retrieved correctly' '
+	git init --ref-format=reftable repo' 'references.format' 'reftable'
+
+test_expect_success "only one value is returned if the same key is requested twice" '
+	echo "references.format" > expected &&
+	git rev-parse --show-ref-format > ref-format &&
+	lf_to_nul <ref-format >>expected &&
+	git repo info references.format references.format > actual &&
+	test_cmp expected actual
+'
+
+test_done
-- 
2.39.5 (Apple Git-154)
^ permalink raw reply related	[flat|nested] 226+ messages in thread
* [GSoC RFC PATCH v4 3/4] repo: add field layout.bare
  2025-07-14 23:52 ` [GSoC RFC PATCH v4 0/4] repo: " Lucas Seiki Oshiro
  2025-07-14 23:52   ` [GSoC RFC PATCH v4 1/4] repo: declare the repo command Lucas Seiki Oshiro
  2025-07-14 23:52   ` [GSoC RFC PATCH v4 2/4] repo: add the field references.format Lucas Seiki Oshiro
@ 2025-07-14 23:52   ` Lucas Seiki Oshiro
  2025-07-14 23:52   ` [GSoC RFC PATCH v4 4/4] repo: add field layout.shallow Lucas Seiki Oshiro
                     ` (2 subsequent siblings)
  5 siblings, 0 replies; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-07-14 23:52 UTC (permalink / raw)
  To: git
  Cc: ps, karthik.188, ben.knoble, gitster, phillip.wood, jltobler,
	Lucas Seiki Oshiro
This commit is part of the series that introduces the new subcommand
git-repo-info.
The flag --is-bare-repository from git-rev-parse is used for retrieving
whether the current repository is bare. This way, it is used for
querying repository metadata, fitting in the purpose of git-repo-info.
Then, add a new field layout.bare to the git-repo-info subcommand
containing that information.
Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Helped-by: Junio C Hamano <gitster@pobox.com>
Helped-by: Justin Tobler <jltobler@gmail.com>
Mentored-by: Karthik Nayak <karthik.188@gmail.com>
Mentored-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
---
 Documentation/git-repo.adoc |  4 ++++
 builtin/repo.c              | 17 +++++++++++++++++
 t/t1900-repo.sh             |  6 ++++++
 3 files changed, 27 insertions(+)
diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc
index b7af6f45a4..db185c5c91 100644
--- a/Documentation/git-repo.adoc
+++ b/Documentation/git-repo.adoc
@@ -49,6 +49,10 @@ categories:
 Reference-related data:
 * `format`: the reference storage format, either `files` or `reftable`.
 
+`layout`::
+Information about the how the current repository is represented:
+* `bare`: `true` if this is a bare repository, otherwise `false`.
+
 SEE ALSO
 --------
 linkgit:git-rev-parse[1]
diff --git a/builtin/repo.c b/builtin/repo.c
index dcda0d6d61..5eefe06918 100644
--- a/builtin/repo.c
+++ b/builtin/repo.c
@@ -1,7 +1,10 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
 #include "builtin.h"
 #include "parse-options.h"
 #include "strbuf.h"
 #include "refs.h"
+#include "environment.h"
 
 typedef void add_field_fn(struct strbuf *buf, struct repository *repo);
 
@@ -16,6 +19,13 @@ static void add_string(struct strbuf *buf,
 	strbuf_addf(buf, "%s\n%s%c", key, value, '\0');
 }
 
+static void add_bool(struct strbuf *buf,
+		     const char *key, const int value)
+{
+	const char *output_value = value ? "true" : "false";
+	strbuf_addf(buf, "%s\n%s%c", key, output_value, '\0');
+}
+
 static void add_references_format(struct strbuf *buf,
 				  struct repository *repo)
 {
@@ -23,8 +33,15 @@ static void add_references_format(struct strbuf *buf,
 		   ref_storage_format_to_name(repo->ref_storage_format));
 }
 
+
+static void add_layout_bare(struct strbuf *buf, struct repository *repo UNUSED)
+{
+	add_bool(buf, "layout.bare", is_bare_repository());
+}
+
 // repo_info_fields keys should be in lexicographical order
 static const struct field repo_info_fields[] = {
+	{"layout.bare", add_layout_bare},
 	{"references.format", add_references_format},
 };
 
diff --git a/t/t1900-repo.sh b/t/t1900-repo.sh
index b80fc6b78b..6155e275b5 100755
--- a/t/t1900-repo.sh
+++ b/t/t1900-repo.sh
@@ -36,6 +36,12 @@ test_repo_info 'ref format files is retrieved correctly' '
 test_repo_info 'ref format reftable is retrieved correctly' '
 	git init --ref-format=reftable repo' 'references.format' 'reftable'
 
+test_repo_info 'bare repository = false is retrieved correctly' '
+	git init repo' 'layout.bare' 'false'
+
+test_repo_info 'bare repository = true is retrieved correctly' '
+	git init --bare repo' 'layout.bare' 'true'
+
 test_expect_success "only one value is returned if the same key is requested twice" '
 	echo "references.format" > expected &&
 	git rev-parse --show-ref-format > ref-format &&
-- 
2.39.5 (Apple Git-154)
^ permalink raw reply related	[flat|nested] 226+ messages in thread
* [GSoC RFC PATCH v4 4/4] repo: add field layout.shallow
  2025-07-14 23:52 ` [GSoC RFC PATCH v4 0/4] repo: " Lucas Seiki Oshiro
                     ` (2 preceding siblings ...)
  2025-07-14 23:52   ` [GSoC RFC PATCH v4 3/4] repo: add field layout.bare Lucas Seiki Oshiro
@ 2025-07-14 23:52   ` Lucas Seiki Oshiro
  2025-07-15 10:34   ` [GSoC RFC PATCH v4 0/4] repo: add new command for retrieving repository info Oswald Buddenhagen
  2025-07-16 20:20   ` Junio C Hamano
  5 siblings, 0 replies; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-07-14 23:52 UTC (permalink / raw)
  To: git
  Cc: ps, karthik.188, ben.knoble, gitster, phillip.wood, jltobler,
	Lucas Seiki Oshiro
This commit is part of the series that introduces the new subcommand
git-repo-info.
The flag `--is-shallow-repository` from git-rev-parse is used for
retrieving whether the repository is shallow. This way, it is used for
querying repository metadata, fitting in the purpose of git-repo-info.
Then, add a new field `layout.shallow` to the git-repo-info subcommand
containing that information.
Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Helped-by: Junio C Hamano <gitster@pobox.com>
Helped-by: Justin Tobler <jltobler@gmail.com>
Mentored-by: Karthik Nayak <karthik.188@gmail.com>
Mentored-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
---
 Documentation/git-repo.adoc |  1 +
 builtin/repo.c              |  7 +++++++
 t/t1900-repo.sh             | 22 ++++++++++++++++++++++
 3 files changed, 30 insertions(+)
diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc
index db185c5c91..864868993b 100644
--- a/Documentation/git-repo.adoc
+++ b/Documentation/git-repo.adoc
@@ -52,6 +52,7 @@ Reference-related data:
 `layout`::
 Information about the how the current repository is represented:
 * `bare`: `true` if this is a bare repository, otherwise `false`.
+* `shallow`: `true` if this is a shallow repository, otherwise `false`.
 
 SEE ALSO
 --------
diff --git a/builtin/repo.c b/builtin/repo.c
index 5eefe06918..d75417a48b 100644
--- a/builtin/repo.c
+++ b/builtin/repo.c
@@ -5,6 +5,7 @@
 #include "strbuf.h"
 #include "refs.h"
 #include "environment.h"
+#include "shallow.h"
 
 typedef void add_field_fn(struct strbuf *buf, struct repository *repo);
 
@@ -39,9 +40,15 @@ static void add_layout_bare(struct strbuf *buf, struct repository *repo UNUSED)
 	add_bool(buf, "layout.bare", is_bare_repository());
 }
 
+static void add_layout_shallow(struct strbuf *buf, struct repository *repo)
+{
+	add_bool(buf, "layout.shallow", is_repository_shallow(repo));
+}
+
 // repo_info_fields keys should be in lexicographical order
 static const struct field repo_info_fields[] = {
 	{"layout.bare", add_layout_bare},
+	{"layout.shallow", add_layout_shallow},
 	{"references.format", add_references_format},
 };
 
diff --git a/t/t1900-repo.sh b/t/t1900-repo.sh
index 6155e275b5..e0e2393247 100755
--- a/t/t1900-repo.sh
+++ b/t/t1900-repo.sh
@@ -42,6 +42,20 @@ test_repo_info 'bare repository = false is retrieved correctly' '
 test_repo_info 'bare repository = true is retrieved correctly' '
 	git init --bare repo' 'layout.bare' 'true'
 
+test_repo_info 'shallow repository = false is retrieved correctly' '
+	git init repo' 'layout.shallow' 'false'
+
+test_repo_info 'shallow repository = true is retrieved correctly' '
+	git init remote &&
+	cd remote &&
+	echo x >x &&
+	git add x &&
+	git commit -m x &&
+	cd .. &&
+	git clone --depth 1 "file://$PWD/remote" repo &&
+	rm -rf remote
+	' 'layout.shallow' 'true'
+
 test_expect_success "only one value is returned if the same key is requested twice" '
 	echo "references.format" > expected &&
 	git rev-parse --show-ref-format > ref-format &&
@@ -50,4 +64,12 @@ test_expect_success "only one value is returned if the same key is requested twi
 	test_cmp expected actual
 '
 
+test_expect_success 'output is returned correctly when two keys are requested' '
+	test_when_finished "rm -f expect" &&
+	printf "layout.bare\nfalseQlayout.shallow\nfalseQ" >expect &&
+	git repo info layout.shallow layout.bare >output &&
+	nul_to_q <output >actual &&
+	test_cmp expect actual
+'
+
 test_done
-- 
2.39.5 (Apple Git-154)
^ permalink raw reply related	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH v4 0/4] repo: add new command for retrieving repository info
  2025-07-14 23:52 ` [GSoC RFC PATCH v4 0/4] repo: " Lucas Seiki Oshiro
                     ` (3 preceding siblings ...)
  2025-07-14 23:52   ` [GSoC RFC PATCH v4 4/4] repo: add field layout.shallow Lucas Seiki Oshiro
@ 2025-07-15 10:34   ` Oswald Buddenhagen
  2025-07-15 11:58     ` Patrick Steinhardt
  2025-07-15 16:49     ` Junio C Hamano
  2025-07-16 20:20   ` Junio C Hamano
  5 siblings, 2 replies; 226+ messages in thread
From: Oswald Buddenhagen @ 2025-07-15 10:34 UTC (permalink / raw)
  To: Lucas Seiki Oshiro
  Cc: git, ps, karthik.188, ben.knoble, gitster, phillip.wood, jltobler
On Mon, Jul 14, 2025 at 08:52:27PM -0300, Lucas Seiki Oshiro wrote:
>- Renames the command to `repo` instead of `repo-info`. All the 
>functionality
>  of `repo-info` will now be under `repo info`. The functionality of `survey`
>  will be moved to another subcommand of `git repo`.
>
this strikes me as a bad idea, given how established the `repo` tool is.
without much thinking and reading prior conversations, i'd go with 
"query", because it's a database-like metadata ... query.
the obvious followup idea would then be "meta", but that suggests that 
it isn't only a read-only command, which i think it is supposed to 
remain?
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH v4 1/4] repo: declare the repo command
  2025-07-14 23:52   ` [GSoC RFC PATCH v4 1/4] repo: declare the repo command Lucas Seiki Oshiro
@ 2025-07-15 11:52     ` Karthik Nayak
  2025-07-15 11:59     ` Patrick Steinhardt
  2025-07-15 18:19     ` Justin Tobler
  2 siblings, 0 replies; 226+ messages in thread
From: Karthik Nayak @ 2025-07-15 11:52 UTC (permalink / raw)
  To: Lucas Seiki Oshiro, git; +Cc: ps, ben.knoble, gitster, phillip.wood, jltobler
[-- Attachment #1: Type: text/plain, Size: 4618 bytes --]
Lucas Seiki Oshiro <lucasseikioshiro@gmail.com> writes:
> Currently, `git rev-parse` covers a wide range of functionality not
> directly related to parsing revisions, as its name says. Over time,
> many features like parsing datestrings, options, paths, and others
> were added to it because there wasn't a more appropriated command
> to place them.
>
> Create a new Git command called `repo`. `git repo` will be the main
> command for obtaining the information about a repository (such as
> metadata and metrics), returning them in a machine readable format
> following the syntax "field<LF>value<NUL>".
I don't think we should enforce a syntax on the command level, but
rather we should enforce it on the sub-command level. This way any new
command, let's say `git repo stats` can provide a more suitable output.
Which could be a more human readable format mimicking 'git-sizer'.
By not enforcing on a command level, we leave it extendable.
>
> Also declare a subcommand for `repo` called `info`. `git repo info`
> will bring the functionality of retrieving repository-related
> information currently returned by `rev-parse`.
>
> Also add entries for this new command in:
>
> - the build files (Makefile, meson.build, Documentation/meson.build)
> - builtin.h
> - git.c
> - .gitignore
> - command-list.txt
> - Documentation
>
Nit: While it is good to state what this patch does, this list is
similar to the diffstat below. Is there additional information it is
providing?
Perhaps:
  We add the required tests, documentation and build changes to enable
  usage of this subcommand.
would suffice?
> Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
> Helped-by: Junio C Hamano <gitster@pobox.com>
> Helped-by: Justin Tobler <jltobler@gmail.com>
> Mentored-by: Karthik Nayak <karthik.188@gmail.com>
> Mentored-by: Patrick Steinhardt <ps@pks.im>
> Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
> ---
>  .gitignore                  |  1 +
>  Documentation/git-repo.adoc | 54 +++++++++++++++++++++++++++++++++++++
>  Documentation/meson.build   |  1 +
>  Makefile                    |  1 +
>  builtin.h                   |  1 +
>  builtin/repo.c              | 38 ++++++++++++++++++++++++++
>  command-list.txt            |  1 +
>  git.c                       |  1 +
>  meson.build                 |  1 +
>  9 files changed, 99 insertions(+)
>  create mode 100644 Documentation/git-repo.adoc
>  create mode 100644 builtin/repo.c
>
> diff --git a/.gitignore b/.gitignore
> index 04c444404e..1803023427 100644
> --- a/.gitignore
> +++ b/.gitignore
> @@ -139,6 +139,7 @@
>  /git-repack
>  /git-replace
>  /git-replay
> +/git-repo
>  /git-request-pull
>  /git-rerere
>  /git-reset
> diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc
> new file mode 100644
> index 0000000000..6f8fe3f6ea
> --- /dev/null
> +++ b/Documentation/git-repo.adoc
> @@ -0,0 +1,54 @@
> +git-repo(1)
> +===========
> +
> +NAME
> +----
> +git-repo - Retrieve information about a repository
> +
> +SYNOPSIS
> +--------
> +[synopsis]
> +git repo info [<key>...]
> +
> +DESCRIPTION
> +-----------
> +Retrieve information about the current repository in a machine-readable format.
> +
I would keep the description of the command short, to:
  This command retrieve repository level information.
The `machine-readable` format is a implementation detail of the
'git-repo info' subcommand.
> +`git repo` will be the primary tool to query repository-specific information,
> +such as metadata that currently can also be done by calling `git rev-parse` (see
> +linkgit:git-rev-parse[1]). `git repo` doesn't query information unrelated to the
> +current repository or that is already retrieved by a specialized command, for
> +example, `git config` (see linkgit:git-config[1]) or `git var` (see
> +linkgit:git-var[1]).
> +
> +This command returns the retrieved data following a null-terminated format with
> +this syntax:
> ++
> +----------------
> +key1<LF>value1<NUL>
> +key2<LF>value2<NUL>
> +...
> +----------------
>
Shouldn't this whole section be below the 'info' subcommand?
> ++
> +THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOR MAY CHANGE.
> +
> +COMMANDS
> +--------
> +info [<key>...]::
> +	Retrieve metadata-related information about the current repository. Only
> +	the requested data will be returned based on their keys (see "INFO KEYS"
> +	section below).
> +
> +INFO KEYS
> +---------
> +
> +The set of data that `git repo` can return is grouped into the following
> +categories:
> +
> +SEE ALSO
> +--------
> +linkgit:git-rev-parse[1]
> +
> +GIT
> +---
> +Part of the linkgit:git[1] suite
[snip]
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 690 bytes --]
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH v4 0/4] repo: add new command for retrieving repository info
  2025-07-15 10:34   ` [GSoC RFC PATCH v4 0/4] repo: add new command for retrieving repository info Oswald Buddenhagen
@ 2025-07-15 11:58     ` Patrick Steinhardt
  2025-07-15 12:20       ` Oswald Buddenhagen
  2025-07-15 19:36       ` Justin Tobler
  2025-07-15 16:49     ` Junio C Hamano
  1 sibling, 2 replies; 226+ messages in thread
From: Patrick Steinhardt @ 2025-07-15 11:58 UTC (permalink / raw)
  To: Oswald Buddenhagen
  Cc: Lucas Seiki Oshiro, git, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler
On Tue, Jul 15, 2025 at 12:34:42PM +0200, Oswald Buddenhagen wrote:
> On Mon, Jul 14, 2025 at 08:52:27PM -0300, Lucas Seiki Oshiro wrote:
> > - Renames the command to `repo` instead of `repo-info`. All the
> > functionality
> >  of `repo-info` will now be under `repo info`. The functionality of `survey`
> >  will be moved to another subcommand of `git repo`.
> > 
> this strikes me as a bad idea, given how established the `repo` tool is.
The `repo` tool wouldn't be executed as `git repo` though, would it? So
I'm not sure whether that really is relevant at all. On the other hand
though I do see that it might be confusing when you interact with the
`repo` tool on a daily basis.
> without much thinking and reading prior conversations, i'd go with "query",
> because it's a database-like metadata ... query.
> the obvious followup idea would then be "meta", but that suggests that it
> isn't only a read-only command, which i think it is supposed to remain?
"Query" is way too generic from my point of view, as it doesn't say
_what_ you query. "Meta" might be a bit better even though it still
loses the information that you act on the repository level, which is a
bit of a shame.
We could of course adapt and call it git-repository(1) to avoid any
confusion with git-repo(1) and repo(1). It's not like this is a tool
that users would typically have to run daily outside of scripts, so I
don't think it hurts much to have a longer command name.
Patrick
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH v4 1/4] repo: declare the repo command
  2025-07-14 23:52   ` [GSoC RFC PATCH v4 1/4] repo: declare the repo command Lucas Seiki Oshiro
  2025-07-15 11:52     ` Karthik Nayak
@ 2025-07-15 11:59     ` Patrick Steinhardt
  2025-07-15 18:38       ` Justin Tobler
  2025-07-20 19:51       ` Lucas Seiki Oshiro
  2025-07-15 18:19     ` Justin Tobler
  2 siblings, 2 replies; 226+ messages in thread
From: Patrick Steinhardt @ 2025-07-15 11:59 UTC (permalink / raw)
  To: Lucas Seiki Oshiro
  Cc: git, karthik.188, ben.knoble, gitster, phillip.wood, jltobler
On Mon, Jul 14, 2025 at 08:52:28PM -0300, Lucas Seiki Oshiro wrote:
> Currently, `git rev-parse` covers a wide range of functionality not
> directly related to parsing revisions, as its name says. Over time,
> many features like parsing datestrings, options, paths, and others
> were added to it because there wasn't a more appropriated command
> to place them.
> 
> Create a new Git command called `repo`. `git repo` will be the main
> command for obtaining the information about a repository (such as
> metadata and metrics), returning them in a machine readable format
> following the syntax "field<LF>value<NUL>".
> 
> Also declare a subcommand for `repo` called `info`. `git repo info`
> will bring the functionality of retrieving repository-related
> information currently returned by `rev-parse`.
> 
> Also add entries for this new command in:
> 
> - the build files (Makefile, meson.build, Documentation/meson.build)
> - builtin.h
> - git.c
> - .gitignore
> - command-list.txt
> - Documentation
Nit: I don't really think it makes sense to have this bulleted list of
files you have changed unless you provide more context. We basically
already have a way more accurate version of this list 10 lines down in
the diffstat.
> diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc
> new file mode 100644
> index 0000000000..6f8fe3f6ea
> --- /dev/null
> +++ b/Documentation/git-repo.adoc
> @@ -0,0 +1,54 @@
> +git-repo(1)
> +===========
> +
> +NAME
> +----
> +git-repo - Retrieve information about a repository
> +
> +SYNOPSIS
> +--------
> +[synopsis]
> +git repo info [<key>...]
> +
> +DESCRIPTION
> +-----------
> +Retrieve information about the current repository in a machine-readable format.
> +
> +`git repo` will be the primary tool to query repository-specific information,
I think we should avoid making any promises how this command will evolve
in the future. I'd rather state what it does right now than to say what
it will eventually do.
> +such as metadata that currently can also be done by calling `git rev-parse` (see
> +linkgit:git-rev-parse[1]). `git repo` doesn't query information unrelated to the
> +current repository or that is already retrieved by a specialized command, for
> +example, `git config` (see linkgit:git-config[1]) or `git var` (see
> +linkgit:git-var[1]).
> +
> +This command returns the retrieved data following a null-terminated format with
> +this syntax:
> ++
> +----------------
> +key1<LF>value1<NUL>
> +key2<LF>value2<NUL>
> +...
> +----------------
> ++
One of the things I wonder is whether we should by default adapt those
tools to have human-readable format, e.g. in a way that it can be easily
added to git-bugreport(1). This would teach script authors that want to
use the command to use `git repo info --format=porcelain` right from the
start to have a machine-parseable output, and it would allow us to
iterate on the exact output format.
> diff --git a/builtin/repo.c b/builtin/repo.c
> new file mode 100644
> index 0000000000..a1787a3cc5
> --- /dev/null
> +++ b/builtin/repo.c
> @@ -0,0 +1,38 @@
> +#include "builtin.h"
> +#include "parse-options.h"
> +
> +static int repo_info(int argc UNUSED,
> +		     const char **argv UNUSED,
> +		     const char *prefix UNUSED,
> +		     struct repository *repo UNUSED)
> +{
> +	return 0;
> +}
> +
> +int cmd_repo(int argc,
> +	     const char **argv,
> +	     const char *prefix,
> +	     struct repository *repo)
> +{
> +	parse_opt_subcommand_fn *fn = NULL;
> +	const char *const repo_usage[] = {
> +		"git repo info",
> +		NULL
> +	};
> +	struct option options[] = {
> +		OPT_SUBCOMMAND("info", &fn, repo_info),
> +		OPT_END()
> +	};
> +
> +	argc = parse_options(argc, argv, prefix, options, repo_usage, 0);
> +
> +	if (fn) {
> +		return fn(argc, argv, prefix, repo);
> +	} else {
> +		if (argc) {
> +			error(_("unknown subcommand: `%s'"), argv[0]);
> +			usage_with_options(repo_usage, options);
> +		}
> +		return 1;
I think we need to print an error `if (!argc)`, as well. Otherwise the
user wouldn't know why `git repo` without any argumentsdoesn't do
anything.
Patrick
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH v4 2/4] repo: add the field references.format
  2025-07-14 23:52   ` [GSoC RFC PATCH v4 2/4] repo: add the field references.format Lucas Seiki Oshiro
@ 2025-07-15 11:59     ` Patrick Steinhardt
  2025-07-18 19:13       ` Lucas Seiki Oshiro
  2025-07-15 12:23     ` Karthik Nayak
  2025-07-15 19:15     ` Justin Tobler
  2 siblings, 1 reply; 226+ messages in thread
From: Patrick Steinhardt @ 2025-07-15 11:59 UTC (permalink / raw)
  To: Lucas Seiki Oshiro
  Cc: git, karthik.188, ben.knoble, gitster, phillip.wood, jltobler
On Mon, Jul 14, 2025 at 08:52:29PM -0300, Lucas Seiki Oshiro wrote:
> diff --git a/builtin/repo.c b/builtin/repo.c
> index a1787a3cc5..dcda0d6d61 100644
> --- a/builtin/repo.c
> +++ b/builtin/repo.c
> @@ -1,11 +1,95 @@
>  #include "builtin.h"
>  #include "parse-options.h"
> +#include "strbuf.h"
> +#include "refs.h"
>  
> -static int repo_info(int argc UNUSED,
> -		     const char **argv UNUSED,
> +typedef void add_field_fn(struct strbuf *buf, struct repository *repo);
> +
> +struct field {
> +	const char *key;
> +	add_field_fn *add_field_callback;
> +};
> +
> +static void add_string(struct strbuf *buf,
> +		       const char *key, const char *value)
> +{
> +	strbuf_addf(buf, "%s\n%s%c", key, value, '\0');
> +}
> +
> +static void add_references_format(struct strbuf *buf,
> +				  struct repository *repo)
> +{
> +	add_string(buf, "references.format",
> +		   ref_storage_format_to_name(repo->ref_storage_format));
> +}
> +
> +// repo_info_fields keys should be in lexicographical order
Style: we don't use '//' comments.
> +static const struct field repo_info_fields[] = {
> +	{"references.format", add_references_format},
Style: we tend to have a space between curly braces and their inner
content.
> +static void print_fields(int argc, const char **argv, struct repository *repo) {
Style: the opening brace for functions should be on their own line.
> +	const char *last = "";
> +	struct strbuf buf;
> +	strbuf_init(&buf, 256);
> +
> +	QSORT(argv, argc, qsort_strcmp);
> +
> +	for (int i = 0; i < argc; i++) {
> +		add_field_fn *callback;
> +		const char *key = argv[i];
> +
> +		if (!strcmp(key, last))
> +			continue;
> +
> +		callback = get_append_callback(key);
> +
> +		if (!callback) {
> +			error("key %s not found", key);
> +			strbuf_release(&buf);
> +			exit(1);
> +		}
> +
> +		callback(&buf, repo);
> +		last = key;
> +	}
> +
> +	fwrite(buf.buf, 1, buf.len, stdout);
> +	strbuf_release(&buf);
Is there any reason why the callback appends to a buffer instead of
printing the data immediately?
Patrick
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH v4 0/4] repo: add new command for retrieving repository info
  2025-07-15 11:58     ` Patrick Steinhardt
@ 2025-07-15 12:20       ` Oswald Buddenhagen
  2025-07-15 19:36       ` Justin Tobler
  1 sibling, 0 replies; 226+ messages in thread
From: Oswald Buddenhagen @ 2025-07-15 12:20 UTC (permalink / raw)
  To: Patrick Steinhardt
  Cc: Lucas Seiki Oshiro, git, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler
On Tue, Jul 15, 2025 at 01:58:55PM +0200, Patrick Steinhardt wrote:
>The `repo` tool wouldn't be executed as `git repo` though, would it? So
>I'm not sure whether that really is relevant at all. On the other hand
>though I do see that it might be confusing when you interact with the
>`repo` tool on a daily basis.
>
i don't think it would be a problem in actual use. i'm more concerned 
about people talking about it. really kinda a trademark thing.
>"Query" is way too generic from my point of view, as it doesn't say
>_what_ you query. "Meta" might be a bit better even though it still
>loses the information that you act on the repository level, which is a
>bit of a shame.
>
by that logic, almost all git commands are too tersely named.
but in practice, a sufficiently suggestive mnemonic is good enough.  
preferably a verb, because it's a command.
the fact that it's now being made into a "multi-tool" also kinda 
preempts future collisions.
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH v4 2/4] repo: add the field references.format
  2025-07-14 23:52   ` [GSoC RFC PATCH v4 2/4] repo: add the field references.format Lucas Seiki Oshiro
  2025-07-15 11:59     ` Patrick Steinhardt
@ 2025-07-15 12:23     ` Karthik Nayak
  2025-07-15 19:15     ` Justin Tobler
  2 siblings, 0 replies; 226+ messages in thread
From: Karthik Nayak @ 2025-07-15 12:23 UTC (permalink / raw)
  To: Lucas Seiki Oshiro, git; +Cc: ps, ben.knoble, gitster, phillip.wood, jltobler
[-- Attachment #1: Type: text/plain, Size: 7296 bytes --]
Lucas Seiki Oshiro <lucasseikioshiro@gmail.com> writes:
> This commit is part of the series that introduce the new subcommand
> git-repo-info.
>
> The flag `--show-ref-format` from git-rev-parse is used for retrieving
> the reference format (i.e. `files` or `reftable`). This way, it is
> used for querying repository metadata, fitting in the purpose of
> git-repo-info.
>
> Then, add a new field `references.format` to the repo-info subcommand
> containing that information.
>
Nit: s/Then, add/Add
>
> Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
> Helped-by: Junio C Hamano <gitster@pobox.com>
> Helped-by: Justin Tobler <jltobler@gmail.com>
> Mentored-by: Karthik Nayak <karthik.188@gmail.com>
> Mentored-by: Patrick Steinhardt <ps@pks.im>
> Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
> ---
>  Documentation/git-repo.adoc |  4 ++
>  builtin/repo.c              | 92 +++++++++++++++++++++++++++++++++++--
>  t/meson.build               |  1 +
>  t/t1900-repo.sh             | 47 +++++++++++++++++++
>  4 files changed, 140 insertions(+), 4 deletions(-)
>  create mode 100755 t/t1900-repo.sh
>
> diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc
> index 6f8fe3f6ea..b7af6f45a4 100644
> --- a/Documentation/git-repo.adoc
> +++ b/Documentation/git-repo.adoc
> @@ -45,6 +45,10 @@ INFO KEYS
>  The set of data that `git repo` can return is grouped into the following
>  categories:
>
> +`references`::
> +Reference-related data:
> +* `format`: the reference storage format, either `files` or `reftable`.
> +
Nit: I would omit the '`files` or `reftable`' here, because while this
is currently true. This might not hold up in the future. So better to
not go into the details of the supported systems.
>  SEE ALSO
>  --------
>  linkgit:git-rev-parse[1]
> diff --git a/builtin/repo.c b/builtin/repo.c
> index a1787a3cc5..dcda0d6d61 100644
> --- a/builtin/repo.c
> +++ b/builtin/repo.c
> @@ -1,11 +1,95 @@
>  #include "builtin.h"
>  #include "parse-options.h"
> +#include "strbuf.h"
> +#include "refs.h"
>
> -static int repo_info(int argc UNUSED,
> -		     const char **argv UNUSED,
> +typedef void add_field_fn(struct strbuf *buf, struct repository *repo);
> +
> +struct field {
> +	const char *key;
> +	add_field_fn *add_field_callback;
> +};
> +
> +static void add_string(struct strbuf *buf,
> +		       const char *key, const char *value)
> +{
> +	strbuf_addf(buf, "%s\n%s%c", key, value, '\0');
> +}
> +
I like the table design used here, makes things much simpler. I do think
that each field shouldn't worry about the formatting, in fact, I would
say that we can move all of this logic to `print_fields`.
So each field would only be incharge of providing the output data. Then
`print_fields` would take the key, the output data and format it as
needed. This would also make it much easier to use a new format if
needed in the future.
> +static void add_references_format(struct strbuf *buf,
> +				  struct repository *repo)
> +{
> +	add_string(buf, "references.format",
> +		   ref_storage_format_to_name(repo->ref_storage_format));
> +}
> +
> +// repo_info_fields keys should be in lexicographical order
> +static const struct field repo_info_fields[] = {
> +	{"references.format", add_references_format},
> +};
> +
> +static int repo_info_fields_cmp(const void *va, const void *vb)
> +{
> +	const struct field *a = va;
> +	const struct field *b = vb;
> +
> +	return strcmp(a->key, b->key);
> +}
> +
> +static add_field_fn *get_append_callback(const char *key) {
> +	const struct field search_key = {key, NULL};
> +	const struct field *found = bsearch(&search_key, repo_info_fields,
> +					    ARRAY_SIZE(repo_info_fields),
> +					    sizeof(struct field),
> +					    repo_info_fields_cmp);
> +	return found ? found->add_field_callback : NULL;
> +}
> +
> +static int qsort_strcmp(const void *va, const void *vb)
> +{
> +	const char *a = *(const char **)va;
> +	const char *b = *(const char **)vb;
> +
> +	return strcmp(a, b);
> +}
> +
> +static void print_fields(int argc, const char **argv, struct repository *repo) {
> +	const char *last = "";
> +	struct strbuf buf;
> +	strbuf_init(&buf, 256);
> +
> +	QSORT(argv, argc, qsort_strcmp);
> +
> +	for (int i = 0; i < argc; i++) {
> +		add_field_fn *callback;
> +		const char *key = argv[i];
> +
> +		if (!strcmp(key, last))
> +			continue;
> +
> +		callback = get_append_callback(key);
> +
> +		if (!callback) {
> +			error("key %s not found", key);
> +			strbuf_release(&buf);
> +			exit(1);
> +		}
> +
> +		callback(&buf, repo);
> +		last = key;
> +	}
> +
> +	fwrite(buf.buf, 1, buf.len, stdout);
> +	strbuf_release(&buf);
> +}
> +
> +static int repo_info(int argc,
> +		     const char **argv,
>  		     const char *prefix UNUSED,
> -		     struct repository *repo UNUSED)
> +		     struct repository *repo)
>  {
> +
> +	print_fields(argc - 1 , argv + 1, repo);
>  	return 0;
>  }
>
> @@ -16,7 +100,7 @@ int cmd_repo(int argc,
>  {
>  	parse_opt_subcommand_fn *fn = NULL;
>  	const char *const repo_usage[] = {
> -		"git repo info",
> +		"git repo info [<key>...]",
Shouldn't this be part of the previous commit?
>  		NULL
>  	};
>  	struct option options[] = {
> diff --git a/t/meson.build b/t/meson.build
> index 1af289425d..8693e6abc4 100644
> --- a/t/meson.build
> +++ b/t/meson.build
> @@ -245,6 +245,7 @@ integration_tests = [
>    't1700-split-index.sh',
>    't1701-racy-split-index.sh',
>    't1800-hook.sh',
> +  't1900-repo.sh',
>    't2000-conflict-when-checking-files-out.sh',
>    't2002-checkout-cache-u.sh',
>    't2003-checkout-cache-mkdir.sh',
> diff --git a/t/t1900-repo.sh b/t/t1900-repo.sh
> new file mode 100755
> index 0000000000..b80fc6b78b
> --- /dev/null
> +++ b/t/t1900-repo.sh
> @@ -0,0 +1,47 @@
> +#!/bin/sh
> +
> +test_description='test git repo-info'
> +
> +. ./test-lib.sh
> +
> +# Test if a field is correctly returned in the null-terminated format
> +#
> +# Usage: test_repo_info <label> <init command> <key> <expected value>
> +#
> +# Arguments:
> +#   label: the label of the test
> +#   init command: a command that creates a repository called 'repo', configured
> +#      accordingly to what is being tested
> +#   key: the key of the field that is being tested
> +#   expected value: the value that the field should contain
> +test_repo_info () {
> +	label=$1
> +	init_command=$2
> +	key=$3
> +	expected_value=$4
> +
> +	test_expect_success "$label" '
> +		test_when_finished "rm -rf repo" &&
> +		eval "$init_command" &&
> +		echo "$expected_value" | lf_to_nul >expected &&
> +		git -C repo repo info "$key" >output &&
> +		tail -n 1 output >actual &&
> +		test_cmp expected actual
> +	'
> +}
> +
> +test_repo_info 'ref format files is retrieved correctly' '
> +	git init --ref-format=files repo' 'references.format' 'files'
> +
> +test_repo_info 'ref format reftable is retrieved correctly' '
> +	git init --ref-format=reftable repo' 'references.format' 'reftable'
> +
> +test_expect_success "only one value is returned if the same key is requested twice" '
> +	echo "references.format" > expected &&
> +	git rev-parse --show-ref-format > ref-format &&
> +	lf_to_nul <ref-format >>expected &&
> +	git repo info references.format references.format > actual &&
> +	test_cmp expected actual
> +'
> +
> +test_done
> --
> 2.39.5 (Apple Git-154)
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 690 bytes --]
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH v4 0/4] repo: add new command for retrieving repository info
  2025-07-15 10:34   ` [GSoC RFC PATCH v4 0/4] repo: add new command for retrieving repository info Oswald Buddenhagen
  2025-07-15 11:58     ` Patrick Steinhardt
@ 2025-07-15 16:49     ` Junio C Hamano
  2025-07-17 10:25       ` Oswald Buddenhagen
  1 sibling, 1 reply; 226+ messages in thread
From: Junio C Hamano @ 2025-07-15 16:49 UTC (permalink / raw)
  To: Oswald Buddenhagen
  Cc: Lucas Seiki Oshiro, git, ps, karthik.188, ben.knoble,
	phillip.wood, jltobler
Oswald Buddenhagen <oswald.buddenhagen@gmx.de> writes:
> On Mon, Jul 14, 2025 at 08:52:27PM -0300, Lucas Seiki Oshiro wrote:
>> - Renames the command to `repo` instead of `repo-info`. All the
>> functionality
>>  of `repo-info` will now be under `repo info`. The functionality of `survey`
>>  will be moved to another subcommand of `git repo`.
>>
> this strikes me as a bad idea, given how established the `repo` tool is.
>
> without much thinking and reading prior conversations, i'd go with
> "query", because it's a database-like metadata ... query.
> the obvious followup idea would then be "meta", but that suggests that
> it isn't only a read-only command, which i think it is supposed to
> remain?
"git repository query"
"git repository stat"
...?
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH v4 1/4] repo: declare the repo command
  2025-07-14 23:52   ` [GSoC RFC PATCH v4 1/4] repo: declare the repo command Lucas Seiki Oshiro
  2025-07-15 11:52     ` Karthik Nayak
  2025-07-15 11:59     ` Patrick Steinhardt
@ 2025-07-15 18:19     ` Justin Tobler
  2 siblings, 0 replies; 226+ messages in thread
From: Justin Tobler @ 2025-07-15 18:19 UTC (permalink / raw)
  To: Lucas Seiki Oshiro
  Cc: git, ps, karthik.188, ben.knoble, gitster, phillip.wood
On 25/07/14 08:52PM, Lucas Seiki Oshiro wrote:
> Currently, `git rev-parse` covers a wide range of functionality not
> directly related to parsing revisions, as its name says. Over time,
s/says/suggests/
> many features like parsing datestrings, options, paths, and others
> were added to it because there wasn't a more appropriated command
s/appropriated/appropriate/
> to place them.
> 
> Create a new Git command called `repo`. `git repo` will be the main
> command for obtaining the information about a repository (such as
> metadata and metrics), returning them in a machine readable format
> following the syntax "field<LF>value<NUL>".
> 
> Also declare a subcommand for `repo` called `info`. `git repo info`
> will bring the functionality of retrieving repository-related
> information currently returned by `rev-parse`.
> 
> Also add entries for this new command in:
> 
> - the build files (Makefile, meson.build, Documentation/meson.build)
> - builtin.h
> - git.c
> - .gitignore
> - command-list.txt
> - Documentation
> 
> Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
> Helped-by: Junio C Hamano <gitster@pobox.com>
> Helped-by: Justin Tobler <jltobler@gmail.com>
> Mentored-by: Karthik Nayak <karthik.188@gmail.com>
> Mentored-by: Patrick Steinhardt <ps@pks.im>
> Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
> ---
>  .gitignore                  |  1 +
>  Documentation/git-repo.adoc | 54 +++++++++++++++++++++++++++++++++++++
>  Documentation/meson.build   |  1 +
>  Makefile                    |  1 +
>  builtin.h                   |  1 +
>  builtin/repo.c              | 38 ++++++++++++++++++++++++++
>  command-list.txt            |  1 +
>  git.c                       |  1 +
>  meson.build                 |  1 +
>  9 files changed, 99 insertions(+)
>  create mode 100644 Documentation/git-repo.adoc
>  create mode 100644 builtin/repo.c
> 
> diff --git a/.gitignore b/.gitignore
> index 04c444404e..1803023427 100644
> --- a/.gitignore
> +++ b/.gitignore
> @@ -139,6 +139,7 @@
>  /git-repack
>  /git-replace
>  /git-replay
> +/git-repo
>  /git-request-pull
>  /git-rerere
>  /git-reset
> diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc
> new file mode 100644
> index 0000000000..6f8fe3f6ea
> --- /dev/null
> +++ b/Documentation/git-repo.adoc
> @@ -0,0 +1,54 @@
> +git-repo(1)
> +===========
> +
> +NAME
> +----
> +git-repo - Retrieve information about a repository
> +
> +SYNOPSIS
> +--------
> +[synopsis]
> +git repo info [<key>...]
> +
> +DESCRIPTION
> +-----------
> +Retrieve information about the current repository in a machine-readable format.
> +
> +`git repo` will be the primary tool to query repository-specific information,
> +such as metadata that currently can also be done by calling `git rev-parse` (see
> +linkgit:git-rev-parse[1]). `git repo` doesn't query information unrelated to the
> +current repository or that is already retrieved by a specialized command, for
> +example, `git config` (see linkgit:git-config[1]) or `git var` (see
> +linkgit:git-var[1]).
> +
> +This command returns the retrieved data following a null-terminated format with
> +this syntax:
> ++
> +----------------
> +key1<LF>value1<NUL>
> +key2<LF>value2<NUL>
> +...
> +----------------
Being that this patch doesn't yet implement any output for the command,
maybe should should hold off on specifying the format.
In other commands, it is common to see a nul-terminated format toggled
behind a `-z` flag. We may want to do something similar here as opposed
to being the default.
-Justin
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH v4 1/4] repo: declare the repo command
  2025-07-15 11:59     ` Patrick Steinhardt
@ 2025-07-15 18:38       ` Justin Tobler
  2025-07-20 19:51       ` Lucas Seiki Oshiro
  1 sibling, 0 replies; 226+ messages in thread
From: Justin Tobler @ 2025-07-15 18:38 UTC (permalink / raw)
  To: Patrick Steinhardt
  Cc: Lucas Seiki Oshiro, git, karthik.188, ben.knoble, gitster,
	phillip.wood
On 25/07/15 01:59PM, Patrick Steinhardt wrote:
> On Mon, Jul 14, 2025 at 08:52:28PM -0300, Lucas Seiki Oshiro wrote:
> > +This command returns the retrieved data following a null-terminated format with
> > +this syntax:
> > ++
> > +----------------
> > +key1<LF>value1<NUL>
> > +key2<LF>value2<NUL>
> > +...
> > +----------------
> > ++
> 
> One of the things I wonder is whether we should by default adapt those
> tools to have human-readable format, e.g. in a way that it can be easily
> added to git-bugreport(1). This would teach script authors that want to
> use the command to use `git repo info --format=porcelain` right from the
> start to have a machine-parseable output, and it would allow us to
> iterate on the exact output format.
For this subcommand (and the future "stats" one), I think the ouput
should default to a simple <key=value> form for each line and use a `-z`
flag to add support for a nul-delimited mode. This way we still have a
default view that a human can feasible consume while also supporting a
more machine friendly format in a manner consistent with other commands.
For a more decorated view of the data, something akin to git-sizer(1),
maybe we could introduce a separate subcommand in the future like `git
repo summary`. This could allow us to implement other information such
as "level of concern" separately and also group the data in a way that
is easier to digest.
-Justin
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH v4 2/4] repo: add the field references.format
  2025-07-14 23:52   ` [GSoC RFC PATCH v4 2/4] repo: add the field references.format Lucas Seiki Oshiro
  2025-07-15 11:59     ` Patrick Steinhardt
  2025-07-15 12:23     ` Karthik Nayak
@ 2025-07-15 19:15     ` Justin Tobler
  2025-07-16  5:38       ` Patrick Steinhardt
  2 siblings, 1 reply; 226+ messages in thread
From: Justin Tobler @ 2025-07-15 19:15 UTC (permalink / raw)
  To: Lucas Seiki Oshiro
  Cc: git, ps, karthik.188, ben.knoble, gitster, phillip.wood
On 25/07/14 08:52PM, Lucas Seiki Oshiro wrote:
> This commit is part of the series that introduce the new subcommand
s/introduce/introduces/
> git-repo-info.
> 
> The flag `--show-ref-format` from git-rev-parse is used for retrieving
> the reference format (i.e. `files` or `reftable`). This way, it is
> used for querying repository metadata, fitting in the purpose of
> git-repo-info.
> 
> Then, add a new field `references.format` to the repo-info subcommand
> containing that information.
> 
> Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
> Helped-by: Junio C Hamano <gitster@pobox.com>
> Helped-by: Justin Tobler <jltobler@gmail.com>
> Mentored-by: Karthik Nayak <karthik.188@gmail.com>
> Mentored-by: Patrick Steinhardt <ps@pks.im>
> Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
> ---
>  Documentation/git-repo.adoc |  4 ++
>  builtin/repo.c              | 92 +++++++++++++++++++++++++++++++++++--
>  t/meson.build               |  1 +
>  t/t1900-repo.sh             | 47 +++++++++++++++++++
>  4 files changed, 140 insertions(+), 4 deletions(-)
>  create mode 100755 t/t1900-repo.sh
> 
> diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc
> index 6f8fe3f6ea..b7af6f45a4 100644
> --- a/Documentation/git-repo.adoc
> +++ b/Documentation/git-repo.adoc
> @@ -45,6 +45,10 @@ INFO KEYS
>  The set of data that `git repo` can return is grouped into the following
>  categories:
>  
> +`references`::
> +Reference-related data:
> +* `format`: the reference storage format, either `files` or `reftable`.
> +
>  SEE ALSO
>  --------
>  linkgit:git-rev-parse[1]
> diff --git a/builtin/repo.c b/builtin/repo.c
> index a1787a3cc5..dcda0d6d61 100644
> --- a/builtin/repo.c
> +++ b/builtin/repo.c
> @@ -1,11 +1,95 @@
>  #include "builtin.h"
>  #include "parse-options.h"
> +#include "strbuf.h"
> +#include "refs.h"
>  
> -static int repo_info(int argc UNUSED,
> -		     const char **argv UNUSED,
> +typedef void add_field_fn(struct strbuf *buf, struct repository *repo);
> +
> +struct field {
> +	const char *key;
> +	add_field_fn *add_field_callback;
> +};
> +
> +static void add_string(struct strbuf *buf,
> +		       const char *key, const char *value)
> +{
> +	strbuf_addf(buf, "%s\n%s%c", key, value, '\0');
> +}
Any reason we add each key/value pair to a buffer instead of just
printing it?
Also, as mentioned in a comment for the previous patch, maybe we should
support printing two output modes. For the default output, maybe a
simple `<key>=<value>\n` where the any value containing special
characters is quoted via `quote_c_style()`.
A null-terminated output, such as the one proposed in this patch, could
be enabled via a `-z` flag similar to how its done in other commands.
-Justin
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH v4 0/4] repo: add new command for retrieving repository info
  2025-07-15 11:58     ` Patrick Steinhardt
  2025-07-15 12:20       ` Oswald Buddenhagen
@ 2025-07-15 19:36       ` Justin Tobler
  1 sibling, 0 replies; 226+ messages in thread
From: Justin Tobler @ 2025-07-15 19:36 UTC (permalink / raw)
  To: Patrick Steinhardt
  Cc: Oswald Buddenhagen, Lucas Seiki Oshiro, git, karthik.188,
	ben.knoble, gitster, phillip.wood
On 25/07/15 01:58PM, Patrick Steinhardt wrote:
> On Tue, Jul 15, 2025 at 12:34:42PM +0200, Oswald Buddenhagen wrote:
> > On Mon, Jul 14, 2025 at 08:52:27PM -0300, Lucas Seiki Oshiro wrote:
> > > - Renames the command to `repo` instead of `repo-info`. All the
> > > functionality
> > >  of `repo-info` will now be under `repo info`. The functionality of `survey`
> > >  will be moved to another subcommand of `git repo`.
> > > 
> > this strikes me as a bad idea, given how established the `repo` tool is.
> 
> The `repo` tool wouldn't be executed as `git repo` though, would it? So
> I'm not sure whether that really is relevant at all. On the other hand
> though I do see that it might be confusing when you interact with the
> `repo` tool on a daily basis.
> 
> > without much thinking and reading prior conversations, i'd go with "query",
> > because it's a database-like metadata ... query.
> > the obvious followup idea would then be "meta", but that suggests that it
> > isn't only a read-only command, which i think it is supposed to remain?
> 
> "Query" is way too generic from my point of view, as it doesn't say
> _what_ you query. "Meta" might be a bit better even though it still
> loses the information that you act on the repository level, which is a
> bit of a shame.
Agreed, "query" sounds too open-ended. Since we are only targeting
repository level data I think it would be confusing.
> We could of course adapt and call it git-repository(1) to avoid any
> confusion with git-repo(1) and repo(1). It's not like this is a tool
> that users would typically have to run daily outside of scripts, so I
> don't think it hurts much to have a longer command name.
Being that git-repo(1) isn't really intended as a common user facing
command, I wonder if there really would be much confusion with repo(1)
anyway. Personally, I perfer the shorter name and think it's fine as-is,
but it's not a big deal either way.
-Justin
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH v4 2/4] repo: add the field references.format
  2025-07-15 19:15     ` Justin Tobler
@ 2025-07-16  5:38       ` Patrick Steinhardt
  2025-07-16 14:04         ` Justin Tobler
  0 siblings, 1 reply; 226+ messages in thread
From: Patrick Steinhardt @ 2025-07-16  5:38 UTC (permalink / raw)
  To: Justin Tobler
  Cc: Lucas Seiki Oshiro, git, karthik.188, ben.knoble, gitster,
	phillip.wood
On Tue, Jul 15, 2025 at 02:15:07PM -0500, Justin Tobler wrote:
> On 25/07/14 08:52PM, Lucas Seiki Oshiro wrote:
> > diff --git a/builtin/repo.c b/builtin/repo.c
> > index a1787a3cc5..dcda0d6d61 100644
> > --- a/builtin/repo.c
> > +++ b/builtin/repo.c
> > @@ -1,11 +1,95 @@
> >  #include "builtin.h"
> >  #include "parse-options.h"
> > +#include "strbuf.h"
> > +#include "refs.h"
> >  
> > -static int repo_info(int argc UNUSED,
> > -		     const char **argv UNUSED,
> > +typedef void add_field_fn(struct strbuf *buf, struct repository *repo);
> > +
> > +struct field {
> > +	const char *key;
> > +	add_field_fn *add_field_callback;
> > +};
> > +
> > +static void add_string(struct strbuf *buf,
> > +		       const char *key, const char *value)
> > +{
> > +	strbuf_addf(buf, "%s\n%s%c", key, value, '\0');
> > +}
> 
> Any reason we add each key/value pair to a buffer instead of just
> printing it?
> 
> Also, as mentioned in a comment for the previous patch, maybe we should
> support printing two output modes. For the default output, maybe a
> simple `<key>=<value>\n` where the any value containing special
> characters is quoted via `quote_c_style()`.
> 
> A null-terminated output, such as the one proposed in this patch, could
> be enabled via a `-z` flag similar to how its done in other commands.
Agreed in general, but instead of using `-z` I wonder whether it would
make sense to use something like `--format=key-value` and `--format=nul`
instead. This gives us more room to introduce additional formats in the
future, like for example the JSON format that was scrapped for now.
Patrick
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH v4 2/4] repo: add the field references.format
  2025-07-16  5:38       ` Patrick Steinhardt
@ 2025-07-16 14:04         ` Justin Tobler
  2025-07-17 13:03           ` Patrick Steinhardt
  0 siblings, 1 reply; 226+ messages in thread
From: Justin Tobler @ 2025-07-16 14:04 UTC (permalink / raw)
  To: Patrick Steinhardt
  Cc: Lucas Seiki Oshiro, git, karthik.188, ben.knoble, gitster,
	phillip.wood
On 25/07/16 07:38AM, Patrick Steinhardt wrote:
> On Tue, Jul 15, 2025 at 02:15:07PM -0500, Justin Tobler wrote:
> > Also, as mentioned in a comment for the previous patch, maybe we should
> > support printing two output modes. For the default output, maybe a
> > simple `<key>=<value>\n` where the any value containing special
> > characters is quoted via `quote_c_style()`.
> > 
> > A null-terminated output, such as the one proposed in this patch, could
> > be enabled via a `-z` flag similar to how its done in other commands.
> 
> Agreed in general, but instead of using `-z` I wonder whether it would
> make sense to use something like `--format=key-value` and `--format=nul`
> instead. This gives us more room to introduce additional formats in the
> future, like for example the JSON format that was scrapped for now.
If we already plan to support additional output formats, they I agree we
should probably a `--format=<output-type>` flag from the start. I still
think it would be nice to have a `-z` flag that is shorthand for
`--format=nul` though as that is fairly common across other commands to
have such an option.
Out of curiousity, is there a reason we are interested in supporting a
JSON output format in addition to what is already proposed? From an
earlier conversation I had with Lucas, it didn't seem like there was any
particular reason for JSON.
-Justin
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH v4 0/4] repo: add new command for retrieving repository info
  2025-07-14 23:52 ` [GSoC RFC PATCH v4 0/4] repo: " Lucas Seiki Oshiro
                     ` (4 preceding siblings ...)
  2025-07-15 10:34   ` [GSoC RFC PATCH v4 0/4] repo: add new command for retrieving repository info Oswald Buddenhagen
@ 2025-07-16 20:20   ` Junio C Hamano
  2025-07-16 20:33     ` Junio C Hamano
  2025-07-21 22:05     ` Lucas Seiki Oshiro
  5 siblings, 2 replies; 226+ messages in thread
From: Junio C Hamano @ 2025-07-16 20:20 UTC (permalink / raw)
  To: Lucas Seiki Oshiro
  Cc: git, ps, karthik.188, ben.knoble, phillip.wood, jltobler
Lucas Seiki Oshiro <lucasseikioshiro@gmail.com> writes:
> This patch, then:
>
> - Renames the command to `repo` instead of `repo-info`. All the functionality
>   of `repo-info` will now be under `repo info`. The functionality of `survey`
>   will be moved to another subcommand of `git repo`.
>
> - Removes the JSON support. Given that after the previous feedback we already
>   have a nice machine-readable format for outputting this data, JSON would not
>   be so useful as it seemed to be at first (when the "other format" was just
>   returning the values without the keys). This makes the code far more simpler,
>   as we don't need to deal with the details of both formats.
>
> - Uses a simpler representation of the fields, based in their keys instead of
>   declaring multiple enums and using nested switches. This new solution is
>   based in a table mapping the keys and the callbacks for retrieving the data.
>
> - Provide a simple infrastructure for extending with the second command.
>
> Given that this v4 is almost a rewrite, I think it isn't worth to send a
> range-diff.
OK.  If it is almost a rewrite, then perhaps we should tart by
making sure that it won't have too many irritating style gotchas to
discourage reviewers from reading it ;-)
The below is from 
    $ git clang-format --diff $(git merge-base master HEAD) -- builtin/repo.c
I removed some obviously bad suggestions but many were improvements.
I'll follow this message up as if I were reviewing what clang-format
produced.
Thanks.
 builtin/repo.c | 47 ++++++++++++++++++++---------------------------
 1 file changed, 20 insertions(+), 27 deletions(-)
diff --git c/builtin/repo.c w/builtin/repo.c
index d75417a48b..e8cf465da6 100644
--- c/builtin/repo.c
+++ w/builtin/repo.c
@@ -14,27 +14,23 @@ struct field {
 	add_field_fn *add_field_callback;
 };
 
-static void add_string(struct strbuf *buf,
-		       const char *key, const char *value)
+static void add_string(struct strbuf *buf, const char *key, const char *value)
 {
 	strbuf_addf(buf, "%s\n%s%c", key, value, '\0');
 }
 
-static void add_bool(struct strbuf *buf,
-		     const char *key, const int value)
+static void add_bool(struct strbuf *buf, const char *key, const int value)
 {
 	const char *output_value = value ? "true" : "false";
 	strbuf_addf(buf, "%s\n%s%c", key, output_value, '\0');
 }
 
-static void add_references_format(struct strbuf *buf,
-				  struct repository *repo)
+static void add_references_format(struct strbuf *buf, struct repository *repo)
 {
 	add_string(buf, "references.format",
 		   ref_storage_format_to_name(repo->ref_storage_format));
 }
 
-
 static void add_layout_bare(struct strbuf *buf, struct repository *repo UNUSED)
 {
 	add_bool(buf, "layout.bare", is_bare_repository());
@@ -45,11 +41,11 @@ static void add_layout_shallow(struct strbuf *buf, struct repository *repo)
 	add_bool(buf, "layout.shallow", is_repository_shallow(repo));
 }
 
-// repo_info_fields keys should be in lexicographical order
+/* repo_info_fields keys should be in lexicographical order */
 static const struct field repo_info_fields[] = {
-	{"layout.bare", add_layout_bare},
-	{"layout.shallow", add_layout_shallow},
-	{"references.format", add_references_format},
+	{ "layout.bare", add_layout_bare },
+	{ "layout.shallow", add_layout_shallow },
+	{ "references.format", add_references_format },
 };
 
 static int repo_info_fields_cmp(const void *va, const void *vb)
@@ -60,12 +56,13 @@ static int repo_info_fields_cmp(const void *va, const void *vb)
 	return strcmp(a->key, b->key);
 }
 
-static add_field_fn *get_append_callback(const char *key) {
-	const struct field search_key = {key, NULL};
-	const struct field *found = bsearch(&search_key, repo_info_fields,
-					    ARRAY_SIZE(repo_info_fields),
-					    sizeof(struct field),
-					    repo_info_fields_cmp);
+static add_field_fn *get_append_callback(const char *key)
+{
+	const struct field search_key = { key, NULL };
+	const struct field *found =
+		bsearch(&search_key, repo_info_fields,
+			ARRAY_SIZE(repo_info_fields), sizeof(struct field),
+			repo_info_fields_cmp);
 	return found ? found->add_field_callback : NULL;
 }
 
@@ -77,7 +74,8 @@ static int qsort_strcmp(const void *va, const void *vb)
 	return strcmp(a, b);
 }
 
-static void print_fields(int argc, const char **argv, struct repository *repo) {
+static void print_fields(int argc, const char **argv, struct repository *repo)
+{
 	const char *last = "";
 	struct strbuf buf;
 	strbuf_init(&buf, 256);
@@ -91,7 +89,7 @@ static void print_fields(int argc, const char **argv, struct repository *repo) {
 		if (!strcmp(key, last))
 			continue;
 
-		callback = get_append_callback(key);
+		callback = *get_append_callback(key);
 
 		if (!callback) {
 			error("key %s not found", key);
@@ -107,19 +105,14 @@ static void print_fields(int argc, const char **argv, struct repository *repo) {
 	strbuf_release(&buf);
 }
 
-static int repo_info(int argc,
-		     const char **argv,
-		     const char *prefix UNUSED,
+static int repo_info(int argc, const char **argv, const char *prefix UNUSED,
 		     struct repository *repo)
 {
-
-	print_fields(argc - 1 , argv + 1, repo);
+	print_fields(argc - 1, argv + 1, repo);
 	return 0;
 }
 
-int cmd_repo(int argc,
-	     const char **argv,
-	     const char *prefix,
+int cmd_repo(int argc, const char **argv, const char *prefix,
 	     struct repository *repo)
 {
 	parse_opt_subcommand_fn *fn = NULL;
^ permalink raw reply related	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH v4 0/4] repo: add new command for retrieving repository info
  2025-07-16 20:20   ` Junio C Hamano
@ 2025-07-16 20:33     ` Junio C Hamano
  2025-07-21 22:05     ` Lucas Seiki Oshiro
  1 sibling, 0 replies; 226+ messages in thread
From: Junio C Hamano @ 2025-07-16 20:33 UTC (permalink / raw)
  To: Lucas Seiki Oshiro
  Cc: git, ps, karthik.188, ben.knoble, phillip.wood, jltobler
Junio C Hamano <gitster@pobox.com> writes:
> The below is from 
>
>     $ git clang-format --diff $(git merge-base master HEAD) -- builtin/repo.c
>
> I removed some obviously bad suggestions but many were improvements.
>
> I'll follow this message up as if I were reviewing what clang-format
> produced.
>
> Thanks.
>
>
>  builtin/repo.c | 47 ++++++++++++++++++++---------------------------
>  1 file changed, 20 insertions(+), 27 deletions(-)
>
> diff --git c/builtin/repo.c w/builtin/repo.c
> index d75417a48b..e8cf465da6 100644
> --- c/builtin/repo.c
> +++ w/builtin/repo.c
> @@ -14,27 +14,23 @@ struct field {
>  	add_field_fn *add_field_callback;
>  };
>  
> -static void add_string(struct strbuf *buf,
> -		       const char *key, const char *value)
> +static void add_string(struct strbuf *buf, const char *key, const char *value)
>  {
>  	strbuf_addf(buf, "%s\n%s%c", key, value, '\0');
>  }
>  
> -static void add_bool(struct strbuf *buf,
> -		     const char *key, const int value)
> +static void add_bool(struct strbuf *buf, const char *key, const int value)
>  {
>  	const char *output_value = value ? "true" : "false";
>  	strbuf_addf(buf, "%s\n%s%c", key, output_value, '\0');
>  }
>  
> -static void add_references_format(struct strbuf *buf,
> -				  struct repository *repo)
> +static void add_references_format(struct strbuf *buf, struct repository *repo)
>  {
>  	add_string(buf, "references.format",
>  		   ref_storage_format_to_name(repo->ref_storage_format));
>  }
If the parameter list fits on a single line not just helps readers
of a code who reads from top to bottom, but those who run "grep" for
the function name.
>  
> -
>  static void add_layout_bare(struct strbuf *buf, struct repository *repo UNUSED)
>  {
>  	add_bool(buf, "layout.bare", is_bare_repository());
No reason to give double-blank between these two functions; it is
not like add_string/bool/references/format are closer together than
this add_layout_bare
> @@ -45,11 +41,11 @@ static void add_layout_shallow(struct strbuf *buf, struct repository *repo)
>  	add_bool(buf, "layout.shallow", is_repository_shallow(repo));
>  }
>  
> -// repo_info_fields keys should be in lexicographical order
> +/* repo_info_fields keys should be in lexicographical order */
We don't do // comments
>  static const struct field repo_info_fields[] = {
> -	{"layout.bare", add_layout_bare},
> -	{"layout.shallow", add_layout_shallow},
> -	{"references.format", add_references_format},
> +	{ "layout.bare", add_layout_bare },
> +	{ "layout.shallow", add_layout_shallow },
> +	{ "references.format", add_references_format },
>  };
Spaces are used inside {braces} like the above.
>  static int repo_info_fields_cmp(const void *va, const void *vb)
> @@ -60,12 +56,13 @@ static int repo_info_fields_cmp(const void *va, const void *vb)
>  	return strcmp(a->key, b->key);
>  }
>  
> -static add_field_fn *get_append_callback(const char *key) {
> -	const struct field search_key = {key, NULL};
> -	const struct field *found = bsearch(&search_key, repo_info_fields,
> -					    ARRAY_SIZE(repo_info_fields),
> -					    sizeof(struct field),
> -					    repo_info_fields_cmp);
> +static add_field_fn *get_append_callback(const char *key)
> +{
"{" opening and "}" closing braces around a function body sit on
their own line alone without anybody else.  This is unlike the
multi-statement blocks in control structures (e.g. opening brace for
the block executed when condition holds in "if (cond) {" comes after
the closing parenthesis ")" for the condition after a SP on the same
line).
> +	const struct field search_key = { key, NULL };
Use of spaces inside brace pair again.
> +	const struct field *found =
> +		bsearch(&search_key, repo_info_fields,
> +			ARRAY_SIZE(repo_info_fields), sizeof(struct field),
> +			repo_info_fields_cmp);
>  	return found ? found->add_field_callback : NULL;
>  }
>  
> @@ -77,7 +74,8 @@ static int qsort_strcmp(const void *va, const void *vb)
>  	return strcmp(a, b);
>  }
>  
> -static void print_fields(int argc, const char **argv, struct repository *repo) {
> +static void print_fields(int argc, const char **argv, struct repository *repo)
> +{
Ditto.
>  	const char *last = "";
>  	struct strbuf buf;
>  	strbuf_init(&buf, 256);
> @@ -107,19 +105,14 @@ static void print_fields(int argc, const char **argv, struct repository *repo) {
>  	strbuf_release(&buf);
>  }
>  
> -static int repo_info(int argc,
> -		     const char **argv,
> -		     const char *prefix UNUSED,
> +static int repo_info(int argc, const char **argv, const char *prefix UNUSED,
>  		     struct repository *repo)
>  {
> -
> -	print_fields(argc - 1 , argv + 1, repo);
Extra SP before ",".
> +	print_fields(argc - 1, argv + 1, repo);
>  	return 0;
>  }
>  
> -int cmd_repo(int argc,
> -	     const char **argv,
> -	     const char *prefix,
> +int cmd_repo(int argc, const char **argv, const char *prefix,
>  	     struct repository *repo)
>  {
>  	parse_opt_subcommand_fn *fn = NULL;
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH v4 0/4] repo: add new command for retrieving repository info
  2025-07-15 16:49     ` Junio C Hamano
@ 2025-07-17 10:25       ` Oswald Buddenhagen
  2025-07-17 10:42         ` Patrick Steinhardt
  0 siblings, 1 reply; 226+ messages in thread
From: Oswald Buddenhagen @ 2025-07-17 10:25 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Lucas Seiki Oshiro, git, ps, karthik.188, ben.knoble,
	phillip.wood, jltobler
On Tue, Jul 15, 2025 at 09:49:52AM -0700, Junio C Hamano wrote:
>Oswald Buddenhagen <oswald.buddenhagen@gmx.de> writes:
>> the obvious followup idea would then be "meta", but that suggests 
>> that
>> it isn't only a read-only command, which i think it is supposed to
>> remain?
>
>"git repository query"
>"git repository stat"
>...?
>
yes, but one could also add "git repository set" or some such. as such 
symmetry is reasonable to expect, people might be confused by its 
absence. an obviously read-only command like "query" would preclude 
this.
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH v4 0/4] repo: add new command for retrieving repository info
  2025-07-17 10:25       ` Oswald Buddenhagen
@ 2025-07-17 10:42         ` Patrick Steinhardt
  0 siblings, 0 replies; 226+ messages in thread
From: Patrick Steinhardt @ 2025-07-17 10:42 UTC (permalink / raw)
  To: Oswald Buddenhagen
  Cc: Junio C Hamano, Lucas Seiki Oshiro, git, karthik.188, ben.knoble,
	phillip.wood, jltobler
On Thu, Jul 17, 2025 at 12:25:03PM +0200, Oswald Buddenhagen wrote:
> On Tue, Jul 15, 2025 at 09:49:52AM -0700, Junio C Hamano wrote:
> > Oswald Buddenhagen <oswald.buddenhagen@gmx.de> writes:
> > > the obvious followup idea would then be "meta", but that suggests
> > > that
> > > it isn't only a read-only command, which i think it is supposed to
> > > remain?
> > 
> > "git repository query"
> > "git repository stat"
> > ...?
> > 
> yes, but one could also add "git repository set" or some such. as such
> symmetry is reasonable to expect, people might be confused by its absence.
> an obviously read-only command like "query" would preclude this.
Well, right now it's exclusively read-only, true. But that doesn't mean
that there will never be a use case for adding a writing subcommand to
it.
Patrick
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH v4 2/4] repo: add the field references.format
  2025-07-16 14:04         ` Justin Tobler
@ 2025-07-17 13:03           ` Patrick Steinhardt
  2025-07-17 16:06             ` Justin Tobler
  0 siblings, 1 reply; 226+ messages in thread
From: Patrick Steinhardt @ 2025-07-17 13:03 UTC (permalink / raw)
  To: Justin Tobler
  Cc: Lucas Seiki Oshiro, git, karthik.188, ben.knoble, gitster,
	phillip.wood
On Wed, Jul 16, 2025 at 09:04:40AM -0500, Justin Tobler wrote:
> On 25/07/16 07:38AM, Patrick Steinhardt wrote:
> > On Tue, Jul 15, 2025 at 02:15:07PM -0500, Justin Tobler wrote:
> > > Also, as mentioned in a comment for the previous patch, maybe we should
> > > support printing two output modes. For the default output, maybe a
> > > simple `<key>=<value>\n` where the any value containing special
> > > characters is quoted via `quote_c_style()`.
> > > 
> > > A null-terminated output, such as the one proposed in this patch, could
> > > be enabled via a `-z` flag similar to how its done in other commands.
> > 
> > Agreed in general, but instead of using `-z` I wonder whether it would
> > make sense to use something like `--format=key-value` and `--format=nul`
> > instead. This gives us more room to introduce additional formats in the
> > future, like for example the JSON format that was scrapped for now.
> 
> If we already plan to support additional output formats, they I agree we
> should probably a `--format=<output-type>` flag from the start. I still
> think it would be nice to have a `-z` flag that is shorthand for
> `--format=nul` though as that is fairly common across other commands to
> have such an option.
> 
> Out of curiousity, is there a reason we are interested in supporting a
> JSON output format in addition to what is already proposed? From an
> earlier conversation I had with Lucas, it didn't seem like there was any
> particular reason for JSON.
I don't care much about the JSON output format. What I do care about is
to have a default format that we are free to iterate on, especially in
the context of `git repo size`. If we ever want to have output that is
as user friendly as git-sizer(1)'s we need to have that freedom.
From my perspective that necessitates two things:
  - That we are able to change formats with a proper `--format=` flag.
    `-z` alone doesn't fit that bill, as we are already talking about
    there formats: user friendly, key-value pairs, and key-value pairs
    with NUL termination.
    That being said I'm not opposed to also have `-z` as an alias as
    long as we also have `--format=`.
  - That the _default_ format is the user friendly format that we can
    iterate on, at least for `git repo size`. Otherwise we have already
    failed on our mission to supply a user-friendly alternative to
    git-sizer(1).
Patrick
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH v4 2/4] repo: add the field references.format
  2025-07-17 13:03           ` Patrick Steinhardt
@ 2025-07-17 16:06             ` Justin Tobler
  2025-07-18 20:26               ` Lucas Seiki Oshiro
  0 siblings, 1 reply; 226+ messages in thread
From: Justin Tobler @ 2025-07-17 16:06 UTC (permalink / raw)
  To: Patrick Steinhardt
  Cc: Lucas Seiki Oshiro, git, karthik.188, ben.knoble, gitster,
	phillip.wood
On 25/07/17 03:03PM, Patrick Steinhardt wrote:
> On Wed, Jul 16, 2025 at 09:04:40AM -0500, Justin Tobler wrote:
> > If we already plan to support additional output formats, they I agree we
> > should probably a `--format=<output-type>` flag from the start. I still
> > think it would be nice to have a `-z` flag that is shorthand for
> > `--format=nul` though as that is fairly common across other commands to
> > have such an option.
> > 
> > Out of curiousity, is there a reason we are interested in supporting a
> > JSON output format in addition to what is already proposed? From an
> > earlier conversation I had with Lucas, it didn't seem like there was any
> > particular reason for JSON.
> 
> I don't care much about the JSON output format. What I do care about is
> to have a default format that we are free to iterate on, especially in
> the context of `git repo size`. If we ever want to have output that is
> as user friendly as git-sizer(1)'s we need to have that freedom.
> 
> From my perspective that necessitates two things:
> 
>   - That we are able to change formats with a proper `--format=` flag.
>     `-z` alone doesn't fit that bill, as we are already talking about
>     there formats: user friendly, key-value pairs, and key-value pairs
>     with NUL termination.
> 
>     That being said I'm not opposed to also have `-z` as an alias as
>     long as we also have `--format=`.
> 
>   - That the _default_ format is the user friendly format that we can
>     iterate on, at least for `git repo size`. Otherwise we have already
>     failed on our mission to supply a user-friendly alternative to
>     git-sizer(1).
I was originally of the mindset that git-repo(1) would focus on being
more of a plumbing commmand and if we wanted to provide a more
user-friendly decorated format for something akin to git-sizer(1) info,
that would be better done through a separate command.
Thinking about this some more though, I agree with you that we should
probably just have git-repo(1) be the single stop and provide the
various output flavors for its subcommands. If this is the route we go
down, the default mode should be user-friendly.
I think a key attribute of this user-friendly mode is that it should be
free to change and be iterated on. If a user wants a stable output
format, they should request the key-value output form that is
line/nul-delimited.
So maybe we have three different output modes for `--format=<mode>`:
`user` (default), `keyvalue`, and `nul`? For `git repo info`, I'm not
entirely certain how the default user-friendly mode would/should differ
from the key-value one, but maybe that is not something we need to worry
about right now. For now, the two modes could match and over time update
the user mode as desired.
-Justin
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH v4 2/4] repo: add the field references.format
  2025-07-15 11:59     ` Patrick Steinhardt
@ 2025-07-18 19:13       ` Lucas Seiki Oshiro
  0 siblings, 0 replies; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-07-18 19:13 UTC (permalink / raw)
  To: Patrick Steinhardt
  Cc: git, karthik.188, ben.knoble, gitster, phillip.wood, jltobler
> Is there any reason why the callback appends to a buffer instead of
> printing the data immediately?
Even though I answered you about that in our meeting, I'll answer you
again only to make it transparent for the other reviewers.
My idea was to build the output string and if something goes wrong
(e.g. the user requested a invalid key after some valid keys), the
process would exit without any output.
After our meeting, we agreed that this wouldn't be so important and it
would be better making the code simpler by just printing the key-value
pairs.
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH v4 2/4] repo: add the field references.format
  2025-07-17 16:06             ` Justin Tobler
@ 2025-07-18 20:26               ` Lucas Seiki Oshiro
  2025-07-21 14:41                 ` Justin Tobler
  0 siblings, 1 reply; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-07-18 20:26 UTC (permalink / raw)
  To: Justin Tobler
  Cc: Patrick Steinhardt, git, karthik.188, ben.knoble, gitster,
	phillip.wood
> So maybe we have three different output modes for `--format=<mode>`:
> `user` (default), `keyvalue`, and `nul`?
What about `porcelain` (default), `keyvalue` and `null` (being `-z` an
alias for this last one)?
> For `git repo info`, I'm not entirely certain how the default
> user-friendly mode would/should differ from the key-value one
Even for the "survey" part, would it be useful to have a key-value and
another human-readable format?
Another thing that I was thinking (as a future feature): what about
using by default the user-friendly format and using the null-terminated
format when piping the output to another command (like git-diff does
with the colors)?
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH v4 1/4] repo: declare the repo command
  2025-07-15 11:59     ` Patrick Steinhardt
  2025-07-15 18:38       ` Justin Tobler
@ 2025-07-20 19:51       ` Lucas Seiki Oshiro
  1 sibling, 0 replies; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-07-20 19:51 UTC (permalink / raw)
  To: Patrick Steinhardt
  Cc: git, karthik.188, ben.knoble, gitster, phillip.wood, jltobler
>> + argc = parse_options(argc, argv, prefix, options, repo_usage, 0);
>> +
>> + if (fn) {
>> + return fn(argc, argv, prefix, repo);
>> + } else {
>> + if (argc) {
>> + error(_("unknown subcommand: `%s'"), argv[0]);
>> + usage_with_options(repo_usage, options);
>> + }
>> + return 1;
> 
> I think we need to print an error `if (!argc)`, as well. Otherwise the
> user wouldn't know why `git repo` without any argumentsdoesn't do
> anything.
Actually, it already does it! The subcommand parsing introduced in fa83cc834d
(parse-options: add support for parsing subcommands, 2022-08-19) displays
"error: need a subcommand" and the command usage when no subcommand is provided.
Actually, this whole if-else can be removed. When an invalid command is
provided, the execution is aborted in parse_options, so it's safe to assume that
fn is a valid function.
I'll change that.
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH v4 2/4] repo: add the field references.format
  2025-07-18 20:26               ` Lucas Seiki Oshiro
@ 2025-07-21 14:41                 ` Justin Tobler
  0 siblings, 0 replies; 226+ messages in thread
From: Justin Tobler @ 2025-07-21 14:41 UTC (permalink / raw)
  To: Lucas Seiki Oshiro
  Cc: Patrick Steinhardt, git, karthik.188, ben.knoble, gitster,
	phillip.wood
On 25/07/18 05:26PM, Lucas Seiki Oshiro wrote:
> 
> > So maybe we have three different output modes for `--format=<mode>`:
> > `user` (default), `keyvalue`, and `nul`?
> 
> What about `porcelain` (default), `keyvalue` and `null` (being `-z` an
> alias for this last one)?
Sure that also would work.
> 
> > For `git repo info`, I'm not entirely certain how the default
> > user-friendly mode would/should differ from the key-value one
> 
> Even for the "survey" part, would it be useful to have a key-value and
> another human-readable format?
The only use I would see if it a user would want a non-decorated output
that is still user-friendly (ie not nul delimited). There is also no
reason we couldn't add this later in the future if we need it. For now,
we could just focus on the "porcelain" and "nul" formats if we want.
> Another thing that I was thinking (as a future feature): what about
> using by default the user-friendly format and using the null-terminated
> format when piping the output to another command (like git-diff does
> with the colors)?
I don't have a strong opinion, but I'm somewhat of the mindset that the
output format should be an explicit choice. Maybe the user would want to
manipulate the user-friendly ouput is some way.
-Justin
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC RFC PATCH v4 0/4] repo: add new command for retrieving repository info
  2025-07-16 20:20   ` Junio C Hamano
  2025-07-16 20:33     ` Junio C Hamano
@ 2025-07-21 22:05     ` Lucas Seiki Oshiro
  1 sibling, 0 replies; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-07-21 22:05 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, ps, karthik.188, ben.knoble, phillip.wood, jltobler
>    $ git clang-format --diff $(git merge-base master HEAD) -- builtin/repo.c
Thanks for your suggestion! I didn't know about it, I'll use to check my
next patches.
^ permalink raw reply	[flat|nested] 226+ messages in thread
* [GSoC PATCH v5 0/5] repo: add new command for retrieving repository info
  2025-06-10 15:21 [GSoC RFC PATCH 0/5] repo-info: add new command for retrieving repository info Lucas Seiki Oshiro
                   ` (10 preceding siblings ...)
  2025-07-14 23:52 ` [GSoC RFC PATCH v4 0/4] repo: " Lucas Seiki Oshiro
@ 2025-07-22  0:28 ` Lucas Seiki Oshiro
  2025-07-22  0:28   ` [GSoC PATCH v5 1/5] repo: declare the repo command Lucas Seiki Oshiro
                     ` (4 more replies)
  2025-07-27 17:51 ` [GSoC PATCH v5 0/5] repo: add new command for retrieving repository info Lucas Seiki Oshiro
                   ` (5 subsequent siblings)
  17 siblings, 5 replies; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-07-22  0:28 UTC (permalink / raw)
  To: git
  Cc: oswald.buddenhagen, ps, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler, Lucas Seiki Oshiro
Hi!
This fifth version addresses the issues from v4.
The major changes are:
- A new output format was added: key=value<LF>. This is the default format.
- The values are printed right after their retrieval, this way, I dropped the
  use of strbuf.
- The callbacks now return strings instead of filling the strbuf.
Things that didn't change:
- After the previous discussions (and the internal discussion with my mentors),
  I'll still keep the name `git repo`.
Future work:
- The current callback format works for the current values, but won't work for
  other fields that may require dynamically allocated strings (e.g. numbers and
  paths). I'm thinking about changing the callbacks to return strbufs instead
  of strings, but I'm open for suggestions.
- Add `-z` and/or `--null` as alias for `--format=null`.
Here's the rangediff from v4 to v5:
1:  c5f08d4342 ! 1:  396cfc256a repo: declare the repo command
    @@ Commit message
         repo: declare the repo command
         Currently, `git rev-parse` covers a wide range of functionality not
    -    directly related to parsing revisions, as its name says. Over time,
    +    directly related to parsing revisions, as its name suggests. Over time,
         many features like parsing datestrings, options, paths, and others
    -    were added to it because there wasn't a more appropriated command
    +    were added to it because there wasn't a more appropriate command
         to place them.
         Create a new Git command called `repo`. `git repo` will be the main
    @@ Commit message
         will bring the functionality of retrieving repository-related
         information currently returned by `rev-parse`.
    -    Also add entries for this new command in:
    -
    -    - the build files (Makefile, meson.build, Documentation/meson.build)
    -    - builtin.h
    -    - git.c
    -    - .gitignore
    -    - command-list.txt
    -    - Documentation
    +    Add the required tests, documentation and build changes to enable
    +    usage of this subcommand.
         Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
         Helped-by: Junio C Hamano <gitster@pobox.com>
    @@ Documentation/git-repo.adoc (new)
     +
     +DESCRIPTION
     +-----------
    -+Retrieve information about the current repository in a machine-readable format.
    -+
    -+`git repo` will be the primary tool to query repository-specific information,
    -+such as metadata that currently can also be done by calling `git rev-parse` (see
    -+linkgit:git-rev-parse[1]). `git repo` doesn't query information unrelated to the
    -+current repository or that is already retrieved by a specialized command, for
    -+example, `git config` (see linkgit:git-config[1]) or `git var` (see
    -+linkgit:git-var[1]).
    ++This command retrieve repository level information.
     +
    -+This command returns the retrieved data following a null-terminated format with
    -+this syntax:
    -++
    -+----------------
    -+key1<LF>value1<NUL>
    -+key2<LF>value2<NUL>
    -+...
    -+----------------
    -++
     +THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOR MAY CHANGE.
     +
     +COMMANDS
    @@ builtin/repo.c (new)
     +#include "builtin.h"
     +#include "parse-options.h"
     +
    -+static int repo_info(int argc UNUSED,
    -+		     const char **argv UNUSED,
    -+		     const char *prefix UNUSED,
    -+		     struct repository *repo UNUSED)
    ++static int repo_info(int argc UNUSED, const char **argv UNUSED,
    ++		     const char *prefix UNUSED, struct repository *repo UNUSED)
     +{
     +	return 0;
     +}
     +
    -+int cmd_repo(int argc,
    -+	     const char **argv,
    -+	     const char *prefix,
    ++int cmd_repo(int argc, const char **argv, const char *prefix,
     +	     struct repository *repo)
     +{
     +	parse_opt_subcommand_fn *fn = NULL;
     +	const char *const repo_usage[] = {
    -+		"git repo info",
    ++		"git repo info [<key>...]",
     +		NULL
     +	};
     +	struct option options[] = {
    @@ builtin/repo.c (new)
     +
     +	argc = parse_options(argc, argv, prefix, options, repo_usage, 0);
     +
    -+	if (fn) {
    -+		return fn(argc, argv, prefix, repo);
    -+	} else {
    -+		if (argc) {
    -+			error(_("unknown subcommand: `%s'"), argv[0]);
    -+			usage_with_options(repo_usage, options);
    -+		}
    -+		return 1;
    -+	}
    ++	return fn(argc, argv, prefix, repo);
     +}
      ## command-list.txt ##
2:  60494d5a17 ! 2:  28f4c21a96 repo: add the field references.format
    @@ Metadata
      ## Commit message ##
         repo: add the field references.format
    -    This commit is part of the series that introduce the new subcommand
    +    This commit is part of the series that introduces the new subcommand
         git-repo-info.
         The flag `--show-ref-format` from git-rev-parse is used for retrieving
    @@ Documentation/git-repo.adoc: INFO KEYS
     +`references`::
     +Reference-related data:
    -+* `format`: the reference storage format, either `files` or `reftable`.
    ++* `format`: the reference storage format
     +
      SEE ALSO
      --------
    @@ builtin/repo.c
     @@
      #include "builtin.h"
      #include "parse-options.h"
    -+#include "strbuf.h"
     +#include "refs.h"
    --static int repo_info(int argc UNUSED,
    --		     const char **argv UNUSED,
    -+typedef void add_field_fn(struct strbuf *buf, struct repository *repo);
    +-static int repo_info(int argc UNUSED, const char **argv UNUSED,
    +-		     const char *prefix UNUSED, struct repository *repo UNUSED)
    ++typedef const char *get_value_fn(struct repository *repo);
     +
     +struct field {
     +	const char *key;
    -+	add_field_fn *add_field_callback;
    ++	get_value_fn *add_field_callback;
     +};
     +
    -+static void add_string(struct strbuf *buf,
    -+		       const char *key, const char *value)
    ++static const char *get_references_format(struct repository *repo)
     +{
    -+	strbuf_addf(buf, "%s\n%s%c", key, value, '\0');
    ++	return ref_storage_format_to_name(repo->ref_storage_format);
     +}
     +
    -+static void add_references_format(struct strbuf *buf,
    -+				  struct repository *repo)
    -+{
    -+	add_string(buf, "references.format",
    -+		   ref_storage_format_to_name(repo->ref_storage_format));
    -+}
    -+
    -+// repo_info_fields keys should be in lexicographical order
    ++/* repo_info_fields keys should be in lexicographical order */
     +static const struct field repo_info_fields[] = {
    -+	{"references.format", add_references_format},
    ++	{ "references.format", get_references_format },
     +};
     +
     +static int repo_info_fields_cmp(const void *va, const void *vb)
    @@ builtin/repo.c
     +	return strcmp(a->key, b->key);
     +}
     +
    -+static add_field_fn *get_append_callback(const char *key) {
    -+	const struct field search_key = {key, NULL};
    ++static get_value_fn *get_value_callback(const char *key)
    + {
    ++	const struct field search_key = { key, NULL };
     +	const struct field *found = bsearch(&search_key, repo_info_fields,
     +					    ARRAY_SIZE(repo_info_fields),
     +					    sizeof(struct field),
    @@ builtin/repo.c
     +	return strcmp(a, b);
     +}
     +
    -+static void print_fields(int argc, const char **argv, struct repository *repo) {
    ++static int print_fields(int argc, const char **argv, struct repository *repo)
    ++{
     +	const char *last = "";
    -+	struct strbuf buf;
    -+	strbuf_init(&buf, 256);
     +
     +	QSORT(argv, argc, qsort_strcmp);
     +
     +	for (int i = 0; i < argc; i++) {
    -+		add_field_fn *callback;
    ++		get_value_fn *callback;
     +		const char *key = argv[i];
    ++		const char *value;
     +
     +		if (!strcmp(key, last))
     +			continue;
     +
    -+		callback = get_append_callback(key);
    ++		callback = get_value_callback(key);
     +
    -+		if (!callback) {
    -+			error("key %s not found", key);
    -+			strbuf_release(&buf);
    -+			exit(1);
    -+		}
    ++		if (!callback)
    ++			return error("key %s not found", key);
     +
    -+		callback(&buf, repo);
    ++		value = callback(repo);
    ++		printf("%s=%s\n", key, value);
     +		last = key;
     +	}
     +
    -+	fwrite(buf.buf, 1, buf.len, stdout);
    -+	strbuf_release(&buf);
    -+}
    -+
    -+static int repo_info(int argc,
    -+		     const char **argv,
    - 		     const char *prefix UNUSED,
    --		     struct repository *repo UNUSED)
    -+		     struct repository *repo)
    - {
    -+
    -+	print_fields(argc - 1 , argv + 1, repo);
      	return 0;
      }
    -@@ builtin/repo.c: int cmd_repo(int argc,
    ++static int repo_info(int argc, const char **argv, const char *prefix UNUSED,
    ++		     struct repository *repo)
    ++{
    ++	return print_fields(argc - 1, argv + 1, repo);
    ++}
    ++
    + int cmd_repo(int argc, const char **argv, const char *prefix,
    + 	     struct repository *repo)
      {
    - 	parse_opt_subcommand_fn *fn = NULL;
    - 	const char *const repo_usage[] = {
    --		"git repo info",
    -+		"git repo info [<key>...]",
    - 		NULL
    - 	};
    - 	struct option options[] = {
      ## t/meson.build ##
     @@ t/meson.build: integration_tests = [
    @@ t/t1900-repo.sh (new)
     +	test_expect_success "$label" '
     +		test_when_finished "rm -rf repo" &&
     +		eval "$init_command" &&
    -+		echo "$expected_value" | lf_to_nul >expected &&
    ++		echo "$expected_value" >expected &&
     +		git -C repo repo info "$key" >output &&
    -+		tail -n 1 output >actual &&
    ++		cut -d "=" -f 2 <output >actual &&
     +		test_cmp expected actual
     +	'
     +}
    @@ t/t1900-repo.sh (new)
     +	git init --ref-format=reftable repo' 'references.format' 'reftable'
     +
     +test_expect_success "only one value is returned if the same key is requested twice" '
    -+	echo "references.format" > expected &&
    -+	git rev-parse --show-ref-format > ref-format &&
    -+	lf_to_nul <ref-format >>expected &&
    -+	git repo info references.format references.format > actual &&
    -+	test_cmp expected actual
    ++	test_when_finished "rm -f expected_key expected_value actual_key actual_value output" &&
    ++	echo "references.format" >expected_key &&
    ++	git rev-parse --show-ref-format >expected_value &&
    ++	git repo info references.format references.format >output &&
    ++	cut -d "=" -f 1 <output >actual_key &&
    ++	cut -d "=" -f 2 <output >actual_value &&
    ++        test_cmp expected_key actual_key &&
    ++        test_cmp expected_value actual_value
     +'
     +
     +test_done
3:  f0a318c3a7 ! 3:  b8001ae87e repo: add field layout.bare
    @@ Commit message
      ## Documentation/git-repo.adoc ##
     @@ Documentation/git-repo.adoc: categories:
      Reference-related data:
    - * `format`: the reference storage format, either `files` or `reftable`.
    + * `format`: the reference storage format
     +`layout`::
     +Information about the how the current repository is represented:
    @@ builtin/repo.c
     +
      #include "builtin.h"
      #include "parse-options.h"
    - #include "strbuf.h"
      #include "refs.h"
     +#include "environment.h"
    - typedef void add_field_fn(struct strbuf *buf, struct repository *repo);
    + typedef const char *get_value_fn(struct repository *repo);
    -@@ builtin/repo.c: static void add_string(struct strbuf *buf,
    - 	strbuf_addf(buf, "%s\n%s%c", key, value, '\0');
    - }
    +@@ builtin/repo.c: struct field {
    + 	get_value_fn *add_field_callback;
    + };
    -+static void add_bool(struct strbuf *buf,
    -+		     const char *key, const int value)
    ++static const char *get_layout_bare(struct repository *repo UNUSED)
     +{
    -+	const char *output_value = value ? "true" : "false";
    -+	strbuf_addf(buf, "%s\n%s%c", key, output_value, '\0');
    ++	return is_bare_repository() ? "true" : "false";
     +}
     +
    - static void add_references_format(struct strbuf *buf,
    - 				  struct repository *repo)
    + static const char *get_references_format(struct repository *repo)
      {
    -@@ builtin/repo.c: static void add_references_format(struct strbuf *buf,
    - 		   ref_storage_format_to_name(repo->ref_storage_format));
    - }
    + 	return ref_storage_format_to_name(repo->ref_storage_format);
    +@@ builtin/repo.c: static const char *get_references_format(struct repository *repo)
    -+
    -+static void add_layout_bare(struct strbuf *buf, struct repository *repo UNUSED)
    -+{
    -+	add_bool(buf, "layout.bare", is_bare_repository());
    -+}
    -+
    - // repo_info_fields keys should be in lexicographical order
    + /* repo_info_fields keys should be in lexicographical order */
      static const struct field repo_info_fields[] = {
    -+	{"layout.bare", add_layout_bare},
    - 	{"references.format", add_references_format},
    ++	{ "layout.bare", get_layout_bare },
    + 	{ "references.format", get_references_format },
      };
    @@ t/t1900-repo.sh: test_repo_info 'ref format files is retrieved correctly' '
     +	git init --bare repo' 'layout.bare' 'true'
     +
      test_expect_success "only one value is returned if the same key is requested twice" '
    - 	echo "references.format" > expected &&
    - 	git rev-parse --show-ref-format > ref-format &&
    + 	test_when_finished "rm -f expected_key expected_value actual_key actual_value output" &&
    + 	echo "references.format" >expected_key &&
4:  220a3e6ca7 ! 4:  bceba54e8b repo: add field layout.shallow
    @@ Documentation/git-repo.adoc: Reference-related data:
      ## builtin/repo.c ##
     @@
    - #include "strbuf.h"
    + #include "parse-options.h"
      #include "refs.h"
      #include "environment.h"
     +#include "shallow.h"
    - typedef void add_field_fn(struct strbuf *buf, struct repository *repo);
    + typedef const char *get_value_fn(struct repository *repo);
    -@@ builtin/repo.c: static void add_layout_bare(struct strbuf *buf, struct repository *repo UNUSED)
    - 	add_bool(buf, "layout.bare", is_bare_repository());
    +@@ builtin/repo.c: static const char *get_layout_bare(struct repository *repo UNUSED)
    + 	return is_bare_repository() ? "true" : "false";
      }
    -+static void add_layout_shallow(struct strbuf *buf, struct repository *repo)
    ++static const char *get_layout_shallow(struct repository *repo)
     +{
    -+	add_bool(buf, "layout.shallow", is_repository_shallow(repo));
    ++	return is_repository_shallow(repo) ? "true" : "false";
     +}
     +
    - // repo_info_fields keys should be in lexicographical order
    + static const char *get_references_format(struct repository *repo)
    + {
    + 	return ref_storage_format_to_name(repo->ref_storage_format);
    +@@ builtin/repo.c: static const char *get_references_format(struct repository *repo)
    + /* repo_info_fields keys should be in lexicographical order */
      static const struct field repo_info_fields[] = {
    - 	{"layout.bare", add_layout_bare},
    -+	{"layout.shallow", add_layout_shallow},
    - 	{"references.format", add_references_format},
    + 	{ "layout.bare", get_layout_bare },
    ++	{ "layout.shallow", get_layout_shallow },
    + 	{ "references.format", get_references_format },
      };
    @@ t/t1900-repo.sh: test_repo_info 'bare repository = false is retrieved correctly'
     +	' 'layout.shallow' 'true'
     +
      test_expect_success "only one value is returned if the same key is requested twice" '
    - 	echo "references.format" > expected &&
    - 	git rev-parse --show-ref-format > ref-format &&
    + 	test_when_finished "rm -f expected_key expected_value actual_key actual_value output" &&
    + 	echo "references.format" >expected_key &&
     @@ t/t1900-repo.sh: test_expect_success "only one value is returned if the same key is requested twi
    - 	test_cmp expected actual
    +         test_cmp expected_value actual_value
      '
     +test_expect_success 'output is returned correctly when two keys are requested' '
     +	test_when_finished "rm -f expect" &&
    -+	printf "layout.bare\nfalseQlayout.shallow\nfalseQ" >expect &&
    -+	git repo info layout.shallow layout.bare >output &&
    -+	nul_to_q <output >actual &&
    ++	printf "layout.bare=false\nlayout.shallow=false\n" >expect &&
    ++	git repo info layout.shallow layout.bare >actual &&
     +	test_cmp expect actual
     +'
     +
-:  ---------- > 5:  f4a2b0a04e repo: add the --format flag
Lucas Seiki Oshiro (5):
  repo: declare the repo command
  repo: add the field references.format
  repo: add field layout.bare
  repo: add field layout.shallow
  repo: add the --format flag
 .gitignore                  |   1 +
 Documentation/git-repo.adoc |  58 ++++++++++++++
 Documentation/meson.build   |   1 +
 Makefile                    |   1 +
 builtin.h                   |   1 +
 builtin/repo.c              | 154 ++++++++++++++++++++++++++++++++++++
 command-list.txt            |   1 +
 git.c                       |   1 +
 meson.build                 |   1 +
 t/meson.build               |   1 +
 t/t1900-repo.sh             |  86 ++++++++++++++++++++
 11 files changed, 306 insertions(+)
 create mode 100644 Documentation/git-repo.adoc
 create mode 100644 builtin/repo.c
 create mode 100755 t/t1900-repo.sh
-- 
2.39.5 (Apple Git-154)
^ permalink raw reply	[flat|nested] 226+ messages in thread
* [GSoC PATCH v5 1/5] repo: declare the repo command
  2025-07-22  0:28 ` [GSoC PATCH v5 0/5] " Lucas Seiki Oshiro
@ 2025-07-22  0:28   ` Lucas Seiki Oshiro
  2025-07-22  9:03     ` Karthik Nayak
  2025-07-23 20:03     ` Jean-Noël AVILA
  2025-07-22  0:28   ` [GSoC PATCH v5 2/5] repo: add the field references.format Lucas Seiki Oshiro
                     ` (3 subsequent siblings)
  4 siblings, 2 replies; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-07-22  0:28 UTC (permalink / raw)
  To: git
  Cc: oswald.buddenhagen, ps, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler, Lucas Seiki Oshiro
Currently, `git rev-parse` covers a wide range of functionality not
directly related to parsing revisions, as its name suggests. Over time,
many features like parsing datestrings, options, paths, and others
were added to it because there wasn't a more appropriate command
to place them.
Create a new Git command called `repo`. `git repo` will be the main
command for obtaining the information about a repository (such as
metadata and metrics), returning them in a machine readable format
following the syntax "field<LF>value<NUL>".
Also declare a subcommand for `repo` called `info`. `git repo info`
will bring the functionality of retrieving repository-related
information currently returned by `rev-parse`.
Add the required tests, documentation and build changes to enable
usage of this subcommand.
Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Helped-by: Junio C Hamano <gitster@pobox.com>
Helped-by: Justin Tobler <jltobler@gmail.com>
Mentored-by: Karthik Nayak <karthik.188@gmail.com>
Mentored-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
---
 .gitignore                  |  1 +
 Documentation/git-repo.adoc | 38 +++++++++++++++++++++++++++++++++++++
 Documentation/meson.build   |  1 +
 Makefile                    |  1 +
 builtin.h                   |  1 +
 builtin/repo.c              | 26 +++++++++++++++++++++++++
 command-list.txt            |  1 +
 git.c                       |  1 +
 meson.build                 |  1 +
 9 files changed, 71 insertions(+)
 create mode 100644 Documentation/git-repo.adoc
 create mode 100644 builtin/repo.c
diff --git a/.gitignore b/.gitignore
index 04c444404e..1803023427 100644
--- a/.gitignore
+++ b/.gitignore
@@ -139,6 +139,7 @@
 /git-repack
 /git-replace
 /git-replay
+/git-repo
 /git-request-pull
 /git-rerere
 /git-reset
diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc
new file mode 100644
index 0000000000..caee7d8aef
--- /dev/null
+++ b/Documentation/git-repo.adoc
@@ -0,0 +1,38 @@
+git-repo(1)
+===========
+
+NAME
+----
+git-repo - Retrieve information about a repository
+
+SYNOPSIS
+--------
+[synopsis]
+git repo info [<key>...]
+
+DESCRIPTION
+-----------
+This command retrieve repository level information.
+
+THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOR MAY CHANGE.
+
+COMMANDS
+--------
+info [<key>...]::
+	Retrieve metadata-related information about the current repository. Only
+	the requested data will be returned based on their keys (see "INFO KEYS"
+	section below).
+
+INFO KEYS
+---------
+
+The set of data that `git repo` can return is grouped into the following
+categories:
+
+SEE ALSO
+--------
+linkgit:git-rev-parse[1]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/meson.build b/Documentation/meson.build
index 2fe1a1369d..1ebdd57789 100644
--- a/Documentation/meson.build
+++ b/Documentation/meson.build
@@ -116,6 +116,7 @@ manpages = {
   'git-repack.adoc' : 1,
   'git-replace.adoc' : 1,
   'git-replay.adoc' : 1,
+  'git-repo.adoc' : 1,
   'git-request-pull.adoc' : 1,
   'git-rerere.adoc' : 1,
   'git-reset.adoc' : 1,
diff --git a/Makefile b/Makefile
index 5f7dd79dfa..9dce446309 100644
--- a/Makefile
+++ b/Makefile
@@ -1306,6 +1306,7 @@ BUILTIN_OBJS += builtin/remote.o
 BUILTIN_OBJS += builtin/repack.o
 BUILTIN_OBJS += builtin/replace.o
 BUILTIN_OBJS += builtin/replay.o
+BUILTIN_OBJS += builtin/repo.o
 BUILTIN_OBJS += builtin/rerere.o
 BUILTIN_OBJS += builtin/reset.o
 BUILTIN_OBJS += builtin/rev-list.o
diff --git a/builtin.h b/builtin.h
index bff13e3069..e6458e6fb9 100644
--- a/builtin.h
+++ b/builtin.h
@@ -216,6 +216,7 @@ int cmd_remote_ext(int argc, const char **argv, const char *prefix, struct repos
 int cmd_remote_fd(int argc, const char **argv, const char *prefix, struct repository *repo);
 int cmd_repack(int argc, const char **argv, const char *prefix, struct repository *repo);
 int cmd_replay(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_repo(int argc, const char **argv, const char *prefix, struct repository *repo);
 int cmd_rerere(int argc, const char **argv, const char *prefix, struct repository *repo);
 int cmd_reset(int argc, const char **argv, const char *prefix, struct repository *repo);
 int cmd_restore(int argc, const char **argv, const char *prefix, struct repository *repo);
diff --git a/builtin/repo.c b/builtin/repo.c
new file mode 100644
index 0000000000..d4f01e35e2
--- /dev/null
+++ b/builtin/repo.c
@@ -0,0 +1,26 @@
+#include "builtin.h"
+#include "parse-options.h"
+
+static int repo_info(int argc UNUSED, const char **argv UNUSED,
+		     const char *prefix UNUSED, struct repository *repo UNUSED)
+{
+	return 0;
+}
+
+int cmd_repo(int argc, const char **argv, const char *prefix,
+	     struct repository *repo)
+{
+	parse_opt_subcommand_fn *fn = NULL;
+	const char *const repo_usage[] = {
+		"git repo info [<key>...]",
+		NULL
+	};
+	struct option options[] = {
+		OPT_SUBCOMMAND("info", &fn, repo_info),
+		OPT_END()
+	};
+
+	argc = parse_options(argc, argv, prefix, options, repo_usage, 0);
+
+	return fn(argc, argv, prefix, repo);
+}
diff --git a/command-list.txt b/command-list.txt
index b7ade3ab9f..1b0bdee00d 100644
--- a/command-list.txt
+++ b/command-list.txt
@@ -164,6 +164,7 @@ git-remote                              ancillarymanipulators           complete
 git-repack                              ancillarymanipulators           complete
 git-replace                             ancillarymanipulators           complete
 git-replay                              plumbingmanipulators
+git-repo                                plumbinginterrogators
 git-request-pull                        foreignscminterface             complete
 git-rerere                              ancillaryinterrogators
 git-reset                               mainporcelain           history
diff --git a/git.c b/git.c
index 07a5fe39fb..8290d8b8c8 100644
--- a/git.c
+++ b/git.c
@@ -611,6 +611,7 @@ static struct cmd_struct commands[] = {
 	{ "repack", cmd_repack, RUN_SETUP },
 	{ "replace", cmd_replace, RUN_SETUP },
 	{ "replay", cmd_replay, RUN_SETUP },
+	{ "repo", cmd_repo, RUN_SETUP },
 	{ "rerere", cmd_rerere, RUN_SETUP },
 	{ "reset", cmd_reset, RUN_SETUP },
 	{ "restore", cmd_restore, RUN_SETUP | NEED_WORK_TREE },
diff --git a/meson.build b/meson.build
index 9579377f3d..15d3e3701f 100644
--- a/meson.build
+++ b/meson.build
@@ -645,6 +645,7 @@ builtin_sources = [
   'builtin/repack.c',
   'builtin/replace.c',
   'builtin/replay.c',
+  'builtin/repo.c',
   'builtin/rerere.c',
   'builtin/reset.c',
   'builtin/rev-list.c',
-- 
2.39.5 (Apple Git-154)
^ permalink raw reply related	[flat|nested] 226+ messages in thread
* [GSoC PATCH v5 2/5] repo: add the field references.format
  2025-07-22  0:28 ` [GSoC PATCH v5 0/5] " Lucas Seiki Oshiro
  2025-07-22  0:28   ` [GSoC PATCH v5 1/5] repo: declare the repo command Lucas Seiki Oshiro
@ 2025-07-22  0:28   ` Lucas Seiki Oshiro
  2025-07-22  9:16     ` Karthik Nayak
                       ` (2 more replies)
  2025-07-22  0:28   ` [GSoC PATCH v5 3/5] repo: add field layout.bare Lucas Seiki Oshiro
                     ` (2 subsequent siblings)
  4 siblings, 3 replies; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-07-22  0:28 UTC (permalink / raw)
  To: git
  Cc: oswald.buddenhagen, ps, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler, Lucas Seiki Oshiro
This commit is part of the series that introduces the new subcommand
git-repo-info.
The flag `--show-ref-format` from git-rev-parse is used for retrieving
the reference format (i.e. `files` or `reftable`). This way, it is
used for querying repository metadata, fitting in the purpose of
git-repo-info.
Then, add a new field `references.format` to the repo-info subcommand
containing that information.
Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Helped-by: Junio C Hamano <gitster@pobox.com>
Helped-by: Justin Tobler <jltobler@gmail.com>
Mentored-by: Karthik Nayak <karthik.188@gmail.com>
Mentored-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
---
 Documentation/git-repo.adoc |  4 ++
 builtin/repo.c              | 75 ++++++++++++++++++++++++++++++++++++-
 t/meson.build               |  1 +
 t/t1900-repo.sh             | 50 +++++++++++++++++++++++++
 4 files changed, 128 insertions(+), 2 deletions(-)
 create mode 100755 t/t1900-repo.sh
diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc
index caee7d8aef..cf8483ec49 100644
--- a/Documentation/git-repo.adoc
+++ b/Documentation/git-repo.adoc
@@ -29,6 +29,10 @@ INFO KEYS
 The set of data that `git repo` can return is grouped into the following
 categories:
 
+`references`::
+Reference-related data:
+* `format`: the reference storage format
+
 SEE ALSO
 --------
 linkgit:git-rev-parse[1]
diff --git a/builtin/repo.c b/builtin/repo.c
index d4f01e35e2..5beae0f781 100644
--- a/builtin/repo.c
+++ b/builtin/repo.c
@@ -1,12 +1,83 @@
 #include "builtin.h"
 #include "parse-options.h"
+#include "refs.h"
 
-static int repo_info(int argc UNUSED, const char **argv UNUSED,
-		     const char *prefix UNUSED, struct repository *repo UNUSED)
+typedef const char *get_value_fn(struct repository *repo);
+
+struct field {
+	const char *key;
+	get_value_fn *add_field_callback;
+};
+
+static const char *get_references_format(struct repository *repo)
+{
+	return ref_storage_format_to_name(repo->ref_storage_format);
+}
+
+/* repo_info_fields keys should be in lexicographical order */
+static const struct field repo_info_fields[] = {
+	{ "references.format", get_references_format },
+};
+
+static int repo_info_fields_cmp(const void *va, const void *vb)
+{
+	const struct field *a = va;
+	const struct field *b = vb;
+
+	return strcmp(a->key, b->key);
+}
+
+static get_value_fn *get_value_callback(const char *key)
 {
+	const struct field search_key = { key, NULL };
+	const struct field *found = bsearch(&search_key, repo_info_fields,
+					    ARRAY_SIZE(repo_info_fields),
+					    sizeof(struct field),
+					    repo_info_fields_cmp);
+	return found ? found->add_field_callback : NULL;
+}
+
+static int qsort_strcmp(const void *va, const void *vb)
+{
+	const char *a = *(const char **)va;
+	const char *b = *(const char **)vb;
+
+	return strcmp(a, b);
+}
+
+static int print_fields(int argc, const char **argv, struct repository *repo)
+{
+	const char *last = "";
+
+	QSORT(argv, argc, qsort_strcmp);
+
+	for (int i = 0; i < argc; i++) {
+		get_value_fn *callback;
+		const char *key = argv[i];
+		const char *value;
+
+		if (!strcmp(key, last))
+			continue;
+
+		callback = get_value_callback(key);
+
+		if (!callback)
+			return error("key %s not found", key);
+
+		value = callback(repo);
+		printf("%s=%s\n", key, value);
+		last = key;
+	}
+
 	return 0;
 }
 
+static int repo_info(int argc, const char **argv, const char *prefix UNUSED,
+		     struct repository *repo)
+{
+	return print_fields(argc - 1, argv + 1, repo);
+}
+
 int cmd_repo(int argc, const char **argv, const char *prefix,
 	     struct repository *repo)
 {
diff --git a/t/meson.build b/t/meson.build
index 1af289425d..8693e6abc4 100644
--- a/t/meson.build
+++ b/t/meson.build
@@ -245,6 +245,7 @@ integration_tests = [
   't1700-split-index.sh',
   't1701-racy-split-index.sh',
   't1800-hook.sh',
+  't1900-repo.sh',
   't2000-conflict-when-checking-files-out.sh',
   't2002-checkout-cache-u.sh',
   't2003-checkout-cache-mkdir.sh',
diff --git a/t/t1900-repo.sh b/t/t1900-repo.sh
new file mode 100755
index 0000000000..f072c7c67b
--- /dev/null
+++ b/t/t1900-repo.sh
@@ -0,0 +1,50 @@
+#!/bin/sh
+
+test_description='test git repo-info'
+
+. ./test-lib.sh
+
+# Test if a field is correctly returned in the null-terminated format
+#
+# Usage: test_repo_info <label> <init command> <key> <expected value>
+#
+# Arguments:
+#   label: the label of the test
+#   init command: a command that creates a repository called 'repo', configured
+#      accordingly to what is being tested
+#   key: the key of the field that is being tested
+#   expected value: the value that the field should contain
+test_repo_info () {
+	label=$1
+	init_command=$2
+	key=$3
+	expected_value=$4
+
+	test_expect_success "$label" '
+		test_when_finished "rm -rf repo" &&
+		eval "$init_command" &&
+		echo "$expected_value" >expected &&
+		git -C repo repo info "$key" >output &&
+		cut -d "=" -f 2 <output >actual &&
+		test_cmp expected actual
+	'
+}
+
+test_repo_info 'ref format files is retrieved correctly' '
+	git init --ref-format=files repo' 'references.format' 'files'
+
+test_repo_info 'ref format reftable is retrieved correctly' '
+	git init --ref-format=reftable repo' 'references.format' 'reftable'
+
+test_expect_success "only one value is returned if the same key is requested twice" '
+	test_when_finished "rm -f expected_key expected_value actual_key actual_value output" &&
+	echo "references.format" >expected_key &&
+	git rev-parse --show-ref-format >expected_value &&
+	git repo info references.format references.format >output &&
+	cut -d "=" -f 1 <output >actual_key &&
+	cut -d "=" -f 2 <output >actual_value &&
+        test_cmp expected_key actual_key &&
+        test_cmp expected_value actual_value
+'
+
+test_done
-- 
2.39.5 (Apple Git-154)
^ permalink raw reply related	[flat|nested] 226+ messages in thread
* [GSoC PATCH v5 3/5] repo: add field layout.bare
  2025-07-22  0:28 ` [GSoC PATCH v5 0/5] " Lucas Seiki Oshiro
  2025-07-22  0:28   ` [GSoC PATCH v5 1/5] repo: declare the repo command Lucas Seiki Oshiro
  2025-07-22  0:28   ` [GSoC PATCH v5 2/5] repo: add the field references.format Lucas Seiki Oshiro
@ 2025-07-22  0:28   ` Lucas Seiki Oshiro
  2025-07-22  0:28   ` [GSoC PATCH v5 4/5] repo: add field layout.shallow Lucas Seiki Oshiro
  2025-07-22  0:28   ` [GSoC PATCH v5 5/5] repo: add the --format flag Lucas Seiki Oshiro
  4 siblings, 0 replies; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-07-22  0:28 UTC (permalink / raw)
  To: git
  Cc: oswald.buddenhagen, ps, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler, Lucas Seiki Oshiro
This commit is part of the series that introduces the new subcommand
git-repo-info.
The flag --is-bare-repository from git-rev-parse is used for retrieving
whether the current repository is bare. This way, it is used for
querying repository metadata, fitting in the purpose of git-repo-info.
Then, add a new field layout.bare to the git-repo-info subcommand
containing that information.
Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Helped-by: Junio C Hamano <gitster@pobox.com>
Helped-by: Justin Tobler <jltobler@gmail.com>
Mentored-by: Karthik Nayak <karthik.188@gmail.com>
Mentored-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
---
 Documentation/git-repo.adoc | 4 ++++
 builtin/repo.c              | 9 +++++++++
 t/t1900-repo.sh             | 6 ++++++
 3 files changed, 19 insertions(+)
diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc
index cf8483ec49..7124487323 100644
--- a/Documentation/git-repo.adoc
+++ b/Documentation/git-repo.adoc
@@ -33,6 +33,10 @@ categories:
 Reference-related data:
 * `format`: the reference storage format
 
+`layout`::
+Information about the how the current repository is represented:
+* `bare`: `true` if this is a bare repository, otherwise `false`.
+
 SEE ALSO
 --------
 linkgit:git-rev-parse[1]
diff --git a/builtin/repo.c b/builtin/repo.c
index 5beae0f781..b85bd10889 100644
--- a/builtin/repo.c
+++ b/builtin/repo.c
@@ -1,6 +1,9 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
 #include "builtin.h"
 #include "parse-options.h"
 #include "refs.h"
+#include "environment.h"
 
 typedef const char *get_value_fn(struct repository *repo);
 
@@ -9,6 +12,11 @@ struct field {
 	get_value_fn *add_field_callback;
 };
 
+static const char *get_layout_bare(struct repository *repo UNUSED)
+{
+	return is_bare_repository() ? "true" : "false";
+}
+
 static const char *get_references_format(struct repository *repo)
 {
 	return ref_storage_format_to_name(repo->ref_storage_format);
@@ -16,6 +24,7 @@ static const char *get_references_format(struct repository *repo)
 
 /* repo_info_fields keys should be in lexicographical order */
 static const struct field repo_info_fields[] = {
+	{ "layout.bare", get_layout_bare },
 	{ "references.format", get_references_format },
 };
 
diff --git a/t/t1900-repo.sh b/t/t1900-repo.sh
index f072c7c67b..03609ffff9 100755
--- a/t/t1900-repo.sh
+++ b/t/t1900-repo.sh
@@ -36,6 +36,12 @@ test_repo_info 'ref format files is retrieved correctly' '
 test_repo_info 'ref format reftable is retrieved correctly' '
 	git init --ref-format=reftable repo' 'references.format' 'reftable'
 
+test_repo_info 'bare repository = false is retrieved correctly' '
+	git init repo' 'layout.bare' 'false'
+
+test_repo_info 'bare repository = true is retrieved correctly' '
+	git init --bare repo' 'layout.bare' 'true'
+
 test_expect_success "only one value is returned if the same key is requested twice" '
 	test_when_finished "rm -f expected_key expected_value actual_key actual_value output" &&
 	echo "references.format" >expected_key &&
-- 
2.39.5 (Apple Git-154)
^ permalink raw reply related	[flat|nested] 226+ messages in thread
* [GSoC PATCH v5 4/5] repo: add field layout.shallow
  2025-07-22  0:28 ` [GSoC PATCH v5 0/5] " Lucas Seiki Oshiro
                     ` (2 preceding siblings ...)
  2025-07-22  0:28   ` [GSoC PATCH v5 3/5] repo: add field layout.bare Lucas Seiki Oshiro
@ 2025-07-22  0:28   ` Lucas Seiki Oshiro
  2025-07-22  0:28   ` [GSoC PATCH v5 5/5] repo: add the --format flag Lucas Seiki Oshiro
  4 siblings, 0 replies; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-07-22  0:28 UTC (permalink / raw)
  To: git
  Cc: oswald.buddenhagen, ps, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler, Lucas Seiki Oshiro
This commit is part of the series that introduces the new subcommand
git-repo-info.
The flag `--is-shallow-repository` from git-rev-parse is used for
retrieving whether the repository is shallow. This way, it is used for
querying repository metadata, fitting in the purpose of git-repo-info.
Then, add a new field `layout.shallow` to the git-repo-info subcommand
containing that information.
Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Helped-by: Junio C Hamano <gitster@pobox.com>
Helped-by: Justin Tobler <jltobler@gmail.com>
Mentored-by: Karthik Nayak <karthik.188@gmail.com>
Mentored-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
---
 Documentation/git-repo.adoc |  1 +
 builtin/repo.c              |  7 +++++++
 t/t1900-repo.sh             | 21 +++++++++++++++++++++
 3 files changed, 29 insertions(+)
diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc
index 7124487323..375b956d3f 100644
--- a/Documentation/git-repo.adoc
+++ b/Documentation/git-repo.adoc
@@ -36,6 +36,7 @@ Reference-related data:
 `layout`::
 Information about the how the current repository is represented:
 * `bare`: `true` if this is a bare repository, otherwise `false`.
+* `shallow`: `true` if this is a shallow repository, otherwise `false`.
 
 SEE ALSO
 --------
diff --git a/builtin/repo.c b/builtin/repo.c
index b85bd10889..490fa9dd49 100644
--- a/builtin/repo.c
+++ b/builtin/repo.c
@@ -4,6 +4,7 @@
 #include "parse-options.h"
 #include "refs.h"
 #include "environment.h"
+#include "shallow.h"
 
 typedef const char *get_value_fn(struct repository *repo);
 
@@ -17,6 +18,11 @@ static const char *get_layout_bare(struct repository *repo UNUSED)
 	return is_bare_repository() ? "true" : "false";
 }
 
+static const char *get_layout_shallow(struct repository *repo)
+{
+	return is_repository_shallow(repo) ? "true" : "false";
+}
+
 static const char *get_references_format(struct repository *repo)
 {
 	return ref_storage_format_to_name(repo->ref_storage_format);
@@ -25,6 +31,7 @@ static const char *get_references_format(struct repository *repo)
 /* repo_info_fields keys should be in lexicographical order */
 static const struct field repo_info_fields[] = {
 	{ "layout.bare", get_layout_bare },
+	{ "layout.shallow", get_layout_shallow },
 	{ "references.format", get_references_format },
 };
 
diff --git a/t/t1900-repo.sh b/t/t1900-repo.sh
index 03609ffff9..c46ace1fd3 100755
--- a/t/t1900-repo.sh
+++ b/t/t1900-repo.sh
@@ -42,6 +42,20 @@ test_repo_info 'bare repository = false is retrieved correctly' '
 test_repo_info 'bare repository = true is retrieved correctly' '
 	git init --bare repo' 'layout.bare' 'true'
 
+test_repo_info 'shallow repository = false is retrieved correctly' '
+	git init repo' 'layout.shallow' 'false'
+
+test_repo_info 'shallow repository = true is retrieved correctly' '
+	git init remote &&
+	cd remote &&
+	echo x >x &&
+	git add x &&
+	git commit -m x &&
+	cd .. &&
+	git clone --depth 1 "file://$PWD/remote" repo &&
+	rm -rf remote
+	' 'layout.shallow' 'true'
+
 test_expect_success "only one value is returned if the same key is requested twice" '
 	test_when_finished "rm -f expected_key expected_value actual_key actual_value output" &&
 	echo "references.format" >expected_key &&
@@ -53,4 +67,11 @@ test_expect_success "only one value is returned if the same key is requested twi
         test_cmp expected_value actual_value
 '
 
+test_expect_success 'output is returned correctly when two keys are requested' '
+	test_when_finished "rm -f expect" &&
+	printf "layout.bare=false\nlayout.shallow=false\n" >expect &&
+	git repo info layout.shallow layout.bare >actual &&
+	test_cmp expect actual
+'
+
 test_done
-- 
2.39.5 (Apple Git-154)
^ permalink raw reply related	[flat|nested] 226+ messages in thread
* [GSoC PATCH v5 5/5] repo: add the --format flag
  2025-07-22  0:28 ` [GSoC PATCH v5 0/5] " Lucas Seiki Oshiro
                     ` (3 preceding siblings ...)
  2025-07-22  0:28   ` [GSoC PATCH v5 4/5] repo: add field layout.shallow Lucas Seiki Oshiro
@ 2025-07-22  0:28   ` Lucas Seiki Oshiro
  2025-07-22  9:26     ` Karthik Nayak
  2025-07-24  6:22     ` Patrick Steinhardt
  4 siblings, 2 replies; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-07-22  0:28 UTC (permalink / raw)
  To: git
  Cc: oswald.buddenhagen, ps, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler, Lucas Seiki Oshiro
Add the --format flag to git-repo-info. By using this flag, the users
can choose the format for obtaining the data they requested.
Given that this command can be used for generating input for another
applications and for being read by end users, it requires at least two
formats: one for being read by humans and other for being read by
machines. Some other Git commands also have two output formats, notably
git-config which was the inspiration for the two formats that were
chosen here:
- keyvalue, where the retrieved data is printed one per line, using =
  for delimiting the key and the value. This is the default format,
  targeted for end users.
- null, where the retrieved data is separated by null characters, using
  the newline character for delimiting the key and the value. This
  format is targeted for being read by machines.
Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Helped-by: Junio C Hamano <gitster@pobox.com>
Helped-by: Justin Tobler <jltobler@gmail.com>
Mentored-by: Karthik Nayak <karthik.188@gmail.com>
Mentored-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
---
 Documentation/git-repo.adoc | 13 +++++++++-
 builtin/repo.c              | 49 ++++++++++++++++++++++++++++++++++---
 t/t1900-repo.sh             | 13 ++++++++--
 3 files changed, 68 insertions(+), 7 deletions(-)
diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc
index 375b956d3f..5bdc3831a7 100644
--- a/Documentation/git-repo.adoc
+++ b/Documentation/git-repo.adoc
@@ -18,10 +18,21 @@ THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOR MAY CHANGE.
 
 COMMANDS
 --------
-info [<key>...]::
+info [--format=<format>] [<key>...]::
 	Retrieve metadata-related information about the current repository. Only
 	the requested data will be returned based on their keys (see "INFO KEYS"
 	section below).
++
+The output format can be chosen through the flag `--format`. Two formats are
+supported:
++
+* `keyvalue`: output key-value pairs one per line using the `=` character as
+the delimiter between the key and the value. This is the default.
+
+* `null`: similar to `keyvalue`, but using a newline character as the delimiter
+between the key and the value and using a null character after each value.
+This format is better suited for being parsed by another applications than
+`keyvalue`.
 
 INFO KEYS
 ---------
diff --git a/builtin/repo.c b/builtin/repo.c
index 490fa9dd49..10d02bb3ea 100644
--- a/builtin/repo.c
+++ b/builtin/repo.c
@@ -8,6 +8,11 @@
 
 typedef const char *get_value_fn(struct repository *repo);
 
+enum output_format {
+	FORMAT_KEYVALUE,
+	FORMAT_NULL_TERMINATED,
+};
+
 struct field {
 	const char *key;
 	get_value_fn *add_field_callback;
@@ -61,9 +66,24 @@ static int qsort_strcmp(const void *va, const void *vb)
 	return strcmp(a, b);
 }
 
-static int print_fields(int argc, const char **argv, struct repository *repo)
+static int print_fields(int argc, const char **argv,
+			struct repository *repo,
+			enum output_format format)
 {
 	const char *last = "";
+	char kv_sep;
+	char field_sep;
+
+	switch (format) {
+	case FORMAT_KEYVALUE:
+		kv_sep = '=';
+		field_sep = '\n';
+		break;
+	case FORMAT_NULL_TERMINATED:
+		kv_sep = '\n';
+		field_sep = '\0';
+		break;
+	}
 
 	QSORT(argv, argc, qsort_strcmp);
 
@@ -81,17 +101,38 @@ static int print_fields(int argc, const char **argv, struct repository *repo)
 			return error("key %s not found", key);
 
 		value = callback(repo);
-		printf("%s=%s\n", key, value);
+		printf("%s%c%s%c", key, kv_sep, value, field_sep);
 		last = key;
 	}
 
 	return 0;
 }
 
-static int repo_info(int argc, const char **argv, const char *prefix UNUSED,
+static int repo_info(int argc, const char **argv, const char *prefix,
 		     struct repository *repo)
 {
-	return print_fields(argc - 1, argv + 1, repo);
+	const char *format_str = "keyvalue";
+	enum output_format format;
+	const char *const repo_info_usage[] = {
+		"git repo info [<key>...]",
+		NULL
+	};
+	struct option options[] = {
+		OPT_STRING(0, "format", &format_str, N_("format"),
+			   N_("output format")),
+		OPT_END()
+	};
+
+	argc = parse_options(argc, argv, prefix, options, repo_info_usage, 0);
+
+	if (!strcmp(format_str, "keyvalue"))
+		format = FORMAT_KEYVALUE;
+	else if (!strcmp(format_str, "null"))
+		format = FORMAT_NULL_TERMINATED;
+	else
+		die("invalid format %s", format_str);
+
+	return print_fields(argc, argv, repo, format);
 }
 
 int cmd_repo(int argc, const char **argv, const char *prefix,
diff --git a/t/t1900-repo.sh b/t/t1900-repo.sh
index c46ace1fd3..fdd3491429 100755
--- a/t/t1900-repo.sh
+++ b/t/t1900-repo.sh
@@ -20,11 +20,20 @@ test_repo_info () {
 	key=$3
 	expected_value=$4
 
-	test_expect_success "$label" '
+	test_expect_success "null-terminated: $label" '
+		test_when_finished "rm -rf repo" &&
+		eval "$init_command" &&
+		echo "$expected_value" | lf_to_nul >expected &&
+		git -C repo repo info --format=null "$key" >output &&
+		tail -n 1 output >actual &&
+		test_cmp expected actual
+	'
+
+	test_expect_success "key-value: $label" '
 		test_when_finished "rm -rf repo" &&
 		eval "$init_command" &&
 		echo "$expected_value" >expected &&
-		git -C repo repo info "$key" >output &&
+		git -C repo repo info --format=keyvalue "$key" >output &&
 		cut -d "=" -f 2 <output >actual &&
 		test_cmp expected actual
 	'
-- 
2.39.5 (Apple Git-154)
^ permalink raw reply related	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v5 1/5] repo: declare the repo command
  2025-07-22  0:28   ` [GSoC PATCH v5 1/5] repo: declare the repo command Lucas Seiki Oshiro
@ 2025-07-22  9:03     ` Karthik Nayak
  2025-07-22 15:21       ` Junio C Hamano
  2025-07-23 15:49       ` Lucas Seiki Oshiro
  2025-07-23 20:03     ` Jean-Noël AVILA
  1 sibling, 2 replies; 226+ messages in thread
From: Karthik Nayak @ 2025-07-22  9:03 UTC (permalink / raw)
  To: Lucas Seiki Oshiro, git
  Cc: oswald.buddenhagen, ps, ben.knoble, gitster, phillip.wood,
	jltobler
[-- Attachment #1: Type: text/plain, Size: 2615 bytes --]
Lucas Seiki Oshiro <lucasseikioshiro@gmail.com> writes:
> Currently, `git rev-parse` covers a wide range of functionality not
> directly related to parsing revisions, as its name suggests. Over time,
> many features like parsing datestrings, options, paths, and others
> were added to it because there wasn't a more appropriate command
> to place them.
>
> Create a new Git command called `repo`. `git repo` will be the main
> command for obtaining the information about a repository (such as
> metadata and metrics), returning them in a machine readable format
> following the syntax "field<LF>value<NUL>".
>
Doesn't the latter sentence only apply to 'git repo info'? Other
sub-commands may not follow the field<LF>value<NUL> syntax, no?
> Also declare a subcommand for `repo` called `info`. `git repo info`
> will bring the functionality of retrieving repository-related
> information currently returned by `rev-parse`.
>
> Add the required tests, documentation and build changes to enable
> usage of this subcommand.
>
> Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
> Helped-by: Junio C Hamano <gitster@pobox.com>
> Helped-by: Justin Tobler <jltobler@gmail.com>
> Mentored-by: Karthik Nayak <karthik.188@gmail.com>
> Mentored-by: Patrick Steinhardt <ps@pks.im>
> Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
> ---
>  .gitignore                  |  1 +
>  Documentation/git-repo.adoc | 38 +++++++++++++++++++++++++++++++++++++
>  Documentation/meson.build   |  1 +
>  Makefile                    |  1 +
>  builtin.h                   |  1 +
>  builtin/repo.c              | 26 +++++++++++++++++++++++++
>  command-list.txt            |  1 +
>  git.c                       |  1 +
>  meson.build                 |  1 +
>  9 files changed, 71 insertions(+)
>  create mode 100644 Documentation/git-repo.adoc
>  create mode 100644 builtin/repo.c
>
> diff --git a/.gitignore b/.gitignore
> index 04c444404e..1803023427 100644
> --- a/.gitignore
> +++ b/.gitignore
> @@ -139,6 +139,7 @@
>  /git-repack
>  /git-replace
>  /git-replay
> +/git-repo
>  /git-request-pull
>  /git-rerere
>  /git-reset
> diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc
> new file mode 100644
> index 0000000000..caee7d8aef
> --- /dev/null
> +++ b/Documentation/git-repo.adoc
> @@ -0,0 +1,38 @@
> +git-repo(1)
> +===========
> +
> +NAME
> +----
> +git-repo - Retrieve information about a repository
> +
> +SYNOPSIS
> +--------
> +[synopsis]
> +git repo info [<key>...]
> +
> +DESCRIPTION
> +-----------
> +This command retrieve repository level information.
> +
s/retrieve/retrieves
[snip]
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 690 bytes --]
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v5 2/5] repo: add the field references.format
  2025-07-22  0:28   ` [GSoC PATCH v5 2/5] repo: add the field references.format Lucas Seiki Oshiro
@ 2025-07-22  9:16     ` Karthik Nayak
  2025-07-22 19:25     ` Justin Tobler
  2025-07-24  6:22     ` Patrick Steinhardt
  2 siblings, 0 replies; 226+ messages in thread
From: Karthik Nayak @ 2025-07-22  9:16 UTC (permalink / raw)
  To: Lucas Seiki Oshiro, git
  Cc: oswald.buddenhagen, ps, ben.knoble, gitster, phillip.wood,
	jltobler
[-- Attachment #1: Type: text/plain, Size: 4119 bytes --]
Lucas Seiki Oshiro <lucasseikioshiro@gmail.com> writes:
> This commit is part of the series that introduces the new subcommand
> git-repo-info.
>
> The flag `--show-ref-format` from git-rev-parse is used for retrieving
> the reference format (i.e. `files` or `reftable`). This way, it is
> used for querying repository metadata, fitting in the purpose of
> git-repo-info.
>
> Then, add a new field `references.format` to the repo-info subcommand
> containing that information.
>
Nit: I don't think we need the 'Then, ' here, perhaps 'Add ...'.
> Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
> Helped-by: Junio C Hamano <gitster@pobox.com>
> Helped-by: Justin Tobler <jltobler@gmail.com>
> Mentored-by: Karthik Nayak <karthik.188@gmail.com>
> Mentored-by: Patrick Steinhardt <ps@pks.im>
> Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
> ---
>  Documentation/git-repo.adoc |  4 ++
>  builtin/repo.c              | 75 ++++++++++++++++++++++++++++++++++++-
>  t/meson.build               |  1 +
>  t/t1900-repo.sh             | 50 +++++++++++++++++++++++++
>  4 files changed, 128 insertions(+), 2 deletions(-)
>  create mode 100755 t/t1900-repo.sh
>
> diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc
> index caee7d8aef..cf8483ec49 100644
> --- a/Documentation/git-repo.adoc
> +++ b/Documentation/git-repo.adoc
> @@ -29,6 +29,10 @@ INFO KEYS
>  The set of data that `git repo` can return is grouped into the following
>  categories:
>
> +`references`::
> +Reference-related data:
> +* `format`: the reference storage format
> +
>  SEE ALSO
>  --------
>  linkgit:git-rev-parse[1]
> diff --git a/builtin/repo.c b/builtin/repo.c
> index d4f01e35e2..5beae0f781 100644
> --- a/builtin/repo.c
> +++ b/builtin/repo.c
> @@ -1,12 +1,83 @@
>  #include "builtin.h"
>  #include "parse-options.h"
> +#include "refs.h"
>
> -static int repo_info(int argc UNUSED, const char **argv UNUSED,
> -		     const char *prefix UNUSED, struct repository *repo UNUSED)
> +typedef const char *get_value_fn(struct repository *repo);
> +
> +struct field {
> +	const char *key;
> +	get_value_fn *add_field_callback;
> +};
> +
Shouldn't 'add_field_callback' be renamed, now that we don't add a field
but rather return a value?
> +static const char *get_references_format(struct repository *repo)
> +{
> +	return ref_storage_format_to_name(repo->ref_storage_format);
> +}
> +
> +/* repo_info_fields keys should be in lexicographical order */
> +static const struct field repo_info_fields[] = {
> +	{ "references.format", get_references_format },
> +};
> +
> +static int repo_info_fields_cmp(const void *va, const void *vb)
> +{
> +	const struct field *a = va;
> +	const struct field *b = vb;
> +
> +	return strcmp(a->key, b->key);
> +}
> +
> +static get_value_fn *get_value_callback(const char *key)
>  {
Nit: A callback generally is a function provided by when a 'fn A' calls
'fn B', providing a 'fn C' which 'fn A' provides.
Here perhaps we can simply rename this to 'get_value_fn_for_key' or
something?
> +	const struct field search_key = { key, NULL };
> +	const struct field *found = bsearch(&search_key, repo_info_fields,
> +					    ARRAY_SIZE(repo_info_fields),
> +					    sizeof(struct field),
> +					    repo_info_fields_cmp);
> +	return found ? found->add_field_callback : NULL;
> +}
> +
> +static int qsort_strcmp(const void *va, const void *vb)
> +{
> +	const char *a = *(const char **)va;
> +	const char *b = *(const char **)vb;
> +
> +	return strcmp(a, b);
> +}
> +
> +static int print_fields(int argc, const char **argv, struct repository *repo)
> +{
> +	const char *last = "";
> +
> +	QSORT(argv, argc, qsort_strcmp);
> +
> +	for (int i = 0; i < argc; i++) {
> +		get_value_fn *callback;
> +		const char *key = argv[i];
> +		const char *value;
> +
> +		if (!strcmp(key, last))
> +			continue;
> +
> +		callback = get_value_callback(key);
> +
> +		if (!callback)
> +			return error("key %s not found", key);
> +
> +		value = callback(repo);
> +		printf("%s=%s\n", key, value);
I like this a lot, since we can simply modify this in the future for
different formats. Nice!
[snip]
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 690 bytes --]
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v5 5/5] repo: add the --format flag
  2025-07-22  0:28   ` [GSoC PATCH v5 5/5] repo: add the --format flag Lucas Seiki Oshiro
@ 2025-07-22  9:26     ` Karthik Nayak
  2025-07-24  6:22     ` Patrick Steinhardt
  1 sibling, 0 replies; 226+ messages in thread
From: Karthik Nayak @ 2025-07-22  9:26 UTC (permalink / raw)
  To: Lucas Seiki Oshiro, git
  Cc: oswald.buddenhagen, ps, ben.knoble, gitster, phillip.wood,
	jltobler
[-- Attachment #1: Type: text/plain, Size: 3336 bytes --]
Lucas Seiki Oshiro <lucasseikioshiro@gmail.com> writes:
> Add the --format flag to git-repo-info. By using this flag, the users
> can choose the format for obtaining the data they requested.
>
> Given that this command can be used for generating input for another
Nit: s/another/other
> applications and for being read by end users, it requires at least two
> formats: one for being read by humans and other for being read by
> machines. Some other Git commands also have two output formats, notably
> git-config which was the inspiration for the two formats that were
> chosen here:
>
> - keyvalue, where the retrieved data is printed one per line, using =
>   for delimiting the key and the value. This is the default format,
>   targeted for end users.
> - null, where the retrieved data is separated by null characters, using
>   the newline character for delimiting the key and the value. This
>   format is targeted for being read by machines.
>
> Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
> Helped-by: Junio C Hamano <gitster@pobox.com>
> Helped-by: Justin Tobler <jltobler@gmail.com>
> Mentored-by: Karthik Nayak <karthik.188@gmail.com>
> Mentored-by: Patrick Steinhardt <ps@pks.im>
> Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
> ---
>  Documentation/git-repo.adoc | 13 +++++++++-
>  builtin/repo.c              | 49 ++++++++++++++++++++++++++++++++++---
>  t/t1900-repo.sh             | 13 ++++++++--
>  3 files changed, 68 insertions(+), 7 deletions(-)
>
> diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc
> index 375b956d3f..5bdc3831a7 100644
> --- a/Documentation/git-repo.adoc
> +++ b/Documentation/git-repo.adoc
> @@ -18,10 +18,21 @@ THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOR MAY CHANGE.
>
>  COMMANDS
>  --------
> -info [<key>...]::
> +info [--format=<format>] [<key>...]::
>  	Retrieve metadata-related information about the current repository. Only
>  	the requested data will be returned based on their keys (see "INFO KEYS"
>  	section below).
> ++
> +The output format can be chosen through the flag `--format`. Two formats are
> +supported:
> ++
It's hard to know where the documentation for '--format' starts from,
perhaps we can take a note from how 'Documentation/git-refs.adoc' does
this?
[snip]
>  int cmd_repo(int argc, const char **argv, const char *prefix,
> diff --git a/t/t1900-repo.sh b/t/t1900-repo.sh
> index c46ace1fd3..fdd3491429 100755
> --- a/t/t1900-repo.sh
> +++ b/t/t1900-repo.sh
> @@ -20,11 +20,20 @@ test_repo_info () {
>  	key=$3
>  	expected_value=$4
>
> -	test_expect_success "$label" '
> +	test_expect_success "null-terminated: $label" '
> +		test_when_finished "rm -rf repo" &&
> +		eval "$init_command" &&
> +		echo "$expected_value" | lf_to_nul >expected &&
> +		git -C repo repo info --format=null "$key" >output &&
> +		tail -n 1 output >actual &&
> +		test_cmp expected actual
> +	'
> +
> +	test_expect_success "key-value: $label" '
>  		test_when_finished "rm -rf repo" &&
>  		eval "$init_command" &&
>  		echo "$expected_value" >expected &&
> -		git -C repo repo info "$key" >output &&
> +		git -C repo repo info --format=keyvalue "$key" >output &&
>  		cut -d "=" -f 2 <output >actual &&
>  		test_cmp expected actual
>  	'
Shouldn't we also test for invalid format? Also perhaps invalid key in
the first commit too.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 690 bytes --]
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v5 1/5] repo: declare the repo command
  2025-07-22  9:03     ` Karthik Nayak
@ 2025-07-22 15:21       ` Junio C Hamano
  2025-07-23 16:28         ` Lucas Seiki Oshiro
  2025-07-24  6:22         ` Patrick Steinhardt
  2025-07-23 15:49       ` Lucas Seiki Oshiro
  1 sibling, 2 replies; 226+ messages in thread
From: Junio C Hamano @ 2025-07-22 15:21 UTC (permalink / raw)
  To: Karthik Nayak
  Cc: Lucas Seiki Oshiro, git, oswald.buddenhagen, ps, ben.knoble,
	phillip.wood, jltobler
Karthik Nayak <karthik.188@gmail.com> writes:
> Lucas Seiki Oshiro <lucasseikioshiro@gmail.com> writes:
>
>> Currently, `git rev-parse` covers a wide range of functionality not
>> directly related to parsing revisions, as its name suggests. Over time,
>> many features like parsing datestrings, options, paths, and others
>> were added to it because there wasn't a more appropriate command
>> to place them.
>>
>> Create a new Git command called `repo`. `git repo` will be the main
>> command for obtaining the information about a repository (such as
>> metadata and metrics), returning them in a machine readable format
>> following the syntax "field<LF>value<NUL>".
>>
>
> Doesn't the latter sentence only apply to 'git repo info'? Other
> sub-commands may not follow the field<LF>value<NUL> syntax, no?
True.
I also wonder who it helps to use <LF> as a field separator.  Once
we require consumers to properly handle <NUL>, it does not make it
easier to write such a consumer script if the format uses <LF>
there, does it?  Besides, wouldn't it possible that field may have
to contain any end-user specified key, including <LF>?  If so, we'd
need to have some quoting/unquoting mechanism in the syntax anyway,
so the behefit of using <NUL> to simplify the parser would already
be lost.
Thanks.
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v5 2/5] repo: add the field references.format
  2025-07-22  0:28   ` [GSoC PATCH v5 2/5] repo: add the field references.format Lucas Seiki Oshiro
  2025-07-22  9:16     ` Karthik Nayak
@ 2025-07-22 19:25     ` Justin Tobler
  2025-07-23 14:53       ` Phillip Wood
  2025-07-23 18:26       ` Lucas Seiki Oshiro
  2025-07-24  6:22     ` Patrick Steinhardt
  2 siblings, 2 replies; 226+ messages in thread
From: Justin Tobler @ 2025-07-22 19:25 UTC (permalink / raw)
  To: Lucas Seiki Oshiro
  Cc: git, oswald.buddenhagen, ps, karthik.188, ben.knoble, gitster,
	phillip.wood
On 25/07/21 09:28PM, Lucas Seiki Oshiro wrote:
> This commit is part of the series that introduces the new subcommand
> git-repo-info.
> 
> The flag `--show-ref-format` from git-rev-parse is used for retrieving
> the reference format (i.e. `files` or `reftable`). This way, it is
> used for querying repository metadata, fitting in the purpose of
> git-repo-info.
> 
> Then, add a new field `references.format` to the repo-info subcommand
> containing that information.
> 
> Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
> Helped-by: Junio C Hamano <gitster@pobox.com>
> Helped-by: Justin Tobler <jltobler@gmail.com>
> Mentored-by: Karthik Nayak <karthik.188@gmail.com>
> Mentored-by: Patrick Steinhardt <ps@pks.im>
> Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
> ---
>  Documentation/git-repo.adoc |  4 ++
>  builtin/repo.c              | 75 ++++++++++++++++++++++++++++++++++++-
>  t/meson.build               |  1 +
>  t/t1900-repo.sh             | 50 +++++++++++++++++++++++++
>  4 files changed, 128 insertions(+), 2 deletions(-)
>  create mode 100755 t/t1900-repo.sh
> 
> diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc
> index caee7d8aef..cf8483ec49 100644
> --- a/Documentation/git-repo.adoc
> +++ b/Documentation/git-repo.adoc
> @@ -29,6 +29,10 @@ INFO KEYS
>  The set of data that `git repo` can return is grouped into the following
>  categories:
>  
> +`references`::
> +Reference-related data:
> +* `format`: the reference storage format
> +
>  SEE ALSO
>  --------
>  linkgit:git-rev-parse[1]
> diff --git a/builtin/repo.c b/builtin/repo.c
> index d4f01e35e2..5beae0f781 100644
> --- a/builtin/repo.c
> +++ b/builtin/repo.c
> @@ -1,12 +1,83 @@
>  #include "builtin.h"
>  #include "parse-options.h"
> +#include "refs.h"
>  
> -static int repo_info(int argc UNUSED, const char **argv UNUSED,
> -		     const char *prefix UNUSED, struct repository *repo UNUSED)
> +typedef const char *get_value_fn(struct repository *repo);
> +
> +struct field {
> +	const char *key;
> +	get_value_fn *add_field_callback;
> +};
> +
> +static const char *get_references_format(struct repository *repo)
> +{
> +	return ref_storage_format_to_name(repo->ref_storage_format);
> +}
> +
> +/* repo_info_fields keys should be in lexicographical order */
> +static const struct field repo_info_fields[] = {
> +	{ "references.format", get_references_format },
> +};
Ok, so each key has a corresponding callback that is used to get its
value. This works fine when we have one operation/callback per key, but
I could see this being a bit inflexible in cases where performing a
single operation could be expected to generate multiple keys worth of
information at a time.
I certainly see this being the case with git-repo-stats where, for
example, interating over references will produce multiple keyvalues
indicating the number of branches, tags, remotes, etc. But, maybe for
git-repo-info this will not be as much of a concern?
> +
> +static int repo_info_fields_cmp(const void *va, const void *vb)
> +{
> +	const struct field *a = va;
> +	const struct field *b = vb;
> +
> +	return strcmp(a->key, b->key);
> +}
> +
> +static get_value_fn *get_value_callback(const char *key)
>  {
> +	const struct field search_key = { key, NULL };
> +	const struct field *found = bsearch(&search_key, repo_info_fields,
> +					    ARRAY_SIZE(repo_info_fields),
> +					    sizeof(struct field),
> +					    repo_info_fields_cmp);
> +	return found ? found->add_field_callback : NULL;
> +}
> +
> +static int qsort_strcmp(const void *va, const void *vb)
> +{
> +	const char *a = *(const char **)va;
> +	const char *b = *(const char **)vb;
> +
> +	return strcmp(a, b);
> +}
> +
> +static int print_fields(int argc, const char **argv, struct repository *repo)
> +{
> +	const char *last = "";
> +
> +	QSORT(argv, argc, qsort_strcmp);
> +
> +	for (int i = 0; i < argc; i++) {
> +		get_value_fn *callback;
> +		const char *key = argv[i];
> +		const char *value;
> +
> +		if (!strcmp(key, last))
> +			continue;
> +
> +		callback = get_value_callback(key);
> +
> +		if (!callback)
> +			return error("key %s not found", key);
> +
> +		value = callback(repo);
> +		printf("%s=%s\n", key, value);
> +		last = key;
> +	}
If the user does not input any keys, we simply do nothing. I do wonder
if this is really the best default behavior. Maybe instead we should
error out? Or maybe treat it as though all keys were requested?
-Justin
> +
>  	return 0;
>  }
>  
> +static int repo_info(int argc, const char **argv, const char *prefix UNUSED,
> +		     struct repository *repo)
> +{
> +	return print_fields(argc - 1, argv + 1, repo);
> +}
> +
>  int cmd_repo(int argc, const char **argv, const char *prefix,
>  	     struct repository *repo)
>  {
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v5 2/5] repo: add the field references.format
  2025-07-22 19:25     ` Justin Tobler
@ 2025-07-23 14:53       ` Phillip Wood
  2025-07-23 17:44         ` Lucas Seiki Oshiro
  2025-07-23 18:26       ` Lucas Seiki Oshiro
  1 sibling, 1 reply; 226+ messages in thread
From: Phillip Wood @ 2025-07-23 14:53 UTC (permalink / raw)
  To: Justin Tobler, Lucas Seiki Oshiro
  Cc: git, oswald.buddenhagen, ps, karthik.188, ben.knoble, gitster,
	phillip.wood
On 22/07/2025 20:25, Justin Tobler wrote:
> On 25/07/21 09:28PM, Lucas Seiki Oshiro wrote:
> 
>> +typedef const char *get_value_fn(struct repository *repo);
>> +
>> +struct field {
>> +	const char *key;
>> +	get_value_fn *add_field_callback;
>> +};
>> +
>> +static const char *get_references_format(struct repository *repo)
>> +{
>> +	return ref_storage_format_to_name(repo->ref_storage_format);
>> +}
>> +
>> +/* repo_info_fields keys should be in lexicographical order */
>> +static const struct field repo_info_fields[] = {
>> +	{ "references.format", get_references_format },
>> +};
> 
> Ok, so each key has a corresponding callback that is used to get its
> value. This works fine when we have one operation/callback per key, but
> I could see this being a bit inflexible in cases where performing a
> single operation could be expected to generate multiple keys worth of
> information at a time.
> 
> I certainly see this being the case with git-repo-stats where, for
> example, interating over references will produce multiple keyvalues
> indicating the number of branches, tags, remotes, etc. But, maybe for
> git-repo-info this will not be as much of a concern?
I think the fact that git_value_fn returns 'const char*' is a concern as 
it means we cannot return an allocated string. It would be better to 
pass a 'struct strbuf' to the callback and write the value to that 
instead. That way a callback can create the value piecemeal if needed 
and we don't have to worry about whether we should be free()ing the 
returned string.
An alternative approach would be to pass a function pointer to the 
callback which it then calls with the key and value to produce the output.
Thanks
Phillip
>> +
>> +static int repo_info_fields_cmp(const void *va, const void *vb)
>> +{
>> +	const struct field *a = va;
>> +	const struct field *b = vb;
>> +
>> +	return strcmp(a->key, b->key);
>> +}
>> +
>> +static get_value_fn *get_value_callback(const char *key)
>>   {
>> +	const struct field search_key = { key, NULL };
>> +	const struct field *found = bsearch(&search_key, repo_info_fields,
>> +					    ARRAY_SIZE(repo_info_fields),
>> +					    sizeof(struct field),
>> +					    repo_info_fields_cmp);
>> +	return found ? found->add_field_callback : NULL;
>> +}
>> +
>> +static int qsort_strcmp(const void *va, const void *vb)
>> +{
>> +	const char *a = *(const char **)va;
>> +	const char *b = *(const char **)vb;
>> +
>> +	return strcmp(a, b);
>> +}
>> +
>> +static int print_fields(int argc, const char **argv, struct repository *repo)
>> +{
>> +	const char *last = "";
>> +
>> +	QSORT(argv, argc, qsort_strcmp);
>> +
>> +	for (int i = 0; i < argc; i++) {
>> +		get_value_fn *callback;
>> +		const char *key = argv[i];
>> +		const char *value;
>> +
>> +		if (!strcmp(key, last))
>> +			continue;
>> +
>> +		callback = get_value_callback(key);
>> +
>> +		if (!callback)
>> +			return error("key %s not found", key);
>> +
>> +		value = callback(repo);
>> +		printf("%s=%s\n", key, value);
>> +		last = key;
>> +	}
> 
> If the user does not input any keys, we simply do nothing. I do wonder
> if this is really the best default behavior. Maybe instead we should
> error out? Or maybe treat it as though all keys were requested?
> 
> -Justin
> 
>> +
>>   	return 0;
>>   }
>>   
>> +static int repo_info(int argc, const char **argv, const char *prefix UNUSED,
>> +		     struct repository *repo)
>> +{
>> +	return print_fields(argc - 1, argv + 1, repo);
>> +}
>> +
>>   int cmd_repo(int argc, const char **argv, const char *prefix,
>>   	     struct repository *repo)
>>   {
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v5 1/5] repo: declare the repo command
  2025-07-22  9:03     ` Karthik Nayak
  2025-07-22 15:21       ` Junio C Hamano
@ 2025-07-23 15:49       ` Lucas Seiki Oshiro
  1 sibling, 0 replies; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-07-23 15:49 UTC (permalink / raw)
  To: Karthik Nayak
  Cc: git, oswald.buddenhagen, ps, ben.knoble, gitster, phillip.wood,
	jltobler
> Doesn't the latter sentence only apply to 'git repo info'?
Yes. I'll fix this commit message.
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v5 1/5] repo: declare the repo command
  2025-07-22 15:21       ` Junio C Hamano
@ 2025-07-23 16:28         ` Lucas Seiki Oshiro
  2025-07-23 17:48           ` Junio C Hamano
  2025-07-24  6:22         ` Patrick Steinhardt
  1 sibling, 1 reply; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-07-23 16:28 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Karthik Nayak, git, oswald.buddenhagen, ps, ben.knoble,
	phillip.wood, jltobler
> I also wonder who it helps to use <LF> as a field separator.
Do you mean the <LF> between the field and the value? If so, it was the
format suggested by Phillip [1]. I accepted the suggestion because:
1. It's easy to be parsed
2. It's easy to write (then I could drop the json_write stuff)
3. It's already used by an existing command (git-config)
> Once we require consumers to properly handle <NUL>, it does not make
> it easier to write such a consumer script if the format uses <LF>
> there, does it?
Not much... Since the keys contain only letters and dots, any other
character would work here, but I wanted to be consistent with
something that already exists.
However, to the best of my knowledge, we have several null-terminated
commands (git ls-files -z, git status -z, git ls-tree -z, etc), but
few commands that use LF as a key-value separator (I only remember
git config -z).
> Besides, wouldn't it possible that field may have to contain any
> end-user specified key, including <LF>?
In `repo info`, no. This way, it's safe to parse everything before
the first <LF> as the key and everything between <LF> and <NUL> as
the value.
The value may contain a <LF>, however, the first <LF> would still
be the separator.
Thanks!
[1] https://lore.kernel.org/git/223c7cbd-610e-49e2-90e2-5914cbc0f1d7@gmail.com/
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v5 2/5] repo: add the field references.format
  2025-07-23 14:53       ` Phillip Wood
@ 2025-07-23 17:44         ` Lucas Seiki Oshiro
  0 siblings, 0 replies; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-07-23 17:44 UTC (permalink / raw)
  To: phillip.wood
  Cc: Justin Tobler, git, oswald.buddenhagen, ps, karthik.188,
	ben.knoble, gitster
> I think the fact that git_value_fn returns 'const char*' is a
> concern as it means we cannot return an allocated string.
Yeah, I was thinking about that. It is not a problem by now, but
after the acceptance of this patchset I'll start to work in the
`path.*` fields and that would be a problem.
> It would be better to pass a 'struct strbuf' to the callback and
> write the value to that instead.
When I was working on this version I was thinking about it, but I
left the way it is to make it simpler, and refactor it when
implementing the `path.*` fields. But now I think it would be
better to change it in v6.
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v5 1/5] repo: declare the repo command
  2025-07-23 16:28         ` Lucas Seiki Oshiro
@ 2025-07-23 17:48           ` Junio C Hamano
  0 siblings, 0 replies; 226+ messages in thread
From: Junio C Hamano @ 2025-07-23 17:48 UTC (permalink / raw)
  To: Lucas Seiki Oshiro
  Cc: Karthik Nayak, git, oswald.buddenhagen, ps, ben.knoble,
	phillip.wood, jltobler
Lucas Seiki Oshiro <lucasseikioshiro@gmail.com> writes:
>> Besides, wouldn't it possible that field may have to contain any
>> end-user specified key, including <LF>?
>
> In `repo info`, no. This way, it's safe to parse everything before
> the first <LF> as the key and everything between <LF> and <NUL> as
> the value.
OK.  Even "git config" punts there by restricting the subsection
part of the configuration variable name by forbidding LF and NUL in
it ;-)  So, I guess we are OK here.
Thanks for thinking it through.
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v5 2/5] repo: add the field references.format
  2025-07-22 19:25     ` Justin Tobler
  2025-07-23 14:53       ` Phillip Wood
@ 2025-07-23 18:26       ` Lucas Seiki Oshiro
  1 sibling, 0 replies; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-07-23 18:26 UTC (permalink / raw)
  To: Justin Tobler
  Cc: git, oswald.buddenhagen, ps, karthik.188, ben.knoble, gitster,
	phillip.wood
> Ok, so each key has a corresponding callback that is used to get its
> value. This works fine when we have one operation/callback per key, but
> I could see this being a bit inflexible in cases where performing a
> single operation could be expected to generate multiple keys worth of
> information at a time.
For git-repo-info it wouldn't be a problem, as we return one value per
requested key.
However, I plan to add a feature in the future for requesting a group
of fields. For example:
$ git repo info layout
layout.bare=true
layout.shallow=false
which, of course, is not what exactly you mean :-). But it is a similar
problem of requesting one key and getting several key-value pairs.
> I certainly see this being the case with git-repo-stats where, for
> example, interating over references will produce multiple keyvalues
> indicating the number of branches, tags, remotes, etc. But, maybe for
> git-repo-info this will not be as much of a concern?
For git-repo-info it isn't, at least by the planned set of values.
However, given that I have plans to add the previous feature, I can
try to make it flexible for doing things like:
$ git repo stats object.count
object.count.blob=123
object.count.tree=456
object.count.commit=789
So you can use the same code for outputting git-repo-stats data. By
now, I plan to finish the basic functionality (i.e. finishing this
"skeleton" and adding the rest of the proposed fields), then I'll
think about this feature.
I think the current solution is simple enough to being refactored to
support this kind of thing in the future.
> If the user does not input any keys, we simply do nothing. I do wonder
> if this is really the best default behavior.
In previous versions it returned all the available fields. There was a
`--allow-empty` flag that allowed to request no field.
After the discussion in [1] we agreed that it would be better to return
nothing by default and add a `--all` flag for returning all the fields
(or a default set of fields).
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v5 1/5] repo: declare the repo command
  2025-07-22  0:28   ` [GSoC PATCH v5 1/5] repo: declare the repo command Lucas Seiki Oshiro
  2025-07-22  9:03     ` Karthik Nayak
@ 2025-07-23 20:03     ` Jean-Noël AVILA
  1 sibling, 0 replies; 226+ messages in thread
From: Jean-Noël AVILA @ 2025-07-23 20:03 UTC (permalink / raw)
  To: git, Lucas Seiki Oshiro
  Cc: oswald.buddenhagen, ps, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler, Lucas Seiki Oshiro
On Tuesday, 22 July 2025 02:28:31 CEST Lucas Seiki Oshiro wrote:
> Currently, `git rev-parse` covers a wide range of functionality not
> directly related to parsing revisions, as its name suggests. Over time,
> many features like parsing datestrings, options, paths, and others
> were added to it because there wasn't a more appropriate command
> to place them.
> 
> Create a new Git command called `repo`. `git repo` will be the main
> command for obtaining the information about a repository (such as
> metadata and metrics), returning them in a machine readable format
> following the syntax "field<LF>value<NUL>".
> 
> Also declare a subcommand for `repo` called `info`. `git repo info`
> will bring the functionality of retrieving repository-related
> information currently returned by `rev-parse`.
> 
> Add the required tests, documentation and build changes to enable
> usage of this subcommand.
> 
> Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
> Helped-by: Junio C Hamano <gitster@pobox.com>
> Helped-by: Justin Tobler <jltobler@gmail.com>
> Mentored-by: Karthik Nayak <karthik.188@gmail.com>
> Mentored-by: Patrick Steinhardt <ps@pks.im>
> Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
> ---
>  .gitignore                  |  1 +
>  Documentation/git-repo.adoc | 38 +++++++++++++++++++++++++++++++++++++
>  Documentation/meson.build   |  1 +
>  Makefile                    |  1 +
>  builtin.h                   |  1 +
>  builtin/repo.c              | 26 +++++++++++++++++++++++++
>  command-list.txt            |  1 +
>  git.c                       |  1 +
>  meson.build                 |  1 +
>  9 files changed, 71 insertions(+)
>  create mode 100644 Documentation/git-repo.adoc
>  create mode 100644 builtin/repo.c
> 
> diff --git a/.gitignore b/.gitignore
> index 04c444404e..1803023427 100644
> --- a/.gitignore
> +++ b/.gitignore
> @@ -139,6 +139,7 @@
>  /git-repack
>  /git-replace
>  /git-replay
> +/git-repo
>  /git-request-pull
>  /git-rerere
>  /git-reset
> diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc
> new file mode 100644
> index 0000000000..caee7d8aef
> --- /dev/null
> +++ b/Documentation/git-repo.adoc
> @@ -0,0 +1,38 @@
> +git-repo(1)
> +===========
> +
> +NAME
> +----
> +git-repo - Retrieve information about a repository
> +
> +SYNOPSIS
> +--------
> +[synopsis]
> +git repo info [<key>...]
> +
> +DESCRIPTION
> +-----------
> +This command retrieve repository level information.
> +
> +THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOR MAY CHANGE.
> +
> +COMMANDS
> +--------
> +info [<key>...]::
The commands and options are quoted with back-quotes with the new synopsis 
style:
`info [<key> ...]`::
Thanks
JN
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v5 1/5] repo: declare the repo command
  2025-07-22 15:21       ` Junio C Hamano
  2025-07-23 16:28         ` Lucas Seiki Oshiro
@ 2025-07-24  6:22         ` Patrick Steinhardt
  2025-07-24 16:06           ` Junio C Hamano
  2025-07-26 21:54           ` Lucas Seiki Oshiro
  1 sibling, 2 replies; 226+ messages in thread
From: Patrick Steinhardt @ 2025-07-24  6:22 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Karthik Nayak, Lucas Seiki Oshiro, git, oswald.buddenhagen,
	ben.knoble, phillip.wood, jltobler
On Tue, Jul 22, 2025 at 08:21:45AM -0700, Junio C Hamano wrote:
> Karthik Nayak <karthik.188@gmail.com> writes:
> 
> > Lucas Seiki Oshiro <lucasseikioshiro@gmail.com> writes:
> >
> >> Currently, `git rev-parse` covers a wide range of functionality not
> >> directly related to parsing revisions, as its name suggests. Over time,
> >> many features like parsing datestrings, options, paths, and others
> >> were added to it because there wasn't a more appropriate command
> >> to place them.
> >>
> >> Create a new Git command called `repo`. `git repo` will be the main
> >> command for obtaining the information about a repository (such as
> >> metadata and metrics), returning them in a machine readable format
> >> following the syntax "field<LF>value<NUL>".
> >>
> >
> > Doesn't the latter sentence only apply to 'git repo info'? Other
> > sub-commands may not follow the field<LF>value<NUL> syntax, no?
> 
> True.
> 
> I also wonder who it helps to use <LF> as a field separator.  Once
> we require consumers to properly handle <NUL>, it does not make it
> easier to write such a consumer script if the format uses <LF>
> there, does it?  Besides, wouldn't it possible that field may have
> to contain any end-user specified key, including <LF>?  If so, we'd
> need to have some quoting/unquoting mechanism in the syntax anyway,
> so the behefit of using <NUL> to simplify the parser would already
> be lost.
Scripts should always use NUL, true. But sometimes a user may want to
inspect these key-value pairs, as well, just to double check a certain
property of the repository, or to figure out how a certain property
looks like while writing a script that parses the same key-value but
NUL-separated pairs. Using NUL bytes would be a bit of a pain in that
situation.
I'm not really too sure whether we need to bother with quoting. The
LF-separated output shouldn't ever be used in a script, so I don't mind
too much whether it always works. But I guess it wouldn't be hard either
to just have something like:
    if (uses_newline)
        quote_c_style(...);
So with that in mind it's probably better to just do the right thing.
Patrick
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v5 2/5] repo: add the field references.format
  2025-07-22  0:28   ` [GSoC PATCH v5 2/5] repo: add the field references.format Lucas Seiki Oshiro
  2025-07-22  9:16     ` Karthik Nayak
  2025-07-22 19:25     ` Justin Tobler
@ 2025-07-24  6:22     ` Patrick Steinhardt
  2 siblings, 0 replies; 226+ messages in thread
From: Patrick Steinhardt @ 2025-07-24  6:22 UTC (permalink / raw)
  To: Lucas Seiki Oshiro
  Cc: git, oswald.buddenhagen, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler
On Mon, Jul 21, 2025 at 09:28:32PM -0300, Lucas Seiki Oshiro wrote:
> diff --git a/builtin/repo.c b/builtin/repo.c
> index d4f01e35e2..5beae0f781 100644
> --- a/builtin/repo.c
> +++ b/builtin/repo.c
> @@ -1,12 +1,83 @@
>  #include "builtin.h"
>  #include "parse-options.h"
> +#include "refs.h"
>  
> -static int repo_info(int argc UNUSED, const char **argv UNUSED,
> -		     const char *prefix UNUSED, struct repository *repo UNUSED)
> +typedef const char *get_value_fn(struct repository *repo);
> +
> +struct field {
> +	const char *key;
> +	get_value_fn *add_field_callback;
> +};
> +
> +static const char *get_references_format(struct repository *repo)
> +{
> +	return ref_storage_format_to_name(repo->ref_storage_format);
> +}
> +
> +/* repo_info_fields keys should be in lexicographical order */
> +static const struct field repo_info_fields[] = {
> +	{ "references.format", get_references_format },
> +};
One problem that we'll eventually face is that we want to add a callback
that needs to return an allocated string. With the current design we
cannot really handle that without creating amemory leak. So I guess it
would make more sense if the callback thus received a pointer to a
strbuf that it is expected to print its value to.
Also, we should be able to return errors. While that's not needed right
now, it may be in the future. So how about:
	typedef int get_value_fn(struct repository *repo, struct strbuf *buf);
	static int get_references_format(struct repository *repo,
					 struct strbuf *buf)
	{
		strbuf_addstr(buf, ref_storage_format_to_name(repo->ref_storage_format));
		return 0;
	}
> +static int repo_info_fields_cmp(const void *va, const void *vb)
> +{
> +	const struct field *a = va;
> +	const struct field *b = vb;
> +
> +	return strcmp(a->key, b->key);
> +}
> +
> +static get_value_fn *get_value_callback(const char *key)
>  {
> +	const struct field search_key = { key, NULL };
> +	const struct field *found = bsearch(&search_key, repo_info_fields,
> +					    ARRAY_SIZE(repo_info_fields),
> +					    sizeof(struct field),
Nit: let's rather use `sizeof(*repo_info_fields)`. Makes it more
trivially correct without having to double check whether
`repo_info_fields` actually is a `struct field`..
Patrick
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v5 5/5] repo: add the --format flag
  2025-07-22  0:28   ` [GSoC PATCH v5 5/5] repo: add the --format flag Lucas Seiki Oshiro
  2025-07-22  9:26     ` Karthik Nayak
@ 2025-07-24  6:22     ` Patrick Steinhardt
  1 sibling, 0 replies; 226+ messages in thread
From: Patrick Steinhardt @ 2025-07-24  6:22 UTC (permalink / raw)
  To: Lucas Seiki Oshiro
  Cc: git, oswald.buddenhagen, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler
On Mon, Jul 21, 2025 at 09:28:35PM -0300, Lucas Seiki Oshiro wrote:
> diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc
> index 375b956d3f..5bdc3831a7 100644
> --- a/Documentation/git-repo.adoc
> +++ b/Documentation/git-repo.adoc
> @@ -18,10 +18,21 @@ THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOR MAY CHANGE.
>  
>  COMMANDS
>  --------
> -info [<key>...]::
> +info [--format=<format>] [<key>...]::
>  	Retrieve metadata-related information about the current repository. Only
>  	the requested data will be returned based on their keys (see "INFO KEYS"
>  	section below).
> ++
> +The output format can be chosen through the flag `--format`. Two formats are
> +supported:
> ++
> +* `keyvalue`: output key-value pairs one per line using the `=` character as
> +the delimiter between the key and the value. This is the default.
> +
> +* `null`: similar to `keyvalue`, but using a newline character as the delimiter
Our manual typically says "NUL"-terminated format in other places, like
for example in git-update-ref(1). So let's rather name the format `nul`.
> diff --git a/builtin/repo.c b/builtin/repo.c
> index 490fa9dd49..10d02bb3ea 100644
> --- a/builtin/repo.c
> +++ b/builtin/repo.c
> @@ -8,6 +8,11 @@
>  
>  typedef const char *get_value_fn(struct repository *repo);
>  
> +enum output_format {
> +	FORMAT_KEYVALUE,
> +	FORMAT_NULL_TERMINATED,
Likewise, this should be `FORMAT_NUL_TERMINATED`.
> @@ -61,9 +66,24 @@ static int qsort_strcmp(const void *va, const void *vb)
>  	return strcmp(a, b);
>  }
>  
> -static int print_fields(int argc, const char **argv, struct repository *repo)
> +static int print_fields(int argc, const char **argv,
> +			struct repository *repo,
> +			enum output_format format)
>  {
>  	const char *last = "";
> +	char kv_sep;
> +	char field_sep;
> +
> +	switch (format) {
> +	case FORMAT_KEYVALUE:
> +		kv_sep = '=';
> +		field_sep = '\n';
> +		break;
> +	case FORMAT_NULL_TERMINATED:
> +		kv_sep = '\n';
> +		field_sep = '\0';
> +		break;
> +	}
>  
>  	QSORT(argv, argc, qsort_strcmp);
>  
Makes sense.
> @@ -81,17 +101,38 @@ static int print_fields(int argc, const char **argv, struct repository *repo)
>  			return error("key %s not found", key);
>  
>  		value = callback(repo);
> -		printf("%s=%s\n", key, value);
> +		printf("%s%c%s%c", key, kv_sep, value, field_sep);
>  		last = key;
This here is where we can introduce the quoting. Something like:
	if (format == FORMAT_KEYVALUE) {
		strbuf_reset("ed_value);
		quote_c_style(value, "ed_value, NULL, 0);
	}
	printf("%s%c%s%c", key, kv_sep,
	       format == FORMAT_KEYVALUE ? quoted_value.buf : value,
	       field_sep);
>  	}
>  
>  	return 0;
>  }
>  
> -static int repo_info(int argc, const char **argv, const char *prefix UNUSED,
> +static int repo_info(int argc, const char **argv, const char *prefix,
>  		     struct repository *repo)
>  {
> -	return print_fields(argc - 1, argv + 1, repo);
> +	const char *format_str = "keyvalue";
> +	enum output_format format;
> +	const char *const repo_info_usage[] = {
> +		"git repo info [<key>...]",
> +		NULL
> +	};
> +	struct option options[] = {
> +		OPT_STRING(0, "format", &format_str, N_("format"),
> +			   N_("output format")),
> +		OPT_END()
> +	};
> +
> +	argc = parse_options(argc, argv, prefix, options, repo_info_usage, 0);
> +
> +	if (!strcmp(format_str, "keyvalue"))
> +		format = FORMAT_KEYVALUE;
> +	else if (!strcmp(format_str, "null"))
> +		format = FORMAT_NULL_TERMINATED;
> +	else
> +		die("invalid format %s", format_str);
Nit: this should be translated and quote the format string:
	die(_("invalid format: '%s'"), format_str);
Patrick
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v5 1/5] repo: declare the repo command
  2025-07-24  6:22         ` Patrick Steinhardt
@ 2025-07-24 16:06           ` Junio C Hamano
  2025-07-25  5:10             ` Patrick Steinhardt
  2025-07-26 21:54           ` Lucas Seiki Oshiro
  1 sibling, 1 reply; 226+ messages in thread
From: Junio C Hamano @ 2025-07-24 16:06 UTC (permalink / raw)
  To: Patrick Steinhardt
  Cc: Karthik Nayak, Lucas Seiki Oshiro, git, oswald.buddenhagen,
	ben.knoble, phillip.wood, jltobler
Patrick Steinhardt <ps@pks.im> writes:
>> True.
>> 
>> I also wonder who it helps to use <LF> as a field separator.  Once
>> we require consumers to properly handle <NUL>, it does not make it
>> easier to write such a consumer script if the format uses <LF>
>> there, does it?  Besides, wouldn't it possible that field may have
>> to contain any end-user specified key, including <LF>?  If so, we'd
>> need to have some quoting/unquoting mechanism in the syntax anyway,
>> so the behefit of using <NUL> to simplify the parser would already
>> be lost.
>
> Scripts should always use NUL, true. But sometimes a user may want to
> inspect these key-value pairs, as well, just to double check a certain
> property of the repository, or to figure out how a certain property
> looks like while writing a script that parses the same key-value but
> NUL-separated pairs. Using NUL bytes would be a bit of a pain in that
> situation.
True.  I do not think the discussion so far had much focus on
helping human users doing ad-hoc inspection, and NUL can be annoying
for such use cases (even though tr is your friend).
> I'm not really too sure whether we need to bother with quoting. The
> LF-separated output shouldn't ever be used in a script, so I don't mind
> too much whether it always works. But I guess it wouldn't be hard either
> to just have something like:
>
>     if (uses_newline)
>         quote_c_style(...);
>
> So with that in mind it's probably better to just do the right thing.
The right thing being...?  Use <LF> as a record separator to avoid
forcing <NUL> on possible human readers, and adopt quoting in a rare
case where <LF>s or <NUL>s need to be in the payload?  Or something
else?
Thanks.
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v5 1/5] repo: declare the repo command
  2025-07-24 16:06           ` Junio C Hamano
@ 2025-07-25  5:10             ` Patrick Steinhardt
  0 siblings, 0 replies; 226+ messages in thread
From: Patrick Steinhardt @ 2025-07-25  5:10 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Karthik Nayak, Lucas Seiki Oshiro, git, oswald.buddenhagen,
	ben.knoble, phillip.wood, jltobler
On Thu, Jul 24, 2025 at 09:06:57AM -0700, Junio C Hamano wrote:
> Patrick Steinhardt <ps@pks.im> writes:
> > I'm not really too sure whether we need to bother with quoting. The
> > LF-separated output shouldn't ever be used in a script, so I don't mind
> > too much whether it always works. But I guess it wouldn't be hard either
> > to just have something like:
> >
> >     if (uses_newline)
> >         quote_c_style(...);
> >
> > So with that in mind it's probably better to just do the right thing.
> 
> The right thing being...?  Use <LF> as a record separator to avoid
> forcing <NUL> on possible human readers, and adopt quoting in a rare
> case where <LF>s or <NUL>s need to be in the payload?  Or something
> else?
Use <LF> by default to help humans, but do C-style quoting in that case.
Provide <NUL> terminated output format for machines so that they don't
have to care about unquoting.
Patrick
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v5 1/5] repo: declare the repo command
  2025-07-24  6:22         ` Patrick Steinhardt
  2025-07-24 16:06           ` Junio C Hamano
@ 2025-07-26 21:54           ` Lucas Seiki Oshiro
  2025-07-28 17:56             ` Junio C Hamano
  1 sibling, 1 reply; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-07-26 21:54 UTC (permalink / raw)
  To: Patrick Steinhardt
  Cc: Junio C Hamano, Karthik Nayak, git, oswald.buddenhagen,
	ben.knoble, phillip.wood, jltobler
> I'm not really too sure whether we need to bother with quoting.
Given the set of values that I have planned for this command, the only
problem that I see is in the (near) future where `git-repo-info` will
return paths and only when those paths have less common bytes in those
paths (e.g. newlines).
I think I'll leave the way it is by now because it won't affect the
current set of values (which are "true", "false", "files" and
"reftable"), and we can discuss more about it in the patches related to
paths.
> So with that in mind it's probably better to just do the right thing.
Hmmm... I'm thinking about what is the "right thing" in this context.
For example, `git config --list` doesn't quote when in its key=value
format. Perhaps I'm citing `git config --list` too much :-), but it is
because is the closer command to `git-repo-info` in that sense.
But by now, I think we can discuss it later. Adding the quote_c_style
would be very easy to do in a future patch without changing the behavior
of what we have by now.
^ permalink raw reply	[flat|nested] 226+ messages in thread
* [GSoC PATCH v5 0/5] repo: add new command for retrieving repository info
  2025-06-10 15:21 [GSoC RFC PATCH 0/5] repo-info: add new command for retrieving repository info Lucas Seiki Oshiro
                   ` (11 preceding siblings ...)
  2025-07-22  0:28 ` [GSoC PATCH v5 0/5] " Lucas Seiki Oshiro
@ 2025-07-27 17:51 ` Lucas Seiki Oshiro
  2025-07-27 17:51   ` [GSoC PATCH v5 1/5] repo: declare the repo command Lucas Seiki Oshiro
                     ` (5 more replies)
  2025-08-01 13:11 ` [GSoC PATCH v7 " Lucas Seiki Oshiro
                   ` (4 subsequent siblings)
  17 siblings, 6 replies; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-07-27 17:51 UTC (permalink / raw)
  To: git
  Cc: oswald.buddenhagen, ps, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler, jn.avila, Lucas Seiki Oshiro
Hi!
This v6 contains small fixes pointed in v5.
The main changes were:
- The functions that retrieve the values now add a string to a strbuf
  instead of returning the string
- The null-terminated format is now identified as "nul"
- Two test cases were added, covering invalid input values in the CLI
In v5, Patrick and Junio were discussing about quoting the values in the
key=value format using `quote_c_style` [1]. Given that it wouldn't affect
this patchset and it's a simple change that can be done later, I didn't
change it and I'll leave for further discussion when I start to deal
with paths.
Thanks!
[1] https://lore.kernel.org/git/aIHRCz_qswp7RgSy@pks.im/
Range-diff versus v5:
1:  396cfc256a ! 1:  bc6f19ba8e repo: declare the repo command
    @@ Commit message
         Create a new Git command called `repo`. `git repo` will be the main
         command for obtaining the information about a repository (such as
    -    metadata and metrics), returning them in a machine readable format
    -    following the syntax "field<LF>value<NUL>".
    +    metadata and metrics).
         Also declare a subcommand for `repo` called `info`. `git repo info`
         will bring the functionality of retrieving repository-related
    @@ Documentation/git-repo.adoc (new)
     +
     +COMMANDS
     +--------
    -+info [<key>...]::
    ++`info [<key>...]`::
     +	Retrieve metadata-related information about the current repository. Only
     +	the requested data will be returned based on their keys (see "INFO KEYS"
     +	section below).
2:  28f4c21a96 ! 2:  b1c0627af8 repo: add the field references.format
    @@ Commit message
         used for querying repository metadata, fitting in the purpose of
         git-repo-info.
    -    Then, add a new field `references.format` to the repo-info subcommand
    +    Add a new field `references.format` to the repo-info subcommand
         containing that information.
         Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
    @@ builtin/repo.c
      #include "builtin.h"
      #include "parse-options.h"
     +#include "refs.h"
    ++#include "strbuf.h"
     -static int repo_info(int argc UNUSED, const char **argv UNUSED,
     -		     const char *prefix UNUSED, struct repository *repo UNUSED)
    -+typedef const char *get_value_fn(struct repository *repo);
    ++typedef int get_value_fn(struct repository *repo, struct strbuf *buf);
     +
     +struct field {
     +	const char *key;
    -+	get_value_fn *add_field_callback;
    ++	get_value_fn *get_value;
     +};
     +
    -+static const char *get_references_format(struct repository *repo)
    ++static int get_references_format(struct repository *repo, struct strbuf *buf)
     +{
    -+	return ref_storage_format_to_name(repo->ref_storage_format);
    ++	strbuf_addstr(buf,
    ++		      ref_storage_format_to_name(repo->ref_storage_format));
    ++	return 0;
     +}
     +
     +/* repo_info_fields keys should be in lexicographical order */
    @@ builtin/repo.c
     +	return strcmp(a->key, b->key);
     +}
     +
    -+static get_value_fn *get_value_callback(const char *key)
    - {
    ++static get_value_fn *get_value_fn_for_key(const char *key)
    ++{
     +	const struct field search_key = { key, NULL };
     +	const struct field *found = bsearch(&search_key, repo_info_fields,
     +					    ARRAY_SIZE(repo_info_fields),
    -+					    sizeof(struct field),
    ++					    sizeof(*found),
     +					    repo_info_fields_cmp);
    -+	return found ? found->add_field_callback : NULL;
    ++	return found ? found->get_value : NULL;
     +}
     +
     +static int qsort_strcmp(const void *va, const void *vb)
    -+{
    + {
     +	const char *a = *(const char **)va;
     +	const char *b = *(const char **)vb;
     +
    @@ builtin/repo.c
     +	QSORT(argv, argc, qsort_strcmp);
     +
     +	for (int i = 0; i < argc; i++) {
    -+		get_value_fn *callback;
    ++		get_value_fn *get_value;
     +		const char *key = argv[i];
    -+		const char *value;
    ++		struct strbuf value;
    ++		strbuf_init(&value, 64);
     +
     +		if (!strcmp(key, last))
     +			continue;
     +
    -+		callback = get_value_callback(key);
    ++		get_value = get_value_fn_for_key(key);
     +
    -+		if (!callback)
    -+			return error("key %s not found", key);
    ++		if (!get_value)
    ++			die(_("key '%s' not found"), key);
     +
    -+		value = callback(repo);
    -+		printf("%s=%s\n", key, value);
    ++		get_value(repo, &value);
    ++		printf("%s=%s\n", key, value.buf);
     +		last = key;
    ++		strbuf_release(&value);
     +	}
     +
      	return 0;
    @@ t/t1900-repo.sh (new)
     +test_repo_info 'ref format reftable is retrieved correctly' '
     +	git init --ref-format=reftable repo' 'references.format' 'reftable'
     +
    ++test_expect_success 'git-repo-info aborts if an invalid key is requested' '
    ++	test_when_finished "rm -rf expected err" &&
    ++	echo "fatal: key '\'foo\'' not found" >expected &&
    ++	test_must_fail git repo info foo 2>err &&
    ++	test_cmp expected err
    ++'
    ++
     +test_expect_success "only one value is returned if the same key is requested twice" '
     +	test_when_finished "rm -f expected_key expected_value actual_key actual_value output" &&
     +	echo "references.format" >expected_key &&
3:  b8001ae87e ! 3:  d002401587 repo: add field layout.bare
    @@ builtin/repo.c
     +#define USE_THE_REPOSITORY_VARIABLE
     +
      #include "builtin.h"
    ++#include "environment.h"
      #include "parse-options.h"
      #include "refs.h"
    -+#include "environment.h"
    -
    - typedef const char *get_value_fn(struct repository *repo);
    -
    + #include "strbuf.h"
     @@ builtin/repo.c: struct field {
    - 	get_value_fn *add_field_callback;
    + 	get_value_fn *get_value;
      };
    -+static const char *get_layout_bare(struct repository *repo UNUSED)
    ++static int get_layout_bare(struct repository *repo UNUSED, struct strbuf *buf)
     +{
    -+	return is_bare_repository() ? "true" : "false";
    ++	strbuf_addstr(buf,
    ++		      is_bare_repository() ? "true" : "false");
    ++	return 0;
     +}
     +
    - static const char *get_references_format(struct repository *repo)
    + static int get_references_format(struct repository *repo, struct strbuf *buf)
      {
    - 	return ref_storage_format_to_name(repo->ref_storage_format);
    -@@ builtin/repo.c: static const char *get_references_format(struct repository *repo)
    + 	strbuf_addstr(buf,
    +@@ builtin/repo.c: static int get_references_format(struct repository *repo, struct strbuf *buf)
      /* repo_info_fields keys should be in lexicographical order */
      static const struct field repo_info_fields[] = {
    @@ t/t1900-repo.sh: test_repo_info 'ref format files is retrieved correctly' '
     +test_repo_info 'bare repository = true is retrieved correctly' '
     +	git init --bare repo' 'layout.bare' 'true'
     +
    - test_expect_success "only one value is returned if the same key is requested twice" '
    - 	test_when_finished "rm -f expected_key expected_value actual_key actual_value output" &&
    - 	echo "references.format" >expected_key &&
    + test_expect_success 'git-repo-info aborts if an invalid key is requested' '
    + 	test_when_finished "rm -rf expected err" &&
    + 	echo "fatal: key '\'foo\'' not found" >expected &&
4:  bceba54e8b ! 4:  6eaac3f9c3 repo: add field layout.shallow
    @@ builtin/repo.c
     @@
      #include "parse-options.h"
      #include "refs.h"
    - #include "environment.h"
    + #include "strbuf.h"
     +#include "shallow.h"
    - typedef const char *get_value_fn(struct repository *repo);
    + typedef int get_value_fn(struct repository *repo, struct strbuf *buf);
    -@@ builtin/repo.c: static const char *get_layout_bare(struct repository *repo UNUSED)
    - 	return is_bare_repository() ? "true" : "false";
    +@@ builtin/repo.c: static int get_layout_bare(struct repository *repo UNUSED, struct strbuf *buf)
    + 	return 0;
      }
    -+static const char *get_layout_shallow(struct repository *repo)
    ++static int get_layout_shallow(struct repository *repo, struct strbuf *buf)
     +{
    -+	return is_repository_shallow(repo) ? "true" : "false";
    ++	strbuf_addstr(buf,
    ++		      is_repository_shallow(repo) ? "true" : "false");
    ++	return 0;
     +}
     +
    - static const char *get_references_format(struct repository *repo)
    + static int get_references_format(struct repository *repo, struct strbuf *buf)
      {
    - 	return ref_storage_format_to_name(repo->ref_storage_format);
    -@@ builtin/repo.c: static const char *get_references_format(struct repository *repo)
    + 	strbuf_addstr(buf,
    +@@ builtin/repo.c: static int get_references_format(struct repository *repo, struct strbuf *buf)
      /* repo_info_fields keys should be in lexicographical order */
      static const struct field repo_info_fields[] = {
      	{ "layout.bare", get_layout_bare },
    @@ t/t1900-repo.sh: test_repo_info 'bare repository = false is retrieved correctly'
     +	rm -rf remote
     +	' 'layout.shallow' 'true'
     +
    - test_expect_success "only one value is returned if the same key is requested twice" '
    - 	test_when_finished "rm -f expected_key expected_value actual_key actual_value output" &&
    - 	echo "references.format" >expected_key &&
    + test_expect_success 'git-repo-info aborts if an invalid key is requested' '
    + 	test_when_finished "rm -rf expected err" &&
    + 	echo "fatal: key '\'foo\'' not found" >expected &&
     @@ t/t1900-repo.sh: test_expect_success "only one value is returned if the same key is requested twi
              test_cmp expected_value actual_value
      '
5:  f4a2b0a04e ! 5:  69c7554bf3 repo: add the --format flag
    @@ Commit message
         Add the --format flag to git-repo-info. By using this flag, the users
         can choose the format for obtaining the data they requested.
    -    Given that this command can be used for generating input for another
    +    Given that this command can be used for generating input for other
         applications and for being read by end users, it requires at least two
         formats: one for being read by humans and other for being read by
         machines. Some other Git commands also have two output formats, notably
    @@ Documentation/git-repo.adoc: THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOR MAY CHAN
      COMMANDS
      --------
    --info [<key>...]::
    -+info [--format=<format>] [<key>...]::
    +-`info [<key>...]`::
    ++`info [--format=<format>] [<key>...]`::
      	Retrieve metadata-related information about the current repository. Only
      	the requested data will be returned based on their keys (see "INFO KEYS"
      	section below).
    @@ Documentation/git-repo.adoc: THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOR MAY CHAN
     +* `keyvalue`: output key-value pairs one per line using the `=` character as
     +the delimiter between the key and the value. This is the default.
     +
    -+* `null`: similar to `keyvalue`, but using a newline character as the delimiter
    ++* `nul`: similar to `keyvalue`, but using a newline character as the delimiter
     +between the key and the value and using a null character after each value.
     +This format is better suited for being parsed by another applications than
     +`keyvalue`.
    @@ Documentation/git-repo.adoc: THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOR MAY CHAN
      ## builtin/repo.c ##
     @@
    - typedef const char *get_value_fn(struct repository *repo);
    + typedef int get_value_fn(struct repository *repo, struct strbuf *buf);
     +enum output_format {
     +	FORMAT_KEYVALUE,
    -+	FORMAT_NULL_TERMINATED,
    ++	FORMAT_NUL_TERMINATED,
     +};
     +
      struct field {
      	const char *key;
    - 	get_value_fn *add_field_callback;
    + 	get_value_fn *get_value;
     @@ builtin/repo.c: static int qsort_strcmp(const void *va, const void *vb)
      	return strcmp(a, b);
      }
    @@ builtin/repo.c: static int qsort_strcmp(const void *va, const void *vb)
     +		kv_sep = '=';
     +		field_sep = '\n';
     +		break;
    -+	case FORMAT_NULL_TERMINATED:
    ++	case FORMAT_NUL_TERMINATED:
     +		kv_sep = '\n';
     +		field_sep = '\0';
     +		break;
    @@ builtin/repo.c: static int qsort_strcmp(const void *va, const void *vb)
      	QSORT(argv, argc, qsort_strcmp);
     @@ builtin/repo.c: static int print_fields(int argc, const char **argv, struct repository *repo)
    - 			return error("key %s not found", key);
    + 			die(_("key '%s' not found"), key);
    - 		value = callback(repo);
    --		printf("%s=%s\n", key, value);
    -+		printf("%s%c%s%c", key, kv_sep, value, field_sep);
    + 		get_value(repo, &value);
    +-		printf("%s=%s\n", key, value.buf);
    ++		printf("%s%c%s%c", key, kv_sep, value.buf, field_sep);
      		last = key;
    + 		strbuf_release(&value);
      	}
    -
    +@@ builtin/repo.c: static int print_fields(int argc, const char **argv, struct repository *repo)
      	return 0;
      }
    @@ builtin/repo.c: static int print_fields(int argc, const char **argv, struct repo
     +
     +	if (!strcmp(format_str, "keyvalue"))
     +		format = FORMAT_KEYVALUE;
    -+	else if (!strcmp(format_str, "null"))
    -+		format = FORMAT_NULL_TERMINATED;
    ++	else if (!strcmp(format_str, "nul"))
    ++		format = FORMAT_NUL_TERMINATED;
     +	else
    -+		die("invalid format %s", format_str);
    ++		die(_("invalid format '%s'"), format_str);
     +
     +	return print_fields(argc, argv, repo, format);
      }
    @@ t/t1900-repo.sh: test_repo_info () {
     +		test_when_finished "rm -rf repo" &&
     +		eval "$init_command" &&
     +		echo "$expected_value" | lf_to_nul >expected &&
    -+		git -C repo repo info --format=null "$key" >output &&
    ++		git -C repo repo info --format=nul "$key" >output &&
     +		tail -n 1 output >actual &&
     +		test_cmp expected actual
     +	'
    @@ t/t1900-repo.sh: test_repo_info () {
      		cut -d "=" -f 2 <output >actual &&
      		test_cmp expected actual
      	'
    +@@ t/t1900-repo.sh: test_expect_success 'output is returned correctly when two keys are requested' '
    + 	test_cmp expect actual
    + '
    +
    ++test_expect_success 'git-repo-info aborts when requesting an invalid format' '
    ++	test_when_finished "rm -f err expected" &&
    ++	echo "fatal: invalid format '\'foo\''" >expected &&
    ++	test_must_fail git repo info --format=foo 2>err &&
    ++	test_cmp expected err
    ++'
    ++
    + test_done
Lucas Seiki Oshiro (5):
  repo: declare the repo command
  repo: add the field references.format
  repo: add field layout.bare
  repo: add field layout.shallow
  repo: add the --format flag
 .gitignore                  |   1 +
 Documentation/git-repo.adoc |  58 +++++++++++++
 Documentation/meson.build   |   1 +
 Makefile                    |   1 +
 builtin.h                   |   1 +
 builtin/repo.c              | 165 ++++++++++++++++++++++++++++++++++++
 command-list.txt            |   1 +
 git.c                       |   1 +
 meson.build                 |   1 +
 t/meson.build               |   1 +
 t/t1900-repo.sh             | 100 ++++++++++++++++++++++
 11 files changed, 331 insertions(+)
 create mode 100644 Documentation/git-repo.adoc
 create mode 100644 builtin/repo.c
 create mode 100755 t/t1900-repo.sh
-- 
2.39.5 (Apple Git-154)
^ permalink raw reply	[flat|nested] 226+ messages in thread
* [GSoC PATCH v5 1/5] repo: declare the repo command
  2025-07-27 17:51 ` [GSoC PATCH v5 0/5] repo: add new command for retrieving repository info Lucas Seiki Oshiro
@ 2025-07-27 17:51   ` Lucas Seiki Oshiro
  2025-07-27 20:20     ` Eric Sunshine
  2025-07-27 17:51   ` [GSoC PATCH v5 2/5] repo: add the field references.format Lucas Seiki Oshiro
                     ` (4 subsequent siblings)
  5 siblings, 1 reply; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-07-27 17:51 UTC (permalink / raw)
  To: git
  Cc: oswald.buddenhagen, ps, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler, jn.avila, Lucas Seiki Oshiro
Currently, `git rev-parse` covers a wide range of functionality not
directly related to parsing revisions, as its name suggests. Over time,
many features like parsing datestrings, options, paths, and others
were added to it because there wasn't a more appropriate command
to place them.
Create a new Git command called `repo`. `git repo` will be the main
command for obtaining the information about a repository (such as
metadata and metrics).
Also declare a subcommand for `repo` called `info`. `git repo info`
will bring the functionality of retrieving repository-related
information currently returned by `rev-parse`.
Add the required tests, documentation and build changes to enable
usage of this subcommand.
Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Helped-by: Junio C Hamano <gitster@pobox.com>
Helped-by: Justin Tobler <jltobler@gmail.com>
Mentored-by: Karthik Nayak <karthik.188@gmail.com>
Mentored-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
---
 .gitignore                  |  1 +
 Documentation/git-repo.adoc | 38 +++++++++++++++++++++++++++++++++++++
 Documentation/meson.build   |  1 +
 Makefile                    |  1 +
 builtin.h                   |  1 +
 builtin/repo.c              | 26 +++++++++++++++++++++++++
 command-list.txt            |  1 +
 git.c                       |  1 +
 meson.build                 |  1 +
 9 files changed, 71 insertions(+)
 create mode 100644 Documentation/git-repo.adoc
 create mode 100644 builtin/repo.c
diff --git a/.gitignore b/.gitignore
index 04c444404e..1803023427 100644
--- a/.gitignore
+++ b/.gitignore
@@ -139,6 +139,7 @@
 /git-repack
 /git-replace
 /git-replay
+/git-repo
 /git-request-pull
 /git-rerere
 /git-reset
diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc
new file mode 100644
index 0000000000..aca76b131b
--- /dev/null
+++ b/Documentation/git-repo.adoc
@@ -0,0 +1,38 @@
+git-repo(1)
+===========
+
+NAME
+----
+git-repo - Retrieve information about a repository
+
+SYNOPSIS
+--------
+[synopsis]
+git repo info [<key>...]
+
+DESCRIPTION
+-----------
+This command retrieve repository level information.
+
+THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOR MAY CHANGE.
+
+COMMANDS
+--------
+`info [<key>...]`::
+	Retrieve metadata-related information about the current repository. Only
+	the requested data will be returned based on their keys (see "INFO KEYS"
+	section below).
+
+INFO KEYS
+---------
+
+The set of data that `git repo` can return is grouped into the following
+categories:
+
+SEE ALSO
+--------
+linkgit:git-rev-parse[1]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/meson.build b/Documentation/meson.build
index 4404c623f0..41f43e0336 100644
--- a/Documentation/meson.build
+++ b/Documentation/meson.build
@@ -116,6 +116,7 @@ manpages = {
   'git-repack.adoc' : 1,
   'git-replace.adoc' : 1,
   'git-replay.adoc' : 1,
+  'git-repo.adoc' : 1,
   'git-request-pull.adoc' : 1,
   'git-rerere.adoc' : 1,
   'git-reset.adoc' : 1,
diff --git a/Makefile b/Makefile
index 5f7dd79dfa..9dce446309 100644
--- a/Makefile
+++ b/Makefile
@@ -1306,6 +1306,7 @@ BUILTIN_OBJS += builtin/remote.o
 BUILTIN_OBJS += builtin/repack.o
 BUILTIN_OBJS += builtin/replace.o
 BUILTIN_OBJS += builtin/replay.o
+BUILTIN_OBJS += builtin/repo.o
 BUILTIN_OBJS += builtin/rerere.o
 BUILTIN_OBJS += builtin/reset.o
 BUILTIN_OBJS += builtin/rev-list.o
diff --git a/builtin.h b/builtin.h
index bff13e3069..e6458e6fb9 100644
--- a/builtin.h
+++ b/builtin.h
@@ -216,6 +216,7 @@ int cmd_remote_ext(int argc, const char **argv, const char *prefix, struct repos
 int cmd_remote_fd(int argc, const char **argv, const char *prefix, struct repository *repo);
 int cmd_repack(int argc, const char **argv, const char *prefix, struct repository *repo);
 int cmd_replay(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_repo(int argc, const char **argv, const char *prefix, struct repository *repo);
 int cmd_rerere(int argc, const char **argv, const char *prefix, struct repository *repo);
 int cmd_reset(int argc, const char **argv, const char *prefix, struct repository *repo);
 int cmd_restore(int argc, const char **argv, const char *prefix, struct repository *repo);
diff --git a/builtin/repo.c b/builtin/repo.c
new file mode 100644
index 0000000000..d4f01e35e2
--- /dev/null
+++ b/builtin/repo.c
@@ -0,0 +1,26 @@
+#include "builtin.h"
+#include "parse-options.h"
+
+static int repo_info(int argc UNUSED, const char **argv UNUSED,
+		     const char *prefix UNUSED, struct repository *repo UNUSED)
+{
+	return 0;
+}
+
+int cmd_repo(int argc, const char **argv, const char *prefix,
+	     struct repository *repo)
+{
+	parse_opt_subcommand_fn *fn = NULL;
+	const char *const repo_usage[] = {
+		"git repo info [<key>...]",
+		NULL
+	};
+	struct option options[] = {
+		OPT_SUBCOMMAND("info", &fn, repo_info),
+		OPT_END()
+	};
+
+	argc = parse_options(argc, argv, prefix, options, repo_usage, 0);
+
+	return fn(argc, argv, prefix, repo);
+}
diff --git a/command-list.txt b/command-list.txt
index b7ade3ab9f..1b0bdee00d 100644
--- a/command-list.txt
+++ b/command-list.txt
@@ -164,6 +164,7 @@ git-remote                              ancillarymanipulators           complete
 git-repack                              ancillarymanipulators           complete
 git-replace                             ancillarymanipulators           complete
 git-replay                              plumbingmanipulators
+git-repo                                plumbinginterrogators
 git-request-pull                        foreignscminterface             complete
 git-rerere                              ancillaryinterrogators
 git-reset                               mainporcelain           history
diff --git a/git.c b/git.c
index 07a5fe39fb..8290d8b8c8 100644
--- a/git.c
+++ b/git.c
@@ -611,6 +611,7 @@ static struct cmd_struct commands[] = {
 	{ "repack", cmd_repack, RUN_SETUP },
 	{ "replace", cmd_replace, RUN_SETUP },
 	{ "replay", cmd_replay, RUN_SETUP },
+	{ "repo", cmd_repo, RUN_SETUP },
 	{ "rerere", cmd_rerere, RUN_SETUP },
 	{ "reset", cmd_reset, RUN_SETUP },
 	{ "restore", cmd_restore, RUN_SETUP | NEED_WORK_TREE },
diff --git a/meson.build b/meson.build
index 9bc1826cb6..8819b64f93 100644
--- a/meson.build
+++ b/meson.build
@@ -645,6 +645,7 @@ builtin_sources = [
   'builtin/repack.c',
   'builtin/replace.c',
   'builtin/replay.c',
+  'builtin/repo.c',
   'builtin/rerere.c',
   'builtin/reset.c',
   'builtin/rev-list.c',
-- 
2.39.5 (Apple Git-154)
^ permalink raw reply related	[flat|nested] 226+ messages in thread
* [GSoC PATCH v5 2/5] repo: add the field references.format
  2025-07-27 17:51 ` [GSoC PATCH v5 0/5] repo: add new command for retrieving repository info Lucas Seiki Oshiro
  2025-07-27 17:51   ` [GSoC PATCH v5 1/5] repo: declare the repo command Lucas Seiki Oshiro
@ 2025-07-27 17:51   ` Lucas Seiki Oshiro
  2025-07-27 21:16     ` Eric Sunshine
  2025-07-29  9:35     ` Patrick Steinhardt
  2025-07-27 17:51   ` [GSoC PATCH v5 3/5] repo: add field layout.bare Lucas Seiki Oshiro
                     ` (3 subsequent siblings)
  5 siblings, 2 replies; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-07-27 17:51 UTC (permalink / raw)
  To: git
  Cc: oswald.buddenhagen, ps, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler, jn.avila, Lucas Seiki Oshiro
This commit is part of the series that introduces the new subcommand
git-repo-info.
The flag `--show-ref-format` from git-rev-parse is used for retrieving
the reference format (i.e. `files` or `reftable`). This way, it is
used for querying repository metadata, fitting in the purpose of
git-repo-info.
Add a new field `references.format` to the repo-info subcommand
containing that information.
Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Helped-by: Junio C Hamano <gitster@pobox.com>
Helped-by: Justin Tobler <jltobler@gmail.com>
Mentored-by: Karthik Nayak <karthik.188@gmail.com>
Mentored-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
---
 Documentation/git-repo.adoc |  4 ++
 builtin/repo.c              | 82 ++++++++++++++++++++++++++++++++++++-
 t/meson.build               |  1 +
 t/t1900-repo.sh             | 57 ++++++++++++++++++++++++++
 4 files changed, 142 insertions(+), 2 deletions(-)
 create mode 100755 t/t1900-repo.sh
diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc
index aca76b131b..ac2578299f 100644
--- a/Documentation/git-repo.adoc
+++ b/Documentation/git-repo.adoc
@@ -29,6 +29,10 @@ INFO KEYS
 The set of data that `git repo` can return is grouped into the following
 categories:
 
+`references`::
+Reference-related data:
+* `format`: the reference storage format
+
 SEE ALSO
 --------
 linkgit:git-rev-parse[1]
diff --git a/builtin/repo.c b/builtin/repo.c
index d4f01e35e2..02d5821c77 100644
--- a/builtin/repo.c
+++ b/builtin/repo.c
@@ -1,12 +1,90 @@
 #include "builtin.h"
 #include "parse-options.h"
+#include "refs.h"
+#include "strbuf.h"
 
-static int repo_info(int argc UNUSED, const char **argv UNUSED,
-		     const char *prefix UNUSED, struct repository *repo UNUSED)
+typedef int get_value_fn(struct repository *repo, struct strbuf *buf);
+
+struct field {
+	const char *key;
+	get_value_fn *get_value;
+};
+
+static int get_references_format(struct repository *repo, struct strbuf *buf)
+{
+	strbuf_addstr(buf,
+		      ref_storage_format_to_name(repo->ref_storage_format));
+	return 0;
+}
+
+/* repo_info_fields keys should be in lexicographical order */
+static const struct field repo_info_fields[] = {
+	{ "references.format", get_references_format },
+};
+
+static int repo_info_fields_cmp(const void *va, const void *vb)
+{
+	const struct field *a = va;
+	const struct field *b = vb;
+
+	return strcmp(a->key, b->key);
+}
+
+static get_value_fn *get_value_fn_for_key(const char *key)
+{
+	const struct field search_key = { key, NULL };
+	const struct field *found = bsearch(&search_key, repo_info_fields,
+					    ARRAY_SIZE(repo_info_fields),
+					    sizeof(*found),
+					    repo_info_fields_cmp);
+	return found ? found->get_value : NULL;
+}
+
+static int qsort_strcmp(const void *va, const void *vb)
 {
+	const char *a = *(const char **)va;
+	const char *b = *(const char **)vb;
+
+	return strcmp(a, b);
+}
+
+static int print_fields(int argc, const char **argv, struct repository *repo)
+{
+	const char *last = "";
+
+	QSORT(argv, argc, qsort_strcmp);
+
+	for (int i = 0; i < argc; i++) {
+		get_value_fn *get_value;
+		const char *key = argv[i];
+		struct strbuf value;
+
+		if (!strcmp(key, last))
+			continue;
+
+		strbuf_init(&value, 64);
+		get_value = get_value_fn_for_key(key);
+
+		if (!get_value) {
+			strbuf_release(&value);
+			return error(_("key '%s' not found"), key);
+		}
+
+		get_value(repo, &value);
+		printf("%s=%s\n", key, value.buf);
+		last = key;
+		strbuf_release(&value);
+	}
+
 	return 0;
 }
 
+static int repo_info(int argc, const char **argv, const char *prefix UNUSED,
+		     struct repository *repo)
+{
+	return print_fields(argc - 1, argv + 1, repo);
+}
+
 int cmd_repo(int argc, const char **argv, const char *prefix,
 	     struct repository *repo)
 {
diff --git a/t/meson.build b/t/meson.build
index 660d780dcc..5de9c3c7e9 100644
--- a/t/meson.build
+++ b/t/meson.build
@@ -245,6 +245,7 @@ integration_tests = [
   't1700-split-index.sh',
   't1701-racy-split-index.sh',
   't1800-hook.sh',
+  't1900-repo.sh',
   't2000-conflict-when-checking-files-out.sh',
   't2002-checkout-cache-u.sh',
   't2003-checkout-cache-mkdir.sh',
diff --git a/t/t1900-repo.sh b/t/t1900-repo.sh
new file mode 100755
index 0000000000..cc54b0644d
--- /dev/null
+++ b/t/t1900-repo.sh
@@ -0,0 +1,57 @@
+#!/bin/sh
+
+test_description='test git repo-info'
+
+. ./test-lib.sh
+
+# Test if a field is correctly returned in the null-terminated format
+#
+# Usage: test_repo_info <label> <init command> <key> <expected value>
+#
+# Arguments:
+#   label: the label of the test
+#   init command: a command that creates a repository called 'repo', configured
+#      accordingly to what is being tested
+#   key: the key of the field that is being tested
+#   expected value: the value that the field should contain
+test_repo_info () {
+	label=$1
+	init_command=$2
+	key=$3
+	expected_value=$4
+
+	test_expect_success "$label" '
+		test_when_finished "rm -rf repo" &&
+		eval "$init_command" &&
+		echo "$expected_value" >expected &&
+		git -C repo repo info "$key" >output &&
+		cut -d "=" -f 2 <output >actual &&
+		test_cmp expected actual
+	'
+}
+
+test_repo_info 'ref format files is retrieved correctly' '
+	git init --ref-format=files repo' 'references.format' 'files'
+
+test_repo_info 'ref format reftable is retrieved correctly' '
+	git init --ref-format=reftable repo' 'references.format' 'reftable'
+
+test_expect_success 'git-repo-info aborts if an invalid key is requested' '
+	test_when_finished "rm -rf expected err" &&
+	echo "error: key '\'foo\'' not found" >expected &&
+	test_must_fail git repo info foo 2>err &&
+	test_cmp expected err
+'
+
+test_expect_success "only one value is returned if the same key is requested twice" '
+	test_when_finished "rm -f expected_key expected_value actual_key actual_value output" &&
+	echo "references.format" >expected_key &&
+	git rev-parse --show-ref-format >expected_value &&
+	git repo info references.format references.format >output &&
+	cut -d "=" -f 1 <output >actual_key &&
+	cut -d "=" -f 2 <output >actual_value &&
+        test_cmp expected_key actual_key &&
+        test_cmp expected_value actual_value
+'
+
+test_done
-- 
2.39.5 (Apple Git-154)
^ permalink raw reply related	[flat|nested] 226+ messages in thread
* [GSoC PATCH v5 3/5] repo: add field layout.bare
  2025-07-27 17:51 ` [GSoC PATCH v5 0/5] repo: add new command for retrieving repository info Lucas Seiki Oshiro
  2025-07-27 17:51   ` [GSoC PATCH v5 1/5] repo: declare the repo command Lucas Seiki Oshiro
  2025-07-27 17:51   ` [GSoC PATCH v5 2/5] repo: add the field references.format Lucas Seiki Oshiro
@ 2025-07-27 17:51   ` Lucas Seiki Oshiro
  2025-07-27 17:51   ` [GSoC PATCH v5 4/5] repo: add field layout.shallow Lucas Seiki Oshiro
                     ` (2 subsequent siblings)
  5 siblings, 0 replies; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-07-27 17:51 UTC (permalink / raw)
  To: git
  Cc: oswald.buddenhagen, ps, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler, jn.avila, Lucas Seiki Oshiro
This commit is part of the series that introduces the new subcommand
git-repo-info.
The flag --is-bare-repository from git-rev-parse is used for retrieving
whether the current repository is bare. This way, it is used for
querying repository metadata, fitting in the purpose of git-repo-info.
Then, add a new field layout.bare to the git-repo-info subcommand
containing that information.
Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Helped-by: Junio C Hamano <gitster@pobox.com>
Helped-by: Justin Tobler <jltobler@gmail.com>
Mentored-by: Karthik Nayak <karthik.188@gmail.com>
Mentored-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
---
 Documentation/git-repo.adoc |  4 ++++
 builtin/repo.c              | 11 +++++++++++
 t/t1900-repo.sh             |  6 ++++++
 3 files changed, 21 insertions(+)
diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc
index ac2578299f..d52f4666be 100644
--- a/Documentation/git-repo.adoc
+++ b/Documentation/git-repo.adoc
@@ -33,6 +33,10 @@ categories:
 Reference-related data:
 * `format`: the reference storage format
 
+`layout`::
+Information about the how the current repository is represented:
+* `bare`: `true` if this is a bare repository, otherwise `false`.
+
 SEE ALSO
 --------
 linkgit:git-rev-parse[1]
diff --git a/builtin/repo.c b/builtin/repo.c
index 02d5821c77..2aba6a39c7 100644
--- a/builtin/repo.c
+++ b/builtin/repo.c
@@ -1,4 +1,7 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
 #include "builtin.h"
+#include "environment.h"
 #include "parse-options.h"
 #include "refs.h"
 #include "strbuf.h"
@@ -10,6 +13,13 @@ struct field {
 	get_value_fn *get_value;
 };
 
+static int get_layout_bare(struct repository *repo UNUSED, struct strbuf *buf)
+{
+	strbuf_addstr(buf,
+		      is_bare_repository() ? "true" : "false");
+	return 0;
+}
+
 static int get_references_format(struct repository *repo, struct strbuf *buf)
 {
 	strbuf_addstr(buf,
@@ -19,6 +29,7 @@ static int get_references_format(struct repository *repo, struct strbuf *buf)
 
 /* repo_info_fields keys should be in lexicographical order */
 static const struct field repo_info_fields[] = {
+	{ "layout.bare", get_layout_bare },
 	{ "references.format", get_references_format },
 };
 
diff --git a/t/t1900-repo.sh b/t/t1900-repo.sh
index cc54b0644d..7304629cb2 100755
--- a/t/t1900-repo.sh
+++ b/t/t1900-repo.sh
@@ -36,6 +36,12 @@ test_repo_info 'ref format files is retrieved correctly' '
 test_repo_info 'ref format reftable is retrieved correctly' '
 	git init --ref-format=reftable repo' 'references.format' 'reftable'
 
+test_repo_info 'bare repository = false is retrieved correctly' '
+	git init repo' 'layout.bare' 'false'
+
+test_repo_info 'bare repository = true is retrieved correctly' '
+	git init --bare repo' 'layout.bare' 'true'
+
 test_expect_success 'git-repo-info aborts if an invalid key is requested' '
 	test_when_finished "rm -rf expected err" &&
 	echo "error: key '\'foo\'' not found" >expected &&
-- 
2.39.5 (Apple Git-154)
^ permalink raw reply related	[flat|nested] 226+ messages in thread
* [GSoC PATCH v5 4/5] repo: add field layout.shallow
  2025-07-27 17:51 ` [GSoC PATCH v5 0/5] repo: add new command for retrieving repository info Lucas Seiki Oshiro
                     ` (2 preceding siblings ...)
  2025-07-27 17:51   ` [GSoC PATCH v5 3/5] repo: add field layout.bare Lucas Seiki Oshiro
@ 2025-07-27 17:51   ` Lucas Seiki Oshiro
  2025-07-27 21:45     ` Eric Sunshine
  2025-07-27 17:51   ` [GSoC PATCH v5 5/5] repo: add the --format flag Lucas Seiki Oshiro
  2025-07-27 20:11   ` [GSoC PATCH v5 0/5] repo: add new command for retrieving repository info Eric Sunshine
  5 siblings, 1 reply; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-07-27 17:51 UTC (permalink / raw)
  To: git
  Cc: oswald.buddenhagen, ps, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler, jn.avila, Lucas Seiki Oshiro
This commit is part of the series that introduces the new subcommand
git-repo-info.
The flag `--is-shallow-repository` from git-rev-parse is used for
retrieving whether the repository is shallow. This way, it is used for
querying repository metadata, fitting in the purpose of git-repo-info.
Then, add a new field `layout.shallow` to the git-repo-info subcommand
containing that information.
Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Helped-by: Junio C Hamano <gitster@pobox.com>
Helped-by: Justin Tobler <jltobler@gmail.com>
Mentored-by: Karthik Nayak <karthik.188@gmail.com>
Mentored-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
---
 Documentation/git-repo.adoc |  1 +
 builtin/repo.c              |  9 +++++++++
 t/t1900-repo.sh             | 21 +++++++++++++++++++++
 3 files changed, 31 insertions(+)
diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc
index d52f4666be..3f920b619f 100644
--- a/Documentation/git-repo.adoc
+++ b/Documentation/git-repo.adoc
@@ -36,6 +36,7 @@ Reference-related data:
 `layout`::
 Information about the how the current repository is represented:
 * `bare`: `true` if this is a bare repository, otherwise `false`.
+* `shallow`: `true` if this is a shallow repository, otherwise `false`.
 
 SEE ALSO
 --------
diff --git a/builtin/repo.c b/builtin/repo.c
index 2aba6a39c7..37fb1803f6 100644
--- a/builtin/repo.c
+++ b/builtin/repo.c
@@ -5,6 +5,7 @@
 #include "parse-options.h"
 #include "refs.h"
 #include "strbuf.h"
+#include "shallow.h"
 
 typedef int get_value_fn(struct repository *repo, struct strbuf *buf);
 
@@ -20,6 +21,13 @@ static int get_layout_bare(struct repository *repo UNUSED, struct strbuf *buf)
 	return 0;
 }
 
+static int get_layout_shallow(struct repository *repo, struct strbuf *buf)
+{
+	strbuf_addstr(buf,
+		      is_repository_shallow(repo) ? "true" : "false");
+	return 0;
+}
+
 static int get_references_format(struct repository *repo, struct strbuf *buf)
 {
 	strbuf_addstr(buf,
@@ -30,6 +38,7 @@ static int get_references_format(struct repository *repo, struct strbuf *buf)
 /* repo_info_fields keys should be in lexicographical order */
 static const struct field repo_info_fields[] = {
 	{ "layout.bare", get_layout_bare },
+	{ "layout.shallow", get_layout_shallow },
 	{ "references.format", get_references_format },
 };
 
diff --git a/t/t1900-repo.sh b/t/t1900-repo.sh
index 7304629cb2..0bdbf6911e 100755
--- a/t/t1900-repo.sh
+++ b/t/t1900-repo.sh
@@ -42,6 +42,20 @@ test_repo_info 'bare repository = false is retrieved correctly' '
 test_repo_info 'bare repository = true is retrieved correctly' '
 	git init --bare repo' 'layout.bare' 'true'
 
+test_repo_info 'shallow repository = false is retrieved correctly' '
+	git init repo' 'layout.shallow' 'false'
+
+test_repo_info 'shallow repository = true is retrieved correctly' '
+	git init remote &&
+	cd remote &&
+	echo x >x &&
+	git add x &&
+	git commit -m x &&
+	cd .. &&
+	git clone --depth 1 "file://$PWD/remote" repo &&
+	rm -rf remote
+	' 'layout.shallow' 'true'
+
 test_expect_success 'git-repo-info aborts if an invalid key is requested' '
 	test_when_finished "rm -rf expected err" &&
 	echo "error: key '\'foo\'' not found" >expected &&
@@ -60,4 +74,11 @@ test_expect_success "only one value is returned if the same key is requested twi
         test_cmp expected_value actual_value
 '
 
+test_expect_success 'output is returned correctly when two keys are requested' '
+	test_when_finished "rm -f expect" &&
+	printf "layout.bare=false\nlayout.shallow=false\n" >expect &&
+	git repo info layout.shallow layout.bare >actual &&
+	test_cmp expect actual
+'
+
 test_done
-- 
2.39.5 (Apple Git-154)
^ permalink raw reply related	[flat|nested] 226+ messages in thread
* [GSoC PATCH v5 5/5] repo: add the --format flag
  2025-07-27 17:51 ` [GSoC PATCH v5 0/5] repo: add new command for retrieving repository info Lucas Seiki Oshiro
                     ` (3 preceding siblings ...)
  2025-07-27 17:51   ` [GSoC PATCH v5 4/5] repo: add field layout.shallow Lucas Seiki Oshiro
@ 2025-07-27 17:51   ` Lucas Seiki Oshiro
  2025-07-27 22:02     ` Eric Sunshine
  2025-07-31 23:15     ` Lucas Seiki Oshiro
  2025-07-27 20:11   ` [GSoC PATCH v5 0/5] repo: add new command for retrieving repository info Eric Sunshine
  5 siblings, 2 replies; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-07-27 17:51 UTC (permalink / raw)
  To: git
  Cc: oswald.buddenhagen, ps, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler, jn.avila, Lucas Seiki Oshiro
Add the --format flag to git-repo-info. By using this flag, the users
can choose the format for obtaining the data they requested.
Given that this command can be used for generating input for other
applications and for being read by end users, it requires at least two
formats: one for being read by humans and other for being read by
machines. Some other Git commands also have two output formats, notably
git-config which was the inspiration for the two formats that were
chosen here:
- keyvalue, where the retrieved data is printed one per line, using =
  for delimiting the key and the value. This is the default format,
  targeted for end users.
- nul, where the retrieved data is separated by null characters, using
  the newline character for delimiting the key and the value. This
  format is targeted for being read by machines.
Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Helped-by: Junio C Hamano <gitster@pobox.com>
Helped-by: Justin Tobler <jltobler@gmail.com>
Mentored-by: Karthik Nayak <karthik.188@gmail.com>
Mentored-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
---
 Documentation/git-repo.adoc | 13 +++++++++-
 builtin/repo.c              | 49 ++++++++++++++++++++++++++++++++++---
 t/t1900-repo.sh             | 20 +++++++++++++--
 3 files changed, 75 insertions(+), 7 deletions(-)
diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc
index 3f920b619f..6cc3ff581c 100644
--- a/Documentation/git-repo.adoc
+++ b/Documentation/git-repo.adoc
@@ -18,10 +18,21 @@ THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOR MAY CHANGE.
 
 COMMANDS
 --------
-`info [<key>...]`::
+`info [--format=<format>] [<key>...]`::
 	Retrieve metadata-related information about the current repository. Only
 	the requested data will be returned based on their keys (see "INFO KEYS"
 	section below).
++
+The output format can be chosen through the flag `--format`. Two formats are
+supported:
++
+* `keyvalue`: output key-value pairs one per line using the `=` character as
+the delimiter between the key and the value. This is the default.
+
+* `nul`: similar to `keyvalue`, but using a newline character as the delimiter
+between the key and the value and using a null character after each value.
+This format is better suited for being parsed by another applications than
+`keyvalue`.
 
 INFO KEYS
 ---------
diff --git a/builtin/repo.c b/builtin/repo.c
index 37fb1803f6..a293d32b92 100644
--- a/builtin/repo.c
+++ b/builtin/repo.c
@@ -9,6 +9,11 @@
 
 typedef int get_value_fn(struct repository *repo, struct strbuf *buf);
 
+enum output_format {
+	FORMAT_KEYVALUE,
+	FORMAT_NUL_TERMINATED,
+};
+
 struct field {
 	const char *key;
 	get_value_fn *get_value;
@@ -68,9 +73,24 @@ static int qsort_strcmp(const void *va, const void *vb)
 	return strcmp(a, b);
 }
 
-static int print_fields(int argc, const char **argv, struct repository *repo)
+static int print_fields(int argc, const char **argv,
+			struct repository *repo,
+			enum output_format format)
 {
 	const char *last = "";
+	char kv_sep;
+	char field_sep;
+
+	switch (format) {
+	case FORMAT_KEYVALUE:
+		kv_sep = '=';
+		field_sep = '\n';
+		break;
+	case FORMAT_NUL_TERMINATED:
+		kv_sep = '\n';
+		field_sep = '\0';
+		break;
+	}
 
 	QSORT(argv, argc, qsort_strcmp);
 
@@ -91,7 +111,7 @@ static int print_fields(int argc, const char **argv, struct repository *repo)
 		}
 
 		get_value(repo, &value);
-		printf("%s=%s\n", key, value.buf);
+		printf("%s%c%s%c", key, kv_sep, value.buf, field_sep);
 		last = key;
 		strbuf_release(&value);
 	}
@@ -99,10 +119,31 @@ static int print_fields(int argc, const char **argv, struct repository *repo)
 	return 0;
 }
 
-static int repo_info(int argc, const char **argv, const char *prefix UNUSED,
+static int repo_info(int argc, const char **argv, const char *prefix,
 		     struct repository *repo)
 {
-	return print_fields(argc - 1, argv + 1, repo);
+	const char *format_str = "keyvalue";
+	enum output_format format;
+	const char *const repo_info_usage[] = {
+		"git repo info [<key>...]",
+		NULL
+	};
+	struct option options[] = {
+		OPT_STRING(0, "format", &format_str, N_("format"),
+			   N_("output format")),
+		OPT_END()
+	};
+
+	argc = parse_options(argc, argv, prefix, options, repo_info_usage, 0);
+
+	if (!strcmp(format_str, "keyvalue"))
+		format = FORMAT_KEYVALUE;
+	else if (!strcmp(format_str, "nul"))
+		format = FORMAT_NUL_TERMINATED;
+	else
+		die(_("invalid format '%s'"), format_str);
+
+	return print_fields(argc, argv, repo, format);
 }
 
 int cmd_repo(int argc, const char **argv, const char *prefix,
diff --git a/t/t1900-repo.sh b/t/t1900-repo.sh
index 0bdbf6911e..94a98c52f6 100755
--- a/t/t1900-repo.sh
+++ b/t/t1900-repo.sh
@@ -20,11 +20,20 @@ test_repo_info () {
 	key=$3
 	expected_value=$4
 
-	test_expect_success "$label" '
+	test_expect_success "null-terminated: $label" '
+		test_when_finished "rm -rf repo" &&
+		eval "$init_command" &&
+		echo "$expected_value" | lf_to_nul >expected &&
+		git -C repo repo info --format=nul "$key" >output &&
+		tail -n 1 output >actual &&
+		test_cmp expected actual
+	'
+
+	test_expect_success "key-value: $label" '
 		test_when_finished "rm -rf repo" &&
 		eval "$init_command" &&
 		echo "$expected_value" >expected &&
-		git -C repo repo info "$key" >output &&
+		git -C repo repo info --format=keyvalue "$key" >output &&
 		cut -d "=" -f 2 <output >actual &&
 		test_cmp expected actual
 	'
@@ -81,4 +90,11 @@ test_expect_success 'output is returned correctly when two keys are requested' '
 	test_cmp expect actual
 '
 
+test_expect_success 'git-repo-info aborts when requesting an invalid format' '
+	test_when_finished "rm -f err expected" &&
+	echo "fatal: invalid format '\'foo\''" >expected &&
+	test_must_fail git repo info --format=foo 2>err &&
+	test_cmp expected err
+'
+
 test_done
-- 
2.39.5 (Apple Git-154)
^ permalink raw reply related	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v5 0/5] repo: add new command for retrieving repository info
  2025-07-27 17:51 ` [GSoC PATCH v5 0/5] repo: add new command for retrieving repository info Lucas Seiki Oshiro
                     ` (4 preceding siblings ...)
  2025-07-27 17:51   ` [GSoC PATCH v5 5/5] repo: add the --format flag Lucas Seiki Oshiro
@ 2025-07-27 20:11   ` Eric Sunshine
  2025-07-29  9:35     ` Patrick Steinhardt
  2025-07-30 15:26     ` Lucas Seiki Oshiro
  5 siblings, 2 replies; 226+ messages in thread
From: Eric Sunshine @ 2025-07-27 20:11 UTC (permalink / raw)
  To: Lucas Seiki Oshiro
  Cc: git, oswald.buddenhagen, ps, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler, jn.avila
On Sun, Jul 27, 2025 at 1:51 PM Lucas Seiki Oshiro
<lucasseikioshiro@gmail.com> wrote:
> This v6 contains small fixes pointed in v5.
>
> In v5, Patrick and Junio were discussing about quoting the values in the
> key=value format using `quote_c_style` [1]. Given that it wouldn't affect
> this patchset and it's a simple change that can be done later, I didn't
> change it and I'll leave for further discussion when I start to deal
> with paths.
The counterargument to this stance is that if you employ
`quote_c_style` from the onset and document it, then if a future
version of Git does start outputting values containing "funny"
characters for properties which previously did not emit such values
(this isn't limited to paths), then consumers who heeded the
documentation won't find their tooling breaking suddenly. Tooling may
break for consumers who did not heed the documentation, but that will
be due to their own shortsightedness, not due to the Git project
failing to care about compatibility between versions. For this reason,
I'm of the opinion that `quote_c_style` should be used and documented
even at this very early stage.
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v5 1/5] repo: declare the repo command
  2025-07-27 17:51   ` [GSoC PATCH v5 1/5] repo: declare the repo command Lucas Seiki Oshiro
@ 2025-07-27 20:20     ` Eric Sunshine
  0 siblings, 0 replies; 226+ messages in thread
From: Eric Sunshine @ 2025-07-27 20:20 UTC (permalink / raw)
  To: Lucas Seiki Oshiro
  Cc: git, oswald.buddenhagen, ps, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler, jn.avila
On Sun, Jul 27, 2025 at 1:51 PM Lucas Seiki Oshiro
<lucasseikioshiro@gmail.com> wrote:
> Currently, `git rev-parse` covers a wide range of functionality not
> directly related to parsing revisions, as its name suggests. Over time,
> many features like parsing datestrings, options, paths, and others
> were added to it because there wasn't a more appropriate command
> to place them.
>
> Create a new Git command called `repo`. `git repo` will be the main
> command for obtaining the information about a repository (such as
> metadata and metrics).
>
> Also declare a subcommand for `repo` called `info`. `git repo info`
> will bring the functionality of retrieving repository-related
> information currently returned by `rev-parse`.
>
> Add the required tests, documentation and build changes to enable
> usage of this subcommand.
This talks about adding tests, however...
> Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
> ---
>  .gitignore                  |  1 +
>  Documentation/git-repo.adoc | 38 +++++++++++++++++++++++++++++++++++++
>  Documentation/meson.build   |  1 +
>  Makefile                    |  1 +
>  builtin.h                   |  1 +
>  builtin/repo.c              | 26 +++++++++++++++++++++++++
>  command-list.txt            |  1 +
>  git.c                       |  1 +
>  meson.build                 |  1 +
>  9 files changed, 71 insertions(+)
...no tests are added.
> diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc
> @@ -0,0 +1,38 @@
> +DESCRIPTION
> +-----------
> +This command retrieve repository level information.
s/retrieve/retrieves/
I'm a native English speaker, but I wonder if, rather than "repository
level", it would be more friendly to non-native speakers to instead
say:
    Retrieve information about the repository.
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v5 2/5] repo: add the field references.format
  2025-07-27 17:51   ` [GSoC PATCH v5 2/5] repo: add the field references.format Lucas Seiki Oshiro
@ 2025-07-27 21:16     ` Eric Sunshine
  2025-07-31 19:39       ` Lucas Seiki Oshiro
  2025-07-29  9:35     ` Patrick Steinhardt
  1 sibling, 1 reply; 226+ messages in thread
From: Eric Sunshine @ 2025-07-27 21:16 UTC (permalink / raw)
  To: Lucas Seiki Oshiro
  Cc: git, oswald.buddenhagen, ps, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler, jn.avila
On Sun, Jul 27, 2025 at 1:52 PM Lucas Seiki Oshiro
<lucasseikioshiro@gmail.com> wrote:
> This commit is part of the series that introduces the new subcommand
> git-repo-info.
>
> The flag `--show-ref-format` from git-rev-parse is used for retrieving
> the reference format (i.e. `files` or `reftable`). This way, it is
> used for querying repository metadata, fitting in the purpose of
> git-repo-info.
>
> Add a new field `references.format` to the repo-info subcommand
> containing that information.
>
> Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
> ---
> diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc
> @@ -29,6 +29,10 @@ INFO KEYS
>  The set of data that `git repo` can return is grouped into the following
>  categories:
>
> +`references`::
> +Reference-related data:
> +* `format`: the reference storage format
Based upon the implementation, I can see that the user must type the
key in "dotted" form:
    git repo info references.format
but I wonder if the above documentation actually conveys this
requirement. I don't think I would figure it out easily. Perhaps
hand-holding the user by giving an example would help.
> diff --git a/builtin/repo.c b/builtin/repo.c
> +/* repo_info_fields keys should be in lexicographical order */
> +static const struct field repo_info_fields[] = {
> +       { "references.format", get_references_format },
> +};
How can we ensure that the lexicographical-order requirement won't
break? If someone adds a new entry which is not in its proper place,
presumably that will be noticed because some existing test in a test
script will stop working, but it feels unnecessarily fragile and a bit
of a maintenance burden. Also, this requirement does feel like a
premature optimization. Do you expect this list to become so huge and
the corresponding lookup function to be called so frequently that a
simple brute-force linear search would be too slow?
> +static int qsort_strcmp(const void *va, const void *vb)
>  {
> +       const char *a = *(const char **)va;
> +       const char *b = *(const char **)vb;
> +
> +       return strcmp(a, b);
> +}
> +
> +static int print_fields(int argc, const char **argv, struct repository *repo)
> +{
> +       const char *last = "";
> +
> +       QSORT(argv, argc, qsort_strcmp);
I can see from the implementation that you are sorting the incoming
arguments in order to detect and fold out duplicates. However, that
raises a couple questions. First, is it really a good idea to do
something other than what the user asked for? Second, if this is a
good idea, then should the behavior be documented?
I can see arguments in favor of sorting and de-duplicating, as well as
in favor of producing exactly the (unordered) output the user asked
for, including duplicates, so I don't have a strong opinion either
way. But, if you do retain this behavior, then the sorting and
deduplication behaviors should probably be documented.
> +       for (int i = 0; i < argc; i++) {
> +               get_value_fn *get_value;
> +               const char *key = argv[i];
> +               struct strbuf value;
> +
> +               if (!strcmp(key, last))
> +                       continue;
> +
> +               strbuf_init(&value, 64);
> +               get_value = get_value_fn_for_key(key);
> +
> +               if (!get_value) {
> +                       strbuf_release(&value);
> +                       return error(_("key '%s' not found"), key);
> +               }
> +
> +               get_value(repo, &value);
A couple observations:
First, you don't actually use the strbuf until the call to
get_value(), so the strbuf_init() call seems to be too early, with the
result that you need a corresponding strbuf_release() in the error
branch. If you move the strbuf_init() so it occurs immediately before
get_value(), then you can simplify the early exit case.
Second, this seems to be getting unnecessarily intimate with strbuf. I
can guess that you're doing this late strbuf_init() to avoid an
allocation in the case when a duplicate key was encountered, however,
STRBUF_INIT doesn't actually perform an allocation, so it would be
clearer to just initialize the strbuf at the time you declare it
rather than calling strbuf_init() manually. However...
Although it is a micro optimization (as well as a
premature-optimization), it is far more common in this code base to
hoist the strbuf outside of the loop and instead call strbuf_reset()
it upon each iteration:
    struct strbuf value = STRBUF_INIT;
    for (...) {
        strbuf_reset(&value);
        ...
        if (error_condition) {
            strbuf_release(...);
            return error(...);
        }
       ...
    }
    strbuf_release(...);
> +               printf("%s=%s\n", key, value.buf);
> +               last = key;
> +               strbuf_release(&value);
> +       }
> +
>         return 0;
>  }
Looking at this from a higher level, is it presenting a good
user-experience by potentially printing some output but then erroring
out upon the first unrecognized key? Would the user-experience be
improved by instead continuing the loop even after reporting an error,
and then adjusting the final `return 0` to conditionally return
success or error depending upon whether any keys were unrecognized?
> diff --git a/t/t1900-repo.sh b/t/t1900-repo.sh
> @@ -0,0 +1,57 @@
> +#!/bin/sh
> +
> +test_description='test git repo-info'
> +
> +. ./test-lib.sh
> +
> +# Test if a field is correctly returned in the null-terminated format
This is talking about null-terminated format, but the implementation
doesn't seem to emit NUL-terminated output at all.
> +# Usage: test_repo_info <label> <init command> <key> <expected value>
> +#
> +# Arguments:
> +#   label: the label of the test
> +#   init command: a command that creates a repository called 'repo', configured
> +#      accordingly to what is being tested
> +#   key: the key of the field that is being tested
> +#   expected value: the value that the field should contain
> +test_repo_info () {
> +       label=$1
> +       init_command=$2
> +       key=$3
> +       expected_value=$4
> +
> +       test_expect_success "$label" '
> +               test_when_finished "rm -rf repo" &&
> +               eval "$init_command" &&
> +               echo "$expected_value" >expected &&
> +               git -C repo repo info "$key" >output &&
> +               cut -d "=" -f 2 <output >actual &&
> +               test_cmp expected actual
> +       '
> +}
It seems that this could be simplified by crafting the expected output
more precisely?
    eval ... &&
    echo "$key=$expected_value" >expect &&
    git -C repo repo info "$key" >actual &&
    test_cmp expect actual
By the way, we typically avoid cleaning up test detritus merely for
the sake of cleaning up because doing so slows down the already
too-slow test suite. Instead, cleanup is usually only performed when
absolutely necessary to avoid some undesirable interaction between
tests. Avoiding cleanup also makes it easier to debug failed tests
since (hopefully) the cause of the failure is still present in the
"trash" directory.
In this case, if you call this function with a distinct repository
name each time, then you don't have to remove the repository at all.
Moreover, giving each repository a distinct and _meaningful_ name,
rather than reusing the same name, could also be helpful when
diagnosing failures.
> +test_repo_info 'ref format files is retrieved correctly' '
> +       git init --ref-format=files repo' 'references.format' 'files'
> +
> +test_repo_info 'ref format reftable is retrieved correctly' '
> +       git init --ref-format=reftable repo' 'references.format' 'reftable'
This is overly fragile. The `test_repo_info` function hardcodes the
name "repo" but then the caller is also expected to pass in the name
as part of the initialization argument (i.e. `git init ... repo`). To
make this more robust, either don't hardcode it in the function, or
stop expecting the caller to supply the name as part of the
initialization argument.
With only two callers, it's not clear at this point whether the
`test_repo_info` function is providing any added value, especially
since the additional abstraction increases cognitive load, but perhaps
later patches in this series add more callers?
> +test_expect_success 'git-repo-info aborts if an invalid key is requested' '
> +       test_when_finished "rm -rf expected err" &&
> +       echo "error: key '\'foo\'' not found" >expected &&
> +       test_must_fail git repo info foo 2>err &&
> +       test_cmp expected err
> +'
> +
> +test_expect_success "only one value is returned if the same key is requested twice" '
This test title can be single-quoted rather than double-quoted.
> +       test_when_finished "rm -f expected_key expected_value actual_key actual_value output" &&
> +       echo "references.format" >expected_key &&
> +       git rev-parse --show-ref-format >expected_value &&
> +       git repo info references.format references.format >output &&
> +       cut -d "=" -f 1 <output >actual_key &&
> +       cut -d "=" -f 2 <output >actual_value &&
> +        test_cmp expected_key actual_key &&
> +        test_cmp expected_value actual_value
> +'
As above, it seems that this could be simplified by crafting the
expected state more precisely rather than slicing and dicing the
actual output. Perhaps something like this?
    val=$(git rev-parse --show-ref-format) &&
    echo "references.format=$val" >expect &&
    git repo info references.format references.format >actual &&
    test_cmp expect actual
Aside from the above tests, based upon the implementation, I also
expected to find a test checking that the command correctly outputs
multiple values, but perhaps a later patch adds that since, presently,
the implementation only knows "references.format" (thus with
deduplication, you can't yet implement such a test).
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v5 4/5] repo: add field layout.shallow
  2025-07-27 17:51   ` [GSoC PATCH v5 4/5] repo: add field layout.shallow Lucas Seiki Oshiro
@ 2025-07-27 21:45     ` Eric Sunshine
  0 siblings, 0 replies; 226+ messages in thread
From: Eric Sunshine @ 2025-07-27 21:45 UTC (permalink / raw)
  To: Lucas Seiki Oshiro
  Cc: git, oswald.buddenhagen, ps, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler, jn.avila
On Sun, Jul 27, 2025 at 1:52 PM Lucas Seiki Oshiro
<lucasseikioshiro@gmail.com> wrote:
> This commit is part of the series that introduces the new subcommand
> git-repo-info.
>
> The flag `--is-shallow-repository` from git-rev-parse is used for
> retrieving whether the repository is shallow. This way, it is used for
> querying repository metadata, fitting in the purpose of git-repo-info.
>
> Then, add a new field `layout.shallow` to the git-repo-info subcommand
> containing that information.
>
> Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
> ---
> diff --git a/t/t1900-repo.sh b/t/t1900-repo.sh
> @@ -42,6 +42,20 @@ test_repo_info 'bare repository = false is retrieved correctly' '
> +test_repo_info 'shallow repository = true is retrieved correctly' '
> +       git init remote &&
> +       cd remote &&
> +       echo x >x &&
> +       git add x &&
> +       git commit -m x &&
> +       cd .. &&
> +       git clone --depth 1 "file://$PWD/remote" repo &&
> +       rm -rf remote
> +       ' 'layout.shallow' 'true'
If a command fails between the `cd remote` and the `cd ..`, then the
test will abort while the working directory is still "remote", and
every subsequent test will then run in the wrong directory (because
the tests are not isolated from one another in that way). So, the rule
is: never use `cd` outside of a subshell. Therefore, you want to do
something like this:
    git init remote &&
    (
        cd remote &&
        echo x >x &&
        git add x &&
        git commit -m x
    )
    git clone --depth 1 "file://$PWD/remote" repo &&
    rm -rf remote
Alternatively, you could avoid `cd` entirely:
    git init remote &&
    echo x >remote/x &&
    git -C remote add x &&
    git -C remote commit -m x &&
    git clone --depth 1 "file://$PWD/remote" repo &&
    rm -rf remote
The choice is subjective, though I find that I can spot the secondary
repository more easily in the first example.
As I noted in my review of an earlier patch in this series, we don't
usually clean up just for the sake of cleaning up since doing so makes
it more difficult to diagnose a failed test and slows down the test
suite, so you could probably also drop the `rm -rf remote.
> @@ -60,4 +74,11 @@ test_expect_success "only one value is returned if the same key is requested twi
> +test_expect_success 'output is returned correctly when two keys are requested' '
I think this test could have been added in the previous patch (and
it's where I was expecting to find it).
> +       test_when_finished "rm -f expect" &&
> +       printf "layout.bare=false\nlayout.shallow=false\n" >expect &&
This could be made a bit easier to read either like this:
    test_write_lines layout.bare=false layout.shallow=false >expect &&
or like this:
    cat >expect <<-\EOF
    layout.bare=false
    layout.shallow=false
    EOF
It's subjective, but I find the latter example to be more obvious at a glance.
> +       git repo info layout.shallow layout.bare >actual &&
> +       test_cmp expect actual
> +'
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v5 5/5] repo: add the --format flag
  2025-07-27 17:51   ` [GSoC PATCH v5 5/5] repo: add the --format flag Lucas Seiki Oshiro
@ 2025-07-27 22:02     ` Eric Sunshine
  2025-07-29  0:15       ` Ben Knoble
  2025-07-31 23:01       ` Lucas Seiki Oshiro
  2025-07-31 23:15     ` Lucas Seiki Oshiro
  1 sibling, 2 replies; 226+ messages in thread
From: Eric Sunshine @ 2025-07-27 22:02 UTC (permalink / raw)
  To: Lucas Seiki Oshiro
  Cc: git, oswald.buddenhagen, ps, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler, jn.avila
On Sun, Jul 27, 2025 at 2:02 PM Lucas Seiki Oshiro
<lucasseikioshiro@gmail.com> wrote:
> Add the --format flag to git-repo-info. By using this flag, the users
> can choose the format for obtaining the data they requested.
> [...]
> - keyvalue, where the retrieved data is printed one per line, using =
>   for delimiting the key and the value. This is the default format,
>   targeted for end users.
> - nul, where the retrieved data is separated by null characters, using
>   the newline character for delimiting the key and the value. This
>   format is targeted for being read by machines.
>
> Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
> ---
> diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc
> @@ -18,10 +18,21 @@ THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOR MAY CHANGE.
> +`info [--format=<format>] [<key>...]`::
> ++
> +The output format can be chosen through the flag `--format`. Two formats are
> +supported:
> ++
> +* `keyvalue`: output key-value pairs one per line using the `=` character as
> +the delimiter between the key and the value. This is the default.
> +
> +* `nul`: similar to `keyvalue`, but using a newline character as the delimiter
> +between the key and the value and using a null character after each value.
> +This format is better suited for being parsed by another applications than
> +`keyvalue`.
s/another/other/
I haven't been following the discussion around this series, but don't
we also usually provide a `-z` short option? Should that be added for
consistency with other commands and to avoid surprising users, or is
it too early to commit to that?
> diff --git a/t/t1900-repo.sh b/t/t1900-repo.sh
> @@ -20,11 +20,20 @@ test_repo_info () {
> +       test_expect_success "null-terminated: $label" '
> +               test_when_finished "rm -rf repo" &&
> +               eval "$init_command" &&
> +               echo "$expected_value" | lf_to_nul >expected &&
Simpler:
    printf "$expected_value\0" >expected &&
> +               git -C repo repo info --format=nul "$key" >output &&
> +               tail -n 1 output >actual &&
> +               test_cmp expected actual
> +       '
How confident are we that `tail -n 1 output >actual` is going to
perform as expected across platforms and versions of those platforms?
It feels awfully fragile to me. Why slice and dice the output anyhow
rather than merely crafting the correct expected output in the first
place and comparing that directly against the actual output? In other
words, something like this:
    printf "$key\n$expected_value\0" >expect &&
    git -C repo repo info --format=nul "$key" >actual &&
    test_cmp_bin expect actual
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v5 1/5] repo: declare the repo command
  2025-07-26 21:54           ` Lucas Seiki Oshiro
@ 2025-07-28 17:56             ` Junio C Hamano
  0 siblings, 0 replies; 226+ messages in thread
From: Junio C Hamano @ 2025-07-28 17:56 UTC (permalink / raw)
  To: Lucas Seiki Oshiro
  Cc: Patrick Steinhardt, Karthik Nayak, git, oswald.buddenhagen,
	ben.knoble, phillip.wood, jltobler
Lucas Seiki Oshiro <lucasseikioshiro@gmail.com> writes:
> Hmmm... I'm thinking about what is the "right thing" in this context.
> For example, `git config --list` doesn't quote when in its key=value
> format. Perhaps I'm citing `git config --list` too much :-), but it is
> because is the closer command to `git-repo-info` in that sense.
Yup.  If we do need to support non-z output format and keep it
parseable, I am afraid that we cannot avoid quoting.
An old mistake is not a good excuse to repeat the same one.  Even
though the config key names forbid <LF> and <NUL>, "git config
--list" still cannot be used without "-z" when the keys may contain
"=", for example, if the caller wants to parse the output correctly
because it was misdesigned to not use any quoting.
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v5 5/5] repo: add the --format flag
  2025-07-27 22:02     ` Eric Sunshine
@ 2025-07-29  0:15       ` Ben Knoble
  2025-07-29  0:27         ` Eric Sunshine
  2025-07-31 23:01       ` Lucas Seiki Oshiro
  1 sibling, 1 reply; 226+ messages in thread
From: Ben Knoble @ 2025-07-29  0:15 UTC (permalink / raw)
  To: Eric Sunshine
  Cc: Lucas Seiki Oshiro, git, oswald.buddenhagen, ps, karthik.188,
	gitster, phillip.wood, jltobler, jn.avila
> Le 27 juil. 2025 à 18:02, Eric Sunshine <sunshine@sunshineco.com> a écrit :
> 
> On Sun, Jul 27, 2025 at 2:02 PM Lucas Seiki Oshiro
> <lucasseikioshiro@gmail.com> wrote:
> 
>> diff --git a/t/t1900-repo.sh b/t/t1900-repo.sh
>> @@ -20,11 +20,20 @@ test_repo_info () {
>> +       test_expect_success "null-terminated: $label" '
>> +               test_when_finished "rm -rf repo" &&
>> +               eval "$init_command" &&
>> +               echo "$expected_value" | lf_to_nul >expected &&
> 
> Simpler:
> 
>    printf "$expected_value\0" >expected &&
(Below as well): the shell linter I use does prefer to see
    printf %s\\0 "$var"
to avoid issues with the variable containing format specifiers. 
(Backslash has to be quoted in double-quotes, too, I think? So I left out the quotes here.)
> 
>> +               git -C repo repo info --format=nul "$key" >output &&
>> +               tail -n 1 output >actual &&
>> +               test_cmp expected actual
>> +       '
> 
> How confident are we that `tail -n 1 output >actual` is going to
> perform as expected across platforms and versions of those platforms?
> It feels awfully fragile to me. Why slice and dice the output anyhow
> rather than merely crafting the correct expected output in the first
> place and comparing that directly against the actual output? In other
> words, something like this:
> 
>    printf "$key\n$expected_value\0" >expect &&
>    git -C repo repo info --format=nul "$key" >actual &&
>    test_cmp_bin expect actual
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v5 5/5] repo: add the --format flag
  2025-07-29  0:15       ` Ben Knoble
@ 2025-07-29  0:27         ` Eric Sunshine
  2025-07-29  0:38           ` Ben Knoble
  2025-07-29  0:39           ` Eric Sunshine
  0 siblings, 2 replies; 226+ messages in thread
From: Eric Sunshine @ 2025-07-29  0:27 UTC (permalink / raw)
  To: Ben Knoble
  Cc: Lucas Seiki Oshiro, git, oswald.buddenhagen, ps, karthik.188,
	gitster, phillip.wood, jltobler, jn.avila
On Mon, Jul 28, 2025 at 8:15 PM Ben Knoble <ben.knoble@gmail.com> wrote:
> > Le 27 juil. 2025 à 18:02, Eric Sunshine <sunshine@sunshineco.com> a écrit :
> > Simpler:
> >    printf "$expected_value\0" >expected &&
>
> (Below as well): the shell linter I use does prefer to see
>
>     printf %s\\0 "$var"
>
> to avoid issues with the variable containing format specifiers.
That's a very good point about using "%s"; I should have suggested
that myself. Thanks for the correction.
> (Backslash has to be quoted in double-quotes, too, I think? So I left out the quotes here.)
No, backslash does not need to be escaped in double-quotes. The
literal form `printf "%s\0"` is common enough in Git test scripts, so,
for consistency, that should be the form we recommend in reviews, not
the form lacking quotes, I'd think.
Taking the above into consideration, the recommendation for Lucas
would, therefore, be:
    printf "%s\0" $expected_value >expected &&
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v5 5/5] repo: add the --format flag
  2025-07-29  0:27         ` Eric Sunshine
@ 2025-07-29  0:38           ` Ben Knoble
  2025-07-29  0:39           ` Eric Sunshine
  1 sibling, 0 replies; 226+ messages in thread
From: Ben Knoble @ 2025-07-29  0:38 UTC (permalink / raw)
  To: Eric Sunshine
  Cc: Lucas Seiki Oshiro, git, oswald.buddenhagen, ps, karthik.188,
	gitster, phillip.wood, jltobler, jn.avila
> Le 28 juil. 2025 à 20:27, Eric Sunshine <sunshine@sunshineco.com> a écrit :
> 
> On Mon, Jul 28, 2025 at 8:15 PM Ben Knoble <ben.knoble@gmail.com> wrote:
>>>> Le 27 juil. 2025 à 18:02, Eric Sunshine <sunshine@sunshineco.com> a écrit :
>>> Simpler:
>>>   printf "$expected_value\0" >expected &&
>> 
>> (Below as well): the shell linter I use does prefer to see
>> 
>>    printf %s\\0 "$var"
>> 
>> to avoid issues with the variable containing format specifiers.
> 
> That's a very good point about using "%s"; I should have suggested
> that myself. Thanks for the correction.
> 
>> (Backslash has to be quoted in double-quotes, too, I think? So I left out the quotes here.)
> 
> No, backslash does not need to be escaped in double-quotes. The
> literal form `printf "%s\0"` is common enough in Git test scripts, so,
> for consistency, that should be the form we recommend in reviews, not
> the form lacking quotes, I'd think.
Right; on second thought, shell quotes (mostly) don’t nest like that. Thanks for the catch. 
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v5 5/5] repo: add the --format flag
  2025-07-29  0:27         ` Eric Sunshine
  2025-07-29  0:38           ` Ben Knoble
@ 2025-07-29  0:39           ` Eric Sunshine
  1 sibling, 0 replies; 226+ messages in thread
From: Eric Sunshine @ 2025-07-29  0:39 UTC (permalink / raw)
  To: Ben Knoble
  Cc: Lucas Seiki Oshiro, git, oswald.buddenhagen, ps, karthik.188,
	gitster, phillip.wood, jltobler, jn.avila
On Mon, Jul 28, 2025 at 8:27 PM Eric Sunshine <sunshine@sunshineco.com> wrote:
> Taking the above into consideration, the recommendation for Lucas
> would, therefore, be:
>
>     printf "%s\0" $expected_value >expected &&
Of course, I accidentally forgot the quotes around the variable
expansion. I should have said:
    printf "%s\0" "$expected_value" >expected &&
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v5 0/5] repo: add new command for retrieving repository info
  2025-07-27 20:11   ` [GSoC PATCH v5 0/5] repo: add new command for retrieving repository info Eric Sunshine
@ 2025-07-29  9:35     ` Patrick Steinhardt
  2025-07-30 15:26     ` Lucas Seiki Oshiro
  1 sibling, 0 replies; 226+ messages in thread
From: Patrick Steinhardt @ 2025-07-29  9:35 UTC (permalink / raw)
  To: Eric Sunshine
  Cc: Lucas Seiki Oshiro, git, oswald.buddenhagen, karthik.188,
	ben.knoble, gitster, phillip.wood, jltobler, jn.avila
On Sun, Jul 27, 2025 at 04:11:57PM -0400, Eric Sunshine wrote:
> On Sun, Jul 27, 2025 at 1:51 PM Lucas Seiki Oshiro
> <lucasseikioshiro@gmail.com> wrote:
> > This v6 contains small fixes pointed in v5.
> >
> > In v5, Patrick and Junio were discussing about quoting the values in the
> > key=value format using `quote_c_style` [1]. Given that it wouldn't affect
> > this patchset and it's a simple change that can be done later, I didn't
> > change it and I'll leave for further discussion when I start to deal
> > with paths.
> 
> The counterargument to this stance is that if you employ
> `quote_c_style` from the onset and document it, then if a future
> version of Git does start outputting values containing "funny"
> characters for properties which previously did not emit such values
> (this isn't limited to paths), then consumers who heeded the
> documentation won't find their tooling breaking suddenly. Tooling may
> break for consumers who did not heed the documentation, but that will
> be due to their own shortsightedness, not due to the Git project
> failing to care about compatibility between versions. For this reason,
> I'm of the opinion that `quote_c_style` should be used and documented
> even at this very early stage.
Likewise, I think we should do it now already. In general I don't think
it should matter much given that tooling should use NUL-terminated modes
anyway. But it's a rather simple change, so I don't see a strong reason
to push it into the future.
Patrick
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v5 2/5] repo: add the field references.format
  2025-07-27 17:51   ` [GSoC PATCH v5 2/5] repo: add the field references.format Lucas Seiki Oshiro
  2025-07-27 21:16     ` Eric Sunshine
@ 2025-07-29  9:35     ` Patrick Steinhardt
  2025-07-31 19:49       ` Lucas Seiki Oshiro
  1 sibling, 1 reply; 226+ messages in thread
From: Patrick Steinhardt @ 2025-07-29  9:35 UTC (permalink / raw)
  To: Lucas Seiki Oshiro
  Cc: git, oswald.buddenhagen, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler, jn.avila
On Sun, Jul 27, 2025 at 02:51:07PM -0300, Lucas Seiki Oshiro wrote:
> diff --git a/builtin/repo.c b/builtin/repo.c
> index d4f01e35e2..02d5821c77 100644
> --- a/builtin/repo.c
> +++ b/builtin/repo.c
> @@ -1,12 +1,90 @@
>  #include "builtin.h"
>  #include "parse-options.h"
> +#include "refs.h"
> +#include "strbuf.h"
>  
> -static int repo_info(int argc UNUSED, const char **argv UNUSED,
> -		     const char *prefix UNUSED, struct repository *repo UNUSED)
> +typedef int get_value_fn(struct repository *repo, struct strbuf *buf);
Nice, this now uses a strbuf as recommended.
> +struct field {
> +	const char *key;
> +	get_value_fn *get_value;
> +};
> +
> +static int get_references_format(struct repository *repo, struct strbuf *buf)
> +{
> +	strbuf_addstr(buf,
> +		      ref_storage_format_to_name(repo->ref_storage_format));
> +	return 0;
> +}
And this prints into the buffer diretcly. Makes sense.
[snip]
> +static int print_fields(int argc, const char **argv, struct repository *repo)
> +{
> +	const char *last = "";
> +
> +	QSORT(argv, argc, qsort_strcmp);
> +
> +	for (int i = 0; i < argc; i++) {
> +		get_value_fn *get_value;
> +		const char *key = argv[i];
> +		struct strbuf value;
Let's declare the strbuf outside of the loop and `strbuf_reset()` it on
every iteration.
> +
> +		if (!strcmp(key, last))
> +			continue;
> +
> +		strbuf_init(&value, 64);
I don't think we should explicitly initialize it with a specific
capacity. Let's just use `STRBUF_INIT`.
> +		get_value = get_value_fn_for_key(key);
> +
> +		if (!get_value) {
> +			strbuf_release(&value);
> +			return error(_("key '%s' not found"), key);
> +		}
> +
> +		get_value(repo, &value);
> +		printf("%s=%s\n", key, value.buf);
> +		last = key;
> +		strbuf_release(&value);
And the call to `strbuf_release()` should be moved to the end of this
function so that we know to reuse the buffer. The above early return
would then be converted into a `goto out` so that we have a common exit
path where we know to clean up all resources.
Patrick
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v5 0/5] repo: add new command for retrieving repository info
  2025-07-27 20:11   ` [GSoC PATCH v5 0/5] repo: add new command for retrieving repository info Eric Sunshine
  2025-07-29  9:35     ` Patrick Steinhardt
@ 2025-07-30 15:26     ` Lucas Seiki Oshiro
  1 sibling, 0 replies; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-07-30 15:26 UTC (permalink / raw)
  To: Eric Sunshine
  Cc: git, oswald.buddenhagen, ps, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler, jn.avila
First of all: thank you for joining this discussion, Eric!
> For this reason, I'm of the opinion that `quote_c_style` should be
> used and documented even at this very early stage.
Ok, so we have three reviews in favor of using `quote_c_style`. I'll
use it in v7.
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v5 2/5] repo: add the field references.format
  2025-07-27 21:16     ` Eric Sunshine
@ 2025-07-31 19:39       ` Lucas Seiki Oshiro
  0 siblings, 0 replies; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-07-31 19:39 UTC (permalink / raw)
  To: Eric Sunshine
  Cc: git, oswald.buddenhagen, ps, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler, jn.avila
> Based upon the implementation, I can see that the user must type the
> key in "dotted" form:
> 
>    git repo info references.format
Agreed, that's an important information that was missing in this
documentation.
> I don't think I would figure it out easily. Perhaps hand-holding the
> user by giving an example would help.
Looks like a good idea. I'll add it in the 4th path of this patchset,
so we'll have an example with more than one field.
> How can we ensure that the lexicographical-order requirement won't
> break?
Good point. We don't ensure it through tests. I plan to add an --all
flag to retrieve all the fields. With that --all flag I can iterate
and check whether the keys are in the correct order.
> Also, this requirement does feel like a premature optimization. Do
> you expect this list to become so huge and the corresponding lookup
> function to be called so frequently that a simple brute-force linear
> search would be too slow?
It won't bebig. My plans for this GSoC is to add the object format
and 9 path-related values, but of course, someone may add more stuff
to this command in the future.
About algorithm complexity, it isn't something that I'm really worried
about, but I also don't want to leave some nested loops with strcmps.
If I'm not mistaken, this is the complexity of the operations here:
- Sorting the requested keys: O(n*s*log(n))
- Searching the keys: O(s*log(m))
- Searching all the requested keys: O(n*s*log(m))
- The current solution: O(n*s*(log(m) + log(n))
- The complexity of brute-forcing would be O(n*m*s)
where:
- n is the number of the requested fields
- m is the number of available fields
- s is the length of the largest requested key
which I don't expect to be too big.
Other thing that I should point here is that I also have plans to
add a feature for requesting the name of a group of keys and then
return all its internal values. For example:
  $ git repo info layout
  layout.bare=true
  layout.shallow=false
Having everything sorted will make this easier.
> I can see from the implementation that you are sorting the incoming
> arguments in order to detect and fold out duplicates.
Yes, that's the main idea. In the previous versions (where we also
had a JSON version), this was done in a more hacky way. Actually,
sorting the values was a suggestion to make it simpler.
> However, that raises a couple questions. First, is it really a good
> idea to do something other than what the user asked for?
In this case, the user isn't asking too much, so we're free here. For
example, in git-rev-parse the data is returned in the correct order.
> Second, if this is a good idea, then should the behavior be documented?
Of course, I'll do that!
>    struct strbuf value = STRBUF_INIT;
>    for (...) {
>        strbuf_reset(&value);
>        ...
>        if (error_condition) {
>            strbuf_release(...);
>            return error(...);
>        }
>       ...
>    }
>    strbuf_release(...);
Much better, thanks!
> Would the user-experience be
> improved by instead continuing the loop even after reporting an error,
> and then adjusting the final `return 0` to conditionally return
> success or error depending upon whether any keys were unrecognized?
It seems ok to me, since we're printing some values even if there is an
invalid key.
> This is talking about null-terminated format, but the implementation
> doesn't seem to emit NUL-terminated output at all.
Oops. I forgot to change it when rebasing...
> In this case, if you call this function with a distinct repository
> name each time, then you don't have to remove the repository at all.
> Moreover, giving each repository a distinct and _meaningful_ name,
> rather than reusing the same name, could also be helpful when
> diagnosing failures.
Nice solution! I'll do that.
> With only two callers, it's not clear at this point whether the
> `test_repo_info` function is providing any added value, especially
> since the additional abstraction increases cognitive load, but perhaps
> later patches in this series add more callers?
Yes. In the next patches of this patchset I'm adding other values (and
there are others that will be added in future patchesets). The tests will
look very similar, only changing the repository creation, the key and
the expected value. Then this will decrease the repetition (and
copy-paste typos).
In the last patch of this series I also add the null-terminated format.
Having two formats doubles the number of tests, and this function will
avoid even more code repetition.
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v5 2/5] repo: add the field references.format
  2025-07-29  9:35     ` Patrick Steinhardt
@ 2025-07-31 19:49       ` Lucas Seiki Oshiro
  0 siblings, 0 replies; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-07-31 19:49 UTC (permalink / raw)
  To: Patrick Steinhardt
  Cc: git, oswald.buddenhagen, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler, jn.avila
> And the call to `strbuf_release()` should be moved to the end of this
> function so that we know to reuse the buffer. The above early return
> would then be converted into a `goto out` so that we have a common exit
> path where we know to clean up all resources.
I agree, however, after Eric's suggestion of keep looping even if find
an invalid key, that goto will now be a continue.
But I'll use strbuf_reset and move the strbuf_release to the end of the
function in the next version.
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v5 5/5] repo: add the --format flag
  2025-07-27 22:02     ` Eric Sunshine
  2025-07-29  0:15       ` Ben Knoble
@ 2025-07-31 23:01       ` Lucas Seiki Oshiro
  1 sibling, 0 replies; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-07-31 23:01 UTC (permalink / raw)
  To: Eric Sunshine
  Cc: git, oswald.buddenhagen, ps, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler, jn.avila
> I haven't been following the discussion around this series, but don't
> we also usually provide a `-z` short option? Should that be added for
> consistency with other commands and to avoid surprising users, or is
> it too early to commit to that?
Yes, it is planned to be added in a future patch!
> something like this:
> 
>    printf "$key\n$expected_value\0" >expect &&
>    git -C repo repo info --format=nul "$key" >actual &&
>    test_cmp_bin expect actual
Even better, and it's consistent to your previous suggestion. I'll
do that in the next version.
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v5 5/5] repo: add the --format flag
  2025-07-27 17:51   ` [GSoC PATCH v5 5/5] repo: add the --format flag Lucas Seiki Oshiro
  2025-07-27 22:02     ` Eric Sunshine
@ 2025-07-31 23:15     ` Lucas Seiki Oshiro
  1 sibling, 0 replies; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-07-31 23:15 UTC (permalink / raw)
  To: git
  Cc: oswald.buddenhagen, ps, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler, jn.avila
> + const char *const repo_info_usage[] = {
> + "git repo info [<key>...]",
Reviewing myself: I missed the `--format` flag here.
^ permalink raw reply	[flat|nested] 226+ messages in thread
* [GSoC PATCH v7 0/5] repo: add new command for retrieving repository info
  2025-06-10 15:21 [GSoC RFC PATCH 0/5] repo-info: add new command for retrieving repository info Lucas Seiki Oshiro
                   ` (12 preceding siblings ...)
  2025-07-27 17:51 ` [GSoC PATCH v5 0/5] repo: add new command for retrieving repository info Lucas Seiki Oshiro
@ 2025-08-01 13:11 ` Lucas Seiki Oshiro
  2025-08-01 13:11   ` [GSoC PATCH v7 1/5] repo: declare the repo command Lucas Seiki Oshiro
                     ` (5 more replies)
  2025-08-06 19:55 ` [GSoC PATCH v8 " Lucas Seiki Oshiro
                   ` (3 subsequent siblings)
  17 siblings, 6 replies; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-08-01 13:11 UTC (permalink / raw)
  To: git
  Cc: oswald.buddenhagen, ps, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler, jn.avila, sunshine, Lucas Seiki Oshiro
Hi!
These are the changes of this 7th version of `git repo`:
- The tests were refactored (thanks Eric for your careful revision!)
- The documentation has been improved: now it is a little more
  descriptive about the keys. I'm also including more information about
  the values
- The documentation now contains examples
- If an invalid key is requested, the command fails, however, now it
  returns all the valid fields that were requested
- Now, I'm using `quote_c_style` in the key=value format
Thanks!
Range-diff versus v6:
1:  bc6f19ba8e ! 1:  b4f063b177 repo: declare the repo command
    @@ Commit message
         will bring the functionality of retrieving repository-related
         information currently returned by `rev-parse`.
    -    Add the required tests, documentation and build changes to enable
    -    usage of this subcommand.
    +    Add the required documentation and build changes to enable usage of
    +    this subcommand.
         Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
         Helped-by: Junio C Hamano <gitster@pobox.com>
         Helped-by: Justin Tobler <jltobler@gmail.com>
    +    Helped-by: Eric Sunshine <sunshine@sunshineco.com>
         Mentored-by: Karthik Nayak <karthik.188@gmail.com>
         Mentored-by: Patrick Steinhardt <ps@pks.im>
         Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
    @@ Documentation/git-repo.adoc (new)
     +
     +NAME
     +----
    -+git-repo - Retrieve information about a repository
    ++git-repo - Retrieve information about the repository
     +
     +SYNOPSIS
     +--------
    @@ Documentation/git-repo.adoc (new)
     +
     +DESCRIPTION
     +-----------
    -+This command retrieve repository level information.
    ++Retrieve information about the repository.
     +
     +THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOR MAY CHANGE.
     +
    @@ Documentation/git-repo.adoc (new)
     +	the requested data will be returned based on their keys (see "INFO KEYS"
     +	section below).
     +
    -+INFO KEYS
    -+---------
    -+
    -+The set of data that `git repo` can return is grouped into the following
    -+categories:
    -+
     +SEE ALSO
     +--------
     +linkgit:git-rev-parse[1]
    @@ builtin/repo.c (new)
     +#include "builtin.h"
     +#include "parse-options.h"
     +
    ++static const char *const repo_usage[] = {
    ++	"git repo info [<key>...]",
    ++	NULL
    ++};
    ++
     +static int repo_info(int argc UNUSED, const char **argv UNUSED,
     +		     const char *prefix UNUSED, struct repository *repo UNUSED)
     +{
    @@ builtin/repo.c (new)
     +	     struct repository *repo)
     +{
     +	parse_opt_subcommand_fn *fn = NULL;
    -+	const char *const repo_usage[] = {
    -+		"git repo info [<key>...]",
    -+		NULL
    -+	};
     +	struct option options[] = {
     +		OPT_SUBCOMMAND("info", &fn, repo_info),
     +		OPT_END()
2:  2b0e91f94d ! 2:  56cb05ecb2 repo: add the field references.format
    @@ Commit message
         Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
         Helped-by: Junio C Hamano <gitster@pobox.com>
         Helped-by: Justin Tobler <jltobler@gmail.com>
    +    Helped-by: Eric Sunshine <sunshine@sunshineco.com>
         Mentored-by: Karthik Nayak <karthik.188@gmail.com>
         Mentored-by: Patrick Steinhardt <ps@pks.im>
         Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
      ## Documentation/git-repo.adoc ##
    -@@ Documentation/git-repo.adoc: INFO KEYS
    - The set of data that `git repo` can return is grouped into the following
    - categories:
    +@@ Documentation/git-repo.adoc: COMMANDS
    + 	Retrieve metadata-related information about the current repository. Only
    + 	the requested data will be returned based on their keys (see "INFO KEYS"
    + 	section below).
    +++
    ++The returned data is lexicographically sorted by the keys.
    ++
    ++INFO KEYS
    ++---------
    ++
    ++In order to obtain a set of values from `git repo info`, you should provide
    ++the keys that identify them. Here's a list of the available keys and the
    ++values that they return:
    ++
    ++`references.format`::
    ++The reference storage format. The valid values are:
    +++
    ++include::ref-storage-format.adoc[]
    -+`references`::
    -+Reference-related data:
    -+* `format`: the reference storage format
    -+
      SEE ALSO
      --------
    - linkgit:git-rev-parse[1]
      ## builtin/repo.c ##
     @@
      #include "builtin.h"
      #include "parse-options.h"
    ++#include "quote.h"
     +#include "refs.h"
     +#include "strbuf.h"
    + static const char *const repo_usage[] = {
    + 	"git repo info [<key>...]",
    + 	NULL
    + };
    +
     -static int repo_info(int argc UNUSED, const char **argv UNUSED,
     -		     const char *prefix UNUSED, struct repository *repo UNUSED)
     +typedef int get_value_fn(struct repository *repo, struct strbuf *buf);
    @@ builtin/repo.c
     +};
     +
     +static int get_references_format(struct repository *repo, struct strbuf *buf)
    -+{
    + {
     +	strbuf_addstr(buf,
     +		      ref_storage_format_to_name(repo->ref_storage_format));
    -+	return 0;
    -+}
    -+
    + 	return 0;
    + }
    +
     +/* repo_info_fields keys should be in lexicographical order */
     +static const struct field repo_info_fields[] = {
     +	{ "references.format", get_references_format },
    @@ builtin/repo.c
     +}
     +
     +static int qsort_strcmp(const void *va, const void *vb)
    - {
    ++{
     +	const char *a = *(const char **)va;
     +	const char *b = *(const char **)vb;
     +
    @@ builtin/repo.c
     +
     +static int print_fields(int argc, const char **argv, struct repository *repo)
     +{
    ++	int ret = 0;
     +	const char *last = "";
    ++	struct strbuf sb = STRBUF_INIT;
     +
     +	QSORT(argv, argc, qsort_strcmp);
     +
     +	for (int i = 0; i < argc; i++) {
     +		get_value_fn *get_value;
     +		const char *key = argv[i];
    -+		struct strbuf value;
    ++		char *value;
     +
     +		if (!strcmp(key, last))
     +			continue;
     +
    -+		strbuf_init(&value, 64);
     +		get_value = get_value_fn_for_key(key);
     +
     +		if (!get_value) {
    -+			strbuf_release(&value);
    -+			return error(_("key '%s' not found"), key);
    ++			ret = error(_("key '%s' not found"), key);
    ++			continue;
     +		}
     +
    -+		get_value(repo, &value);
    -+		printf("%s=%s\n", key, value.buf);
    ++		strbuf_reset(&sb);
    ++		get_value(repo, &sb);
    ++
    ++		value = strbuf_detach(&sb, NULL);
    ++		quote_c_style(value, &sb, NULL, 0);
    ++		free(value);
    ++
    ++		printf("%s=%s\n", key, sb.buf);
     +		last = key;
    -+		strbuf_release(&value);
     +	}
     +
    - 	return 0;
    - }
    -
    ++	strbuf_release(&sb);
    ++	return ret;
    ++}
    ++
     +static int repo_info(int argc, const char **argv, const char *prefix UNUSED,
     +		     struct repository *repo)
     +{
    @@ t/t1900-repo.sh (new)
     +
     +. ./test-lib.sh
     +
    -+# Test if a field is correctly returned in the null-terminated format
    ++# Test whether a key-value pair is correctly returned
     +#
     +# Usage: test_repo_info <label> <init command> <key> <expected value>
     +#
     +# Arguments:
     +#   label: the label of the test
    -+#   init command: a command that creates a repository called 'repo', configured
    ++#   init command: a command which creates a repository named with its first argument,
     +#      accordingly to what is being tested
     +#   key: the key of the field that is being tested
     +#   expected value: the value that the field should contain
     +test_repo_info () {
     +	label=$1
     +	init_command=$2
    -+	key=$3
    -+	expected_value=$4
    ++	repo_name=$3
    ++	key=$4
    ++	expected_value=$5
     +
     +	test_expect_success "$label" '
    -+		test_when_finished "rm -rf repo" &&
    -+		eval "$init_command" &&
    -+		echo "$expected_value" >expected &&
    -+		git -C repo repo info "$key" >output &&
    -+		cut -d "=" -f 2 <output >actual &&
    ++		eval "$init_command $repo_name" &&
    ++		echo "$key=$expected_value" >expected &&
    ++		git -C $repo_name repo info "$key" >actual &&
     +		test_cmp expected actual
     +	'
     +}
     +
     +test_repo_info 'ref format files is retrieved correctly' '
    -+	git init --ref-format=files repo' 'references.format' 'files'
    ++	git init --ref-format=files' 'format-files' 'references.format' 'files'
     +
     +test_repo_info 'ref format reftable is retrieved correctly' '
    -+	git init --ref-format=reftable repo' 'references.format' 'reftable'
    ++	git init --ref-format=reftable' 'format-reftable' 'references.format' 'reftable'
    ++
    ++test_expect_success 'git-repo-info fails if an invalid key is requested' '
    ++	echo "error: key '\'foo\'' not found" >expected_err &&
    ++	test_must_fail git repo info foo 2>actual_err &&
    ++	test_cmp expected_err actual_err
    ++'
     +
    -+test_expect_success 'git-repo-info aborts if an invalid key is requested' '
    -+	test_when_finished "rm -rf expected err" &&
    -+	echo "error: key '\'foo\'' not found" >expected &&
    -+	test_must_fail git repo info foo 2>err &&
    -+	test_cmp expected err
    ++test_expect_success 'git-repo-info outputs data even if there is an invalid field' '
    ++	echo "references.format=files" >expected &&
    ++	test_must_fail git repo info foo references.format bar >actual &&
    ++	test_cmp expected actual
     +'
     +
    -+test_expect_success "only one value is returned if the same key is requested twice" '
    -+	test_when_finished "rm -f expected_key expected_value actual_key actual_value output" &&
    -+	echo "references.format" >expected_key &&
    -+	git rev-parse --show-ref-format >expected_value &&
    -+	git repo info references.format references.format >output &&
    -+	cut -d "=" -f 1 <output >actual_key &&
    -+	cut -d "=" -f 2 <output >actual_value &&
    -+        test_cmp expected_key actual_key &&
    -+        test_cmp expected_value actual_value
    ++test_expect_success 'only one value is returned if the same key is requested twice' '
    ++	val=$(git rev-parse --show-ref-format) &&
    ++	echo "references.format=$val" >expect &&
    ++	git repo info references.format references.format >actual &&
    ++	test_cmp expect actual
     +'
     +
     +test_done
3:  733d3533d8 ! 3:  fc4c70d9b7 repo: add field layout.bare
    @@ Metadata
     Author: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
      ## Commit message ##
    -    repo: add field layout.bare
    +    repo: add the field layout.bare
         This commit is part of the series that introduces the new subcommand
         git-repo-info.
    @@ Commit message
         Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
         Helped-by: Junio C Hamano <gitster@pobox.com>
         Helped-by: Justin Tobler <jltobler@gmail.com>
    +    Helped-by: Eric Sunshine <sunshine@sunshineco.com>
         Mentored-by: Karthik Nayak <karthik.188@gmail.com>
         Mentored-by: Patrick Steinhardt <ps@pks.im>
         Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
      ## Documentation/git-repo.adoc ##
    -@@ Documentation/git-repo.adoc: categories:
    - Reference-related data:
    - * `format`: the reference storage format
    +@@ Documentation/git-repo.adoc: In order to obtain a set of values from `git repo info`, you should provide
    + the keys that identify them. Here's a list of the available keys and the
    + values that they return:
    -+`layout`::
    -+Information about the how the current repository is represented:
    -+* `bare`: `true` if this is a bare repository, otherwise `false`.
    ++`layout.bare`::
    ++`true` if this is a bare repository, otherwise `false`.
     +
    - SEE ALSO
    - --------
    - linkgit:git-rev-parse[1]
    + `references.format`::
    + The reference storage format. The valid values are:
    + +
      ## builtin/repo.c ##
     @@
    @@ builtin/repo.c
      #include "builtin.h"
     +#include "environment.h"
      #include "parse-options.h"
    + #include "quote.h"
      #include "refs.h"
    - #include "strbuf.h"
     @@ builtin/repo.c: struct field {
      	get_value_fn *get_value;
      };
    @@ builtin/repo.c: static int get_references_format(struct repository *repo, struct
      ## t/t1900-repo.sh ##
     @@ t/t1900-repo.sh: test_repo_info 'ref format files is retrieved correctly' '
      test_repo_info 'ref format reftable is retrieved correctly' '
    - 	git init --ref-format=reftable repo' 'references.format' 'reftable'
    + 	git init --ref-format=reftable' 'format-reftable' 'references.format' 'reftable'
     +test_repo_info 'bare repository = false is retrieved correctly' '
    -+	git init repo' 'layout.bare' 'false'
    ++	git init' 'bare' 'layout.bare' 'false'
     +
     +test_repo_info 'bare repository = true is retrieved correctly' '
    -+	git init --bare repo' 'layout.bare' 'true'
    ++	git init --bare' 'nonbare' 'layout.bare' 'true'
     +
    - test_expect_success 'git-repo-info aborts if an invalid key is requested' '
    - 	test_when_finished "rm -rf expected err" &&
    - 	echo "error: key '\'foo\'' not found" >expected &&
    + test_expect_success 'git-repo-info fails if an invalid key is requested' '
    + 	echo "error: key '\'foo\'' not found" >expected_err &&
    + 	test_must_fail git repo info foo 2>actual_err &&
    +@@ t/t1900-repo.sh: test_expect_success 'only one value is returned if the same key is requested twi
    + 	test_cmp expect actual
    + '
    +
    ++test_expect_success 'output is returned correctly when two keys are requested' '
    ++	cat >expect <<-\EOF &&
    ++	layout.bare=false
    ++	references.format=files
    ++	EOF
    ++	git init --ref-format=files two-keys &&
    ++	git -C two-keys repo info layout.bare references.format
    ++'
    + test_done
4:  fa17719ebc ! 4:  f35704442a repo: add field layout.shallow
    @@ Metadata
     Author: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
      ## Commit message ##
    -    repo: add field layout.shallow
    +    repo: add the field layout.shallow
         This commit is part of the series that introduces the new subcommand
         git-repo-info.
    @@ Commit message
         Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
         Helped-by: Junio C Hamano <gitster@pobox.com>
         Helped-by: Justin Tobler <jltobler@gmail.com>
    +    Helped-by: Eric Sunshine <sunshine@sunshineco.com>
         Mentored-by: Karthik Nayak <karthik.188@gmail.com>
         Mentored-by: Patrick Steinhardt <ps@pks.im>
         Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
      ## Documentation/git-repo.adoc ##
    -@@ Documentation/git-repo.adoc: Reference-related data:
    - `layout`::
    - Information about the how the current repository is represented:
    - * `bare`: `true` if this is a bare repository, otherwise `false`.
    -+* `shallow`: `true` if this is a shallow repository, otherwise `false`.
    +@@ Documentation/git-repo.adoc: values that they return:
    + `layout.bare`::
    + `true` if this is a bare repository, otherwise `false`.
    - SEE ALSO
    - --------
    ++`layout.shallow`::
    ++`true` if this is a shallow repository, otherwise `false`.
    ++
    + `references.format`::
    + The reference storage format. The valid values are:
    + +
      ## builtin/repo.c ##
     @@
    - #include "parse-options.h"
    + #include "quote.h"
      #include "refs.h"
      #include "strbuf.h"
     +#include "shallow.h"
    - typedef int get_value_fn(struct repository *repo, struct strbuf *buf);
    -
    + static const char *const repo_usage[] = {
    + 	"git repo info [<key>...]",
     @@ builtin/repo.c: static int get_layout_bare(struct repository *repo UNUSED, struct strbuf *buf)
      	return 0;
      }
    @@ builtin/repo.c: static int get_references_format(struct repository *repo, struct
      ## t/t1900-repo.sh ##
     @@ t/t1900-repo.sh: test_repo_info 'bare repository = false is retrieved correctly' '
      test_repo_info 'bare repository = true is retrieved correctly' '
    - 	git init --bare repo' 'layout.bare' 'true'
    + 	git init --bare' 'nonbare' 'layout.bare' 'true'
     +test_repo_info 'shallow repository = false is retrieved correctly' '
    -+	git init repo' 'layout.shallow' 'false'
    ++	git init' 'nonshallow' 'layout.shallow' 'false'
     +
     +test_repo_info 'shallow repository = true is retrieved correctly' '
     +	git init remote &&
    -+	cd remote &&
    -+	echo x >x &&
    -+	git add x &&
    -+	git commit -m x &&
    -+	cd .. &&
    -+	git clone --depth 1 "file://$PWD/remote" repo &&
    -+	rm -rf remote
    -+	' 'layout.shallow' 'true'
    ++	echo x >remote/x &&
    ++	git -C remote add x &&
    ++	git -C remote commit -m x &&
    ++	git clone --depth 1 "file://$PWD/remote"' 'shallow' 'layout.shallow' 'true'
     +
    - test_expect_success 'git-repo-info aborts if an invalid key is requested' '
    - 	test_when_finished "rm -rf expected err" &&
    - 	echo "error: key '\'foo\'' not found" >expected &&
    -@@ t/t1900-repo.sh: test_expect_success "only one value is returned if the same key is requested twi
    -         test_cmp expected_value actual_value
    + test_expect_success 'git-repo-info fails if an invalid key is requested' '
    + 	echo "error: key '\'foo\'' not found" >expected_err &&
    + 	test_must_fail git repo info foo 2>actual_err &&
    +@@ t/t1900-repo.sh: test_expect_success 'output is returned correctly when two keys are requested' '
    + 	git init --ref-format=files two-keys &&
    + 	git -C two-keys repo info layout.bare references.format
      '
    -
    -+test_expect_success 'output is returned correctly when two keys are requested' '
    -+	test_when_finished "rm -f expect" &&
    -+	printf "layout.bare=false\nlayout.shallow=false\n" >expect &&
    -+	git repo info layout.shallow layout.bare >actual &&
    -+	test_cmp expect actual
    -+'
     +
      test_done
5:  b72a61b73b ! 5:  8931b12eca repo: add the --format flag
    @@ Commit message
         Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
         Helped-by: Junio C Hamano <gitster@pobox.com>
         Helped-by: Justin Tobler <jltobler@gmail.com>
    +    Helped-by: Eric Sunshine <sunshine@sunshineco.com>
         Mentored-by: Karthik Nayak <karthik.188@gmail.com>
         Mentored-by: Patrick Steinhardt <ps@pks.im>
         Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
    @@ Documentation/git-repo.adoc: THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOR MAY CHAN
      COMMANDS
      --------
     -`info [<key>...]`::
    -+`info [--format=<format>] [<key>...]`::
    ++`info [--format=<keyvalue|nul>] [<key>...]`::
      	Retrieve metadata-related information about the current repository. Only
      	the requested data will be returned based on their keys (see "INFO KEYS"
      	section below).
    + +
    + The returned data is lexicographically sorted by the keys.
     ++
     +The output format can be chosen through the flag `--format`. Two formats are
     +supported:
    @@ Documentation/git-repo.adoc: THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOR MAY CHAN
      INFO KEYS
      ---------
    +@@ Documentation/git-repo.adoc: The reference storage format. The valid values are:
    + +
    + include::ref-storage-format.adoc[]
    +
    ++
    ++Examples
    ++--------
    ++
    ++* Retrieves the reference format of the current repository:
    +++
    ++------------
    ++git repo info references.format
    ++------------
    +++
    ++
    ++* Retrieves whether the current repository is bare and whether it is shallow
    ++using the `nul` format:
    +++
    ++------------
    ++git repo info --format=nul layout.bare layout.shallow
    ++------------
    ++
    + SEE ALSO
    + --------
    + linkgit:git-rev-parse[1]
      ## builtin/repo.c ##
     @@
    + #include "shallow.h"
    +
    + static const char *const repo_usage[] = {
    +-	"git repo info [<key>...]",
    ++	"git repo info [--format=<keyvalue|nul>] [<key>...]",
    + 	NULL
    + };
      typedef int get_value_fn(struct repository *repo, struct strbuf *buf);
    @@ builtin/repo.c: static int qsort_strcmp(const void *va, const void *vb)
     +			struct repository *repo,
     +			enum output_format format)
      {
    + 	int ret = 0;
      	const char *last = "";
    + 	struct strbuf sb = STRBUF_INIT;
    +
     +	char kv_sep;
     +	char field_sep;
     +
    @@ builtin/repo.c: static int qsort_strcmp(const void *va, const void *vb)
     +		field_sep = '\0';
     +		break;
     +	}
    -
    ++
      	QSORT(argv, argc, qsort_strcmp);
    + 	for (int i = 0; i < argc; i++) {
    + 		get_value_fn *get_value;
    + 		const char *key = argv[i];
    +-		char *value;
    +
    + 		if (!strcmp(key, last))
    + 			continue;
     @@ builtin/repo.c: static int print_fields(int argc, const char **argv, struct repository *repo)
    - 		}
    + 		strbuf_reset(&sb);
    + 		get_value(repo, &sb);
    +
    +-		value = strbuf_detach(&sb, NULL);
    +-		quote_c_style(value, &sb, NULL, 0);
    +-		free(value);
    ++		if (format == FORMAT_KEYVALUE) {
    ++			char *value;
    ++			value = strbuf_detach(&sb, NULL);
    ++			quote_c_style(value, &sb, NULL, 0);
    ++			free(value);
    ++		}
    - 		get_value(repo, &value);
    --		printf("%s=%s\n", key, value.buf);
    -+		printf("%s%c%s%c", key, kv_sep, value.buf, field_sep);
    +-		printf("%s=%s\n", key, sb.buf);
    ++		printf("%s%c%s%c", key, kv_sep, sb.buf, field_sep);
      		last = key;
    - 		strbuf_release(&value);
      	}
    +
     @@ builtin/repo.c: static int print_fields(int argc, const char **argv, struct repository *repo)
    - 	return 0;
    + 	return ret;
      }
     -static int repo_info(int argc, const char **argv, const char *prefix UNUSED,
    @@ builtin/repo.c: static int print_fields(int argc, const char **argv, struct repo
     -	return print_fields(argc - 1, argv + 1, repo);
     +	const char *format_str = "keyvalue";
     +	enum output_format format;
    -+	const char *const repo_info_usage[] = {
    -+		"git repo info [<key>...]",
    -+		NULL
    -+	};
     +	struct option options[] = {
     +		OPT_STRING(0, "format", &format_str, N_("format"),
     +			   N_("output format")),
     +		OPT_END()
     +	};
     +
    -+	argc = parse_options(argc, argv, prefix, options, repo_info_usage, 0);
    ++	argc = parse_options(argc, argv, prefix, options, repo_usage, 0);
     +
     +	if (!strcmp(format_str, "keyvalue"))
     +		format = FORMAT_KEYVALUE;
    @@ builtin/repo.c: static int print_fields(int argc, const char **argv, struct repo
      ## t/t1900-repo.sh ##
     @@ t/t1900-repo.sh: test_repo_info () {
    - 	key=$3
    - 	expected_value=$4
    + 	key=$4
    + 	expected_value=$5
     -	test_expect_success "$label" '
    -+	test_expect_success "null-terminated: $label" '
    -+		test_when_finished "rm -rf repo" &&
    -+		eval "$init_command" &&
    -+		echo "$expected_value" | lf_to_nul >expected &&
    -+		git -C repo repo info --format=nul "$key" >output &&
    -+		tail -n 1 output >actual &&
    +-		eval "$init_command $repo_name" &&
    ++	test_expect_success "keyvalue: $label" '
    ++		eval "$init_command keyvalue-$repo_name" &&
    + 		echo "$key=$expected_value" >expected &&
    +-		git -C $repo_name repo info "$key" >actual &&
    ++		git -C keyvalue-$repo_name repo info "$key" >actual &&
     +		test_cmp expected actual
     +	'
     +
    -+	test_expect_success "key-value: $label" '
    - 		test_when_finished "rm -rf repo" &&
    - 		eval "$init_command" &&
    - 		echo "$expected_value" >expected &&
    --		git -C repo repo info "$key" >output &&
    -+		git -C repo repo info --format=keyvalue "$key" >output &&
    - 		cut -d "=" -f 2 <output >actual &&
    ++	test_expect_success "nul: $label" '
    ++		eval "$init_command nul-$repo_name" &&
    ++		printf "%s\n%s\0" "$key" "$expected_value" >expected &&
    ++		git -C nul-$repo_name repo info --format=nul "$key" >actual &&
      		test_cmp expected actual
      	'
    + }
    +@@ t/t1900-repo.sh: test_repo_info 'shallow repository = false is retrieved correctly' '
    + 	git init' 'nonshallow' 'layout.shallow' 'false'
    +
    + test_repo_info 'shallow repository = true is retrieved correctly' '
    ++	test_when_finished "rm -rf remote" &&
    + 	git init remote &&
    + 	echo x >remote/x &&
    + 	git -C remote add x &&
     @@ t/t1900-repo.sh: test_expect_success 'output is returned correctly when two keys are requested' '
    - 	test_cmp expect actual
    + 	git -C two-keys repo info layout.bare references.format
      '
     +test_expect_success 'git-repo-info aborts when requesting an invalid format' '
Lucas Seiki Oshiro (5):
  repo: declare the repo command
  repo: add the field references.format
  repo: add the field layout.bare
  repo: add the field layout.shallow
  repo: add the --format flag
 .gitignore                  |   1 +
 Documentation/git-repo.adoc |  81 +++++++++++++++++
 Documentation/meson.build   |   1 +
 Makefile                    |   1 +
 builtin.h                   |   1 +
 builtin/repo.c              | 173 ++++++++++++++++++++++++++++++++++++
 command-list.txt            |   1 +
 git.c                       |   1 +
 meson.build                 |   1 +
 t/meson.build               |   1 +
 t/t1900-repo.sh             |  97 ++++++++++++++++++++
 11 files changed, 359 insertions(+)
 create mode 100644 Documentation/git-repo.adoc
 create mode 100644 builtin/repo.c
 create mode 100755 t/t1900-repo.sh
-- 
2.39.5 (Apple Git-154)
^ permalink raw reply	[flat|nested] 226+ messages in thread
* [GSoC PATCH v7 1/5] repo: declare the repo command
  2025-08-01 13:11 ` [GSoC PATCH v7 " Lucas Seiki Oshiro
@ 2025-08-01 13:11   ` Lucas Seiki Oshiro
  2025-08-01 13:11   ` [GSoC PATCH v7 2/5] repo: add the field references.format Lucas Seiki Oshiro
                     ` (4 subsequent siblings)
  5 siblings, 0 replies; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-08-01 13:11 UTC (permalink / raw)
  To: git
  Cc: oswald.buddenhagen, ps, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler, jn.avila, sunshine, Lucas Seiki Oshiro
Currently, `git rev-parse` covers a wide range of functionality not
directly related to parsing revisions, as its name suggests. Over time,
many features like parsing datestrings, options, paths, and others
were added to it because there wasn't a more appropriate command
to place them.
Create a new Git command called `repo`. `git repo` will be the main
command for obtaining the information about a repository (such as
metadata and metrics).
Also declare a subcommand for `repo` called `info`. `git repo info`
will bring the functionality of retrieving repository-related
information currently returned by `rev-parse`.
Add the required documentation and build changes to enable usage of
this subcommand.
Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Helped-by: Junio C Hamano <gitster@pobox.com>
Helped-by: Justin Tobler <jltobler@gmail.com>
Helped-by: Eric Sunshine <sunshine@sunshineco.com>
Mentored-by: Karthik Nayak <karthik.188@gmail.com>
Mentored-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
---
 .gitignore                  |  1 +
 Documentation/git-repo.adoc | 32 ++++++++++++++++++++++++++++++++
 Documentation/meson.build   |  1 +
 Makefile                    |  1 +
 builtin.h                   |  1 +
 builtin/repo.c              | 27 +++++++++++++++++++++++++++
 command-list.txt            |  1 +
 git.c                       |  1 +
 meson.build                 |  1 +
 9 files changed, 66 insertions(+)
 create mode 100644 Documentation/git-repo.adoc
 create mode 100644 builtin/repo.c
diff --git a/.gitignore b/.gitignore
index 04c444404e..1803023427 100644
--- a/.gitignore
+++ b/.gitignore
@@ -139,6 +139,7 @@
 /git-repack
 /git-replace
 /git-replay
+/git-repo
 /git-request-pull
 /git-rerere
 /git-reset
diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc
new file mode 100644
index 0000000000..68c706f5a0
--- /dev/null
+++ b/Documentation/git-repo.adoc
@@ -0,0 +1,32 @@
+git-repo(1)
+===========
+
+NAME
+----
+git-repo - Retrieve information about the repository
+
+SYNOPSIS
+--------
+[synopsis]
+git repo info [<key>...]
+
+DESCRIPTION
+-----------
+Retrieve information about the repository.
+
+THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOR MAY CHANGE.
+
+COMMANDS
+--------
+`info [<key>...]`::
+	Retrieve metadata-related information about the current repository. Only
+	the requested data will be returned based on their keys (see "INFO KEYS"
+	section below).
+
+SEE ALSO
+--------
+linkgit:git-rev-parse[1]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/meson.build b/Documentation/meson.build
index 4404c623f0..41f43e0336 100644
--- a/Documentation/meson.build
+++ b/Documentation/meson.build
@@ -116,6 +116,7 @@ manpages = {
   'git-repack.adoc' : 1,
   'git-replace.adoc' : 1,
   'git-replay.adoc' : 1,
+  'git-repo.adoc' : 1,
   'git-request-pull.adoc' : 1,
   'git-rerere.adoc' : 1,
   'git-reset.adoc' : 1,
diff --git a/Makefile b/Makefile
index 5f7dd79dfa..9dce446309 100644
--- a/Makefile
+++ b/Makefile
@@ -1306,6 +1306,7 @@ BUILTIN_OBJS += builtin/remote.o
 BUILTIN_OBJS += builtin/repack.o
 BUILTIN_OBJS += builtin/replace.o
 BUILTIN_OBJS += builtin/replay.o
+BUILTIN_OBJS += builtin/repo.o
 BUILTIN_OBJS += builtin/rerere.o
 BUILTIN_OBJS += builtin/reset.o
 BUILTIN_OBJS += builtin/rev-list.o
diff --git a/builtin.h b/builtin.h
index bff13e3069..e6458e6fb9 100644
--- a/builtin.h
+++ b/builtin.h
@@ -216,6 +216,7 @@ int cmd_remote_ext(int argc, const char **argv, const char *prefix, struct repos
 int cmd_remote_fd(int argc, const char **argv, const char *prefix, struct repository *repo);
 int cmd_repack(int argc, const char **argv, const char *prefix, struct repository *repo);
 int cmd_replay(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_repo(int argc, const char **argv, const char *prefix, struct repository *repo);
 int cmd_rerere(int argc, const char **argv, const char *prefix, struct repository *repo);
 int cmd_reset(int argc, const char **argv, const char *prefix, struct repository *repo);
 int cmd_restore(int argc, const char **argv, const char *prefix, struct repository *repo);
diff --git a/builtin/repo.c b/builtin/repo.c
new file mode 100644
index 0000000000..fd2a9b4216
--- /dev/null
+++ b/builtin/repo.c
@@ -0,0 +1,27 @@
+#include "builtin.h"
+#include "parse-options.h"
+
+static const char *const repo_usage[] = {
+	"git repo info [<key>...]",
+	NULL
+};
+
+static int repo_info(int argc UNUSED, const char **argv UNUSED,
+		     const char *prefix UNUSED, struct repository *repo UNUSED)
+{
+	return 0;
+}
+
+int cmd_repo(int argc, const char **argv, const char *prefix,
+	     struct repository *repo)
+{
+	parse_opt_subcommand_fn *fn = NULL;
+	struct option options[] = {
+		OPT_SUBCOMMAND("info", &fn, repo_info),
+		OPT_END()
+	};
+
+	argc = parse_options(argc, argv, prefix, options, repo_usage, 0);
+
+	return fn(argc, argv, prefix, repo);
+}
diff --git a/command-list.txt b/command-list.txt
index b7ade3ab9f..1b0bdee00d 100644
--- a/command-list.txt
+++ b/command-list.txt
@@ -164,6 +164,7 @@ git-remote                              ancillarymanipulators           complete
 git-repack                              ancillarymanipulators           complete
 git-replace                             ancillarymanipulators           complete
 git-replay                              plumbingmanipulators
+git-repo                                plumbinginterrogators
 git-request-pull                        foreignscminterface             complete
 git-rerere                              ancillaryinterrogators
 git-reset                               mainporcelain           history
diff --git a/git.c b/git.c
index 07a5fe39fb..8290d8b8c8 100644
--- a/git.c
+++ b/git.c
@@ -611,6 +611,7 @@ static struct cmd_struct commands[] = {
 	{ "repack", cmd_repack, RUN_SETUP },
 	{ "replace", cmd_replace, RUN_SETUP },
 	{ "replay", cmd_replay, RUN_SETUP },
+	{ "repo", cmd_repo, RUN_SETUP },
 	{ "rerere", cmd_rerere, RUN_SETUP },
 	{ "reset", cmd_reset, RUN_SETUP },
 	{ "restore", cmd_restore, RUN_SETUP | NEED_WORK_TREE },
diff --git a/meson.build b/meson.build
index 9bc1826cb6..8819b64f93 100644
--- a/meson.build
+++ b/meson.build
@@ -645,6 +645,7 @@ builtin_sources = [
   'builtin/repack.c',
   'builtin/replace.c',
   'builtin/replay.c',
+  'builtin/repo.c',
   'builtin/rerere.c',
   'builtin/reset.c',
   'builtin/rev-list.c',
-- 
2.39.5 (Apple Git-154)
^ permalink raw reply related	[flat|nested] 226+ messages in thread
* [GSoC PATCH v7 2/5] repo: add the field references.format
  2025-08-01 13:11 ` [GSoC PATCH v7 " Lucas Seiki Oshiro
  2025-08-01 13:11   ` [GSoC PATCH v7 1/5] repo: declare the repo command Lucas Seiki Oshiro
@ 2025-08-01 13:11   ` Lucas Seiki Oshiro
  2025-08-01 20:59     ` Eric Sunshine
  2025-08-01 13:11   ` [GSoC PATCH v7 3/5] repo: add the field layout.bare Lucas Seiki Oshiro
                     ` (3 subsequent siblings)
  5 siblings, 1 reply; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-08-01 13:11 UTC (permalink / raw)
  To: git
  Cc: oswald.buddenhagen, ps, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler, jn.avila, sunshine, Lucas Seiki Oshiro
This commit is part of the series that introduces the new subcommand
git-repo-info.
The flag `--show-ref-format` from git-rev-parse is used for retrieving
the reference format (i.e. `files` or `reftable`). This way, it is
used for querying repository metadata, fitting in the purpose of
git-repo-info.
Add a new field `references.format` to the repo-info subcommand
containing that information.
Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Helped-by: Junio C Hamano <gitster@pobox.com>
Helped-by: Justin Tobler <jltobler@gmail.com>
Helped-by: Eric Sunshine <sunshine@sunshineco.com>
Mentored-by: Karthik Nayak <karthik.188@gmail.com>
Mentored-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
---
 Documentation/git-repo.adoc | 14 ++++++
 builtin/repo.c              | 90 ++++++++++++++++++++++++++++++++++++-
 t/meson.build               |  1 +
 t/t1900-repo.sh             | 57 +++++++++++++++++++++++
 4 files changed, 160 insertions(+), 2 deletions(-)
 create mode 100755 t/t1900-repo.sh
diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc
index 68c706f5a0..2dd130f3dd 100644
--- a/Documentation/git-repo.adoc
+++ b/Documentation/git-repo.adoc
@@ -22,6 +22,20 @@ COMMANDS
 	Retrieve metadata-related information about the current repository. Only
 	the requested data will be returned based on their keys (see "INFO KEYS"
 	section below).
++
+The returned data is lexicographically sorted by the keys.
+
+INFO KEYS
+---------
+
+In order to obtain a set of values from `git repo info`, you should provide
+the keys that identify them. Here's a list of the available keys and the
+values that they return:
+
+`references.format`::
+The reference storage format. The valid values are:
++
+include::ref-storage-format.adoc[]
 
 SEE ALSO
 --------
diff --git a/builtin/repo.c b/builtin/repo.c
index fd2a9b4216..6824e50d00 100644
--- a/builtin/repo.c
+++ b/builtin/repo.c
@@ -1,17 +1,103 @@
 #include "builtin.h"
 #include "parse-options.h"
+#include "quote.h"
+#include "refs.h"
+#include "strbuf.h"
 
 static const char *const repo_usage[] = {
 	"git repo info [<key>...]",
 	NULL
 };
 
-static int repo_info(int argc UNUSED, const char **argv UNUSED,
-		     const char *prefix UNUSED, struct repository *repo UNUSED)
+typedef int get_value_fn(struct repository *repo, struct strbuf *buf);
+
+struct field {
+	const char *key;
+	get_value_fn *get_value;
+};
+
+static int get_references_format(struct repository *repo, struct strbuf *buf)
 {
+	strbuf_addstr(buf,
+		      ref_storage_format_to_name(repo->ref_storage_format));
 	return 0;
 }
 
+/* repo_info_fields keys should be in lexicographical order */
+static const struct field repo_info_fields[] = {
+	{ "references.format", get_references_format },
+};
+
+static int repo_info_fields_cmp(const void *va, const void *vb)
+{
+	const struct field *a = va;
+	const struct field *b = vb;
+
+	return strcmp(a->key, b->key);
+}
+
+static get_value_fn *get_value_fn_for_key(const char *key)
+{
+	const struct field search_key = { key, NULL };
+	const struct field *found = bsearch(&search_key, repo_info_fields,
+					    ARRAY_SIZE(repo_info_fields),
+					    sizeof(*found),
+					    repo_info_fields_cmp);
+	return found ? found->get_value : NULL;
+}
+
+static int qsort_strcmp(const void *va, const void *vb)
+{
+	const char *a = *(const char **)va;
+	const char *b = *(const char **)vb;
+
+	return strcmp(a, b);
+}
+
+static int print_fields(int argc, const char **argv, struct repository *repo)
+{
+	int ret = 0;
+	const char *last = "";
+	struct strbuf sb = STRBUF_INIT;
+
+	QSORT(argv, argc, qsort_strcmp);
+
+	for (int i = 0; i < argc; i++) {
+		get_value_fn *get_value;
+		const char *key = argv[i];
+		char *value;
+
+		if (!strcmp(key, last))
+			continue;
+
+		get_value = get_value_fn_for_key(key);
+
+		if (!get_value) {
+			ret = error(_("key '%s' not found"), key);
+			continue;
+		}
+
+		strbuf_reset(&sb);
+		get_value(repo, &sb);
+
+		value = strbuf_detach(&sb, NULL);
+		quote_c_style(value, &sb, NULL, 0);
+		free(value);
+
+		printf("%s=%s\n", key, sb.buf);
+		last = key;
+	}
+
+	strbuf_release(&sb);
+	return ret;
+}
+
+static int repo_info(int argc, const char **argv, const char *prefix UNUSED,
+		     struct repository *repo)
+{
+	return print_fields(argc - 1, argv + 1, repo);
+}
+
 int cmd_repo(int argc, const char **argv, const char *prefix,
 	     struct repository *repo)
 {
diff --git a/t/meson.build b/t/meson.build
index 660d780dcc..5de9c3c7e9 100644
--- a/t/meson.build
+++ b/t/meson.build
@@ -245,6 +245,7 @@ integration_tests = [
   't1700-split-index.sh',
   't1701-racy-split-index.sh',
   't1800-hook.sh',
+  't1900-repo.sh',
   't2000-conflict-when-checking-files-out.sh',
   't2002-checkout-cache-u.sh',
   't2003-checkout-cache-mkdir.sh',
diff --git a/t/t1900-repo.sh b/t/t1900-repo.sh
new file mode 100755
index 0000000000..9796e36087
--- /dev/null
+++ b/t/t1900-repo.sh
@@ -0,0 +1,57 @@
+#!/bin/sh
+
+test_description='test git repo-info'
+
+. ./test-lib.sh
+
+# Test whether a key-value pair is correctly returned
+#
+# Usage: test_repo_info <label> <init command> <key> <expected value>
+#
+# Arguments:
+#   label: the label of the test
+#   init command: a command which creates a repository named with its first argument,
+#      accordingly to what is being tested
+#   key: the key of the field that is being tested
+#   expected value: the value that the field should contain
+test_repo_info () {
+	label=$1
+	init_command=$2
+	repo_name=$3
+	key=$4
+	expected_value=$5
+
+	test_expect_success "$label" '
+		eval "$init_command $repo_name" &&
+		echo "$key=$expected_value" >expected &&
+		git -C $repo_name repo info "$key" >actual &&
+		test_cmp expected actual
+	'
+}
+
+test_repo_info 'ref format files is retrieved correctly' '
+	git init --ref-format=files' 'format-files' 'references.format' 'files'
+
+test_repo_info 'ref format reftable is retrieved correctly' '
+	git init --ref-format=reftable' 'format-reftable' 'references.format' 'reftable'
+
+test_expect_success 'git-repo-info fails if an invalid key is requested' '
+	echo "error: key '\'foo\'' not found" >expected_err &&
+	test_must_fail git repo info foo 2>actual_err &&
+	test_cmp expected_err actual_err
+'
+
+test_expect_success 'git-repo-info outputs data even if there is an invalid field' '
+	echo "references.format=files" >expected &&
+	test_must_fail git repo info foo references.format bar >actual &&
+	test_cmp expected actual
+'
+
+test_expect_success 'only one value is returned if the same key is requested twice' '
+	val=$(git rev-parse --show-ref-format) &&
+	echo "references.format=$val" >expect &&
+	git repo info references.format references.format >actual &&
+	test_cmp expect actual
+'
+
+test_done
-- 
2.39.5 (Apple Git-154)
^ permalink raw reply related	[flat|nested] 226+ messages in thread
* [GSoC PATCH v7 3/5] repo: add the field layout.bare
  2025-08-01 13:11 ` [GSoC PATCH v7 " Lucas Seiki Oshiro
  2025-08-01 13:11   ` [GSoC PATCH v7 1/5] repo: declare the repo command Lucas Seiki Oshiro
  2025-08-01 13:11   ` [GSoC PATCH v7 2/5] repo: add the field references.format Lucas Seiki Oshiro
@ 2025-08-01 13:11   ` Lucas Seiki Oshiro
  2025-08-01 21:21     ` Eric Sunshine
  2025-08-05 12:50     ` Patrick Steinhardt
  2025-08-01 13:11   ` [GSoC PATCH v7 4/5] repo: add the field layout.shallow Lucas Seiki Oshiro
                     ` (2 subsequent siblings)
  5 siblings, 2 replies; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-08-01 13:11 UTC (permalink / raw)
  To: git
  Cc: oswald.buddenhagen, ps, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler, jn.avila, sunshine, Lucas Seiki Oshiro
This commit is part of the series that introduces the new subcommand
git-repo-info.
The flag --is-bare-repository from git-rev-parse is used for retrieving
whether the current repository is bare. This way, it is used for
querying repository metadata, fitting in the purpose of git-repo-info.
Then, add a new field layout.bare to the git-repo-info subcommand
containing that information.
Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Helped-by: Junio C Hamano <gitster@pobox.com>
Helped-by: Justin Tobler <jltobler@gmail.com>
Helped-by: Eric Sunshine <sunshine@sunshineco.com>
Mentored-by: Karthik Nayak <karthik.188@gmail.com>
Mentored-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
---
 Documentation/git-repo.adoc |  3 +++
 builtin/repo.c              | 11 +++++++++++
 t/t1900-repo.sh             | 14 ++++++++++++++
 3 files changed, 28 insertions(+)
diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc
index 2dd130f3dd..98358c5539 100644
--- a/Documentation/git-repo.adoc
+++ b/Documentation/git-repo.adoc
@@ -32,6 +32,9 @@ In order to obtain a set of values from `git repo info`, you should provide
 the keys that identify them. Here's a list of the available keys and the
 values that they return:
 
+`layout.bare`::
+`true` if this is a bare repository, otherwise `false`.
+
 `references.format`::
 The reference storage format. The valid values are:
 +
diff --git a/builtin/repo.c b/builtin/repo.c
index 6824e50d00..2d51bfa195 100644
--- a/builtin/repo.c
+++ b/builtin/repo.c
@@ -1,4 +1,7 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
 #include "builtin.h"
+#include "environment.h"
 #include "parse-options.h"
 #include "quote.h"
 #include "refs.h"
@@ -16,6 +19,13 @@ struct field {
 	get_value_fn *get_value;
 };
 
+static int get_layout_bare(struct repository *repo UNUSED, struct strbuf *buf)
+{
+	strbuf_addstr(buf,
+		      is_bare_repository() ? "true" : "false");
+	return 0;
+}
+
 static int get_references_format(struct repository *repo, struct strbuf *buf)
 {
 	strbuf_addstr(buf,
@@ -25,6 +35,7 @@ static int get_references_format(struct repository *repo, struct strbuf *buf)
 
 /* repo_info_fields keys should be in lexicographical order */
 static const struct field repo_info_fields[] = {
+	{ "layout.bare", get_layout_bare },
 	{ "references.format", get_references_format },
 };
 
diff --git a/t/t1900-repo.sh b/t/t1900-repo.sh
index 9796e36087..6c555e90c3 100755
--- a/t/t1900-repo.sh
+++ b/t/t1900-repo.sh
@@ -35,6 +35,12 @@ test_repo_info 'ref format files is retrieved correctly' '
 test_repo_info 'ref format reftable is retrieved correctly' '
 	git init --ref-format=reftable' 'format-reftable' 'references.format' 'reftable'
 
+test_repo_info 'bare repository = false is retrieved correctly' '
+	git init' 'bare' 'layout.bare' 'false'
+
+test_repo_info 'bare repository = true is retrieved correctly' '
+	git init --bare' 'nonbare' 'layout.bare' 'true'
+
 test_expect_success 'git-repo-info fails if an invalid key is requested' '
 	echo "error: key '\'foo\'' not found" >expected_err &&
 	test_must_fail git repo info foo 2>actual_err &&
@@ -54,4 +60,12 @@ test_expect_success 'only one value is returned if the same key is requested twi
 	test_cmp expect actual
 '
 
+test_expect_success 'output is returned correctly when two keys are requested' '
+	cat >expect <<-\EOF &&
+	layout.bare=false
+	references.format=files
+	EOF
+	git init --ref-format=files two-keys &&
+	git -C two-keys repo info layout.bare references.format
+'
 test_done
-- 
2.39.5 (Apple Git-154)
^ permalink raw reply related	[flat|nested] 226+ messages in thread
* [GSoC PATCH v7 4/5] repo: add the field layout.shallow
  2025-08-01 13:11 ` [GSoC PATCH v7 " Lucas Seiki Oshiro
                     ` (2 preceding siblings ...)
  2025-08-01 13:11   ` [GSoC PATCH v7 3/5] repo: add the field layout.bare Lucas Seiki Oshiro
@ 2025-08-01 13:11   ` Lucas Seiki Oshiro
  2025-08-05 12:50     ` Patrick Steinhardt
  2025-08-01 13:11   ` [GSoC PATCH v7 5/5] repo: add the --format flag Lucas Seiki Oshiro
  2025-08-05 12:50   ` [GSoC PATCH v7 0/5] repo: add new command for retrieving repository info Patrick Steinhardt
  5 siblings, 1 reply; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-08-01 13:11 UTC (permalink / raw)
  To: git
  Cc: oswald.buddenhagen, ps, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler, jn.avila, sunshine, Lucas Seiki Oshiro
This commit is part of the series that introduces the new subcommand
git-repo-info.
The flag `--is-shallow-repository` from git-rev-parse is used for
retrieving whether the repository is shallow. This way, it is used for
querying repository metadata, fitting in the purpose of git-repo-info.
Then, add a new field `layout.shallow` to the git-repo-info subcommand
containing that information.
Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Helped-by: Junio C Hamano <gitster@pobox.com>
Helped-by: Justin Tobler <jltobler@gmail.com>
Helped-by: Eric Sunshine <sunshine@sunshineco.com>
Mentored-by: Karthik Nayak <karthik.188@gmail.com>
Mentored-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
---
 Documentation/git-repo.adoc |  3 +++
 builtin/repo.c              |  9 +++++++++
 t/t1900-repo.sh             | 11 +++++++++++
 3 files changed, 23 insertions(+)
diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc
index 98358c5539..140ee3a0aa 100644
--- a/Documentation/git-repo.adoc
+++ b/Documentation/git-repo.adoc
@@ -35,6 +35,9 @@ values that they return:
 `layout.bare`::
 `true` if this is a bare repository, otherwise `false`.
 
+`layout.shallow`::
+`true` if this is a shallow repository, otherwise `false`.
+
 `references.format`::
 The reference storage format. The valid values are:
 +
diff --git a/builtin/repo.c b/builtin/repo.c
index 2d51bfa195..56c3a4027f 100644
--- a/builtin/repo.c
+++ b/builtin/repo.c
@@ -6,6 +6,7 @@
 #include "quote.h"
 #include "refs.h"
 #include "strbuf.h"
+#include "shallow.h"
 
 static const char *const repo_usage[] = {
 	"git repo info [<key>...]",
@@ -26,6 +27,13 @@ static int get_layout_bare(struct repository *repo UNUSED, struct strbuf *buf)
 	return 0;
 }
 
+static int get_layout_shallow(struct repository *repo, struct strbuf *buf)
+{
+	strbuf_addstr(buf,
+		      is_repository_shallow(repo) ? "true" : "false");
+	return 0;
+}
+
 static int get_references_format(struct repository *repo, struct strbuf *buf)
 {
 	strbuf_addstr(buf,
@@ -36,6 +44,7 @@ static int get_references_format(struct repository *repo, struct strbuf *buf)
 /* repo_info_fields keys should be in lexicographical order */
 static const struct field repo_info_fields[] = {
 	{ "layout.bare", get_layout_bare },
+	{ "layout.shallow", get_layout_shallow },
 	{ "references.format", get_references_format },
 };
 
diff --git a/t/t1900-repo.sh b/t/t1900-repo.sh
index 6c555e90c3..6706cb4c44 100755
--- a/t/t1900-repo.sh
+++ b/t/t1900-repo.sh
@@ -41,6 +41,16 @@ test_repo_info 'bare repository = false is retrieved correctly' '
 test_repo_info 'bare repository = true is retrieved correctly' '
 	git init --bare' 'nonbare' 'layout.bare' 'true'
 
+test_repo_info 'shallow repository = false is retrieved correctly' '
+	git init' 'nonshallow' 'layout.shallow' 'false'
+
+test_repo_info 'shallow repository = true is retrieved correctly' '
+	git init remote &&
+	echo x >remote/x &&
+	git -C remote add x &&
+	git -C remote commit -m x &&
+	git clone --depth 1 "file://$PWD/remote"' 'shallow' 'layout.shallow' 'true'
+
 test_expect_success 'git-repo-info fails if an invalid key is requested' '
 	echo "error: key '\'foo\'' not found" >expected_err &&
 	test_must_fail git repo info foo 2>actual_err &&
@@ -68,4 +78,5 @@ test_expect_success 'output is returned correctly when two keys are requested' '
 	git init --ref-format=files two-keys &&
 	git -C two-keys repo info layout.bare references.format
 '
+
 test_done
-- 
2.39.5 (Apple Git-154)
^ permalink raw reply related	[flat|nested] 226+ messages in thread
* [GSoC PATCH v7 5/5] repo: add the --format flag
  2025-08-01 13:11 ` [GSoC PATCH v7 " Lucas Seiki Oshiro
                     ` (3 preceding siblings ...)
  2025-08-01 13:11   ` [GSoC PATCH v7 4/5] repo: add the field layout.shallow Lucas Seiki Oshiro
@ 2025-08-01 13:11   ` Lucas Seiki Oshiro
  2025-08-01 19:25     ` Junio C Hamano
                       ` (3 more replies)
  2025-08-05 12:50   ` [GSoC PATCH v7 0/5] repo: add new command for retrieving repository info Patrick Steinhardt
  5 siblings, 4 replies; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-08-01 13:11 UTC (permalink / raw)
  To: git
  Cc: oswald.buddenhagen, ps, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler, jn.avila, sunshine, Lucas Seiki Oshiro
Add the --format flag to git-repo-info. By using this flag, the users
can choose the format for obtaining the data they requested.
Given that this command can be used for generating input for other
applications and for being read by end users, it requires at least two
formats: one for being read by humans and other for being read by
machines. Some other Git commands also have two output formats, notably
git-config which was the inspiration for the two formats that were
chosen here:
- keyvalue, where the retrieved data is printed one per line, using =
  for delimiting the key and the value. This is the default format,
  targeted for end users.
- nul, where the retrieved data is separated by null characters, using
  the newline character for delimiting the key and the value. This
  format is targeted for being read by machines.
Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Helped-by: Junio C Hamano <gitster@pobox.com>
Helped-by: Justin Tobler <jltobler@gmail.com>
Helped-by: Eric Sunshine <sunshine@sunshineco.com>
Mentored-by: Karthik Nayak <karthik.188@gmail.com>
Mentored-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
---
 Documentation/git-repo.adoc | 31 +++++++++++++++++++-
 builtin/repo.c              | 58 +++++++++++++++++++++++++++++++------
 t/t1900-repo.sh             | 21 ++++++++++++--
 3 files changed, 97 insertions(+), 13 deletions(-)
diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc
index 140ee3a0aa..b735cf4737 100644
--- a/Documentation/git-repo.adoc
+++ b/Documentation/git-repo.adoc
@@ -18,12 +18,23 @@ THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOR MAY CHANGE.
 
 COMMANDS
 --------
-`info [<key>...]`::
+`info [--format=<keyvalue|nul>] [<key>...]`::
 	Retrieve metadata-related information about the current repository. Only
 	the requested data will be returned based on their keys (see "INFO KEYS"
 	section below).
 +
 The returned data is lexicographically sorted by the keys.
++
+The output format can be chosen through the flag `--format`. Two formats are
+supported:
++
+* `keyvalue`: output key-value pairs one per line using the `=` character as
+the delimiter between the key and the value. This is the default.
+
+* `nul`: similar to `keyvalue`, but using a newline character as the delimiter
+between the key and the value and using a null character after each value.
+This format is better suited for being parsed by another applications than
+`keyvalue`.
 
 INFO KEYS
 ---------
@@ -43,6 +54,24 @@ The reference storage format. The valid values are:
 +
 include::ref-storage-format.adoc[]
 
+
+Examples
+--------
+
+* Retrieves the reference format of the current repository:
++
+------------
+git repo info references.format
+------------
++
+
+* Retrieves whether the current repository is bare and whether it is shallow
+using the `nul` format:
++
+------------
+git repo info --format=nul layout.bare layout.shallow
+------------
+
 SEE ALSO
 --------
 linkgit:git-rev-parse[1]
diff --git a/builtin/repo.c b/builtin/repo.c
index 56c3a4027f..4015cf88b7 100644
--- a/builtin/repo.c
+++ b/builtin/repo.c
@@ -9,12 +9,17 @@
 #include "shallow.h"
 
 static const char *const repo_usage[] = {
-	"git repo info [<key>...]",
+	"git repo info [--format=<keyvalue|nul>] [<key>...]",
 	NULL
 };
 
 typedef int get_value_fn(struct repository *repo, struct strbuf *buf);
 
+enum output_format {
+	FORMAT_KEYVALUE,
+	FORMAT_NUL_TERMINATED,
+};
+
 struct field {
 	const char *key;
 	get_value_fn *get_value;
@@ -74,18 +79,33 @@ static int qsort_strcmp(const void *va, const void *vb)
 	return strcmp(a, b);
 }
 
-static int print_fields(int argc, const char **argv, struct repository *repo)
+static int print_fields(int argc, const char **argv,
+			struct repository *repo,
+			enum output_format format)
 {
 	int ret = 0;
 	const char *last = "";
 	struct strbuf sb = STRBUF_INIT;
 
+	char kv_sep;
+	char field_sep;
+
+	switch (format) {
+	case FORMAT_KEYVALUE:
+		kv_sep = '=';
+		field_sep = '\n';
+		break;
+	case FORMAT_NUL_TERMINATED:
+		kv_sep = '\n';
+		field_sep = '\0';
+		break;
+	}
+
 	QSORT(argv, argc, qsort_strcmp);
 
 	for (int i = 0; i < argc; i++) {
 		get_value_fn *get_value;
 		const char *key = argv[i];
-		char *value;
 
 		if (!strcmp(key, last))
 			continue;
@@ -100,11 +120,14 @@ static int print_fields(int argc, const char **argv, struct repository *repo)
 		strbuf_reset(&sb);
 		get_value(repo, &sb);
 
-		value = strbuf_detach(&sb, NULL);
-		quote_c_style(value, &sb, NULL, 0);
-		free(value);
+		if (format == FORMAT_KEYVALUE) {
+			char *value;
+			value = strbuf_detach(&sb, NULL);
+			quote_c_style(value, &sb, NULL, 0);
+			free(value);
+		}
 
-		printf("%s=%s\n", key, sb.buf);
+		printf("%s%c%s%c", key, kv_sep, sb.buf, field_sep);
 		last = key;
 	}
 
@@ -112,10 +135,27 @@ static int print_fields(int argc, const char **argv, struct repository *repo)
 	return ret;
 }
 
-static int repo_info(int argc, const char **argv, const char *prefix UNUSED,
+static int repo_info(int argc, const char **argv, const char *prefix,
 		     struct repository *repo)
 {
-	return print_fields(argc - 1, argv + 1, repo);
+	const char *format_str = "keyvalue";
+	enum output_format format;
+	struct option options[] = {
+		OPT_STRING(0, "format", &format_str, N_("format"),
+			   N_("output format")),
+		OPT_END()
+	};
+
+	argc = parse_options(argc, argv, prefix, options, repo_usage, 0);
+
+	if (!strcmp(format_str, "keyvalue"))
+		format = FORMAT_KEYVALUE;
+	else if (!strcmp(format_str, "nul"))
+		format = FORMAT_NUL_TERMINATED;
+	else
+		die(_("invalid format '%s'"), format_str);
+
+	return print_fields(argc, argv, repo, format);
 }
 
 int cmd_repo(int argc, const char **argv, const char *prefix,
diff --git a/t/t1900-repo.sh b/t/t1900-repo.sh
index 6706cb4c44..463ec3af92 100755
--- a/t/t1900-repo.sh
+++ b/t/t1900-repo.sh
@@ -21,10 +21,17 @@ test_repo_info () {
 	key=$4
 	expected_value=$5
 
-	test_expect_success "$label" '
-		eval "$init_command $repo_name" &&
+	test_expect_success "keyvalue: $label" '
+		eval "$init_command keyvalue-$repo_name" &&
 		echo "$key=$expected_value" >expected &&
-		git -C $repo_name repo info "$key" >actual &&
+		git -C keyvalue-$repo_name repo info "$key" >actual &&
+		test_cmp expected actual
+	'
+
+	test_expect_success "nul: $label" '
+		eval "$init_command nul-$repo_name" &&
+		printf "%s\n%s\0" "$key" "$expected_value" >expected &&
+		git -C nul-$repo_name repo info --format=nul "$key" >actual &&
 		test_cmp expected actual
 	'
 }
@@ -45,6 +52,7 @@ test_repo_info 'shallow repository = false is retrieved correctly' '
 	git init' 'nonshallow' 'layout.shallow' 'false'
 
 test_repo_info 'shallow repository = true is retrieved correctly' '
+	test_when_finished "rm -rf remote" &&
 	git init remote &&
 	echo x >remote/x &&
 	git -C remote add x &&
@@ -79,4 +87,11 @@ test_expect_success 'output is returned correctly when two keys are requested' '
 	git -C two-keys repo info layout.bare references.format
 '
 
+test_expect_success 'git-repo-info aborts when requesting an invalid format' '
+	test_when_finished "rm -f err expected" &&
+	echo "fatal: invalid format '\'foo\''" >expected &&
+	test_must_fail git repo info --format=foo 2>err &&
+	test_cmp expected err
+'
+
 test_done
-- 
2.39.5 (Apple Git-154)
^ permalink raw reply related	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v7 5/5] repo: add the --format flag
  2025-08-01 13:11   ` [GSoC PATCH v7 5/5] repo: add the --format flag Lucas Seiki Oshiro
@ 2025-08-01 19:25     ` Junio C Hamano
  2025-08-01 20:27     ` Jean-Noël AVILA
                       ` (2 subsequent siblings)
  3 siblings, 0 replies; 226+ messages in thread
From: Junio C Hamano @ 2025-08-01 19:25 UTC (permalink / raw)
  To: Lucas Seiki Oshiro
  Cc: git, oswald.buddenhagen, ps, karthik.188, ben.knoble,
	phillip.wood, jltobler, jn.avila, sunshine
Lucas Seiki Oshiro <lucasseikioshiro@gmail.com> writes:
> Add the --format flag to git-repo-info. By using this flag, the users
> can choose the format for obtaining the data they requested.
>
> Given that this command can be used for generating input for other
> applications and for being read by end users, it requires at least two
> formats: one for being read by humans and other for being read by
> machines. Some other Git commands also have two output formats, notably
> git-config which was the inspiration for the two formats that were
> chosen here:
>
> - keyvalue, where the retrieved data is printed one per line, using =
>   for delimiting the key and the value. This is the default format,
>   targeted for end users.
> - nul, where the retrieved data is separated by null characters, using
>   the newline character for delimiting the key and the value. This
>   format is targeted for being read by machines.
>
> Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
> Helped-by: Junio C Hamano <gitster@pobox.com>
> Helped-by: Justin Tobler <jltobler@gmail.com>
> Helped-by: Eric Sunshine <sunshine@sunshineco.com>
> Mentored-by: Karthik Nayak <karthik.188@gmail.com>
> Mentored-by: Patrick Steinhardt <ps@pks.im>
> Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
> ---
>  Documentation/git-repo.adoc | 31 +++++++++++++++++++-
>  builtin/repo.c              | 58 +++++++++++++++++++++++++++++++------
>  t/t1900-repo.sh             | 21 ++++++++++++--
>  3 files changed, 97 insertions(+), 13 deletions(-)
This will break t0450, won't it?
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v7 5/5] repo: add the --format flag
  2025-08-01 13:11   ` [GSoC PATCH v7 5/5] repo: add the --format flag Lucas Seiki Oshiro
  2025-08-01 19:25     ` Junio C Hamano
@ 2025-08-01 20:27     ` Jean-Noël AVILA
  2025-08-01 21:50     ` Eric Sunshine
  2025-08-05 12:50     ` Patrick Steinhardt
  3 siblings, 0 replies; 226+ messages in thread
From: Jean-Noël AVILA @ 2025-08-01 20:27 UTC (permalink / raw)
  To: git, Lucas Seiki Oshiro
  Cc: oswald.buddenhagen, ps, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler, sunshine, Lucas Seiki Oshiro
On Friday, 1 August 2025 15:11:10 CEST Lucas Seiki Oshiro wrote:
> Add the --format flag to git-repo-info. By using this flag, the users
> can choose the format for obtaining the data they requested.
> 
> Given that this command can be used for generating input for other
> applications and for being read by end users, it requires at least two
> formats: one for being read by humans and other for being read by
> machines. Some other Git commands also have two output formats, notably
> git-config which was the inspiration for the two formats that were
> chosen here:
> 
> - keyvalue, where the retrieved data is printed one per line, using =
>   for delimiting the key and the value. This is the default format,
>   targeted for end users.
> - nul, where the retrieved data is separated by null characters, using
>   the newline character for delimiting the key and the value. This
>   format is targeted for being read by machines.
> 
> Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
> Helped-by: Junio C Hamano <gitster@pobox.com>
> Helped-by: Justin Tobler <jltobler@gmail.com>
> Helped-by: Eric Sunshine <sunshine@sunshineco.com>
> Mentored-by: Karthik Nayak <karthik.188@gmail.com>
> Mentored-by: Patrick Steinhardt <ps@pks.im>
> Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
> ---
>  Documentation/git-repo.adoc | 31 +++++++++++++++++++-
>  builtin/repo.c              | 58 +++++++++++++++++++++++++++++++------
>  t/t1900-repo.sh             | 21 ++++++++++++--
>  3 files changed, 97 insertions(+), 13 deletions(-)
> 
> diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc
> index 140ee3a0aa..b735cf4737 100644
> --- a/Documentation/git-repo.adoc
> +++ b/Documentation/git-repo.adoc
> @@ -18,12 +18,23 @@ THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOR MAY CHANGE.
> 
>  COMMANDS
>  --------
> -`info [<key>...]`::
> +`info [--format=<keyvalue|nul>] [<key>...]`::
According to the source code, I understand that this line should read:
`info [--format=(keyvalue|nul)] [<key>...]`::
With parentheses, which is that `keyvalue` and `nul` are keywords describing 
the type of format.
>  	Retrieve metadata-related information about the current 
repository. Only
>  	the requested data will be returned based on their keys (see "INFO 
KEYS"
>  	section below).
>  +
>  The returned data is lexicographically sorted by the keys.
> ++
> +The output format can be chosen through the flag `--format`. Two formats are
> +supported:
> ++
> +* `keyvalue`: output key-value pairs one per line using the `=` character 
as
> +the delimiter between the key and the value. This is the default.
> +
> +* `nul`: similar to `keyvalue`, but using a newline character as the 
delimiter
> +between the key and the value and using a null character after each value.
> +This format is better suited for being parsed by another applications than
> +`keyvalue`.
> 
>  INFO KEYS
>  ---------
> @@ -43,6 +54,24 @@ The reference storage format. The valid values are:
>  +
>  include::ref-storage-format.adoc[]
> 
> +
> +Examples
> +--------
> +
> +* Retrieves the reference format of the current repository:
> ++
> +------------
> +git repo info references.format
> +------------
> ++
> +
> +* Retrieves whether the current repository is bare and whether it is 
shallow
> +using the `nul` format:
> ++
> +------------
> +git repo info --format=nul layout.bare layout.shallow
> +------------
> +
>  SEE ALSO
>  --------
>  linkgit:git-rev-parse[1]
> diff --git a/builtin/repo.c b/builtin/repo.c
> index 56c3a4027f..4015cf88b7 100644
> --- a/builtin/repo.c
> +++ b/builtin/repo.c
> @@ -9,12 +9,17 @@
>  #include "shallow.h"
> 
>  static const char *const repo_usage[] = {
> -	"git repo info [<key>...]",
> +	"git repo info [--format=<keyvalue|nul>] [<key>...]",
>  	NULL
>  };
> 
>  typedef int get_value_fn(struct repository *repo, struct strbuf *buf);
> 
> +enum output_format {
> +	FORMAT_KEYVALUE,
> +	FORMAT_NUL_TERMINATED,
> +};
> +
>  struct field {
>  	const char *key;
>  	get_value_fn *get_value;
> @@ -74,18 +79,33 @@ static int qsort_strcmp(const void *va, const void *vb)
>  	return strcmp(a, b);
>  }
> 
> -static int print_fields(int argc, const char **argv, struct repository 
*repo)
> +static int print_fields(int argc, const char **argv,
> +			struct repository *repo,
> +			enum output_format format)
>  {
>  	int ret = 0;
>  	const char *last = "";
>  	struct strbuf sb = STRBUF_INIT;
> 
> +	char kv_sep;
> +	char field_sep;
> +
> +	switch (format) {
> +	case FORMAT_KEYVALUE:
> +		kv_sep = '=';
> +		field_sep = '\n';
> +		break;
> +	case FORMAT_NUL_TERMINATED:
> +		kv_sep = '\n';
> +		field_sep = '\0';
> +		break;
> +	}
> +
>  	QSORT(argv, argc, qsort_strcmp);
> 
>  	for (int i = 0; i < argc; i++) {
>  		get_value_fn *get_value;
>  		const char *key = argv[i];
> -		char *value;
> 
>  		if (!strcmp(key, last))
>  			continue;
> @@ -100,11 +120,14 @@ static int print_fields(int argc, const char **argv, 
struct
> repository *repo) strbuf_reset(&sb);
>  		get_value(repo, &sb);
> 
> -		value = strbuf_detach(&sb, NULL);
> -		quote_c_style(value, &sb, NULL, 0);
> -		free(value);
> +		if (format == FORMAT_KEYVALUE) {
> +			char *value;
> +			value = strbuf_detach(&sb, NULL);
> +			quote_c_style(value, &sb, NULL, 0);
> +			free(value);
> +		}
> 
> -		printf("%s=%s\n", key, sb.buf);
> +		printf("%s%c%s%c", key, kv_sep, sb.buf, field_sep);
>  		last = key;
>  	}
> 
> @@ -112,10 +135,27 @@ static int print_fields(int argc, const char **argv, 
struct
> repository *repo) return ret;
>  }
> 
> -static int repo_info(int argc, const char **argv, const char *prefix UNUSED,
> +static int repo_info(int argc, const char **argv, const char *prefix,
>  		     struct repository *repo)
>  {
> -	return print_fields(argc - 1, argv + 1, repo);
> +	const char *format_str = "keyvalue";
> +	enum output_format format;
> +	struct option options[] = {
> +		OPT_STRING(0, "format", &format_str, N_("format"),
> +			   N_("output format")),
> +		OPT_END()
> +	};
> +
> +	argc = parse_options(argc, argv, prefix, options, repo_usage, 0);
> +
> +	if (!strcmp(format_str, "keyvalue"))
> +		format = FORMAT_KEYVALUE;
> +	else if (!strcmp(format_str, "nul"))
> +		format = FORMAT_NUL_TERMINATED;
> +	else
> +		die(_("invalid format '%s'"), format_str);
> +
> +	return print_fields(argc, argv, repo, format);
>  }
> 
>  int cmd_repo(int argc, const char **argv, const char *prefix,
> diff --git a/t/t1900-repo.sh b/t/t1900-repo.sh
> index 6706cb4c44..463ec3af92 100755
> --- a/t/t1900-repo.sh
> +++ b/t/t1900-repo.sh
> @@ -21,10 +21,17 @@ test_repo_info () {
>  	key=$4
>  	expected_value=$5
> 
> -	test_expect_success "$label" '
> -		eval "$init_command $repo_name" &&
> +	test_expect_success "keyvalue: $label" '
> +		eval "$init_command keyvalue-$repo_name" &&
>  		echo "$key=$expected_value" >expected &&
> -		git -C $repo_name repo info "$key" >actual &&
> +		git -C keyvalue-$repo_name repo info "$key" >actual &&
> +		test_cmp expected actual
> +	'
> +
> +	test_expect_success "nul: $label" '
> +		eval "$init_command nul-$repo_name" &&
> +		printf "%s\n%s\0" "$key" "$expected_value" >expected &&
> +		git -C nul-$repo_name repo info --format=nul "$key" 
>actual &&
>  		test_cmp expected actual
>  	'
>  }
> @@ -45,6 +52,7 @@ test_repo_info 'shallow repository = false is retrieved
> correctly' ' git init' 'nonshallow' 'layout.shallow' 'false'
> 
>  test_repo_info 'shallow repository = true is retrieved correctly' '
> +	test_when_finished "rm -rf remote" &&
>  	git init remote &&
>  	echo x >remote/x &&
>  	git -C remote add x &&
> @@ -79,4 +87,11 @@ test_expect_success 'output is returned correctly when 
two keys
> are requested' ' git -C two-keys repo info layout.bare references.format
>  '
> 
> +test_expect_success 'git-repo-info aborts when requesting an invalid 
format' '
> +	test_when_finished "rm -f err expected" &&
> +	echo "fatal: invalid format '\'foo\''" >expected &&
> +	test_must_fail git repo info --format=foo 2>err &&
> +	test_cmp expected err
> +'
> +
>  test_done
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v7 2/5] repo: add the field references.format
  2025-08-01 13:11   ` [GSoC PATCH v7 2/5] repo: add the field references.format Lucas Seiki Oshiro
@ 2025-08-01 20:59     ` Eric Sunshine
  2025-08-03 21:47       ` Lucas Seiki Oshiro
  0 siblings, 1 reply; 226+ messages in thread
From: Eric Sunshine @ 2025-08-01 20:59 UTC (permalink / raw)
  To: Lucas Seiki Oshiro
  Cc: git, oswald.buddenhagen, ps, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler, jn.avila
On Fri, Aug 1, 2025 at 9:11 AM Lucas Seiki Oshiro
<lucasseikioshiro@gmail.com> wrote:
> This commit is part of the series that introduces the new subcommand
> git-repo-info.
> [...]
> Add a new field `references.format` to the repo-info subcommand
> containing that information.
>
> Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
> ---
> diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc
> @@ -22,6 +22,20 @@ COMMANDS
> +In order to obtain a set of values from `git repo info`, you should provide
> +the keys that identify them. Here's a list of the available keys and the
> +values that they return:
> +
> +`references.format`::
> +The reference storage format. The valid values are:
> ++
> +include::ref-storage-format.adoc[]
In the implementation below, I see that this version of the series
passes all the printed values through quote_c_style(), which is a
welcome change, however, an equally (if not more) important change
seems to be missing. Namely, we _must_ document that values with
"funny" characters will be C-style quoted. Without such documentation,
consumers are left in the same sort of situation as they were in
without quote_c_style(); to wit, they will be surprised and their
tooling may break when they suddenly encounter a value which is
quoted.
> diff --git a/builtin/repo.c b/builtin/repo.c
> +static int print_fields(int argc, const char **argv, struct repository *repo)
> +{
> +       int ret = 0;
> +       const char *last = "";
> +       struct strbuf sb = STRBUF_INIT;
> +
> +       QSORT(argv, argc, qsort_strcmp);
> +
> +       for (int i = 0; i < argc; i++) {
> +               get_value_fn *get_value;
> +               const char *key = argv[i];
> +               char *value;
> +
> +               if (!strcmp(key, last))
> +                       continue;
> +
> +               get_value = get_value_fn_for_key(key);
> +
> +               if (!get_value) {
> +                       ret = error(_("key '%s' not found"), key);
> +                       continue;
> +               }
> +
> +               strbuf_reset(&sb);
> +               get_value(repo, &sb);
> +
> +               value = strbuf_detach(&sb, NULL);
> +               quote_c_style(value, &sb, NULL, 0);
> +               free(value);
> +
> +               printf("%s=%s\n", key, sb.buf);
> +               last = key;
> +       }
> +
> +       strbuf_release(&sb);
> +       return ret;
> +}
This logic leads to a poor user-experience if the user asks for the
same non-existent key multiple times since that case subverts the
deduplication logic. For instance:
    % git repo info non.existent references.format non.existent
    key 'non.existent' not found
    key 'non.existent' not found
    references.format=gobbledygook
You can fix this by performing the `last` assignment earlier in the
loop prior to any other `continue` statements:
    if (!strcmp(key, last))
        continue;
    last = key;
    get_value = get_value_fn_for_key(key);
    if (!get_value) {
        ret = error(_("key '%s' not found"), key);
        continue;
    }
That aside, the strbuf detach/repurpose/free dance that the code does:
    value = strbuf_detach(&sb, NULL);
    quote_c_style(value, &sb, NULL, 0);
    free(value);
is unnecessarily confusing and difficult to fathom because it is
repurposing the strubuf and increasing the number of allocations and
deallocations for no apparent reason. You can decrease the cognitive
load simply by using two strbufs, one for each distinct purpose,
perhaps like this:
    struct strbuf valbuf = STRBUF_INIT;
    struct strbuf quotbuf = STRBUF_INIT;
    ...
    for (int i = 0; i < argc; i++) {
        ...
        strbuf_reset(&valbuf);
        strbuf_reset("buf);
        get_value(repo, &valbuf);
        quote_c_style(valbuf.buf, "buf, NULL, 0);
        printf("%s=%s\n", key, quotbuf.buf);
    }
    strbuf_release("buf);
    strbuf_release(&valbuf);
> diff --git a/t/t1900-repo.sh b/t/t1900-repo.sh
> @@ -0,0 +1,57 @@
> +# Test whether a key-value pair is correctly returned
> +#
> +# Usage: test_repo_info <label> <init command> <key> <expected value>
> +#
> +# Arguments:
> +#   label: the label of the test
> +#   init command: a command which creates a repository named with its first argument,
> +#      accordingly to what is being tested
> +#   key: the key of the field that is being tested
> +#   expected value: the value that the field should contain
> +test_repo_info () {
> +       label=$1
> +       init_command=$2
> +       repo_name=$3
> +       key=$4
> +       expected_value=$5
The function documentation (including "Usage") talks about four
arguments, but the function expects five.
I'm having trouble understanding what is meant by "repository named
with its first argument accordingly to what is being tested". Also:
s/accordingly/according/
> +       test_expect_success "$label" '
> +               eval "$init_command $repo_name" &&
> +               echo "$key=$expected_value" >expected &&
> +               git -C $repo_name repo info "$key" >actual &&
> +               test_cmp expected actual
> +       '
> +}
> +
> +test_expect_success 'git-repo-info outputs data even if there is an invalid field' '
> +       echo "references.format=files" >expected &&
> +       test_must_fail git repo info foo references.format bar >actual &&
> +       test_cmp expected actual
> +'
> +
> +test_expect_success 'only one value is returned if the same key is requested twice' '
> +       val=$(git rev-parse --show-ref-format) &&
> +       echo "references.format=$val" >expect &&
> +       git repo info references.format references.format >actual &&
> +       test_cmp expect actual
> +'
These tests are easier to understand and are more robust in this version. Good.
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v7 3/5] repo: add the field layout.bare
  2025-08-01 13:11   ` [GSoC PATCH v7 3/5] repo: add the field layout.bare Lucas Seiki Oshiro
@ 2025-08-01 21:21     ` Eric Sunshine
  2025-08-03 22:54       ` Lucas Seiki Oshiro
  2025-08-05 12:50     ` Patrick Steinhardt
  1 sibling, 1 reply; 226+ messages in thread
From: Eric Sunshine @ 2025-08-01 21:21 UTC (permalink / raw)
  To: Lucas Seiki Oshiro
  Cc: git, oswald.buddenhagen, ps, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler, jn.avila
On Fri, Aug 1, 2025 at 9:11 AM Lucas Seiki Oshiro
<lucasseikioshiro@gmail.com> wrote:
> This commit is part of the series that introduces the new subcommand
> git-repo-info.
>
> The flag --is-bare-repository from git-rev-parse is used for retrieving
> whether the current repository is bare. This way, it is used for
> querying repository metadata, fitting in the purpose of git-repo-info.
>
> Then, add a new field layout.bare to the git-repo-info subcommand
> containing that information.
>
> Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
> ---
> diff --git a/builtin/repo.c b/builtin/repo.c
> @@ -16,6 +19,13 @@ struct field {
> +static int get_layout_bare(struct repository *repo UNUSED, struct strbuf *buf)
> +{
> +       strbuf_addstr(buf,
> +                     is_bare_repository() ? "true" : "false");
> +       return 0;
> +}
Nit: You can drop the unnecessary line wrapping:
    strbuf_addstr(buf, is_bare_repository() ? "true" : "false");
But don't re-roll just for this.
> diff --git a/t/t1900-repo.sh b/t/t1900-repo.sh
> @@ -35,6 +35,12 @@ test_repo_info 'ref format files is retrieved correctly' '
> +test_repo_info 'bare repository = false is retrieved correctly' '
> +       git init' 'bare' 'layout.bare' 'false'
> +
> +test_repo_info 'bare repository = true is retrieved correctly' '
> +       git init --bare' 'nonbare' 'layout.bare' 'true'
The quote placement used in these calls to `test_repo_info` is quite
unusual and more than a little confusing. I'm guessing you did it this
way to avoid having to use a backslash to continue the line or did it
to mimic how `test_expect/fail` is called, but it makes the function
call more difficult to understand than it ought to be. Instead, call
the function in the more traditional way:
    test_repo_info 'bare repository = true is retrieved correctly' \
        'git init --bare' 'nonbare' 'layout.bare' 'true'
This comment applies to the previous patch, as well, but I didn't
notice the issue when reviewing that patch.
> @@ -54,4 +60,12 @@ test_expect_success 'only one value is returned if the same key is requested twi
> +test_expect_success 'output is returned correctly when two keys are requested' '
> +       cat >expect <<-\EOF &&
> +       layout.bare=false
> +       references.format=files
> +       EOF
> +       git init --ref-format=files two-keys &&
> +       git -C two-keys repo info layout.bare references.format
> +'
It's good to see use of the heredoc as suggested in the previous
review, but isn't this test missing something important? Namely, it's
never comparing the actual output to the expected output; in fact,
it's never even capturing the actual output.
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v7 5/5] repo: add the --format flag
  2025-08-01 13:11   ` [GSoC PATCH v7 5/5] repo: add the --format flag Lucas Seiki Oshiro
  2025-08-01 19:25     ` Junio C Hamano
  2025-08-01 20:27     ` Jean-Noël AVILA
@ 2025-08-01 21:50     ` Eric Sunshine
  2025-08-05 12:50     ` Patrick Steinhardt
  3 siblings, 0 replies; 226+ messages in thread
From: Eric Sunshine @ 2025-08-01 21:50 UTC (permalink / raw)
  To: Lucas Seiki Oshiro
  Cc: git, oswald.buddenhagen, ps, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler, jn.avila
On Fri, Aug 1, 2025 at 9:11 AM Lucas Seiki Oshiro
<lucasseikioshiro@gmail.com> wrote:
> Add the --format flag to git-repo-info. By using this flag, the users
> can choose the format for obtaining the data they requested.
>
> Given that this command can be used for generating input for other
> applications and for being read by end users, it requires at least two
> formats: one for being read by humans and other for being read by
> machines. Some other Git commands also have two output formats, notably
> git-config which was the inspiration for the two formats that were
> chosen here:
>
> - keyvalue, where the retrieved data is printed one per line, using =
>   for delimiting the key and the value. This is the default format,
>   targeted for end users.
> - nul, where the retrieved data is separated by null characters, using
>   the newline character for delimiting the key and the value. This
>   format is targeted for being read by machines.
>
> Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
> ---
> diff --git a/t/t1900-repo.sh b/t/t1900-repo.sh
> @@ -21,10 +21,17 @@ test_repo_info () {
> -       test_expect_success "$label" '
> -               eval "$init_command $repo_name" &&
> +       test_expect_success "keyvalue: $label" '
> +               eval "$init_command keyvalue-$repo_name" &&
>                 echo "$key=$expected_value" >expected &&
> -               git -C $repo_name repo info "$key" >actual &&
> +               git -C keyvalue-$repo_name repo info "$key" >actual &&
> +               test_cmp expected actual
> +       '
> +
> +       test_expect_success "nul: $label" '
> +               eval "$init_command nul-$repo_name" &&
> +               printf "%s\n%s\0" "$key" "$expected_value" >expected &&
> +               git -C nul-$repo_name repo info --format=nul "$key" >actual &&
>                 test_cmp expected actual
>         '
Due to the embedded NUL's in this new "nul" test, I'm pretty sure you
want to be using `test_cmp_bin` here as suggested previously[*].
[*]: https://lore.kernel.org/git/CAPig+cQn7c5+k06yHOD2jxYTGnny7is=fbo4tOw26eD+4zX-Jw@mail.gmail.com/
> @@ -45,6 +52,7 @@ test_repo_info 'shallow repository = false is retrieved correctly' '
>  test_repo_info 'shallow repository = true is retrieved correctly' '
> +       test_when_finished "rm -rf remote" &&
>         git init remote &&
>         echo x >remote/x &&
>         git -C remote add x &&
For what it's worth, it would be clearer to turn the removal of
"remote" into a "make sure we have a clean-slate for what we are about
to do" rather than making it an after-the-fact cleanup. That is:
    test_repo_info 'shallow repository = true is retrieved correctly' '
        rm -rf remote &&
        git init remote &&
        ...
    '
Alternatively, since the "remote" repository is static in the sense
that it is the same for both the "keyvalue" and "nul" cases, it would
be even clearer to just separate it out into its own "setup"-style
test:
    test_expect_success 'setup remote' '
        git init remote &&
        echo x >remote/x &&
        ...
    '
    test_repo_info 'shallow repository = true is retrieved correctly' \
       'git clone --depth 1 "file://$PWD/remote"' 'shallow'
'layout.shallow' 'true'
> @@ -79,4 +87,11 @@ test_expect_success 'output is returned correctly when two keys are requested' '
> +test_expect_success 'git-repo-info aborts when requesting an invalid format' '
> +       test_when_finished "rm -f err expected" &&
> +       echo "fatal: invalid format '\'foo\''" >expected &&
> +       test_must_fail git repo info --format=foo 2>err &&
> +       test_cmp expected err
> +'
Do we need to perform this `test_when_finished` cleanup? As mentioned
in earlier reviews, we don't usually perform cleanup unnecessarily
since doing so slows down the test suite and makes it more difficult
to debug a failing test.
Also, didn't patch [2/5] already add this exact test?
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v7 2/5] repo: add the field references.format
  2025-08-01 20:59     ` Eric Sunshine
@ 2025-08-03 21:47       ` Lucas Seiki Oshiro
  0 siblings, 0 replies; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-08-03 21:47 UTC (permalink / raw)
  To: Eric Sunshine
  Cc: git, oswald.buddenhagen, ps, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler, jn.avila
> This logic leads to a poor user-experience if the user asks for the
> same non-existent key multiple times since that case subverts the
> deduplication logic.
Makes sense. I'll change it in v8.
> is unnecessarily confusing and difficult to fathom because it is
> repurposing the strubuf and increasing the number of allocations and
> deallocations for no apparent reason.
Agreed. Given that the strings that I'm storing are relatively small,
it won't hurt to have two strbufs. I'll incorporate your suggestion.
> The function documentation (including "Usage") talks about four
> arguments, but the function expects five.
I changed the parameters but I forgot to change the docs. I'll
change it in v8.
> I'm having trouble understanding what is meant by "repository named
> with its first argument accordingly to what is being tested".
Indeed, this is confusing. Actually, this solution of using
`eval "$init_command $repo_name"` is quite fragile. I'll change it
to a more robust solution.
> These tests are easier to understand and are more robust in this version. Good.
Thanks, Eric. Your reviews were really helpful for making these
tests better!
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v7 3/5] repo: add the field layout.bare
  2025-08-01 21:21     ` Eric Sunshine
@ 2025-08-03 22:54       ` Lucas Seiki Oshiro
  2025-08-03 23:06         ` Eric Sunshine
  0 siblings, 1 reply; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-08-03 22:54 UTC (permalink / raw)
  To: Eric Sunshine
  Cc: git, oswald.buddenhagen, ps, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler, jn.avila
> The quote placement used in these calls to `test_repo_info` is quite
> unusual and more than a little confusing. I'm guessing you did it this
> way to avoid having to use a backslash to continue the line or did it
> to mimic how `test_expect/fail` is called
Yeah, that's true :-). I'll change it. However, in the next patch, where
I add `repository.shallow`, I need a more complex script for creating
a shallow repository which needs several lines. In this case, do you
think it would it be better to use the backslash before the line break
or would it be like it currently is?
Thanks!
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v7 3/5] repo: add the field layout.bare
  2025-08-03 22:54       ` Lucas Seiki Oshiro
@ 2025-08-03 23:06         ` Eric Sunshine
  0 siblings, 0 replies; 226+ messages in thread
From: Eric Sunshine @ 2025-08-03 23:06 UTC (permalink / raw)
  To: Lucas Seiki Oshiro
  Cc: git, oswald.buddenhagen, ps, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler, jn.avila
On Sun, Aug 3, 2025 at 6:54 PM Lucas Seiki Oshiro
<lucasseikioshiro@gmail.com> wrote:
> > The quote placement used in these calls to `test_repo_info` is quite
> > unusual and more than a little confusing. I'm guessing you did it this
> > way to avoid having to use a backslash to continue the line or did it
> > to mimic how `test_expect/fail` is called
>
> Yeah, that's true :-). I'll change it. However, in the next patch, where
> I add `repository.shallow`, I need a more complex script for creating
> a shallow repository which needs several lines. In this case, do you
> think it would it be better to use the backslash before the line break
> or would it be like it currently is?
If you take the suggestion I made in my review[*] of that subsequent
patch (specifically, create a separate "setup"-style test), then I'm
pretty sure you won't need to use the complex script for the function
argument; it should collapse to a single line as shown in [*].
[*]: https://lore.kernel.org/git/CAPig+cTtJHn3NxrXF-AU_0cRzccDOo+j8JTAq1Jyqm4BzXBpSw@mail.gmail.com/
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v7 3/5] repo: add the field layout.bare
  2025-08-01 13:11   ` [GSoC PATCH v7 3/5] repo: add the field layout.bare Lucas Seiki Oshiro
  2025-08-01 21:21     ` Eric Sunshine
@ 2025-08-05 12:50     ` Patrick Steinhardt
  1 sibling, 0 replies; 226+ messages in thread
From: Patrick Steinhardt @ 2025-08-05 12:50 UTC (permalink / raw)
  To: Lucas Seiki Oshiro
  Cc: git, oswald.buddenhagen, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler, jn.avila, sunshine
On Fri, Aug 01, 2025 at 10:11:08AM -0300, Lucas Seiki Oshiro wrote:
> diff --git a/t/t1900-repo.sh b/t/t1900-repo.sh
> index 9796e36087..6c555e90c3 100755
> --- a/t/t1900-repo.sh
> +++ b/t/t1900-repo.sh
> @@ -54,4 +60,12 @@ test_expect_success 'only one value is returned if the same key is requested twi
>  	test_cmp expect actual
>  '
>  
> +test_expect_success 'output is returned correctly when two keys are requested' '
> +	cat >expect <<-\EOF &&
> +	layout.bare=false
> +	references.format=files
> +	EOF
> +	git init --ref-format=files two-keys &&
> +	git -C two-keys repo info layout.bare references.format
> +'
>  test_done
Tiny nit: there's a newline missing between the test and `test_done`.
Patrick
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v7 4/5] repo: add the field layout.shallow
  2025-08-01 13:11   ` [GSoC PATCH v7 4/5] repo: add the field layout.shallow Lucas Seiki Oshiro
@ 2025-08-05 12:50     ` Patrick Steinhardt
  0 siblings, 0 replies; 226+ messages in thread
From: Patrick Steinhardt @ 2025-08-05 12:50 UTC (permalink / raw)
  To: Lucas Seiki Oshiro
  Cc: git, oswald.buddenhagen, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler, jn.avila, sunshine
On Fri, Aug 01, 2025 at 10:11:09AM -0300, Lucas Seiki Oshiro wrote:
> diff --git a/builtin/repo.c b/builtin/repo.c
> index 2d51bfa195..56c3a4027f 100644
> --- a/builtin/repo.c
> +++ b/builtin/repo.c
> diff --git a/t/t1900-repo.sh b/t/t1900-repo.sh
> index 6c555e90c3..6706cb4c44 100755
> --- a/t/t1900-repo.sh
> +++ b/t/t1900-repo.sh
> @@ -68,4 +78,5 @@ test_expect_success 'output is returned correctly when two keys are requested' '
>  	git init --ref-format=files two-keys &&
>  	git -C two-keys repo info layout.bare references.format
>  '
> +
>  test_done
Ah, you add the newline back in over here. You should move this fix into
the preceding commit.
Patrick
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v7 5/5] repo: add the --format flag
  2025-08-01 13:11   ` [GSoC PATCH v7 5/5] repo: add the --format flag Lucas Seiki Oshiro
                       ` (2 preceding siblings ...)
  2025-08-01 21:50     ` Eric Sunshine
@ 2025-08-05 12:50     ` Patrick Steinhardt
  3 siblings, 0 replies; 226+ messages in thread
From: Patrick Steinhardt @ 2025-08-05 12:50 UTC (permalink / raw)
  To: Lucas Seiki Oshiro
  Cc: git, oswald.buddenhagen, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler, jn.avila, sunshine
On Fri, Aug 01, 2025 at 10:11:10AM -0300, Lucas Seiki Oshiro wrote:
> diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc
> index 140ee3a0aa..b735cf4737 100644
> --- a/Documentation/git-repo.adoc
> +++ b/Documentation/git-repo.adoc
> @@ -18,12 +18,23 @@ THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOR MAY CHANGE.
>  
>  COMMANDS
>  --------
> -`info [<key>...]`::
> +`info [--format=<keyvalue|nul>] [<key>...]`::
>  	Retrieve metadata-related information about the current repository. Only
>  	the requested data will be returned based on their keys (see "INFO KEYS"
>  	section below).
>  +
>  The returned data is lexicographically sorted by the keys.
> ++
> +The output format can be chosen through the flag `--format`. Two formats are
> +supported:
> ++
> +* `keyvalue`: output key-value pairs one per line using the `=` character as
> +the delimiter between the key and the value. This is the default.
Let's also mention that the value will be C-quoted.
> +* `nul`: similar to `keyvalue`, but using a newline character as the delimiter
> +between the key and the value and using a null character after each value.
> +This format is better suited for being parsed by another applications than
> +`keyvalue`.
And here we can then explicitly say that it's not quoted.
> diff --git a/builtin/repo.c b/builtin/repo.c
> index 56c3a4027f..4015cf88b7 100644
> --- a/builtin/repo.c
> +++ b/builtin/repo.c
> @@ -74,18 +79,33 @@ static int qsort_strcmp(const void *va, const void *vb)
>  	return strcmp(a, b);
>  }
>  
> -static int print_fields(int argc, const char **argv, struct repository *repo)
> +static int print_fields(int argc, const char **argv,
> +			struct repository *repo,
> +			enum output_format format)
>  {
>  	int ret = 0;
>  	const char *last = "";
>  	struct strbuf sb = STRBUF_INIT;
>  
> +	char kv_sep;
> +	char field_sep;
Nit: we don't usually have newlines between variable declarations.
Patrick
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v7 0/5] repo: add new command for retrieving repository info
  2025-08-01 13:11 ` [GSoC PATCH v7 " Lucas Seiki Oshiro
                     ` (4 preceding siblings ...)
  2025-08-01 13:11   ` [GSoC PATCH v7 5/5] repo: add the --format flag Lucas Seiki Oshiro
@ 2025-08-05 12:50   ` Patrick Steinhardt
  5 siblings, 0 replies; 226+ messages in thread
From: Patrick Steinhardt @ 2025-08-05 12:50 UTC (permalink / raw)
  To: Lucas Seiki Oshiro
  Cc: git, oswald.buddenhagen, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler, jn.avila, sunshine
On Fri, Aug 01, 2025 at 10:11:05AM -0300, Lucas Seiki Oshiro wrote:
> Hi!
> 
> These are the changes of this 7th version of `git repo`:
> 
> - The tests were refactored (thanks Eric for your careful revision!)
> 
> - The documentation has been improved: now it is a little more
>   descriptive about the keys. I'm also including more information about
>   the values
> 
> - The documentation now contains examples
> 
> - If an invalid key is requested, the command fails, however, now it
>   returns all the valid fields that were requested
> 
> - Now, I'm using `quote_c_style` in the key=value format
> 
> Thanks!
I think this series should be almost ready. I expect another final
reroll to address the nits, but once those are addressed it should be
ready to go.
Thanks!
Patrick
^ permalink raw reply	[flat|nested] 226+ messages in thread
* [GSoC PATCH v8 0/5] repo: add new command for retrieving repository info
  2025-06-10 15:21 [GSoC RFC PATCH 0/5] repo-info: add new command for retrieving repository info Lucas Seiki Oshiro
                   ` (13 preceding siblings ...)
  2025-08-01 13:11 ` [GSoC PATCH v7 " Lucas Seiki Oshiro
@ 2025-08-06 19:55 ` Lucas Seiki Oshiro
  2025-08-06 19:55   ` [GSoC PATCH v8 1/5] repo: declare the repo command Lucas Seiki Oshiro
                     ` (6 more replies)
  2025-08-07 15:02 ` [GSoC PATCH v9 " Lucas Seiki Oshiro
                   ` (2 subsequent siblings)
  17 siblings, 7 replies; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-08-06 19:55 UTC (permalink / raw)
  To: git
  Cc: oswald.buddenhagen, ps, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler, jn.avila, sunshine, Lucas Seiki Oshiro
Hi again!
This 8th version of `git-repo` basically address minor issues from the 7th
version:
- A test wasn't passing in the CI because it assumed that the ref
  format was files by default. I fixed that.
- t0450 wasn't passing because the documentation didn't match the
  usage string. I fixed that.
- A test generated the output and the expected value but wasn't
  comparing them. I also fixed that.
- strbuf management: now we have two strbufs for printing values:
  one for unquoted values and other for quoted values
- Test codestyle: now it's ending test case liness with \ instead of
  open strings
- Documentation: this version documents that we escape the value in
  the `keyvalue` format.
Here's the range-diff versus v7:
1:  51b20490e2 = 1:  3c2ede66be repo: declare the repo command
2:  8be77db9e5 ! 2:  396bee171a repo: add the field references.format
    @@ Documentation/git-repo.adoc: COMMANDS
      	section below).
     ++
     +The returned data is lexicographically sorted by the keys.
    +++
    ++The output format consists of key-value pairs one per line using the `=`
    ++character as the delimiter between the key and the value. Values containing
    ++"unusual" characters are quoted as explained for the configuration variable
    ++`core.quotePath` (see linkgit:git-config[1]). This is the default.
     +
     +INFO KEYS
     +---------
    @@ builtin/repo.c
     +{
     +	int ret = 0;
     +	const char *last = "";
    -+	struct strbuf sb = STRBUF_INIT;
    ++	struct strbuf valbuf = STRBUF_INIT;
    ++	struct strbuf quotbuf = STRBUF_INIT;
     +
     +	QSORT(argv, argc, qsort_strcmp);
     +
     +	for (int i = 0; i < argc; i++) {
     +		get_value_fn *get_value;
     +		const char *key = argv[i];
    -+		char *value;
    ++
    ++		strbuf_reset(&valbuf);
    ++		strbuf_reset("buf);
     +
     +		if (!strcmp(key, last))
     +			continue;
     +
    ++		last = key;
     +		get_value = get_value_fn_for_key(key);
     +
     +		if (!get_value) {
    @@ builtin/repo.c
     +			continue;
     +		}
     +
    -+		strbuf_reset(&sb);
    -+		get_value(repo, &sb);
    -+
    -+		value = strbuf_detach(&sb, NULL);
    -+		quote_c_style(value, &sb, NULL, 0);
    -+		free(value);
    -+
    -+		printf("%s=%s\n", key, sb.buf);
    -+		last = key;
    ++		get_value(repo, &valbuf);
    ++		quote_c_style(valbuf.buf, "buf, NULL, 0);
    ++		printf("%s=%s\n", key, quotbuf.buf);
     +	}
     +
    -+	strbuf_release(&sb);
    ++	strbuf_release(&valbuf);
    ++	strbuf_release("buf);
     +	return ret;
     +}
     +
    @@ t/t1900-repo.sh (new)
     +#
     +# Arguments:
     +#   label: the label of the test
    -+#   init command: a command which creates a repository named with its first argument,
    -+#      accordingly to what is being tested
    ++#   init_command: a command which creates a repository
    ++#   repo_name: the name of the repository that will be created in init_command
     +#   key: the key of the field that is being tested
    -+#   expected value: the value that the field should contain
    ++#   expected_value: the value that the field should contain
     +test_repo_info () {
     +	label=$1
     +	init_command=$2
    @@ t/t1900-repo.sh (new)
     +'
     +
     +test_expect_success 'git-repo-info outputs data even if there is an invalid field' '
    -+	echo "references.format=files" >expected &&
    ++	echo "references.format=$(test_detect_ref_format)" >expected &&
     +	test_must_fail git repo info foo references.format bar >actual &&
     +	test_cmp expected actual
     +'
3:  c93aeafb05 ! 3:  4dbc83c64c repo: add the field layout.bare
    @@ builtin/repo.c: struct field {
     +static int get_layout_bare(struct repository *repo UNUSED, struct strbuf *buf)
     +{
    -+	strbuf_addstr(buf,
    -+		      is_bare_repository() ? "true" : "false");
    ++	strbuf_addstr(buf, is_bare_repository() ? "true" : "false");
     +	return 0;
     +}
     +
    @@ t/t1900-repo.sh: test_repo_info 'ref format files is retrieved correctly' '
      test_repo_info 'ref format reftable is retrieved correctly' '
      	git init --ref-format=reftable' 'format-reftable' 'references.format' 'reftable'
    -+test_repo_info 'bare repository = false is retrieved correctly' '
    -+	git init' 'bare' 'layout.bare' 'false'
    ++test_repo_info 'bare repository = false is retrieved correctly' \
    ++	'git init' 'nonbare' 'layout.bare' 'false'
     +
    -+test_repo_info 'bare repository = true is retrieved correctly' '
    -+	git init --bare' 'nonbare' 'layout.bare' 'true'
    ++test_repo_info 'bare repository = true is retrieved correctly' \
    ++	'git init --bare' 'bare' 'layout.bare' 'true'
     +
      test_expect_success 'git-repo-info fails if an invalid key is requested' '
      	echo "error: key '\'foo\'' not found" >expected_err &&
    @@ t/t1900-repo.sh: test_expect_success 'only one value is returned if the same key
      '
     +test_expect_success 'output is returned correctly when two keys are requested' '
    -+	cat >expect <<-\EOF &&
    ++	cat >expected <<-\EOF &&
     +	layout.bare=false
     +	references.format=files
     +	EOF
     +	git init --ref-format=files two-keys &&
    -+	git -C two-keys repo info layout.bare references.format
    ++	git -C two-keys repo info layout.bare references.format > actual &&
    ++	test_cmp expected actual
     +'
    ++
      test_done
4:  4463b85193 ! 4:  5c65a24df4 repo: add the field layout.shallow
    @@ builtin/repo.c: static int get_references_format(struct repository *repo, struct
      ## t/t1900-repo.sh ##
    -@@ t/t1900-repo.sh: test_repo_info 'bare repository = false is retrieved correctly' '
    - test_repo_info 'bare repository = true is retrieved correctly' '
    - 	git init --bare' 'nonbare' 'layout.bare' 'true'
    +@@ t/t1900-repo.sh: test_repo_info 'bare repository = false is retrieved correctly' \
    + test_repo_info 'bare repository = true is retrieved correctly' \
    + 	'git init --bare' 'bare' 'layout.bare' 'true'
    -+test_repo_info 'shallow repository = false is retrieved correctly' '
    -+	git init' 'nonshallow' 'layout.shallow' 'false'
    ++test_repo_info 'shallow repository = false is retrieved correctly' \
    ++	'git init' 'nonshallow' 'layout.shallow' 'false'
     +
    -+test_repo_info 'shallow repository = true is retrieved correctly' '
    -+	git init remote &&
    ++test_repo_info 'shallow repository = true is retrieved correctly' \
    ++	'git init remote &&
     +	echo x >remote/x &&
     +	git -C remote add x &&
     +	git -C remote commit -m x &&
    @@ t/t1900-repo.sh: test_repo_info 'bare repository = false is retrieved correctly'
      test_expect_success 'git-repo-info fails if an invalid key is requested' '
      	echo "error: key '\'foo\'' not found" >expected_err &&
      	test_must_fail git repo info foo 2>actual_err &&
    -@@ t/t1900-repo.sh: test_expect_success 'output is returned correctly when two keys are requested' '
    - 	git init --ref-format=files two-keys &&
    - 	git -C two-keys repo info layout.bare references.format
    - '
    -+
    - test_done
5:  90427acf54 ! 5:  dc8ea099f5 repo: add the --format flag
    @@ Documentation/git-repo.adoc: git-repo - Retrieve information about the repositor
      --------
      [synopsis]
     -git repo info [<key>...]
    -+git repo info [--format=<keyvalue|nul>] [<key>...]
    ++git repo info [--format=(keyvalue|nul)] [<key>...]
      DESCRIPTION
      -----------
    @@ Documentation/git-repo.adoc: THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOR MAY CHAN
      COMMANDS
      --------
     -`info [<key>...]`::
    -+`info [--format=<keyvalue|nul>] [<key>...]`::
    ++`info [--format=(keyvalue|nul)] [<key>...]`::
      	Retrieve metadata-related information about the current repository. Only
      	the requested data will be returned based on their keys (see "INFO KEYS"
      	section below).
      +
      The returned data is lexicographically sorted by the keys.
    -++
    + +
    +-The output format consists of key-value pairs one per line using the `=`
    +-character as the delimiter between the key and the value. Values containing
    +-"unusual" characters are quoted as explained for the configuration variable
     +The output format can be chosen through the flag `--format`. Two formats are
     +supported:
     ++
     +* `keyvalue`: output key-value pairs one per line using the `=` character as
    -+the delimiter between the key and the value. This is the default.
    -+
    ++the delimiter between the key and the value. Values containing "unusual"
    ++characters are quoted as explained for the configuration variable
    + `core.quotePath` (see linkgit:git-config[1]). This is the default.
    +
     +* `nul`: similar to `keyvalue`, but using a newline character as the delimiter
     +between the key and the value and using a null character after each value.
     +This format is better suited for being parsed by another applications than
    -+`keyvalue`.
    -
    ++`keyvalue`. Unlike in the `keyvalue` format, the values are never quoted.
    ++
      INFO KEYS
      ---------
    +
     @@ Documentation/git-repo.adoc: The reference storage format. The valid values are:
      +
      include::ref-storage-format.adoc[]
    @@ builtin/repo.c
      static const char *const repo_usage[] = {
     -	"git repo info [<key>...]",
    -+	"git repo info [--format=<keyvalue|nul>] [<key>...]",
    ++	"git repo info [--format=(keyvalue|nul)] [<key>...]",
      	NULL
      };
    @@ builtin/repo.c: static int qsort_strcmp(const void *va, const void *vb)
      {
      	int ret = 0;
      	const char *last = "";
    - 	struct strbuf sb = STRBUF_INIT;
    +@@ builtin/repo.c: static int print_fields(int argc, const char **argv, struct repository *repo)
    + 		}
    -+	char kv_sep;
    -+	char field_sep;
    -+
    -+	switch (format) {
    -+	case FORMAT_KEYVALUE:
    -+		kv_sep = '=';
    -+		field_sep = '\n';
    -+		break;
    -+	case FORMAT_NUL_TERMINATED:
    -+		kv_sep = '\n';
    -+		field_sep = '\0';
    -+		break;
    -+	}
    + 		get_value(repo, &valbuf);
    +-		quote_c_style(valbuf.buf, "buf, NULL, 0);
    +-		printf("%s=%s\n", key, quotbuf.buf);
     +
    - 	QSORT(argv, argc, qsort_strcmp);
    -
    - 	for (int i = 0; i < argc; i++) {
    - 		get_value_fn *get_value;
    - 		const char *key = argv[i];
    --		char *value;
    -
    - 		if (!strcmp(key, last))
    - 			continue;
    -@@ builtin/repo.c: static int print_fields(int argc, const char **argv, struct repository *repo)
    - 		strbuf_reset(&sb);
    - 		get_value(repo, &sb);
    -
    --		value = strbuf_detach(&sb, NULL);
    --		quote_c_style(value, &sb, NULL, 0);
    --		free(value);
    -+		if (format == FORMAT_KEYVALUE) {
    -+			char *value;
    -+			value = strbuf_detach(&sb, NULL);
    -+			quote_c_style(value, &sb, NULL, 0);
    -+			free(value);
    ++		switch (format) {
    ++		case FORMAT_KEYVALUE:
    ++			quote_c_style(valbuf.buf, "buf, NULL, 0);
    ++			printf("%s=%s\n", key, quotbuf.buf);
    ++			break;
    ++		case FORMAT_NUL_TERMINATED:
    ++			printf("%s\n%s%c", key, valbuf.buf, '\0');
    ++			break;
    ++		default:
    ++			BUG("%d: not a valid output format", format);
     +		}
    -
    --		printf("%s=%s\n", key, sb.buf);
    -+		printf("%s%c%s%c", key, kv_sep, sb.buf, field_sep);
    - 		last = key;
      	}
    + 	strbuf_release(&valbuf);
     @@ builtin/repo.c: static int print_fields(int argc, const char **argv, struct repository *repo)
      	return ret;
      }
    @@ t/t1900-repo.sh: test_repo_info () {
     -	test_expect_success "$label" '
     -		eval "$init_command $repo_name" &&
    -+	test_expect_success "keyvalue: $label" '
    -+		eval "$init_command keyvalue-$repo_name" &&
    - 		echo "$key=$expected_value" >expected &&
    +-		echo "$key=$expected_value" >expected &&
     -		git -C $repo_name repo info "$key" >actual &&
    -+		git -C keyvalue-$repo_name repo info "$key" >actual &&
    -+		test_cmp expected actual
    -+	'
    ++	repo_name_keyvalue="$repo_name"-keyvalue
    ++	repo_name_nul="$repo_name"-nul
     +
    -+	test_expect_success "nul: $label" '
    -+		eval "$init_command nul-$repo_name" &&
    -+		printf "%s\n%s\0" "$key" "$expected_value" >expected &&
    -+		git -C nul-$repo_name repo info --format=nul "$key" >actual &&
    ++	test_expect_success "keyvalue: $label" '
    ++		eval "$init_command $repo_name_keyvalue" &&
    ++		echo "$key=$expected_value" > expected &&
    ++		git -C "$repo_name_keyvalue" repo info "$key" >actual &&
      		test_cmp expected actual
      	'
    ++
    ++	test_expect_success "nul: $label" '
    ++		eval "$init_command $repo_name_nul" &&
    ++		printf "%s\n%s\0" "$key" "$expected_value" >expected &&
    ++		git -C "$repo_name_nul" repo info --format=nul "$key" >actual &&
    ++		test_cmp_bin expected actual
    ++	'
      }
    -@@ t/t1900-repo.sh: test_repo_info 'shallow repository = false is retrieved correctly' '
    - 	git init' 'nonshallow' 'layout.shallow' 'false'
    - test_repo_info 'shallow repository = true is retrieved correctly' '
    -+	test_when_finished "rm -rf remote" &&
    - 	git init remote &&
    + test_repo_info 'ref format files is retrieved correctly' '
    +@@ t/t1900-repo.sh: test_repo_info 'bare repository = true is retrieved correctly' \
    + test_repo_info 'shallow repository = false is retrieved correctly' \
    + 	'git init' 'nonshallow' 'layout.shallow' 'false'
    +
    +-test_repo_info 'shallow repository = true is retrieved correctly' \
    +-	'git init remote &&
    ++test_expect_success 'setup remote' '
    ++	git init remote &&
      	echo x >remote/x &&
      	git -C remote add x &&
    +-	git -C remote commit -m x &&
    +-	git clone --depth 1 "file://$PWD/remote"' 'shallow' 'layout.shallow' 'true'
    ++	git -C remote commit -m x
    ++'
    ++
    ++test_repo_info 'shallow repository = true is retrieved correctly' \
    ++	'git clone --depth 1 "file://$PWD/remote"' 'shallow' 'layout.shallow' 'true'
    +
    + test_expect_success 'git-repo-info fails if an invalid key is requested' '
    + 	echo "error: key '\'foo\'' not found" >expected_err &&
     @@ t/t1900-repo.sh: test_expect_success 'output is returned correctly when two keys are requested' '
    - 	git -C two-keys repo info layout.bare references.format
    + 	test_cmp expected actual
      '
     +test_expect_success 'git-repo-info aborts when requesting an invalid format' '
    -+	test_when_finished "rm -f err expected" &&
     +	echo "fatal: invalid format '\'foo\''" >expected &&
     +	test_must_fail git repo info --format=foo 2>err &&
     +	test_cmp expected err
Lucas Seiki Oshiro (5):
  repo: declare the repo command
  repo: add the field references.format
  repo: add the field layout.bare
  repo: add the field layout.shallow
  repo: add the --format flag
 .gitignore                  |   1 +
 Documentation/git-repo.adoc |  81 ++++++++++++++++++
 Documentation/meson.build   |   1 +
 Makefile                    |   1 +
 builtin.h                   |   1 +
 builtin/repo.c              | 165 ++++++++++++++++++++++++++++++++++++
 command-list.txt            |   1 +
 git.c                       |   1 +
 meson.build                 |   1 +
 t/meson.build               |   1 +
 t/t1900-repo.sh             | 102 ++++++++++++++++++++++
 11 files changed, 356 insertions(+)
 create mode 100644 Documentation/git-repo.adoc
 create mode 100644 builtin/repo.c
 create mode 100755 t/t1900-repo.sh
-- 
2.39.5 (Apple Git-154)
^ permalink raw reply	[flat|nested] 226+ messages in thread
* [GSoC PATCH v8 1/5] repo: declare the repo command
  2025-08-06 19:55 ` [GSoC PATCH v8 " Lucas Seiki Oshiro
@ 2025-08-06 19:55   ` Lucas Seiki Oshiro
  2025-08-06 19:55   ` [GSoC PATCH v8 2/5] repo: add the field references.format Lucas Seiki Oshiro
                     ` (5 subsequent siblings)
  6 siblings, 0 replies; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-08-06 19:55 UTC (permalink / raw)
  To: git
  Cc: oswald.buddenhagen, ps, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler, jn.avila, sunshine, Lucas Seiki Oshiro
Currently, `git rev-parse` covers a wide range of functionality not
directly related to parsing revisions, as its name suggests. Over time,
many features like parsing datestrings, options, paths, and others
were added to it because there wasn't a more appropriate command
to place them.
Create a new Git command called `repo`. `git repo` will be the main
command for obtaining the information about a repository (such as
metadata and metrics).
Also declare a subcommand for `repo` called `info`. `git repo info`
will bring the functionality of retrieving repository-related
information currently returned by `rev-parse`.
Add the required documentation and build changes to enable usage of
this subcommand.
Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Helped-by: Junio C Hamano <gitster@pobox.com>
Helped-by: Justin Tobler <jltobler@gmail.com>
Helped-by: Eric Sunshine <sunshine@sunshineco.com>
Mentored-by: Karthik Nayak <karthik.188@gmail.com>
Mentored-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
---
 .gitignore                  |  1 +
 Documentation/git-repo.adoc | 32 ++++++++++++++++++++++++++++++++
 Documentation/meson.build   |  1 +
 Makefile                    |  1 +
 builtin.h                   |  1 +
 builtin/repo.c              | 27 +++++++++++++++++++++++++++
 command-list.txt            |  1 +
 git.c                       |  1 +
 meson.build                 |  1 +
 9 files changed, 66 insertions(+)
 create mode 100644 Documentation/git-repo.adoc
 create mode 100644 builtin/repo.c
diff --git a/.gitignore b/.gitignore
index 04c444404e..1803023427 100644
--- a/.gitignore
+++ b/.gitignore
@@ -139,6 +139,7 @@
 /git-repack
 /git-replace
 /git-replay
+/git-repo
 /git-request-pull
 /git-rerere
 /git-reset
diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc
new file mode 100644
index 0000000000..68c706f5a0
--- /dev/null
+++ b/Documentation/git-repo.adoc
@@ -0,0 +1,32 @@
+git-repo(1)
+===========
+
+NAME
+----
+git-repo - Retrieve information about the repository
+
+SYNOPSIS
+--------
+[synopsis]
+git repo info [<key>...]
+
+DESCRIPTION
+-----------
+Retrieve information about the repository.
+
+THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOR MAY CHANGE.
+
+COMMANDS
+--------
+`info [<key>...]`::
+	Retrieve metadata-related information about the current repository. Only
+	the requested data will be returned based on their keys (see "INFO KEYS"
+	section below).
+
+SEE ALSO
+--------
+linkgit:git-rev-parse[1]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/meson.build b/Documentation/meson.build
index 4404c623f0..41f43e0336 100644
--- a/Documentation/meson.build
+++ b/Documentation/meson.build
@@ -116,6 +116,7 @@ manpages = {
   'git-repack.adoc' : 1,
   'git-replace.adoc' : 1,
   'git-replay.adoc' : 1,
+  'git-repo.adoc' : 1,
   'git-request-pull.adoc' : 1,
   'git-rerere.adoc' : 1,
   'git-reset.adoc' : 1,
diff --git a/Makefile b/Makefile
index e11340c1ae..ec7ac58980 100644
--- a/Makefile
+++ b/Makefile
@@ -1306,6 +1306,7 @@ BUILTIN_OBJS += builtin/remote.o
 BUILTIN_OBJS += builtin/repack.o
 BUILTIN_OBJS += builtin/replace.o
 BUILTIN_OBJS += builtin/replay.o
+BUILTIN_OBJS += builtin/repo.o
 BUILTIN_OBJS += builtin/rerere.o
 BUILTIN_OBJS += builtin/reset.o
 BUILTIN_OBJS += builtin/rev-list.o
diff --git a/builtin.h b/builtin.h
index bff13e3069..e6458e6fb9 100644
--- a/builtin.h
+++ b/builtin.h
@@ -216,6 +216,7 @@ int cmd_remote_ext(int argc, const char **argv, const char *prefix, struct repos
 int cmd_remote_fd(int argc, const char **argv, const char *prefix, struct repository *repo);
 int cmd_repack(int argc, const char **argv, const char *prefix, struct repository *repo);
 int cmd_replay(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_repo(int argc, const char **argv, const char *prefix, struct repository *repo);
 int cmd_rerere(int argc, const char **argv, const char *prefix, struct repository *repo);
 int cmd_reset(int argc, const char **argv, const char *prefix, struct repository *repo);
 int cmd_restore(int argc, const char **argv, const char *prefix, struct repository *repo);
diff --git a/builtin/repo.c b/builtin/repo.c
new file mode 100644
index 0000000000..fd2a9b4216
--- /dev/null
+++ b/builtin/repo.c
@@ -0,0 +1,27 @@
+#include "builtin.h"
+#include "parse-options.h"
+
+static const char *const repo_usage[] = {
+	"git repo info [<key>...]",
+	NULL
+};
+
+static int repo_info(int argc UNUSED, const char **argv UNUSED,
+		     const char *prefix UNUSED, struct repository *repo UNUSED)
+{
+	return 0;
+}
+
+int cmd_repo(int argc, const char **argv, const char *prefix,
+	     struct repository *repo)
+{
+	parse_opt_subcommand_fn *fn = NULL;
+	struct option options[] = {
+		OPT_SUBCOMMAND("info", &fn, repo_info),
+		OPT_END()
+	};
+
+	argc = parse_options(argc, argv, prefix, options, repo_usage, 0);
+
+	return fn(argc, argv, prefix, repo);
+}
diff --git a/command-list.txt b/command-list.txt
index b7ade3ab9f..1b0bdee00d 100644
--- a/command-list.txt
+++ b/command-list.txt
@@ -164,6 +164,7 @@ git-remote                              ancillarymanipulators           complete
 git-repack                              ancillarymanipulators           complete
 git-replace                             ancillarymanipulators           complete
 git-replay                              plumbingmanipulators
+git-repo                                plumbinginterrogators
 git-request-pull                        foreignscminterface             complete
 git-rerere                              ancillaryinterrogators
 git-reset                               mainporcelain           history
diff --git a/git.c b/git.c
index 83eac0aeab..d4ff4d5517 100644
--- a/git.c
+++ b/git.c
@@ -611,6 +611,7 @@ static struct cmd_struct commands[] = {
 	{ "repack", cmd_repack, RUN_SETUP },
 	{ "replace", cmd_replace, RUN_SETUP },
 	{ "replay", cmd_replay, RUN_SETUP },
+	{ "repo", cmd_repo, RUN_SETUP },
 	{ "rerere", cmd_rerere, RUN_SETUP },
 	{ "reset", cmd_reset, RUN_SETUP },
 	{ "restore", cmd_restore, RUN_SETUP | NEED_WORK_TREE },
diff --git a/meson.build b/meson.build
index 5dd299b496..e8ec0eca16 100644
--- a/meson.build
+++ b/meson.build
@@ -645,6 +645,7 @@ builtin_sources = [
   'builtin/repack.c',
   'builtin/replace.c',
   'builtin/replay.c',
+  'builtin/repo.c',
   'builtin/rerere.c',
   'builtin/reset.c',
   'builtin/rev-list.c',
-- 
2.39.5 (Apple Git-154)
^ permalink raw reply related	[flat|nested] 226+ messages in thread
* [GSoC PATCH v8 2/5] repo: add the field references.format
  2025-08-06 19:55 ` [GSoC PATCH v8 " Lucas Seiki Oshiro
  2025-08-06 19:55   ` [GSoC PATCH v8 1/5] repo: declare the repo command Lucas Seiki Oshiro
@ 2025-08-06 19:55   ` Lucas Seiki Oshiro
  2025-08-07  7:43     ` Karthik Nayak
  2025-08-06 19:55   ` [GSoC PATCH v8 3/5] repo: add the field layout.bare Lucas Seiki Oshiro
                     ` (4 subsequent siblings)
  6 siblings, 1 reply; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-08-06 19:55 UTC (permalink / raw)
  To: git
  Cc: oswald.buddenhagen, ps, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler, jn.avila, sunshine, Lucas Seiki Oshiro
This commit is part of the series that introduces the new subcommand
git-repo-info.
The flag `--show-ref-format` from git-rev-parse is used for retrieving
the reference format (i.e. `files` or `reftable`). This way, it is
used for querying repository metadata, fitting in the purpose of
git-repo-info.
Add a new field `references.format` to the repo-info subcommand
containing that information.
Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Helped-by: Junio C Hamano <gitster@pobox.com>
Helped-by: Justin Tobler <jltobler@gmail.com>
Helped-by: Eric Sunshine <sunshine@sunshineco.com>
Mentored-by: Karthik Nayak <karthik.188@gmail.com>
Mentored-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
---
 Documentation/git-repo.adoc | 19 ++++++++
 builtin/repo.c              | 89 ++++++++++++++++++++++++++++++++++++-
 t/meson.build               |  1 +
 t/t1900-repo.sh             | 57 ++++++++++++++++++++++++
 4 files changed, 164 insertions(+), 2 deletions(-)
 create mode 100755 t/t1900-repo.sh
diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc
index 68c706f5a0..0ee783abc2 100644
--- a/Documentation/git-repo.adoc
+++ b/Documentation/git-repo.adoc
@@ -22,6 +22,25 @@ COMMANDS
 	Retrieve metadata-related information about the current repository. Only
 	the requested data will be returned based on their keys (see "INFO KEYS"
 	section below).
++
+The returned data is lexicographically sorted by the keys.
++
+The output format consists of key-value pairs one per line using the `=`
+character as the delimiter between the key and the value. Values containing
+"unusual" characters are quoted as explained for the configuration variable
+`core.quotePath` (see linkgit:git-config[1]). This is the default.
+
+INFO KEYS
+---------
+
+In order to obtain a set of values from `git repo info`, you should provide
+the keys that identify them. Here's a list of the available keys and the
+values that they return:
+
+`references.format`::
+The reference storage format. The valid values are:
++
+include::ref-storage-format.adoc[]
 
 SEE ALSO
 --------
diff --git a/builtin/repo.c b/builtin/repo.c
index fd2a9b4216..2b7ab5875e 100644
--- a/builtin/repo.c
+++ b/builtin/repo.c
@@ -1,17 +1,102 @@
 #include "builtin.h"
 #include "parse-options.h"
+#include "quote.h"
+#include "refs.h"
+#include "strbuf.h"
 
 static const char *const repo_usage[] = {
 	"git repo info [<key>...]",
 	NULL
 };
 
-static int repo_info(int argc UNUSED, const char **argv UNUSED,
-		     const char *prefix UNUSED, struct repository *repo UNUSED)
+typedef int get_value_fn(struct repository *repo, struct strbuf *buf);
+
+struct field {
+	const char *key;
+	get_value_fn *get_value;
+};
+
+static int get_references_format(struct repository *repo, struct strbuf *buf)
 {
+	strbuf_addstr(buf,
+		      ref_storage_format_to_name(repo->ref_storage_format));
 	return 0;
 }
 
+/* repo_info_fields keys should be in lexicographical order */
+static const struct field repo_info_fields[] = {
+	{ "references.format", get_references_format },
+};
+
+static int repo_info_fields_cmp(const void *va, const void *vb)
+{
+	const struct field *a = va;
+	const struct field *b = vb;
+
+	return strcmp(a->key, b->key);
+}
+
+static get_value_fn *get_value_fn_for_key(const char *key)
+{
+	const struct field search_key = { key, NULL };
+	const struct field *found = bsearch(&search_key, repo_info_fields,
+					    ARRAY_SIZE(repo_info_fields),
+					    sizeof(*found),
+					    repo_info_fields_cmp);
+	return found ? found->get_value : NULL;
+}
+
+static int qsort_strcmp(const void *va, const void *vb)
+{
+	const char *a = *(const char **)va;
+	const char *b = *(const char **)vb;
+
+	return strcmp(a, b);
+}
+
+static int print_fields(int argc, const char **argv, struct repository *repo)
+{
+	int ret = 0;
+	const char *last = "";
+	struct strbuf valbuf = STRBUF_INIT;
+	struct strbuf quotbuf = STRBUF_INIT;
+
+	QSORT(argv, argc, qsort_strcmp);
+
+	for (int i = 0; i < argc; i++) {
+		get_value_fn *get_value;
+		const char *key = argv[i];
+
+		strbuf_reset(&valbuf);
+		strbuf_reset("buf);
+
+		if (!strcmp(key, last))
+			continue;
+
+		last = key;
+		get_value = get_value_fn_for_key(key);
+
+		if (!get_value) {
+			ret = error(_("key '%s' not found"), key);
+			continue;
+		}
+
+		get_value(repo, &valbuf);
+		quote_c_style(valbuf.buf, "buf, NULL, 0);
+		printf("%s=%s\n", key, quotbuf.buf);
+	}
+
+	strbuf_release(&valbuf);
+	strbuf_release("buf);
+	return ret;
+}
+
+static int repo_info(int argc, const char **argv, const char *prefix UNUSED,
+		     struct repository *repo)
+{
+	return print_fields(argc - 1, argv + 1, repo);
+}
+
 int cmd_repo(int argc, const char **argv, const char *prefix,
 	     struct repository *repo)
 {
diff --git a/t/meson.build b/t/meson.build
index bbeba1a8d5..252dbbc031 100644
--- a/t/meson.build
+++ b/t/meson.build
@@ -230,6 +230,7 @@ integration_tests = [
   't1700-split-index.sh',
   't1701-racy-split-index.sh',
   't1800-hook.sh',
+  't1900-repo.sh',
   't2000-conflict-when-checking-files-out.sh',
   't2002-checkout-cache-u.sh',
   't2003-checkout-cache-mkdir.sh',
diff --git a/t/t1900-repo.sh b/t/t1900-repo.sh
new file mode 100755
index 0000000000..ce02b394da
--- /dev/null
+++ b/t/t1900-repo.sh
@@ -0,0 +1,57 @@
+#!/bin/sh
+
+test_description='test git repo-info'
+
+. ./test-lib.sh
+
+# Test whether a key-value pair is correctly returned
+#
+# Usage: test_repo_info <label> <init command> <key> <expected value>
+#
+# Arguments:
+#   label: the label of the test
+#   init_command: a command which creates a repository
+#   repo_name: the name of the repository that will be created in init_command
+#   key: the key of the field that is being tested
+#   expected_value: the value that the field should contain
+test_repo_info () {
+	label=$1
+	init_command=$2
+	repo_name=$3
+	key=$4
+	expected_value=$5
+
+	test_expect_success "$label" '
+		eval "$init_command $repo_name" &&
+		echo "$key=$expected_value" >expected &&
+		git -C $repo_name repo info "$key" >actual &&
+		test_cmp expected actual
+	'
+}
+
+test_repo_info 'ref format files is retrieved correctly' '
+	git init --ref-format=files' 'format-files' 'references.format' 'files'
+
+test_repo_info 'ref format reftable is retrieved correctly' '
+	git init --ref-format=reftable' 'format-reftable' 'references.format' 'reftable'
+
+test_expect_success 'git-repo-info fails if an invalid key is requested' '
+	echo "error: key '\'foo\'' not found" >expected_err &&
+	test_must_fail git repo info foo 2>actual_err &&
+	test_cmp expected_err actual_err
+'
+
+test_expect_success 'git-repo-info outputs data even if there is an invalid field' '
+	echo "references.format=$(test_detect_ref_format)" >expected &&
+	test_must_fail git repo info foo references.format bar >actual &&
+	test_cmp expected actual
+'
+
+test_expect_success 'only one value is returned if the same key is requested twice' '
+	val=$(git rev-parse --show-ref-format) &&
+	echo "references.format=$val" >expect &&
+	git repo info references.format references.format >actual &&
+	test_cmp expect actual
+'
+
+test_done
-- 
2.39.5 (Apple Git-154)
^ permalink raw reply related	[flat|nested] 226+ messages in thread
* [GSoC PATCH v8 3/5] repo: add the field layout.bare
  2025-08-06 19:55 ` [GSoC PATCH v8 " Lucas Seiki Oshiro
  2025-08-06 19:55   ` [GSoC PATCH v8 1/5] repo: declare the repo command Lucas Seiki Oshiro
  2025-08-06 19:55   ` [GSoC PATCH v8 2/5] repo: add the field references.format Lucas Seiki Oshiro
@ 2025-08-06 19:55   ` Lucas Seiki Oshiro
  2025-08-07  5:20     ` Patrick Steinhardt
  2025-08-06 19:55   ` [GSoC PATCH v8 4/5] repo: add the field layout.shallow Lucas Seiki Oshiro
                     ` (3 subsequent siblings)
  6 siblings, 1 reply; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-08-06 19:55 UTC (permalink / raw)
  To: git
  Cc: oswald.buddenhagen, ps, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler, jn.avila, sunshine, Lucas Seiki Oshiro
This commit is part of the series that introduces the new subcommand
git-repo-info.
The flag --is-bare-repository from git-rev-parse is used for retrieving
whether the current repository is bare. This way, it is used for
querying repository metadata, fitting in the purpose of git-repo-info.
Then, add a new field layout.bare to the git-repo-info subcommand
containing that information.
Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Helped-by: Junio C Hamano <gitster@pobox.com>
Helped-by: Justin Tobler <jltobler@gmail.com>
Helped-by: Eric Sunshine <sunshine@sunshineco.com>
Mentored-by: Karthik Nayak <karthik.188@gmail.com>
Mentored-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
---
 Documentation/git-repo.adoc |  3 +++
 builtin/repo.c              | 10 ++++++++++
 t/t1900-repo.sh             | 16 ++++++++++++++++
 3 files changed, 29 insertions(+)
diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc
index 0ee783abc2..0ef851ee9c 100644
--- a/Documentation/git-repo.adoc
+++ b/Documentation/git-repo.adoc
@@ -37,6 +37,9 @@ In order to obtain a set of values from `git repo info`, you should provide
 the keys that identify them. Here's a list of the available keys and the
 values that they return:
 
+`layout.bare`::
+`true` if this is a bare repository, otherwise `false`.
+
 `references.format`::
 The reference storage format. The valid values are:
 +
diff --git a/builtin/repo.c b/builtin/repo.c
index 2b7ab5875e..abdc929e19 100644
--- a/builtin/repo.c
+++ b/builtin/repo.c
@@ -1,4 +1,7 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
 #include "builtin.h"
+#include "environment.h"
 #include "parse-options.h"
 #include "quote.h"
 #include "refs.h"
@@ -16,6 +19,12 @@ struct field {
 	get_value_fn *get_value;
 };
 
+static int get_layout_bare(struct repository *repo UNUSED, struct strbuf *buf)
+{
+	strbuf_addstr(buf, is_bare_repository() ? "true" : "false");
+	return 0;
+}
+
 static int get_references_format(struct repository *repo, struct strbuf *buf)
 {
 	strbuf_addstr(buf,
@@ -25,6 +34,7 @@ static int get_references_format(struct repository *repo, struct strbuf *buf)
 
 /* repo_info_fields keys should be in lexicographical order */
 static const struct field repo_info_fields[] = {
+	{ "layout.bare", get_layout_bare },
 	{ "references.format", get_references_format },
 };
 
diff --git a/t/t1900-repo.sh b/t/t1900-repo.sh
index ce02b394da..32f64b635b 100755
--- a/t/t1900-repo.sh
+++ b/t/t1900-repo.sh
@@ -35,6 +35,12 @@ test_repo_info 'ref format files is retrieved correctly' '
 test_repo_info 'ref format reftable is retrieved correctly' '
 	git init --ref-format=reftable' 'format-reftable' 'references.format' 'reftable'
 
+test_repo_info 'bare repository = false is retrieved correctly' \
+	'git init' 'nonbare' 'layout.bare' 'false'
+
+test_repo_info 'bare repository = true is retrieved correctly' \
+	'git init --bare' 'bare' 'layout.bare' 'true'
+
 test_expect_success 'git-repo-info fails if an invalid key is requested' '
 	echo "error: key '\'foo\'' not found" >expected_err &&
 	test_must_fail git repo info foo 2>actual_err &&
@@ -54,4 +60,14 @@ test_expect_success 'only one value is returned if the same key is requested twi
 	test_cmp expect actual
 '
 
+test_expect_success 'output is returned correctly when two keys are requested' '
+	cat >expected <<-\EOF &&
+	layout.bare=false
+	references.format=files
+	EOF
+	git init --ref-format=files two-keys &&
+	git -C two-keys repo info layout.bare references.format > actual &&
+	test_cmp expected actual
+'
+
 test_done
-- 
2.39.5 (Apple Git-154)
^ permalink raw reply related	[flat|nested] 226+ messages in thread
* [GSoC PATCH v8 4/5] repo: add the field layout.shallow
  2025-08-06 19:55 ` [GSoC PATCH v8 " Lucas Seiki Oshiro
                     ` (2 preceding siblings ...)
  2025-08-06 19:55   ` [GSoC PATCH v8 3/5] repo: add the field layout.bare Lucas Seiki Oshiro
@ 2025-08-06 19:55   ` Lucas Seiki Oshiro
  2025-08-06 19:55   ` [GSoC PATCH v8 5/5] repo: add the --format flag Lucas Seiki Oshiro
                     ` (2 subsequent siblings)
  6 siblings, 0 replies; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-08-06 19:55 UTC (permalink / raw)
  To: git
  Cc: oswald.buddenhagen, ps, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler, jn.avila, sunshine, Lucas Seiki Oshiro
This commit is part of the series that introduces the new subcommand
git-repo-info.
The flag `--is-shallow-repository` from git-rev-parse is used for
retrieving whether the repository is shallow. This way, it is used for
querying repository metadata, fitting in the purpose of git-repo-info.
Then, add a new field `layout.shallow` to the git-repo-info subcommand
containing that information.
Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Helped-by: Junio C Hamano <gitster@pobox.com>
Helped-by: Justin Tobler <jltobler@gmail.com>
Helped-by: Eric Sunshine <sunshine@sunshineco.com>
Mentored-by: Karthik Nayak <karthik.188@gmail.com>
Mentored-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
---
 Documentation/git-repo.adoc |  3 +++
 builtin/repo.c              |  9 +++++++++
 t/t1900-repo.sh             | 10 ++++++++++
 3 files changed, 22 insertions(+)
diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc
index 0ef851ee9c..1ae9c09fac 100644
--- a/Documentation/git-repo.adoc
+++ b/Documentation/git-repo.adoc
@@ -40,6 +40,9 @@ values that they return:
 `layout.bare`::
 `true` if this is a bare repository, otherwise `false`.
 
+`layout.shallow`::
+`true` if this is a shallow repository, otherwise `false`.
+
 `references.format`::
 The reference storage format. The valid values are:
 +
diff --git a/builtin/repo.c b/builtin/repo.c
index abdc929e19..312fd08c34 100644
--- a/builtin/repo.c
+++ b/builtin/repo.c
@@ -6,6 +6,7 @@
 #include "quote.h"
 #include "refs.h"
 #include "strbuf.h"
+#include "shallow.h"
 
 static const char *const repo_usage[] = {
 	"git repo info [<key>...]",
@@ -25,6 +26,13 @@ static int get_layout_bare(struct repository *repo UNUSED, struct strbuf *buf)
 	return 0;
 }
 
+static int get_layout_shallow(struct repository *repo, struct strbuf *buf)
+{
+	strbuf_addstr(buf,
+		      is_repository_shallow(repo) ? "true" : "false");
+	return 0;
+}
+
 static int get_references_format(struct repository *repo, struct strbuf *buf)
 {
 	strbuf_addstr(buf,
@@ -35,6 +43,7 @@ static int get_references_format(struct repository *repo, struct strbuf *buf)
 /* repo_info_fields keys should be in lexicographical order */
 static const struct field repo_info_fields[] = {
 	{ "layout.bare", get_layout_bare },
+	{ "layout.shallow", get_layout_shallow },
 	{ "references.format", get_references_format },
 };
 
diff --git a/t/t1900-repo.sh b/t/t1900-repo.sh
index 32f64b635b..ef8205f7fd 100755
--- a/t/t1900-repo.sh
+++ b/t/t1900-repo.sh
@@ -41,6 +41,16 @@ test_repo_info 'bare repository = false is retrieved correctly' \
 test_repo_info 'bare repository = true is retrieved correctly' \
 	'git init --bare' 'bare' 'layout.bare' 'true'
 
+test_repo_info 'shallow repository = false is retrieved correctly' \
+	'git init' 'nonshallow' 'layout.shallow' 'false'
+
+test_repo_info 'shallow repository = true is retrieved correctly' \
+	'git init remote &&
+	echo x >remote/x &&
+	git -C remote add x &&
+	git -C remote commit -m x &&
+	git clone --depth 1 "file://$PWD/remote"' 'shallow' 'layout.shallow' 'true'
+
 test_expect_success 'git-repo-info fails if an invalid key is requested' '
 	echo "error: key '\'foo\'' not found" >expected_err &&
 	test_must_fail git repo info foo 2>actual_err &&
-- 
2.39.5 (Apple Git-154)
^ permalink raw reply related	[flat|nested] 226+ messages in thread
* [GSoC PATCH v8 5/5] repo: add the --format flag
  2025-08-06 19:55 ` [GSoC PATCH v8 " Lucas Seiki Oshiro
                     ` (3 preceding siblings ...)
  2025-08-06 19:55   ` [GSoC PATCH v8 4/5] repo: add the field layout.shallow Lucas Seiki Oshiro
@ 2025-08-06 19:55   ` Lucas Seiki Oshiro
  2025-08-07  5:20     ` Patrick Steinhardt
  2025-08-06 22:38   ` [GSoC PATCH v8 0/5] repo: add new command for retrieving repository info Junio C Hamano
  2025-08-07  7:48   ` Karthik Nayak
  6 siblings, 1 reply; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-08-06 19:55 UTC (permalink / raw)
  To: git
  Cc: oswald.buddenhagen, ps, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler, jn.avila, sunshine, Lucas Seiki Oshiro
Add the --format flag to git-repo-info. By using this flag, the users
can choose the format for obtaining the data they requested.
Given that this command can be used for generating input for other
applications and for being read by end users, it requires at least two
formats: one for being read by humans and other for being read by
machines. Some other Git commands also have two output formats, notably
git-config which was the inspiration for the two formats that were
chosen here:
- keyvalue, where the retrieved data is printed one per line, using =
  for delimiting the key and the value. This is the default format,
  targeted for end users.
- nul, where the retrieved data is separated by null characters, using
  the newline character for delimiting the key and the value. This
  format is targeted for being read by machines.
Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Helped-by: Junio C Hamano <gitster@pobox.com>
Helped-by: Justin Tobler <jltobler@gmail.com>
Helped-by: Eric Sunshine <sunshine@sunshineco.com>
Mentored-by: Karthik Nayak <karthik.188@gmail.com>
Mentored-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
---
 Documentation/git-repo.adoc | 36 ++++++++++++++++++++++++-----
 builtin/repo.c              | 46 ++++++++++++++++++++++++++++++++-----
 t/t1900-repo.sh             | 35 +++++++++++++++++++++-------
 3 files changed, 97 insertions(+), 20 deletions(-)
diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc
index 1ae9c09fac..2b63954098 100644
--- a/Documentation/git-repo.adoc
+++ b/Documentation/git-repo.adoc
@@ -8,7 +8,7 @@ git-repo - Retrieve information about the repository
 SYNOPSIS
 --------
 [synopsis]
-git repo info [<key>...]
+git repo info [--format=(keyvalue|nul)] [<key>...]
 
 DESCRIPTION
 -----------
@@ -18,21 +18,28 @@ THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOR MAY CHANGE.
 
 COMMANDS
 --------
-`info [<key>...]`::
+`info [--format=(keyvalue|nul)] [<key>...]`::
 	Retrieve metadata-related information about the current repository. Only
 	the requested data will be returned based on their keys (see "INFO KEYS"
 	section below).
 +
 The returned data is lexicographically sorted by the keys.
 +
-The output format consists of key-value pairs one per line using the `=`
-character as the delimiter between the key and the value. Values containing
-"unusual" characters are quoted as explained for the configuration variable
+The output format can be chosen through the flag `--format`. Two formats are
+supported:
++
+* `keyvalue`: output key-value pairs one per line using the `=` character as
+the delimiter between the key and the value. Values containing "unusual"
+characters are quoted as explained for the configuration variable
 `core.quotePath` (see linkgit:git-config[1]). This is the default.
 
+* `nul`: similar to `keyvalue`, but using a newline character as the delimiter
+between the key and the value and using a null character after each value.
+This format is better suited for being parsed by another applications than
+`keyvalue`. Unlike in the `keyvalue` format, the values are never quoted.
+
 INFO KEYS
 ---------
-
 In order to obtain a set of values from `git repo info`, you should provide
 the keys that identify them. Here's a list of the available keys and the
 values that they return:
@@ -48,6 +55,23 @@ The reference storage format. The valid values are:
 +
 include::ref-storage-format.adoc[]
 
+EXAMPLES
+--------
+
+* Retrieves the reference format of the current repository:
++
+------------
+git repo info references.format
+------------
++
+
+* Retrieves whether the current repository is bare and whether it is shallow
+using the `nul` format:
++
+------------
+git repo info --format=nul layout.bare layout.shallow
+------------
+
 SEE ALSO
 --------
 linkgit:git-rev-parse[1]
diff --git a/builtin/repo.c b/builtin/repo.c
index 312fd08c34..37b5726816 100644
--- a/builtin/repo.c
+++ b/builtin/repo.c
@@ -9,12 +9,17 @@
 #include "shallow.h"
 
 static const char *const repo_usage[] = {
-	"git repo info [<key>...]",
+	"git repo info [--format=(keyvalue|nul)] [<key>...]",
 	NULL
 };
 
 typedef int get_value_fn(struct repository *repo, struct strbuf *buf);
 
+enum output_format {
+	FORMAT_KEYVALUE,
+	FORMAT_NUL_TERMINATED,
+};
+
 struct field {
 	const char *key;
 	get_value_fn *get_value;
@@ -73,7 +78,9 @@ static int qsort_strcmp(const void *va, const void *vb)
 	return strcmp(a, b);
 }
 
-static int print_fields(int argc, const char **argv, struct repository *repo)
+static int print_fields(int argc, const char **argv,
+			struct repository *repo,
+			enum output_format format)
 {
 	int ret = 0;
 	const char *last = "";
@@ -101,8 +108,18 @@ static int print_fields(int argc, const char **argv, struct repository *repo)
 		}
 
 		get_value(repo, &valbuf);
-		quote_c_style(valbuf.buf, "buf, NULL, 0);
-		printf("%s=%s\n", key, quotbuf.buf);
+
+		switch (format) {
+		case FORMAT_KEYVALUE:
+			quote_c_style(valbuf.buf, "buf, NULL, 0);
+			printf("%s=%s\n", key, quotbuf.buf);
+			break;
+		case FORMAT_NUL_TERMINATED:
+			printf("%s\n%s%c", key, valbuf.buf, '\0');
+			break;
+		default:
+			BUG("%d: not a valid output format", format);
+		}
 	}
 
 	strbuf_release(&valbuf);
@@ -110,10 +127,27 @@ static int print_fields(int argc, const char **argv, struct repository *repo)
 	return ret;
 }
 
-static int repo_info(int argc, const char **argv, const char *prefix UNUSED,
+static int repo_info(int argc, const char **argv, const char *prefix,
 		     struct repository *repo)
 {
-	return print_fields(argc - 1, argv + 1, repo);
+	const char *format_str = "keyvalue";
+	enum output_format format;
+	struct option options[] = {
+		OPT_STRING(0, "format", &format_str, N_("format"),
+			   N_("output format")),
+		OPT_END()
+	};
+
+	argc = parse_options(argc, argv, prefix, options, repo_usage, 0);
+
+	if (!strcmp(format_str, "keyvalue"))
+		format = FORMAT_KEYVALUE;
+	else if (!strcmp(format_str, "nul"))
+		format = FORMAT_NUL_TERMINATED;
+	else
+		die(_("invalid format '%s'"), format_str);
+
+	return print_fields(argc, argv, repo, format);
 }
 
 int cmd_repo(int argc, const char **argv, const char *prefix,
diff --git a/t/t1900-repo.sh b/t/t1900-repo.sh
index ef8205f7fd..573cf62575 100755
--- a/t/t1900-repo.sh
+++ b/t/t1900-repo.sh
@@ -21,12 +21,22 @@ test_repo_info () {
 	key=$4
 	expected_value=$5
 
-	test_expect_success "$label" '
-		eval "$init_command $repo_name" &&
-		echo "$key=$expected_value" >expected &&
-		git -C $repo_name repo info "$key" >actual &&
+	repo_name_keyvalue="$repo_name"-keyvalue
+	repo_name_nul="$repo_name"-nul
+
+	test_expect_success "keyvalue: $label" '
+		eval "$init_command $repo_name_keyvalue" &&
+		echo "$key=$expected_value" > expected &&
+		git -C "$repo_name_keyvalue" repo info "$key" >actual &&
 		test_cmp expected actual
 	'
+
+	test_expect_success "nul: $label" '
+		eval "$init_command $repo_name_nul" &&
+		printf "%s\n%s\0" "$key" "$expected_value" >expected &&
+		git -C "$repo_name_nul" repo info --format=nul "$key" >actual &&
+		test_cmp_bin expected actual
+	'
 }
 
 test_repo_info 'ref format files is retrieved correctly' '
@@ -44,12 +54,15 @@ test_repo_info 'bare repository = true is retrieved correctly' \
 test_repo_info 'shallow repository = false is retrieved correctly' \
 	'git init' 'nonshallow' 'layout.shallow' 'false'
 
-test_repo_info 'shallow repository = true is retrieved correctly' \
-	'git init remote &&
+test_expect_success 'setup remote' '
+	git init remote &&
 	echo x >remote/x &&
 	git -C remote add x &&
-	git -C remote commit -m x &&
-	git clone --depth 1 "file://$PWD/remote"' 'shallow' 'layout.shallow' 'true'
+	git -C remote commit -m x
+'
+
+test_repo_info 'shallow repository = true is retrieved correctly' \
+	'git clone --depth 1 "file://$PWD/remote"' 'shallow' 'layout.shallow' 'true'
 
 test_expect_success 'git-repo-info fails if an invalid key is requested' '
 	echo "error: key '\'foo\'' not found" >expected_err &&
@@ -80,4 +93,10 @@ test_expect_success 'output is returned correctly when two keys are requested' '
 	test_cmp expected actual
 '
 
+test_expect_success 'git-repo-info aborts when requesting an invalid format' '
+	echo "fatal: invalid format '\'foo\''" >expected &&
+	test_must_fail git repo info --format=foo 2>err &&
+	test_cmp expected err
+'
+
 test_done
-- 
2.39.5 (Apple Git-154)
^ permalink raw reply related	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v8 0/5] repo: add new command for retrieving repository info
  2025-08-06 19:55 ` [GSoC PATCH v8 " Lucas Seiki Oshiro
                     ` (4 preceding siblings ...)
  2025-08-06 19:55   ` [GSoC PATCH v8 5/5] repo: add the --format flag Lucas Seiki Oshiro
@ 2025-08-06 22:38   ` Junio C Hamano
  2025-08-07  7:48   ` Karthik Nayak
  6 siblings, 0 replies; 226+ messages in thread
From: Junio C Hamano @ 2025-08-06 22:38 UTC (permalink / raw)
  To: Lucas Seiki Oshiro
  Cc: git, oswald.buddenhagen, ps, karthik.188, ben.knoble,
	phillip.wood, jltobler, jn.avila, sunshine
Lucas Seiki Oshiro <lucasseikioshiro@gmail.com> writes:
> Hi again!
>
> This 8th version of `git-repo` basically address minor issues from the 7th
> version:
>
> - A test wasn't passing in the CI because it assumed that the ref
>   format was files by default. I fixed that.
>
> - t0450 wasn't passing because the documentation didn't match the
>   usage string. I fixed that.
>
> - A test generated the output and the expected value but wasn't
>   comparing them. I also fixed that.
>
> - strbuf management: now we have two strbufs for printing values:
>   one for unquoted values and other for quoted values
>
> - Test codestyle: now it's ending test case liness with \ instead of
>   open strings
>
> - Documentation: this version documents that we escape the value in
>   the `keyvalue` format.
Thanks for these updates.  Will replace and merge to 'seen'.
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v8 3/5] repo: add the field layout.bare
  2025-08-06 19:55   ` [GSoC PATCH v8 3/5] repo: add the field layout.bare Lucas Seiki Oshiro
@ 2025-08-07  5:20     ` Patrick Steinhardt
  0 siblings, 0 replies; 226+ messages in thread
From: Patrick Steinhardt @ 2025-08-07  5:20 UTC (permalink / raw)
  To: Lucas Seiki Oshiro
  Cc: git, oswald.buddenhagen, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler, jn.avila, sunshine
On Wed, Aug 06, 2025 at 04:55:35PM -0300, Lucas Seiki Oshiro wrote:
> diff --git a/t/t1900-repo.sh b/t/t1900-repo.sh
> index ce02b394da..32f64b635b 100755
> --- a/t/t1900-repo.sh
> +++ b/t/t1900-repo.sh
> @@ -54,4 +60,14 @@ test_expect_success 'only one value is returned if the same key is requested twi
>  	test_cmp expect actual
>  '
>  
> +test_expect_success 'output is returned correctly when two keys are requested' '
> +	cat >expected <<-\EOF &&
> +	layout.bare=false
> +	references.format=files
> +	EOF
> +	git init --ref-format=files two-keys &&
> +	git -C two-keys repo info layout.bare references.format > actual &&
Tiny nit, not worth a reroll on its own: our code style doesn't have a
space between the redirect operator and its target.
Patrick
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v8 5/5] repo: add the --format flag
  2025-08-06 19:55   ` [GSoC PATCH v8 5/5] repo: add the --format flag Lucas Seiki Oshiro
@ 2025-08-07  5:20     ` Patrick Steinhardt
  2025-08-07 15:44       ` Junio C Hamano
  0 siblings, 1 reply; 226+ messages in thread
From: Patrick Steinhardt @ 2025-08-07  5:20 UTC (permalink / raw)
  To: Lucas Seiki Oshiro
  Cc: git, oswald.buddenhagen, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler, jn.avila, sunshine
On Wed, Aug 06, 2025 at 04:55:37PM -0300, Lucas Seiki Oshiro wrote:
> diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc
> index 1ae9c09fac..2b63954098 100644
> --- a/Documentation/git-repo.adoc
> +++ b/Documentation/git-repo.adoc
> diff --git a/builtin/repo.c b/builtin/repo.c
> index 312fd08c34..37b5726816 100644
> --- a/builtin/repo.c
> +++ b/builtin/repo.c
> @@ -101,8 +108,18 @@ static int print_fields(int argc, const char **argv, struct repository *repo)
>  		}
>  
>  		get_value(repo, &valbuf);
> -		quote_c_style(valbuf.buf, "buf, NULL, 0);
> -		printf("%s=%s\n", key, quotbuf.buf);
> +
> +		switch (format) {
> +		case FORMAT_KEYVALUE:
> +			quote_c_style(valbuf.buf, "buf, NULL, 0);
> +			printf("%s=%s\n", key, quotbuf.buf);
> +			break;
> +		case FORMAT_NUL_TERMINATED:
> +			printf("%s\n%s%c", key, valbuf.buf, '\0');
> +			break;
> +		default:
> +			BUG("%d: not a valid output format", format);
Nit: we typically say it the other way round.
	BUG("not a valid output format: %d", format);
Doesn't matter too much though as ideally this message shouldn't ever be
seen by any user out there.
Other than my two nits the series looks good to me, thanks! I don't
terribly mind whether or not those nits are addressed.
Patrick
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v8 2/5] repo: add the field references.format
  2025-08-06 19:55   ` [GSoC PATCH v8 2/5] repo: add the field references.format Lucas Seiki Oshiro
@ 2025-08-07  7:43     ` Karthik Nayak
  0 siblings, 0 replies; 226+ messages in thread
From: Karthik Nayak @ 2025-08-07  7:43 UTC (permalink / raw)
  To: Lucas Seiki Oshiro, git
  Cc: oswald.buddenhagen, ps, ben.knoble, gitster, phillip.wood,
	jltobler, jn.avila, sunshine
[-- Attachment #1: Type: text/plain, Size: 2269 bytes --]
Lucas Seiki Oshiro <lucasseikioshiro@gmail.com> writes:
> diff --git a/t/t1900-repo.sh b/t/t1900-repo.sh
> new file mode 100755
> index 0000000000..ce02b394da
> --- /dev/null
> +++ b/t/t1900-repo.sh
> @@ -0,0 +1,57 @@
> +#!/bin/sh
> +
> +test_description='test git repo-info'
> +
> +. ./test-lib.sh
> +
> +# Test whether a key-value pair is correctly returned
> +#
> +# Usage: test_repo_info <label> <init command> <key> <expected value>
> +#
> +# Arguments:
> +#   label: the label of the test
> +#   init_command: a command which creates a repository
> +#   repo_name: the name of the repository that will be created in init_command
> +#   key: the key of the field that is being tested
> +#   expected_value: the value that the field should contain
> +test_repo_info () {
> +	label=$1
> +	init_command=$2
> +	repo_name=$3
> +	key=$4
> +	expected_value=$5
> +
> +	test_expect_success "$label" '
> +		eval "$init_command $repo_name" &&
> +		echo "$key=$expected_value" >expected &&
> +		git -C $repo_name repo info "$key" >actual &&
> +		test_cmp expected actual
> +	'
> +}
> +
> +test_repo_info 'ref format files is retrieved correctly' '
> +	git init --ref-format=files' 'format-files' 'references.format' 'files'
> +
> +test_repo_info 'ref format reftable is retrieved correctly' '
> +	git init --ref-format=reftable' 'format-reftable' 'references.format' 'reftable'
> +
> +test_expect_success 'git-repo-info fails if an invalid key is requested' '
> +	echo "error: key '\'foo\'' not found" >expected_err &&
Nit: we generally use '${SQ}foo${SQ}' for single quoting in tests.
> +	test_must_fail git repo info foo 2>actual_err &&
> +	test_cmp expected_err actual_err
> +'
> +
> +test_expect_success 'git-repo-info outputs data even if there is an invalid field' '
> +	echo "references.format=$(test_detect_ref_format)" >expected &&
> +	test_must_fail git repo info foo references.format bar >actual &&
> +	test_cmp expected actual
> +'
> +
> +test_expect_success 'only one value is returned if the same key is requested twice' '
> +	val=$(git rev-parse --show-ref-format) &&
> +	echo "references.format=$val" >expect &&
> +	git repo info references.format references.format >actual &&
> +	test_cmp expect actual
> +'
> +
> +test_done
> --
> 2.39.5 (Apple Git-154)
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 690 bytes --]
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v8 0/5] repo: add new command for retrieving repository info
  2025-08-06 19:55 ` [GSoC PATCH v8 " Lucas Seiki Oshiro
                     ` (5 preceding siblings ...)
  2025-08-06 22:38   ` [GSoC PATCH v8 0/5] repo: add new command for retrieving repository info Junio C Hamano
@ 2025-08-07  7:48   ` Karthik Nayak
  6 siblings, 0 replies; 226+ messages in thread
From: Karthik Nayak @ 2025-08-07  7:48 UTC (permalink / raw)
  To: Lucas Seiki Oshiro, git
  Cc: oswald.buddenhagen, ps, ben.knoble, gitster, phillip.wood,
	jltobler, jn.avila, sunshine
[-- Attachment #1: Type: text/plain, Size: 917 bytes --]
Lucas Seiki Oshiro <lucasseikioshiro@gmail.com> writes:
> Hi again!
>
> This 8th version of `git-repo` basically address minor issues from the 7th
> version:
>
> - A test wasn't passing in the CI because it assumed that the ref
>   format was files by default. I fixed that.
>
> - t0450 wasn't passing because the documentation didn't match the
>   usage string. I fixed that.
>
> - A test generated the output and the expected value but wasn't
>   comparing them. I also fixed that.
>
> - strbuf management: now we have two strbufs for printing values:
>   one for unquoted values and other for quoted values
>
> - Test codestyle: now it's ending test case liness with \ instead of
>   open strings
>
> - Documentation: this version documents that we escape the value in
>   the `keyvalue` format.
>
Apart from a single nit on my side, I couldn't find any other changes
needed, this version looks good! :)
[snip]
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 690 bytes --]
^ permalink raw reply	[flat|nested] 226+ messages in thread
* [GSoC PATCH v9 0/5] repo: add new command for retrieving repository info
  2025-06-10 15:21 [GSoC RFC PATCH 0/5] repo-info: add new command for retrieving repository info Lucas Seiki Oshiro
                   ` (14 preceding siblings ...)
  2025-08-06 19:55 ` [GSoC PATCH v8 " Lucas Seiki Oshiro
@ 2025-08-07 15:02 ` Lucas Seiki Oshiro
  2025-08-07 15:02   ` [GSoC PATCH v9 1/5] repo: declare the repo command Lucas Seiki Oshiro
                     ` (6 more replies)
  2025-08-15 13:55 ` [GSoC PATCH v10 0/5] repo: declare the repo command Lucas Seiki Oshiro
  2025-08-16 22:45 ` [GSoC PATCH v11 0/5] repo: declare the repo command Lucas Seiki Oshiro
  17 siblings, 7 replies; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-08-07 15:02 UTC (permalink / raw)
  To: git
  Cc: oswald.buddenhagen, ps, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler, jn.avila, sunshine, Lucas Seiki Oshiro
Hi!
Thank you all for your time reviewing and helping me with this patchset!
This v9 only solve tiny nitpicks pointed by Karthik and Patrick in v8,
just to make clear that everything is ok!
Junio, would you mind to replace v8 by this v9 as lo/repo-info in seen?
Here's the range-diff:
1:  3c2ede66be = 1:  3c2ede66be repo: declare the repo command
2:  396bee171a ! 2:  b18e74763d repo: add the field references.format
    @@ t/t1900-repo.sh (new)
     +	git init --ref-format=reftable' 'format-reftable' 'references.format' 'reftable'
     +
     +test_expect_success 'git-repo-info fails if an invalid key is requested' '
    -+	echo "error: key '\'foo\'' not found" >expected_err &&
    ++	echo "error: key ${SQ}foo${SQ} not found" >expected_err &&
     +	test_must_fail git repo info foo 2>actual_err &&
     +	test_cmp expected_err actual_err
     +'
3:  4dbc83c64c ! 3:  35916b210e repo: add the field layout.bare
    @@ t/t1900-repo.sh: test_repo_info 'ref format files is retrieved correctly' '
     +	'git init --bare' 'bare' 'layout.bare' 'true'
     +
      test_expect_success 'git-repo-info fails if an invalid key is requested' '
    - 	echo "error: key '\'foo\'' not found" >expected_err &&
    + 	echo "error: key ${SQ}foo${SQ} not found" >expected_err &&
      	test_must_fail git repo info foo 2>actual_err &&
     @@ t/t1900-repo.sh: test_expect_success 'only one value is returned if the same key is requested twi
      	test_cmp expect actual
    @@ t/t1900-repo.sh: test_expect_success 'only one value is returned if the same key
     +	references.format=files
     +	EOF
     +	git init --ref-format=files two-keys &&
    -+	git -C two-keys repo info layout.bare references.format > actual &&
    ++	git -C two-keys repo info layout.bare references.format >actual &&
     +	test_cmp expected actual
     +'
     +
4:  5c65a24df4 ! 4:  91fc5c4e50 repo: add the field layout.shallow
    @@ t/t1900-repo.sh: test_repo_info 'bare repository = false is retrieved correctly'
     +	git clone --depth 1 "file://$PWD/remote"' 'shallow' 'layout.shallow' 'true'
     +
      test_expect_success 'git-repo-info fails if an invalid key is requested' '
    - 	echo "error: key '\'foo\'' not found" >expected_err &&
    + 	echo "error: key ${SQ}foo${SQ} not found" >expected_err &&
      	test_must_fail git repo info foo 2>actual_err &&
5:  923b491324 ! 5:  8af32d7066 repo: add the --format flag
    @@ builtin/repo.c: static int print_fields(int argc, const char **argv, struct repo
     +			printf("%s\n%s%c", key, valbuf.buf, '\0');
     +			break;
     +		default:
    -+			BUG("%d: not a valid output format", format);
    ++			BUG("not a valid output format: %d", format);
     +		}
      	}
    @@ t/t1900-repo.sh: test_repo_info 'bare repository = true is retrieved correctly'
     +	'git clone --depth 1 "file://$PWD/remote"' 'shallow' 'layout.shallow' 'true'
      test_expect_success 'git-repo-info fails if an invalid key is requested' '
    - 	echo "error: key '\'foo\'' not found" >expected_err &&
    + 	echo "error: key ${SQ}foo${SQ} not found" >expected_err &&
     @@ t/t1900-repo.sh: test_expect_success 'output is returned correctly when two keys are requested' '
      	test_cmp expected actual
      '
Lucas Seiki Oshiro (5):
  repo: declare the repo command
  repo: add the field references.format
  repo: add the field layout.bare
  repo: add the field layout.shallow
  repo: add the --format flag
 .gitignore                  |   1 +
 Documentation/git-repo.adoc |  81 ++++++++++++++++++
 Documentation/meson.build   |   1 +
 Makefile                    |   1 +
 builtin.h                   |   1 +
 builtin/repo.c              | 165 ++++++++++++++++++++++++++++++++++++
 command-list.txt            |   1 +
 git.c                       |   1 +
 meson.build                 |   1 +
 t/meson.build               |   1 +
 t/t1900-repo.sh             | 102 ++++++++++++++++++++++
 11 files changed, 356 insertions(+)
 create mode 100644 Documentation/git-repo.adoc
 create mode 100644 builtin/repo.c
 create mode 100755 t/t1900-repo.sh
-- 
2.39.5 (Apple Git-154)
^ permalink raw reply	[flat|nested] 226+ messages in thread
* [GSoC PATCH v9 1/5] repo: declare the repo command
  2025-08-07 15:02 ` [GSoC PATCH v9 " Lucas Seiki Oshiro
@ 2025-08-07 15:02   ` Lucas Seiki Oshiro
  2025-08-07 15:02   ` [GSoC PATCH v9 2/5] repo: add the field references.format Lucas Seiki Oshiro
                     ` (5 subsequent siblings)
  6 siblings, 0 replies; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-08-07 15:02 UTC (permalink / raw)
  To: git
  Cc: oswald.buddenhagen, ps, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler, jn.avila, sunshine, Lucas Seiki Oshiro
Currently, `git rev-parse` covers a wide range of functionality not
directly related to parsing revisions, as its name suggests. Over time,
many features like parsing datestrings, options, paths, and others
were added to it because there wasn't a more appropriate command
to place them.
Create a new Git command called `repo`. `git repo` will be the main
command for obtaining the information about a repository (such as
metadata and metrics).
Also declare a subcommand for `repo` called `info`. `git repo info`
will bring the functionality of retrieving repository-related
information currently returned by `rev-parse`.
Add the required documentation and build changes to enable usage of
this subcommand.
Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Helped-by: Junio C Hamano <gitster@pobox.com>
Helped-by: Justin Tobler <jltobler@gmail.com>
Helped-by: Eric Sunshine <sunshine@sunshineco.com>
Mentored-by: Karthik Nayak <karthik.188@gmail.com>
Mentored-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
---
 .gitignore                  |  1 +
 Documentation/git-repo.adoc | 32 ++++++++++++++++++++++++++++++++
 Documentation/meson.build   |  1 +
 Makefile                    |  1 +
 builtin.h                   |  1 +
 builtin/repo.c              | 27 +++++++++++++++++++++++++++
 command-list.txt            |  1 +
 git.c                       |  1 +
 meson.build                 |  1 +
 9 files changed, 66 insertions(+)
 create mode 100644 Documentation/git-repo.adoc
 create mode 100644 builtin/repo.c
diff --git a/.gitignore b/.gitignore
index 04c444404e..1803023427 100644
--- a/.gitignore
+++ b/.gitignore
@@ -139,6 +139,7 @@
 /git-repack
 /git-replace
 /git-replay
+/git-repo
 /git-request-pull
 /git-rerere
 /git-reset
diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc
new file mode 100644
index 0000000000..68c706f5a0
--- /dev/null
+++ b/Documentation/git-repo.adoc
@@ -0,0 +1,32 @@
+git-repo(1)
+===========
+
+NAME
+----
+git-repo - Retrieve information about the repository
+
+SYNOPSIS
+--------
+[synopsis]
+git repo info [<key>...]
+
+DESCRIPTION
+-----------
+Retrieve information about the repository.
+
+THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOR MAY CHANGE.
+
+COMMANDS
+--------
+`info [<key>...]`::
+	Retrieve metadata-related information about the current repository. Only
+	the requested data will be returned based on their keys (see "INFO KEYS"
+	section below).
+
+SEE ALSO
+--------
+linkgit:git-rev-parse[1]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/meson.build b/Documentation/meson.build
index 4404c623f0..41f43e0336 100644
--- a/Documentation/meson.build
+++ b/Documentation/meson.build
@@ -116,6 +116,7 @@ manpages = {
   'git-repack.adoc' : 1,
   'git-replace.adoc' : 1,
   'git-replay.adoc' : 1,
+  'git-repo.adoc' : 1,
   'git-request-pull.adoc' : 1,
   'git-rerere.adoc' : 1,
   'git-reset.adoc' : 1,
diff --git a/Makefile b/Makefile
index e11340c1ae..ec7ac58980 100644
--- a/Makefile
+++ b/Makefile
@@ -1306,6 +1306,7 @@ BUILTIN_OBJS += builtin/remote.o
 BUILTIN_OBJS += builtin/repack.o
 BUILTIN_OBJS += builtin/replace.o
 BUILTIN_OBJS += builtin/replay.o
+BUILTIN_OBJS += builtin/repo.o
 BUILTIN_OBJS += builtin/rerere.o
 BUILTIN_OBJS += builtin/reset.o
 BUILTIN_OBJS += builtin/rev-list.o
diff --git a/builtin.h b/builtin.h
index bff13e3069..e6458e6fb9 100644
--- a/builtin.h
+++ b/builtin.h
@@ -216,6 +216,7 @@ int cmd_remote_ext(int argc, const char **argv, const char *prefix, struct repos
 int cmd_remote_fd(int argc, const char **argv, const char *prefix, struct repository *repo);
 int cmd_repack(int argc, const char **argv, const char *prefix, struct repository *repo);
 int cmd_replay(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_repo(int argc, const char **argv, const char *prefix, struct repository *repo);
 int cmd_rerere(int argc, const char **argv, const char *prefix, struct repository *repo);
 int cmd_reset(int argc, const char **argv, const char *prefix, struct repository *repo);
 int cmd_restore(int argc, const char **argv, const char *prefix, struct repository *repo);
diff --git a/builtin/repo.c b/builtin/repo.c
new file mode 100644
index 0000000000..fd2a9b4216
--- /dev/null
+++ b/builtin/repo.c
@@ -0,0 +1,27 @@
+#include "builtin.h"
+#include "parse-options.h"
+
+static const char *const repo_usage[] = {
+	"git repo info [<key>...]",
+	NULL
+};
+
+static int repo_info(int argc UNUSED, const char **argv UNUSED,
+		     const char *prefix UNUSED, struct repository *repo UNUSED)
+{
+	return 0;
+}
+
+int cmd_repo(int argc, const char **argv, const char *prefix,
+	     struct repository *repo)
+{
+	parse_opt_subcommand_fn *fn = NULL;
+	struct option options[] = {
+		OPT_SUBCOMMAND("info", &fn, repo_info),
+		OPT_END()
+	};
+
+	argc = parse_options(argc, argv, prefix, options, repo_usage, 0);
+
+	return fn(argc, argv, prefix, repo);
+}
diff --git a/command-list.txt b/command-list.txt
index b7ade3ab9f..1b0bdee00d 100644
--- a/command-list.txt
+++ b/command-list.txt
@@ -164,6 +164,7 @@ git-remote                              ancillarymanipulators           complete
 git-repack                              ancillarymanipulators           complete
 git-replace                             ancillarymanipulators           complete
 git-replay                              plumbingmanipulators
+git-repo                                plumbinginterrogators
 git-request-pull                        foreignscminterface             complete
 git-rerere                              ancillaryinterrogators
 git-reset                               mainporcelain           history
diff --git a/git.c b/git.c
index 83eac0aeab..d4ff4d5517 100644
--- a/git.c
+++ b/git.c
@@ -611,6 +611,7 @@ static struct cmd_struct commands[] = {
 	{ "repack", cmd_repack, RUN_SETUP },
 	{ "replace", cmd_replace, RUN_SETUP },
 	{ "replay", cmd_replay, RUN_SETUP },
+	{ "repo", cmd_repo, RUN_SETUP },
 	{ "rerere", cmd_rerere, RUN_SETUP },
 	{ "reset", cmd_reset, RUN_SETUP },
 	{ "restore", cmd_restore, RUN_SETUP | NEED_WORK_TREE },
diff --git a/meson.build b/meson.build
index 5dd299b496..e8ec0eca16 100644
--- a/meson.build
+++ b/meson.build
@@ -645,6 +645,7 @@ builtin_sources = [
   'builtin/repack.c',
   'builtin/replace.c',
   'builtin/replay.c',
+  'builtin/repo.c',
   'builtin/rerere.c',
   'builtin/reset.c',
   'builtin/rev-list.c',
-- 
2.39.5 (Apple Git-154)
^ permalink raw reply related	[flat|nested] 226+ messages in thread
* [GSoC PATCH v9 2/5] repo: add the field references.format
  2025-08-07 15:02 ` [GSoC PATCH v9 " Lucas Seiki Oshiro
  2025-08-07 15:02   ` [GSoC PATCH v9 1/5] repo: declare the repo command Lucas Seiki Oshiro
@ 2025-08-07 15:02   ` Lucas Seiki Oshiro
  2025-08-11  5:12     ` Eric Sunshine
  2025-08-11 14:41     ` Phillip Wood
  2025-08-07 15:02   ` [GSoC PATCH v9 3/5] repo: add the field layout.bare Lucas Seiki Oshiro
                     ` (4 subsequent siblings)
  6 siblings, 2 replies; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-08-07 15:02 UTC (permalink / raw)
  To: git
  Cc: oswald.buddenhagen, ps, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler, jn.avila, sunshine, Lucas Seiki Oshiro
This commit is part of the series that introduces the new subcommand
git-repo-info.
The flag `--show-ref-format` from git-rev-parse is used for retrieving
the reference format (i.e. `files` or `reftable`). This way, it is
used for querying repository metadata, fitting in the purpose of
git-repo-info.
Add a new field `references.format` to the repo-info subcommand
containing that information.
Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Helped-by: Junio C Hamano <gitster@pobox.com>
Helped-by: Justin Tobler <jltobler@gmail.com>
Helped-by: Eric Sunshine <sunshine@sunshineco.com>
Mentored-by: Karthik Nayak <karthik.188@gmail.com>
Mentored-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
---
 Documentation/git-repo.adoc | 19 ++++++++
 builtin/repo.c              | 89 ++++++++++++++++++++++++++++++++++++-
 t/meson.build               |  1 +
 t/t1900-repo.sh             | 57 ++++++++++++++++++++++++
 4 files changed, 164 insertions(+), 2 deletions(-)
 create mode 100755 t/t1900-repo.sh
diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc
index 68c706f5a0..0ee783abc2 100644
--- a/Documentation/git-repo.adoc
+++ b/Documentation/git-repo.adoc
@@ -22,6 +22,25 @@ COMMANDS
 	Retrieve metadata-related information about the current repository. Only
 	the requested data will be returned based on their keys (see "INFO KEYS"
 	section below).
++
+The returned data is lexicographically sorted by the keys.
++
+The output format consists of key-value pairs one per line using the `=`
+character as the delimiter between the key and the value. Values containing
+"unusual" characters are quoted as explained for the configuration variable
+`core.quotePath` (see linkgit:git-config[1]). This is the default.
+
+INFO KEYS
+---------
+
+In order to obtain a set of values from `git repo info`, you should provide
+the keys that identify them. Here's a list of the available keys and the
+values that they return:
+
+`references.format`::
+The reference storage format. The valid values are:
++
+include::ref-storage-format.adoc[]
 
 SEE ALSO
 --------
diff --git a/builtin/repo.c b/builtin/repo.c
index fd2a9b4216..2b7ab5875e 100644
--- a/builtin/repo.c
+++ b/builtin/repo.c
@@ -1,17 +1,102 @@
 #include "builtin.h"
 #include "parse-options.h"
+#include "quote.h"
+#include "refs.h"
+#include "strbuf.h"
 
 static const char *const repo_usage[] = {
 	"git repo info [<key>...]",
 	NULL
 };
 
-static int repo_info(int argc UNUSED, const char **argv UNUSED,
-		     const char *prefix UNUSED, struct repository *repo UNUSED)
+typedef int get_value_fn(struct repository *repo, struct strbuf *buf);
+
+struct field {
+	const char *key;
+	get_value_fn *get_value;
+};
+
+static int get_references_format(struct repository *repo, struct strbuf *buf)
 {
+	strbuf_addstr(buf,
+		      ref_storage_format_to_name(repo->ref_storage_format));
 	return 0;
 }
 
+/* repo_info_fields keys should be in lexicographical order */
+static const struct field repo_info_fields[] = {
+	{ "references.format", get_references_format },
+};
+
+static int repo_info_fields_cmp(const void *va, const void *vb)
+{
+	const struct field *a = va;
+	const struct field *b = vb;
+
+	return strcmp(a->key, b->key);
+}
+
+static get_value_fn *get_value_fn_for_key(const char *key)
+{
+	const struct field search_key = { key, NULL };
+	const struct field *found = bsearch(&search_key, repo_info_fields,
+					    ARRAY_SIZE(repo_info_fields),
+					    sizeof(*found),
+					    repo_info_fields_cmp);
+	return found ? found->get_value : NULL;
+}
+
+static int qsort_strcmp(const void *va, const void *vb)
+{
+	const char *a = *(const char **)va;
+	const char *b = *(const char **)vb;
+
+	return strcmp(a, b);
+}
+
+static int print_fields(int argc, const char **argv, struct repository *repo)
+{
+	int ret = 0;
+	const char *last = "";
+	struct strbuf valbuf = STRBUF_INIT;
+	struct strbuf quotbuf = STRBUF_INIT;
+
+	QSORT(argv, argc, qsort_strcmp);
+
+	for (int i = 0; i < argc; i++) {
+		get_value_fn *get_value;
+		const char *key = argv[i];
+
+		strbuf_reset(&valbuf);
+		strbuf_reset("buf);
+
+		if (!strcmp(key, last))
+			continue;
+
+		last = key;
+		get_value = get_value_fn_for_key(key);
+
+		if (!get_value) {
+			ret = error(_("key '%s' not found"), key);
+			continue;
+		}
+
+		get_value(repo, &valbuf);
+		quote_c_style(valbuf.buf, "buf, NULL, 0);
+		printf("%s=%s\n", key, quotbuf.buf);
+	}
+
+	strbuf_release(&valbuf);
+	strbuf_release("buf);
+	return ret;
+}
+
+static int repo_info(int argc, const char **argv, const char *prefix UNUSED,
+		     struct repository *repo)
+{
+	return print_fields(argc - 1, argv + 1, repo);
+}
+
 int cmd_repo(int argc, const char **argv, const char *prefix,
 	     struct repository *repo)
 {
diff --git a/t/meson.build b/t/meson.build
index bbeba1a8d5..252dbbc031 100644
--- a/t/meson.build
+++ b/t/meson.build
@@ -230,6 +230,7 @@ integration_tests = [
   't1700-split-index.sh',
   't1701-racy-split-index.sh',
   't1800-hook.sh',
+  't1900-repo.sh',
   't2000-conflict-when-checking-files-out.sh',
   't2002-checkout-cache-u.sh',
   't2003-checkout-cache-mkdir.sh',
diff --git a/t/t1900-repo.sh b/t/t1900-repo.sh
new file mode 100755
index 0000000000..2b2516dbae
--- /dev/null
+++ b/t/t1900-repo.sh
@@ -0,0 +1,57 @@
+#!/bin/sh
+
+test_description='test git repo-info'
+
+. ./test-lib.sh
+
+# Test whether a key-value pair is correctly returned
+#
+# Usage: test_repo_info <label> <init command> <key> <expected value>
+#
+# Arguments:
+#   label: the label of the test
+#   init_command: a command which creates a repository
+#   repo_name: the name of the repository that will be created in init_command
+#   key: the key of the field that is being tested
+#   expected_value: the value that the field should contain
+test_repo_info () {
+	label=$1
+	init_command=$2
+	repo_name=$3
+	key=$4
+	expected_value=$5
+
+	test_expect_success "$label" '
+		eval "$init_command $repo_name" &&
+		echo "$key=$expected_value" >expected &&
+		git -C $repo_name repo info "$key" >actual &&
+		test_cmp expected actual
+	'
+}
+
+test_repo_info 'ref format files is retrieved correctly' '
+	git init --ref-format=files' 'format-files' 'references.format' 'files'
+
+test_repo_info 'ref format reftable is retrieved correctly' '
+	git init --ref-format=reftable' 'format-reftable' 'references.format' 'reftable'
+
+test_expect_success 'git-repo-info fails if an invalid key is requested' '
+	echo "error: key ${SQ}foo${SQ} not found" >expected_err &&
+	test_must_fail git repo info foo 2>actual_err &&
+	test_cmp expected_err actual_err
+'
+
+test_expect_success 'git-repo-info outputs data even if there is an invalid field' '
+	echo "references.format=$(test_detect_ref_format)" >expected &&
+	test_must_fail git repo info foo references.format bar >actual &&
+	test_cmp expected actual
+'
+
+test_expect_success 'only one value is returned if the same key is requested twice' '
+	val=$(git rev-parse --show-ref-format) &&
+	echo "references.format=$val" >expect &&
+	git repo info references.format references.format >actual &&
+	test_cmp expect actual
+'
+
+test_done
-- 
2.39.5 (Apple Git-154)
^ permalink raw reply related	[flat|nested] 226+ messages in thread
* [GSoC PATCH v9 3/5] repo: add the field layout.bare
  2025-08-07 15:02 ` [GSoC PATCH v9 " Lucas Seiki Oshiro
  2025-08-07 15:02   ` [GSoC PATCH v9 1/5] repo: declare the repo command Lucas Seiki Oshiro
  2025-08-07 15:02   ` [GSoC PATCH v9 2/5] repo: add the field references.format Lucas Seiki Oshiro
@ 2025-08-07 15:02   ` Lucas Seiki Oshiro
  2025-08-11  5:21     ` Eric Sunshine
  2025-08-07 15:02   ` [GSoC PATCH v9 4/5] repo: add the field layout.shallow Lucas Seiki Oshiro
                     ` (3 subsequent siblings)
  6 siblings, 1 reply; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-08-07 15:02 UTC (permalink / raw)
  To: git
  Cc: oswald.buddenhagen, ps, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler, jn.avila, sunshine, Lucas Seiki Oshiro
This commit is part of the series that introduces the new subcommand
git-repo-info.
The flag --is-bare-repository from git-rev-parse is used for retrieving
whether the current repository is bare. This way, it is used for
querying repository metadata, fitting in the purpose of git-repo-info.
Then, add a new field layout.bare to the git-repo-info subcommand
containing that information.
Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Helped-by: Junio C Hamano <gitster@pobox.com>
Helped-by: Justin Tobler <jltobler@gmail.com>
Helped-by: Eric Sunshine <sunshine@sunshineco.com>
Mentored-by: Karthik Nayak <karthik.188@gmail.com>
Mentored-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
---
 Documentation/git-repo.adoc |  3 +++
 builtin/repo.c              | 10 ++++++++++
 t/t1900-repo.sh             | 16 ++++++++++++++++
 3 files changed, 29 insertions(+)
diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc
index 0ee783abc2..0ef851ee9c 100644
--- a/Documentation/git-repo.adoc
+++ b/Documentation/git-repo.adoc
@@ -37,6 +37,9 @@ In order to obtain a set of values from `git repo info`, you should provide
 the keys that identify them. Here's a list of the available keys and the
 values that they return:
 
+`layout.bare`::
+`true` if this is a bare repository, otherwise `false`.
+
 `references.format`::
 The reference storage format. The valid values are:
 +
diff --git a/builtin/repo.c b/builtin/repo.c
index 2b7ab5875e..abdc929e19 100644
--- a/builtin/repo.c
+++ b/builtin/repo.c
@@ -1,4 +1,7 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
 #include "builtin.h"
+#include "environment.h"
 #include "parse-options.h"
 #include "quote.h"
 #include "refs.h"
@@ -16,6 +19,12 @@ struct field {
 	get_value_fn *get_value;
 };
 
+static int get_layout_bare(struct repository *repo UNUSED, struct strbuf *buf)
+{
+	strbuf_addstr(buf, is_bare_repository() ? "true" : "false");
+	return 0;
+}
+
 static int get_references_format(struct repository *repo, struct strbuf *buf)
 {
 	strbuf_addstr(buf,
@@ -25,6 +34,7 @@ static int get_references_format(struct repository *repo, struct strbuf *buf)
 
 /* repo_info_fields keys should be in lexicographical order */
 static const struct field repo_info_fields[] = {
+	{ "layout.bare", get_layout_bare },
 	{ "references.format", get_references_format },
 };
 
diff --git a/t/t1900-repo.sh b/t/t1900-repo.sh
index 2b2516dbae..e5a624ec71 100755
--- a/t/t1900-repo.sh
+++ b/t/t1900-repo.sh
@@ -35,6 +35,12 @@ test_repo_info 'ref format files is retrieved correctly' '
 test_repo_info 'ref format reftable is retrieved correctly' '
 	git init --ref-format=reftable' 'format-reftable' 'references.format' 'reftable'
 
+test_repo_info 'bare repository = false is retrieved correctly' \
+	'git init' 'nonbare' 'layout.bare' 'false'
+
+test_repo_info 'bare repository = true is retrieved correctly' \
+	'git init --bare' 'bare' 'layout.bare' 'true'
+
 test_expect_success 'git-repo-info fails if an invalid key is requested' '
 	echo "error: key ${SQ}foo${SQ} not found" >expected_err &&
 	test_must_fail git repo info foo 2>actual_err &&
@@ -54,4 +60,14 @@ test_expect_success 'only one value is returned if the same key is requested twi
 	test_cmp expect actual
 '
 
+test_expect_success 'output is returned correctly when two keys are requested' '
+	cat >expected <<-\EOF &&
+	layout.bare=false
+	references.format=files
+	EOF
+	git init --ref-format=files two-keys &&
+	git -C two-keys repo info layout.bare references.format >actual &&
+	test_cmp expected actual
+'
+
 test_done
-- 
2.39.5 (Apple Git-154)
^ permalink raw reply related	[flat|nested] 226+ messages in thread
* [GSoC PATCH v9 4/5] repo: add the field layout.shallow
  2025-08-07 15:02 ` [GSoC PATCH v9 " Lucas Seiki Oshiro
                     ` (2 preceding siblings ...)
  2025-08-07 15:02   ` [GSoC PATCH v9 3/5] repo: add the field layout.bare Lucas Seiki Oshiro
@ 2025-08-07 15:02   ` Lucas Seiki Oshiro
  2025-08-07 15:02   ` [GSoC PATCH v9 5/5] repo: add the --format flag Lucas Seiki Oshiro
                     ` (2 subsequent siblings)
  6 siblings, 0 replies; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-08-07 15:02 UTC (permalink / raw)
  To: git
  Cc: oswald.buddenhagen, ps, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler, jn.avila, sunshine, Lucas Seiki Oshiro
This commit is part of the series that introduces the new subcommand
git-repo-info.
The flag `--is-shallow-repository` from git-rev-parse is used for
retrieving whether the repository is shallow. This way, it is used for
querying repository metadata, fitting in the purpose of git-repo-info.
Then, add a new field `layout.shallow` to the git-repo-info subcommand
containing that information.
Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Helped-by: Junio C Hamano <gitster@pobox.com>
Helped-by: Justin Tobler <jltobler@gmail.com>
Helped-by: Eric Sunshine <sunshine@sunshineco.com>
Mentored-by: Karthik Nayak <karthik.188@gmail.com>
Mentored-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
---
 Documentation/git-repo.adoc |  3 +++
 builtin/repo.c              |  9 +++++++++
 t/t1900-repo.sh             | 10 ++++++++++
 3 files changed, 22 insertions(+)
diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc
index 0ef851ee9c..1ae9c09fac 100644
--- a/Documentation/git-repo.adoc
+++ b/Documentation/git-repo.adoc
@@ -40,6 +40,9 @@ values that they return:
 `layout.bare`::
 `true` if this is a bare repository, otherwise `false`.
 
+`layout.shallow`::
+`true` if this is a shallow repository, otherwise `false`.
+
 `references.format`::
 The reference storage format. The valid values are:
 +
diff --git a/builtin/repo.c b/builtin/repo.c
index abdc929e19..312fd08c34 100644
--- a/builtin/repo.c
+++ b/builtin/repo.c
@@ -6,6 +6,7 @@
 #include "quote.h"
 #include "refs.h"
 #include "strbuf.h"
+#include "shallow.h"
 
 static const char *const repo_usage[] = {
 	"git repo info [<key>...]",
@@ -25,6 +26,13 @@ static int get_layout_bare(struct repository *repo UNUSED, struct strbuf *buf)
 	return 0;
 }
 
+static int get_layout_shallow(struct repository *repo, struct strbuf *buf)
+{
+	strbuf_addstr(buf,
+		      is_repository_shallow(repo) ? "true" : "false");
+	return 0;
+}
+
 static int get_references_format(struct repository *repo, struct strbuf *buf)
 {
 	strbuf_addstr(buf,
@@ -35,6 +43,7 @@ static int get_references_format(struct repository *repo, struct strbuf *buf)
 /* repo_info_fields keys should be in lexicographical order */
 static const struct field repo_info_fields[] = {
 	{ "layout.bare", get_layout_bare },
+	{ "layout.shallow", get_layout_shallow },
 	{ "references.format", get_references_format },
 };
 
diff --git a/t/t1900-repo.sh b/t/t1900-repo.sh
index e5a624ec71..2018772631 100755
--- a/t/t1900-repo.sh
+++ b/t/t1900-repo.sh
@@ -41,6 +41,16 @@ test_repo_info 'bare repository = false is retrieved correctly' \
 test_repo_info 'bare repository = true is retrieved correctly' \
 	'git init --bare' 'bare' 'layout.bare' 'true'
 
+test_repo_info 'shallow repository = false is retrieved correctly' \
+	'git init' 'nonshallow' 'layout.shallow' 'false'
+
+test_repo_info 'shallow repository = true is retrieved correctly' \
+	'git init remote &&
+	echo x >remote/x &&
+	git -C remote add x &&
+	git -C remote commit -m x &&
+	git clone --depth 1 "file://$PWD/remote"' 'shallow' 'layout.shallow' 'true'
+
 test_expect_success 'git-repo-info fails if an invalid key is requested' '
 	echo "error: key ${SQ}foo${SQ} not found" >expected_err &&
 	test_must_fail git repo info foo 2>actual_err &&
-- 
2.39.5 (Apple Git-154)
^ permalink raw reply related	[flat|nested] 226+ messages in thread
* [GSoC PATCH v9 5/5] repo: add the --format flag
  2025-08-07 15:02 ` [GSoC PATCH v9 " Lucas Seiki Oshiro
                     ` (3 preceding siblings ...)
  2025-08-07 15:02   ` [GSoC PATCH v9 4/5] repo: add the field layout.shallow Lucas Seiki Oshiro
@ 2025-08-07 15:02   ` Lucas Seiki Oshiro
  2025-08-11  5:44     ` Eric Sunshine
  2025-08-08  5:45   ` [GSoC PATCH v9 0/5] repo: add new command for retrieving repository info Patrick Steinhardt
  2025-08-08  9:20   ` Karthik Nayak
  6 siblings, 1 reply; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-08-07 15:02 UTC (permalink / raw)
  To: git
  Cc: oswald.buddenhagen, ps, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler, jn.avila, sunshine, Lucas Seiki Oshiro
Add the --format flag to git-repo-info. By using this flag, the users
can choose the format for obtaining the data they requested.
Given that this command can be used for generating input for other
applications and for being read by end users, it requires at least two
formats: one for being read by humans and other for being read by
machines. Some other Git commands also have two output formats, notably
git-config which was the inspiration for the two formats that were
chosen here:
- keyvalue, where the retrieved data is printed one per line, using =
  for delimiting the key and the value. This is the default format,
  targeted for end users.
- nul, where the retrieved data is separated by null characters, using
  the newline character for delimiting the key and the value. This
  format is targeted for being read by machines.
Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Helped-by: Junio C Hamano <gitster@pobox.com>
Helped-by: Justin Tobler <jltobler@gmail.com>
Helped-by: Eric Sunshine <sunshine@sunshineco.com>
Mentored-by: Karthik Nayak <karthik.188@gmail.com>
Mentored-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
---
 Documentation/git-repo.adoc | 36 ++++++++++++++++++++++++-----
 builtin/repo.c              | 46 ++++++++++++++++++++++++++++++++-----
 t/t1900-repo.sh             | 35 +++++++++++++++++++++-------
 3 files changed, 97 insertions(+), 20 deletions(-)
diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc
index 1ae9c09fac..2b63954098 100644
--- a/Documentation/git-repo.adoc
+++ b/Documentation/git-repo.adoc
@@ -8,7 +8,7 @@ git-repo - Retrieve information about the repository
 SYNOPSIS
 --------
 [synopsis]
-git repo info [<key>...]
+git repo info [--format=(keyvalue|nul)] [<key>...]
 
 DESCRIPTION
 -----------
@@ -18,21 +18,28 @@ THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOR MAY CHANGE.
 
 COMMANDS
 --------
-`info [<key>...]`::
+`info [--format=(keyvalue|nul)] [<key>...]`::
 	Retrieve metadata-related information about the current repository. Only
 	the requested data will be returned based on their keys (see "INFO KEYS"
 	section below).
 +
 The returned data is lexicographically sorted by the keys.
 +
-The output format consists of key-value pairs one per line using the `=`
-character as the delimiter between the key and the value. Values containing
-"unusual" characters are quoted as explained for the configuration variable
+The output format can be chosen through the flag `--format`. Two formats are
+supported:
++
+* `keyvalue`: output key-value pairs one per line using the `=` character as
+the delimiter between the key and the value. Values containing "unusual"
+characters are quoted as explained for the configuration variable
 `core.quotePath` (see linkgit:git-config[1]). This is the default.
 
+* `nul`: similar to `keyvalue`, but using a newline character as the delimiter
+between the key and the value and using a null character after each value.
+This format is better suited for being parsed by another applications than
+`keyvalue`. Unlike in the `keyvalue` format, the values are never quoted.
+
 INFO KEYS
 ---------
-
 In order to obtain a set of values from `git repo info`, you should provide
 the keys that identify them. Here's a list of the available keys and the
 values that they return:
@@ -48,6 +55,23 @@ The reference storage format. The valid values are:
 +
 include::ref-storage-format.adoc[]
 
+EXAMPLES
+--------
+
+* Retrieves the reference format of the current repository:
++
+------------
+git repo info references.format
+------------
++
+
+* Retrieves whether the current repository is bare and whether it is shallow
+using the `nul` format:
++
+------------
+git repo info --format=nul layout.bare layout.shallow
+------------
+
 SEE ALSO
 --------
 linkgit:git-rev-parse[1]
diff --git a/builtin/repo.c b/builtin/repo.c
index 312fd08c34..aca29729eb 100644
--- a/builtin/repo.c
+++ b/builtin/repo.c
@@ -9,12 +9,17 @@
 #include "shallow.h"
 
 static const char *const repo_usage[] = {
-	"git repo info [<key>...]",
+	"git repo info [--format=(keyvalue|nul)] [<key>...]",
 	NULL
 };
 
 typedef int get_value_fn(struct repository *repo, struct strbuf *buf);
 
+enum output_format {
+	FORMAT_KEYVALUE,
+	FORMAT_NUL_TERMINATED,
+};
+
 struct field {
 	const char *key;
 	get_value_fn *get_value;
@@ -73,7 +78,9 @@ static int qsort_strcmp(const void *va, const void *vb)
 	return strcmp(a, b);
 }
 
-static int print_fields(int argc, const char **argv, struct repository *repo)
+static int print_fields(int argc, const char **argv,
+			struct repository *repo,
+			enum output_format format)
 {
 	int ret = 0;
 	const char *last = "";
@@ -101,8 +108,18 @@ static int print_fields(int argc, const char **argv, struct repository *repo)
 		}
 
 		get_value(repo, &valbuf);
-		quote_c_style(valbuf.buf, "buf, NULL, 0);
-		printf("%s=%s\n", key, quotbuf.buf);
+
+		switch (format) {
+		case FORMAT_KEYVALUE:
+			quote_c_style(valbuf.buf, "buf, NULL, 0);
+			printf("%s=%s\n", key, quotbuf.buf);
+			break;
+		case FORMAT_NUL_TERMINATED:
+			printf("%s\n%s%c", key, valbuf.buf, '\0');
+			break;
+		default:
+			BUG("not a valid output format: %d", format);
+		}
 	}
 
 	strbuf_release(&valbuf);
@@ -110,10 +127,27 @@ static int print_fields(int argc, const char **argv, struct repository *repo)
 	return ret;
 }
 
-static int repo_info(int argc, const char **argv, const char *prefix UNUSED,
+static int repo_info(int argc, const char **argv, const char *prefix,
 		     struct repository *repo)
 {
-	return print_fields(argc - 1, argv + 1, repo);
+	const char *format_str = "keyvalue";
+	enum output_format format;
+	struct option options[] = {
+		OPT_STRING(0, "format", &format_str, N_("format"),
+			   N_("output format")),
+		OPT_END()
+	};
+
+	argc = parse_options(argc, argv, prefix, options, repo_usage, 0);
+
+	if (!strcmp(format_str, "keyvalue"))
+		format = FORMAT_KEYVALUE;
+	else if (!strcmp(format_str, "nul"))
+		format = FORMAT_NUL_TERMINATED;
+	else
+		die(_("invalid format '%s'"), format_str);
+
+	return print_fields(argc, argv, repo, format);
 }
 
 int cmd_repo(int argc, const char **argv, const char *prefix,
diff --git a/t/t1900-repo.sh b/t/t1900-repo.sh
index 2018772631..eb37c9d16b 100755
--- a/t/t1900-repo.sh
+++ b/t/t1900-repo.sh
@@ -21,12 +21,22 @@ test_repo_info () {
 	key=$4
 	expected_value=$5
 
-	test_expect_success "$label" '
-		eval "$init_command $repo_name" &&
-		echo "$key=$expected_value" >expected &&
-		git -C $repo_name repo info "$key" >actual &&
+	repo_name_keyvalue="$repo_name"-keyvalue
+	repo_name_nul="$repo_name"-nul
+
+	test_expect_success "keyvalue: $label" '
+		eval "$init_command $repo_name_keyvalue" &&
+		echo "$key=$expected_value" > expected &&
+		git -C "$repo_name_keyvalue" repo info "$key" >actual &&
 		test_cmp expected actual
 	'
+
+	test_expect_success "nul: $label" '
+		eval "$init_command $repo_name_nul" &&
+		printf "%s\n%s\0" "$key" "$expected_value" >expected &&
+		git -C "$repo_name_nul" repo info --format=nul "$key" >actual &&
+		test_cmp_bin expected actual
+	'
 }
 
 test_repo_info 'ref format files is retrieved correctly' '
@@ -44,12 +54,15 @@ test_repo_info 'bare repository = true is retrieved correctly' \
 test_repo_info 'shallow repository = false is retrieved correctly' \
 	'git init' 'nonshallow' 'layout.shallow' 'false'
 
-test_repo_info 'shallow repository = true is retrieved correctly' \
-	'git init remote &&
+test_expect_success 'setup remote' '
+	git init remote &&
 	echo x >remote/x &&
 	git -C remote add x &&
-	git -C remote commit -m x &&
-	git clone --depth 1 "file://$PWD/remote"' 'shallow' 'layout.shallow' 'true'
+	git -C remote commit -m x
+'
+
+test_repo_info 'shallow repository = true is retrieved correctly' \
+	'git clone --depth 1 "file://$PWD/remote"' 'shallow' 'layout.shallow' 'true'
 
 test_expect_success 'git-repo-info fails if an invalid key is requested' '
 	echo "error: key ${SQ}foo${SQ} not found" >expected_err &&
@@ -80,4 +93,10 @@ test_expect_success 'output is returned correctly when two keys are requested' '
 	test_cmp expected actual
 '
 
+test_expect_success 'git-repo-info aborts when requesting an invalid format' '
+	echo "fatal: invalid format '\'foo\''" >expected &&
+	test_must_fail git repo info --format=foo 2>err &&
+	test_cmp expected err
+'
+
 test_done
-- 
2.39.5 (Apple Git-154)
^ permalink raw reply related	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v8 5/5] repo: add the --format flag
  2025-08-07  5:20     ` Patrick Steinhardt
@ 2025-08-07 15:44       ` Junio C Hamano
  0 siblings, 0 replies; 226+ messages in thread
From: Junio C Hamano @ 2025-08-07 15:44 UTC (permalink / raw)
  To: Patrick Steinhardt
  Cc: Lucas Seiki Oshiro, git, oswald.buddenhagen, karthik.188,
	ben.knoble, phillip.wood, jltobler, jn.avila, sunshine
Patrick Steinhardt <ps@pks.im> writes:
>> +		default:
>> +			BUG("%d: not a valid output format", format);
>
> Nit: we typically say it the other way round.
>
> 	BUG("not a valid output format: %d", format);
It is in the coding guidelines
 - Say what the error is first ("cannot open '%s'", not "%s: cannot open").
but sometimes we forget.  Thanks for good eyes.
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v9 0/5] repo: add new command for retrieving repository info
  2025-08-07 15:02 ` [GSoC PATCH v9 " Lucas Seiki Oshiro
                     ` (4 preceding siblings ...)
  2025-08-07 15:02   ` [GSoC PATCH v9 5/5] repo: add the --format flag Lucas Seiki Oshiro
@ 2025-08-08  5:45   ` Patrick Steinhardt
  2025-08-08 15:02     ` Junio C Hamano
  2025-08-08  9:20   ` Karthik Nayak
  6 siblings, 1 reply; 226+ messages in thread
From: Patrick Steinhardt @ 2025-08-08  5:45 UTC (permalink / raw)
  To: Lucas Seiki Oshiro
  Cc: git, oswald.buddenhagen, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler, jn.avila, sunshine
On Thu, Aug 07, 2025 at 12:02:34PM -0300, Lucas Seiki Oshiro wrote:
> Hi!
> 
> Thank you all for your time reviewing and helping me with this patchset!
> 
> This v9 only solve tiny nitpicks pointed by Karthik and Patrick in v8,
> just to make clear that everything is ok!
> 
> Junio, would you mind to replace v8 by this v9 as lo/repo-info in seen?
Thanks, this version looks good to me!
Patrick
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v9 0/5] repo: add new command for retrieving repository info
  2025-08-07 15:02 ` [GSoC PATCH v9 " Lucas Seiki Oshiro
                     ` (5 preceding siblings ...)
  2025-08-08  5:45   ` [GSoC PATCH v9 0/5] repo: add new command for retrieving repository info Patrick Steinhardt
@ 2025-08-08  9:20   ` Karthik Nayak
  6 siblings, 0 replies; 226+ messages in thread
From: Karthik Nayak @ 2025-08-08  9:20 UTC (permalink / raw)
  To: Lucas Seiki Oshiro, git
  Cc: oswald.buddenhagen, ps, ben.knoble, gitster, phillip.wood,
	jltobler, jn.avila, sunshine
[-- Attachment #1: Type: text/plain, Size: 377 bytes --]
Lucas Seiki Oshiro <lucasseikioshiro@gmail.com> writes:
> Hi!
>
> Thank you all for your time reviewing and helping me with this patchset!
>
> This v9 only solve tiny nitpicks pointed by Karthik and Patrick in v8,
> just to make clear that everything is ok!
>
> Junio, would you mind to replace v8 by this v9 as lo/repo-info in seen?
>
The changes look good, Thanks.
[snip]
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 690 bytes --]
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v9 0/5] repo: add new command for retrieving repository info
  2025-08-08  5:45   ` [GSoC PATCH v9 0/5] repo: add new command for retrieving repository info Patrick Steinhardt
@ 2025-08-08 15:02     ` Junio C Hamano
  0 siblings, 0 replies; 226+ messages in thread
From: Junio C Hamano @ 2025-08-08 15:02 UTC (permalink / raw)
  To: Patrick Steinhardt
  Cc: Lucas Seiki Oshiro, git, oswald.buddenhagen, karthik.188,
	ben.knoble, phillip.wood, jltobler, jn.avila, sunshine
Patrick Steinhardt <ps@pks.im> writes:
> On Thu, Aug 07, 2025 at 12:02:34PM -0300, Lucas Seiki Oshiro wrote:
>> Hi!
>> 
>> Thank you all for your time reviewing and helping me with this patchset!
>> 
>> This v9 only solve tiny nitpicks pointed by Karthik and Patrick in v8,
>> just to make clear that everything is ok!
>> 
>> Junio, would you mind to replace v8 by this v9 as lo/repo-info in seen?
>
> Thanks, this version looks good to me!
>
> Patrick
Thanks, both.  Let's mark it for 'next' now.
5753e542 (repo: add the --format flag, 2025-08-07)
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v9 2/5] repo: add the field references.format
  2025-08-07 15:02   ` [GSoC PATCH v9 2/5] repo: add the field references.format Lucas Seiki Oshiro
@ 2025-08-11  5:12     ` Eric Sunshine
  2025-08-11 14:41     ` Phillip Wood
  1 sibling, 0 replies; 226+ messages in thread
From: Eric Sunshine @ 2025-08-11  5:12 UTC (permalink / raw)
  To: Lucas Seiki Oshiro
  Cc: git, oswald.buddenhagen, ps, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler, jn.avila
On Thu, Aug 7, 2025 at 11:04 AM Lucas Seiki Oshiro
<lucasseikioshiro@gmail.com> wrote:
> This commit is part of the series that introduces the new subcommand
> git-repo-info.
>
> The flag `--show-ref-format` from git-rev-parse is used for retrieving
> the reference format (i.e. `files` or `reftable`). This way, it is
> used for querying repository metadata, fitting in the purpose of
> git-repo-info.
>
> Add a new field `references.format` to the repo-info subcommand
> containing that information.
>
> Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
> ---
> diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc
> @@ -22,6 +22,25 @@ COMMANDS
>         Retrieve metadata-related information about the current repository. Only
>         the requested data will be returned based on their keys (see "INFO KEYS"
>         section below).
> ++
> +The returned data is lexicographically sorted by the keys.
> ++
> +The output format consists of key-value pairs one per line using the `=`
> +character as the delimiter between the key and the value. Values containing
> +"unusual" characters are quoted as explained for the configuration variable
> +`core.quotePath` (see linkgit:git-config[1]). This is the default.
I don't see any alternative formats presented, so what does "This is
the default" mean here?
(I'm guessing that it might gain meaning in a later patch when NUL
output format is added, but lacking such context in this patch, the
sentence is more than a bit confusing.)
> diff --git a/builtin/repo.c b/builtin/repo.c
> @@ -1,17 +1,102 @@
> +/* repo_info_fields keys should be in lexicographical order */
> +static const struct field repo_info_fields[] = {
> +       { "references.format", get_references_format },
> +};
The comment ought to be more assertive: s/should/must/
> +static int print_fields(int argc, const char **argv, struct repository *repo)
> +{
> +       struct strbuf valbuf = STRBUF_INIT;
> +       struct strbuf quotbuf = STRBUF_INIT;
> +
> +       for (int i = 0; i < argc; i++) {
> +               get_value_fn *get_value;
> +               const char *key = argv[i];
> +
> +               strbuf_reset(&valbuf);
> +               strbuf_reset("buf);
> +
> +               if (!strcmp(key, last))
> +                       continue;
> +
> +               last = key;
> +               get_value = get_value_fn_for_key(key);
> +
> +               if (!get_value) {
> +                       ret = error(_("key '%s' not found"), key);
> +                       continue;
> +               }
> +
> +               get_value(repo, &valbuf);
> +               quote_c_style(valbuf.buf, "buf, NULL, 0);
> +               printf("%s=%s\n", key, quotbuf.buf);
> +       }
Nit: To avoid unnecessary work in the two `continue` cases, I would
have placed the strbuf_reset() calls just before the call to
get_value() as illustrated in my earlier review[1]. Subjective and not
worth a reroll, though.
> diff --git a/t/t1900-repo.sh b/t/t1900-repo.sh
> @@ -0,0 +1,57 @@
> +# Test whether a key-value pair is correctly returned
> +#
> +# Usage: test_repo_info <label> <init command> <key> <expected value>
> +#
> +# Arguments:
> +#   label: the label of the test
> +#   init_command: a command which creates a repository
> +#   repo_name: the name of the repository that will be created in init_command
> +#   key: the key of the field that is being tested
> +#   expected_value: the value that the field should contain
The "Usage" is still wrong (as mentioned earlier[1]). It shows only
four arguments despite the function taking five.
> +test_repo_info () {
> +       label=$1
> +       init_command=$2
> +       repo_name=$3
> +       key=$4
> +       expected_value=$5
> +
> +       test_expect_success "$label" '
> +               eval "$init_command $repo_name" &&
> +               echo "$key=$expected_value" >expected &&
> +               git -C $repo_name repo info "$key" >actual &&
> +               test_cmp expected actual
> +       '
> +}
> +
> +test_repo_info 'ref format files is retrieved correctly' '
> +       git init --ref-format=files' 'format-files' 'references.format' 'files'
> +
> +test_repo_info 'ref format reftable is retrieved correctly' '
> +       git init --ref-format=reftable' 'format-reftable' 'references.format' 'reftable'
The quote placement used in these calls to `test_repo_info` is still
unusual and confusing, as mentioned previously[2]. Calling the
function in the more traditional way would be preferable:
    test_repo_info 'ref format files is retrieved correctly' \
        'git init --ref-format=files' 'format-files' 'references.format' 'files'
> +test_expect_success 'git-repo-info fails if an invalid key is requested' '
> +       echo "error: key ${SQ}foo${SQ} not found" >expected_err &&
> +       test_must_fail git repo info foo 2>actual_err &&
> +       test_cmp expected_err actual_err
> +'
> +
> +test_expect_success 'git-repo-info outputs data even if there is an invalid field' '
> +       echo "references.format=$(test_detect_ref_format)" >expected &&
> +       test_must_fail git repo info foo references.format bar >actual &&
> +       test_cmp expected actual
> +'
> +
> +test_expect_success 'only one value is returned if the same key is requested twice' '
> +       val=$(git rev-parse --show-ref-format) &&
> +       echo "references.format=$val" >expect &&
> +       git repo info references.format references.format >actual &&
> +       test_cmp expect actual
> +'
In my previous review[1], I identified a problem in which the logic
would/could present a poor user-experience by emitting "key '%s' not
found" multiple times for a given unknown key, but I don't see a test
verifying that this problem has been fixed.
[1]: https://lore.kernel.org/git/CAPig+cTxNUPayO2SdCL-BPtjb2rfr3e3RK=BsQxAiiEAtpBaRg@mail.gmail.com/
[2]: https://lore.kernel.org/git/CAPig+cR=vRu7GwGx_wpS_GZNdX7giosDK12K+qQdOW1va-6oWw@mail.gmail.com/
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v9 3/5] repo: add the field layout.bare
  2025-08-07 15:02   ` [GSoC PATCH v9 3/5] repo: add the field layout.bare Lucas Seiki Oshiro
@ 2025-08-11  5:21     ` Eric Sunshine
  2025-08-14 18:22       ` Lucas Seiki Oshiro
  0 siblings, 1 reply; 226+ messages in thread
From: Eric Sunshine @ 2025-08-11  5:21 UTC (permalink / raw)
  To: Lucas Seiki Oshiro
  Cc: git, oswald.buddenhagen, ps, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler, jn.avila
On Thu, Aug 7, 2025 at 11:04 AM Lucas Seiki Oshiro
<lucasseikioshiro@gmail.com> wrote:
> This commit is part of the series that introduces the new subcommand
> git-repo-info.
>
> The flag --is-bare-repository from git-rev-parse is used for retrieving
> whether the current repository is bare. This way, it is used for
> querying repository metadata, fitting in the purpose of git-repo-info.
>
> Then, add a new field layout.bare to the git-repo-info subcommand
> containing that information.
>
> Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
> ---
> diff --git a/t/t1900-repo.sh b/t/t1900-repo.sh
> @@ -54,4 +60,14 @@ test_expect_success 'only one value is returned if the same key is requested twi
> +test_expect_success 'output is returned correctly when two keys are requested' '
> +       cat >expected <<-\EOF &&
> +       layout.bare=false
> +       references.format=files
> +       EOF
> +       git init --ref-format=files two-keys &&
> +       git -C two-keys repo info layout.bare references.format >actual &&
> +       test_cmp expected actual
> +'
Since the documentation asserts that the emitted key/value lines will
be sorted lexicographically, can we also have a test that verifies
that behavior? There are a couple ways you could do that: (1) either
add another test just like this one but reverse the order of the
arguments to the `git repo info` invocation, or (2) modify this test
by reversing the arguments and (*importantly*) add a comment to the
test body explaining that the order of the arguments to the command
invocation are intentionally different from the output to prove that
the output order is unrelated to the argument order.
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v9 5/5] repo: add the --format flag
  2025-08-07 15:02   ` [GSoC PATCH v9 5/5] repo: add the --format flag Lucas Seiki Oshiro
@ 2025-08-11  5:44     ` Eric Sunshine
  0 siblings, 0 replies; 226+ messages in thread
From: Eric Sunshine @ 2025-08-11  5:44 UTC (permalink / raw)
  To: Lucas Seiki Oshiro
  Cc: git, oswald.buddenhagen, ps, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler, jn.avila
On Thu, Aug 7, 2025 at 11:04 AM Lucas Seiki Oshiro
<lucasseikioshiro@gmail.com> wrote:
> Add the --format flag to git-repo-info. By using this flag, the users
> can choose the format for obtaining the data they requested.
> [...]
> Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
> ---
> diff --git a/t/t1900-repo.sh b/t/t1900-repo.sh
> @@ -21,12 +21,22 @@ test_repo_info () {
> -       test_expect_success "$label" '
> -               eval "$init_command $repo_name" &&
> -               echo "$key=$expected_value" >expected &&
> -               git -C $repo_name repo info "$key" >actual &&
> +       repo_name_keyvalue="$repo_name"-keyvalue
> +       repo_name_nul="$repo_name"-nul
> +
> +       test_expect_success "keyvalue: $label" '
> +               eval "$init_command $repo_name_keyvalue" &&
> +               echo "$key=$expected_value" > expected &&
Style nit: drop space following redirection operator[1]. Not worth a reroll.
> +               git -C "$repo_name_keyvalue" repo info "$key" >actual &&
>                 test_cmp expected actual
>         '
> +
> +       test_expect_success "nul: $label" '
> +               eval "$init_command $repo_name_nul" &&
> +               printf "%s\n%s\0" "$key" "$expected_value" >expected &&
> +               git -C "$repo_name_nul" repo info --format=nul "$key" >actual &&
> +               test_cmp_bin expected actual
> +       '
>  }
> @@ -44,12 +54,15 @@ test_repo_info 'bare repository = true is retrieved correctly' \
>  test_expect_success 'git-repo-info fails if an invalid key is requested' '
>         echo "error: key ${SQ}foo${SQ} not found" >expected_err &&
Nit: Here you used ${SQ} as suggested by Karthik[2]...
> @@ -80,4 +93,10 @@ test_expect_success 'output is returned correctly when two keys are requested' '
> +test_expect_success 'git-repo-info aborts when requesting an invalid format' '
> +       echo "fatal: invalid format '\'foo\''" >expected &&
...but here you did not.
> +       test_must_fail git repo info --format=foo 2>err &&
> +       test_cmp expected err
> +'
[1]: https://lore.kernel.org/git/aJQ3sVf4MsgnCaMz@pks.im/
[2]: https://lore.kernel.org/git/CAOLa=ZSX0hFt7PRdXssz2xGG17bmDchS=EheBSmQj9xr+r_baA@mail.gmail.com/
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v9 2/5] repo: add the field references.format
  2025-08-07 15:02   ` [GSoC PATCH v9 2/5] repo: add the field references.format Lucas Seiki Oshiro
  2025-08-11  5:12     ` Eric Sunshine
@ 2025-08-11 14:41     ` Phillip Wood
  2025-08-11 15:44       ` Junio C Hamano
  2025-08-13 21:18       ` Lucas Seiki Oshiro
  1 sibling, 2 replies; 226+ messages in thread
From: Phillip Wood @ 2025-08-11 14:41 UTC (permalink / raw)
  To: Lucas Seiki Oshiro, git
  Cc: oswald.buddenhagen, ps, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler, jn.avila, sunshine
Hi Lucas
On 07/08/2025 16:02, Lucas Seiki Oshiro wrote:
> ++
> +The returned data is lexicographically sorted by the keys.
What's the reason for this? If I query three keys from a script then it 
is much easier to parse the output if I know the keys are going to 
appear in the same order that they were on the command line. If the 
command re-orders them my script now has to check the value of each key 
which results in a bunch of unnecessary string comparisons because it 
cannot determine the key from the position in the output. While we were 
producing json output there was a need to de-duplicate the keys when 
that output format was selected. However, we no-longer produce json and 
in any case de-duplication could have been achieved without sorting the 
input keys by using a hash table, or, as there is a small fixed number 
of keys, an array that records the keys we've already seen.
Thanks
Phillip
> ++
> +The output format consists of key-value pairs one per line using the `=`
> +character as the delimiter between the key and the value. Values containing
> +"unusual" characters are quoted as explained for the configuration variable
> +`core.quotePath` (see linkgit:git-config[1]). This is the default.
> +
> +INFO KEYS
> +---------
> +
> +In order to obtain a set of values from `git repo info`, you should provide
> +the keys that identify them. Here's a list of the available keys and the
> +values that they return:
> +
> +`references.format`::
> +The reference storage format. The valid values are:
> ++
> +include::ref-storage-format.adoc[]
>   
>   SEE ALSO
>   --------
> diff --git a/builtin/repo.c b/builtin/repo.c
> index fd2a9b4216..2b7ab5875e 100644
> --- a/builtin/repo.c
> +++ b/builtin/repo.c
> @@ -1,17 +1,102 @@
>   #include "builtin.h"
>   #include "parse-options.h"
> +#include "quote.h"
> +#include "refs.h"
> +#include "strbuf.h"
>   
>   static const char *const repo_usage[] = {
>   	"git repo info [<key>...]",
>   	NULL
>   };
>   
> -static int repo_info(int argc UNUSED, const char **argv UNUSED,
> -		     const char *prefix UNUSED, struct repository *repo UNUSED)
> +typedef int get_value_fn(struct repository *repo, struct strbuf *buf);
> +
> +struct field {
> +	const char *key;
> +	get_value_fn *get_value;
> +};
> +
> +static int get_references_format(struct repository *repo, struct strbuf *buf)
>   {
> +	strbuf_addstr(buf,
> +		      ref_storage_format_to_name(repo->ref_storage_format));
>   	return 0;
>   }
>   
> +/* repo_info_fields keys should be in lexicographical order */
> +static const struct field repo_info_fields[] = {
> +	{ "references.format", get_references_format },
> +};
> +
> +static int repo_info_fields_cmp(const void *va, const void *vb)
> +{
> +	const struct field *a = va;
> +	const struct field *b = vb;
> +
> +	return strcmp(a->key, b->key);
> +}
> +
> +static get_value_fn *get_value_fn_for_key(const char *key)
> +{
> +	const struct field search_key = { key, NULL };
> +	const struct field *found = bsearch(&search_key, repo_info_fields,
> +					    ARRAY_SIZE(repo_info_fields),
> +					    sizeof(*found),
> +					    repo_info_fields_cmp);
> +	return found ? found->get_value : NULL;
> +}
> +
> +static int qsort_strcmp(const void *va, const void *vb)
> +{
> +	const char *a = *(const char **)va;
> +	const char *b = *(const char **)vb;
> +
> +	return strcmp(a, b);
> +}
> +
> +static int print_fields(int argc, const char **argv, struct repository *repo)
> +{
> +	int ret = 0;
> +	const char *last = "";
> +	struct strbuf valbuf = STRBUF_INIT;
> +	struct strbuf quotbuf = STRBUF_INIT;
> +
> +	QSORT(argv, argc, qsort_strcmp);
> +
> +	for (int i = 0; i < argc; i++) {
> +		get_value_fn *get_value;
> +		const char *key = argv[i];
> +
> +		strbuf_reset(&valbuf);
> +		strbuf_reset("buf);
> +
> +		if (!strcmp(key, last))
> +			continue;
> +
> +		last = key;
> +		get_value = get_value_fn_for_key(key);
> +
> +		if (!get_value) {
> +			ret = error(_("key '%s' not found"), key);
> +			continue;
> +		}
> +
> +		get_value(repo, &valbuf);
> +		quote_c_style(valbuf.buf, "buf, NULL, 0);
> +		printf("%s=%s\n", key, quotbuf.buf);
> +	}
> +
> +	strbuf_release(&valbuf);
> +	strbuf_release("buf);
> +	return ret;
> +}
> +
> +static int repo_info(int argc, const char **argv, const char *prefix UNUSED,
> +		     struct repository *repo)
> +{
> +	return print_fields(argc - 1, argv + 1, repo);
> +}
> +
>   int cmd_repo(int argc, const char **argv, const char *prefix,
>   	     struct repository *repo)
>   {
> diff --git a/t/meson.build b/t/meson.build
> index bbeba1a8d5..252dbbc031 100644
> --- a/t/meson.build
> +++ b/t/meson.build
> @@ -230,6 +230,7 @@ integration_tests = [
>     't1700-split-index.sh',
>     't1701-racy-split-index.sh',
>     't1800-hook.sh',
> +  't1900-repo.sh',
>     't2000-conflict-when-checking-files-out.sh',
>     't2002-checkout-cache-u.sh',
>     't2003-checkout-cache-mkdir.sh',
> diff --git a/t/t1900-repo.sh b/t/t1900-repo.sh
> new file mode 100755
> index 0000000000..2b2516dbae
> --- /dev/null
> +++ b/t/t1900-repo.sh
> @@ -0,0 +1,57 @@
> +#!/bin/sh
> +
> +test_description='test git repo-info'
> +
> +. ./test-lib.sh
> +
> +# Test whether a key-value pair is correctly returned
> +#
> +# Usage: test_repo_info <label> <init command> <key> <expected value>
> +#
> +# Arguments:
> +#   label: the label of the test
> +#   init_command: a command which creates a repository
> +#   repo_name: the name of the repository that will be created in init_command
> +#   key: the key of the field that is being tested
> +#   expected_value: the value that the field should contain
> +test_repo_info () {
> +	label=$1
> +	init_command=$2
> +	repo_name=$3
> +	key=$4
> +	expected_value=$5
> +
> +	test_expect_success "$label" '
> +		eval "$init_command $repo_name" &&
> +		echo "$key=$expected_value" >expected &&
> +		git -C $repo_name repo info "$key" >actual &&
> +		test_cmp expected actual
> +	'
> +}
> +
> +test_repo_info 'ref format files is retrieved correctly' '
> +	git init --ref-format=files' 'format-files' 'references.format' 'files'
> +
> +test_repo_info 'ref format reftable is retrieved correctly' '
> +	git init --ref-format=reftable' 'format-reftable' 'references.format' 'reftable'
> +
> +test_expect_success 'git-repo-info fails if an invalid key is requested' '
> +	echo "error: key ${SQ}foo${SQ} not found" >expected_err &&
> +	test_must_fail git repo info foo 2>actual_err &&
> +	test_cmp expected_err actual_err
> +'
> +
> +test_expect_success 'git-repo-info outputs data even if there is an invalid field' '
> +	echo "references.format=$(test_detect_ref_format)" >expected &&
> +	test_must_fail git repo info foo references.format bar >actual &&
> +	test_cmp expected actual
> +'
> +
> +test_expect_success 'only one value is returned if the same key is requested twice' '
> +	val=$(git rev-parse --show-ref-format) &&
> +	echo "references.format=$val" >expect &&
> +	git repo info references.format references.format >actual &&
> +	test_cmp expect actual
> +'
> +
> +test_done
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v9 2/5] repo: add the field references.format
  2025-08-11 14:41     ` Phillip Wood
@ 2025-08-11 15:44       ` Junio C Hamano
  2025-08-13 21:18       ` Lucas Seiki Oshiro
  1 sibling, 0 replies; 226+ messages in thread
From: Junio C Hamano @ 2025-08-11 15:44 UTC (permalink / raw)
  To: Phillip Wood
  Cc: Lucas Seiki Oshiro, git, oswald.buddenhagen, ps, karthik.188,
	ben.knoble, phillip.wood, jltobler, jn.avila, sunshine
Phillip Wood <phillip.wood123@gmail.com> writes:
> Hi Lucas
>
> On 07/08/2025 16:02, Lucas Seiki Oshiro wrote:
>> ++
>> +The returned data is lexicographically sorted by the keys.
>
> What's the reason for this? If I query three keys from a script then
> it is much easier to parse the output if I know the keys are going to
> appear in the same order that they were on the command line. If the
> command re-orders them my script now has to check the value of each
> key which results in a bunch of unnecessary string comparisons because
> it cannot determine the key from the position in the output. While we
> were producing json output there was a need to de-duplicate the keys
> when that output format was selected. However, we no-longer produce
> json and in any case de-duplication could have been achieved without
> sorting the input keys by using a hash table, or, as there is a small
> fixed number of keys, an array that records the keys we've already
> seen.
Very good.  Thanks.
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v9 2/5] repo: add the field references.format
  2025-08-11 14:41     ` Phillip Wood
  2025-08-11 15:44       ` Junio C Hamano
@ 2025-08-13 21:18       ` Lucas Seiki Oshiro
  2025-08-13 21:46         ` Eric Sunshine
  1 sibling, 1 reply; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-08-13 21:18 UTC (permalink / raw)
  To: phillip.wood
  Cc: git, oswald.buddenhagen, ps, karthik.188, ben.knoble, gitster,
	jltobler, jn.avila, sunshine
> What's the reason for this?
Basically, filter out duplicated keys. This is also helpful for not 
repeating the same "key not found" multiple times, as suggested by 
Eric [1].
I could also use other data structures for doing that, but I think it
would make the code too complex without having a real benefit.
> If I query three keys from a script then it is much easier to parse
> the output if I know the keys are going to appear in the same order
> that they were on the command line.
This assumption would be a little bit broken as one can ask an invalid
key. In this case, this command will print the error to stderr, and
proceed to the next value.
> If the command re-orders them my script now has to check the value of
> each key which results in a bunch of unnecessary string comparisons
> because it cannot determine the key from the position in the output.
In cases where the client don't want to compare strings, it is still
possible to ask one key at time, just like other Git commands (e.g.
git var, git config). Since this command won't return too many values,
it would be ok even if the user requests all the possible keys.
> While we were producing json output there was a need to de-duplicate
> the keys when that output format was selected. However, we no-longer
> produce json and in any case de-duplication could have been achieved
> without sorting the input keys by using a hash table, or, as there is
> a small fixed number of keys, an array that records the keys we've
> already seen.
I still think that it would over-engineer this command. If I follow
this path of returning the values in the same order they were in the
command line, I think it would be better to just allow duplicated keys
and multiple "key not found" errors for the same unknown key instead
of increasing the complexity of this command.
What do you think?
[1] https://lore.kernel.org/git/CAPig+cTxNUPayO2SdCL-BPtjb2rfr3e3RK=BsQxAiiEAtpBaRg@mail.gmail.com/
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v9 2/5] repo: add the field references.format
  2025-08-13 21:18       ` Lucas Seiki Oshiro
@ 2025-08-13 21:46         ` Eric Sunshine
  2025-08-13 22:24           ` Lucas Seiki Oshiro
  2025-08-14 13:58           ` Phillip Wood
  0 siblings, 2 replies; 226+ messages in thread
From: Eric Sunshine @ 2025-08-13 21:46 UTC (permalink / raw)
  To: Lucas Seiki Oshiro
  Cc: phillip.wood, git, oswald.buddenhagen, ps, karthik.188,
	ben.knoble, gitster, jltobler, jn.avila
On Wed, Aug 13, 2025 at 5:18 PM Lucas Seiki Oshiro
<lucasseikioshiro@gmail.com> wrote:
> > What's the reason for this?
>
> Basically, filter out duplicated keys. This is also helpful for not
> repeating the same "key not found" multiple times, as suggested by
> Eric [1].
The suggestion you cite has relevance only as long as deduplication is
the chosen implementation scheme, however, Phillip is arguing that the
deduplication and key reordering logic should be dropped, hence, the
cited reference isn't relevant in light of Phillip's suggestion.
> > If I query three keys from a script then it is much easier to parse
> > the output if I know the keys are going to appear in the same order
> > that they were on the command line.
>
> This assumption would be a little bit broken as one can ask an invalid
> key. In this case, this command will print the error to stderr, and
> proceed to the next value.
Yes and no. While it's true that a caller might ask for an invalid
key, the primary (and useful) purpose of this command is to facilitate
scripting. Once the script author has "debugged" the call to `git
repo`, then the output will be predictable. Hence, although you make a
fair point, it's not a strong argument against Phillip's
recommendation to drop the deduplication and key re-ordering logic.
> > If the command re-orders them my script now has to check the value of
> > each key which results in a bunch of unnecessary string comparisons
> > because it cannot determine the key from the position in the output.
>
> In cases where the client don't want to compare strings, it is still
> possible to ask one key at time, just like other Git commands (e.g.
> git var, git config). Since this command won't return too many values,
> it would be ok even if the user requests all the possible keys.
Generally speaking, process creation is slow. Process creation on
Microsoft Windows is especially slow, excruciatingly so. Authors of
tooling around Git often pay close attention to such matters because
they don't want the functionality provided by their tooling to be
slow, so we ought to be weary of a counterargument (such as the one
above) which suggests simply running the command multiple times, once
for each item.
> > While we were producing json output there was a need to de-duplicate
> > the keys when that output format was selected. However, we no-longer
> > produce json and in any case de-duplication could have been achieved
> > without sorting the input keys by using a hash table, or, as there is
> > a small fixed number of keys, an array that records the keys we've
> > already seen.
>
> I still think that it would over-engineer this command.
I don't think that Phillip was suggesting dropping only the reordering
while keeping the deduplication; he was merely giving an example of an
alternative implementation which would accomplish the deduplication
goal, so he wasn't asking to over-engineer. Instead, (according to my
reading), he is suggesting dropping both deduplication and reordering.
> If I follow
> this path of returning the values in the same order they were in the
> command line, I think it would be better to just allow duplicated keys
> and multiple "key not found" errors for the same unknown key instead
> of increasing the complexity of this command.
>
> What do you think?
I think that's exactly what Phillip was suggesting: present output in
order requested, no deduplication
I had suggested the same back in [*], but I also said that I could
formulate arguments in favor of either behavior, so I didn't have a
strong opinion. However, Phillip has presented a good reason to prefer
"output in order requested, no deduplication", and I do find his
argument compelling.
[*]: https://lore.kernel.org/git/CAPig+cTuiUy=+2Jf1Lrp1gaM03_zPf8EFMVSKmShqU05t-3aWQ@mail.gmail.com/
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v9 2/5] repo: add the field references.format
  2025-08-13 21:46         ` Eric Sunshine
@ 2025-08-13 22:24           ` Lucas Seiki Oshiro
  2025-08-14 13:58           ` Phillip Wood
  1 sibling, 0 replies; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-08-13 22:24 UTC (permalink / raw)
  To: Eric Sunshine
  Cc: phillip.wood, git, oswald.buddenhagen, ps, karthik.188,
	ben.knoble, gitster, jltobler, jn.avila
> The suggestion you cite has relevance only as long as deduplication is
> the chosen implementation scheme, however, Phillip is arguing that the
> deduplication and key reordering logic should be dropped, hence, the
> cited reference isn't relevant in light of Phillip's suggestion.
Ok!
> However, Phillip has presented a good reason to prefer
> "output in order requested, no deduplication", and I do find his
> argument compelling.
I'll do that! Thanks!
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v9 2/5] repo: add the field references.format
  2025-08-13 21:46         ` Eric Sunshine
  2025-08-13 22:24           ` Lucas Seiki Oshiro
@ 2025-08-14 13:58           ` Phillip Wood
  1 sibling, 0 replies; 226+ messages in thread
From: Phillip Wood @ 2025-08-14 13:58 UTC (permalink / raw)
  To: Eric Sunshine, Lucas Seiki Oshiro
  Cc: phillip.wood, git, oswald.buddenhagen, ps, karthik.188,
	ben.knoble, gitster, jltobler, jn.avila
On 13/08/2025 22:46, Eric Sunshine wrote:
> On Wed, Aug 13, 2025 at 5:18 PM Lucas Seiki Oshiro
> <lucasseikioshiro@gmail.com> wrote:
> 
> I don't think that Phillip was suggesting dropping only the reordering
> while keeping the deduplication; he was merely giving an example of an
> alternative implementation which would accomplish the deduplication
> goal, so he wasn't asking to over-engineer. Instead, (according to my
> reading), he is suggesting dropping both deduplication and reordering.
Exactly
>> If I follow
>> this path of returning the values in the same order they were in the
>> command line, I think it would be better to just allow duplicated keys
>> and multiple "key not found" errors for the same unknown key instead
>> of increasing the complexity of this command.
>>
>> What do you think?
> 
> I think that's exactly what Phillip was suggesting: present output in
> order requested, no deduplication
> 
> I had suggested the same back in [*], but I also said that I could
> formulate arguments in favor of either behavior, so I didn't have a
> strong opinion. However, Phillip has presented a good reason to prefer
> "output in order requested, no deduplication", and I do find his
> argument compelling.
If this command was producing output primarily for human consumption 
then I think the argument for sorting and de-duplicating the output 
would be much stronger. However, as this command is intended to replace 
some uses of "git rev-parse" in scripts, I think that "output in order 
requested, no de-duplication" is more convenient.
Thanks
Phillip
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v9 3/5] repo: add the field layout.bare
  2025-08-11  5:21     ` Eric Sunshine
@ 2025-08-14 18:22       ` Lucas Seiki Oshiro
  2025-08-14 18:32         ` Eric Sunshine
  0 siblings, 1 reply; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-08-14 18:22 UTC (permalink / raw)
  To: Eric Sunshine
  Cc: git, oswald.buddenhagen, ps, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler, jn.avila
> Since the documentation asserts that the emitted key/value lines will
> be sorted lexicographically, can we also have a test that verifies
> that behavior?
Since we agreed to return the values in the order they were requested,
I'll test that order instead:
test_expect_success 'the values are returned in the same order they were requested' '
	printf "references.format=files\nlayout.bare=false\n" >expected1 &&
	printf "layout.bare=false\nreferences.format=files\n" >expected2 &&
	git init --ref-format=files same-order &&
	git -C same-order repo info references.format layout.bare >actual1 &&
	git -C same-order repo info layout.bare references.format >actual2 &&
	test_cmp expected1 actual1 &&
	test_cmp expected2 actual2
'
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v9 3/5] repo: add the field layout.bare
  2025-08-14 18:22       ` Lucas Seiki Oshiro
@ 2025-08-14 18:32         ` Eric Sunshine
  2025-08-14 18:51           ` Junio C Hamano
  0 siblings, 1 reply; 226+ messages in thread
From: Eric Sunshine @ 2025-08-14 18:32 UTC (permalink / raw)
  To: Lucas Seiki Oshiro
  Cc: git, oswald.buddenhagen, ps, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler, jn.avila
On Thu, Aug 14, 2025 at 2:23 PM Lucas Seiki Oshiro
<lucasseikioshiro@gmail.com> wrote:
> > Since the documentation asserts that the emitted key/value lines will
> > be sorted lexicographically, can we also have a test that verifies
> > that behavior?
>
> Since we agreed to return the values in the order they were requested,
> I'll test that order instead:
Yep, sounds good.
> test_expect_success 'the values are returned in the same order they were requested' '
>         printf "references.format=files\nlayout.bare=false\n" >expected1 &&
>         printf "layout.bare=false\nreferences.format=files\n" >expected2 &&
>         git init --ref-format=files same-order &&
>         git -C same-order repo info references.format layout.bare >actual1 &&
>         git -C same-order repo info layout.bare references.format >actual2 &&
>         test_cmp expected1 actual1 &&
>         test_cmp expected2 actual2
> '
Rather than the above, I think a more satisfactory and meaningful test would be:
    test_expect_success 'values returned in order requested' '
        cat >expect <<-\EOF &&
        layout.bare=false
        references.format=files
        layout.bare=false
        EOF
        git init --ref-format=files ordered &&
        git -C ordered repo info layout.bare references.format
layout.bare >actual &&
        test_cmp expect actual
    '
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v9 3/5] repo: add the field layout.bare
  2025-08-14 18:32         ` Eric Sunshine
@ 2025-08-14 18:51           ` Junio C Hamano
  2025-08-14 22:05             ` Eric Sunshine
  2025-08-14 22:18             ` Lucas Seiki Oshiro
  0 siblings, 2 replies; 226+ messages in thread
From: Junio C Hamano @ 2025-08-14 18:51 UTC (permalink / raw)
  To: Eric Sunshine
  Cc: Lucas Seiki Oshiro, git, oswald.buddenhagen, ps, karthik.188,
	ben.knoble, phillip.wood, jltobler, jn.avila
Eric Sunshine <sunshine@sunshineco.com> writes:
>> test_expect_success 'the values are returned in the same order they were requested' '
>>         printf "references.format=files\nlayout.bare=false\n" >expected1 &&
>>         printf "layout.bare=false\nreferences.format=files\n" >expected2 &&
>>         git init --ref-format=files same-order &&
>>         git -C same-order repo info references.format layout.bare >actual1 &&
>>         git -C same-order repo info layout.bare references.format >actual2 &&
>>         test_cmp expected1 actual1 &&
>>         test_cmp expected2 actual2
>> '
>
> Rather than the above, I think a more satisfactory and meaningful test would be:
>
>     test_expect_success 'values returned in order requested' '
>         cat >expect <<-\EOF &&
>         layout.bare=false
>         references.format=files
>         layout.bare=false
>         EOF
>         git init --ref-format=files ordered &&
>         git -C ordered repo info layout.bare references.format
> layout.bare >actual &&
>         test_cmp expect actual
>     '
I do not think the second "layout.bare" should be line-wrapped.
Your point that it is more obvious when the expectations are shown
in HERE-doc may be valid.  Overly long printf with \n indeed is
harder to follow.  Even though there is no reason for a real user to
do so, asking for the same piece of information twice would
demonstrate that there is no deduplication.
I also care about future-proofing, though.  When Git is built with
WITH_BREAKING_CHANGES=YesPlease, this test would break as the
default reference backend will be reftable in that alternate world,
wouldn't it?
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v9 3/5] repo: add the field layout.bare
  2025-08-14 18:51           ` Junio C Hamano
@ 2025-08-14 22:05             ` Eric Sunshine
  2025-08-15  1:20               ` Junio C Hamano
  2025-08-14 22:18             ` Lucas Seiki Oshiro
  1 sibling, 1 reply; 226+ messages in thread
From: Eric Sunshine @ 2025-08-14 22:05 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Lucas Seiki Oshiro, git, oswald.buddenhagen, ps, karthik.188,
	ben.knoble, phillip.wood, jltobler, jn.avila
On Thu, Aug 14, 2025 at 2:51 PM Junio C Hamano <gitster@pobox.com> wrote:
> Eric Sunshine <sunshine@sunshineco.com> writes:
> > Rather than the above, I think a more satisfactory and meaningful test would be:
> >
> >     test_expect_success 'values returned in order requested' '
> >         cat >expect <<-\EOF &&
> >         layout.bare=false
> >         references.format=files
> >         layout.bare=false
> >         EOF
> >         git init --ref-format=files ordered &&
> >         git -C ordered repo info layout.bare references.format
> > layout.bare >actual &&
> >         test_cmp expect actual
> >     '
>
> I do not think the second "layout.bare" should be line-wrapped.
I typed that command all one one line; Gmail wrapped the line.
> Your point that it is more obvious when the expectations are shown
> in HERE-doc may be valid.  Overly long printf with \n indeed is
> harder to follow.  Even though there is no reason for a real user to
> do so, asking for the same piece of information twice would
> demonstrate that there is no deduplication.
Yes, part of the point of the illustrated test was indeed to
demonstrate lack of deduplication.
By the way, as a real-world developer/user, I do periodically find
myself in situations in which it *is* convenient to ask for the same
piece of information twice (or thrice) because it simplifies
downstream scripting in ad hoc (and not so ad hoc) situations when I
need to manipulate the same value in different ways. In such cases,
asking for the information more than once saves me the trouble of
having to assign the value to a variable, which is handy when the
downstream language or tool doesn't provide variables.
> I also care about future-proofing, though.  When Git is built with
> WITH_BREAKING_CHANGES=YesPlease, this test would break as the
> default reference backend will be reftable in that alternate world,
> wouldn't it?
I think Lucas already future-proofed this (and my example copied his
future-proofing) by using `--ref-format=files` with the git-init
invocation.
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v9 3/5] repo: add the field layout.bare
  2025-08-14 18:51           ` Junio C Hamano
  2025-08-14 22:05             ` Eric Sunshine
@ 2025-08-14 22:18             ` Lucas Seiki Oshiro
  2025-08-14 23:41               ` Eric Sunshine
  1 sibling, 1 reply; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-08-14 22:18 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Eric Sunshine, git, oswald.buddenhagen, ps, karthik.188,
	ben.knoble, phillip.wood, jltobler, jn.avila
> I also care about future-proofing, though.  When Git is built with
> WITH_BREAKING_CHANGES=YesPlease, this test would break as the
> default reference backend will be reftable in that alternate world,
> wouldn't it?
To be honest, it wouldn't matter what are the keys selected for
testing this behavior. I'm only using references.format because it
was the first that I implemented. But given that, I can also change
their order to something like:
[1/5] repo: declare the repo command
[2/5] repo: add the field layout.bare
[3/5] repo: add the field layout.shallow
[2/5] repo: add the field references.format
[5/5] repo: add the --format flag
This way, this tests could be placed in 3/5 and using layout.bare and
layout.shallow as keys.
Thanks!
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v9 3/5] repo: add the field layout.bare
  2025-08-14 22:18             ` Lucas Seiki Oshiro
@ 2025-08-14 23:41               ` Eric Sunshine
  0 siblings, 0 replies; 226+ messages in thread
From: Eric Sunshine @ 2025-08-14 23:41 UTC (permalink / raw)
  To: Lucas Seiki Oshiro
  Cc: Junio C Hamano, git, oswald.buddenhagen, ps, karthik.188,
	ben.knoble, phillip.wood, jltobler, jn.avila
On Thu, Aug 14, 2025 at 6:18 PM Lucas Seiki Oshiro
<lucasseikioshiro@gmail.com> wrote:
> > I also care about future-proofing, though.  When Git is built with
> > WITH_BREAKING_CHANGES=YesPlease, this test would break as the
> > default reference backend will be reftable in that alternate world,
> > wouldn't it?
>
> To be honest, it wouldn't matter what are the keys selected for
> testing this behavior. I'm only using references.format because it
> was the first that I implemented. But given that, I can also change
> their order to something like:
>
> [1/5] repo: declare the repo command
> [2/5] repo: add the field layout.bare
> [3/5] repo: add the field layout.shallow
> [2/5] repo: add the field references.format
> [5/5] repo: add the --format flag
>
> This way, this tests could be placed in 3/5 and using layout.bare and
> layout.shallow as keys.
I don't have a strong preference since I think you already
future-proofed the test by using `--ref-format=files` with the
git-init
invocation, but the above suggested patch order would work, as well,
and seems sufficiently reviewer-friendly.
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v9 3/5] repo: add the field layout.bare
  2025-08-14 22:05             ` Eric Sunshine
@ 2025-08-15  1:20               ` Junio C Hamano
  0 siblings, 0 replies; 226+ messages in thread
From: Junio C Hamano @ 2025-08-15  1:20 UTC (permalink / raw)
  To: Eric Sunshine
  Cc: Lucas Seiki Oshiro, git, oswald.buddenhagen, ps, karthik.188,
	ben.knoble, phillip.wood, jltobler, jn.avila
Eric Sunshine <sunshine@sunshineco.com> writes:
>> I also care about future-proofing, though.  When Git is built with
>> WITH_BREAKING_CHANGES=YesPlease, this test would break as the
>> default reference backend will be reftable in that alternate world,
>> wouldn't it?
>
> I think Lucas already future-proofed this (and my example copied his
> future-proofing) by using `--ref-format=files` with the git-init
> invocation.
Ah, OK, if we are forcing a specific format, then we are already
future-proofed, especially when the format is something that will be
with us forever, like the files backend.
Thanks.
^ permalink raw reply	[flat|nested] 226+ messages in thread
* [GSoC PATCH v10 0/5] repo: declare the repo command
  2025-06-10 15:21 [GSoC RFC PATCH 0/5] repo-info: add new command for retrieving repository info Lucas Seiki Oshiro
                   ` (15 preceding siblings ...)
  2025-08-07 15:02 ` [GSoC PATCH v9 " Lucas Seiki Oshiro
@ 2025-08-15 13:55 ` Lucas Seiki Oshiro
  2025-08-15 13:55   ` [GSoC PATCH v10 1/5] " Lucas Seiki Oshiro
                     ` (4 more replies)
  2025-08-16 22:45 ` [GSoC PATCH v11 0/5] repo: declare the repo command Lucas Seiki Oshiro
  17 siblings, 5 replies; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-08-15 13:55 UTC (permalink / raw)
  To: git
  Cc: oswald.buddenhagen, ps, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler, jn.avila, sunshine, Lucas Seiki Oshiro
Hi!
The only major change in this v10 is that git-repo-info now returns the
values following the same order as they were requested instead of
sorting the keys. In past versions, the sorting existed for dropping
duplicated keys, but after the discussion with Eric, Phillip and Junio,
we agreed that returning the values following the keys order was more
important than removing the duplications, which weren't exactly a bad
thing. Consequently, the duplication checks were also removed.
Other minor issues pointed by Eric were also addressed.
Thanks!
Here's the range-diff versus v9:
1:  3c2ede66be = 1:  6767028da3 repo: declare the repo command
2:  b18e74763d ! 2:  c44e2d1619 repo: add the field references.format
    @@ Documentation/git-repo.adoc: COMMANDS
      	the requested data will be returned based on their keys (see "INFO KEYS"
      	section below).
     ++
    -+The returned data is lexicographically sorted by the keys.
    ++The values are returned in the same order in which their respective keys were
    ++requested.
     ++
     +The output format consists of key-value pairs one per line using the `=`
     +character as the delimiter between the key and the value. Values containing
     +"unusual" characters are quoted as explained for the configuration variable
    -+`core.quotePath` (see linkgit:git-config[1]). This is the default.
    ++`core.quotePath` (see linkgit:git-config[1]).
     +
     +INFO KEYS
     +---------
    @@ builtin/repo.c
      	return 0;
      }
      
    -+/* repo_info_fields keys should be in lexicographical order */
    ++/* repo_info_fields keys must be in lexicographical order */
     +static const struct field repo_info_fields[] = {
     +	{ "references.format", get_references_format },
     +};
    @@ builtin/repo.c
     +	return found ? found->get_value : NULL;
     +}
     +
    -+static int qsort_strcmp(const void *va, const void *vb)
    -+{
    -+	const char *a = *(const char **)va;
    -+	const char *b = *(const char **)vb;
    -+
    -+	return strcmp(a, b);
    -+}
    -+
     +static int print_fields(int argc, const char **argv, struct repository *repo)
     +{
     +	int ret = 0;
    -+	const char *last = "";
     +	struct strbuf valbuf = STRBUF_INIT;
     +	struct strbuf quotbuf = STRBUF_INIT;
     +
    -+	QSORT(argv, argc, qsort_strcmp);
    -+
     +	for (int i = 0; i < argc; i++) {
     +		get_value_fn *get_value;
     +		const char *key = argv[i];
     +
    -+		strbuf_reset(&valbuf);
    -+		strbuf_reset("buf);
    -+
    -+		if (!strcmp(key, last))
    -+			continue;
    -+
    -+		last = key;
     +		get_value = get_value_fn_for_key(key);
     +
     +		if (!get_value) {
    @@ builtin/repo.c
     +			continue;
     +		}
     +
    ++		strbuf_reset(&valbuf);
    ++		strbuf_reset("buf);
    ++
     +		get_value(repo, &valbuf);
     +		quote_c_style(valbuf.buf, "buf, NULL, 0);
     +		printf("%s=%s\n", key, quotbuf.buf);
    @@ t/t1900-repo.sh (new)
     +
     +# Test whether a key-value pair is correctly returned
     +#
    -+# Usage: test_repo_info <label> <init command> <key> <expected value>
    ++# Usage: test_repo_info <label> <init command> <repo_name> <key> <expected value>
     +#
     +# Arguments:
     +#   label: the label of the test
    @@ t/t1900-repo.sh (new)
     +	'
     +}
     +
    -+test_repo_info 'ref format files is retrieved correctly' '
    -+	git init --ref-format=files' 'format-files' 'references.format' 'files'
    ++test_repo_info 'ref format files is retrieved correctly' \
    ++	'git init --ref-format=files' 'format-files' 'references.format' 'files'
     +
    -+test_repo_info 'ref format reftable is retrieved correctly' '
    -+	git init --ref-format=reftable' 'format-reftable' 'references.format' 'reftable'
    ++test_repo_info 'ref format reftable is retrieved correctly' \
    ++	'git init --ref-format=reftable' 'format-reftable' 'references.format' 'reftable'
     +
     +test_expect_success 'git-repo-info fails if an invalid key is requested' '
     +	echo "error: key ${SQ}foo${SQ} not found" >expected_err &&
    @@ t/t1900-repo.sh (new)
     +	test_cmp expected actual
     +'
     +
    -+test_expect_success 'only one value is returned if the same key is requested twice' '
    -+	val=$(git rev-parse --show-ref-format) &&
    -+	echo "references.format=$val" >expect &&
    -+	git repo info references.format references.format >actual &&
    -+	test_cmp expect actual
    -+'
    -+
     +test_done
3:  35916b210e ! 3:  e3009a85e1 repo: add the field layout.bare
    @@ builtin/repo.c: struct field {
      	strbuf_addstr(buf,
     @@ builtin/repo.c: static int get_references_format(struct repository *repo, struct strbuf *buf)
      
    - /* repo_info_fields keys should be in lexicographical order */
    + /* repo_info_fields keys must be in lexicographical order */
      static const struct field repo_info_fields[] = {
     +	{ "layout.bare", get_layout_bare },
      	{ "references.format", get_references_format },
    @@ builtin/repo.c: static int get_references_format(struct repository *repo, struct
      
     
      ## t/t1900-repo.sh ##
    -@@ t/t1900-repo.sh: test_repo_info 'ref format files is retrieved correctly' '
    - test_repo_info 'ref format reftable is retrieved correctly' '
    - 	git init --ref-format=reftable' 'format-reftable' 'references.format' 'reftable'
    +@@ t/t1900-repo.sh: test_repo_info 'ref format files is retrieved correctly' \
    + test_repo_info 'ref format reftable is retrieved correctly' \
    + 	'git init --ref-format=reftable' 'format-reftable' 'references.format' 'reftable'
      
     +test_repo_info 'bare repository = false is retrieved correctly' \
     +	'git init' 'nonbare' 'layout.bare' 'false'
    @@ t/t1900-repo.sh: test_repo_info 'ref format files is retrieved correctly' '
     +test_repo_info 'bare repository = true is retrieved correctly' \
     +	'git init --bare' 'bare' 'layout.bare' 'true'
     +
    - test_expect_success 'git-repo-info fails if an invalid key is requested' '
    - 	echo "error: key ${SQ}foo${SQ} not found" >expected_err &&
    - 	test_must_fail git repo info foo 2>actual_err &&
    -@@ t/t1900-repo.sh: test_expect_success 'only one value is returned if the same key is requested twi
    - 	test_cmp expect actual
    - '
    - 
    -+test_expect_success 'output is returned correctly when two keys are requested' '
    -+	cat >expected <<-\EOF &&
    ++test_expect_success 'values returned in order requested' '
    ++	cat >expect <<-\EOF &&
     +	layout.bare=false
     +	references.format=files
    ++	layout.bare=false
     +	EOF
    -+	git init --ref-format=files two-keys &&
    -+	git -C two-keys repo info layout.bare references.format >actual &&
    -+	test_cmp expected actual
    ++	git init --ref-format=files ordered &&
    ++	git -C ordered repo info layout.bare references.format layout.bare >actual &&
    ++	test_cmp expect actual
     +'
     +
    - test_done
    + test_expect_success 'git-repo-info fails if an invalid key is requested' '
    + 	echo "error: key ${SQ}foo${SQ} not found" >expected_err &&
    + 	test_must_fail git repo info foo 2>actual_err &&
4:  91fc5c4e50 ! 4:  3837899c32 repo: add the field layout.shallow
    @@ builtin/repo.c: static int get_layout_bare(struct repository *repo UNUSED, struc
      {
      	strbuf_addstr(buf,
     @@ builtin/repo.c: static int get_references_format(struct repository *repo, struct strbuf *buf)
    - /* repo_info_fields keys should be in lexicographical order */
    + /* repo_info_fields keys must be in lexicographical order */
      static const struct field repo_info_fields[] = {
      	{ "layout.bare", get_layout_bare },
     +	{ "layout.shallow", get_layout_shallow },
    @@ t/t1900-repo.sh: test_repo_info 'bare repository = false is retrieved correctly'
     +test_repo_info 'shallow repository = false is retrieved correctly' \
     +	'git init' 'nonshallow' 'layout.shallow' 'false'
     +
    -+test_repo_info 'shallow repository = true is retrieved correctly' \
    -+	'git init remote &&
    ++test_expect_success 'setup remote' '
    ++	git init remote &&
     +	echo x >remote/x &&
     +	git -C remote add x &&
    -+	git -C remote commit -m x &&
    -+	git clone --depth 1 "file://$PWD/remote"' 'shallow' 'layout.shallow' 'true'
    ++	git -C remote commit -m x
    ++'
    ++
    ++test_repo_info 'shallow repository = true is retrieved correctly' \
    ++	'git clone --depth 1 "file://$PWD/remote"' 'shallow' 'layout.shallow' 'true'
     +
    - test_expect_success 'git-repo-info fails if an invalid key is requested' '
    - 	echo "error: key ${SQ}foo${SQ} not found" >expected_err &&
    - 	test_must_fail git repo info foo 2>actual_err &&
    + test_expect_success 'values returned in order requested' '
    + 	cat >expect <<-\EOF &&
    + 	layout.bare=false
5:  8af32d7066 ! 5:  19fdfce646 repo: add the --format flag
    @@ Documentation/git-repo.adoc: THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOR MAY CHAN
      	Retrieve metadata-related information about the current repository. Only
      	the requested data will be returned based on their keys (see "INFO KEYS"
      	section below).
    - +
    - The returned data is lexicographically sorted by the keys.
    +@@ Documentation/git-repo.adoc: COMMANDS
    + The values are returned in the same order in which their respective keys were
    + requested.
      +
     -The output format consists of key-value pairs one per line using the `=`
     -character as the delimiter between the key and the value. Values containing
     -"unusual" characters are quoted as explained for the configuration variable
    +-`core.quotePath` (see linkgit:git-config[1]).
     +The output format can be chosen through the flag `--format`. Two formats are
     +supported:
     ++
     +* `keyvalue`: output key-value pairs one per line using the `=` character as
     +the delimiter between the key and the value. Values containing "unusual"
     +characters are quoted as explained for the configuration variable
    - `core.quotePath` (see linkgit:git-config[1]). This is the default.
    - 
    ++`core.quotePath` (see linkgit:git-config[1]). This is the default.
    ++
     +* `nul`: similar to `keyvalue`, but using a newline character as the delimiter
     +between the key and the value and using a null character after each value.
     +This format is better suited for being parsed by another applications than
     +`keyvalue`. Unlike in the `keyvalue` format, the values are never quoted.
    -+
    + 
      INFO KEYS
      ---------
     -
    @@ builtin/repo.c
      struct field {
      	const char *key;
      	get_value_fn *get_value;
    -@@ builtin/repo.c: static int qsort_strcmp(const void *va, const void *vb)
    - 	return strcmp(a, b);
    +@@ builtin/repo.c: static get_value_fn *get_value_fn_for_key(const char *key)
    + 	return found ? found->get_value : NULL;
      }
      
     -static int print_fields(int argc, const char **argv, struct repository *repo)
    @@ builtin/repo.c: static int qsort_strcmp(const void *va, const void *vb)
     +			enum output_format format)
      {
      	int ret = 0;
    - 	const char *last = "";
    + 	struct strbuf valbuf = STRBUF_INIT;
     @@ builtin/repo.c: static int print_fields(int argc, const char **argv, struct repository *repo)
    - 		}
    + 		strbuf_reset("buf);
      
      		get_value(repo, &valbuf);
     -		quote_c_style(valbuf.buf, "buf, NULL, 0);
    @@ t/t1900-repo.sh: test_repo_info () {
     +	'
      }
      
    - test_repo_info 'ref format files is retrieved correctly' '
    -@@ t/t1900-repo.sh: test_repo_info 'bare repository = true is retrieved correctly' \
    - test_repo_info 'shallow repository = false is retrieved correctly' \
    - 	'git init' 'nonshallow' 'layout.shallow' 'false'
    - 
    --test_repo_info 'shallow repository = true is retrieved correctly' \
    --	'git init remote &&
    -+test_expect_success 'setup remote' '
    -+	git init remote &&
    - 	echo x >remote/x &&
    - 	git -C remote add x &&
    --	git -C remote commit -m x &&
    --	git clone --depth 1 "file://$PWD/remote"' 'shallow' 'layout.shallow' 'true'
    -+	git -C remote commit -m x
    -+'
    -+
    -+test_repo_info 'shallow repository = true is retrieved correctly' \
    -+	'git clone --depth 1 "file://$PWD/remote"' 'shallow' 'layout.shallow' 'true'
    - 
    - test_expect_success 'git-repo-info fails if an invalid key is requested' '
    - 	echo "error: key ${SQ}foo${SQ} not found" >expected_err &&
    -@@ t/t1900-repo.sh: test_expect_success 'output is returned correctly when two keys are requested' '
    + test_repo_info 'ref format files is retrieved correctly' \
    +@@ t/t1900-repo.sh: test_expect_success 'git-repo-info outputs data even if there is an invalid fiel
      	test_cmp expected actual
      '
      
     +test_expect_success 'git-repo-info aborts when requesting an invalid format' '
    -+	echo "fatal: invalid format '\'foo\''" >expected &&
    ++	echo "fatal: invalid format ${SQ}foo${SQ}" >expected &&
     +	test_must_fail git repo info --format=foo 2>err &&
     +	test_cmp expected err
     +'
Lucas Seiki Oshiro (5):
  repo: declare the repo command
  repo: add the field references.format
  repo: add the field layout.bare
  repo: add the field layout.shallow
  repo: add the --format flag
 .gitignore                  |   1 +
 Documentation/git-repo.adoc |  82 ++++++++++++++++++++
 Documentation/meson.build   |   1 +
 Makefile                    |   1 +
 builtin.h                   |   1 +
 builtin/repo.c              | 150 ++++++++++++++++++++++++++++++++++++
 command-list.txt            |   1 +
 git.c                       |   1 +
 meson.build                 |   1 +
 t/meson.build               |   1 +
 t/t1900-repo.sh             |  96 +++++++++++++++++++++++
 11 files changed, 336 insertions(+)
 create mode 100644 Documentation/git-repo.adoc
 create mode 100644 builtin/repo.c
 create mode 100755 t/t1900-repo.sh
-- 
2.39.5 (Apple Git-154)
^ permalink raw reply	[flat|nested] 226+ messages in thread
* [GSoC PATCH v10 1/5] repo: declare the repo command
  2025-08-15 13:55 ` [GSoC PATCH v10 0/5] repo: declare the repo command Lucas Seiki Oshiro
@ 2025-08-15 13:55   ` Lucas Seiki Oshiro
  2025-08-15 13:55   ` [GSoC PATCH v10 2/5] repo: add the field references.format Lucas Seiki Oshiro
                     ` (3 subsequent siblings)
  4 siblings, 0 replies; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-08-15 13:55 UTC (permalink / raw)
  To: git
  Cc: oswald.buddenhagen, ps, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler, jn.avila, sunshine, Lucas Seiki Oshiro
Currently, `git rev-parse` covers a wide range of functionality not
directly related to parsing revisions, as its name suggests. Over time,
many features like parsing datestrings, options, paths, and others
were added to it because there wasn't a more appropriate command
to place them.
Create a new Git command called `repo`. `git repo` will be the main
command for obtaining the information about a repository (such as
metadata and metrics).
Also declare a subcommand for `repo` called `info`. `git repo info`
will bring the functionality of retrieving repository-related
information currently returned by `rev-parse`.
Add the required documentation and build changes to enable usage of
this subcommand.
Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Helped-by: Junio C Hamano <gitster@pobox.com>
Helped-by: Justin Tobler <jltobler@gmail.com>
Helped-by: Eric Sunshine <sunshine@sunshineco.com>
Mentored-by: Karthik Nayak <karthik.188@gmail.com>
Mentored-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
---
 .gitignore                  |  1 +
 Documentation/git-repo.adoc | 32 ++++++++++++++++++++++++++++++++
 Documentation/meson.build   |  1 +
 Makefile                    |  1 +
 builtin.h                   |  1 +
 builtin/repo.c              | 27 +++++++++++++++++++++++++++
 command-list.txt            |  1 +
 git.c                       |  1 +
 meson.build                 |  1 +
 9 files changed, 66 insertions(+)
 create mode 100644 Documentation/git-repo.adoc
 create mode 100644 builtin/repo.c
diff --git a/.gitignore b/.gitignore
index 04c444404e..1803023427 100644
--- a/.gitignore
+++ b/.gitignore
@@ -139,6 +139,7 @@
 /git-repack
 /git-replace
 /git-replay
+/git-repo
 /git-request-pull
 /git-rerere
 /git-reset
diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc
new file mode 100644
index 0000000000..68c706f5a0
--- /dev/null
+++ b/Documentation/git-repo.adoc
@@ -0,0 +1,32 @@
+git-repo(1)
+===========
+
+NAME
+----
+git-repo - Retrieve information about the repository
+
+SYNOPSIS
+--------
+[synopsis]
+git repo info [<key>...]
+
+DESCRIPTION
+-----------
+Retrieve information about the repository.
+
+THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOR MAY CHANGE.
+
+COMMANDS
+--------
+`info [<key>...]`::
+	Retrieve metadata-related information about the current repository. Only
+	the requested data will be returned based on their keys (see "INFO KEYS"
+	section below).
+
+SEE ALSO
+--------
+linkgit:git-rev-parse[1]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/meson.build b/Documentation/meson.build
index 4404c623f0..41f43e0336 100644
--- a/Documentation/meson.build
+++ b/Documentation/meson.build
@@ -116,6 +116,7 @@ manpages = {
   'git-repack.adoc' : 1,
   'git-replace.adoc' : 1,
   'git-replay.adoc' : 1,
+  'git-repo.adoc' : 1,
   'git-request-pull.adoc' : 1,
   'git-rerere.adoc' : 1,
   'git-reset.adoc' : 1,
diff --git a/Makefile b/Makefile
index e11340c1ae..ec7ac58980 100644
--- a/Makefile
+++ b/Makefile
@@ -1306,6 +1306,7 @@ BUILTIN_OBJS += builtin/remote.o
 BUILTIN_OBJS += builtin/repack.o
 BUILTIN_OBJS += builtin/replace.o
 BUILTIN_OBJS += builtin/replay.o
+BUILTIN_OBJS += builtin/repo.o
 BUILTIN_OBJS += builtin/rerere.o
 BUILTIN_OBJS += builtin/reset.o
 BUILTIN_OBJS += builtin/rev-list.o
diff --git a/builtin.h b/builtin.h
index bff13e3069..e6458e6fb9 100644
--- a/builtin.h
+++ b/builtin.h
@@ -216,6 +216,7 @@ int cmd_remote_ext(int argc, const char **argv, const char *prefix, struct repos
 int cmd_remote_fd(int argc, const char **argv, const char *prefix, struct repository *repo);
 int cmd_repack(int argc, const char **argv, const char *prefix, struct repository *repo);
 int cmd_replay(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_repo(int argc, const char **argv, const char *prefix, struct repository *repo);
 int cmd_rerere(int argc, const char **argv, const char *prefix, struct repository *repo);
 int cmd_reset(int argc, const char **argv, const char *prefix, struct repository *repo);
 int cmd_restore(int argc, const char **argv, const char *prefix, struct repository *repo);
diff --git a/builtin/repo.c b/builtin/repo.c
new file mode 100644
index 0000000000..fd2a9b4216
--- /dev/null
+++ b/builtin/repo.c
@@ -0,0 +1,27 @@
+#include "builtin.h"
+#include "parse-options.h"
+
+static const char *const repo_usage[] = {
+	"git repo info [<key>...]",
+	NULL
+};
+
+static int repo_info(int argc UNUSED, const char **argv UNUSED,
+		     const char *prefix UNUSED, struct repository *repo UNUSED)
+{
+	return 0;
+}
+
+int cmd_repo(int argc, const char **argv, const char *prefix,
+	     struct repository *repo)
+{
+	parse_opt_subcommand_fn *fn = NULL;
+	struct option options[] = {
+		OPT_SUBCOMMAND("info", &fn, repo_info),
+		OPT_END()
+	};
+
+	argc = parse_options(argc, argv, prefix, options, repo_usage, 0);
+
+	return fn(argc, argv, prefix, repo);
+}
diff --git a/command-list.txt b/command-list.txt
index b7ade3ab9f..1b0bdee00d 100644
--- a/command-list.txt
+++ b/command-list.txt
@@ -164,6 +164,7 @@ git-remote                              ancillarymanipulators           complete
 git-repack                              ancillarymanipulators           complete
 git-replace                             ancillarymanipulators           complete
 git-replay                              plumbingmanipulators
+git-repo                                plumbinginterrogators
 git-request-pull                        foreignscminterface             complete
 git-rerere                              ancillaryinterrogators
 git-reset                               mainporcelain           history
diff --git a/git.c b/git.c
index 83eac0aeab..d4ff4d5517 100644
--- a/git.c
+++ b/git.c
@@ -611,6 +611,7 @@ static struct cmd_struct commands[] = {
 	{ "repack", cmd_repack, RUN_SETUP },
 	{ "replace", cmd_replace, RUN_SETUP },
 	{ "replay", cmd_replay, RUN_SETUP },
+	{ "repo", cmd_repo, RUN_SETUP },
 	{ "rerere", cmd_rerere, RUN_SETUP },
 	{ "reset", cmd_reset, RUN_SETUP },
 	{ "restore", cmd_restore, RUN_SETUP | NEED_WORK_TREE },
diff --git a/meson.build b/meson.build
index 5dd299b496..e8ec0eca16 100644
--- a/meson.build
+++ b/meson.build
@@ -645,6 +645,7 @@ builtin_sources = [
   'builtin/repack.c',
   'builtin/replace.c',
   'builtin/replay.c',
+  'builtin/repo.c',
   'builtin/rerere.c',
   'builtin/reset.c',
   'builtin/rev-list.c',
-- 
2.39.5 (Apple Git-154)
^ permalink raw reply related	[flat|nested] 226+ messages in thread
* [GSoC PATCH v10 2/5] repo: add the field references.format
  2025-08-15 13:55 ` [GSoC PATCH v10 0/5] repo: declare the repo command Lucas Seiki Oshiro
  2025-08-15 13:55   ` [GSoC PATCH v10 1/5] " Lucas Seiki Oshiro
@ 2025-08-15 13:55   ` Lucas Seiki Oshiro
  2025-08-15 18:40     ` Junio C Hamano
  2025-08-15 13:55   ` [GSoC PATCH v10 3/5] repo: add the field layout.bare Lucas Seiki Oshiro
                     ` (2 subsequent siblings)
  4 siblings, 1 reply; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-08-15 13:55 UTC (permalink / raw)
  To: git
  Cc: oswald.buddenhagen, ps, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler, jn.avila, sunshine, Lucas Seiki Oshiro
This commit is part of the series that introduces the new subcommand
git-repo-info.
The flag `--show-ref-format` from git-rev-parse is used for retrieving
the reference format (i.e. `files` or `reftable`). This way, it is
used for querying repository metadata, fitting in the purpose of
git-repo-info.
Add a new field `references.format` to the repo-info subcommand
containing that information.
Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Helped-by: Junio C Hamano <gitster@pobox.com>
Helped-by: Justin Tobler <jltobler@gmail.com>
Helped-by: Eric Sunshine <sunshine@sunshineco.com>
Mentored-by: Karthik Nayak <karthik.188@gmail.com>
Mentored-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
---
 Documentation/git-repo.adoc | 20 ++++++++++
 builtin/repo.c              | 74 ++++++++++++++++++++++++++++++++++++-
 t/meson.build               |  1 +
 t/t1900-repo.sh             | 50 +++++++++++++++++++++++++
 4 files changed, 143 insertions(+), 2 deletions(-)
 create mode 100755 t/t1900-repo.sh
diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc
index 68c706f5a0..a708c70a3d 100644
--- a/Documentation/git-repo.adoc
+++ b/Documentation/git-repo.adoc
@@ -22,6 +22,26 @@ COMMANDS
 	Retrieve metadata-related information about the current repository. Only
 	the requested data will be returned based on their keys (see "INFO KEYS"
 	section below).
++
+The values are returned in the same order in which their respective keys were
+requested.
++
+The output format consists of key-value pairs one per line using the `=`
+character as the delimiter between the key and the value. Values containing
+"unusual" characters are quoted as explained for the configuration variable
+`core.quotePath` (see linkgit:git-config[1]).
+
+INFO KEYS
+---------
+
+In order to obtain a set of values from `git repo info`, you should provide
+the keys that identify them. Here's a list of the available keys and the
+values that they return:
+
+`references.format`::
+The reference storage format. The valid values are:
++
+include::ref-storage-format.adoc[]
 
 SEE ALSO
 --------
diff --git a/builtin/repo.c b/builtin/repo.c
index fd2a9b4216..73d4e27a16 100644
--- a/builtin/repo.c
+++ b/builtin/repo.c
@@ -1,17 +1,87 @@
 #include "builtin.h"
 #include "parse-options.h"
+#include "quote.h"
+#include "refs.h"
+#include "strbuf.h"
 
 static const char *const repo_usage[] = {
 	"git repo info [<key>...]",
 	NULL
 };
 
-static int repo_info(int argc UNUSED, const char **argv UNUSED,
-		     const char *prefix UNUSED, struct repository *repo UNUSED)
+typedef int get_value_fn(struct repository *repo, struct strbuf *buf);
+
+struct field {
+	const char *key;
+	get_value_fn *get_value;
+};
+
+static int get_references_format(struct repository *repo, struct strbuf *buf)
 {
+	strbuf_addstr(buf,
+		      ref_storage_format_to_name(repo->ref_storage_format));
 	return 0;
 }
 
+/* repo_info_fields keys must be in lexicographical order */
+static const struct field repo_info_fields[] = {
+	{ "references.format", get_references_format },
+};
+
+static int repo_info_fields_cmp(const void *va, const void *vb)
+{
+	const struct field *a = va;
+	const struct field *b = vb;
+
+	return strcmp(a->key, b->key);
+}
+
+static get_value_fn *get_value_fn_for_key(const char *key)
+{
+	const struct field search_key = { key, NULL };
+	const struct field *found = bsearch(&search_key, repo_info_fields,
+					    ARRAY_SIZE(repo_info_fields),
+					    sizeof(*found),
+					    repo_info_fields_cmp);
+	return found ? found->get_value : NULL;
+}
+
+static int print_fields(int argc, const char **argv, struct repository *repo)
+{
+	int ret = 0;
+	struct strbuf valbuf = STRBUF_INIT;
+	struct strbuf quotbuf = STRBUF_INIT;
+
+	for (int i = 0; i < argc; i++) {
+		get_value_fn *get_value;
+		const char *key = argv[i];
+
+		get_value = get_value_fn_for_key(key);
+
+		if (!get_value) {
+			ret = error(_("key '%s' not found"), key);
+			continue;
+		}
+
+		strbuf_reset(&valbuf);
+		strbuf_reset("buf);
+
+		get_value(repo, &valbuf);
+		quote_c_style(valbuf.buf, "buf, NULL, 0);
+		printf("%s=%s\n", key, quotbuf.buf);
+	}
+
+	strbuf_release(&valbuf);
+	strbuf_release("buf);
+	return ret;
+}
+
+static int repo_info(int argc, const char **argv, const char *prefix UNUSED,
+		     struct repository *repo)
+{
+	return print_fields(argc - 1, argv + 1, repo);
+}
+
 int cmd_repo(int argc, const char **argv, const char *prefix,
 	     struct repository *repo)
 {
diff --git a/t/meson.build b/t/meson.build
index 983245501c..7555d52917 100644
--- a/t/meson.build
+++ b/t/meson.build
@@ -231,6 +231,7 @@ integration_tests = [
   't1700-split-index.sh',
   't1701-racy-split-index.sh',
   't1800-hook.sh',
+  't1900-repo.sh',
   't2000-conflict-when-checking-files-out.sh',
   't2002-checkout-cache-u.sh',
   't2003-checkout-cache-mkdir.sh',
diff --git a/t/t1900-repo.sh b/t/t1900-repo.sh
new file mode 100755
index 0000000000..dca4023a00
--- /dev/null
+++ b/t/t1900-repo.sh
@@ -0,0 +1,50 @@
+#!/bin/sh
+
+test_description='test git repo-info'
+
+. ./test-lib.sh
+
+# Test whether a key-value pair is correctly returned
+#
+# Usage: test_repo_info <label> <init command> <repo_name> <key> <expected value>
+#
+# Arguments:
+#   label: the label of the test
+#   init_command: a command which creates a repository
+#   repo_name: the name of the repository that will be created in init_command
+#   key: the key of the field that is being tested
+#   expected_value: the value that the field should contain
+test_repo_info () {
+	label=$1
+	init_command=$2
+	repo_name=$3
+	key=$4
+	expected_value=$5
+
+	test_expect_success "$label" '
+		eval "$init_command $repo_name" &&
+		echo "$key=$expected_value" >expected &&
+		git -C $repo_name repo info "$key" >actual &&
+		test_cmp expected actual
+	'
+}
+
+test_repo_info 'ref format files is retrieved correctly' \
+	'git init --ref-format=files' 'format-files' 'references.format' 'files'
+
+test_repo_info 'ref format reftable is retrieved correctly' \
+	'git init --ref-format=reftable' 'format-reftable' 'references.format' 'reftable'
+
+test_expect_success 'git-repo-info fails if an invalid key is requested' '
+	echo "error: key ${SQ}foo${SQ} not found" >expected_err &&
+	test_must_fail git repo info foo 2>actual_err &&
+	test_cmp expected_err actual_err
+'
+
+test_expect_success 'git-repo-info outputs data even if there is an invalid field' '
+	echo "references.format=$(test_detect_ref_format)" >expected &&
+	test_must_fail git repo info foo references.format bar >actual &&
+	test_cmp expected actual
+'
+
+test_done
-- 
2.39.5 (Apple Git-154)
^ permalink raw reply related	[flat|nested] 226+ messages in thread
* [GSoC PATCH v10 3/5] repo: add the field layout.bare
  2025-08-15 13:55 ` [GSoC PATCH v10 0/5] repo: declare the repo command Lucas Seiki Oshiro
  2025-08-15 13:55   ` [GSoC PATCH v10 1/5] " Lucas Seiki Oshiro
  2025-08-15 13:55   ` [GSoC PATCH v10 2/5] repo: add the field references.format Lucas Seiki Oshiro
@ 2025-08-15 13:55   ` Lucas Seiki Oshiro
  2025-08-15 13:55   ` [GSoC PATCH v10 4/5] repo: add the field layout.shallow Lucas Seiki Oshiro
  2025-08-15 13:55   ` [GSoC PATCH v10 5/5] repo: add the --format flag Lucas Seiki Oshiro
  4 siblings, 0 replies; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-08-15 13:55 UTC (permalink / raw)
  To: git
  Cc: oswald.buddenhagen, ps, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler, jn.avila, sunshine, Lucas Seiki Oshiro
This commit is part of the series that introduces the new subcommand
git-repo-info.
The flag --is-bare-repository from git-rev-parse is used for retrieving
whether the current repository is bare. This way, it is used for
querying repository metadata, fitting in the purpose of git-repo-info.
Then, add a new field layout.bare to the git-repo-info subcommand
containing that information.
Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Helped-by: Junio C Hamano <gitster@pobox.com>
Helped-by: Justin Tobler <jltobler@gmail.com>
Helped-by: Eric Sunshine <sunshine@sunshineco.com>
Mentored-by: Karthik Nayak <karthik.188@gmail.com>
Mentored-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
---
 Documentation/git-repo.adoc |  3 +++
 builtin/repo.c              | 10 ++++++++++
 t/t1900-repo.sh             | 17 +++++++++++++++++
 3 files changed, 30 insertions(+)
diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc
index a708c70a3d..d26c01a21b 100644
--- a/Documentation/git-repo.adoc
+++ b/Documentation/git-repo.adoc
@@ -38,6 +38,9 @@ In order to obtain a set of values from `git repo info`, you should provide
 the keys that identify them. Here's a list of the available keys and the
 values that they return:
 
+`layout.bare`::
+`true` if this is a bare repository, otherwise `false`.
+
 `references.format`::
 The reference storage format. The valid values are:
 +
diff --git a/builtin/repo.c b/builtin/repo.c
index 73d4e27a16..aada476e1c 100644
--- a/builtin/repo.c
+++ b/builtin/repo.c
@@ -1,4 +1,7 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
 #include "builtin.h"
+#include "environment.h"
 #include "parse-options.h"
 #include "quote.h"
 #include "refs.h"
@@ -16,6 +19,12 @@ struct field {
 	get_value_fn *get_value;
 };
 
+static int get_layout_bare(struct repository *repo UNUSED, struct strbuf *buf)
+{
+	strbuf_addstr(buf, is_bare_repository() ? "true" : "false");
+	return 0;
+}
+
 static int get_references_format(struct repository *repo, struct strbuf *buf)
 {
 	strbuf_addstr(buf,
@@ -25,6 +34,7 @@ static int get_references_format(struct repository *repo, struct strbuf *buf)
 
 /* repo_info_fields keys must be in lexicographical order */
 static const struct field repo_info_fields[] = {
+	{ "layout.bare", get_layout_bare },
 	{ "references.format", get_references_format },
 };
 
diff --git a/t/t1900-repo.sh b/t/t1900-repo.sh
index dca4023a00..8368a168b6 100755
--- a/t/t1900-repo.sh
+++ b/t/t1900-repo.sh
@@ -35,6 +35,23 @@ test_repo_info 'ref format files is retrieved correctly' \
 test_repo_info 'ref format reftable is retrieved correctly' \
 	'git init --ref-format=reftable' 'format-reftable' 'references.format' 'reftable'
 
+test_repo_info 'bare repository = false is retrieved correctly' \
+	'git init' 'nonbare' 'layout.bare' 'false'
+
+test_repo_info 'bare repository = true is retrieved correctly' \
+	'git init --bare' 'bare' 'layout.bare' 'true'
+
+test_expect_success 'values returned in order requested' '
+	cat >expect <<-\EOF &&
+	layout.bare=false
+	references.format=files
+	layout.bare=false
+	EOF
+	git init --ref-format=files ordered &&
+	git -C ordered repo info layout.bare references.format layout.bare >actual &&
+	test_cmp expect actual
+'
+
 test_expect_success 'git-repo-info fails if an invalid key is requested' '
 	echo "error: key ${SQ}foo${SQ} not found" >expected_err &&
 	test_must_fail git repo info foo 2>actual_err &&
-- 
2.39.5 (Apple Git-154)
^ permalink raw reply related	[flat|nested] 226+ messages in thread
* [GSoC PATCH v10 4/5] repo: add the field layout.shallow
  2025-08-15 13:55 ` [GSoC PATCH v10 0/5] repo: declare the repo command Lucas Seiki Oshiro
                     ` (2 preceding siblings ...)
  2025-08-15 13:55   ` [GSoC PATCH v10 3/5] repo: add the field layout.bare Lucas Seiki Oshiro
@ 2025-08-15 13:55   ` Lucas Seiki Oshiro
  2025-08-15 19:36     ` Junio C Hamano
  2025-08-15 13:55   ` [GSoC PATCH v10 5/5] repo: add the --format flag Lucas Seiki Oshiro
  4 siblings, 1 reply; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-08-15 13:55 UTC (permalink / raw)
  To: git
  Cc: oswald.buddenhagen, ps, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler, jn.avila, sunshine, Lucas Seiki Oshiro
This commit is part of the series that introduces the new subcommand
git-repo-info.
The flag `--is-shallow-repository` from git-rev-parse is used for
retrieving whether the repository is shallow. This way, it is used for
querying repository metadata, fitting in the purpose of git-repo-info.
Then, add a new field `layout.shallow` to the git-repo-info subcommand
containing that information.
Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Helped-by: Junio C Hamano <gitster@pobox.com>
Helped-by: Justin Tobler <jltobler@gmail.com>
Helped-by: Eric Sunshine <sunshine@sunshineco.com>
Mentored-by: Karthik Nayak <karthik.188@gmail.com>
Mentored-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
---
 Documentation/git-repo.adoc |  3 +++
 builtin/repo.c              |  9 +++++++++
 t/t1900-repo.sh             | 13 +++++++++++++
 3 files changed, 25 insertions(+)
diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc
index d26c01a21b..3231a93947 100644
--- a/Documentation/git-repo.adoc
+++ b/Documentation/git-repo.adoc
@@ -41,6 +41,9 @@ values that they return:
 `layout.bare`::
 `true` if this is a bare repository, otherwise `false`.
 
+`layout.shallow`::
+`true` if this is a shallow repository, otherwise `false`.
+
 `references.format`::
 The reference storage format. The valid values are:
 +
diff --git a/builtin/repo.c b/builtin/repo.c
index aada476e1c..3c9140593b 100644
--- a/builtin/repo.c
+++ b/builtin/repo.c
@@ -6,6 +6,7 @@
 #include "quote.h"
 #include "refs.h"
 #include "strbuf.h"
+#include "shallow.h"
 
 static const char *const repo_usage[] = {
 	"git repo info [<key>...]",
@@ -25,6 +26,13 @@ static int get_layout_bare(struct repository *repo UNUSED, struct strbuf *buf)
 	return 0;
 }
 
+static int get_layout_shallow(struct repository *repo, struct strbuf *buf)
+{
+	strbuf_addstr(buf,
+		      is_repository_shallow(repo) ? "true" : "false");
+	return 0;
+}
+
 static int get_references_format(struct repository *repo, struct strbuf *buf)
 {
 	strbuf_addstr(buf,
@@ -35,6 +43,7 @@ static int get_references_format(struct repository *repo, struct strbuf *buf)
 /* repo_info_fields keys must be in lexicographical order */
 static const struct field repo_info_fields[] = {
 	{ "layout.bare", get_layout_bare },
+	{ "layout.shallow", get_layout_shallow },
 	{ "references.format", get_references_format },
 };
 
diff --git a/t/t1900-repo.sh b/t/t1900-repo.sh
index 8368a168b6..78766a3f4f 100755
--- a/t/t1900-repo.sh
+++ b/t/t1900-repo.sh
@@ -41,6 +41,19 @@ test_repo_info 'bare repository = false is retrieved correctly' \
 test_repo_info 'bare repository = true is retrieved correctly' \
 	'git init --bare' 'bare' 'layout.bare' 'true'
 
+test_repo_info 'shallow repository = false is retrieved correctly' \
+	'git init' 'nonshallow' 'layout.shallow' 'false'
+
+test_expect_success 'setup remote' '
+	git init remote &&
+	echo x >remote/x &&
+	git -C remote add x &&
+	git -C remote commit -m x
+'
+
+test_repo_info 'shallow repository = true is retrieved correctly' \
+	'git clone --depth 1 "file://$PWD/remote"' 'shallow' 'layout.shallow' 'true'
+
 test_expect_success 'values returned in order requested' '
 	cat >expect <<-\EOF &&
 	layout.bare=false
-- 
2.39.5 (Apple Git-154)
^ permalink raw reply related	[flat|nested] 226+ messages in thread
* [GSoC PATCH v10 5/5] repo: add the --format flag
  2025-08-15 13:55 ` [GSoC PATCH v10 0/5] repo: declare the repo command Lucas Seiki Oshiro
                     ` (3 preceding siblings ...)
  2025-08-15 13:55   ` [GSoC PATCH v10 4/5] repo: add the field layout.shallow Lucas Seiki Oshiro
@ 2025-08-15 13:55   ` Lucas Seiki Oshiro
  2025-08-15 19:23     ` Junio C Hamano
  4 siblings, 1 reply; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-08-15 13:55 UTC (permalink / raw)
  To: git
  Cc: oswald.buddenhagen, ps, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler, jn.avila, sunshine, Lucas Seiki Oshiro
Add the --format flag to git-repo-info. By using this flag, the users
can choose the format for obtaining the data they requested.
Given that this command can be used for generating input for other
applications and for being read by end users, it requires at least two
formats: one for being read by humans and other for being read by
machines. Some other Git commands also have two output formats, notably
git-config which was the inspiration for the two formats that were
chosen here:
- keyvalue, where the retrieved data is printed one per line, using =
  for delimiting the key and the value. This is the default format,
  targeted for end users.
- nul, where the retrieved data is separated by null characters, using
  the newline character for delimiting the key and the value. This
  format is targeted for being read by machines.
Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Helped-by: Junio C Hamano <gitster@pobox.com>
Helped-by: Justin Tobler <jltobler@gmail.com>
Helped-by: Eric Sunshine <sunshine@sunshineco.com>
Mentored-by: Karthik Nayak <karthik.188@gmail.com>
Mentored-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
---
 Documentation/git-repo.adoc | 38 ++++++++++++++++++++++++------
 builtin/repo.c              | 46 ++++++++++++++++++++++++++++++++-----
 t/t1900-repo.sh             | 24 +++++++++++++++----
 3 files changed, 91 insertions(+), 17 deletions(-)
diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc
index 3231a93947..cb22f7ef65 100644
--- a/Documentation/git-repo.adoc
+++ b/Documentation/git-repo.adoc
@@ -8,7 +8,7 @@ git-repo - Retrieve information about the repository
 SYNOPSIS
 --------
 [synopsis]
-git repo info [<key>...]
+git repo info [--format=(keyvalue|nul)] [<key>...]
 
 DESCRIPTION
 -----------
@@ -18,7 +18,7 @@ THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOR MAY CHANGE.
 
 COMMANDS
 --------
-`info [<key>...]`::
+`info [--format=(keyvalue|nul)] [<key>...]`::
 	Retrieve metadata-related information about the current repository. Only
 	the requested data will be returned based on their keys (see "INFO KEYS"
 	section below).
@@ -26,14 +26,21 @@ COMMANDS
 The values are returned in the same order in which their respective keys were
 requested.
 +
-The output format consists of key-value pairs one per line using the `=`
-character as the delimiter between the key and the value. Values containing
-"unusual" characters are quoted as explained for the configuration variable
-`core.quotePath` (see linkgit:git-config[1]).
+The output format can be chosen through the flag `--format`. Two formats are
+supported:
++
+* `keyvalue`: output key-value pairs one per line using the `=` character as
+the delimiter between the key and the value. Values containing "unusual"
+characters are quoted as explained for the configuration variable
+`core.quotePath` (see linkgit:git-config[1]). This is the default.
+
+* `nul`: similar to `keyvalue`, but using a newline character as the delimiter
+between the key and the value and using a null character after each value.
+This format is better suited for being parsed by another applications than
+`keyvalue`. Unlike in the `keyvalue` format, the values are never quoted.
 
 INFO KEYS
 ---------
-
 In order to obtain a set of values from `git repo info`, you should provide
 the keys that identify them. Here's a list of the available keys and the
 values that they return:
@@ -49,6 +56,23 @@ The reference storage format. The valid values are:
 +
 include::ref-storage-format.adoc[]
 
+EXAMPLES
+--------
+
+* Retrieves the reference format of the current repository:
++
+------------
+git repo info references.format
+------------
++
+
+* Retrieves whether the current repository is bare and whether it is shallow
+using the `nul` format:
++
+------------
+git repo info --format=nul layout.bare layout.shallow
+------------
+
 SEE ALSO
 --------
 linkgit:git-rev-parse[1]
diff --git a/builtin/repo.c b/builtin/repo.c
index 3c9140593b..8c6e7f42ab 100644
--- a/builtin/repo.c
+++ b/builtin/repo.c
@@ -9,12 +9,17 @@
 #include "shallow.h"
 
 static const char *const repo_usage[] = {
-	"git repo info [<key>...]",
+	"git repo info [--format=(keyvalue|nul)] [<key>...]",
 	NULL
 };
 
 typedef int get_value_fn(struct repository *repo, struct strbuf *buf);
 
+enum output_format {
+	FORMAT_KEYVALUE,
+	FORMAT_NUL_TERMINATED,
+};
+
 struct field {
 	const char *key;
 	get_value_fn *get_value;
@@ -65,7 +70,9 @@ static get_value_fn *get_value_fn_for_key(const char *key)
 	return found ? found->get_value : NULL;
 }
 
-static int print_fields(int argc, const char **argv, struct repository *repo)
+static int print_fields(int argc, const char **argv,
+			struct repository *repo,
+			enum output_format format)
 {
 	int ret = 0;
 	struct strbuf valbuf = STRBUF_INIT;
@@ -86,8 +93,18 @@ static int print_fields(int argc, const char **argv, struct repository *repo)
 		strbuf_reset("buf);
 
 		get_value(repo, &valbuf);
-		quote_c_style(valbuf.buf, "buf, NULL, 0);
-		printf("%s=%s\n", key, quotbuf.buf);
+
+		switch (format) {
+		case FORMAT_KEYVALUE:
+			quote_c_style(valbuf.buf, "buf, NULL, 0);
+			printf("%s=%s\n", key, quotbuf.buf);
+			break;
+		case FORMAT_NUL_TERMINATED:
+			printf("%s\n%s%c", key, valbuf.buf, '\0');
+			break;
+		default:
+			BUG("not a valid output format: %d", format);
+		}
 	}
 
 	strbuf_release(&valbuf);
@@ -95,10 +112,27 @@ static int print_fields(int argc, const char **argv, struct repository *repo)
 	return ret;
 }
 
-static int repo_info(int argc, const char **argv, const char *prefix UNUSED,
+static int repo_info(int argc, const char **argv, const char *prefix,
 		     struct repository *repo)
 {
-	return print_fields(argc - 1, argv + 1, repo);
+	const char *format_str = "keyvalue";
+	enum output_format format;
+	struct option options[] = {
+		OPT_STRING(0, "format", &format_str, N_("format"),
+			   N_("output format")),
+		OPT_END()
+	};
+
+	argc = parse_options(argc, argv, prefix, options, repo_usage, 0);
+
+	if (!strcmp(format_str, "keyvalue"))
+		format = FORMAT_KEYVALUE;
+	else if (!strcmp(format_str, "nul"))
+		format = FORMAT_NUL_TERMINATED;
+	else
+		die(_("invalid format '%s'"), format_str);
+
+	return print_fields(argc, argv, repo, format);
 }
 
 int cmd_repo(int argc, const char **argv, const char *prefix,
diff --git a/t/t1900-repo.sh b/t/t1900-repo.sh
index 78766a3f4f..a4ec6b42df 100755
--- a/t/t1900-repo.sh
+++ b/t/t1900-repo.sh
@@ -21,12 +21,22 @@ test_repo_info () {
 	key=$4
 	expected_value=$5
 
-	test_expect_success "$label" '
-		eval "$init_command $repo_name" &&
-		echo "$key=$expected_value" >expected &&
-		git -C $repo_name repo info "$key" >actual &&
+	repo_name_keyvalue="$repo_name"-keyvalue
+	repo_name_nul="$repo_name"-nul
+
+	test_expect_success "keyvalue: $label" '
+		eval "$init_command $repo_name_keyvalue" &&
+		echo "$key=$expected_value" > expected &&
+		git -C "$repo_name_keyvalue" repo info "$key" >actual &&
 		test_cmp expected actual
 	'
+
+	test_expect_success "nul: $label" '
+		eval "$init_command $repo_name_nul" &&
+		printf "%s\n%s\0" "$key" "$expected_value" >expected &&
+		git -C "$repo_name_nul" repo info --format=nul "$key" >actual &&
+		test_cmp_bin expected actual
+	'
 }
 
 test_repo_info 'ref format files is retrieved correctly' \
@@ -77,4 +87,10 @@ test_expect_success 'git-repo-info outputs data even if there is an invalid fiel
 	test_cmp expected actual
 '
 
+test_expect_success 'git-repo-info aborts when requesting an invalid format' '
+	echo "fatal: invalid format ${SQ}foo${SQ}" >expected &&
+	test_must_fail git repo info --format=foo 2>err &&
+	test_cmp expected err
+'
+
 test_done
-- 
2.39.5 (Apple Git-154)
^ permalink raw reply related	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v10 2/5] repo: add the field references.format
  2025-08-15 13:55   ` [GSoC PATCH v10 2/5] repo: add the field references.format Lucas Seiki Oshiro
@ 2025-08-15 18:40     ` Junio C Hamano
  2025-08-15 19:12       ` Lucas Seiki Oshiro
  0 siblings, 1 reply; 226+ messages in thread
From: Junio C Hamano @ 2025-08-15 18:40 UTC (permalink / raw)
  To: Lucas Seiki Oshiro
  Cc: git, oswald.buddenhagen, ps, karthik.188, ben.knoble,
	phillip.wood, jltobler, jn.avila, sunshine
Lucas Seiki Oshiro <lucasseikioshiro@gmail.com> writes:
> diff --git a/t/t1900-repo.sh b/t/t1900-repo.sh
> new file mode 100755
> index 0000000000..dca4023a00
> --- /dev/null
> +++ b/t/t1900-repo.sh
> @@ -0,0 +1,50 @@
> +#!/bin/sh
> +
> +test_description='test git repo-info'
> +
> +. ./test-lib.sh
> +
> +# Test whether a key-value pair is correctly returned
> +#
> +# Usage: test_repo_info <label> <init command> <repo_name> <key> <expected value>
> +#
> +# Arguments:
> +#   label: the label of the test
> +#   init_command: a command which creates a repository
> +#   repo_name: the name of the repository that will be created in init_command
> +#   key: the key of the field that is being tested
> +#   expected_value: the value that the field should contain
> +test_repo_info () {
> +	label=$1
> +	init_command=$2
> +	repo_name=$3
> +	key=$4
> +	expected_value=$5
> +
> +	test_expect_success "$label" '
> +		eval "$init_command $repo_name" &&
> +		echo "$key=$expected_value" >expected &&
> +		git -C $repo_name repo info "$key" >actual &&
Most tests compare "expect" and "actual" by convention, so this is a
bit unusual, but I'll let it go.
I know it is tempting to write a helper function like this that
looks overly generic, but I've seen that we end up either tests that
are too hard to modify (because such helpers are not flexible enough)
or we end up adding more helpers to cover different cases, and
either case the presense of the helper does not help the resulting
tests easier to read or modify.
If this were "test repo-info for ref.format only" that takes a
single parameter (format), that might have been more palatable, but
I'll withhold my judgement until we have tests to handle more keys
in later steps.
> +		test_cmp expected actual
> +	'
> +}
> +
> +test_repo_info 'ref format files is retrieved correctly' \
> +	'git init --ref-format=files' 'format-files' 'references.format' 'files'
> +
> +test_repo_info 'ref format reftable is retrieved correctly' \
> +	'git init --ref-format=reftable' 'format-reftable' 'references.format' 'reftable'
> +
> +test_expect_success 'git-repo-info fails if an invalid key is requested' '
> +	echo "error: key ${SQ}foo${SQ} not found" >expected_err &&
> +	test_must_fail git repo info foo 2>actual_err &&
> +	test_cmp expected_err actual_err
> +'
Also, unless we capture both standard output (in actual) and
standard error (in actual_err) from the command being tested, and
instead are interested in testing only what comes out of the error
stream, it is more common to use the usual "expect vs actual".
> +
> +test_expect_success 'git-repo-info outputs data even if there is an invalid field' '
> +	echo "references.format=$(test_detect_ref_format)" >expected &&
> +	test_must_fail git repo info foo references.format bar >actual &&
> +	test_cmp expected actual
> +'
> +
> +test_done
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v10 2/5] repo: add the field references.format
  2025-08-15 18:40     ` Junio C Hamano
@ 2025-08-15 19:12       ` Lucas Seiki Oshiro
  0 siblings, 0 replies; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-08-15 19:12 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: git, oswald.buddenhagen, ps, karthik.188, ben.knoble,
	phillip.wood, jltobler, jn.avila, sunshine
> I know it is tempting to write a helper function like this that
> looks overly generic, but I've seen that we end up either tests that
> are too hard to modify (because such helpers are not flexible enough)
> or we end up adding more helpers to cover different cases, and
> either case the presense of the helper does not help the resulting
> tests easier to read or modify.
I understand... But in this case, most of the tests would look almost
the same and there will be a lot of code duplication, since I'm
testing both output formats (not in this patch, but in 5/5).
> If this were "test repo-info for ref.format only" that takes a
> single parameter (format), that might have been more palatable, but
> I'll withhold my judgement until we have tests to handle more keys
> in later steps.
I have already done objects.format here, which follows the same
structure.
> Also, unless we capture both standard output (in actual) and
> standard error (in actual_err) from the command being tested, and
> instead are interested in testing only what comes out of the error
> stream, it is more common to use the usual "expect vs actual".
Ok. Should I send a v11 or is it ok to keep it like this by now?
Thanks!
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v10 5/5] repo: add the --format flag
  2025-08-15 13:55   ` [GSoC PATCH v10 5/5] repo: add the --format flag Lucas Seiki Oshiro
@ 2025-08-15 19:23     ` Junio C Hamano
  0 siblings, 0 replies; 226+ messages in thread
From: Junio C Hamano @ 2025-08-15 19:23 UTC (permalink / raw)
  To: Lucas Seiki Oshiro
  Cc: git, oswald.buddenhagen, ps, karthik.188, ben.knoble,
	phillip.wood, jltobler, jn.avila, sunshine
Lucas Seiki Oshiro <lucasseikioshiro@gmail.com> writes:
> Add the --format flag to git-repo-info. By using this flag, the users
> can choose the format for obtaining the data they requested.
>
> Given that this command can be used for generating input for other
> applications and for being read by end users, it requires at least two
> formats: one for being read by humans and other for being read by
> machines. Some other Git commands also have two output formats, notably
> git-config which was the inspiration for the two formats that were
> chosen here:
>
> - keyvalue, where the retrieved data is printed one per line, using =
>   for delimiting the key and the value. This is the default format,
>   targeted for end users.
> - nul, where the retrieved data is separated by null characters, using
These characters are commonly spelled "NUL characters".
    $ git grep -i -e 'NUL ch' -e 'NULL ch' Documentation/
Same for the explanation for the "nul" in the documentation.
> +
> +		switch (format) {
> +		case FORMAT_KEYVALUE:
> +			quote_c_style(valbuf.buf, "buf, NULL, 0);
> +			printf("%s=%s\n", key, quotbuf.buf);
> +			break;
> +		case FORMAT_NUL_TERMINATED:
> +			printf("%s\n%s%c", key, valbuf.buf, '\0');
> +			break;
> +		default:
> +			BUG("not a valid output format: %d", format);
> +		}
OK.
> diff --git a/t/t1900-repo.sh b/t/t1900-repo.sh
> index 78766a3f4f..a4ec6b42df 100755
> --- a/t/t1900-repo.sh
> +++ b/t/t1900-repo.sh
> @@ -21,12 +21,22 @@ test_repo_info () {
>  	key=$4
>  	expected_value=$5
>  
> -	test_expect_success "$label" '
> -		eval "$init_command $repo_name" &&
> -		echo "$key=$expected_value" >expected &&
> -		git -C $repo_name repo info "$key" >actual &&
> +	repo_name_keyvalue="$repo_name"-keyvalue
> +	repo_name_nul="$repo_name"-nul
> +
> +	test_expect_success "keyvalue: $label" '
> +		eval "$init_command $repo_name_keyvalue" &&
> +		echo "$key=$expected_value" > expected &&
> +		git -C "$repo_name_keyvalue" repo info "$key" >actual &&
>  		test_cmp expected actual
>  	'
> +
> +	test_expect_success "nul: $label" '
> +		eval "$init_command $repo_name_nul" &&
> +		printf "%s\n%s\0" "$key" "$expected_value" >expected &&
> +		git -C "$repo_name_nul" repo info --format=nul "$key" >actual &&
> +		test_cmp_bin expected actual
> +	'
>  }
This is curious.
If my understanding is correct, the --format=nul/keyvalue affects
only the output format when "repo info" is executed.  I do not see
why we need two separate repositories.
^ permalink raw reply	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v10 4/5] repo: add the field layout.shallow
  2025-08-15 13:55   ` [GSoC PATCH v10 4/5] repo: add the field layout.shallow Lucas Seiki Oshiro
@ 2025-08-15 19:36     ` Junio C Hamano
  0 siblings, 0 replies; 226+ messages in thread
From: Junio C Hamano @ 2025-08-15 19:36 UTC (permalink / raw)
  To: Lucas Seiki Oshiro
  Cc: git, oswald.buddenhagen, ps, karthik.188, ben.knoble,
	phillip.wood, jltobler, jn.avila, sunshine
Lucas Seiki Oshiro <lucasseikioshiro@gmail.com> writes:
> @@ -41,6 +41,9 @@ values that they return:
>  `layout.bare`::
>  `true` if this is a bare repository, otherwise `false`.
>  
> +`layout.shallow`::
> +`true` if this is a shallow repository, otherwise `false`.
> +
>  `references.format`::
>  The reference storage format. The valid values are:
>  +
Common to all three patches that adds each of these three, but I
think we want to see these definition list like so:
	`layout.bare`::
		`true` if this is a bare...
	`layout.shallow`::
		'true` if this is a shallow...
	`reference.format`::
		The reference storage format.
It should not make any difference in the rendered result.  The
existing documentation pages follow this style because it makes the
layout of the text in the source file resemble the formatted output
more closely.
Also, I wonder if it makes the document structure (from the point of
view of mark-up) more apparent if we make the listing of two
possible values for the "--format=" option a nested definition list,
inside the definition list with a single element "info" in it.
Something like the following on top of your series, that is.
The first hunk does make the result rendered differently; the second
hunk should produce the identical rendition as your version.
Thanks.
 Documentation/git-repo.adoc | 24 +++++++++++++-----------
 1 file changed, 13 insertions(+), 11 deletions(-)
diff --git c/Documentation/git-repo.adoc w/Documentation/git-repo.adoc
index cb22f7ef65..5424deea69 100644
--- c/Documentation/git-repo.adoc
+++ w/Documentation/git-repo.adoc
@@ -29,15 +29,17 @@ requested.
 The output format can be chosen through the flag `--format`. Two formats are
 supported:
 +
-* `keyvalue`: output key-value pairs one per line using the `=` character as
-the delimiter between the key and the value. Values containing "unusual"
-characters are quoted as explained for the configuration variable
-`core.quotePath` (see linkgit:git-config[1]). This is the default.
+`keyvalue`;;
+	output key-value pairs one per line using the `=` character as
+	the delimiter between the key and the value. Values containing "unusual"
+	characters are quoted as explained for the configuration variable
+	`core.quotePath` (see linkgit:git-config[1]). This is the default.
 
-* `nul`: similar to `keyvalue`, but using a newline character as the delimiter
-between the key and the value and using a null character after each value.
-This format is better suited for being parsed by another applications than
-`keyvalue`. Unlike in the `keyvalue` format, the values are never quoted.
+`nul`;;
+	similar to `keyvalue`, but using a newline character as the delimiter
+	between the key and the value and using a null character after each value.
+	This format is better suited for being parsed by another applications than
+	`keyvalue`. Unlike in the `keyvalue` format, the values are never quoted.
 
 INFO KEYS
 ---------
@@ -46,13 +48,13 @@ the keys that identify them. Here's a list of the available keys and the
 values that they return:
 
 `layout.bare`::
-`true` if this is a bare repository, otherwise `false`.
+	`true` if this is a bare repository, otherwise `false`.
 
 `layout.shallow`::
-`true` if this is a shallow repository, otherwise `false`.
+	`true` if this is a shallow repository, otherwise `false`.
 
 `references.format`::
-The reference storage format. The valid values are:
+	The reference storage format. The valid values are:
 +
 include::ref-storage-format.adoc[]
 
^ permalink raw reply related	[flat|nested] 226+ messages in thread
* [GSoC PATCH v11 0/5] repo: declare the repo command
  2025-06-10 15:21 [GSoC RFC PATCH 0/5] repo-info: add new command for retrieving repository info Lucas Seiki Oshiro
                   ` (16 preceding siblings ...)
  2025-08-15 13:55 ` [GSoC PATCH v10 0/5] repo: declare the repo command Lucas Seiki Oshiro
@ 2025-08-16 22:45 ` Lucas Seiki Oshiro
  2025-08-16 22:45   ` [GSoC PATCH v11 1/5] " Lucas Seiki Oshiro
                     ` (5 more replies)
  17 siblings, 6 replies; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-08-16 22:45 UTC (permalink / raw)
  To: git
  Cc: oswald.buddenhagen, ps, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler, jn.avila, sunshine, Lucas Seiki Oshiro
Hi!
This v11 addresses the minor issues pointed by Junio in v10. They are mostly
spelling changes:
- using "expect" and "actual" in all test_cmp calls, even when we're capturing
  stderr
- indent list items in the documentation
- use a nested description list when describing the possible values of --format
- spelling: "NUL characters" instead of "null characters"
- initialize the repository in `test_repo_info` outside the test cases,
  creating a single repository for both keyvalue and nul formats
Here's the rangediff versus v10:
1:  6767028da3 = 1:  6767028da3 repo: declare the repo command
2:  c44e2d1619 ! 2:  1a3fa8e12f repo: add the field references.format
    @@ Documentation/git-repo.adoc: COMMANDS
     +values that they return:
     +
     +`references.format`::
    -+The reference storage format. The valid values are:
    ++	The reference storage format. The valid values are:
     ++
     +include::ref-storage-format.adoc[]
    @@ t/t1900-repo.sh (new)
     +	key=$4
     +	expected_value=$5
     +
    ++	test_expect_success "setup: $label" '
    ++		eval "$init_command $repo_name"
    ++	'
    ++
     +	test_expect_success "$label" '
    -+		eval "$init_command $repo_name" &&
    -+		echo "$key=$expected_value" >expected &&
    ++		echo "$key=$expected_value" >expect &&
     +		git -C $repo_name repo info "$key" >actual &&
    -+		test_cmp expected actual
    ++		test_cmp expect actual
     +	'
     +}
     +
    @@ t/t1900-repo.sh (new)
     +	'git init --ref-format=reftable' 'format-reftable' 'references.format' 'reftable'
     +
     +test_expect_success 'git-repo-info fails if an invalid key is requested' '
    -+	echo "error: key ${SQ}foo${SQ} not found" >expected_err &&
    -+	test_must_fail git repo info foo 2>actual_err &&
    -+	test_cmp expected_err actual_err
    ++	echo "error: key ${SQ}foo${SQ} not found" >expect &&
    ++	test_must_fail git repo info foo 2>actual &&
    ++	test_cmp expect actual
     +'
     +
     +test_expect_success 'git-repo-info outputs data even if there is an invalid field' '
    -+	echo "references.format=$(test_detect_ref_format)" >expected &&
    ++	echo "references.format=$(test_detect_ref_format)" >expect &&
     +	test_must_fail git repo info foo references.format bar >actual &&
    -+	test_cmp expected actual
    ++	test_cmp expect actual
     +'
     +
     +test_done
3:  e3009a85e1 ! 3:  a3b05def63 repo: add the field layout.bare
    @@ Documentation/git-repo.adoc: In order to obtain a set of values from `git repo i
      values that they return:
     +`layout.bare`::
    -+`true` if this is a bare repository, otherwise `false`.
    ++	`true` if this is a bare repository, otherwise `false`.
     +
      `references.format`::
    - The reference storage format. The valid values are:
    + 	The reference storage format. The valid values are:
      +
      ## builtin/repo.c ##
    @@ t/t1900-repo.sh: test_repo_info 'ref format files is retrieved correctly' \
     +'
     +
      test_expect_success 'git-repo-info fails if an invalid key is requested' '
    - 	echo "error: key ${SQ}foo${SQ} not found" >expected_err &&
    - 	test_must_fail git repo info foo 2>actual_err &&
    + 	echo "error: key ${SQ}foo${SQ} not found" >expect &&
    + 	test_must_fail git repo info foo 2>actual &&
4:  3837899c32 ! 4:  034dd414e5 repo: add the field layout.shallow
    @@ Commit message
      ## Documentation/git-repo.adoc ##
     @@ Documentation/git-repo.adoc: values that they return:
      `layout.bare`::
    - `true` if this is a bare repository, otherwise `false`.
    + 	`true` if this is a bare repository, otherwise `false`.
     +`layout.shallow`::
    -+`true` if this is a shallow repository, otherwise `false`.
    ++	`true` if this is a shallow repository, otherwise `false`.
     +
      `references.format`::
    - The reference storage format. The valid values are:
    + 	The reference storage format. The valid values are:
      +
      ## builtin/repo.c ##
5:  19fdfce646 ! 5:  442a3b7afa repo: add the --format flag
    @@ Commit message
         - keyvalue, where the retrieved data is printed one per line, using =
           for delimiting the key and the value. This is the default format,
           targeted for end users.
    -    - nul, where the retrieved data is separated by null characters, using
    +    - nul, where the retrieved data is separated by NUL characters, using
           the newline character for delimiting the key and the value. This
           format is targeted for being read by machines.
    @@ Documentation/git-repo.adoc: COMMANDS
     +The output format can be chosen through the flag `--format`. Two formats are
     +supported:
     ++
    -+* `keyvalue`: output key-value pairs one per line using the `=` character as
    -+the delimiter between the key and the value. Values containing "unusual"
    -+characters are quoted as explained for the configuration variable
    -+`core.quotePath` (see linkgit:git-config[1]). This is the default.
    ++`keyvalue`:::
    ++	output key-value pairs one per line using the `=` character as
    ++	the delimiter between the key and the value. Values containing "unusual"
    ++	characters are quoted as explained for the configuration variable
    ++	`core.quotePath` (see linkgit:git-config[1]). This is the default.
     +
    -+* `nul`: similar to `keyvalue`, but using a newline character as the delimiter
    -+between the key and the value and using a null character after each value.
    -+This format is better suited for being parsed by another applications than
    -+`keyvalue`. Unlike in the `keyvalue` format, the values are never quoted.
    ++`nul`:::
    ++	similar to `keyvalue`, but using a newline character as the delimiter
    ++	between the key and the value and using a NUL character after each value.
    ++	This format is better suited for being parsed by another applications than
    ++	`keyvalue`. Unlike in the `keyvalue` format, the values are never quoted.
      INFO KEYS
      ---------
    @@ Documentation/git-repo.adoc: COMMANDS
      In order to obtain a set of values from `git repo info`, you should provide
      the keys that identify them. Here's a list of the available keys and the
      values that they return:
    -@@ Documentation/git-repo.adoc: The reference storage format. The valid values are:
    +@@ Documentation/git-repo.adoc: values that they return:
      +
      include::ref-storage-format.adoc[]
    @@ builtin/repo.c: static int print_fields(int argc, const char **argv, struct repo
      ## t/t1900-repo.sh ##
     @@ t/t1900-repo.sh: test_repo_info () {
    - 	key=$4
    - 	expected_value=$5
    + 		eval "$init_command $repo_name"
    + 	'
     -	test_expect_success "$label" '
    --		eval "$init_command $repo_name" &&
    --		echo "$key=$expected_value" >expected &&
    +-		echo "$key=$expected_value" >expect &&
     -		git -C $repo_name repo info "$key" >actual &&
    -+	repo_name_keyvalue="$repo_name"-keyvalue
    -+	repo_name_nul="$repo_name"-nul
    -+
     +	test_expect_success "keyvalue: $label" '
    -+		eval "$init_command $repo_name_keyvalue" &&
    -+		echo "$key=$expected_value" > expected &&
    -+		git -C "$repo_name_keyvalue" repo info "$key" >actual &&
    - 		test_cmp expected actual
    ++		echo "$key=$expected_value" > expect &&
    ++		git -C "$repo_name" repo info "$key" >actual &&
    + 		test_cmp expect actual
      	'
     +
     +	test_expect_success "nul: $label" '
    -+		eval "$init_command $repo_name_nul" &&
    -+		printf "%s\n%s\0" "$key" "$expected_value" >expected &&
    -+		git -C "$repo_name_nul" repo info --format=nul "$key" >actual &&
    -+		test_cmp_bin expected actual
    ++		printf "%s\n%s\0" "$key" "$expected_value" >expect &&
    ++		git -C "$repo_name" repo info --format=nul "$key" >actual &&
    ++		test_cmp_bin expect actual
     +	'
      }
      test_repo_info 'ref format files is retrieved correctly' \
     @@ t/t1900-repo.sh: test_expect_success 'git-repo-info outputs data even if there is an invalid fiel
    - 	test_cmp expected actual
    + 	test_cmp expect actual
      '
     +test_expect_success 'git-repo-info aborts when requesting an invalid format' '
    -+	echo "fatal: invalid format ${SQ}foo${SQ}" >expected &&
    -+	test_must_fail git repo info --format=foo 2>err &&
    -+	test_cmp expected err
    ++	echo "fatal: invalid format ${SQ}foo${SQ}" >expect &&
    ++	test_must_fail git repo info --format=foo 2>actual &&
    ++	test_cmp expect actual
     +'
     +
      test_done
Lucas Seiki Oshiro (5):
  repo: declare the repo command
  repo: add the field references.format
  repo: add the field layout.bare
  repo: add the field layout.shallow
  repo: add the --format flag
 .gitignore                  |   1 +
 Documentation/git-repo.adoc |  84 ++++++++++++++++++++
 Documentation/meson.build   |   1 +
 Makefile                    |   1 +
 builtin.h                   |   1 +
 builtin/repo.c              | 150 ++++++++++++++++++++++++++++++++++++
 command-list.txt            |   1 +
 git.c                       |   1 +
 meson.build                 |   1 +
 t/meson.build               |   1 +
 t/t1900-repo.sh             |  95 +++++++++++++++++++++++
 11 files changed, 337 insertions(+)
 create mode 100644 Documentation/git-repo.adoc
 create mode 100644 builtin/repo.c
 create mode 100755 t/t1900-repo.sh
-- 
2.39.5 (Apple Git-154)
^ permalink raw reply	[flat|nested] 226+ messages in thread
* [GSoC PATCH v11 1/5] repo: declare the repo command
  2025-08-16 22:45 ` [GSoC PATCH v11 0/5] repo: declare the repo command Lucas Seiki Oshiro
@ 2025-08-16 22:45   ` Lucas Seiki Oshiro
  2025-08-16 22:46   ` [GSoC PATCH v11 2/5] repo: add the field references.format Lucas Seiki Oshiro
                     ` (4 subsequent siblings)
  5 siblings, 0 replies; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-08-16 22:45 UTC (permalink / raw)
  To: git
  Cc: oswald.buddenhagen, ps, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler, jn.avila, sunshine, Lucas Seiki Oshiro
Currently, `git rev-parse` covers a wide range of functionality not
directly related to parsing revisions, as its name suggests. Over time,
many features like parsing datestrings, options, paths, and others
were added to it because there wasn't a more appropriate command
to place them.
Create a new Git command called `repo`. `git repo` will be the main
command for obtaining the information about a repository (such as
metadata and metrics).
Also declare a subcommand for `repo` called `info`. `git repo info`
will bring the functionality of retrieving repository-related
information currently returned by `rev-parse`.
Add the required documentation and build changes to enable usage of
this subcommand.
Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Helped-by: Junio C Hamano <gitster@pobox.com>
Helped-by: Justin Tobler <jltobler@gmail.com>
Helped-by: Eric Sunshine <sunshine@sunshineco.com>
Mentored-by: Karthik Nayak <karthik.188@gmail.com>
Mentored-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
---
 .gitignore                  |  1 +
 Documentation/git-repo.adoc | 32 ++++++++++++++++++++++++++++++++
 Documentation/meson.build   |  1 +
 Makefile                    |  1 +
 builtin.h                   |  1 +
 builtin/repo.c              | 27 +++++++++++++++++++++++++++
 command-list.txt            |  1 +
 git.c                       |  1 +
 meson.build                 |  1 +
 9 files changed, 66 insertions(+)
 create mode 100644 Documentation/git-repo.adoc
 create mode 100644 builtin/repo.c
diff --git a/.gitignore b/.gitignore
index 04c444404e..1803023427 100644
--- a/.gitignore
+++ b/.gitignore
@@ -139,6 +139,7 @@
 /git-repack
 /git-replace
 /git-replay
+/git-repo
 /git-request-pull
 /git-rerere
 /git-reset
diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc
new file mode 100644
index 0000000000..68c706f5a0
--- /dev/null
+++ b/Documentation/git-repo.adoc
@@ -0,0 +1,32 @@
+git-repo(1)
+===========
+
+NAME
+----
+git-repo - Retrieve information about the repository
+
+SYNOPSIS
+--------
+[synopsis]
+git repo info [<key>...]
+
+DESCRIPTION
+-----------
+Retrieve information about the repository.
+
+THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOR MAY CHANGE.
+
+COMMANDS
+--------
+`info [<key>...]`::
+	Retrieve metadata-related information about the current repository. Only
+	the requested data will be returned based on their keys (see "INFO KEYS"
+	section below).
+
+SEE ALSO
+--------
+linkgit:git-rev-parse[1]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/meson.build b/Documentation/meson.build
index 4404c623f0..41f43e0336 100644
--- a/Documentation/meson.build
+++ b/Documentation/meson.build
@@ -116,6 +116,7 @@ manpages = {
   'git-repack.adoc' : 1,
   'git-replace.adoc' : 1,
   'git-replay.adoc' : 1,
+  'git-repo.adoc' : 1,
   'git-request-pull.adoc' : 1,
   'git-rerere.adoc' : 1,
   'git-reset.adoc' : 1,
diff --git a/Makefile b/Makefile
index e11340c1ae..ec7ac58980 100644
--- a/Makefile
+++ b/Makefile
@@ -1306,6 +1306,7 @@ BUILTIN_OBJS += builtin/remote.o
 BUILTIN_OBJS += builtin/repack.o
 BUILTIN_OBJS += builtin/replace.o
 BUILTIN_OBJS += builtin/replay.o
+BUILTIN_OBJS += builtin/repo.o
 BUILTIN_OBJS += builtin/rerere.o
 BUILTIN_OBJS += builtin/reset.o
 BUILTIN_OBJS += builtin/rev-list.o
diff --git a/builtin.h b/builtin.h
index bff13e3069..e6458e6fb9 100644
--- a/builtin.h
+++ b/builtin.h
@@ -216,6 +216,7 @@ int cmd_remote_ext(int argc, const char **argv, const char *prefix, struct repos
 int cmd_remote_fd(int argc, const char **argv, const char *prefix, struct repository *repo);
 int cmd_repack(int argc, const char **argv, const char *prefix, struct repository *repo);
 int cmd_replay(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_repo(int argc, const char **argv, const char *prefix, struct repository *repo);
 int cmd_rerere(int argc, const char **argv, const char *prefix, struct repository *repo);
 int cmd_reset(int argc, const char **argv, const char *prefix, struct repository *repo);
 int cmd_restore(int argc, const char **argv, const char *prefix, struct repository *repo);
diff --git a/builtin/repo.c b/builtin/repo.c
new file mode 100644
index 0000000000..fd2a9b4216
--- /dev/null
+++ b/builtin/repo.c
@@ -0,0 +1,27 @@
+#include "builtin.h"
+#include "parse-options.h"
+
+static const char *const repo_usage[] = {
+	"git repo info [<key>...]",
+	NULL
+};
+
+static int repo_info(int argc UNUSED, const char **argv UNUSED,
+		     const char *prefix UNUSED, struct repository *repo UNUSED)
+{
+	return 0;
+}
+
+int cmd_repo(int argc, const char **argv, const char *prefix,
+	     struct repository *repo)
+{
+	parse_opt_subcommand_fn *fn = NULL;
+	struct option options[] = {
+		OPT_SUBCOMMAND("info", &fn, repo_info),
+		OPT_END()
+	};
+
+	argc = parse_options(argc, argv, prefix, options, repo_usage, 0);
+
+	return fn(argc, argv, prefix, repo);
+}
diff --git a/command-list.txt b/command-list.txt
index b7ade3ab9f..1b0bdee00d 100644
--- a/command-list.txt
+++ b/command-list.txt
@@ -164,6 +164,7 @@ git-remote                              ancillarymanipulators           complete
 git-repack                              ancillarymanipulators           complete
 git-replace                             ancillarymanipulators           complete
 git-replay                              plumbingmanipulators
+git-repo                                plumbinginterrogators
 git-request-pull                        foreignscminterface             complete
 git-rerere                              ancillaryinterrogators
 git-reset                               mainporcelain           history
diff --git a/git.c b/git.c
index 83eac0aeab..d4ff4d5517 100644
--- a/git.c
+++ b/git.c
@@ -611,6 +611,7 @@ static struct cmd_struct commands[] = {
 	{ "repack", cmd_repack, RUN_SETUP },
 	{ "replace", cmd_replace, RUN_SETUP },
 	{ "replay", cmd_replay, RUN_SETUP },
+	{ "repo", cmd_repo, RUN_SETUP },
 	{ "rerere", cmd_rerere, RUN_SETUP },
 	{ "reset", cmd_reset, RUN_SETUP },
 	{ "restore", cmd_restore, RUN_SETUP | NEED_WORK_TREE },
diff --git a/meson.build b/meson.build
index 5dd299b496..e8ec0eca16 100644
--- a/meson.build
+++ b/meson.build
@@ -645,6 +645,7 @@ builtin_sources = [
   'builtin/repack.c',
   'builtin/replace.c',
   'builtin/replay.c',
+  'builtin/repo.c',
   'builtin/rerere.c',
   'builtin/reset.c',
   'builtin/rev-list.c',
-- 
2.39.5 (Apple Git-154)
^ permalink raw reply related	[flat|nested] 226+ messages in thread
* [GSoC PATCH v11 2/5] repo: add the field references.format
  2025-08-16 22:45 ` [GSoC PATCH v11 0/5] repo: declare the repo command Lucas Seiki Oshiro
  2025-08-16 22:45   ` [GSoC PATCH v11 1/5] " Lucas Seiki Oshiro
@ 2025-08-16 22:46   ` Lucas Seiki Oshiro
  2025-08-16 22:46   ` [GSoC PATCH v11 3/5] repo: add the field layout.bare Lucas Seiki Oshiro
                     ` (3 subsequent siblings)
  5 siblings, 0 replies; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-08-16 22:46 UTC (permalink / raw)
  To: git
  Cc: oswald.buddenhagen, ps, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler, jn.avila, sunshine, Lucas Seiki Oshiro
This commit is part of the series that introduces the new subcommand
git-repo-info.
The flag `--show-ref-format` from git-rev-parse is used for retrieving
the reference format (i.e. `files` or `reftable`). This way, it is
used for querying repository metadata, fitting in the purpose of
git-repo-info.
Add a new field `references.format` to the repo-info subcommand
containing that information.
Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Helped-by: Junio C Hamano <gitster@pobox.com>
Helped-by: Justin Tobler <jltobler@gmail.com>
Helped-by: Eric Sunshine <sunshine@sunshineco.com>
Mentored-by: Karthik Nayak <karthik.188@gmail.com>
Mentored-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
---
 Documentation/git-repo.adoc | 20 ++++++++++
 builtin/repo.c              | 74 ++++++++++++++++++++++++++++++++++++-
 t/meson.build               |  1 +
 t/t1900-repo.sh             | 53 ++++++++++++++++++++++++++
 4 files changed, 146 insertions(+), 2 deletions(-)
 create mode 100755 t/t1900-repo.sh
diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc
index 68c706f5a0..2779a6d995 100644
--- a/Documentation/git-repo.adoc
+++ b/Documentation/git-repo.adoc
@@ -22,6 +22,26 @@ COMMANDS
 	Retrieve metadata-related information about the current repository. Only
 	the requested data will be returned based on their keys (see "INFO KEYS"
 	section below).
++
+The values are returned in the same order in which their respective keys were
+requested.
++
+The output format consists of key-value pairs one per line using the `=`
+character as the delimiter between the key and the value. Values containing
+"unusual" characters are quoted as explained for the configuration variable
+`core.quotePath` (see linkgit:git-config[1]).
+
+INFO KEYS
+---------
+
+In order to obtain a set of values from `git repo info`, you should provide
+the keys that identify them. Here's a list of the available keys and the
+values that they return:
+
+`references.format`::
+	The reference storage format. The valid values are:
++
+include::ref-storage-format.adoc[]
 
 SEE ALSO
 --------
diff --git a/builtin/repo.c b/builtin/repo.c
index fd2a9b4216..73d4e27a16 100644
--- a/builtin/repo.c
+++ b/builtin/repo.c
@@ -1,17 +1,87 @@
 #include "builtin.h"
 #include "parse-options.h"
+#include "quote.h"
+#include "refs.h"
+#include "strbuf.h"
 
 static const char *const repo_usage[] = {
 	"git repo info [<key>...]",
 	NULL
 };
 
-static int repo_info(int argc UNUSED, const char **argv UNUSED,
-		     const char *prefix UNUSED, struct repository *repo UNUSED)
+typedef int get_value_fn(struct repository *repo, struct strbuf *buf);
+
+struct field {
+	const char *key;
+	get_value_fn *get_value;
+};
+
+static int get_references_format(struct repository *repo, struct strbuf *buf)
 {
+	strbuf_addstr(buf,
+		      ref_storage_format_to_name(repo->ref_storage_format));
 	return 0;
 }
 
+/* repo_info_fields keys must be in lexicographical order */
+static const struct field repo_info_fields[] = {
+	{ "references.format", get_references_format },
+};
+
+static int repo_info_fields_cmp(const void *va, const void *vb)
+{
+	const struct field *a = va;
+	const struct field *b = vb;
+
+	return strcmp(a->key, b->key);
+}
+
+static get_value_fn *get_value_fn_for_key(const char *key)
+{
+	const struct field search_key = { key, NULL };
+	const struct field *found = bsearch(&search_key, repo_info_fields,
+					    ARRAY_SIZE(repo_info_fields),
+					    sizeof(*found),
+					    repo_info_fields_cmp);
+	return found ? found->get_value : NULL;
+}
+
+static int print_fields(int argc, const char **argv, struct repository *repo)
+{
+	int ret = 0;
+	struct strbuf valbuf = STRBUF_INIT;
+	struct strbuf quotbuf = STRBUF_INIT;
+
+	for (int i = 0; i < argc; i++) {
+		get_value_fn *get_value;
+		const char *key = argv[i];
+
+		get_value = get_value_fn_for_key(key);
+
+		if (!get_value) {
+			ret = error(_("key '%s' not found"), key);
+			continue;
+		}
+
+		strbuf_reset(&valbuf);
+		strbuf_reset("buf);
+
+		get_value(repo, &valbuf);
+		quote_c_style(valbuf.buf, "buf, NULL, 0);
+		printf("%s=%s\n", key, quotbuf.buf);
+	}
+
+	strbuf_release(&valbuf);
+	strbuf_release("buf);
+	return ret;
+}
+
+static int repo_info(int argc, const char **argv, const char *prefix UNUSED,
+		     struct repository *repo)
+{
+	return print_fields(argc - 1, argv + 1, repo);
+}
+
 int cmd_repo(int argc, const char **argv, const char *prefix,
 	     struct repository *repo)
 {
diff --git a/t/meson.build b/t/meson.build
index 983245501c..7555d52917 100644
--- a/t/meson.build
+++ b/t/meson.build
@@ -231,6 +231,7 @@ integration_tests = [
   't1700-split-index.sh',
   't1701-racy-split-index.sh',
   't1800-hook.sh',
+  't1900-repo.sh',
   't2000-conflict-when-checking-files-out.sh',
   't2002-checkout-cache-u.sh',
   't2003-checkout-cache-mkdir.sh',
diff --git a/t/t1900-repo.sh b/t/t1900-repo.sh
new file mode 100755
index 0000000000..be8a4b2499
--- /dev/null
+++ b/t/t1900-repo.sh
@@ -0,0 +1,53 @@
+#!/bin/sh
+
+test_description='test git repo-info'
+
+. ./test-lib.sh
+
+# Test whether a key-value pair is correctly returned
+#
+# Usage: test_repo_info <label> <init command> <repo_name> <key> <expected value>
+#
+# Arguments:
+#   label: the label of the test
+#   init_command: a command which creates a repository
+#   repo_name: the name of the repository that will be created in init_command
+#   key: the key of the field that is being tested
+#   expected_value: the value that the field should contain
+test_repo_info () {
+	label=$1
+	init_command=$2
+	repo_name=$3
+	key=$4
+	expected_value=$5
+
+	test_expect_success "setup: $label" '
+		eval "$init_command $repo_name"
+	'
+
+	test_expect_success "$label" '
+		echo "$key=$expected_value" >expect &&
+		git -C $repo_name repo info "$key" >actual &&
+		test_cmp expect actual
+	'
+}
+
+test_repo_info 'ref format files is retrieved correctly' \
+	'git init --ref-format=files' 'format-files' 'references.format' 'files'
+
+test_repo_info 'ref format reftable is retrieved correctly' \
+	'git init --ref-format=reftable' 'format-reftable' 'references.format' 'reftable'
+
+test_expect_success 'git-repo-info fails if an invalid key is requested' '
+	echo "error: key ${SQ}foo${SQ} not found" >expect &&
+	test_must_fail git repo info foo 2>actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'git-repo-info outputs data even if there is an invalid field' '
+	echo "references.format=$(test_detect_ref_format)" >expect &&
+	test_must_fail git repo info foo references.format bar >actual &&
+	test_cmp expect actual
+'
+
+test_done
-- 
2.39.5 (Apple Git-154)
^ permalink raw reply related	[flat|nested] 226+ messages in thread
* [GSoC PATCH v11 3/5] repo: add the field layout.bare
  2025-08-16 22:45 ` [GSoC PATCH v11 0/5] repo: declare the repo command Lucas Seiki Oshiro
  2025-08-16 22:45   ` [GSoC PATCH v11 1/5] " Lucas Seiki Oshiro
  2025-08-16 22:46   ` [GSoC PATCH v11 2/5] repo: add the field references.format Lucas Seiki Oshiro
@ 2025-08-16 22:46   ` Lucas Seiki Oshiro
  2025-08-16 22:46   ` [GSoC PATCH v11 4/5] repo: add the field layout.shallow Lucas Seiki Oshiro
                     ` (2 subsequent siblings)
  5 siblings, 0 replies; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-08-16 22:46 UTC (permalink / raw)
  To: git
  Cc: oswald.buddenhagen, ps, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler, jn.avila, sunshine, Lucas Seiki Oshiro
This commit is part of the series that introduces the new subcommand
git-repo-info.
The flag --is-bare-repository from git-rev-parse is used for retrieving
whether the current repository is bare. This way, it is used for
querying repository metadata, fitting in the purpose of git-repo-info.
Then, add a new field layout.bare to the git-repo-info subcommand
containing that information.
Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Helped-by: Junio C Hamano <gitster@pobox.com>
Helped-by: Justin Tobler <jltobler@gmail.com>
Helped-by: Eric Sunshine <sunshine@sunshineco.com>
Mentored-by: Karthik Nayak <karthik.188@gmail.com>
Mentored-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
---
 Documentation/git-repo.adoc |  3 +++
 builtin/repo.c              | 10 ++++++++++
 t/t1900-repo.sh             | 17 +++++++++++++++++
 3 files changed, 30 insertions(+)
diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc
index 2779a6d995..932b08c26f 100644
--- a/Documentation/git-repo.adoc
+++ b/Documentation/git-repo.adoc
@@ -38,6 +38,9 @@ In order to obtain a set of values from `git repo info`, you should provide
 the keys that identify them. Here's a list of the available keys and the
 values that they return:
 
+`layout.bare`::
+	`true` if this is a bare repository, otherwise `false`.
+
 `references.format`::
 	The reference storage format. The valid values are:
 +
diff --git a/builtin/repo.c b/builtin/repo.c
index 73d4e27a16..aada476e1c 100644
--- a/builtin/repo.c
+++ b/builtin/repo.c
@@ -1,4 +1,7 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
 #include "builtin.h"
+#include "environment.h"
 #include "parse-options.h"
 #include "quote.h"
 #include "refs.h"
@@ -16,6 +19,12 @@ struct field {
 	get_value_fn *get_value;
 };
 
+static int get_layout_bare(struct repository *repo UNUSED, struct strbuf *buf)
+{
+	strbuf_addstr(buf, is_bare_repository() ? "true" : "false");
+	return 0;
+}
+
 static int get_references_format(struct repository *repo, struct strbuf *buf)
 {
 	strbuf_addstr(buf,
@@ -25,6 +34,7 @@ static int get_references_format(struct repository *repo, struct strbuf *buf)
 
 /* repo_info_fields keys must be in lexicographical order */
 static const struct field repo_info_fields[] = {
+	{ "layout.bare", get_layout_bare },
 	{ "references.format", get_references_format },
 };
 
diff --git a/t/t1900-repo.sh b/t/t1900-repo.sh
index be8a4b2499..b0438d276e 100755
--- a/t/t1900-repo.sh
+++ b/t/t1900-repo.sh
@@ -38,6 +38,23 @@ test_repo_info 'ref format files is retrieved correctly' \
 test_repo_info 'ref format reftable is retrieved correctly' \
 	'git init --ref-format=reftable' 'format-reftable' 'references.format' 'reftable'
 
+test_repo_info 'bare repository = false is retrieved correctly' \
+	'git init' 'nonbare' 'layout.bare' 'false'
+
+test_repo_info 'bare repository = true is retrieved correctly' \
+	'git init --bare' 'bare' 'layout.bare' 'true'
+
+test_expect_success 'values returned in order requested' '
+	cat >expect <<-\EOF &&
+	layout.bare=false
+	references.format=files
+	layout.bare=false
+	EOF
+	git init --ref-format=files ordered &&
+	git -C ordered repo info layout.bare references.format layout.bare >actual &&
+	test_cmp expect actual
+'
+
 test_expect_success 'git-repo-info fails if an invalid key is requested' '
 	echo "error: key ${SQ}foo${SQ} not found" >expect &&
 	test_must_fail git repo info foo 2>actual &&
-- 
2.39.5 (Apple Git-154)
^ permalink raw reply related	[flat|nested] 226+ messages in thread
* [GSoC PATCH v11 4/5] repo: add the field layout.shallow
  2025-08-16 22:45 ` [GSoC PATCH v11 0/5] repo: declare the repo command Lucas Seiki Oshiro
                     ` (2 preceding siblings ...)
  2025-08-16 22:46   ` [GSoC PATCH v11 3/5] repo: add the field layout.bare Lucas Seiki Oshiro
@ 2025-08-16 22:46   ` Lucas Seiki Oshiro
  2025-08-16 22:46   ` [GSoC PATCH v11 5/5] repo: add the --format flag Lucas Seiki Oshiro
  2025-08-17 16:21   ` [GSoC PATCH v11 0/5] repo: declare the repo command Junio C Hamano
  5 siblings, 0 replies; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-08-16 22:46 UTC (permalink / raw)
  To: git
  Cc: oswald.buddenhagen, ps, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler, jn.avila, sunshine, Lucas Seiki Oshiro
This commit is part of the series that introduces the new subcommand
git-repo-info.
The flag `--is-shallow-repository` from git-rev-parse is used for
retrieving whether the repository is shallow. This way, it is used for
querying repository metadata, fitting in the purpose of git-repo-info.
Then, add a new field `layout.shallow` to the git-repo-info subcommand
containing that information.
Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Helped-by: Junio C Hamano <gitster@pobox.com>
Helped-by: Justin Tobler <jltobler@gmail.com>
Helped-by: Eric Sunshine <sunshine@sunshineco.com>
Mentored-by: Karthik Nayak <karthik.188@gmail.com>
Mentored-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
---
 Documentation/git-repo.adoc |  3 +++
 builtin/repo.c              |  9 +++++++++
 t/t1900-repo.sh             | 13 +++++++++++++
 3 files changed, 25 insertions(+)
diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc
index 932b08c26f..01b7f9c95e 100644
--- a/Documentation/git-repo.adoc
+++ b/Documentation/git-repo.adoc
@@ -41,6 +41,9 @@ values that they return:
 `layout.bare`::
 	`true` if this is a bare repository, otherwise `false`.
 
+`layout.shallow`::
+	`true` if this is a shallow repository, otherwise `false`.
+
 `references.format`::
 	The reference storage format. The valid values are:
 +
diff --git a/builtin/repo.c b/builtin/repo.c
index aada476e1c..3c9140593b 100644
--- a/builtin/repo.c
+++ b/builtin/repo.c
@@ -6,6 +6,7 @@
 #include "quote.h"
 #include "refs.h"
 #include "strbuf.h"
+#include "shallow.h"
 
 static const char *const repo_usage[] = {
 	"git repo info [<key>...]",
@@ -25,6 +26,13 @@ static int get_layout_bare(struct repository *repo UNUSED, struct strbuf *buf)
 	return 0;
 }
 
+static int get_layout_shallow(struct repository *repo, struct strbuf *buf)
+{
+	strbuf_addstr(buf,
+		      is_repository_shallow(repo) ? "true" : "false");
+	return 0;
+}
+
 static int get_references_format(struct repository *repo, struct strbuf *buf)
 {
 	strbuf_addstr(buf,
@@ -35,6 +43,7 @@ static int get_references_format(struct repository *repo, struct strbuf *buf)
 /* repo_info_fields keys must be in lexicographical order */
 static const struct field repo_info_fields[] = {
 	{ "layout.bare", get_layout_bare },
+	{ "layout.shallow", get_layout_shallow },
 	{ "references.format", get_references_format },
 };
 
diff --git a/t/t1900-repo.sh b/t/t1900-repo.sh
index b0438d276e..6a9cbf3d47 100755
--- a/t/t1900-repo.sh
+++ b/t/t1900-repo.sh
@@ -44,6 +44,19 @@ test_repo_info 'bare repository = false is retrieved correctly' \
 test_repo_info 'bare repository = true is retrieved correctly' \
 	'git init --bare' 'bare' 'layout.bare' 'true'
 
+test_repo_info 'shallow repository = false is retrieved correctly' \
+	'git init' 'nonshallow' 'layout.shallow' 'false'
+
+test_expect_success 'setup remote' '
+	git init remote &&
+	echo x >remote/x &&
+	git -C remote add x &&
+	git -C remote commit -m x
+'
+
+test_repo_info 'shallow repository = true is retrieved correctly' \
+	'git clone --depth 1 "file://$PWD/remote"' 'shallow' 'layout.shallow' 'true'
+
 test_expect_success 'values returned in order requested' '
 	cat >expect <<-\EOF &&
 	layout.bare=false
-- 
2.39.5 (Apple Git-154)
^ permalink raw reply related	[flat|nested] 226+ messages in thread
* [GSoC PATCH v11 5/5] repo: add the --format flag
  2025-08-16 22:45 ` [GSoC PATCH v11 0/5] repo: declare the repo command Lucas Seiki Oshiro
                     ` (3 preceding siblings ...)
  2025-08-16 22:46   ` [GSoC PATCH v11 4/5] repo: add the field layout.shallow Lucas Seiki Oshiro
@ 2025-08-16 22:46   ` Lucas Seiki Oshiro
  2025-08-17 16:21   ` [GSoC PATCH v11 0/5] repo: declare the repo command Junio C Hamano
  5 siblings, 0 replies; 226+ messages in thread
From: Lucas Seiki Oshiro @ 2025-08-16 22:46 UTC (permalink / raw)
  To: git
  Cc: oswald.buddenhagen, ps, karthik.188, ben.knoble, gitster,
	phillip.wood, jltobler, jn.avila, sunshine, Lucas Seiki Oshiro
Add the --format flag to git-repo-info. By using this flag, the users
can choose the format for obtaining the data they requested.
Given that this command can be used for generating input for other
applications and for being read by end users, it requires at least two
formats: one for being read by humans and other for being read by
machines. Some other Git commands also have two output formats, notably
git-config which was the inspiration for the two formats that were
chosen here:
- keyvalue, where the retrieved data is printed one per line, using =
  for delimiting the key and the value. This is the default format,
  targeted for end users.
- nul, where the retrieved data is separated by NUL characters, using
  the newline character for delimiting the key and the value. This
  format is targeted for being read by machines.
Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Helped-by: Junio C Hamano <gitster@pobox.com>
Helped-by: Justin Tobler <jltobler@gmail.com>
Helped-by: Eric Sunshine <sunshine@sunshineco.com>
Mentored-by: Karthik Nayak <karthik.188@gmail.com>
Mentored-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
---
 Documentation/git-repo.adoc | 40 ++++++++++++++++++++++++++------
 builtin/repo.c              | 46 ++++++++++++++++++++++++++++++++-----
 t/t1900-repo.sh             | 18 ++++++++++++---
 3 files changed, 88 insertions(+), 16 deletions(-)
diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc
index 01b7f9c95e..2870828d93 100644
--- a/Documentation/git-repo.adoc
+++ b/Documentation/git-repo.adoc
@@ -8,7 +8,7 @@ git-repo - Retrieve information about the repository
 SYNOPSIS
 --------
 [synopsis]
-git repo info [<key>...]
+git repo info [--format=(keyvalue|nul)] [<key>...]
 
 DESCRIPTION
 -----------
@@ -18,7 +18,7 @@ THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOR MAY CHANGE.
 
 COMMANDS
 --------
-`info [<key>...]`::
+`info [--format=(keyvalue|nul)] [<key>...]`::
 	Retrieve metadata-related information about the current repository. Only
 	the requested data will be returned based on their keys (see "INFO KEYS"
 	section below).
@@ -26,14 +26,23 @@ COMMANDS
 The values are returned in the same order in which their respective keys were
 requested.
 +
-The output format consists of key-value pairs one per line using the `=`
-character as the delimiter between the key and the value. Values containing
-"unusual" characters are quoted as explained for the configuration variable
-`core.quotePath` (see linkgit:git-config[1]).
+The output format can be chosen through the flag `--format`. Two formats are
+supported:
++
+`keyvalue`:::
+	output key-value pairs one per line using the `=` character as
+	the delimiter between the key and the value. Values containing "unusual"
+	characters are quoted as explained for the configuration variable
+	`core.quotePath` (see linkgit:git-config[1]). This is the default.
+
+`nul`:::
+	similar to `keyvalue`, but using a newline character as the delimiter
+	between the key and the value and using a NUL character after each value.
+	This format is better suited for being parsed by another applications than
+	`keyvalue`. Unlike in the `keyvalue` format, the values are never quoted.
 
 INFO KEYS
 ---------
-
 In order to obtain a set of values from `git repo info`, you should provide
 the keys that identify them. Here's a list of the available keys and the
 values that they return:
@@ -49,6 +58,23 @@ values that they return:
 +
 include::ref-storage-format.adoc[]
 
+EXAMPLES
+--------
+
+* Retrieves the reference format of the current repository:
++
+------------
+git repo info references.format
+------------
++
+
+* Retrieves whether the current repository is bare and whether it is shallow
+using the `nul` format:
++
+------------
+git repo info --format=nul layout.bare layout.shallow
+------------
+
 SEE ALSO
 --------
 linkgit:git-rev-parse[1]
diff --git a/builtin/repo.c b/builtin/repo.c
index 3c9140593b..8c6e7f42ab 100644
--- a/builtin/repo.c
+++ b/builtin/repo.c
@@ -9,12 +9,17 @@
 #include "shallow.h"
 
 static const char *const repo_usage[] = {
-	"git repo info [<key>...]",
+	"git repo info [--format=(keyvalue|nul)] [<key>...]",
 	NULL
 };
 
 typedef int get_value_fn(struct repository *repo, struct strbuf *buf);
 
+enum output_format {
+	FORMAT_KEYVALUE,
+	FORMAT_NUL_TERMINATED,
+};
+
 struct field {
 	const char *key;
 	get_value_fn *get_value;
@@ -65,7 +70,9 @@ static get_value_fn *get_value_fn_for_key(const char *key)
 	return found ? found->get_value : NULL;
 }
 
-static int print_fields(int argc, const char **argv, struct repository *repo)
+static int print_fields(int argc, const char **argv,
+			struct repository *repo,
+			enum output_format format)
 {
 	int ret = 0;
 	struct strbuf valbuf = STRBUF_INIT;
@@ -86,8 +93,18 @@ static int print_fields(int argc, const char **argv, struct repository *repo)
 		strbuf_reset("buf);
 
 		get_value(repo, &valbuf);
-		quote_c_style(valbuf.buf, "buf, NULL, 0);
-		printf("%s=%s\n", key, quotbuf.buf);
+
+		switch (format) {
+		case FORMAT_KEYVALUE:
+			quote_c_style(valbuf.buf, "buf, NULL, 0);
+			printf("%s=%s\n", key, quotbuf.buf);
+			break;
+		case FORMAT_NUL_TERMINATED:
+			printf("%s\n%s%c", key, valbuf.buf, '\0');
+			break;
+		default:
+			BUG("not a valid output format: %d", format);
+		}
 	}
 
 	strbuf_release(&valbuf);
@@ -95,10 +112,27 @@ static int print_fields(int argc, const char **argv, struct repository *repo)
 	return ret;
 }
 
-static int repo_info(int argc, const char **argv, const char *prefix UNUSED,
+static int repo_info(int argc, const char **argv, const char *prefix,
 		     struct repository *repo)
 {
-	return print_fields(argc - 1, argv + 1, repo);
+	const char *format_str = "keyvalue";
+	enum output_format format;
+	struct option options[] = {
+		OPT_STRING(0, "format", &format_str, N_("format"),
+			   N_("output format")),
+		OPT_END()
+	};
+
+	argc = parse_options(argc, argv, prefix, options, repo_usage, 0);
+
+	if (!strcmp(format_str, "keyvalue"))
+		format = FORMAT_KEYVALUE;
+	else if (!strcmp(format_str, "nul"))
+		format = FORMAT_NUL_TERMINATED;
+	else
+		die(_("invalid format '%s'"), format_str);
+
+	return print_fields(argc, argv, repo, format);
 }
 
 int cmd_repo(int argc, const char **argv, const char *prefix,
diff --git a/t/t1900-repo.sh b/t/t1900-repo.sh
index 6a9cbf3d47..a69c715357 100755
--- a/t/t1900-repo.sh
+++ b/t/t1900-repo.sh
@@ -25,11 +25,17 @@ test_repo_info () {
 		eval "$init_command $repo_name"
 	'
 
-	test_expect_success "$label" '
-		echo "$key=$expected_value" >expect &&
-		git -C $repo_name repo info "$key" >actual &&
+	test_expect_success "keyvalue: $label" '
+		echo "$key=$expected_value" > expect &&
+		git -C "$repo_name" repo info "$key" >actual &&
 		test_cmp expect actual
 	'
+
+	test_expect_success "nul: $label" '
+		printf "%s\n%s\0" "$key" "$expected_value" >expect &&
+		git -C "$repo_name" repo info --format=nul "$key" >actual &&
+		test_cmp_bin expect actual
+	'
 }
 
 test_repo_info 'ref format files is retrieved correctly' \
@@ -80,4 +86,10 @@ test_expect_success 'git-repo-info outputs data even if there is an invalid fiel
 	test_cmp expect actual
 '
 
+test_expect_success 'git-repo-info aborts when requesting an invalid format' '
+	echo "fatal: invalid format ${SQ}foo${SQ}" >expect &&
+	test_must_fail git repo info --format=foo 2>actual &&
+	test_cmp expect actual
+'
+
 test_done
-- 
2.39.5 (Apple Git-154)
^ permalink raw reply related	[flat|nested] 226+ messages in thread
* Re: [GSoC PATCH v11 0/5] repo: declare the repo command
  2025-08-16 22:45 ` [GSoC PATCH v11 0/5] repo: declare the repo command Lucas Seiki Oshiro
                     ` (4 preceding siblings ...)
  2025-08-16 22:46   ` [GSoC PATCH v11 5/5] repo: add the --format flag Lucas Seiki Oshiro
@ 2025-08-17 16:21   ` Junio C Hamano
  5 siblings, 0 replies; 226+ messages in thread
From: Junio C Hamano @ 2025-08-17 16:21 UTC (permalink / raw)
  To: Lucas Seiki Oshiro
  Cc: git, oswald.buddenhagen, ps, karthik.188, ben.knoble,
	phillip.wood, jltobler, jn.avila, sunshine
Lucas Seiki Oshiro <lucasseikioshiro@gmail.com> writes:
>      +The output format can be chosen through the flag `--format`. Two formats are
>      +supported:
>      ++
>     ++`keyvalue`:::
>     ++	output key-value pairs one per line using the `=` character as
Earlier I suggested to use ';;' out of habit, but using ':::' seems
to be more kosher, according to
    https://docs.asciidoctor.org/asciidoc/latest/lists/description/
Thanks for sticking to the best practice.
Let's mark the topic for 'next', unless no further changes are
needed.
Thanks.
^ permalink raw reply	[flat|nested] 226+ messages in thread
end of thread, other threads:[~2025-08-17 16:21 UTC | newest]
Thread overview: 226+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-06-10 15:21 [GSoC RFC PATCH 0/5] repo-info: add new command for retrieving repository info Lucas Seiki Oshiro
2025-06-10 15:21 ` [GSoC RFC PATCH 1/5] repo-info: declare the repo-info command Lucas Seiki Oshiro
2025-06-11  8:59   ` Karthik Nayak
2025-06-10 15:21 ` [GSoC RFC PATCH 2/5] repo-info: add the --format flag Lucas Seiki Oshiro
2025-06-11  9:30   ` Karthik Nayak
2025-06-12 17:56     ` Lucas Seiki Oshiro
2025-06-13  7:31       ` Karthik Nayak
2025-06-10 15:21 ` [GSoC RFC PATCH 3/5] repo-info: add the field references.format Lucas Seiki Oshiro
2025-06-11 12:59   ` Karthik Nayak
2025-06-12 15:01     ` Junio C Hamano
2025-06-10 15:21 ` [GSoC RFC PATCH 4/5] repo-info: add field layout.bare Lucas Seiki Oshiro
2025-06-11 13:13   ` Karthik Nayak
2025-06-12 19:39     ` Lucas Seiki Oshiro
2025-06-12 19:53       ` Junio C Hamano
2025-06-10 15:21 ` [GSoC RFC PATCH 5/5] repo-info: add field layout.shallow Lucas Seiki Oshiro
2025-06-10 16:39 ` [GSoC RFC PATCH 0/5] repo-info: add new command for retrieving repository info Kristoffer Haugsbakk
2025-06-10 16:40 ` Junio C Hamano
2025-06-12 20:25   ` Lucas Seiki Oshiro
2025-06-12 21:01     ` Junio C Hamano
2025-06-16 22:19       ` Lucas Seiki Oshiro
2025-06-16 22:40         ` Junio C Hamano
2025-06-19  1:44           ` Lucas Seiki Oshiro
2025-06-11 13:17 ` Karthik Nayak
2025-06-19 22:57 ` [GSoC RFC PATCH v2 0/7] " Lucas Seiki Oshiro
2025-06-19 22:57   ` [GSoC RFC PATCH v2 1/7] repo-info: declare the repo-info command Lucas Seiki Oshiro
2025-06-20  7:36     ` Karthik Nayak
2025-06-20 23:55       ` Junio C Hamano
2025-06-23  9:19         ` Karthik Nayak
2025-06-23 19:04       ` Lucas Seiki Oshiro
2025-06-20  7:56     ` Karthik Nayak
2025-06-24 14:03     ` Phillip Wood
2025-07-03 11:31     ` Patrick Steinhardt
2025-07-04 21:40       ` Lucas Seiki Oshiro
2025-07-07  6:01         ` Patrick Steinhardt
2025-07-09 20:05           ` Justin Tobler
2025-06-19 22:57   ` [GSoC RFC PATCH v2 2/7] repo-info: add the --format flag Lucas Seiki Oshiro
2025-06-20  8:06     ` Karthik Nayak
2025-06-20 21:31     ` Junio C Hamano
2025-07-03 11:31     ` Patrick Steinhardt
2025-06-19 22:57   ` [GSoC RFC PATCH v2 3/7] repo-info: add plaintext as an output format Lucas Seiki Oshiro
2025-06-20 21:37     ` Junio C Hamano
2025-07-03 11:32     ` Patrick Steinhardt
2025-06-19 22:57   ` [GSoC RFC PATCH v2 4/7] repo-info: add the --allow-empty flag Lucas Seiki Oshiro
2025-06-20  9:54     ` Karthik Nayak
2025-06-23  2:39       ` Lucas Seiki Oshiro
2025-06-20 21:39     ` Junio C Hamano
2025-06-23  9:26       ` Karthik Nayak
2025-06-23 20:28         ` Lucas Seiki Oshiro
2025-06-19 22:57   ` [GSoC RFC PATCH v2 5/7] repo-info: add the field references.format Lucas Seiki Oshiro
2025-06-20 22:26     ` Junio C Hamano
2025-06-24 14:03     ` Phillip Wood
2025-06-24 15:25       ` Junio C Hamano
2025-06-25  8:40         ` Phillip Wood
2025-07-03 11:32     ` Patrick Steinhardt
2025-07-04 21:11       ` Lucas Seiki Oshiro
2025-06-19 22:57   ` [GSoC RFC PATCH v2 6/7] repo-info: add field layout.bare Lucas Seiki Oshiro
2025-07-03 11:32     ` Patrick Steinhardt
2025-07-03 14:14       ` Lucas Seiki Oshiro
2025-07-04  8:32         ` Phillip Wood
2025-06-19 22:57   ` [GSoC RFC PATCH v2 7/7] repo-info: add field layout.shallow Lucas Seiki Oshiro
2025-06-23 13:42   ` [GSoC RFC PATCH v2 0/7] repo-info: add new command for retrieving repository info Phillip Wood
2025-06-23 18:49     ` Lucas Seiki Oshiro
2025-06-24 13:03       ` Phillip Wood
2025-06-24 13:43         ` Junio C Hamano
2025-07-01 22:18         ` Lucas Seiki Oshiro
2025-07-02  9:10           ` phillip.wood123
2025-07-06 23:19 ` [GSoC RFC PATCH v3 0/5] " Lucas Seiki Oshiro
2025-07-06 23:19   ` [GSoC RFC PATCH v3 1/5] repo-info: declare the repo-info command Lucas Seiki Oshiro
2025-07-06 23:19   ` [GSoC RFC PATCH v3 2/5] repo-info: add the --format flag Lucas Seiki Oshiro
2025-07-06 23:19   ` [GSoC RFC PATCH v3 3/5] repo-info: add the field references.format Lucas Seiki Oshiro
2025-07-06 23:19   ` [GSoC RFC PATCH v3 4/5] repo-info: add field layout.bare Lucas Seiki Oshiro
2025-07-06 23:19   ` [GSoC RFC PATCH v3 5/5] repo-info: add field layout.shallow Lucas Seiki Oshiro
2025-07-08 10:11   ` [GSoC RFC PATCH v3 0/5] repo-info: add new command for retrieving repository info Phillip Wood
2025-07-08 19:27     ` Lucas Seiki Oshiro
2025-07-10 13:15       ` Phillip Wood
2025-07-11 17:13   ` Lucas Seiki Oshiro
2025-07-11 17:37     ` Justin Tobler
2025-07-14 23:52 ` [GSoC RFC PATCH v4 0/4] repo: " Lucas Seiki Oshiro
2025-07-14 23:52   ` [GSoC RFC PATCH v4 1/4] repo: declare the repo command Lucas Seiki Oshiro
2025-07-15 11:52     ` Karthik Nayak
2025-07-15 11:59     ` Patrick Steinhardt
2025-07-15 18:38       ` Justin Tobler
2025-07-20 19:51       ` Lucas Seiki Oshiro
2025-07-15 18:19     ` Justin Tobler
2025-07-14 23:52   ` [GSoC RFC PATCH v4 2/4] repo: add the field references.format Lucas Seiki Oshiro
2025-07-15 11:59     ` Patrick Steinhardt
2025-07-18 19:13       ` Lucas Seiki Oshiro
2025-07-15 12:23     ` Karthik Nayak
2025-07-15 19:15     ` Justin Tobler
2025-07-16  5:38       ` Patrick Steinhardt
2025-07-16 14:04         ` Justin Tobler
2025-07-17 13:03           ` Patrick Steinhardt
2025-07-17 16:06             ` Justin Tobler
2025-07-18 20:26               ` Lucas Seiki Oshiro
2025-07-21 14:41                 ` Justin Tobler
2025-07-14 23:52   ` [GSoC RFC PATCH v4 3/4] repo: add field layout.bare Lucas Seiki Oshiro
2025-07-14 23:52   ` [GSoC RFC PATCH v4 4/4] repo: add field layout.shallow Lucas Seiki Oshiro
2025-07-15 10:34   ` [GSoC RFC PATCH v4 0/4] repo: add new command for retrieving repository info Oswald Buddenhagen
2025-07-15 11:58     ` Patrick Steinhardt
2025-07-15 12:20       ` Oswald Buddenhagen
2025-07-15 19:36       ` Justin Tobler
2025-07-15 16:49     ` Junio C Hamano
2025-07-17 10:25       ` Oswald Buddenhagen
2025-07-17 10:42         ` Patrick Steinhardt
2025-07-16 20:20   ` Junio C Hamano
2025-07-16 20:33     ` Junio C Hamano
2025-07-21 22:05     ` Lucas Seiki Oshiro
2025-07-22  0:28 ` [GSoC PATCH v5 0/5] " Lucas Seiki Oshiro
2025-07-22  0:28   ` [GSoC PATCH v5 1/5] repo: declare the repo command Lucas Seiki Oshiro
2025-07-22  9:03     ` Karthik Nayak
2025-07-22 15:21       ` Junio C Hamano
2025-07-23 16:28         ` Lucas Seiki Oshiro
2025-07-23 17:48           ` Junio C Hamano
2025-07-24  6:22         ` Patrick Steinhardt
2025-07-24 16:06           ` Junio C Hamano
2025-07-25  5:10             ` Patrick Steinhardt
2025-07-26 21:54           ` Lucas Seiki Oshiro
2025-07-28 17:56             ` Junio C Hamano
2025-07-23 15:49       ` Lucas Seiki Oshiro
2025-07-23 20:03     ` Jean-Noël AVILA
2025-07-22  0:28   ` [GSoC PATCH v5 2/5] repo: add the field references.format Lucas Seiki Oshiro
2025-07-22  9:16     ` Karthik Nayak
2025-07-22 19:25     ` Justin Tobler
2025-07-23 14:53       ` Phillip Wood
2025-07-23 17:44         ` Lucas Seiki Oshiro
2025-07-23 18:26       ` Lucas Seiki Oshiro
2025-07-24  6:22     ` Patrick Steinhardt
2025-07-22  0:28   ` [GSoC PATCH v5 3/5] repo: add field layout.bare Lucas Seiki Oshiro
2025-07-22  0:28   ` [GSoC PATCH v5 4/5] repo: add field layout.shallow Lucas Seiki Oshiro
2025-07-22  0:28   ` [GSoC PATCH v5 5/5] repo: add the --format flag Lucas Seiki Oshiro
2025-07-22  9:26     ` Karthik Nayak
2025-07-24  6:22     ` Patrick Steinhardt
2025-07-27 17:51 ` [GSoC PATCH v5 0/5] repo: add new command for retrieving repository info Lucas Seiki Oshiro
2025-07-27 17:51   ` [GSoC PATCH v5 1/5] repo: declare the repo command Lucas Seiki Oshiro
2025-07-27 20:20     ` Eric Sunshine
2025-07-27 17:51   ` [GSoC PATCH v5 2/5] repo: add the field references.format Lucas Seiki Oshiro
2025-07-27 21:16     ` Eric Sunshine
2025-07-31 19:39       ` Lucas Seiki Oshiro
2025-07-29  9:35     ` Patrick Steinhardt
2025-07-31 19:49       ` Lucas Seiki Oshiro
2025-07-27 17:51   ` [GSoC PATCH v5 3/5] repo: add field layout.bare Lucas Seiki Oshiro
2025-07-27 17:51   ` [GSoC PATCH v5 4/5] repo: add field layout.shallow Lucas Seiki Oshiro
2025-07-27 21:45     ` Eric Sunshine
2025-07-27 17:51   ` [GSoC PATCH v5 5/5] repo: add the --format flag Lucas Seiki Oshiro
2025-07-27 22:02     ` Eric Sunshine
2025-07-29  0:15       ` Ben Knoble
2025-07-29  0:27         ` Eric Sunshine
2025-07-29  0:38           ` Ben Knoble
2025-07-29  0:39           ` Eric Sunshine
2025-07-31 23:01       ` Lucas Seiki Oshiro
2025-07-31 23:15     ` Lucas Seiki Oshiro
2025-07-27 20:11   ` [GSoC PATCH v5 0/5] repo: add new command for retrieving repository info Eric Sunshine
2025-07-29  9:35     ` Patrick Steinhardt
2025-07-30 15:26     ` Lucas Seiki Oshiro
2025-08-01 13:11 ` [GSoC PATCH v7 " Lucas Seiki Oshiro
2025-08-01 13:11   ` [GSoC PATCH v7 1/5] repo: declare the repo command Lucas Seiki Oshiro
2025-08-01 13:11   ` [GSoC PATCH v7 2/5] repo: add the field references.format Lucas Seiki Oshiro
2025-08-01 20:59     ` Eric Sunshine
2025-08-03 21:47       ` Lucas Seiki Oshiro
2025-08-01 13:11   ` [GSoC PATCH v7 3/5] repo: add the field layout.bare Lucas Seiki Oshiro
2025-08-01 21:21     ` Eric Sunshine
2025-08-03 22:54       ` Lucas Seiki Oshiro
2025-08-03 23:06         ` Eric Sunshine
2025-08-05 12:50     ` Patrick Steinhardt
2025-08-01 13:11   ` [GSoC PATCH v7 4/5] repo: add the field layout.shallow Lucas Seiki Oshiro
2025-08-05 12:50     ` Patrick Steinhardt
2025-08-01 13:11   ` [GSoC PATCH v7 5/5] repo: add the --format flag Lucas Seiki Oshiro
2025-08-01 19:25     ` Junio C Hamano
2025-08-01 20:27     ` Jean-Noël AVILA
2025-08-01 21:50     ` Eric Sunshine
2025-08-05 12:50     ` Patrick Steinhardt
2025-08-05 12:50   ` [GSoC PATCH v7 0/5] repo: add new command for retrieving repository info Patrick Steinhardt
2025-08-06 19:55 ` [GSoC PATCH v8 " Lucas Seiki Oshiro
2025-08-06 19:55   ` [GSoC PATCH v8 1/5] repo: declare the repo command Lucas Seiki Oshiro
2025-08-06 19:55   ` [GSoC PATCH v8 2/5] repo: add the field references.format Lucas Seiki Oshiro
2025-08-07  7:43     ` Karthik Nayak
2025-08-06 19:55   ` [GSoC PATCH v8 3/5] repo: add the field layout.bare Lucas Seiki Oshiro
2025-08-07  5:20     ` Patrick Steinhardt
2025-08-06 19:55   ` [GSoC PATCH v8 4/5] repo: add the field layout.shallow Lucas Seiki Oshiro
2025-08-06 19:55   ` [GSoC PATCH v8 5/5] repo: add the --format flag Lucas Seiki Oshiro
2025-08-07  5:20     ` Patrick Steinhardt
2025-08-07 15:44       ` Junio C Hamano
2025-08-06 22:38   ` [GSoC PATCH v8 0/5] repo: add new command for retrieving repository info Junio C Hamano
2025-08-07  7:48   ` Karthik Nayak
2025-08-07 15:02 ` [GSoC PATCH v9 " Lucas Seiki Oshiro
2025-08-07 15:02   ` [GSoC PATCH v9 1/5] repo: declare the repo command Lucas Seiki Oshiro
2025-08-07 15:02   ` [GSoC PATCH v9 2/5] repo: add the field references.format Lucas Seiki Oshiro
2025-08-11  5:12     ` Eric Sunshine
2025-08-11 14:41     ` Phillip Wood
2025-08-11 15:44       ` Junio C Hamano
2025-08-13 21:18       ` Lucas Seiki Oshiro
2025-08-13 21:46         ` Eric Sunshine
2025-08-13 22:24           ` Lucas Seiki Oshiro
2025-08-14 13:58           ` Phillip Wood
2025-08-07 15:02   ` [GSoC PATCH v9 3/5] repo: add the field layout.bare Lucas Seiki Oshiro
2025-08-11  5:21     ` Eric Sunshine
2025-08-14 18:22       ` Lucas Seiki Oshiro
2025-08-14 18:32         ` Eric Sunshine
2025-08-14 18:51           ` Junio C Hamano
2025-08-14 22:05             ` Eric Sunshine
2025-08-15  1:20               ` Junio C Hamano
2025-08-14 22:18             ` Lucas Seiki Oshiro
2025-08-14 23:41               ` Eric Sunshine
2025-08-07 15:02   ` [GSoC PATCH v9 4/5] repo: add the field layout.shallow Lucas Seiki Oshiro
2025-08-07 15:02   ` [GSoC PATCH v9 5/5] repo: add the --format flag Lucas Seiki Oshiro
2025-08-11  5:44     ` Eric Sunshine
2025-08-08  5:45   ` [GSoC PATCH v9 0/5] repo: add new command for retrieving repository info Patrick Steinhardt
2025-08-08 15:02     ` Junio C Hamano
2025-08-08  9:20   ` Karthik Nayak
2025-08-15 13:55 ` [GSoC PATCH v10 0/5] repo: declare the repo command Lucas Seiki Oshiro
2025-08-15 13:55   ` [GSoC PATCH v10 1/5] " Lucas Seiki Oshiro
2025-08-15 13:55   ` [GSoC PATCH v10 2/5] repo: add the field references.format Lucas Seiki Oshiro
2025-08-15 18:40     ` Junio C Hamano
2025-08-15 19:12       ` Lucas Seiki Oshiro
2025-08-15 13:55   ` [GSoC PATCH v10 3/5] repo: add the field layout.bare Lucas Seiki Oshiro
2025-08-15 13:55   ` [GSoC PATCH v10 4/5] repo: add the field layout.shallow Lucas Seiki Oshiro
2025-08-15 19:36     ` Junio C Hamano
2025-08-15 13:55   ` [GSoC PATCH v10 5/5] repo: add the --format flag Lucas Seiki Oshiro
2025-08-15 19:23     ` Junio C Hamano
2025-08-16 22:45 ` [GSoC PATCH v11 0/5] repo: declare the repo command Lucas Seiki Oshiro
2025-08-16 22:45   ` [GSoC PATCH v11 1/5] " Lucas Seiki Oshiro
2025-08-16 22:46   ` [GSoC PATCH v11 2/5] repo: add the field references.format Lucas Seiki Oshiro
2025-08-16 22:46   ` [GSoC PATCH v11 3/5] repo: add the field layout.bare Lucas Seiki Oshiro
2025-08-16 22:46   ` [GSoC PATCH v11 4/5] repo: add the field layout.shallow Lucas Seiki Oshiro
2025-08-16 22:46   ` [GSoC PATCH v11 5/5] repo: add the --format flag Lucas Seiki Oshiro
2025-08-17 16:21   ` [GSoC PATCH v11 0/5] repo: declare the repo command Junio C Hamano
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 NNTP newsgroup(s).