* [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; 3+ 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] 3+ messages in thread
* Re: [GSoC Patch] repo: support category-based prefix querying for info keys
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
2026-07-12 2:52 ` K Jayatheerth
0 siblings, 1 reply; 3+ messages in thread
From: Junio C Hamano @ 2026-07-03 22:49 UTC (permalink / raw)
To: K Jayatheerth; +Cc: git, jltobler, lucasseikioshiro
K Jayatheerth <jayatheerthkulkarni2005@gmail.com> writes:
> 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
You mean "repo info" takes layout.bare and layout.shallow (right
now, later we may gain a lot more), so you want to say "everything
under 'layout' to grab these two values?
Why should we limit ourselves to "prefix match"? Would a glob like
"layout.*", or "path.*.absolute", work better? Especially the
latter, i.e., "I want the path variables, but am not interested in
their .relative values, only the .absolute ones." It is especially
puzzling as you are going to do a dumb linear search in this mode
anyway.
Perhaps during each iteration of the loop over argv[], you can first
look for exact match using the existing bsearch() codepath. If that
succeeds, you have a single key to return the value for. If it does
not match exactly any key, use the new "prefix" (or "glob" which I
think would make far more sense) match codepath to find which key(s)
to return values for, so iterate over them (or say "Hey, that pattern
does not match any key!" and fail).
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [GSoC Patch] repo: support category-based prefix querying for info keys
2026-07-03 22:49 ` Junio C Hamano
@ 2026-07-12 2:52 ` K Jayatheerth
0 siblings, 0 replies; 3+ messages in thread
From: K Jayatheerth @ 2026-07-12 2:52 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git, jltobler, lucasseikioshiro
Hey Junio,
On Sat, Jul 4, 2026 at 4:19 AM Junio C Hamano <gitster@pobox.com> wrote:
>
> You mean "repo info" takes layout.bare and layout.shallow (right
> now, later we may gain a lot more), so you want to say "everything
> under 'layout' to grab these two values?
>
> Why should we limit ourselves to "prefix match"? Would a glob like
> "layout.*", or "path.*.absolute", work better? Especially the
> latter, i.e., "I want the path variables, but am not interested in
> their .relative values, only the .absolute ones." It is especially
> puzzling as you are going to do a dumb linear search in this mode
> anyway.
>
> Perhaps during each iteration of the loop over argv[], you can first
> look for exact match using the existing bsearch() codepath. If that
> succeeds, you have a single key to return the value for. If it does
> not match exactly any key, use the new "prefix" (or "glob" which I
> think would make far more sense) match codepath to find which key(s)
> to return values for, so iterate over them (or say "Hey, that pattern
> does not match any key!" and fail).
Sorry this response took a long time but I have given a good thought about this
You are right that adding globs makes much more sense in this case.
I was initially skeptical about globs, but looking at the direction we took
in path.* keys it makes much more sense.
But I think adding a query system is not a good idea anymore.
I have discussed this with my mentors at length.
Since we are building a plumbing command, we couldn't think of a use-case where
people would need globs over hard-coded value in scripts.
Also globing might introduce uncertainties if the script doesn't have
an appropriate fall back.
I am also wondering if there will be any significant performance difference
with --all vs globs.
A query system in itself is meant to simplify commands for user usage,
but I don't think adding it makes sense "yet".
I also wanted your opinion on this
For my GSoC I can pick the histograms patch in the git repo structure
instead of this.
Regards,
- K Jayatheerth
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-07-12 2:52 UTC | newest]
Thread overview: 3+ 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
2026-07-12 2:52 ` K Jayatheerth
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.