threads / patch / 65101

patch, 4 partsrepo: add support for path-related fields

Subject: [PATCH 0/4] repo: add support for path-related fields

## tl;dr

26 messages between Feb 28, 2026 and Mar 8, 2026. Diffs are folded; open one to read it.

replies: 25people: 7as markdown or json

Lucas Seiki Oshiro· Feb 28, 2026, 22:05 UTC · lore
Hi!

This patch series adds support for path-related fields in repo-info, based on what we already have in git-rev-parse:

1. The two first patches moves the path formatting used by git-rev-parse to
   path.c. This will allow us to reuse this code in git-repo-info
2. The second patch add a new flag --path-format to git-repo-info, similar to
   the flag of git-rev-parse with the same name
3. Add the new field `path.toplevel` as a proof of concept.

This arises from the fact that I didn't know what should be the default behavior of git-repo-info when dealing with paths. Some ideas were:

1. Add --path-format, just like we have in git-rev-parse
2. Use what rev-parse uses by default
3. Add keys for both relative and absolute formats

In this case, I'm using 1, but I'm not sure if it's the best option. One downside that I see here is that git-repo-info won't be able to return a relative and an absolute path for different keys in the same call.

Since there are many people interested in contributing to git-repo-info, I'll leave the remaining path-related fields to them :-)

I'm CC'ing here:
- brian, who was the original author of the `print_path` [1]
- Ayush, Tian, Jayatheerth, Soutrik and Pushkar, since they expressed interested
  in contributing to git-repo-info in GSoC. (I hope that I didn't forget anyone)

This patch is based on top of master 2cc7191751 (The 8th batch, 2026-02-27) with lo/repo-leftover-bits merged.

[1] fac60b8925 (rev-parse: add option for absolute or relative path formatting, 2020-12-13)
Lucas Seiki Oshiro (4):
  rev-parse: prepend `path_` to path-related enums
  path: add new function strbuf_add_path
  repo: add the --format-path flag
  repo: add the field path.toplevel
 Documentation/git-repo.adoc |  8 ++-
 builtin/repo.c              | 67 +++++++++++++++++++------
 builtin/rev-parse.c         | 98 +++++++------------------------------
 path.c                      | 51 +++++++++++++++++++
 path.h                      | 23 +++++++++
 t/t1900-repo-info.sh        | 69 ++++++++++++++++++++++++++
 6 files changed, 221 insertions(+), 95 deletions(-)
-- 
2.50.1 (Apple Git-155)
Lucas Seiki Oshiro· Feb 28, 2026, 22:05 UTC · re: Lucas Seiki Oshiro · lore

[PATCH 1/4] rev-parse: prepend `path_` to path-related enums

There are two enums used in rev-parse for deciding how paths will be printed by the function `print_path`: `format_type` and `default_type`. Even though there aren't any ambiguities yet, their names aren't clear that those "types" are path types.

Rename both enums and their values by prepending the word `path_`, to clarify that they are used for choosing path types.

Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
---
 builtin/rev-parse.c | 56 ++++++++++++++++++++++-----------------------
 1 file changed, 28 insertions(+), 28 deletions(-)
Show changes to builtin/rev-parse.c +28 −28
diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c
index 9032cc6327..a2162ff39e 100644
--- a/builtin/rev-parse.c
+++ b/builtin/rev-parse.c
@@ -623,27 +623,27 @@ static void handle_ref_opt(const char *pattern, const char *prefix)
 	clear_ref_exclusions(&ref_excludes);
 }
 
