Git development
 help / color / mirror / Atom feed
* [GSoC Patch] repo: support category-based prefix querying for info keys
@ 2026-07-03 16:47 K Jayatheerth
  2026-07-03 22:49 ` Junio C Hamano
  0 siblings, 1 reply; 2+ messages in thread
From: K Jayatheerth @ 2026-07-03 16:47 UTC (permalink / raw)
  To: git; +Cc: jltobler, lucasseikioshiro, K Jayatheerth

Currently, git repo info relies on an all-or-nothing query model
where users must either know the exact, fully-qualified key name or use
the --all flag to dump the entire repository state.
As the number of supported keys expands, dumping all metadata and
relying on external filters like grep becomes an inefficient bottleneck
for a plumbing command.

Enable category-based prefix querying so users can request
entire groups of related keys natively

Mentored-by: Justin Tobler <jltobler@gmail.com>
Mentored-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
Signed-off-by: K Jayatheerth <jayatheerthkulkarni2005@gmail.com>
---
Hi!

This patch adds category-based prefix querying to
`git repo info` as part of my GSoC project.
A quick note on the implementation: I replaced the `bsearch` with
a linear search to find the initial prefix match.
I discussed this with my mentors, and we decided to fall back
to a linear search because the overhead of a custom binary search
(to find the *first* match in a block) wasn't justified given
the currently small size of the `repo_info_field` array.

Since the array is strictly sorted alphabetically,
the loop safely short-circuits via `strncmp`
once it steps outside the matching prefix block.

Looking forward to feedback!

 Documentation/git-repo.adoc | 12 ++++++++
 builtin/repo.c              | 58 +++++++++++++++++++++++--------------
 t/t1900-repo-info.sh        | 16 ++++++++++
 3 files changed, 64 insertions(+), 22 deletions(-)

diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc
index 42262c1983..3e840d6323 100644
--- a/Documentation/git-repo.adoc
+++ b/Documentation/git-repo.adoc
@@ -25,6 +25,12 @@ COMMANDS
 	the requested data will be returned based on their keys (see "INFO KEYS"
 	section below).
 +
+If a `<key>` argument matches a category prefix (i.e. a namespace that ends at
+a `.` boundary), all keys within that namespace are returned. For example,
+`layout` returns both `layout.bare` and `layout.shallow`. The prefix must
+align with a namespace boundary; partial prefixes that do not end at a `.`
+separator (e.g. `lay`) are treated as unknown keys and will produce an error.
++
 The values are returned in the same order in which their respective keys were
 requested. The `--all` flag requests the values for all the available keys.
 +
@@ -126,6 +132,12 @@ using the `nul` format:
 git repo info --format=nul layout.bare layout.shallow
 ------------
 
+* Retrieves all keys under the `layout` category prefix:
++
+------------
+git repo info layout
+------------
+
 SEE ALSO
 --------
 linkgit:git-rev-parse[1]
diff --git a/builtin/repo.c b/builtin/repo.c
index 71a5c1c29c..91ea5b5459 100644
--- a/builtin/repo.c
+++ b/builtin/repo.c
@@ -90,24 +90,27 @@ static const struct repo_info_field repo_info_field[] = {
 	{ "references.format", get_references_format },
 };
 
-static int repo_info_field_cmp(const void *va, const void *vb)
+static int is_valid_prefix_match(const char *key, const char *prefix)
 {
-	const struct repo_info_field *a = va;
-	const struct repo_info_field *b = vb;
+	size_t prefix_len = strlen(prefix);
 
-	return strcmp(a->key, b->key);
+	if (!prefix_len)
+		return 0;
+
+	if (strncmp(key, prefix, prefix_len))
+		return 0;
+
+	return key[prefix_len] == '\0' || prefix[prefix_len - 1] == '.' || key[prefix_len] == '.';
 }
 
-static const struct repo_info_field *get_repo_info_field(const char *key)
+static size_t find_first_repo_info_field_match(const char *prefix)
 {
-	const struct repo_info_field search_key = { key, NULL };
-	const struct repo_info_field *found = bsearch(&search_key,
-						      repo_info_field,
-						      ARRAY_SIZE(repo_info_field),
-						      sizeof(*found),
-						      repo_info_field_cmp);
-
-	return found;
+	for (size_t i = 0; i < ARRAY_SIZE(repo_info_field); i++) {
+		if (is_valid_prefix_match(repo_info_field[i].key, prefix)) {
+			return i;
+		}
+	}
+	return SIZE_MAX;
 }
 
 static void print_field(enum output_format format, const char *key,
@@ -135,17 +138,28 @@ static int print_fields(int argc, const char **argv,
 	struct strbuf valbuf = STRBUF_INIT;
 
 	for (int i = 0; i < argc; i++) {
-		const char *key = argv[i];
-		const struct repo_info_field *field = get_repo_info_field(key);
-
-		if (!field) {
-			ret = error(_("key '%s' not found"), key);
-			continue;
+		const char *prefix = argv[i];
+		size_t prefix_len = strlen(prefix);
+		size_t idx = find_first_repo_info_field_match(prefix);
+		int found = 0;
+
+		for (; idx < ARRAY_SIZE(repo_info_field); idx++) {
+			const struct repo_info_field *field = &repo_info_field[idx];
+
+			if (strncmp(field->key, prefix, prefix_len))
+				break;
+
+			if (is_valid_prefix_match(field->key, prefix)) {
+				strbuf_reset(&valbuf);
+				field->get_value(repo, &valbuf);
+				print_field(format, field->key, valbuf.buf);
+				found = 1;
+			}
 		}
 
-		strbuf_reset(&valbuf);
-		field->get_value(repo, &valbuf);
-		print_field(format, key, valbuf.buf);
+		if (!found) {
+			ret = error(_("key '%s' not found"), prefix);
+		}
 	}
 
 	strbuf_release(&valbuf);
diff --git a/t/t1900-repo-info.sh b/t/t1900-repo-info.sh
index 39bb77dda0..80ae8f8396 100755
--- a/t/t1900-repo-info.sh
+++ b/t/t1900-repo-info.sh
@@ -149,6 +149,22 @@ test_expect_success 'git repo info --keys uses lines as its default output forma
 	test_cmp expect actual
 '
 
+test_expect_success 'git repo info with category prefix returns all keys in namespace' '
+	cat >expect <<-\EOF &&
+	layout.bare=false
+	layout.shallow=false
+	EOF
+	git init prefix-repo &&
+	git -C prefix-repo repo info layout >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'git repo info with invalid partial boundary fails' '
+	echo "error: key ${SQ}lay${SQ} not found" >expect &&
+	test_must_fail git -C prefix-repo repo info lay 2>actual &&
+	test_cmp expect actual
+'
+
 test_expect_success 'git repo info -h shows only repo info usage' '
 	test_must_fail git repo info -h >actual &&
 	test_grep "git repo info" actual &&
-- 
2.55.0-rc1

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

end of thread, other threads:[~2026-07-03 22:49 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-03 16:47 [GSoC Patch] repo: support category-based prefix querying for info keys K Jayatheerth
2026-07-03 22:49 ` 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