[GSoC PATCH v7 0/5] repo: add new command for retrieving repository info
From: Lucas Seiki Oshiro <hidden>
Date: 2025-08-01 13:11:22
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 [off-list ref]
Helped-by: Junio C Hamano [off-list ref]
Helped-by: Justin Tobler [off-list ref]
+ Helped-by: Eric Sunshine [off-list ref]
Mentored-by: Karthik Nayak [off-list ref]
Mentored-by: Patrick Steinhardt [off-list ref]
Signed-off-by: Lucas Seiki Oshiro [off-list ref]
@@ 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 [off-list ref]
Helped-by: Junio C Hamano [off-list ref]
Helped-by: Justin Tobler [off-list ref]
+ Helped-by: Eric Sunshine [off-list ref]
Mentored-by: Karthik Nayak [off-list ref]
Mentored-by: Patrick Steinhardt [off-list ref]
Signed-off-by: Lucas Seiki Oshiro [off-list ref]
## 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 [off-list ref]
## 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 [off-list ref]
Helped-by: Junio C Hamano [off-list ref]
Helped-by: Justin Tobler [off-list ref]
+ Helped-by: Eric Sunshine [off-list ref]
Mentored-by: Karthik Nayak [off-list ref]
Mentored-by: Patrick Steinhardt [off-list ref]
Signed-off-by: Lucas Seiki Oshiro [off-list ref]
## 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 [off-list ref]
## 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 [off-list ref]
Helped-by: Junio C Hamano [off-list ref]
Helped-by: Justin Tobler [off-list ref]
+ Helped-by: Eric Sunshine [off-list ref]
Mentored-by: Karthik Nayak [off-list ref]
Mentored-by: Patrick Steinhardt [off-list ref]
Signed-off-by: Lucas Seiki Oshiro [off-list ref]
## 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 [off-list ref]
Helped-by: Junio C Hamano [off-list ref]
Helped-by: Justin Tobler [off-list ref]
+ Helped-by: Eric Sunshine [off-list ref]
Mentored-by: Karthik Nayak [off-list ref]
Mentored-by: Patrick Steinhardt [off-list ref]
Signed-off-by: Lucas Seiki Oshiro [off-list ref]
@@ 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)