-enum format_type {
+enum path_format_type {
 	/* We would like a relative path. */
-	FORMAT_RELATIVE,
+	PATH_FORMAT_RELATIVE,
 	/* We would like a canonical absolute path. */
-	FORMAT_CANONICAL,
+	PATH_FORMAT_CANONICAL,
 	/* We would like the default behavior. */
-	FORMAT_DEFAULT,
+	PATH_FORMAT_DEFAULT,
 };
 
-enum default_type {
+enum path_default_type {
 	/* Our default is a relative path. */
-	DEFAULT_RELATIVE,
+	PATH_DEFAULT_RELATIVE,
 	/* Our default is a relative path if there's a shared root. */
-	DEFAULT_RELATIVE_IF_SHARED,
+	PATH_DEFAULT_RELATIVE_IF_SHARED,
 	/* Our default is a canonical absolute path. */
-	DEFAULT_CANONICAL,
+	PATH_DEFAULT_CANONICAL,
 	/* Our default is not to modify the item. */
-	DEFAULT_UNMODIFIED,
+	PATH_DEFAULT_UNMODIFIED,
 };
 
-static void print_path(const char *path, const char *prefix, enum format_type format, enum default_type def)
+static void print_path(const char *path, const char *prefix, enum path_format_type format, enum path_default_type def)
 {
 	char *cwd = NULL;
 	/*
@@ -654,12 +654,12 @@ static void print_path(const char *path, const char *prefix, enum format_type fo
 	 * set it in that case, since doing so causes a relative path to always
 	 * be produced if possible.
 	 */
-	if (!prefix && (format != FORMAT_DEFAULT || def != DEFAULT_RELATIVE_IF_SHARED))
+	if (!prefix && (format != PATH_FORMAT_DEFAULT || def != PATH_DEFAULT_RELATIVE_IF_SHARED))
 		prefix = cwd = xgetcwd();
-	if (format == FORMAT_DEFAULT && def == DEFAULT_UNMODIFIED) {
+	if (format == PATH_FORMAT_DEFAULT && def == PATH_DEFAULT_UNMODIFIED) {
 		puts(path);
-	} else if (format == FORMAT_RELATIVE ||
-		  (format == FORMAT_DEFAULT && def == DEFAULT_RELATIVE)) {
+	} else if (format == PATH_FORMAT_RELATIVE ||
+		  (format == PATH_FORMAT_DEFAULT && def == PATH_DEFAULT_RELATIVE)) {
 		/*
 		 * In order for relative_path to work as expected, we need to
 		 * make sure that both paths are absolute paths.  If we don't,
@@ -679,7 +679,7 @@ static void print_path(const char *path, const char *prefix, enum format_type fo
 		strbuf_release(&buf);
 		strbuf_release(&realbuf);
 		strbuf_release(&prefixbuf);
-	} else if (format == FORMAT_DEFAULT && def == DEFAULT_RELATIVE_IF_SHARED) {
+	} else if (format == PATH_FORMAT_DEFAULT && def == PATH_DEFAULT_RELATIVE_IF_SHARED) {
 		struct strbuf buf = STRBUF_INIT;
 		puts(relative_path(path, prefix, &buf));
 		strbuf_release(&buf);
@@ -708,7 +708,7 @@ int cmd_rev_parse(int argc,
 	const char *name = NULL;
 	struct strbuf buf = STRBUF_INIT;
 	int seen_end_of_options = 0;
-	enum format_type format = FORMAT_DEFAULT;
+	enum path_format_type format = PATH_FORMAT_DEFAULT;
 
 	show_usage_if_asked(argc, argv, builtin_rev_parse_usage);
 
@@ -789,7 +789,7 @@ int cmd_rev_parse(int argc,
 				print_path(repo_git_path_replace(the_repository, &buf,
 								 "%s", argv[i + 1]), prefix,
 						format,
-						DEFAULT_RELATIVE_IF_SHARED);
+					   PATH_DEFAULT_RELATIVE_IF_SHARED);
 				i++;
 				continue;
 			}
@@ -811,9 +811,9 @@ int cmd_rev_parse(int argc,
 				if (!arg)
 					die(_("--path-format requires an argument"));
 				if (!strcmp(arg, "absolute")) {
-					format = FORMAT_CANONICAL;
+					format = PATH_FORMAT_CANONICAL;
 				} else if (!strcmp(arg, "relative")) {
-					format = FORMAT_RELATIVE;
+					format = PATH_FORMAT_RELATIVE;
 				} else {
 					die(_("unknown argument to --path-format: %s"), arg);
 				}
@@ -977,7 +977,7 @@ int cmd_rev_parse(int argc,
 			if (!strcmp(arg, "--show-toplevel")) {
 				const char *work_tree = repo_get_work_tree(the_repository);
 				if (work_tree)
-					print_path(work_tree, prefix, format, DEFAULT_UNMODIFIED);
+					print_path(work_tree, prefix, format, PATH_DEFAULT_UNMODIFIED);
 				else
 					die(_("this operation must be run in a work tree"));
 				continue;
@@ -985,7 +985,7 @@ int cmd_rev_parse(int argc,
 			if (!strcmp(arg, "--show-superproject-working-tree")) {
 				struct strbuf superproject = STRBUF_INIT;
 				if (get_superproject_working_tree(&superproject))
-					print_path(superproject.buf, prefix, format, DEFAULT_UNMODIFIED);
+					print_path(superproject.buf, prefix, format, PATH_DEFAULT_UNMODIFIED);
 				strbuf_release(&superproject);
 				continue;
 			}
@@ -1020,18 +1020,18 @@ int cmd_rev_parse(int argc,
 				const char *gitdir = getenv(GIT_DIR_ENVIRONMENT);
 				char *cwd;
 				int len;
-				enum format_type wanted = format;
+				enum path_format_type wanted = format;
 				if (arg[2] == 'g') {	/* --git-dir */
 					if (gitdir) {
-						print_path(gitdir, prefix, format, DEFAULT_UNMODIFIED);
+						print_path(gitdir, prefix, format, PATH_DEFAULT_UNMODIFIED);
 						continue;
 					}
 					if (!prefix) {
-						print_path(".git", prefix, format, DEFAULT_UNMODIFIED);
+						print_path(".git", prefix, format, PATH_DEFAULT_UNMODIFIED);
 						continue;
 					}
 				} else {		/* --absolute-git-dir */
-					wanted = FORMAT_CANONICAL;
+					wanted = PATH_FORMAT_CANONICAL;
 					if (!gitdir && !prefix)
 						gitdir = ".git";
 					if (gitdir) {
@@ -1047,11 +1047,11 @@ int cmd_rev_parse(int argc,
 				strbuf_reset(&buf);
 				strbuf_addf(&buf, "%s%s.git", cwd, len && cwd[len-1] != '/' ? "/" : "");
 				free(cwd);
-				print_path(buf.buf, prefix, wanted, DEFAULT_CANONICAL);
+				print_path(buf.buf, prefix, wanted, PATH_DEFAULT_CANONICAL);
 				continue;
 			}
 			if (!strcmp(arg, "--git-common-dir")) {
-				print_path(repo_get_common_dir(the_repository), prefix, format, DEFAULT_RELATIVE_IF_SHARED);
+				print_path(repo_get_common_dir(the_repository), prefix, format, PATH_DEFAULT_RELATIVE_IF_SHARED);
 				continue;
 			}
 			if (!strcmp(arg, "--is-inside-git-dir")) {
@@ -1081,7 +1081,7 @@ int cmd_rev_parse(int argc,
 				if (the_repository->index->split_index) {
 					const struct object_id *oid = &the_repository->index->split_index->base_oid;
 					const char *path = repo_git_path_replace(the_repository, &buf, "sharedindex.%s", oid_to_hex(oid));
-					print_path(path, prefix, format, DEFAULT_RELATIVE);
+					print_path(path, prefix, format, PATH_DEFAULT_RELATIVE);
 				}
 				continue;
 			}
-- 
2.50.1 (Apple Git-155)
Lucas Seiki Oshiro· Feb 28, 2026, 22:05 UTC · re: Lucas Seiki Oshiro · lore

[PATCH 2/4] path: add new function strbuf_add_path

The function `print_path`, introduced in fac60b8925 (rev-parse: add option for absolute or relative path formatting, 2020-12-13), is used by git-rev-parse for printing paths, deciding between using relative or absolute paths. This decision, however, could benefit other commands, notably git-repo-info.

Encapsulate this logic into a new function called `strbuf_add_path`, located in `path.c`. Move to path.c the two enums used for deciding the path format, i.e. `path_default_type` and `path_format_type`.

Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
---
 builtin/rev-parse.c | 72 ++++-----------------------------------------
 path.c              | 51 ++++++++++++++++++++++++++++++++
 path.h              | 23 +++++++++++++++
 3 files changed, 80 insertions(+), 66 deletions(-)
Show changes to 3 files +80 −66

builtin/rev-parse.c, path.c, path.h

diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c
index a2162ff39e..024a9e7d5f 100644
--- a/builtin/rev-parse.c
+++ b/builtin/rev-parse.c
@@ -623,73 +623,13 @@ static void handle_ref_opt(const char *pattern, const char *prefix)
 	clear_ref_exclusions(&ref_excludes);
 }
 
-enum path_format_type {
-	/* We would like a relative path. */
-	PATH_FORMAT_RELATIVE,
-	/* We would like a canonical absolute path. */
-	PATH_FORMAT_CANONICAL,
-	/* We would like the default behavior. */
-	PATH_FORMAT_DEFAULT,
-};
-
-enum path_default_type {
-	/* Our default is a relative path. */
-	PATH_DEFAULT_RELATIVE,
-	/* Our default is a relative path if there's a shared root. */
-	PATH_DEFAULT_RELATIVE_IF_SHARED,
-	/* Our default is a canonical absolute path. */
-	PATH_DEFAULT_CANONICAL,
-	/* Our default is not to modify the item. */
-	PATH_DEFAULT_UNMODIFIED,
-};
-
-static void print_path(const char *path, const char *prefix, enum path_format_type format, enum path_default_type def)
+static void print_path(const char *path, const char *prefix,
+		       enum path_format_type format, enum path_default_type def)
 {
-	char *cwd = NULL;
-	/*
-	 * We don't ever produce a relative path if prefix is NULL, so set the
-	 * prefix to the current directory so that we can produce a relative
-	 * path whenever possible.  If we're using RELATIVE_IF_SHARED mode, then
-	 * we want an absolute path unless the two share a common prefix, so don't
-	 * set it in that case, since doing so causes a relative path to always
-	 * be produced if possible.
-	 */
-	if (!prefix && (format != PATH_FORMAT_DEFAULT || def != PATH_DEFAULT_RELATIVE_IF_SHARED))
-		prefix = cwd = xgetcwd();
-	if (format == PATH_FORMAT_DEFAULT && def == PATH_DEFAULT_UNMODIFIED) {
-		puts(path);
-	} else if (format == PATH_FORMAT_RELATIVE ||
-		  (format == PATH_FORMAT_DEFAULT && def == PATH_DEFAULT_RELATIVE)) {
-		/*
-		 * In order for relative_path to work as expected, we need to
-		 * make sure that both paths are absolute paths.  If we don't,
-		 * we can end up with an unexpected absolute path that the user
-		 * didn't want.
-		 */
-		struct strbuf buf = STRBUF_INIT, realbuf = STRBUF_INIT, prefixbuf = STRBUF_INIT;
-		if (!is_absolute_path(path)) {
-			strbuf_realpath_forgiving(&realbuf, path,  1);
-			path = realbuf.buf;
-		}
-		if (!is_absolute_path(prefix)) {
-			strbuf_realpath_forgiving(&prefixbuf, prefix, 1);
-			prefix = prefixbuf.buf;
-		}
-		puts(relative_path(path, prefix, &buf));
-		strbuf_release(&buf);
-		strbuf_release(&realbuf);
-		strbuf_release(&prefixbuf);
-	} else if (format == PATH_FORMAT_DEFAULT && def == PATH_DEFAULT_RELATIVE_IF_SHARED) {
-		struct strbuf buf = STRBUF_INIT;
-		puts(relative_path(path, prefix, &buf));
-		strbuf_release(&buf);
-	} else {
-		struct strbuf buf = STRBUF_INIT;
-		strbuf_realpath_forgiving(&buf, path, 1);
-		puts(buf.buf);
-		strbuf_release(&buf);
-	}
-	free(cwd);
+	struct strbuf sb = STRBUF_INIT;
+	strbuf_add_path(&sb, path, prefix, format, def);
+	puts(sb.buf);
+	strbuf_release(&sb);
 }
 
 int cmd_rev_parse(int argc,
diff --git a/path.c b/path.c
index d726537622..ab9669abff 100644
--- a/path.c
+++ b/path.c
@@ -1574,6 +1574,57 @@ char *xdg_cache_home(const char *filename)
 	return NULL;
 }
 
+void strbuf_add_path(struct strbuf *sb, const char *path, const char *prefix,
+		     enum path_format_type format, enum path_default_type def)
+{
+	char *cwd = NULL;
+	/*
+	 * We don't ever produce a relative path if prefix is NULL, so set the
+	 * prefix to the current directory so that we can produce a relative
+	 * path whenever possible.  If we're using RELATIVE_IF_SHARED mode, then
+	 * we want an absolute path unless the two share a common prefix, so don't
+	 * set it in that case, since doing so causes a relative path to always
+	 * be produced if possible.
+	 */
+	if (!prefix && (format != PATH_FORMAT_DEFAULT || def != PATH_DEFAULT_RELATIVE_IF_SHARED))
+		prefix = cwd = xgetcwd();
+	if (format == PATH_FORMAT_DEFAULT && def == PATH_DEFAULT_UNMODIFIED) {
+		strbuf_addstr(sb, path);
+	} else if (format == PATH_FORMAT_RELATIVE ||
+		   (format == PATH_FORMAT_DEFAULT && def == PATH_DEFAULT_RELATIVE)) {
+		/*
+		 * In order for relative_path to work as expected, we need to
+		 * make sure that both paths are absolute paths.  If we don't,
+		 * we can end up with an unexpected absolute path that the user
+		 * didn't want.
+		 */
+		struct strbuf buf = STRBUF_INIT, realbuf = STRBUF_INIT, prefixbuf = STRBUF_INIT;
+		if (!is_absolute_path(path)) {
+			strbuf_realpath_forgiving(&realbuf, path,  1);
+			path = realbuf.buf;
+		}
+		if (!is_absolute_path(prefix)) {
+			strbuf_realpath_forgiving(&prefixbuf, prefix, 1);
+			prefix = prefixbuf.buf;
+		}
+		strbuf_addstr(sb, relative_path(path, prefix, &buf));
+		strbuf_release(&buf);
+		strbuf_release(&realbuf);
+		strbuf_release(&prefixbuf);
+	} else if (format == PATH_FORMAT_DEFAULT && def == PATH_DEFAULT_RELATIVE_IF_SHARED) {
+		struct strbuf buf = STRBUF_INIT;
+		strbuf_addstr(sb, relative_path(path, prefix, &buf));
+		strbuf_release(&buf);
+	} else {
+		struct strbuf buf = STRBUF_INIT;
+		strbuf_realpath_forgiving(&buf, path, 1);
+		strbuf_addbuf(sb, &buf);
+		strbuf_release(&buf);
+	}
+	free(cwd);
+}
+
+
 REPO_GIT_PATH_FUNC(squash_msg, "SQUASH_MSG")
 REPO_GIT_PATH_FUNC(merge_msg, "MERGE_MSG")
 REPO_GIT_PATH_FUNC(merge_rr, "MERGE_RR")
diff --git a/path.h b/path.h
index 0ec95a0b07..c152d20c71 100644
--- a/path.h
+++ b/path.h
@@ -258,6 +258,29 @@ enum scld_error safe_create_leading_directories_no_share(char *path);
 int safe_create_file_with_leading_directories(struct repository *repo,
 					      const char *path);
 
+enum path_format_type {
+	/* We would like a relative path. */
+	PATH_FORMAT_RELATIVE,
+	/* We would like a canonical absolute path. */
+	PATH_FORMAT_CANONICAL,
+	/* We would like the default behavior. */
+	PATH_FORMAT_DEFAULT,
+};
+
+enum path_default_type {
+	/* Our default is a relative path. */
+	PATH_DEFAULT_RELATIVE,
+	/* Our default is a relative path if there's a shared root. */
+	PATH_DEFAULT_RELATIVE_IF_SHARED,
+	/* Our default is a canonical absolute path. */
+	PATH_DEFAULT_CANONICAL,
+	/* Our default is not to modify the item. */
+	PATH_DEFAULT_UNMODIFIED,
+};
+
+void strbuf_add_path(struct strbuf *buf, const char *path, const char *prefix,
+		     enum path_format_type format, enum path_default_type def);
+
 # ifdef USE_THE_REPOSITORY_VARIABLE
 #  include "strbuf.h"
 #  include "repository.h"
-- 
2.50.1 (Apple Git-155)
Lucas Seiki Oshiro· Feb 28, 2026, 22:05 UTC · re: Lucas Seiki Oshiro · lore

[PATCH 3/4] repo: add the --format-path flag

Some paths handled by Git are better presented in their absolute format and others are better presented relative to the current working directory.

Add a `--format-path` flag to git-repo-info, allowing the user to force the outputted paths to be either in the absolute or in the relative format. This flag is similar to its homonymous in git-rev-parse, introduced in fac60b8925 (rev-parse: add option for absolute or relative path formatting, 2020-12-13).

Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
---
 Documentation/git-repo.adoc |  8 ++++++--
 builtin/repo.c              | 24 +++++++++++++++++++-----
 t/t1900-repo-info.sh        |  7 +++++++
 3 files changed, 32 insertions(+), 7 deletions(-)
Show changes to 3 files +32 −7

Documentation/git-repo.adoc, builtin/repo.c, t/t1900-repo-info.sh

diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc
index 5e2968b707..478737b8ff 100644
--- a/Documentation/git-repo.adoc
+++ b/Documentation/git-repo.adoc
@@ -8,7 +8,7 @@ git-repo - Retrieve information about the repository
 SYNOPSIS
 --------
 [synopsis]
-git repo info [--format=(lines|nul) | -z] [--all | <key>...]
+git repo info [--format=(lines|nul) | -z] [--path-format=(absolute|relative)] [--all | <key>...]
 git repo info --keys [--format=(lines|nul) | -z]
 git repo structure [--format=(table|lines|nul) | -z]
 
@@ -20,7 +20,7 @@ THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOR MAY CHANGE.
 
 COMMANDS
 --------
-`info [--format=(lines|nul) | -z] [--all | <key>...]`::
+`info [--format=(lines|nul) | -z] [--path-format=(absolute|relative)] [--all | <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).
@@ -45,6 +45,10 @@ supported:
 	`lines`. Unlike in the `lines` format, the values are never quoted.
 +
 `-z` is an alias for `--format=nul`.
++
+By default, the path values may be in the absolute or relative path, depending
+on the requested keys. However, the format can be forced by using the flag
+`--path-format`.
 
 `info --keys [--format=(lines|nul) | -z]`::
 	List all the available keys, one per line. The output format can be chosen
diff --git a/builtin/repo.c b/builtin/repo.c
index f943be7451..cff4c6db9b 100644
--- a/builtin/repo.c
+++ b/builtin/repo.c
@@ -7,17 +7,16 @@
 #include "parse-options.h"
 #include "path-walk.h"
 #include "progress.h"
+#include "path.h"
 #include "quote.h"
 #include "ref-filter.h"
 #include "refs.h"
 #include "revision.h"
-#include "strbuf.h"
-#include "string-list.h"
 #include "shallow.h"
 #include "utf8.h"
 
 static const char *const repo_usage[] = {
-	"git repo info [--format=(lines|nul) | -z] [--all | <key>...]",
+	"git repo info [--format=(lines|nul) | -z] [--path-format=(absolute|relative)] [--all | <key>...]",
 	"git repo info --keys [--format=(lines|nul) | -z]",
 	"git repo structure [--format=(table|lines|nul) | -z]",
 	NULL
@@ -109,7 +108,8 @@ static void print_field(enum output_format format, const char *key,
 
 static int print_fields(int argc, const char **argv,
 			struct repository *repo,
-			enum output_format format)
+			enum output_format format,
+			enum path_format_type path_format UNUSED)
 {
 	int ret = 0;
 	struct strbuf valbuf = STRBUF_INIT;
@@ -197,6 +197,9 @@ static int cmd_repo_info(int argc, const char **argv, const char *prefix,
 	enum output_format format = FORMAT_NEWLINE_TERMINATED;
 	int all_keys = 0;
 	int show_keys = 0;
+	const char *path_format_str = NULL;
+	enum path_format_type path_format = PATH_FORMAT_DEFAULT;
+
 	struct option options[] = {
 		OPT_CALLBACK_F(0, "format", &format, N_("format"),
 			       N_("output format"),
@@ -207,6 +210,8 @@ static int cmd_repo_info(int argc, const char **argv, const char *prefix,
 			       parse_format_cb),
 		OPT_BOOL(0, "all", &all_keys, N_("print all keys/values")),
 		OPT_BOOL(0, "keys", &show_keys, N_("show keys")),
+		OPT_STRING(0, "path-format", &path_format_str,
+			   N_("path-format"), N_("path format")),
 		OPT_END()
 	};
 
@@ -221,13 +226,22 @@ static int cmd_repo_info(int argc, const char **argv, const char *prefix,
 	if (format != FORMAT_NEWLINE_TERMINATED && format != FORMAT_NUL_TERMINATED)
 		die(_("unsupported output format"));
 
+	if (path_format_str) {
+		if (!strcmp(path_format_str, "absolute"))
+			path_format = PATH_FORMAT_CANONICAL;
+		else if (!strcmp(path_format_str, "relative"))
+			path_format = PATH_FORMAT_RELATIVE;
+		else
+			die(_("invalid path format '%s'"), path_format_str);
+	}
+
 	if (all_keys && argc)
 		die(_("--all and <key> cannot be used together"));
 
 	if (all_keys)
 		return print_all_fields(repo, format);
 	else
-		return print_fields(argc, argv, repo, format);
+		return print_fields(argc, argv, repo, format, path_format);
 }
 
 struct ref_stats {
diff --git a/t/t1900-repo-info.sh b/t/t1900-repo-info.sh
index a9eb07abe8..f5c76067cb 100755
--- a/t/t1900-repo-info.sh
+++ b/t/t1900-repo-info.sh
@@ -149,4 +149,11 @@ test_expect_success 'git repo info --keys uses lines as its default output forma
 	test_cmp expect actual
 '
 
+test_expect_success 'git-repo-info aborts when requesting an invalid path format' '
+	test_when_finished "rm -f err expected" &&
+	echo "fatal: invalid path format '\'foo\''" >expected &&
+	test_must_fail git repo info --path-format=foo 2>err &&
+	test_cmp expected err
+'
+
 test_done
-- 
2.50.1 (Apple Git-155)
Lucas Seiki Oshiro· Feb 28, 2026, 22:05 UTC · re: Lucas Seiki Oshiro · lore

[PATCH 4/4] repo: add the field path.toplevel

The flag `--show-toplevel` from git-rev-parse is used for retrieving the top level directory path of the repository. This way, it is used for querying repository metadata, fitting in the purpose of git-repo-info.

Add a new field `path.toplevel` to the git-repo-info subcommand containing that information.

Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
---
 builtin/repo.c       | 47 +++++++++++++++++++++++++--------
 t/t1900-repo-info.sh | 62 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 98 insertions(+), 11 deletions(-)
Show changes to 2 files +98 −11

builtin/repo.c, t/t1900-repo-info.sh

diff --git a/builtin/repo.c b/builtin/repo.c
index cff4c6db9b..61cd539e05 100644
--- a/builtin/repo.c
+++ b/builtin/repo.c
@@ -22,7 +22,8 @@ static const char *const repo_usage[] = {
 	NULL
 };
 
-typedef int get_value_fn(struct repository *repo, struct strbuf *buf);
+typedef int get_value_fn(struct repository *repo, struct strbuf *buf,
+			 const char *prefix, enum path_format_type format);
 
 enum output_format {
 	FORMAT_TABLE,
@@ -35,26 +36,46 @@ struct repo_info_field {
 	get_value_fn *get_value;
 };
 
-static int get_layout_bare(struct repository *repo UNUSED, struct strbuf *buf)
+static int get_layout_bare(struct repository *repo UNUSED, struct strbuf *buf,
+			   const char *prefix UNUSED,
+			   enum path_format_type format UNUSED)
 {
 	strbuf_addstr(buf, is_bare_repository() ? "true" : "false");
 	return 0;
 }
 
-static int get_layout_shallow(struct repository *repo, struct strbuf *buf)
+static int get_layout_shallow(struct repository *repo, struct strbuf *buf,
+			      const char *prefix UNUSED,
+			      enum path_format_type format UNUSED)
 {
 	strbuf_addstr(buf,
 		      is_repository_shallow(repo) ? "true" : "false");
 	return 0;
 }
 
-static int get_object_format(struct repository *repo, struct strbuf *buf)
+static int get_object_format(struct repository *repo, struct strbuf *buf,
+			     const char *prefix UNUSED,
+			     enum path_format_type format UNUSED)
 {
 	strbuf_addstr(buf, repo->hash_algo->name);
 	return 0;
 }
 
-static int get_references_format(struct repository *repo, struct strbuf *buf)
+static int get_path_toplevel(struct repository *repo, struct strbuf *buf,
+			     const char *prefix, enum path_format_type format)
+{
+	const char *work_tree = repo_get_work_tree(repo);
+	if (work_tree)
+		strbuf_add_path(buf, work_tree, prefix, format,
+				PATH_DEFAULT_UNMODIFIED);
+	else
+		return error(_("this operation must be run in a work tree"));
+	return 0;
+}
+
+static int get_references_format(struct repository *repo, struct strbuf *buf,
+				 const char *prefix UNUSED,
+				 enum path_format_type format UNUSED)
 {
 	strbuf_addstr(buf,
 		      ref_storage_format_to_name(repo->ref_storage_format));
@@ -66,6 +87,7 @@ static const struct repo_info_field repo_info_field[] = {
 	{ "layout.bare", get_layout_bare },
 	{ "layout.shallow", get_layout_shallow },
 	{ "object.format", get_object_format },
+	{ "path.toplevel", get_path_toplevel },
 	{ "references.format", get_references_format },
 };
 
@@ -108,8 +130,9 @@ static void print_field(enum output_format format, const char *key,
 
 static int print_fields(int argc, const char **argv,
 			struct repository *repo,
+			const char *prefix,
 			enum output_format format,
-			enum path_format_type path_format UNUSED)
+			enum path_format_type path_format)
 {
 	int ret = 0;
 	struct strbuf valbuf = STRBUF_INIT;
@@ -124,7 +147,7 @@ static int print_fields(int argc, const char **argv,
 		}
 
 		strbuf_reset(&valbuf);
-		field->get_value(repo, &valbuf);
+		field->get_value(repo, &valbuf, prefix, path_format);
 		print_field(format, key, valbuf.buf);
 	}
 
@@ -133,7 +156,9 @@ static int print_fields(int argc, const char **argv,
 }
 
 static int print_all_fields(struct repository *repo,
-			    enum output_format format)
+			    const char *prefix,
+			    enum output_format format,
+			    enum path_format_type path_format)
 {
 	struct strbuf valbuf = STRBUF_INIT;
 
@@ -141,7 +166,7 @@ static int print_all_fields(struct repository *repo,
 		const struct repo_info_field *field = &repo_info_field[i];
 
 		strbuf_reset(&valbuf);
-		field->get_value(repo, &valbuf);
+		field->get_value(repo, &valbuf, prefix, path_format);
 		print_field(format, field->key, valbuf.buf);
 	}
 
@@ -239,9 +264,9 @@ static int cmd_repo_info(int argc, const char **argv, const char *prefix,
 		die(_("--all and <key> cannot be used together"));
 
 	if (all_keys)
-		return print_all_fields(repo, format);
+		return print_all_fields(repo, prefix, format, path_format);
 	else
-		return print_fields(argc, argv, repo, format, path_format);
+		return print_fields(argc, argv, repo, prefix, format, path_format);
 }
 
 struct ref_stats {
diff --git a/t/t1900-repo-info.sh b/t/t1900-repo-info.sh
index f5c76067cb..4985a9cc70 100755
--- a/t/t1900-repo-info.sh
+++ b/t/t1900-repo-info.sh
@@ -38,6 +38,53 @@ test_repo_info () {
 	'
 }
 
+test_repo_info_path () {
+	label=$1
+	repo_name=$2
+	key=$3
+	relative_path=$4
+	default=$5
+
+	absolute_path=$(cd "$relative_path"; pwd)/"$repo_name"
+
+	case $default in
+	absolute)
+		expected_value="$absolute_path"
+		;;
+	relative)
+		expected_value="$relative_path"
+		;;
+	esac
+
+	test_expect_success "setup: $label" '
+		git init "$repo_name"
+	'
+
+	test_expect_success "nul: $label" '
+		printf "%s\n%s\0" "$key" "$expected_value" >expected &&
+		git -C "$repo_name" repo info --format=nul "$key" >actual &&
+		test_cmp expected actual
+	'
+
+	test_expect_success "default: $label" '
+		echo "$key=$expected_value" > expected &&
+		git -C "$repo_name" repo info "$key" >actual &&
+		test_cmp expected actual
+	'
+
+	test_expect_success "absolute: $label" '
+		echo "$key=$absolute_path" > expected &&
+		git -C "$repo_name" repo info --path-format=absolute "$key" >actual &&
+		test_cmp expected actual
+	'
+
+	test_expect_success "relative: $label" '
+		echo "$key=$relative_path" > expected &&
+		git -C "$repo_name" repo info --path-format=relative "$key" >actual &&
+		test_cmp expected actual
+	'
+}
+
 test_repo_info 'ref format files is retrieved correctly' \
 	'git init --ref-format=files' 'format-files' 'references.format' 'files'
 
@@ -69,6 +116,21 @@ test_repo_info 'object.format = sha1 is retrieved correctly' \
 test_repo_info 'object.format = sha256 is retrieved correctly' \
 	'git init --object-format=sha256' 'sha256' 'object.format' 'sha256'
 
+test_repo_info_path 'toplevel is retrieved correctly' \
+	'toplevel' 'path.toplevel' './' 'absolute'
+
+test_expect_success 'git-repo-info fails if an invalid key is requested' '
+	echo "error: key ${SQ}foo${SQ} 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 outputs data even if there is an invalid field' '
+	echo "references.format=$(test_detect_ref_format)" >expected &&
+	test_must_fail git repo info foo references.format bar >actual &&
+	test_cmp expected actual
+'
+
 test_expect_success 'values returned in order requested' '
 	cat >expect <<-\EOF &&
 	layout.bare=false
-- 
2.50.1 (Apple Git-155)
Tian Yuchen· Mar 1, 2026, 04:24 UTC · re: Lucas Seiki Oshiro · lore

Re: [PATCH 4/4] repo: add the field path.toplevel

Hi Lucas,
 > I'm CC'ing here:
 >
 > - brian, who was the original author of the `print_path` [1]
 > - Ayush, Tian, Jayatheerth, Soutrik and Pushkar, since they expressed 
 >   interested in contributing to git-repo-info in GSoC. (I hope that I
 >   didn't forget anyone)
Thank you for your thoughtful consideration!
 > 1. Add --path-format, just like we have in git-rev-parse
 > 2. Use what rev-parse uses by default
 > 3. Add keys for both relative and absolute formats
It makes me wonder if we can use Format Modifiers as in ref-filter.c...
	https://git-scm.com/docs/git-for-each-ref
...which allow us to control the output precisely. For example:
	%(path:relative)
	%(path:absolute)
	%(path:short)
	%(path:strip=2)...
Just a thought.
 > There are two enums used in rev-parse for deciding how paths will
 > be printed by the function `print_path`: `format_type` and
 > `default_type`. Even though there aren't any ambiguities yet, their
 > names aren't clear that those "types" are path types.
This one makes sense to me. Also reduce naming conflicts.
 > +void strbuf_add_path(struct strbuf *sb, const char *path, const char 
 > *prefix, enum path_format_type format, enum path_default_type def)

Isn't it a bit inappropriate for a generic character concatenation function to know about format and def? I don't think this should be the responsibility of a low-level function, at least not str_buf_add_path().

All functions starting with strbuf_add.. listed by git grep strbuf_add are mostly pure string concatenation operations. I believe this should be the case here as well.

 > +	if (!prefix && (format != PATH_FORMAT_DEFAULT || def != 
PATH_DEFAULT_RELATIVE_IF_SHARED))
 > +		prefix = cwd = xgetcwd();

I think the logic here shouldn't be tied to PATH_DEFAULT_RELATIVE_IF_SHARED, I believe the attribution here is the same as above.

 > +		prefix = cwd = xgetcwd()

Will there be a performance regression? Since xgetcwd() here is a system call, right? If prefix == NULL and the get repo info command is used to locate the top-level path among a large number of submodules, and this command will be executed multiple times.

In my opinion, upper-level commands should call xgetcwd() only once before entering the loop, then pass the obtained prefix as an argument to the underlying implementation.

Show 54 quoted lines
> -typedef int get_value_fn(struct repository *repo, struct strbuf *buf);
> +typedef int get_value_fn(struct repository *repo, struct strbuf *buf,
> +			 const char *prefix, enum path_format_type format);
>  
>  enum output_format {
>  	FORMAT_TABLE,
> @@ -35,26 +36,46 @@ struct repo_info_field {
>  	get_value_fn *get_value;
>  };
>  
> -static int get_layout_bare(struct repository *repo UNUSED, struct strbuf *buf)
> +static int get_layout_bare(struct repository *repo UNUSED, struct strbuf *buf,
> +			   const char *prefix UNUSED,
> +			   enum path_format_type format UNUSED)
>  {
>  	strbuf_addstr(buf, is_bare_repository() ? "true" : "false");
>  	return 0;
>  }
>  
> -static int get_layout_shallow(struct repository *repo, struct strbuf *buf)
> +static int get_layout_shallow(struct repository *repo, struct strbuf *buf,
> +			      const char *prefix UNUSED,
> +			      enum path_format_type format UNUSED)
>  {
>  	strbuf_addstr(buf,
>  		      is_repository_shallow(repo) ? "true" : "false");
>  	return 0;
>  }
>  
> -static int get_object_format(struct repository *repo, struct strbuf *buf)
> +static int get_object_format(struct repository *repo, struct strbuf *buf,
> +			     const char *prefix UNUSED,
> +			     enum path_format_type format UNUSED)
>  {
>  	strbuf_addstr(buf, repo->hash_algo->name);
>  	return 0;
>  }
>  
> -static int get_references_format(struct repository *repo, struct strbuf *buf)
> +static int get_path_toplevel(struct repository *repo, struct strbuf *buf,
> +			     const char *prefix, enum path_format_type format)
> +{
> +	const char *work_tree = repo_get_work_tree(repo);
> +	if (work_tree)
> +		strbuf_add_path(buf, work_tree, prefix, format,
> +				PATH_DEFAULT_UNMODIFIED);
> +	else
> +		return error(_("this operation must be run in a work tree"));
> +	return 0;
> +}
> +
> +static int get_references_format(struct repository *repo, struct strbuf *buf,
> +				 const char *prefix UNUSED,
> +

I don't think we should add the two new parameters to all get_ functions here. As changed in your patch, functions like get_object_format don't really, need to know about prefix or format, so the corresponding parameters are marked as UNUSED. Imagine if more and more data needs to be retrieved by these get_ series functions in the future — is it really advisable to add unnecessary parameters to all remaining functions just for the sake of a few?

I'm not entirely sure about the above content either; I'm just throwing out ideas to spark discussion. (´~`)

Thanks again for starting this discussion!
Regards,
Yuchen
Lucas Seiki Oshiro· Mar 1, 2026, 20:21 UTC · re: Tian Yuchen · lore

Re: [PATCH 4/4] repo: add the field path.toplevel

> Hi Lucas,
Hi, Tian!
Show 6 quoted lines
> > +void strbuf_add_path(struct strbuf *sb, const char *path, const char > *prefix, enum path_format_type format, enum path_default_type def)
> 
> Isn't it a bit inappropriate for a generic character concatenation
> function to know about format and def? I don't think this should be
> the responsibility of a low-level function, at least not
> str_buf_add_path().

I don't think it can be considered a low-level function, but I agree that its name can be misleading.

> > + prefix = cwd = xgetcwd()
> 
> Will there be a performance regression? Since xgetcwd() here is a
> system call, right?
In this case, no, it is defined in wrapper.h.
Show 7 quoted lines
> I don't think we should add the two new parameters to all get_
> functions here. As changed in your patch, functions like
> get_object_format don't really, need to know about prefix or format,
> so the corresponding parameters are marked as UNUSED. Imagine if
> more and more data needs to be retrieved by these get_ series
> functions in the future — is it really advisable to add unnecessary
> parameters to all remaining functions just for the sake of a few?

In this case, we need to add them to match the signature of get_value_fn. Those values will be useful for all the path.*, but if we start to add more than that I agree that we'll need to think in a better solution.

> I'm not entirely sure about the above content either; I'm just
> throwing out ideas to spark discussion. (´~`)

Thanks, it's also good to see more points of view. I'm also not sure about it :-)

Tian Yuchen· Mar 2, 2026, 04:54 UTC · re: Lucas Seiki Oshiro · lore

Re: [PATCH 4/4] repo: add the field path.toplevel

Hi Lucas
> I don't think it can be considered a low-level function, but I
> agree that its name can be misleading.

Hummm...If a function is solely responsible for string concatenation and resides in like path.c, why isn't it a low level function?

I think the key issue lies in the fact that this function's responsibilities are not quite appropriate, rather than merely the name. Does a string buffer need to understand Git's path formatting rules? It should only know how to append bytes, right? Maybe it would be better suited as a domain-specific formatter like 'format_path_output()' in a higher level module? I am quite uncertain about it.

> In this case, no, it is defined in wrapper.h.
Yes it is defined in wrapper.h. However in wrapper.c we have:
char *xgetcwd(void)
{
	struct strbuf sb = STRBUF_INIT;
	if (strbuf_getcwd(&sb))
		die_errno(_("unable to get current working directory"));
	return strbuf_detach(&sb, NULL);
}
and the for the stfbuf_getcwd(), in strbuf.c we have:
int strbuf_getcwd(struct strbuf *sb)
{
	size_t oldalloc = sb->alloc;
	size_t guessed_len = 128;
	for (;; guessed_len *= 2) {
		strbuf_grow(sb, guessed_len);
		if (getcwd(sb->buf, sb->alloc)) {
			strbuf_setlen(sb, strlen(sb->buf));
			return 0;
...

Notice the getcwd() function, which is indeed a system call, which you can check with 'man 2 getcwd' in terminal. Wrapping it in wrapper.c is just providing a shortcut, right?

But I don't think using system calls is inherently problematic. The issue lies in where this xgetbuf() is placed:

In builtin/rev-parse.c, the print_path() function is inside of cmd_rev_parse(), which is like:

int cmd_rev_parse(....){
	for (i = 1; i < argc; i++){
	...
	if (....){
		print_path(....)
	}
	...
}
And your print_path() implement was:
Show 8 quoted lines
> +static void print_path(const char *path, const char *prefix,
> +		       enum path_format_type format, enum path_default_type def)
>  {
> +	struct strbuf sb = STRBUF_INIT;
> +	strbuf_add_path(&sb, path, prefix, format, def);
> +	puts(sb.buf);
> +	strbuf_release(&sb);
>  }

So this system call is indeed invoked in the loop. Specifically, it gets called every time 'git rev-parse' is invoked, and as far as I know it should be a command used extensively in like shell scripts...?

Maybe cache-up approach is more robust? For example in builtin/rev-parse.c:
const char *cached_cwd = ...->original_cwd;
if (!cached_cwd)
	cached_cwd = xgetcwd();
for (...) {
	if (...) {
		print_path_with_cwd(..., cached_cwd, ...);
	}
}
> In this case, we need to add them to match the signature of
> get_value_fn. Those values will be useful for all the path.*, but
> if we start to add more than that I agree that we'll need to think
> in a better solution.
Yes indeed.
> Thanks, it's also good to see more points of view. I'm also not
> sure about it :-)
Thank you for the patch again!
Regards,
Yuchen
JAYATHEERTH K· Mar 1, 2026, 02:58 UTC · re: Lucas Seiki Oshiro · lore

Re: [PATCH 0/4] repo: add support for path-related fields

On Sun, Mar 1, 2026 at 4:14 AM Lucas Seiki Oshiro <lucasseikioshiro@gmail.com> wrote:

>
> Hi!
>
Hey Lucas,
Show 20 quoted lines
> This patch series adds support for path-related fields in repo-info, based on
> what we already have in git-rev-parse:
>
> 1. The two first patches moves the path formatting used by git-rev-parse to
>    path.c. This will allow us to reuse this code in git-repo-info
> 2. The second patch add a new flag --path-format to git-repo-info, similar to
>    the flag of git-rev-parse with the same name
> 3. Add the new field `path.toplevel` as a proof of concept.
>
> This arises from the fact that I didn't know what should be the default behavior
> of git-repo-info when dealing with paths. Some ideas were:
>
> 1. Add --path-format, just like we have in git-rev-parse
> 2. Use what rev-parse uses by default
> 3. Add keys for both relative and absolute formats
>
> In this case, I'm using 1, but I'm not sure if it's the best option. One
> downside that I see here is that git-repo-info won't be able to return
> a relative and an absolute path for different keys in the same call.
>

Option 1 feels like the cleanest approach. Even though it means git-repo-info can't return both a relative and absolute path in the exact same call, it keeps the API highly predictable for scripting without bloating the key namespace (which Option 3 would do).

The behaviour is different when compared to the command itself where we have to use --all, but I think in this area this is the right approach.

> Since there are many people interested in contributing to git-repo-info, I'll
> leave the remaining path-related fields to them :-)
>
Thank you ;)
Show 8 quoted lines
> I'm CC'ing here:
>
> - brian, who was the original author of the `print_path` [1]
> - Ayush, Tian, Jayatheerth, Soutrik and Pushkar, since they expressed interested
>   in contributing to git-repo-info in GSoC. (I hope that I didn't forget anyone)
>
> This patch is based on top of master 2cc7191751 (The 8th batch, 2026-02-27) with
> lo/repo-leftover-bits merged.

This provides a fantastic foundation. I have updated my GSoC proposal based on these patches to build out the remaining path.* keys, alongside category-based querying and global state removal.

I will be sending that in a completely new thread shortly.
Regards
- Jayatheerth
Ayush Jha· Mar 1, 2026, 05:45 UTC · re: JAYATHEERTH K · lore

Re: [PATCH 0/4] repo: add support for path-related fields

Hi Lucas,

Thanks for sharing this series — moving the path formatting logic into path.c makes a lot of sense and avoids duplication with rev-parse.

Regarding the limitation you mentioned about not being able to mix relative and absolute paths within the same invocation, I was wondering whether it might be worth considering making the path format part of the key itself, rather than controlled by a global flag.

For example, something along the lines of: path.toplevel path.absolute.toplevel path.relative.toplevel

This could allow users to request different formats in a single call without introducing global state into the command output. That said, I’m not sure whether this would complicate the key namespace too much, or whether maintaining parity with rev-parse semantics is preferable for consistency.

I’d be interested to hear your thoughts on this trade-off.

Best, Ayush

On Sun, Mar 1, 2026 at 8:28 AM JAYATHEERTH K <jayatheerthkulkarni2005@gmail.com> wrote:

Show 63 quoted lines
>
> On Sun, Mar 1, 2026 at 4:14 AM Lucas Seiki Oshiro
> <lucasseikioshiro@gmail.com> wrote:
> >
> > Hi!
> >
>
> Hey Lucas,
>
> > This patch series adds support for path-related fields in repo-info, based on
> > what we already have in git-rev-parse:
> >
> > 1. The two first patches moves the path formatting used by git-rev-parse to
> >    path.c. This will allow us to reuse this code in git-repo-info
> > 2. The second patch add a new flag --path-format to git-repo-info, similar to
> >    the flag of git-rev-parse with the same name
> > 3. Add the new field `path.toplevel` as a proof of concept.
> >
> > This arises from the fact that I didn't know what should be the default behavior
> > of git-repo-info when dealing with paths. Some ideas were:
> >
> > 1. Add --path-format, just like we have in git-rev-parse
> > 2. Use what rev-parse uses by default
> > 3. Add keys for both relative and absolute formats
> >
> > In this case, I'm using 1, but I'm not sure if it's the best option. One
> > downside that I see here is that git-repo-info won't be able to return
> > a relative and an absolute path for different keys in the same call.
> >
>
> Option 1 feels like the cleanest approach.
> Even though it means git-repo-info can't return both a relative and
> absolute path in the exact same call, it keeps the API highly predictable
> for scripting without bloating the key namespace (which Option 3 would do).
>
> The behaviour is different when compared to the command itself where we
> have to use --all, but I think in this area this is the right approach.
>
> > Since there are many people interested in contributing to git-repo-info, I'll
> > leave the remaining path-related fields to them :-)
> >
>
> Thank you ;)
>
> > I'm CC'ing here:
> >
> > - brian, who was the original author of the `print_path` [1]
> > - Ayush, Tian, Jayatheerth, Soutrik and Pushkar, since they expressed interested
> >   in contributing to git-repo-info in GSoC. (I hope that I didn't forget anyone)
> >
> > This patch is based on top of master 2cc7191751 (The 8th batch, 2026-02-27) with
> > lo/repo-leftover-bits merged.
>
>
> This provides a fantastic foundation.
> I have updated my GSoC proposal based on these patches to build out
> the remaining path.* keys, alongside category-based querying and
> global state removal.
>
> I will be sending that in a completely new thread shortly.
>
> Regards
> - Jayatheerth
JAYATHEERTH K· Mar 1, 2026, 06:50 UTC · re: Ayush Jha · lore

Re: [PATCH 0/4] repo: add support for path-related fields

Hi Ayush,
On Sun, Mar 1, 2026 at 11:15 AM Ayush Jha <kumarayushjha123@gmail.com> wrote:
Show 21 quoted lines
>
> Hi Lucas,
>
> Thanks for sharing this series — moving the path formatting logic into
> path.c makes a lot of sense and avoids duplication with rev-parse.
>
> Regarding the limitation you mentioned about not being able to mix
> relative and absolute paths within the same invocation, I was
> wondering whether it might be worth considering making the path format
> part of the key itself, rather than controlled by a global flag.
>
> For example, something along the lines of:
> path.toplevel
> path.absolute.toplevel
> path.relative.toplevel
>
> This could allow users to request different formats in a single call
> without introducing global state into the command output.
> That said, I’m not sure whether this would complicate the key
> namespace too much, or whether maintaining parity with rev-parse
> semantics is preferable for consistency.

I think this idea works for individual retrieval It still won't work when the request is for --all The main problem of absolute vs relative would arrive from the --all perspective, no?

If a script specifically needs both formats for a set of paths, the caller can easily just invoke the command twice: i.e git repo info --path-format=absolute <keys...> git repo info --path-format=relative <keys...>

It would still work for individual path terms

I think adding the absolute or relative terms in key is more of a "user" friendly one.

What do you think about it?
Regards,
- Jayatheerth
Lucas Seiki Oshiro· Mar 1, 2026, 19:55 UTC · re: Ayush Jha · lore

Re: [PATCH 0/4] repo: add support for path-related fields

> Hi Lucas,
Hi, Ayush!
> Thanks for sharing this series — moving the path formatting logic into
> path.c makes a lot of sense and avoids duplication with rev-parse.

Yeah, but since git-repo-info was written as a better home for some features currently in git-rev-parse, now we can think in better solutions.

> For example, something along the lines of:
> path.toplevel
> path.absolute.toplevel
> path.relative.toplevel

I also thought about that, but what would happen with --all? If --all returns both absolute and relative, then we would have the third solution.

Ayush Jha· Mar 3, 2026, 03:27 UTC · re: Lucas Seiki Oshiro · lore

Re: [PATCH 0/4] repo: add support for path-related fields

Hi Lucas,

I completely agree that having --all dump three variants of every path (default, relative, absolute) would be far too noisy and defeat the purpose of a clean metadata dump.

My thought is that the path.absolute.* and path.relative.* keys could be treated as "virtual" or computed keys.

If a user runs --all, the command would only iterate over and print the base keys (e.g., path.toplevel, path.git-dir). The specific format variants would simply be hidden from the iteration list, much like how some APIs only return expensive or highly-specific fields if they are explicitly requested.

This way, --all stays perfectly clean and concise, but scripts that need mixed granular control can still invoke git repo info path.absolute.git-dir path.relative.toplevel in a single pass without relying on global state flags.

Do you think treating them as explicit-request-only fields strikes the right balance between a clean --all output and a stateless API?

On Mon, Mar 2, 2026 at 1:25 AM Lucas Seiki Oshiro <lucasseikioshiro@gmail.com> wrote:

Show 21 quoted lines
>
>
> > Hi Lucas,
>
> Hi, Ayush!
>
> > Thanks for sharing this series — moving the path formatting logic into
> > path.c makes a lot of sense and avoids duplication with rev-parse.
>
> Yeah, but since git-repo-info was written as a better home for
> some features currently in git-rev-parse, now we can think in
> better solutions.
>
> > For example, something along the lines of:
> > path.toplevel
> > path.absolute.toplevel
> > path.relative.toplevel
>
> I also thought about that, but what would happen with --all?
> If --all returns both absolute and relative, then we would
> have the third solution.
Lucas Seiki Oshiro· Mar 1, 2026, 19:49 UTC · re: JAYATHEERTH K · lore

Re: [PATCH 0/4] repo: add support for path-related fields

> Option 1 feels like the cleanest approach.
> Even though it means git-repo-info can't return both a relative and
> absolute path in the exact same call, it keeps the API highly predictable
> for scripting without bloating the key namespace (which Option 3 would do).

Yeah. I think that in the future most of them will be path.*, and 3 would double them...

Phillip Wood· Mar 1, 2026, 10:44 UTC · re: Lucas Seiki Oshiro · lore

Re: [PATCH 0/4] repo: add support for path-related fields

Hi Lucas
On 28/02/2026 22:05, Lucas Seiki Oshiro wrote:
Show 10 quoted lines
> Hi!
> 
> This patch series adds support for path-related fields in repo-info, based on
> what we already have in git-rev-parse:
> 
> 1. The two first patches moves the path formatting used by git-rev-parse to
>     path.c. This will allow us to reuse this code in git-repo-info
> 2. The second patch add a new flag --path-format to git-repo-info, similar to
>     the flag of git-rev-parse with the same name
> 3. Add the new field `path.toplevel` as a proof of concept.

How does this effort relate to similar effort at at https://lore.kernel.org/pull.2208.v5.git.git.1772220640.gitgitgadget@gmail.com ? Also note the suggestion from Junio in that thread to use "path.working-tree" rather than copying the name from "git rev-parse"

> This arises from the fact that I didn't know what should be the default behavior
> of git-repo-info when dealing with paths. Some ideas were:
> 
> 1. Add --path-format, just like we have in git-rev-parse

I think that's the best solution. Having different defaults for different paths like rev-parse is confusing and having different keys for absolute and relative versions of the same path gets rather verbose.

Thanks
Phillip
Show 35 quoted lines
> 2. Use what rev-parse uses by default
> 3. Add keys for both relative and absolute formats
> 
> In this case, I'm using 1, but I'm not sure if it's the best option. One
> downside that I see here is that git-repo-info won't be able to return
> a relative and an absolute path for different keys in the same call.
> 
> Since there are many people interested in contributing to git-repo-info, I'll
> leave the remaining path-related fields to them :-)
> 
> I'm CC'ing here:
> 
> - brian, who was the original author of the `print_path` [1]
> - Ayush, Tian, Jayatheerth, Soutrik and Pushkar, since they expressed interested
>    in contributing to git-repo-info in GSoC. (I hope that I didn't forget anyone)
> 
> This patch is based on top of master 2cc7191751 (The 8th batch, 2026-02-27) with
> lo/repo-leftover-bits merged.
> 
> [1] fac60b8925 (rev-parse: add option for absolute or relative path formatting, 2020-12-13)
> 
> Lucas Seiki Oshiro (4):
>    rev-parse: prepend `path_` to path-related enums
>    path: add new function strbuf_add_path
>    repo: add the --format-path flag
>    repo: add the field path.toplevel
> 
>   Documentation/git-repo.adoc |  8 ++-
>   builtin/repo.c              | 67 +++++++++++++++++++------
>   builtin/rev-parse.c         | 98 +++++++------------------------------
>   path.c                      | 51 +++++++++++++++++++
>   path.h                      | 23 +++++++++
>   t/t1900-repo-info.sh        | 69 ++++++++++++++++++++++++++
>   6 files changed, 221 insertions(+), 95 deletions(-)
> 
Lucas Seiki Oshiro· Mar 1, 2026, 19:40 UTC · re: Phillip Wood · lore

Re: [PATCH 0/4] repo: add support for path-related fields

> Hi Lucas
Hi, Phillip!
> How does this effort relate to similar effort at at
> https://lore.kernel.org/pull.2208.v5.git.git.1772220640.gitgitgadget@gmail.com ?

I have this patch series started since July, but I could only send this after having my two previous changes in git-repo-info accepted.

I think that patch series you mentioned is based on some previous message (or the GSoC project ideas) where I listed what was still need to be implemented. It uses a similar --path-format flag, but without dealing with the multiple possibilities currently used by git-rev-parse (see [1]).

The original print_path from git-rev-parse has four possible default formats (relative, relative if there's a shared root, canonical (absolute), and unmodified), and we can force it to use the relative or absolute formats. If I understood it correctly, this complex logic was added ([1]) to allow the user to force one of these two formats without breaking the default behavior. Since git-repo-info is a new command, we are free from being compatible with that, and perhaps this doesn't make sense.

Since there are many people interested in contributing to git-repo-info, especially in the path-* fields, I just wanted to finish what I have here and leave the rest for them :-)

Show 6 quoted lines
>> 1. Add --path-format, just like we have in git-rev-parse
> 
> I think that's the best solution. Having different defaults
> for different paths like rev-parse is confusing and having
> different keys for absolute and relative versions of the
> same path gets rather verbose.

I agree, but I still think that it feels weird that we won't be able return absolute and relative paths in a single git-repo-info call. But it also won't cost too much to call it twice.

> Thanks

Thanks, Phillip! Phillip

PS: I'm also CC'ing:
- Eslam (the author of the patch mentioned by Phillip)
- Karthik, Justin, Ayush, and Siddhart (possible mentors for
  "Improve the new git repo command")
- Patrick, who was my GSoC mentor and the person I first
  discussed with about --path-format
[1] fac60b8925 (rev-parse: add option for absolute or relative path formatting, 2020-12-13)
brian m. carlson· Mar 1, 2026, 21:25 UTC · re: Lucas Seiki Oshiro · lore

Re: [PATCH 0/4] repo: add support for path-related fields

On 2026-02-28 at 22:05:54, Lucas Seiki Oshiro wrote:
Show 21 quoted lines
> Hi!
> 
> This patch series adds support for path-related fields in repo-info, based on
> what we already have in git-rev-parse:
> 
> 1. The two first patches moves the path formatting used by git-rev-parse to
>    path.c. This will allow us to reuse this code in git-repo-info
> 2. The second patch add a new flag --path-format to git-repo-info, similar to
>    the flag of git-rev-parse with the same name
> 3. Add the new field `path.toplevel` as a proof of concept.
> 
> This arises from the fact that I didn't know what should be the default behavior
> of git-repo-info when dealing with paths. Some ideas were:
> 
> 1. Add --path-format, just like we have in git-rev-parse
> 2. Use what rev-parse uses by default
> 3. Add keys for both relative and absolute formats
> 
> In this case, I'm using 1, but I'm not sure if it's the best option. One
> downside that I see here is that git-repo-info won't be able to return
> a relative and an absolute path for different keys in the same call.

I think you should provide both. I originally added this for things like `--git-common-dir`, which Git LFS would really like to have as an absolute path in the way that Git canonicalizes it, as well as potentially a relative path.

The reason is that the way Git canonicalizes things on Windows is not easily accessible on all systems or in all languages. For instance, Go has steadfastly refused to provide functionality for `GetFinalPathnameByHandle`, despite that being necessary to canonicalize the way Git does, so it's important to be able to get that information both in a relative way and as an absolute path.

On Unix, things are easier since there are fewer special file system objects and `realpath` or its equivalent are usually present in most languages.

With `git rev-parse`, you can change `--path-format` on the command line between options, so if you want both, you just request one thing, use `--path-format`, and then request the other. However, that can't be done with `git repo` and `--path-format`.

-- 
brian m. carlson (they/them)
Toronto, Ontario, CA
Junio C Hamano· Mar 2, 2026, 16:38 UTC · re: brian m. carlson · lore

Re: [PATCH 0/4] repo: add support for path-related fields

"brian m. carlson" <sandals@crustytoothpaste.net> writes:
> With `git rev-parse`, you can change `--path-format` on the command line
> between options, so if you want both, you just request one thing, use
> `--path-format`, and then request the other.  However, that can't be
> done with `git repo` and `--path-format`.

Hmph, that is one advantage of that incremental option handling done by "rev-parse", which often is a source of confusion and complaints, though ;-)

Tian Yuchen· Mar 2, 2026, 18:51 UTC · re: Junio C Hamano · lore

Re: [PATCH 0/4] repo: add support for path-related fields

On 3/3/26 00:38, Junio C Hamano wrote:
Show 10 quoted lines
> "brian m. carlson" <sandals@crustytoothpaste.net> writes:
> 
>> With `git rev-parse`, you can change `--path-format` on the command line
>> between options, so if you want both, you just request one thing, use
>> `--path-format`, and then request the other.  However, that can't be
>> done with `git repo` and `--path-format`.
> 
> Hmph, that is one advantage of that incremental option handling done
> by "rev-parse", which often is a source of confusion and complaints,
> though ;-)

Short question: Is using format modifier like (%path:relative), (%path:absolute) a good solution here? I think it can be implemented by simply adding a path parsing function in ref-filter.c (and some other work that aren't particularly challenging).

It should be user-friendly, readable and free of global flags, right? :-]
Regards,
Yuchen
Junio C Hamano· Mar 2, 2026, 21:34 UTC · re: Tian Yuchen · lore

Re: [PATCH 0/4] repo: add support for path-related fields

Tian Yuchen <a3205153416@gmail.com> writes:
Show 18 quoted lines
> On 3/3/26 00:38, Junio C Hamano wrote:
>> "brian m. carlson" <sandals@crustytoothpaste.net> writes:
>> 
>>> With `git rev-parse`, you can change `--path-format` on the command line
>>> between options, so if you want both, you just request one thing, use
>>> `--path-format`, and then request the other.  However, that can't be
>>> done with `git repo` and `--path-format`.
>> 
>> Hmph, that is one advantage of that incremental option handling done
>> by "rev-parse", which often is a source of confusion and complaints,
>> though ;-)
>
> Short question: Is using format modifier like (%path:relative), 
> (%path:absolute) a good solution here? I think it can be implemented by 
> simply adding a path parsing function in ref-filter.c (and some other 
> work that aren't particularly challenging).
>
> It should be user-friendly, readable and free of global flags, right? :-]

What command are we talking about now? Is it a plumbing where predictability, simplicity and performance matters more than end-user friendliness?

JAYATHEERTH K· Mar 3, 2026, 02:48 UTC · re: Tian Yuchen · lore

Re: [PATCH 0/4] repo: add support for path-related fields

Show 6 quoted lines
>
> Short question: Is using format modifier like (%path:relative),
> (%path:absolute) a good solution here? I think it can be implemented by
> simply adding a path parsing function in ref-filter.c (and some other
> work that aren't particularly challenging).
>

I see your point here. but wouldn't this effectively be the same as Ayush's suggestion, just with a different syntax? Whether we use distinct keys (path.absolute.toplevel) or format modifiers (%(path:absolute)) It would still result in almost the same internals.

Show 7 quoted lines
>
> Short question: Is using format modifier like (%path:relative),
> (%path:absolute) a good solution here? I think it can be implemented by
> simply adding a path parsing function in ref-filter.c (and some other
> work that aren't particularly challenging).
>
> It should be user-friendly, readable and free of global flags, right? :-]
I don't think the syntax is a concern, even if both of them are equally verbose.

Coming to user friendliness I believe Junio has already raised an appropriate question.

Tian Yuchen· Mar 3, 2026, 04:32 UTC · re: JAYATHEERTH K · lore

Re: [PATCH 0/4] repo: add support for path-related fields

Hi JAYATHEERTH,
> I see your point here.
> but wouldn't this effectively be the same as Ayush's suggestion, just
> with a different syntax?

In my view, this issue is actually to choose the most suitable tool for the job. After all, we don't want to use something like rev-parse, which is riddled with *ancient* technical debt, nor do we want to write an even more verbose parsing function from scratch for what you call verbose user input, right?

If I'm not mistaken, using different parsing functions to parse input is absolutely not just a matter of syntax differences. Instead, this will directly result in differences in data structures.

In ref-filter.c, we can easily see how Git parses format modifiers.

After the user input is parse by parse_ref_filter_atom(), it is then passed to the atom_valid[] static registry, which is like;

static struct {
	const char *name;
	info_source source;
	cmp_type cmp_type;
	int (*parser)(struct ref_format *format, struct used_atom *atom,
		      const char *arg, struct strbuf *err);
} valid_atom[] = {
	[ATOM_REFNAME] = { "refname", SOURCE_NONE, FIELD_STR, 
refname_atom_parser },
	[ATOM_OBJECTTYPE] = { "objecttype", SOURCE_OTHER, FIELD_STR, 
objecttype_atom_parser },
	[ATOM_OBJECTSIZE] = { "objectsize", SOURCE_OTHER, FIELD_ULONG, 
objectsize_atom_parser },
	[ATOM_OBJECTNAME] = { "objectname", SOURCE_OTHER, FIELD_STR, 
oid_atom_parser },
...

As you can see, each mapping relationship points to a parsing function (..._parser()). This parsing function is solely responsible for handling the state arg, fundamentally resolving the issue of function responsibility/naming confusion.

The reason I recommend this approach is because its implementation is incredibly clear and concise. To achieve the functionality we desire, all we need to do is add the following to the registry:

[ATOM_PATH] = { "path", SOURCE_NONE, FIELD_STR, path_atom_parser }
And the corresponding path_atom_parser().

This approach also offers strong scalability: If one day I decide to add a new feature like %(path:commondir,relative) output, all it would take is adding a switch statement in the parser() function (along with a few other minor tweaks).

*I'm not saying this approach is better than the solution you've discussed. I'm simply presenting a possible implementation for reference. (´~`)

> Coming to user friendliness
> I believe Junio has already raised an appropriate question.

This isn't a case of “you can't have your cake and eat it too,” right? I think user-friendliness can be achieved without compromising maintainability, predictability, or high performance in this case.

Regards,
Yuchen
JAYATHEERTH K· Mar 3, 2026, 07:23 UTC · re: Tian Yuchen · lore

Re: [PATCH 0/4] repo: add support for path-related fields

On Tue, Mar 3, 2026 at 10:02 AM Tian Yuchen <a3205153416@gmail.com> wrote:
>
> Hi JAYATHEERTH,
Hi Tian,
Show 11 quoted lines
>
> > I see your point here.
> > but wouldn't this effectively be the same as Ayush's suggestion, just
> > with a different syntax?
>
> In my view, this issue is actually to choose the most suitable tool for
> the job. After all, we don't want to use something like rev-parse, which
> is riddled with *ancient* technical debt, nor do we want to write an
> even more verbose parsing function from scratch for what you call
> verbose user input, right?
>

I agree that it provides a clean and scalable mechanism, especially in terms of extensibility and per-field formatting without relying on global flags.

To clarify my earlier comment: I wasn't arguing against ref-filter. In fact, I’m more inclined toward using the best tool for the job. My earlier point was mainly about behavioral similarity and how both belong to the same camp even though they might seem different.

Show 20 quoted lines
> If I'm not mistaken, using different parsing functions to parse input is
> absolutely not just a matter of syntax differences. Instead, this will
> directly result in differences in data structures.
>
> The reason I recommend this approach is because its implementation is
> incredibly clear and concise. To achieve the functionality we desire,
> all we need to do is add the following to the registry:
>
> [ATOM_PATH] = { "path", SOURCE_NONE, FIELD_STR, path_atom_parser }
>
> And the corresponding path_atom_parser().
>
> This approach also offers strong scalability: If one day I decide to add
> a new feature like %(path:commondir,relative) output, all it would take
> is adding a switch statement in the parser() function (along with a few
> other minor tweaks).
>
> *I'm not saying this approach is better than the solution you've
> discussed. I'm simply presenting a possible implementation for
> reference. (´~`)
That is a detailed mail, thanks for taking time

When I said similar I meant

something like this:
static const struct repo_info_field repo_info_field[] = {
    { "layout.bare", get_layout_bare },
    { "layout.shallow", get_layout_shallow },
    { "object.format", get_object_format },
    { "path.toplevel", get_path_toplevel },
};

This array contains all the keys You do not need to hardcode path.absolute.toplevel, path.relative.toplevel, etc., in the array...

Instead,

If the user asks for path.absolute.toplevel: You detect the absolute. middle part. strip it out to find the base key path.toplevel. You find path.toplevel in the aray, the array works with default values when entered --all

/*
 * Helper to parse the key variant.
 * Takes "path.absolute.git-dir" -> returns "path.git-dir" and sets
opts->format.
 */
static char *normalize_key(const char *raw_key, struct repo_info_opts *opts)
{
    const char *suffix;
    /* Check for "path.absolute." prefix */
    if (skip_prefix(raw_key, "path.absolute.", &suffix)) {
        opts->path_format = PATH_FORMAT_ABSOLUTE;
        return xstrfmt("path.%s", suffix);
    }
    /* Check for "path.relative." prefix */
    if (skip_prefix(raw_key, "path.relative.", &suffix)) {
        opts->path_format = PATH_FORMAT_RELATIVE;
        return xstrfmt("path.%s", suffix);
    }
    /* No variant found, return raw key as-is */
    return xstrdup(raw_key);
}

Structurally, this mimics the ref-filter parsing phase almost exactly. Just as ref-filter splits a compound atom like %(refname:short) into an identity (refname) and a modifier (short) to populate the handler's state, normalize_key splits path.absolute.git-dir into the identity (path.git-dir) and the modifier (absolute).

I just meant both the ideas are in the same camp just unrealized.
What do you think?
Regards
- Jayatheerth
Tian Yuchen· Mar 3, 2026, 09:28 UTC · re: JAYATHEERTH K · lore

Re: [PATCH 0/4] repo: add support for path-related fields

Hi JAYATHEERTH,
Thanks for the reply.
> To clarify my earlier comment: I wasn't arguing against ref-filter.
> In fact, I’m more inclined toward using the best tool for the job.
> My earlier point was mainly about behavioral similarity and how both
> belong to the same camp even though they might seem different.
 > I just meant both the ideas are in the same camp just unrealized.

That's exactly right. I was just reminding that there's a ready-made solution available that seems to work very well. Wouldn't reinventing something that already exists, with only minor differences, cause confusion? (´;ω;`)

Show 45 quoted lines
> something like this:
> 
> static const struct repo_info_field repo_info_field[] = {
>      { "layout.bare", get_layout_bare },
>      { "layout.shallow", get_layout_shallow },
>      { "object.format", get_object_format },
>      { "path.toplevel", get_path_toplevel },
> };
> 
> This array contains all the keys
> You do not need to hardcode path.absolute.toplevel,
> path.relative.toplevel, etc., in the array...
> 
> Instead,
> 
> If the user asks for path.absolute.toplevel:
> You detect the absolute. middle part. strip it out to find the base
> key path.toplevel.
> You find path.toplevel in the aray, the array works with default
> values when entered --all
> 
> /*
>   * Helper to parse the key variant.
>   * Takes "path.absolute.git-dir" -> returns "path.git-dir" and sets
> opts->format.
>   */
> static char *normalize_key(const char *raw_key, struct repo_info_opts *opts)
> {
>      const char *suffix;
> 
>      /* Check for "path.absolute." prefix */
>      if (skip_prefix(raw_key, "path.absolute.", &suffix)) {
>          opts->path_format = PATH_FORMAT_ABSOLUTE;
>          return xstrfmt("path.%s", suffix);
>      }
> 
>      /* Check for "path.relative." prefix */
>      if (skip_prefix(raw_key, "path.relative.", &suffix)) {
>          opts->path_format = PATH_FORMAT_RELATIVE;
>          return xstrfmt("path.%s", suffix);
>      }
> 
>      /* No variant found, return raw key as-is */
>      return xstrdup(raw_key);
> }

I see. What you've written matches what you described — it essentially replicates the functionality of ref-filter.c. While I understand this is just a simple code implementation demo:

 >          opts->path_format = PATH_FORMAT_ABSOLUTE;

This implementation appears unable to support input like 'git repo-info --keys=path.absolute.toplevel,path.relative.gitdir', meaning it cannot handle multiple paths output from a single call as previously mentioned by Brain. The 'opts' here should be a global shared state, right?

I think it's better for the parser to allocate a separate memory for each arg it encounters. But then we'd be back to implementing something like struct used_atom, hahaha (ゝ∀・)

Thank you again for your email.
Yuchen

(I feel like we've been on this topic for too long. If you don't want to reply, you don't have to :-)

JAYATHEERTH K· Mar 3, 2026, 10:31 UTC · re: Tian Yuchen · lore

Re: [PATCH 0/4] repo: add support for path-related fields

Show 19 quoted lines
>
> I see. What you've written matches what you described — it essentially
> replicates the functionality of ref-filter.c. While I understand this is
> just a simple code implementation demo:
>
>  >          opts->path_format = PATH_FORMAT_ABSOLUTE;
>
> This implementation appears unable to support input like 'git repo-info
> --keys=path.absolute.toplevel,path.relative.gitdir', meaning it cannot
> handle multiple paths output from a single call as previously mentioned
> by Brain. The 'opts' here should be a global shared state, right?
>
> I think it's better for the parser to allocate a separate memory for
> each arg it encounters. But then we'd be back to implementing something
> like struct used_atom, hahaha (ゝ∀・)
>
> Thank you again for your email.
>
> Yuchen

We create a fresh local_opts copy from the global_opts defaults for every single key:

for (int i = 0; i < argc; i++) {
    struct repo_info_opts local_opts = global_opts; /* Fresh reset */
    char *base_key = normalize_key(argv[i], &local_opts);
    /* ... find_field and get_value logic ... */
}

Since local_opts is local to the loop iteration, path.absolute.toplevel only modifies the state for that specific turn. When the loop moves to path.relative.gitdir, it gets a brand-new local_opts and starts over. It handles mixed formats in a single call perfectly, without any persistent _pollution_ or the need for complex heap allocations.

>
> (I feel like we've been on this topic for too long. If you don't want to
> reply, you don't have to :-)
>

I agree we've covered a lot of ground here, so I'll leave it at that. Thanks for the great discussion ;)

Regards, Jayatheerth

Lucas Seiki Oshiro· Mar 8, 2026, 00:29 UTC · re: brian m. carlson · lore

Re: [PATCH 0/4] repo: add support for path-related fields

> I think you should provide both.  I originally added this for things
> like `--git-common-dir`, which Git LFS would really like to have as an
> absolute path in the way that Git canonicalizes it, as well as
> potentially a relative path.
Thanks for your input, brian!
> With `git rev-parse`, you can change `--path-format` on the command line
> between options, so if you want both, you just request one thing, use
> `--path-format`, and then request the other.  However, that can't be
> done with `git repo` and `--path-format`.

It makes sense. If we use the key format suggested by Ayush [1] we could retrieve both values with something like

   $ git repo info path.git-dir.absolute path.git-dir.relative

I'll stop by now. Since many people are interested in contributing to git-repo-info in GSoC, I'll leave this decision to the person who will work on it, if there is one.

[1] B46AA932-28EF-4A2C-96B9-0F05D9641C1C@gmail.com

← back to recent threads