git/list[1] front-page[2] threads[3] people[4] search[5] about
 

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

From
Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
Date
Feb 28, 2026, 22:05 UTC
Message-ID
<20260228224252.72788-5-lucasseikioshiro@gmail.com>
In-Reply-To
<20260228224252.72788-1-lucasseikioshiro@gmail.com>

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(-)
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)
Previous: Lucas Seiki OshiroNext: Tian Yuchen
Message 5 of 26 in “repo: add support for path-related fields”
  1. 0/4 repo: add support for path-related fieldsLucas Seiki Oshiro, Feb 28, 2026
  2. 1/4 rev-parse: prepend `path_` to path-related enumsLucas Seiki Oshiro, Feb 28, 2026
  3. 2/4 path: add new function strbuf_add_pathLucas Seiki Oshiro, Feb 28, 2026
  4. 3/4 repo: add the --format-path flagLucas Seiki Oshiro, Feb 28, 2026
  5. 4/4 repo: add the field path.toplevelLucas Seiki Oshiro, Feb 28, 2026
  6. Tian YuchenMar 1, 2026
  7. Lucas Seiki OshiroMar 1, 2026
  8. Tian YuchenMar 2, 2026
  9. JAYATHEERTH KMar 1, 2026
  10. Ayush JhaMar 1, 2026
  11. JAYATHEERTH KMar 1, 2026
  12. Lucas Seiki OshiroMar 1, 2026
  13. Ayush JhaMar 3, 2026
  14. Lucas Seiki OshiroMar 1, 2026
  15. Phillip WoodMar 1, 2026
  16. Lucas Seiki OshiroMar 1, 2026
  17. brian m. carlsonMar 1, 2026
  18. Junio C HamanoMar 2, 2026
  19. Tian YuchenMar 2, 2026
  20. Junio C HamanoMar 2, 2026
  21. JAYATHEERTH KMar 3, 2026
  22. Tian YuchenMar 3, 2026
  23. JAYATHEERTH KMar 3, 2026
  24. Tian YuchenMar 3, 2026
  25. JAYATHEERTH KMar 3, 2026
  26. Lucas Seiki OshiroMar 8, 2026

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.