From: "eslam reda via GitGitGadget" <gitgitgadget@gmail.com>
To: git@vger.kernel.org
Cc: Karthik Nayak <karthik.188@gmail.com>,
Justin Tobler <jltobler@gmail.com>,
Ayush Chandekar <ayu.chandekar@gmail.com>,
Siddharth Asthana <siddharthasthana31@gmail.com>,
Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>,
eslam reda <eslam.reda.div@gmail.com>
Subject: [PATCH v2 0/9] repo: extend info path reporting and structure statistics
Date: Mon, 23 Feb 2026 14:21:00 +0000 [thread overview]
Message-ID: <pull.2208.v2.git.git.1771856469.gitgitgadget@gmail.com> (raw)
In-Reply-To: <pull.2208.git.git.1771784936.gitgitgadget@gmail.com>
This series improves git repo info and git repo structure with a
================================================================
cleanly split commit history and explicit documentation/tests.
For git repo info, this series:
* introduces explicit command context plumbing (instead of ad-hoc global
reliance in this codepath),
* adds category-key expansion (for example, requesting layout expands to
layout.* keys),
* adds path-oriented keys (path.*) that expose repository locations,
* adds --path-format=(absolute|relative) to control path rendering.
For git repo structure, this series adds richer metrics:
* maximum inflated object size (overall + per type),
* maximum on-disk object size (overall + per type),
* maximum commit parent count,
* maximum tree entry count,
* maximum blob path length and path depth,
* maximum annotated tag chain depth,
* aggregate keyvalue/nul totals (references.count, objects.count,
objects.inflated_size, objects.disk_size).
Tests and documentation are updated accordingly.
----------------------------------------------------------------------------
Why this change
===============
The intent is to make git repo more script-friendly and more useful for
repository diagnostics:
* repo info becomes easier to query programmatically (category keys,
explicit path formatting).
* repo structure becomes more actionable by exposing outlier-focused
metrics (maxima), not only totals.
* keyvalue/nul output now includes aggregate totals so scripts do not need
to recompute them externally.
----------------------------------------------------------------------------
Commit structure (v2 rewrite)
=============================
This iteration rewrites history into smaller logical steps (no
“fix-on-fix”):
1. repo: teach info context and category keys
2. repo: add path keys to repo info
3. repo: add --path-format for info path output
4. repo: add structure max object size metrics
5. repo: add structure topology and path-depth metrics
6. repo: add aggregate structure totals to keyvalue output
7. t1900: cover repo info path keys and path-format
8. t1901: extend structure metric coverage and portability
9. docs: describe repo info path keys and structure metrics
All commits are signed off using real-name identity.
----------------------------------------------------------------------------
Changes since v1
================
* Rewrote series into smaller logical commits.
* Folded fixes into proper history (no trailing fix-up patches).
* Unified author/sign-off identity to real name.
* Addressed portability concerns raised in review:
* hash-algorithm-sensitive expectations are handled robustly,
* BSD/macOS wc whitespace behavior is handled in tests.
* Improved test robustness around keyvalue/nul expectations.
* Expanded docs to explicitly describe new keys/metrics and behavior.
* Revalidated in Docker with focused and full test runs.
----------------------------------------------------------------------------
Validation
==========
Focused:
* t1900-repo.sh
* GIT_TEST_DEFAULT_REF_FORMAT=reftable t/t1901-repo-structure.sh
Full:
* make -C t -j4 test in clean Docker environment
* Result: failed 0
----------------------------------------------------------------------------
Eslam reda ragheb (9):
repo: teach info context and category keys
repo: add path keys to repo info
repo: add --path-format for info path output
repo: add structure max object size metrics
repo: add structure topology and path-depth metrics
repo: add aggregate structure totals to keyvalue output
t1900: cover repo info path keys and path-format
t1901: extend structure metric coverage and portability
docs: describe repo info path keys and structure metrics
Documentation/git-repo.adoc | 67 ++++-
builtin/repo.c | 518 ++++++++++++++++++++++++++++++++++--
t/t1900-repo.sh | 196 ++++++++++++++
t/t1901-repo-structure.sh | 250 ++++++++++++-----
4 files changed, 946 insertions(+), 85 deletions(-)
base-commit: 7c02d39fc2ed2702223c7674f73150d9a7e61ba4
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-2208%2Feslam-reda-div%2Fgsoc-contribute-v2
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-2208/eslam-reda-div/gsoc-contribute-v2
Pull-Request: https://github.com/git/git/pull/2208
Range-diff vs v1:
-: ---------- > 1: 99c8058298 repo: teach info context and category keys
-: ---------- > 2: 6d5b9ff075 repo: add path keys to repo info
-: ---------- > 3: 5c438d045b repo: add --path-format for info path output
-: ---------- > 4: 504d9cf7a0 repo: add structure max object size metrics
-: ---------- > 5: 4b502925c9 repo: add structure topology and path-depth metrics
-: ---------- > 6: 1751181950 repo: add aggregate structure totals to keyvalue output
-: ---------- > 7: fd18f28db0 t1900: cover repo info path keys and path-format
1: 9f2b3a46a4 ! 8: 0525ed4cd9 repo: extend info paths and structure statistics
@@
## Metadata ##
-Author: eslam-reda-div <eslam.reda.div@gmail.com>
+Author: Eslam reda ragheb <eslam.reda.div@gmail.com>
## Commit message ##
- repo: extend info paths and structure statistics
+ t1901: extend structure metric coverage and portability
- Improve git repo info by adding path-oriented keys that match values
- users currently obtain from git rev-parse, including common directory,
- git directory, top-level, superproject working tree, and additional
- git-path based locations.
+ Expand t1901 to cover additional structure metrics emitted by git
+ repo structure, including maxima and aggregate keyvalue/nul
+ checks.
- Teach git repo info to accept category keys like layout and path,
- and add --path-format=(absolute|relative) so scripts can request the
- desired path style explicitly. The command now uses repository context
- passed to the command path instead of relying on global state.
+ The test now validates both human-oriented table content and
+ machine-readable fields for the extended metric set.
- Extend git repo structure with deeper repository metrics inspired by
- git-sizer, including per-type maximum inflated and on-disk object sizes,
- maximum commit parent count, maximum tree entry count, longest/deepest
- blob path, and deepest annotated tag chain.
+ Also make expectations more portable across hash algorithms and
+ platforms by avoiding brittle assumptions.
- Update documentation and tests to cover new keys, formats, and metrics.
+ This includes wc output quirks on BSD/macOS and hash-format-
+ sensitive expectations.
- Signed-off-by: eslam-reda-div <eslam.reda.div@gmail.com>
-
- ## Documentation/git-repo.adoc ##
-@@ Documentation/git-repo.adoc: git-repo - Retrieve information about the repository
- 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]
-
- DESCRIPTION
-@@ Documentation/git-repo.adoc: supported:
- +
- `-z` is an alias for `--format=nul`.
-
-+`--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]`::
- Retrieve statistics about the current repository structure. The
- following kinds of information are reported:
-@@ Documentation/git-repo.adoc: supported:
- * Reachable object counts categorized by type
- * Total inflated size of reachable objects by type
- * Total disk size of reachable objects by type
-+* Largest inflated reachable object size by type
-+* Largest disk size of a reachable object by type
-+* Largest parent count among reachable commits
-+* Largest entry count among reachable trees
-+* Longest and deepest path among reachable blobs
-+* Deepest annotated tag chain
- +
- The output format can be chosen through the flag `--format`. Three formats are
- supported:
-@@ Documentation/git-repo.adoc: supported:
- `keyvalue`:::
- 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.
- Values containing "unusual" characters are quoted as explained for the
- configuration variable `core.quotePath` (see linkgit:git-config[1]).
-
-@@ Documentation/git-repo.adoc: supported:
-
- INFO KEYS
- ---------
--In order to obtain a set of values from `git repo info`, you should provide
--the keys that identify them. Here's a list of the available keys and the
--values that they return:
-+In order to obtain values from `git repo info`, provide either individual keys
-+or category names. A category returns all keys within that category. For
-+example, `layout` returns both `layout.bare` and `layout.shallow`.
-+
-+Here's a list of the available keys and the values that they return:
-
- `layout.bare`::
- `true` if this is a bare repository, otherwise `false`.
-@@ Documentation/git-repo.adoc: values that they return:
- `object.format`::
- The object format (hash algorithm) used in the repository.
-
-+`path.common-dir`::
-+ The path to the common git directory.
-+
-+`path.config-file`::
-+ The path to the `config` file in the git directory.
-+
-+`path.git-dir`::
-+ The path to the git directory.
-+
-+`path.git-prefix`::
-+ The path of the current working directory relative to the top-level
-+ directory.
-+
-+`path.grafts-file`::
-+ The path to the `info/grafts` file.
-+
-+`path.hooks-directory`::
-+ The path to the `hooks` directory.
-+
-+`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.
-+
-+`path.toplevel`::
-+ The path to the top-level working tree directory, or an empty string
-+ for bare repositories.
-+
- `references.format`::
- The reference storage format. The valid values are:
- +
-
- ## builtin/repo.c ##
-@@
--#define USE_THE_REPOSITORY_VARIABLE
--
- #include "builtin.h"
--#include "environment.h"
-+#include "abspath.h"
- #include "hex.h"
- #include "odb.h"
- #include "parse-options.h"
-+#include "path.h"
- #include "path-walk.h"
- #include "progress.h"
- #include "quote.h"
-@@
- #include "revision.h"
- #include "strbuf.h"
- #include "string-list.h"
-+#include "submodule.h"
- #include "shallow.h"
-+#include "tree-walk.h"
- #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]",
- NULL
- };
-
--typedef int get_value_fn(struct repository *repo, struct strbuf *buf);
-+enum path_format {
-+ PATH_FORMAT_ABSOLUTE,
-+ PATH_FORMAT_RELATIVE,
-+};
-+
-+struct repo_info {
-+ struct repository *repo;
-+ const char *prefix;
-+ enum path_format path_format;
-+};
-+
-+typedef int get_value_fn(struct repo_info *info, struct strbuf *buf);
-
- enum output_format {
- FORMAT_TABLE,
-@@ builtin/repo.c: struct field {
- get_value_fn *get_value;
- };
-
--static int get_layout_bare(struct repository *repo UNUSED, struct strbuf *buf)
-+static void repo_info_add_path(struct repo_info *info,
-+ struct strbuf *buf,
-+ const char *path)
- {
-- strbuf_addstr(buf, is_bare_repository() ? "true" : "false");
-+ if (info->path_format == PATH_FORMAT_RELATIVE) {
-+ char *cwd = xgetcwd();
-+ struct strbuf rel_path = STRBUF_INIT;
-+
-+ strbuf_addstr(buf, relative_path(path, cwd, &rel_path));
-+ strbuf_release(&rel_path);
-+ free(cwd);
-+ return;
-+ }
-+
-+ strbuf_add_absolute_path(buf, path);
-+}
-+
-+static int get_layout_bare(struct repo_info *info, struct strbuf *buf)
-+{
-+ struct repository *repo = info->repo;
-+ strbuf_addstr(buf, repo_get_work_tree(repo) ? "false" : "true");
- return 0;
- }
-
--static int get_layout_shallow(struct repository *repo, struct strbuf *buf)
-+static int get_layout_shallow(struct repo_info *info, struct strbuf *buf)
- {
-+ struct repository *repo = info->repo;
- 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 repo_info *info, struct strbuf *buf)
- {
-+ struct repository *repo = info->repo;
- strbuf_addstr(buf, repo->hash_algo->name);
- return 0;
- }
-
--static int get_references_format(struct repository *repo, struct strbuf *buf)
-+static int get_path_common_dir(struct repo_info *info, struct strbuf *buf)
-+{
-+ repo_info_add_path(info, buf, repo_get_common_dir(info->repo));
-+ return 0;
-+}
-+
-+static int get_path_config_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, "config"));
-+ strbuf_release(&path);
-+ return 0;
-+}
-+
-+static int get_path_git_dir(struct repo_info *info, struct strbuf *buf)
-+{
-+ repo_info_add_path(info, buf, repo_get_git_dir(info->repo));
-+ return 0;
-+}
-+
-+static int get_path_git_prefix(struct repo_info *info, struct strbuf *buf)
-+{
-+ if (info->prefix)
-+ strbuf_addstr(buf, info->prefix);
-+ return 0;
-+}
-+
-+static int get_path_grafts_file(struct repo_info *info, struct strbuf *buf)
-+{
-+ repo_info_add_path(info, buf, repo_get_graft_file(info->repo));
-+ return 0;
-+}
-+
-+static int get_path_hooks_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, "hooks"));
-+ strbuf_release(&path);
-+ return 0;
-+}
-+
-+static int get_path_index_file(struct repo_info *info, struct strbuf *buf)
-+{
-+ repo_info_add_path(info, buf, repo_get_index_file(info->repo));
-+ 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)
-+{
-+ struct strbuf superproject = STRBUF_INIT;
-+
-+ if (get_superproject_working_tree(&superproject))
-+ repo_info_add_path(info, buf, superproject.buf);
-+
-+ strbuf_release(&superproject);
-+ return 0;
-+}
-+
-+static int get_path_toplevel(struct repo_info *info, struct strbuf *buf)
-+{
-+ const char *work_tree = repo_get_work_tree(info->repo);
-+
-+ if (work_tree)
-+ repo_info_add_path(info, buf, work_tree);
-+
-+ return 0;
-+}
-+
-+static int get_references_format(struct repo_info *info, struct strbuf *buf)
- {
-+ struct repository *repo = info->repo;
- strbuf_addstr(buf,
- ref_storage_format_to_name(repo->ref_storage_format));
- return 0;
-@@ builtin/repo.c: static const struct field repo_info_fields[] = {
- { "layout.bare", get_layout_bare },
- { "layout.shallow", get_layout_shallow },
- { "object.format", get_object_format },
-+ { "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.superproject-working-tree", get_path_superproject_working_tree },
-+ { "path.toplevel", get_path_toplevel },
- { "references.format", get_references_format },
- };
-
-@@ 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,
- }
-
- static int print_fields(int argc, const char **argv,
-- struct repository *repo,
-+ struct repo_info *info,
- enum output_format format)
- {
- 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);
-- 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);
- }
-
- strbuf_release(&valbuf);
- return ret;
- }
-
--static int print_all_fields(struct repository *repo,
-+static int print_all_fields(struct repo_info *info,
- enum output_format format)
- {
- struct strbuf valbuf = STRBUF_INIT;
-@@ builtin/repo.c: static int print_all_fields(struct repository *repo,
- const struct field *field = &repo_info_fields[i];
-
- strbuf_reset(&valbuf);
-- field->get_value(repo, &valbuf);
-+ field->get_value(info, &valbuf);
- print_field(format, field->key, valbuf.buf);
- }
-
-@@ builtin/repo.c: static int parse_format_cb(const struct option *opt,
- return 0;
- }
-
-+static int parse_path_format_cb(const struct option *opt,
-+ const char *arg, int unset UNUSED)
-+{
-+ enum path_format *path_format = opt->value;
-+
-+ if (!strcmp(arg, "absolute"))
-+ *path_format = PATH_FORMAT_ABSOLUTE;
-+ else if (!strcmp(arg, "relative"))
-+ *path_format = PATH_FORMAT_RELATIVE;
-+ else
-+ die(_("invalid path format '%s'"), arg);
-+
-+ return 0;
-+}
-+
- static int cmd_repo_info(int argc, const char **argv, const char *prefix,
- struct repository *repo)
- {
- enum output_format format = FORMAT_KEYVALUE;
-+ struct repo_info info = {
-+ .repo = repo,
-+ .prefix = prefix,
-+ .path_format = PATH_FORMAT_ABSOLUTE,
-+ };
- int all_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,
- N_("synonym for --format=nul"),
- PARSE_OPT_NONEG | PARSE_OPT_NOARG,
- parse_format_cb),
-+ OPT_CALLBACK_F(0, "path-format", &info.path_format,
-+ 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_END()
- };
-@@ builtin/repo.c: 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(&info, format);
- else
-- return print_fields(argc, argv, repo, format);
-+ return print_fields(argc, argv, &info, format);
- }
-
- struct ref_stats {
-@@ 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;
-+ size_t max_commit_parent_count;
-+ size_t max_tree_entry_count;
-+ size_t max_blob_path_length;
-+ size_t max_blob_path_depth;
-+ size_t max_tag_chain_depth;
- };
-
- 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;
- }
-
-+static inline size_t get_max_object_value(struct object_values *values)
-+{
-+ size_t max = values->commits;
-+
-+ if (values->trees > max)
-+ max = values->trees;
-+ if (values->blobs > max)
-+ max = values->blobs;
-+ if (values->tags > max)
-+ max = values->tags;
-+
-+ return max;
-+}
-+
-+static size_t get_commit_parent_count(struct repository *repo,
-+ const struct object_id *oid)
-+{
-+ unsigned long size = 0;
-+ const char *cur;
-+ const char *end;
-+ void *buf;
-+ size_t count = 0;
-+
-+ buf = odb_read_object_peeled(repo->objects, oid, OBJ_COMMIT, &size, NULL);
-+ if (!buf)
-+ return 0;
-+
-+ cur = buf;
-+ end = cur + size;
-+ while (cur < end) {
-+ const char *newline = memchr(cur, '\n', end - cur);
-+ size_t line_len;
-+
-+ if (!newline)
-+ break;
-+ line_len = newline - cur;
-+ if (!line_len)
-+ break;
-+
-+ if (line_len > 7 && !memcmp(cur, "parent ", 7))
-+ count++;
-+
-+ cur = newline + 1;
-+ }
-+
-+ free(buf);
-+ return count;
-+}
-+
-+static size_t get_tree_entry_count(struct repository *repo,
-+ const struct object_id *oid)
-+{
-+ struct tree_desc desc;
-+ struct name_entry entry;
-+ unsigned long size = 0;
-+ void *buf;
-+ size_t count = 0;
-+
-+ buf = odb_read_object_peeled(repo->objects, oid, OBJ_TREE, &size, NULL);
-+ if (!buf)
-+ return 0;
-+
-+ init_tree_desc(&desc, oid, buf, size);
-+ while (tree_entry(&desc, &entry))
-+ count++;
-+
-+ free(buf);
-+ return count;
-+}
-+
-+static size_t get_path_depth(const char *path)
-+{
-+ size_t depth = 0;
-+
-+ if (!path || !*path)
-+ return 0;
-+
-+ depth = 1;
-+ for (const char *cur = path; *cur; cur++)
-+ if (*cur == '/')
-+ depth++;
-+
-+ return depth;
-+}
-+
-+static size_t get_tag_chain_depth(struct repository *repo,
-+ const struct object_id *oid)
-+{
-+ struct object_id current = *oid;
-+ size_t depth = 0;
-+
-+ while (1) {
-+ enum object_type type;
-+ unsigned long size = 0;
-+ struct object_id next;
-+ const char *p, *end;
-+ void *buf = odb_read_object(repo->objects, ¤t, &type, &size);
-+
-+ if (!buf)
-+ break;
-+ if (type != OBJ_TAG) {
-+ free(buf);
-+ break;
-+ }
-+
-+ p = buf;
-+ if (!skip_prefix(p, "object ", &p) ||
-+ parse_oid_hex_algop(p, &next, &end, repo->hash_algo) ||
-+ *end != '\n') {
-+ free(buf);
-+ break;
-+ }
-+
-+ depth++;
-+ free(buf);
-+
-+ if (oideq(&next, ¤t))
-+ break;
-+ oidcpy(¤t, &next);
-+ }
-+
-+ return depth;
-+}
-+
- 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"));
-+
-+ 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"));
-+
-+ 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"));
-+
-+ stats_table_count_addf(table, objects->max_commit_parent_count,
-+ " * %s", _("Largest parent count"));
-+ stats_table_count_addf(table, objects->max_tree_entry_count,
-+ " * %s", _("Largest tree entries"));
-+ stats_table_count_addf(table, objects->max_blob_path_length,
-+ " * %s", _("Longest blob path"));
-+ stats_table_count_addf(table, objects->max_blob_path_depth,
-+ " * %s", _("Deepest blob path"));
-+ stats_table_count_addf(table, objects->max_tag_chain_depth,
-+ " * %s", _("Deepest tag chain"));
- }
-
- 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)
- {
-+ size_t references_count_total = get_total_reference_count(&stats->refs);
-+ size_t object_count_total = get_total_object_values(&stats->objects.type_counts);
-+ size_t inflated_size_total = get_total_object_values(&stats->objects.inflated_sizes);
-+ size_t disk_size_total = get_total_object_values(&stats->objects.disk_sizes);
-+ 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.count%c%" PRIuMAX "%c", key_delim,
-+ (uintmax_t)references_count_total, value_delim);
- 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("references.others.count%c%" PRIuMAX "%c", key_delim,
- (uintmax_t)stats->refs.others, value_delim);
-
-+ printf("objects.count%c%" PRIuMAX "%c", key_delim,
-+ (uintmax_t)object_count_total, value_delim);
- printf("objects.commits.count%c%" PRIuMAX "%c", key_delim,
- (uintmax_t)stats->objects.type_counts.commits, value_delim);
- printf("objects.trees.count%c%" PRIuMAX "%c", key_delim,
-@@ builtin/repo.c: static void structure_keyvalue_print(struct repo_structure *stats,
- printf("objects.tags.count%c%" PRIuMAX "%c", key_delim,
- (uintmax_t)stats->objects.type_counts.tags, value_delim);
-
-+ printf("objects.inflated_size%c%" PRIuMAX "%c", key_delim,
-+ (uintmax_t)inflated_size_total, value_delim);
- printf("objects.commits.inflated_size%c%" PRIuMAX "%c", key_delim,
- (uintmax_t)stats->objects.inflated_sizes.commits, value_delim);
- printf("objects.trees.inflated_size%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);
-
-+ 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.disk_size%c%" PRIuMAX "%c", key_delim,
-+ (uintmax_t)disk_size_total, 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.max_parent_count%c%" PRIuMAX "%c", key_delim,
-+ (uintmax_t)stats->objects.max_commit_parent_count, value_delim);
-+ printf("objects.trees.max_entry_count%c%" PRIuMAX "%c", key_delim,
-+ (uintmax_t)stats->objects.max_tree_entry_count, value_delim);
-+ printf("objects.blobs.max_path_length%c%" PRIuMAX "%c", key_delim,
-+ (uintmax_t)stats->objects.max_blob_path_length, value_delim);
-+ printf("objects.blobs.max_path_depth%c%" PRIuMAX "%c", key_delim,
-+ (uintmax_t)stats->objects.max_blob_path_depth, value_delim);
-+ printf("objects.tags.max_chain_depth%c%" PRIuMAX "%c", key_delim,
-+ (uintmax_t)stats->objects.max_tag_chain_depth, 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: struct count_objects_data {
- struct progress *progress;
- };
-
--static int count_objects(const char *path UNUSED, struct oid_array *oids,
-+static int count_objects(const char *path, struct oid_array *oids,
- enum object_type type, void *cb_data)
- {
- struct count_objects_data *data = cb_data;
- 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;
-
- for (size_t i = 0; i < oids->nr; i++) {
-@@ builtin/repo.c: static int count_objects(const char *path UNUSED, struct oid_array *oids,
-
- if (odb_read_object_info_extended(data->odb, &oids->oid[i], &oi,
- OBJECT_INFO_SKIP_FETCH_OBJECT |
-- OBJECT_INFO_QUICK) < 0)
-+ OBJECT_INFO_QUICK) < 0)
-+ 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;
- }
-
- switch (type) {
- case OBJ_TAG:
-+ for (size_t i = 0; i < oids->nr; i++) {
-+ size_t tag_chain_depth = get_tag_chain_depth(data->odb->repo,
-+ &oids->oid[i]);
-+
-+ if (tag_chain_depth > stats->max_tag_chain_depth)
-+ stats->max_tag_chain_depth = tag_chain_depth;
-+ }
-+
- 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:
-+ for (size_t i = 0; i < oids->nr; i++) {
-+ size_t parent_count = get_commit_parent_count(data->odb->repo,
-+ &oids->oid[i]);
-+
-+ if (parent_count > stats->max_commit_parent_count)
-+ stats->max_commit_parent_count = parent_count;
-+ }
-+
- 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:
-+ for (size_t i = 0; i < oids->nr; i++) {
-+ size_t entry_count = get_tree_entry_count(data->odb->repo,
-+ &oids->oid[i]);
-+
-+ if (entry_count > stats->max_tree_entry_count)
-+ stats->max_tree_entry_count = entry_count;
-+ }
-+
- 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:
-+ if (path && *path) {
-+ size_t path_len = strlen(path);
-+ size_t path_depth = get_path_depth(path);
-+
-+ if (path_len > stats->max_blob_path_length)
-+ stats->max_blob_path_length = path_len;
-+ if (path_depth > stats->max_blob_path_depth)
-+ stats->max_blob_path_depth = path_depth;
-+ }
-+
- 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");
-
- ## t/t1900-repo.sh ##
-@@ t/t1900-repo.sh: 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.superproject-working-tree
-+ path.toplevel
- 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.superproject-working-tree
-+ path.toplevel
-+'
-+
- # Test whether a key-value pair is correctly returned
- #
- # Usage: test_repo_info <label> <init command> <repo_name> <key> <expected value>
-@@ t/t1900-repo.sh: test_expect_success 'values returned in order requested' '
- test_cmp expect actual
- '
-
-+test_expect_success 'category key returns all matching keys' '
-+ cat >expect <<-\EOF &&
-+ layout.bare=false
-+ layout.shallow=false
-+ EOF
-+ git init category-layout &&
-+ git -C category-layout repo info layout >actual &&
-+ test_cmp expect actual
-+'
-+
-+test_expect_success 'mixed key/category requests preserve request order' '
-+ cat >expect <<-\EOF &&
-+ object.format=sha1
-+ layout.bare=false
-+ layout.shallow=false
-+ EOF
-+ git init mixed-order &&
-+ git -C mixed-order repo info object.format layout >actual &&
-+ test_cmp expect actual
-+'
-+
-+test_expect_success 'path.git-dir matches rev-parse --absolute-git-dir' '
-+ git init path-git-dir &&
-+ expected_value=$(git -C path-git-dir rev-parse --absolute-git-dir) &&
-+ echo "path.git-dir=$expected_value" >expect &&
-+ git -C path-git-dir repo info path.git-dir >actual &&
-+ test_cmp expect actual
-+'
-+
-+test_expect_success 'path.common-dir matches rev-parse --git-common-dir' '
-+ git init path-common-dir &&
-+ expected_value=$(git -C path-common-dir rev-parse --path-format=absolute --git-common-dir) &&
-+ echo "path.common-dir=$expected_value" >expect &&
-+ git -C path-common-dir repo info path.common-dir >actual &&
-+ test_cmp expect actual
-+'
-+
-+test_expect_success 'path.toplevel matches rev-parse --show-toplevel' '
-+ git init path-toplevel &&
-+ expected_value=$(git -C path-toplevel rev-parse --show-toplevel) &&
-+ echo "path.toplevel=$expected_value" >expect &&
-+ git -C path-toplevel repo info path.toplevel >actual &&
-+ test_cmp expect actual
-+'
-+
-+test_expect_success 'path.toplevel is empty in bare repository' '
-+ git init --bare bare-path-toplevel &&
-+ echo "path.toplevel=" >expect &&
-+ git -C bare-path-toplevel repo info path.toplevel >actual &&
-+ test_cmp expect actual
-+'
-+
-+test_expect_success 'path.git-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 &&
-+ test_cmp expect actual
-+'
-+
-+test_expect_success 'git-path style keys match rev-parse --git-path' '
-+ git init path-git-path &&
-+
-+ expected_value=$(git -C path-git-path rev-parse --path-format=absolute --git-path info/grafts) &&
-+ echo "path.grafts-file=$expected_value" >expect &&
-+ git -C path-git-path repo info path.grafts-file >actual &&
-+ test_cmp expect actual &&
-+
-+ expected_value=$(git -C path-git-path rev-parse --path-format=absolute --git-path index) &&
-+ echo "path.index-file=$expected_value" >expect &&
-+ git -C path-git-path repo info path.index-file >actual &&
-+ test_cmp expect actual &&
-+
-+ expected_value=$(git -C path-git-path rev-parse --path-format=absolute --git-path objects) &&
-+ echo "path.objects-directory=$expected_value" >expect &&
-+ git -C path-git-path repo info path.objects-directory >actual &&
-+ test_cmp expect actual &&
-+
-+ expected_value=$(git -C path-git-path rev-parse --path-format=absolute --git-path hooks) &&
-+ echo "path.hooks-directory=$expected_value" >expect &&
-+ git -C path-git-path repo info path.hooks-directory >actual &&
-+ test_cmp expect actual &&
-+
-+ 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 &&
-+
-+ 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 &&
-+
-+ 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_cmp expect actual
-+'
-+
-+test_expect_success 'path.superproject-working-tree is empty when not a submodule' '
-+ git init path-superproject &&
-+ echo "path.superproject-working-tree=" >expect &&
-+ git -C path-superproject repo info path.superproject-working-tree >actual &&
-+ test_cmp expect actual
-+'
-+
-+test_expect_success 'path.superproject-working-tree matches rev-parse in submodule' '
-+ git init path-superproject-origin &&
-+ echo x >path-superproject-origin/x &&
-+ git -C path-superproject-origin add x &&
-+ git -C path-superproject-origin commit -m x &&
-+
-+ git init path-superproject-parent &&
-+ git -C path-superproject-parent -c protocol.file.allow=always submodule add ../path-superproject-origin sm &&
-+
-+ expected_value=$(git -C path-superproject-parent/sm rev-parse --show-superproject-working-tree) &&
-+ echo "path.superproject-working-tree=$expected_value" >expect &&
-+ git -C path-superproject-parent/sm repo info path.superproject-working-tree >actual &&
-+ test_cmp expect actual
-+'
-+
-+test_expect_success 'path category returns all path keys' '
-+ git init path-category &&
-+ >expect &&
-+ for key in $REPO_INFO_PATH_KEYS
-+ do
-+ git -C path-category repo info "$key" >>expect || return 1
-+ done &&
-+ git -C path-category repo info path >actual &&
-+ test_cmp expect actual
-+'
-+
-+test_expect_success 'path-format=relative matches rev-parse for git-dir' '
-+ git init path-format-relative &&
-+ expected_value=$(git -C path-format-relative rev-parse --path-format=relative --git-dir) &&
-+ echo "path.git-dir=$expected_value" >expect &&
-+ git -C path-format-relative repo info --path-format=relative path.git-dir >actual &&
-+ test_cmp expect actual
-+'
-+
-+test_expect_success 'git repo info uses the last requested path format' '
-+ git init path-format-last &&
-+ expected_value=$(git -C path-format-last rev-parse --path-format=relative --git-dir) &&
-+ echo "path.git-dir=$expected_value" >expect &&
-+ git -C path-format-last repo info --path-format=absolute --path-format=relative path.git-dir >actual &&
-+ test_cmp expect actual
-+'
-+
-+test_expect_success 'git-repo-info aborts when requesting an invalid path format' '
-+ echo "fatal: invalid path format ${SQ}foo${SQ}" >expect &&
-+ test_must_fail git repo info --path-format=foo path.git-dir 2>actual &&
-+ test_cmp expect actual
-+'
-+
- test_expect_success 'git-repo-info fails if an invalid key is requested' '
- echo "error: key ${SQ}foo${SQ} not found" >expect &&
- test_must_fail git repo info foo 2>actual &&
+ Signed-off-by: Eslam reda ragheb <eslam.reda.div@gmail.com>
## t/t1901-repo-structure.sh ##
@@ t/t1901-repo-structure.sh: object_type_disk_usage() {
@@ t/t1901-repo-structure.sh: object_type_disk_usage() {
+ --filter=object:type=tree --filter-provided-objects | cut -d" " -f1)
+ do
+ entries=$(git cat-file -p "$oid" | wc -l) || return 1
-+ test "$entries" -gt "$max" && max=$entries
++ test $entries -gt $max && max=$entries
+ done
+
-+ echo "$max"
++ echo $max
+}
+
+blob_max_path_length() {
2: cb85ee3b48 < -: ---------- t1900,t1901: make repo tests hash-agnostic and wc-portable
3: 3c656bf152 < -: ---------- t1900,t1901: fix test portability issues
-: ---------- > 9: f17c0f03e5 docs: describe repo info path keys and structure metrics
--
gitgitgadget
next prev parent reply other threads:[~2026-02-23 14:21 UTC|newest]
Thread overview: 68+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-02-22 18:28 [PATCH 0/3] repo: extend info path reporting and structure statistics eslam reda via GitGitGadget
2026-02-22 18:28 ` [PATCH 1/3] repo: extend info paths " eslam-reda-div via GitGitGadget
2026-02-22 20:35 ` Lucas Seiki Oshiro
2026-02-23 3:02 ` Justin Tobler
2026-02-22 18:28 ` [PATCH 2/3] t1900,t1901: make repo tests hash-agnostic and wc-portable Eslam reda ragheb via GitGitGadget
2026-02-22 20:46 ` Lucas Seiki Oshiro
2026-02-22 18:28 ` [PATCH 3/3] t1900,t1901: fix test portability issues Eslam reda ragheb via GitGitGadget
2026-02-22 22:37 ` [PATCH 0/3] repo: extend info path reporting and structure statistics Junio C Hamano
2026-02-23 14:21 ` eslam reda via GitGitGadget [this message]
2026-02-23 14:21 ` [PATCH v2 1/9] repo: teach info context and category keys Eslam reda ragheb via GitGitGadget
2026-02-23 14:21 ` [PATCH v2 2/9] repo: add path keys to repo info Eslam reda ragheb via GitGitGadget
2026-02-23 14:21 ` [PATCH v2 4/9] repo: add structure max object size metrics Eslam reda ragheb via GitGitGadget
2026-02-23 14:21 ` [PATCH v2 5/9] repo: add structure topology and path-depth metrics Eslam reda ragheb via GitGitGadget
2026-02-23 14:21 ` [PATCH v2 6/9] repo: add aggregate structure totals to keyvalue output Eslam reda ragheb via GitGitGadget
2026-02-23 14:21 ` [PATCH v2 7/9] t1900: cover repo info path keys and path-format Eslam reda ragheb via GitGitGadget
2026-02-23 14:21 ` [PATCH v2 8/9] t1901: extend structure metric coverage and portability Eslam reda ragheb via GitGitGadget
2026-02-23 14:21 ` [PATCH v2 9/9] docs: describe repo info path keys and structure metrics Eslam reda ragheb via GitGitGadget
2026-02-23 19:43 ` [PATCH v3 0/5] repo: extend info path reporting and structure statistics eslam reda via GitGitGadget
2026-02-23 19:43 ` [PATCH v3 1/5] repo: teach info context and category keys Eslam reda ragheb via GitGitGadget
2026-02-23 19:43 ` [PATCH v3 2/5] repo: add path keys to repo info Eslam reda ragheb via GitGitGadget
2026-02-23 19:43 ` [PATCH v3 3/5] repo: add --path-format for info path output Eslam reda ragheb via GitGitGadget
2026-02-23 19:43 ` [PATCH v3 4/5] t1900: cover repo info path keys and path-format Eslam reda ragheb via GitGitGadget
2026-02-23 19:43 ` [PATCH v3 5/5] docs: describe repo info path keys Eslam reda ragheb via GitGitGadget
2026-02-26 21:14 ` [PATCH v4 00/10] repo info: add category/path keys and --path-format eslam reda via GitGitGadget
2026-02-26 21:14 ` [PATCH v4 01/10] repo: teach info context and category keys Eslam reda ragheb via GitGitGadget
2026-02-26 23:21 ` Junio C Hamano
2026-02-26 21:14 ` [PATCH v4 02/10] repo: add path keys to repo info Eslam reda ragheb via GitGitGadget
2026-02-26 23:29 ` Junio C Hamano
2026-02-27 9:04 ` Phillip Wood
2026-02-27 19:51 ` Junio C Hamano
2026-03-01 10:36 ` Phillip Wood
2026-03-02 6:42 ` Junio C Hamano
2026-02-26 21:14 ` [PATCH v4 03/10] repo: add --path-format for info path output Eslam reda ragheb via GitGitGadget
2026-02-26 21:14 ` [PATCH v4 04/10] repo: add structure max object size metrics Eslam reda ragheb via GitGitGadget
2026-02-26 21:14 ` [PATCH v4 05/10] repo: add structure topology and path-depth metrics Eslam reda ragheb via GitGitGadget
2026-02-26 21:14 ` [PATCH v4 06/10] repo: add aggregate structure totals to keyvalue output Eslam reda ragheb via GitGitGadget
2026-02-26 21:14 ` [PATCH v4 07/10] t1900: cover repo info path keys and path-format Eslam reda ragheb via GitGitGadget
2026-02-26 21:14 ` [PATCH v4 08/10] t1901: extend structure metric coverage and portability Eslam reda ragheb via GitGitGadget
2026-02-26 21:14 ` [PATCH v4 09/10] docs: describe repo info path keys and structure metrics Eslam reda ragheb via GitGitGadget
2026-02-26 21:14 ` [PATCH v4 10/10] repo: reduce repetition in structure keyvalue output Eslam reda ragheb via GitGitGadget
2026-02-27 19:30 ` [PATCH v5 00/11] repo info: add category/path keys and --path-format eslam reda via GitGitGadget
2026-02-27 19:30 ` [PATCH v5 01/11] repo: teach info context and category keys Eslam reda ragheb via GitGitGadget
2026-02-27 21:42 ` Lucas Seiki Oshiro
2026-02-27 19:30 ` [PATCH v5 02/11] repo: add path keys to repo info Eslam reda ragheb via GitGitGadget
2026-02-27 19:30 ` [PATCH v5 03/11] repo: add --path-format for info path output Eslam reda ragheb via GitGitGadget
2026-02-27 19:30 ` [PATCH v5 04/11] repo: add structure max object size metrics Eslam reda ragheb via GitGitGadget
2026-02-27 19:30 ` [PATCH v5 05/11] repo: add structure topology and path-depth metrics Eslam reda ragheb via GitGitGadget
2026-02-27 19:30 ` [PATCH v5 06/11] repo: add aggregate structure totals to keyvalue output Eslam reda ragheb via GitGitGadget
2026-02-27 19:30 ` [PATCH v5 07/11] t1900: cover repo info path keys and path-format Eslam reda ragheb via GitGitGadget
2026-02-27 19:30 ` [PATCH v5 08/11] t1901: extend structure metric coverage and portability Eslam reda ragheb via GitGitGadget
2026-02-27 19:30 ` [PATCH v5 09/11] docs: describe repo info path keys and structure metrics Eslam reda ragheb via GitGitGadget
2026-02-27 19:30 ` [PATCH v5 10/11] repo: reduce repetition in structure keyvalue output Eslam reda ragheb via GitGitGadget
2026-02-27 19:30 ` [PATCH v5 11/11] repo: refine path keys for repo info Eslam reda ragheb via GitGitGadget
2026-03-01 10:33 ` Phillip Wood
2026-02-27 21:52 ` [PATCH v5 00/11] repo info: add category/path keys and --path-format Lucas Seiki Oshiro
2026-03-02 5:15 ` [PATCH v6 0/6] " eslam reda via GitGitGadget
2026-03-02 5:15 ` [PATCH v6 1/6] repo: introduce repo_info context plumbing Eslam reda ragheb via GitGitGadget
2026-03-02 5:15 ` [PATCH v6 2/6] repo: support category requests in repo info Eslam reda ragheb via GitGitGadget
2026-03-02 5:15 ` [PATCH v6 3/6] repo: add path keys to " Eslam reda ragheb via GitGitGadget
2026-03-02 5:15 ` [PATCH v6 4/6] repo: add --path-format for info path output Eslam reda ragheb via GitGitGadget
2026-03-02 5:15 ` [PATCH v6 5/6] t1900: cover repo info path keys and path-format Eslam reda ragheb via GitGitGadget
2026-03-02 5:15 ` [PATCH v6 6/6] docs: describe repo info path keys Eslam reda ragheb via GitGitGadget
2026-03-18 20:44 ` [PATCH v6 0/6] repo info: add category/path keys and --path-format Jialong Wang
2026-03-19 3:36 ` K Jayatheerth
2026-03-19 20:32 ` Jerry Wang
2026-03-20 1:49 ` K Jayatheerth
2026-03-19 20:58 ` [PATCH v6 5/6] t1900: cover repo info path keys and path-format Jialong Wang
2026-03-19 20:59 ` [PATCH] t1900: cover repo info path keys in non-default layouts Jialong Wang
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=pull.2208.v2.git.git.1771856469.gitgitgadget@gmail.com \
--to=gitgitgadget@gmail.com \
--cc=ayu.chandekar@gmail.com \
--cc=eslam.reda.div@gmail.com \
--cc=git@vger.kernel.org \
--cc=jltobler@gmail.com \
--cc=karthik.188@gmail.com \
--cc=lucasseikioshiro@gmail.com \
--cc=siddharthasthana31@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox