Subject: [PATCH v6 0/6] repo info: add category/path keys and --path-format

From: "eslam reda via GitGitGadget" <[email-masked]>
Date: Mon, 02 Mar 2026 05:15:42 +0000

This series now focuses only on git repo info improvements.
===========================================================

It introduces category-aware key requests, adds path-oriented keys (path.*),
and adds --path-format=(absolute|relative) so scripts can request stable
path rendering behavior.

What this PR does
=================

For git repo info, this series:

 * introduces explicit repo_info context plumbing,
 * adds category-key expansion (for example, layout expands to layout.*),
 * adds path-oriented keys (path.*) for common repository locations,
 * adds --path-format=(absolute|relative) to control path output style.

Tests and documentation are updated accordingly.

What this PR does NOT do
========================

 * No git repo structure feature changes.
 * No t1901 structure test changes.
 * No structure metrics/docs additions.

Key naming/scope adjustments from review
========================================

 * renamed path.git-prefix to path.prefix,
 * added path.working-tree (alias for path.toplevel),
 * removed file-layout-oriented keys:
   * path.logs-directory
   * path.packed-refs-file
   * path.refs-directory
   * path.shallow-file
 * for bare repositories, work-tree style keys return empty values.

Commit structure
================

 * repo: introduce repo_info context plumbing
 * repo: support category requests in repo info
 * repo: add path keys to repo info
 * repo: add --path-format for info path output
 * t1900: cover repo info path keys and path-format
 * docs: describe repo info path keys

All commits are signed off with the same real-name identity.

Changes since previous revision
===============================

 * dropped all repo structure code/tests/docs from this branch,
 * split context plumbing and category expansion into separate commits,
 * rebased and cleaned history to avoid fix-on-fix commits,
 * aligned key naming/scope with review feedback.

Validation
==========

Focused (Linux Docker):

 * make -C t test T=t1900-repo.sh → passed (53/53)

Eslam reda ragheb (6):
  repo: introduce repo_info context plumbing
  repo: support category requests in repo info
  repo: add path keys to repo info
  repo: add --path-format for info path output
  t1900: cover repo info path keys and path-format
  docs: describe repo info path keys

 Documentation/git-repo.adoc |  58 +++++++++-
 builtin/repo.c              | 209 +++++++++++++++++++++++++++++++++---
 t/t1900-repo.sh             | 194 +++++++++++++++++++++++++++++++++
 3 files changed, 441 insertions(+), 20 deletions(-)

base-commit: 2cc71917514657b93014134350864f4849edfc83
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-2208%2Feslam-reda-div%2Fgsoc-contribute-v6
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-2208/eslam-reda-div/gsoc-contribute-v6
Pull-Request: https://github.com/git/git/pull/2208

