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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.