repo: add the --format flag

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> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Lucas Seiki Oshiro committed Aug 16, 2025 at 19:46 UTC a81224d12818e94a2e3c257ee2e5b0f3169da12b
3 files changed +88 -16
Documentation/git-repo.adoc
+33 -7
@@ -8,7 +8,7 @@ git-repo - Retrieve information about the repository
8 SYNOPSIS
9 --------
10 [synopsis]
11 -git repo info [<key>...]
11 +git repo info [--format=(keyvalue|nul)] [<key>...]
12
13 DESCRIPTION
14 -----------
@@ -18,7 +18,7 @@ THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOR MAY CHANGE.
18
19 COMMANDS
20 --------
21 -`info [<key>...]`::
21 +`info [--format=(keyvalue|nul)] [<key>...]`::
22 Retrieve metadata-related information about the current repository. Only
23 the requested data will be returned based on their keys (see "INFO KEYS"
24 section below).
@@ -26,14 +26,23 @@ COMMANDS
26 The values are returned in the same order in which their respective keys were
27 requested.
28 +
29 -The output format consists of key-value pairs one per line using the `=`
30 -character as the delimiter between the key and the value. Values containing
31 -"unusual" characters are quoted as explained for the configuration variable
32 -`core.quotePath` (see linkgit:git-config[1]).
29 +The output format can be chosen through the flag `--format`. Two formats are
30 +supported:
31 ++
32 +`keyvalue`:::
33 + output key-value pairs one per line using the `=` character as
34 + the delimiter between the key and the value. Values containing "unusual"
35 + characters are quoted as explained for the configuration variable
36 + `core.quotePath` (see linkgit:git-config[1]). This is the default.
37 +
38 +`nul`:::
39 + similar to `keyvalue`, but using a newline character as the delimiter
40 + between the key and the value and using a NUL character after each value.
41 + This format is better suited for being parsed by another applications than
42 + `keyvalue`. Unlike in the `keyvalue` format, the values are never quoted.
43
44 INFO KEYS
45 ---------
36 -
46 In order to obtain a set of values from `git repo info`, you should provide
47 the keys that identify them. Here's a list of the available keys and the
48 values that they return:
@@ -49,6 +58,23 @@ values that they return:
58 +
59 include::ref-storage-format.adoc[]
60
61 +EXAMPLES
62 +--------
63 +
64 +* Retrieves the reference format of the current repository:
65 ++
66 +------------
67 +git repo info references.format
68 +------------
69 ++
70 +
71 +* Retrieves whether the current repository is bare and whether it is shallow
72 +using the `nul` format:
73 ++
74 +------------
75 +git repo info --format=nul layout.bare layout.shallow
76 +------------
77 +
78 SEE ALSO
79 --------
80 linkgit:git-rev-parse[1]
builtin/repo.c
+40 -6
@@ -9,12 +9,17 @@
9 #include "shallow.h"
10
11 static const char *const repo_usage[] = {
12 - "git repo info [<key>...]",
12 + "git repo info [--format=(keyvalue|nul)] [<key>...]",
13 NULL
14 };
15
16 typedef int get_value_fn(struct repository *repo, struct strbuf *buf);
17
18 +enum output_format {
19 + FORMAT_KEYVALUE,
20 + FORMAT_NUL_TERMINATED,
21 +};
22 +
23 struct field {
24 const char *key;
25 get_value_fn *get_value;
@@ -65,7 +70,9 @@ static get_value_fn *get_value_fn_for_key(const char *key)
70 return found ? found->get_value : NULL;
71 }
72
68 -static int print_fields(int argc, const char **argv, struct repository *repo)
73 +static int print_fields(int argc, const char **argv,
74 + struct repository *repo,
75 + enum output_format format)
76 {
77 int ret = 0;
78 struct strbuf valbuf = STRBUF_INIT;
@@ -86,8 +93,18 @@ static int print_fields(int argc, const char **argv, struct repository *repo)
93 strbuf_reset(&quotbuf);
94
95 get_value(repo, &valbuf);
89 - quote_c_style(valbuf.buf, &quotbuf, NULL, 0);
90 - printf("%s=%s\n", key, quotbuf.buf);
96 +
97 + switch (format) {
98 + case FORMAT_KEYVALUE:
99 + quote_c_style(valbuf.buf, &quotbuf, NULL, 0);
100 + printf("%s=%s\n", key, quotbuf.buf);
101 + break;
102 + case FORMAT_NUL_TERMINATED:
103 + printf("%s\n%s%c", key, valbuf.buf, '\0');
104 + break;
105 + default:
106 + BUG("not a valid output format: %d", format);
107 + }
108 }
109
110 strbuf_release(&valbuf);
@@ -95,10 +112,27 @@ static int print_fields(int argc, const char **argv, struct repository *repo)
112 return ret;
113 }
114
98 -static int repo_info(int argc, const char **argv, const char *prefix UNUSED,
115 +static int repo_info(int argc, const char **argv, const char *prefix,
116 struct repository *repo)
117 {
101 - return print_fields(argc - 1, argv + 1, repo);
118 + const char *format_str = "keyvalue";
119 + enum output_format format;
120 + struct option options[] = {
121 + OPT_STRING(0, "format", &format_str, N_("format"),
122 + N_("output format")),
123 + OPT_END()
124 + };
125 +
126 + argc = parse_options(argc, argv, prefix, options, repo_usage, 0);
127 +
128 + if (!strcmp(format_str, "keyvalue"))
129 + format = FORMAT_KEYVALUE;
130 + else if (!strcmp(format_str, "nul"))
131 + format = FORMAT_NUL_TERMINATED;
132 + else
133 + die(_("invalid format '%s'"), format_str);
134 +
135 + return print_fields(argc, argv, repo, format);
136 }
137
138 int cmd_repo(int argc, const char **argv, const char *prefix,
t/t1900-repo.sh
+15 -3
@@ -25,11 +25,17 @@ test_repo_info () {
25 eval "$init_command $repo_name"
26 '
27
28 - test_expect_success "$label" '
29 - echo "$key=$expected_value" >expect &&
30 - git -C $repo_name repo info "$key" >actual &&
28 + test_expect_success "keyvalue: $label" '
29 + echo "$key=$expected_value" > expect &&
30 + git -C "$repo_name" repo info "$key" >actual &&
31 test_cmp expect actual
32 '
33 +
34 + test_expect_success "nul: $label" '
35 + printf "%s\n%s\0" "$key" "$expected_value" >expect &&
36 + git -C "$repo_name" repo info --format=nul "$key" >actual &&
37 + test_cmp_bin expect actual
38 + '
39 }
40
41 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
86 test_cmp expect actual
87 '
88
89 +test_expect_success 'git-repo-info aborts when requesting an invalid format' '
90 + echo "fatal: invalid format ${SQ}foo${SQ}" >expect &&
91 + test_must_fail git repo info --format=foo 2>actual &&
92 + test_cmp expect actual
93 +'
94 +
95 test_done