Range-diff vs v5:

  1:  99c8058298 !  1:  bddea1a22e repo: teach info context and category keys
     @@ Metadata
      Author: Eslam reda ragheb <[email-masked]>
      
       ## Commit message ##
     -    repo: teach info context and category keys
     +    repo: introduce repo_info context plumbing
      
     -    Introduce an explicit repo_info context for the repo info codepath
     -    and thread it through value lookups and field printing.
     +    Introduce a repo_info context and thread it through get_value_fn,
     +    field lookup, and value-printing helpers.
      
     -    This removes direct coupling from these helpers to ad-hoc
     -    repository globals and makes key retrieval logic easier to extend
     -    safely.
     -
     -    Also teach git repo info to accept category names (for example,
     -    layout) and expand them to matching key.* entries in request
     -    order.
     -
     -    This improves script ergonomics while preserving existing behavior
     -    for explicit keys and clear errors for unknown names.
     +    This prepares repo info for fields that need invocation-specific
     +    context in addition to the repository handle.
      
          Signed-off-by: Eslam reda ragheb <[email-masked]>
      
     @@ builtin/repo.c: struct field {
       	strbuf_addstr(buf,
       		      ref_storage_format_to_name(repo->ref_storage_format));
       	return 0;
     -@@ builtin/repo.c: static get_value_fn *get_value_fn_for_key(const char *key)
     - 	return found ? found->get_value : NULL;
     - }
     - 
     -+static void print_field(enum output_format format, const char *key,
     -+			const char *value);
     -+
     -+static int print_category_fields(const char *category,
     -+				 struct repo_info *info,
     -+				 enum output_format format,
     -+				 struct strbuf *valbuf)
     -+{
     -+	int found = 0;
     -+	size_t category_len = strlen(category);
     -+
     -+	for (size_t i = 0; i < ARRAY_SIZE(repo_info_fields); i++) {
     -+		const struct field *field = &repo_info_fields[i];
     -+
     -+		if (!starts_with(field->key, category) ||
     -+		    field->key[category_len] != '.')
     -+			continue;
     -+
     -+		strbuf_reset(valbuf);
     -+		field->get_value(info, valbuf);
     -+		print_field(format, field->key, valbuf->buf);
     -+		found = 1;
     -+	}
     -+
     -+	return found;
     -+}
     -+
     - static void print_field(enum output_format format, const char *key,
     - 			const char *value)
     - {
      @@ builtin/repo.c: static void print_field(enum output_format format, const char *key,
       }
       
     @@ builtin/repo.c: static void print_field(enum output_format format, const char *k
       {
       	int ret = 0;
      @@ builtin/repo.c: static int print_fields(int argc, const char **argv,
     - 
     - 		get_value = get_value_fn_for_key(key);
     - 
     --		if (!get_value) {
     --			ret = error(_("key '%s' not found"), key);
     -+		if (get_value) {
     -+			strbuf_reset(&valbuf);
     -+			get_value(info, &valbuf);
     -+			print_field(format, key, valbuf.buf);
     - 			continue;
       		}
       
     --		strbuf_reset(&valbuf);
     + 		strbuf_reset(&valbuf);
      -		get_value(repo, &valbuf);
     --		print_field(format, key, valbuf.buf);
     -+		if (!print_category_fields(key, info, format, &valbuf))
     -+			ret = error(_("key '%s' not found"), key);
     ++		get_value(info, &valbuf);
     + 		print_field(format, key, valbuf.buf);
       	}
       
     - 	strbuf_release(&valbuf);
     +@@ builtin/repo.c: static int print_fields(int argc, const char **argv,
       	return ret;
       }
       
     @@ builtin/repo.c: static int print_all_fields(struct repository *repo,
      @@ builtin/repo.c: static int cmd_repo_info(int argc, const char **argv, const char *prefix,
       			 struct repository *repo)
       {
     - 	enum output_format format = FORMAT_KEYVALUE;
     + 	enum output_format format = FORMAT_NEWLINE_TERMINATED;
      +	struct repo_info info = {
      +		.repo = repo,
      +		.prefix = prefix,
      +	};
       	int all_keys = 0;
     + 	int show_keys = 0;
       	struct option options[] = {
     - 		OPT_CALLBACK_F(0, "format", &format, N_("format"),
      @@ builtin/repo.c: static int cmd_repo_info(int argc, const char **argv, const char *prefix,
       		die(_("--all and <key> cannot be used together"));
       
  4:  504d9cf7a0 !  2:  2369608976 repo: add structure max object size metrics
     @@ Metadata
      Author: Eslam reda ragheb <[email-masked]>
      
       ## Commit message ##
     -    repo: add structure max object size metrics
     +    repo: support category requests in repo info
      
     -    Extend git repo structure with maximum inflated and on-disk object
     -    sizes, both per type and overall max values.
     +    Teach repo info to accept category names (for example, layout)
     +    and expand them to matching key.* entries in request order.
      
     -    This complements existing totals by highlighting outliers that
     -    often drive repository bloat analysis.
     -
     -    The implementation updates object counting to track per-type maxima
     -    while walking reachable objects.
     -
     -    It exposes those values in both table and keyvalue formats for
     -    scripts and human output.
     +    Explicit keys keep their existing behavior; unknown keys or
     +    categories still report clear errors.
      
          Signed-off-by: Eslam reda ragheb <[email-masked]>
      
       ## builtin/repo.c ##
     -@@ builtin/repo.c: struct object_values {
     - struct object_stats {
     - 	struct object_values type_counts;
     - 	struct object_values inflated_sizes;
     -+	struct object_values max_inflated_sizes;
     - 	struct object_values disk_sizes;
     -+	struct object_values max_disk_sizes;
     - };
     - 
     - struct repo_structure {
     -@@ builtin/repo.c: static inline size_t get_total_object_values(struct object_values *values)
     - 	return values->tags + values->commits + values->trees + values->blobs;
     +@@ builtin/repo.c: static get_value_fn *get_value_fn_for_key(const char *key)
     + 	return found ? found->get_value : NULL;
       }
       
     -+static inline size_t get_max_object_value(struct object_values *values)
     ++static void print_field(enum output_format format, const char *key,
     ++			const char *value);
     ++
     ++static int print_category_fields(const char *category,
     ++				 struct repo_info *info,
     ++				 enum output_format format,
     ++				 struct strbuf *valbuf)
      +{
     -+	size_t max = values->commits;
     ++	int found = 0;
     ++	size_t category_len = strlen(category);
      +
     -+	if (values->trees > max)
     -+		max = values->trees;
     -+	if (values->blobs > max)
     -+		max = values->blobs;
     -+	if (values->tags > max)
     -+		max = values->tags;
     ++	for (size_t i = 0; i < ARRAY_SIZE(repo_info_fields); i++) {
     ++		const struct field *field = &repo_info_fields[i];
      +
     -+	return max;
     -+}
     ++		if (!starts_with(field->key, category) ||
     ++		    field->key[category_len] != '.')
     ++			continue;
      +
     - static void stats_table_setup_structure(struct stats_table *table,
     - 					struct repo_structure *stats)
     - {
     -@@ builtin/repo.c: static void stats_table_setup_structure(struct stats_table *table,
     - 			      "    * %s", _("Blobs"));
     - 	stats_table_size_addf(table, objects->disk_sizes.tags,
     - 			      "    * %s", _("Tags"));
     ++		strbuf_reset(valbuf);
     ++		field->get_value(info, valbuf);
     ++		print_field(format, field->key, valbuf->buf);
     ++		found = 1;
     ++	}
      +
     -+	stats_table_size_addf(table, objects->max_inflated_sizes.commits,
     -+			      "  * %s", _("Largest commit"));
     -+	stats_table_size_addf(table, objects->max_inflated_sizes.trees,
     -+			      "  * %s", _("Largest tree"));
     -+	stats_table_size_addf(table, objects->max_inflated_sizes.blobs,
     -+			      "  * %s", _("Largest blob"));
     -+	stats_table_size_addf(table, objects->max_inflated_sizes.tags,
     -+			      "  * %s", _("Largest tag"));
     ++	return found;
     ++}
      +
     -+	stats_table_size_addf(table, get_max_object_value(&objects->max_disk_sizes),
     -+			      "  * %s", _("Largest disk size"));
     -+	stats_table_size_addf(table, objects->max_disk_sizes.commits,
     -+			      "    * %s", _("Commits"));
     -+	stats_table_size_addf(table, objects->max_disk_sizes.trees,
     -+			      "    * %s", _("Trees"));
     -+	stats_table_size_addf(table, objects->max_disk_sizes.blobs,
     -+			      "    * %s", _("Blobs"));
     -+	stats_table_size_addf(table, objects->max_disk_sizes.tags,
     -+			      "    * %s", _("Tags"));
     - }
     - 
     - static void stats_table_print_structure(const struct stats_table *table)
     -@@ builtin/repo.c: static void stats_table_clear(struct stats_table *table)
     - static void structure_keyvalue_print(struct repo_structure *stats,
     - 				     char key_delim, char value_delim)
     + static void print_field(enum output_format format, const char *key,
     + 			const char *value)
       {
     -+	size_t max_inflated_size = get_max_object_value(&stats->objects.max_inflated_sizes);
     -+	size_t max_disk_size = get_max_object_value(&stats->objects.max_disk_sizes);
     -+
     - 	printf("references.branches.count%c%" PRIuMAX "%c", key_delim,
     - 	       (uintmax_t)stats->refs.branches, value_delim);
     - 	printf("references.tags.count%c%" PRIuMAX "%c", key_delim,
     -@@ builtin/repo.c: static void structure_keyvalue_print(struct repo_structure *stats,
     - 	printf("objects.tags.inflated_size%c%" PRIuMAX "%c", key_delim,
     - 	       (uintmax_t)stats->objects.inflated_sizes.tags, value_delim);
     +@@ builtin/repo.c: static int print_fields(int argc, const char **argv,
       
     -+	printf("objects.max_inflated_size%c%" PRIuMAX "%c", key_delim,
     -+	       (uintmax_t)max_inflated_size, value_delim);
     -+	printf("objects.commits.max_inflated_size%c%" PRIuMAX "%c", key_delim,
     -+	       (uintmax_t)stats->objects.max_inflated_sizes.commits, value_delim);
     -+	printf("objects.trees.max_inflated_size%c%" PRIuMAX "%c", key_delim,
     -+	       (uintmax_t)stats->objects.max_inflated_sizes.trees, value_delim);
     -+	printf("objects.blobs.max_inflated_size%c%" PRIuMAX "%c", key_delim,
     -+	       (uintmax_t)stats->objects.max_inflated_sizes.blobs, value_delim);
     -+	printf("objects.tags.max_inflated_size%c%" PRIuMAX "%c", key_delim,
     -+	       (uintmax_t)stats->objects.max_inflated_sizes.tags, value_delim);
     -+
     -+	printf("objects.max_disk_size%c%" PRIuMAX "%c", key_delim,
     -+	       (uintmax_t)max_disk_size, value_delim);
     -+	printf("objects.commits.max_disk_size%c%" PRIuMAX "%c", key_delim,
     -+	       (uintmax_t)stats->objects.max_disk_sizes.commits, value_delim);
     -+	printf("objects.trees.max_disk_size%c%" PRIuMAX "%c", key_delim,
     -+	       (uintmax_t)stats->objects.max_disk_sizes.trees, value_delim);
     -+	printf("objects.blobs.max_disk_size%c%" PRIuMAX "%c", key_delim,
     -+	       (uintmax_t)stats->objects.max_disk_sizes.blobs, value_delim);
     -+	printf("objects.tags.max_disk_size%c%" PRIuMAX "%c", key_delim,
     -+	       (uintmax_t)stats->objects.max_disk_sizes.tags, value_delim);
     -+
     - 	printf("objects.commits.disk_size%c%" PRIuMAX "%c", key_delim,
     - 	       (uintmax_t)stats->objects.disk_sizes.commits, value_delim);
     - 	printf("objects.trees.disk_size%c%" PRIuMAX "%c", key_delim,
     -@@ builtin/repo.c: static int count_objects(const char *path UNUSED, struct oid_array *oids,
     - 	struct object_stats *stats = data->stats;
     - 	size_t inflated_total = 0;
     - 	size_t disk_total = 0;
     -+	size_t max_inflated = 0;
     -+	size_t max_disk = 0;
     - 	size_t object_count;
     + 		get_value = get_value_fn_for_key(key);
       
     - 	for (size_t i = 0; i < oids->nr; i++) {
     -@@ builtin/repo.c: static int count_objects(const char *path UNUSED, struct oid_array *oids,
     - 						  OBJECT_INFO_SKIP_FETCH_OBJECT |
     - 						  OBJECT_INFO_QUICK) < 0)
     +-		if (!get_value) {
     +-			ret = error(_("key '%s' not found"), key);
     ++		if (get_value) {
     ++			strbuf_reset(&valbuf);
     ++			get_value(info, &valbuf);
     ++			print_field(format, key, valbuf.buf);
       			continue;
     -+		if (disk < 0)
     -+			continue;
     + 		}
       
     - 		inflated_total += inflated;
     --		disk_total += disk;
     -+		disk_total += (size_t)disk;
     -+		if (inflated > max_inflated)
     -+			max_inflated = inflated;
     -+		if ((size_t)disk > max_disk)
     -+			max_disk = (size_t)disk;
     +-		strbuf_reset(&valbuf);
     +-		get_value(info, &valbuf);
     +-		print_field(format, key, valbuf.buf);
     ++		if (!print_category_fields(key, info, format, &valbuf))
     ++			ret = error(_("key '%s' not found"), key);
       	}
       
     - 	switch (type) {
     - 	case OBJ_TAG:
     - 		stats->type_counts.tags += oids->nr;
     - 		stats->inflated_sizes.tags += inflated_total;
     -+		if (max_inflated > stats->max_inflated_sizes.tags)
     -+			stats->max_inflated_sizes.tags = max_inflated;
     - 		stats->disk_sizes.tags += disk_total;
     -+		if (max_disk > stats->max_disk_sizes.tags)
     -+			stats->max_disk_sizes.tags = max_disk;
     - 		break;
     - 	case OBJ_COMMIT:
     - 		stats->type_counts.commits += oids->nr;
     - 		stats->inflated_sizes.commits += inflated_total;
     -+		if (max_inflated > stats->max_inflated_sizes.commits)
     -+			stats->max_inflated_sizes.commits = max_inflated;
     - 		stats->disk_sizes.commits += disk_total;
     -+		if (max_disk > stats->max_disk_sizes.commits)
     -+			stats->max_disk_sizes.commits = max_disk;
     - 		break;
     - 	case OBJ_TREE:
     - 		stats->type_counts.trees += oids->nr;
     - 		stats->inflated_sizes.trees += inflated_total;
     -+		if (max_inflated > stats->max_inflated_sizes.trees)
     -+			stats->max_inflated_sizes.trees = max_inflated;
     - 		stats->disk_sizes.trees += disk_total;
     -+		if (max_disk > stats->max_disk_sizes.trees)
     -+			stats->max_disk_sizes.trees = max_disk;
     - 		break;
     - 	case OBJ_BLOB:
     - 		stats->type_counts.blobs += oids->nr;
     - 		stats->inflated_sizes.blobs += inflated_total;
     -+		if (max_inflated > stats->max_inflated_sizes.blobs)
     -+			stats->max_inflated_sizes.blobs = max_inflated;
     - 		stats->disk_sizes.blobs += disk_total;
     -+		if (max_disk > stats->max_disk_sizes.blobs)
     -+			stats->max_disk_sizes.blobs = max_disk;
     - 		break;
     - 	default:
     - 		BUG("invalid object type");
     + 	strbuf_release(&valbuf);
  2:  6d5b9ff075 !  3:  477333a94c repo: add path keys to repo info
     @@ builtin/repo.c: static int get_object_format(struct repo_info *info, struct strb
      +	return 0;
      +}
      +
     -+static int get_path_git_prefix(struct repo_info *info, struct strbuf *buf)
     ++static int get_path_prefix(struct repo_info *info, struct strbuf *buf)
      +{
     -+	if (info->prefix)
     -+		strbuf_addstr(buf, info->prefix);
     ++	strbuf_addstr(buf, info->prefix);
      +	return 0;
      +}
      +
     @@ builtin/repo.c: static int get_object_format(struct repo_info *info, struct strb
      +	return 0;
      +}
      +
     -+static int get_path_logs_directory(struct repo_info *info, struct strbuf *buf)
     -+{
     -+	struct strbuf path = STRBUF_INIT;
     -+
     -+	repo_info_add_path(info, buf, repo_git_path_replace(info->repo, &path, "logs"));
     -+	strbuf_release(&path);
     -+	return 0;
     -+}
     -+
      +static int get_path_objects_directory(struct repo_info *info, struct strbuf *buf)
      +{
      +	repo_info_add_path(info, buf, repo_get_object_directory(info->repo));
      +	return 0;
      +}
      +
     -+static int get_path_packed_refs_file(struct repo_info *info, struct strbuf *buf)
     -+{
     -+	struct strbuf path = STRBUF_INIT;
     -+
     -+	repo_info_add_path(info, buf, repo_git_path_replace(info->repo, &path, "packed-refs"));
     -+	strbuf_release(&path);
     -+	return 0;
     -+}
     -+
     -+static int get_path_refs_directory(struct repo_info *info, struct strbuf *buf)
     -+{
     -+	struct strbuf path = STRBUF_INIT;
     -+
     -+	repo_info_add_path(info, buf, repo_git_path_replace(info->repo, &path, "refs"));
     -+	strbuf_release(&path);
     -+	return 0;
     -+}
     -+
     -+static int get_path_shallow_file(struct repo_info *info, struct strbuf *buf)
     -+{
     -+	struct strbuf path = STRBUF_INIT;
     -+
     -+	repo_info_add_path(info, buf, repo_git_path_replace(info->repo, &path, "shallow"));
     -+	strbuf_release(&path);
     -+	return 0;
     -+}
     -+
      +static int get_path_superproject_working_tree(struct repo_info *info,
      +					     struct strbuf *buf)
      +{
     @@ builtin/repo.c: static int get_object_format(struct repo_info *info, struct strb
      +
      +	return 0;
      +}
     ++
     ++static int get_path_work_tree(struct repo_info *info, struct strbuf *buf)
     ++{
     ++	return get_path_toplevel(info, buf);
     ++}
      +
       static int get_references_format(struct repo_info *info, struct strbuf *buf)
       {
     @@ builtin/repo.c: static const struct field repo_info_fields[] = {
      +	{ "path.common-dir", get_path_common_dir },
      +	{ "path.config-file", get_path_config_file },
      +	{ "path.git-dir", get_path_git_dir },
     -+	{ "path.git-prefix", get_path_git_prefix },
      +	{ "path.grafts-file", get_path_grafts_file },
      +	{ "path.hooks-directory", get_path_hooks_directory },
      +	{ "path.index-file", get_path_index_file },
     -+	{ "path.logs-directory", get_path_logs_directory },
      +	{ "path.objects-directory", get_path_objects_directory },
     -+	{ "path.packed-refs-file", get_path_packed_refs_file },
     -+	{ "path.refs-directory", get_path_refs_directory },
     -+	{ "path.shallow-file", get_path_shallow_file },
     ++	{ "path.prefix", get_path_prefix },
      +	{ "path.superproject-working-tree", get_path_superproject_working_tree },
      +	{ "path.toplevel", get_path_toplevel },
     ++	{ "path.working-tree", get_path_work_tree },
       	{ "references.format", get_references_format },
       };
       
     +@@ builtin/repo.c: static int cmd_repo_info(int argc, const char **argv, const char *prefix,
     + 	enum output_format format = FORMAT_NEWLINE_TERMINATED;
     + 	struct repo_info info = {
     + 		.repo = repo,
     +-		.prefix = prefix,
     ++		.prefix = prefix ? prefix : "",
     + 	};
     + 	int all_keys = 0;
     + 	int show_keys = 0;
  3:  5c438d045b !  4:  2a7afe4f87 repo: add --path-format for info path output
     @@ builtin/repo.c
       #include "utf8.h"
       
       static const char *const repo_usage[] = {
     --	"git repo info [--format=(keyvalue|nul) | -z] [--all | <key>...]",
     -+	"git repo info [--format=(keyvalue|nul) | -z] [--path-format=(absolute|relative)] [--all | <key>...]",
     - 	"git repo structure [--format=(table|keyvalue|nul) | -z]",
     +-	"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
       };
       
     @@ builtin/repo.c: static int parse_format_cb(const struct option *opt,
      @@ builtin/repo.c: static int cmd_repo_info(int argc, const char **argv, const char *prefix,
       	struct repo_info info = {
       		.repo = repo,
     - 		.prefix = prefix,
     + 		.prefix = prefix ? prefix : "",
      +		.path_format = PATH_FORMAT_ABSOLUTE,
       	};
       	int all_keys = 0;
     - 	struct option options[] = {
     + 	int show_keys = 0;
      @@ builtin/repo.c: static int cmd_repo_info(int argc, const char **argv, const char *prefix,
       			       N_("synonym for --format=nul"),
       			       PARSE_OPT_NONEG | PARSE_OPT_NOARG,
     @@ builtin/repo.c: static int cmd_repo_info(int argc, const char **argv, const char
      +			       N_("format"), N_("path output format"),
      +			       PARSE_OPT_NONEG, parse_path_format_cb),
       		OPT_BOOL(0, "all", &all_keys, N_("print all keys/values")),
     + 		OPT_BOOL(0, "keys", &show_keys, N_("show keys")),
       		OPT_END()
     - 	};
  5:  4b502925c9 <  -:  ---------- repo: add structure topology and path-depth metrics
  6:  1751181950 <  -:  ---------- repo: add aggregate structure totals to keyvalue output
  7:  fd18f28db0 !  5:  1e52e7bd7f t1900: cover repo info path keys and path-format
     @@ Commit message
          Signed-off-by: Eslam reda ragheb <[email-masked]>
      
       ## t/t1900-repo.sh ##
     -@@ t/t1900-repo.sh: REPO_INFO_KEYS='
     - 	layout.bare
     - 	layout.shallow
     - 	object.format
     +@@ t/t1900-repo.sh: test_description='test git repo-info'
     + 
     + . ./test-lib.sh
     + 
     ++# git-repo-info keys. It must contain the same keys listed in the const
     ++# repo_info_fields, in lexicographical order.
     ++REPO_INFO_KEYS='
     ++	layout.bare
     ++	layout.shallow
     ++	object.format
      +	path.common-dir
      +	path.config-file
      +	path.git-dir
     -+	path.git-prefix
      +	path.grafts-file
      +	path.hooks-directory
      +	path.index-file
     -+	path.logs-directory
      +	path.objects-directory
     -+	path.packed-refs-file
     -+	path.refs-directory
     -+	path.shallow-file
     ++	path.prefix
      +	path.superproject-working-tree
      +	path.toplevel
     - 	references.format
     - '
     - 
     ++	path.working-tree
     ++	references.format
     ++'
     ++
      +REPO_INFO_PATH_KEYS='
      +	path.common-dir
      +	path.config-file
      +	path.git-dir
     -+	path.git-prefix
      +	path.grafts-file
      +	path.hooks-directory
      +	path.index-file
     -+	path.logs-directory
      +	path.objects-directory
     -+	path.packed-refs-file
     -+	path.refs-directory
     -+	path.shallow-file
     ++	path.prefix
      +	path.superproject-working-tree
      +	path.toplevel
     ++	path.working-tree
      +'
      +
       # Test whether a key-value pair is correctly returned
     @@ t/t1900-repo.sh: test_expect_success 'values returned in order requested' '
      +	test_cmp expect actual
      +'
      +
     -+test_expect_success 'path.git-prefix matches rev-parse --show-prefix' '
     ++test_expect_success 'path.prefix matches rev-parse --show-prefix' '
      +	git init path-prefix &&
      +	mkdir -p path-prefix/a/b &&
      +	expected_value=$(git -C path-prefix/a/b rev-parse --show-prefix) &&
     -+	echo "path.git-prefix=$expected_value" >expect &&
     -+	git -C path-prefix/a/b repo info path.git-prefix >actual &&
     ++	echo "path.prefix=$expected_value" >expect &&
     ++	git -C path-prefix/a/b repo info path.prefix >actual &&
      +	test_cmp expect actual
      +'
      +
     @@ t/t1900-repo.sh: test_expect_success 'values returned in order requested' '
      +	expected_value=$(git -C path-git-path rev-parse --path-format=absolute --git-path config) &&
      +	echo "path.config-file=$expected_value" >expect &&
      +	git -C path-git-path repo info path.config-file >actual &&
     -+	test_cmp expect actual &&
     -+
     -+	expected_value=$(git -C path-git-path rev-parse --path-format=absolute --git-path logs) &&
     -+	echo "path.logs-directory=$expected_value" >expect &&
     -+	git -C path-git-path repo info path.logs-directory >actual &&
     -+	test_cmp expect actual &&
     -+
     -+	expected_value=$(git -C path-git-path rev-parse --path-format=absolute --git-path packed-refs) &&
     -+	echo "path.packed-refs-file=$expected_value" >expect &&
     -+	git -C path-git-path repo info path.packed-refs-file >actual &&
     -+	test_cmp expect actual &&
     ++	test_cmp expect actual
     ++'
      +
     -+	expected_value=$(git -C path-git-path rev-parse --path-format=absolute --git-path refs) &&
     -+	echo "path.refs-directory=$expected_value" >expect &&
     -+	git -C path-git-path repo info path.refs-directory >actual &&
     -+	test_cmp expect actual &&
     ++test_expect_success 'path.working-tree matches path.toplevel' '
     ++	git init path-work-tree &&
     ++	expected_value=$(git -C path-work-tree rev-parse --show-toplevel) &&
     ++	echo "path.working-tree=$expected_value" >expect &&
     ++	git -C path-work-tree repo info path.working-tree >actual &&
     ++	test_cmp expect actual
     ++'
      +
     -+	expected_value=$(git -C path-git-path rev-parse --path-format=absolute --git-path shallow) &&
     -+	echo "path.shallow-file=$expected_value" >expect &&
     -+	git -C path-git-path repo info path.shallow-file >actual &&
     ++test_expect_success 'path.working-tree is empty in bare repository' '
     ++	git init --bare bare-path-work-tree &&
     ++	echo "path.working-tree=" >expect &&
     ++	git -C bare-path-work-tree repo info path.working-tree >actual &&
      +	test_cmp expect actual
      +'
      +
  8:  0525ed4cd9 <  -:  ---------- t1901: extend structure metric coverage and portability
  9:  f17c0f03e5 !  6:  b98490a4a4 docs: describe repo info path keys and structure metrics
     @@ Metadata
      Author: Eslam reda ragheb <[email-masked]>
      
       ## Commit message ##
     -    docs: describe repo info path keys and structure metrics
     +    docs: describe repo info path keys
      
     -    Document the newly added repo info capabilities, including
     -    category keys and path-oriented key definitions.
     -
     -    Also describe --path-format behavior for path outputs.
     -
     -    Update git repo structure documentation to cover newly reported
     -    maxima and aggregate keyvalue/nul fields.
     -
     -    This keeps command behavior and output keys fully specified for
     -    users and scripts.
     +    Document repo info category requests, path.* keys, and
     +    --path-format behavior.
      
          Signed-off-by: Eslam reda ragheb <[email-masked]>
      
     @@ Documentation/git-repo.adoc: git-repo - Retrieve information about the repositor
       SYNOPSIS
       --------
       [synopsis]
     --git repo info [--format=(keyvalue|nul) | -z] [--all | <key>...]
     -+git repo info [--format=(keyvalue|nul) | -z] [--path-format=(absolute|relative)] [--all | <key>...]
     - git repo structure [--format=(table|keyvalue|nul) | -z]
     +-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]
       
     - DESCRIPTION
      @@ Documentation/git-repo.adoc: supported:
     - +
     - `-z` is an alias for `--format=nul`.
     + `nul`:::
     + 	Similar to `lines`, but using a _NUL_ character after each value.
       
      +`--path-format=(absolute|relative)`:::
      +	Controls formatting for keys in the `path` category. The default is
      +	`absolute`. This option may be specified multiple times; the last one
      +	specified takes effect.
      +
     - `structure [--format=(table|keyvalue|nul) | -z]`::
     + `structure [--format=(table|lines|nul) | -z]`::
       	Retrieve statistics about the current repository structure. The
       	following kinds of information are reported:
      @@ Documentation/git-repo.adoc: supported:
     @@ Documentation/git-repo.adoc: supported:
       The output format can be chosen through the flag `--format`. Three formats are
       supported:
      @@ Documentation/git-repo.adoc: supported:
     - `keyvalue`:::
     + `lines`:::
       	Each line of output contains a key-value pair for a repository stat.
       	The '=' character is used to delimit between the key and the value.
      +	Both aggregate metrics and per-type metrics are included.
     @@ Documentation/git-repo.adoc: values that they return:
      +`path.git-dir`::
      +	The path to the git directory.
      +
     -+`path.git-prefix`::
     ++`path.prefix`::
      +	The path of the current working directory relative to the top-level
      +	directory.
      +
     @@ Documentation/git-repo.adoc: values that they return:
      +`path.index-file`::
      +	The path to the index file.
      +
     -+`path.logs-directory`::
     -+	The path to the `logs` directory.
     -+
      +`path.objects-directory`::
      +	The path to the objects directory.
      +
     -+`path.packed-refs-file`::
     -+	The path to the `packed-refs` file.
     -+
     -+`path.refs-directory`::
     -+	The path to the `refs` directory.
     -+
     -+`path.shallow-file`::
     -+	The path to the `shallow` file.
     -+
      +`path.superproject-working-tree`::
      +	The path to the superproject's working tree root, or an empty string
      +	when the repository is not used as a submodule.
     @@ Documentation/git-repo.adoc: values that they return:
      +`path.toplevel`::
      +	The path to the top-level working tree directory, or an empty string
      +	for bare repositories.
     ++
     ++`path.working-tree`::
     ++	Alias for `path.toplevel`.
      +
       `references.format`::
       	The reference storage format. The valid values are:
 10:  1bc100d6ca <  -:  ---------- repo: reduce repetition in structure keyvalue output
 11:  8af17ad831 <  -:  ---------- repo: refine path keys for repo info

-- 
gitgitgadget