GSoC 2026 Week 4: Green Flag and the Query System
With Week 4, the version on the mailing list finally got a green flag from Junio.
There is one final nitpick I have to resolve with the initial flags, but these things take time, we are dealing with the absolute foundation here.
That said, I have started working on the query system.
What is the Query System?
Initially, the problem was that you had to
either get --all the keys, or type
out every individual key yourself.
That was one issue.
The other workaround was to pipe --all
through grep.
While grep works, keep in mind
that this is a plumbing command. It is supposed
to be predictable, and scripts generally prefer
it when the native command itself provides the
correct output format.
This is why we are adding the query system.
Before this, if someone ran:
git repo info layout
It wouldn't work.
With the query system, it prints:
layout.bare=false
layout.shallow=false
Much simpler. And not a lot of code had to change either.
Binary Search vs. Linear Search
This is a single patch that, when merged, will introduce these changes.
My initial implementation used a binary search,
because Lucas had previously used the
bsearch() function, and I now had
to hardcode a custom binary search on top of
that.
After discussing the tradeoffs between hard-to-read code and the number of iterations, a linear search turned out to be the much better option, the opposite of what I had proposed.
Maybe in the future, when the number of keys
grows large enough, a bsearch will
make sense. But for now it is overkill.
Here's the patch using the linear search approach:
View Patch: repo: support category-based prefix querying for info keys
Subject: [GSoC Patch] repo: support category-based prefix querying for info
keys
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>
---
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
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] == ' ' || 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' '
That's my Week 4!