From: "Mark C. Chu-Carroll" <markchucarroll@fastmail.com>
To: git@vger.kernel.org
Cc: jltobler@gmail.com, "Mark C. Chu-Carroll" <markchucarroll@fastmail.com>
Subject: [PATCH 1/1] repo: add filtering options to "repo structure"
Date: Thu, 24 Sep 2026 12:45:03 -0400 [thread overview]
Message-ID: <20260924164503.119506-2-markchucarroll@fastmail.com> (raw)
In-Reply-To: <20260924164503.119506-1-markchucarroll@fastmail.com>
"git repo structure" provides a collection of useful information
about the information stored in a repo. In particular, it's
valuable for diagnosing performance issues caused by large objects
stored in a repo.
The current implementation of "git repo stucture" provides summary
information about everything in the repository - all of the
branches, remotes, tags, stashes, and notes. But sometimes
to properly diagnose a problem, it's useful to be able to exclude
refs that are known to not be relevant to the issue at hand.
Add a set of flags that allow a user to selective exclude
reference types from the report generated by "git repo structure".
When a ref type is excluded by the filter, it no longer appears
in the report (ie, if "--no-tags" is passed, the report line
for "Branches" will no longer appear under "* References").
Following the pattern of flags that are only used to
disable functionality (eg, "--no-verify" in "builtins/push.c"),
only the "--no-<reftype>" syntax is listed in the updated
documentation.
Overview of the changes:
- Add an enum to represent the structure flags.
- Add structure flags to the options for the "repo structure" commands.
- For each reference flag, add a conditional in "count_references"
which decides whether or not to add a ref to the pending list.
If an references is not added to the pending list, the things it
transitively references will not be added to the stats.
- Add a set of test cases to verify that reference counts
in the repo structure report correctly omit the specified
resource types.
- Update the documentation for git-repo to include the new options.
Signed-off-by: Mark C. Chu-Carroll <markchucarroll@fastmail.com>
---
Documentation/git-repo.adoc | 35 ++++-
builtin/repo.c | 158 +++++++++++++++------
t/t1901-repo-structure.sh | 276 ++++++++++++++++++++++++++++++++++++
3 files changed, 427 insertions(+), 42 deletions(-)
diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc
index ed7d80c690..463260cd23 100644
--- a/Documentation/git-repo.adoc
+++ b/Documentation/git-repo.adoc
@@ -10,7 +10,7 @@ SYNOPSIS
[synopsis]
git repo info [--format=(lines|nul) | -z] [--all | <key>...]
git repo info --keys [--format=(lines|nul) | -z]
-git repo structure [--format=(table|lines|nul) | -z]
+git repo structure [--format=(table|lines|nul) | -z] [--no-branches] [--no-tags] [--no-remotes] [--no-notes] [--no-stashes]`::
DESCRIPTION
-----------
@@ -56,7 +56,7 @@ supported:
`nul`:::
Similar to `lines`, but using a _NUL_ character after each value.
-`structure [--format=(table|lines|nul) | -z]`::
+`structure [--format=(table|lines|nul) | -z] [--no-branches] [--no-tags] [--no-remotes] [--no-notes] [--no-stashes]`::
Retrieve statistics about the current repository structure. The
following kinds of information are reported:
+
@@ -66,6 +66,23 @@ supported:
* Total disk size of reachable objects by type
* Largest reachable objects in the repository by type
+
+The types of objects counted can be filtered using flags:
++
+`--no-branches`:::
+ Omit branch refs from the set of objects to count.
+
+`--no-tags`:::
+ Omit tags from the set of objects to count.
+
+`--no-remotes`:::
+ Omit remotes from the set of objects to count.
+
+`--no-notes`:::
+ Omit notes from the set of objects to count.
+
+`--no-stashes`:::
+ Omit stashes from the set of objects to count.
++
The output format can be chosen through the flag `--format`. Three formats are
supported:
+
@@ -141,6 +158,20 @@ using the `nul` format:
git repo info --format=nul layout.bare layout.shallow
------------
+* Generates information about storage usage in the repository:
++
+------------
+git repo structure
+------------
++
+
+* Generates information about storage usage in the repository omitting
+remotes:
++
+------------
+git repo structure --no-remotes
+------------
+
SEE ALSO
--------
linkgit:git-rev-parse[1]
diff --git a/builtin/repo.c b/builtin/repo.c
index 84e012f83f..c8f6e38011 100644
--- a/builtin/repo.c
+++ b/builtin/repo.c
@@ -53,6 +53,20 @@ enum output_format {
FORMAT_NUL_TERMINATED,
};
+enum repo_structure_filter_flags {
+ REPO_STRUCTURE_FILTER_BRANCHES = (1 << 0),
+ REPO_STRUCTURE_FILTER_TAGS = (1 << 1),
+ REPO_STRUCTURE_FILTER_REMOTES = (1 << 2),
+ REPO_STRUCTURE_FILTER_NOTES = (1 << 3),
+ REPO_STRUCTURE_FILTER_STASHES = (1 << 4),
+};
+
+#define REPO_STRUCTURE_FILTER_FLAGS_ALL (REPO_STRUCTURE_FILTER_BRANCHES | \
+ REPO_STRUCTURE_FILTER_TAGS | \
+ REPO_STRUCTURE_FILTER_REMOTES | \
+ REPO_STRUCTURE_FILTER_NOTES |\
+ REPO_STRUCTURE_FILTER_STASHES)
+
struct repo_info_field {
const char *key;
get_value_fn *get_value;
@@ -490,7 +504,8 @@ static inline size_t get_total_object_values(struct object_values *values)
}
static void stats_table_setup_structure(struct stats_table *table,
- struct repo_structure *stats)
+ struct repo_structure *stats,
+ enum repo_structure_filter_flags flags)
{
struct object_stats *objects = &stats->objects;
struct ref_stats *refs = &stats->refs;
@@ -502,9 +517,15 @@ static void stats_table_setup_structure(struct stats_table *table,
ref_total = get_total_reference_count(refs);
stats_table_addf(table, "* %s", _("References"));
stats_table_count_addf(table, ref_total, " * %s", _("Count"));
- stats_table_count_addf(table, refs->branches, " * %s", _("Branches"));
- stats_table_count_addf(table, refs->tags, " * %s", _("Tags"));
- stats_table_count_addf(table, refs->remotes, " * %s", _("Remotes"));
+ if (flags & REPO_STRUCTURE_FILTER_BRANCHES) {
+ stats_table_count_addf(table, refs->branches, " * %s", _("Branches"));
+ }
+ if (flags & REPO_STRUCTURE_FILTER_TAGS) {
+ stats_table_count_addf(table, refs->tags, " * %s", _("Tags"));
+ }
+ if (flags & REPO_STRUCTURE_FILTER_REMOTES) {
+ stats_table_count_addf(table, refs->remotes, " * %s", _("Remotes"));
+ }
stats_table_count_addf(table, refs->others, " * %s", _("Others"));
object_count_total = get_total_object_values(&objects->type_counts);
@@ -517,8 +538,10 @@ static void stats_table_setup_structure(struct stats_table *table,
" * %s", _("Trees"));
stats_table_count_addf(table, objects->type_counts.blobs,
" * %s", _("Blobs"));
- stats_table_count_addf(table, objects->type_counts.tags,
- " * %s", _("Tags"));
+ if (flags & REPO_STRUCTURE_FILTER_TAGS) {
+ stats_table_count_addf(table, objects->type_counts.tags,
+ " * %s", _("Tags"));
+ }
inflated_object_total = get_total_object_values(&objects->inflated_sizes);
stats_table_size_addf(table, inflated_object_total,
@@ -529,8 +552,11 @@ static void stats_table_setup_structure(struct stats_table *table,
" * %s", _("Trees"));
stats_table_size_addf(table, objects->inflated_sizes.blobs,
" * %s", _("Blobs"));
- stats_table_size_addf(table, objects->inflated_sizes.tags,
- " * %s", _("Tags"));
+
+ if (flags & REPO_STRUCTURE_FILTER_TAGS) {
+ stats_table_size_addf(table, objects->inflated_sizes.tags,
+ " * %s", _("Tags"));
+ }
disk_object_total = get_total_object_values(&objects->disk_sizes);
stats_table_size_addf(table, disk_object_total,
@@ -541,8 +567,10 @@ static void stats_table_setup_structure(struct stats_table *table,
" * %s", _("Trees"));
stats_table_size_addf(table, objects->disk_sizes.blobs,
" * %s", _("Blobs"));
- stats_table_size_addf(table, objects->disk_sizes.tags,
- " * %s", _("Tags"));
+ if (flags & REPO_STRUCTURE_FILTER_TAGS) {
+ stats_table_size_addf(table, objects->disk_sizes.tags,
+ " * %s", _("Tags"));
+ }
stats_table_addf(table, "");
stats_table_addf(table, "* %s", _("Largest objects"));
@@ -569,11 +597,13 @@ static void stats_table_setup_structure(struct stats_table *table,
&objects->largest.blob_size.oid,
objects->largest.blob_size.value,
" * %s", _("Maximum size"));
- stats_table_addf(table, " * %s", _("Tags"));
- stats_table_object_size_addf(table,
- &objects->largest.tag_size.oid,
- objects->largest.tag_size.value,
- " * %s", _("Maximum size"));
+ if (flags & REPO_STRUCTURE_FILTER_TAGS) {
+ stats_table_addf(table, " * %s", _("Tags"));
+ stats_table_object_size_addf(table,
+ &objects->largest.tag_size.oid,
+ objects->largest.tag_size.value,
+ " * %s", _("Maximum size"));
+ }
}
#define INDEX_WIDTH 4
@@ -681,14 +711,21 @@ static void print_object_data(const char *key, char key_delim,
}
static void structure_keyvalue_print(struct repo_structure *stats,
- char key_delim, char value_delim)
+ char key_delim, char value_delim,
+ enum repo_structure_filter_flags flags)
{
- print_keyvalue("references.branches.count", key_delim,
- stats->refs.branches, value_delim);
+ if (flags & REPO_STRUCTURE_FILTER_BRANCHES) {
+ print_keyvalue("references.branches.count", key_delim,
+ stats->refs.branches, value_delim);
+ }
+ if (flags & REPO_STRUCTURE_FILTER_TAGS) {
print_keyvalue("references.tags.count", key_delim,
stats->refs.tags, value_delim);
- print_keyvalue("references.remotes.count", key_delim,
- stats->refs.remotes, value_delim);
+ }
+ if (flags & REPO_STRUCTURE_FILTER_REMOTES) {
+ print_keyvalue("references.remotes.count", key_delim,
+ stats->refs.remotes, value_delim);
+ }
print_keyvalue("references.others.count", key_delim,
stats->refs.others, value_delim);
@@ -698,8 +735,10 @@ static void structure_keyvalue_print(struct repo_structure *stats,
stats->objects.type_counts.trees, value_delim);
print_keyvalue("objects.blobs.count", key_delim,
stats->objects.type_counts.blobs, value_delim);
- print_keyvalue("objects.tags.count", key_delim,
- stats->objects.type_counts.tags, value_delim);
+ if (flags & REPO_STRUCTURE_FILTER_TAGS) {
+ print_keyvalue("objects.tags.count", key_delim,
+ stats->objects.type_counts.tags, value_delim);
+ }
print_keyvalue("objects.commits.inflated_size", key_delim,
stats->objects.inflated_sizes.commits, value_delim);
@@ -707,8 +746,10 @@ static void structure_keyvalue_print(struct repo_structure *stats,
stats->objects.inflated_sizes.trees, value_delim);
print_keyvalue("objects.blobs.inflated_size", key_delim,
stats->objects.inflated_sizes.blobs, value_delim);
- print_keyvalue("objects.tags.inflated_size", key_delim,
- stats->objects.inflated_sizes.tags, value_delim);
+ if (flags & REPO_STRUCTURE_FILTER_TAGS) {
+ print_keyvalue("objects.tags.inflated_size", key_delim,
+ stats->objects.inflated_sizes.tags, value_delim);
+ }
print_keyvalue("objects.commits.disk_size", key_delim,
stats->objects.disk_sizes.commits, value_delim);
@@ -716,8 +757,10 @@ static void structure_keyvalue_print(struct repo_structure *stats,
stats->objects.disk_sizes.trees, value_delim);
print_keyvalue("objects.blobs.disk_size", key_delim,
stats->objects.disk_sizes.blobs, value_delim);
- print_keyvalue("objects.tags.disk_size", key_delim,
- stats->objects.disk_sizes.tags, value_delim);
+ if (flags & REPO_STRUCTURE_FILTER_TAGS) {
+ print_keyvalue("objects.tags.disk_size", key_delim,
+ stats->objects.disk_sizes.tags, value_delim);
+ }
print_object_data("objects.commits.max_size", key_delim,
&stats->objects.largest.commit_size, value_delim);
@@ -725,8 +768,10 @@ static void structure_keyvalue_print(struct repo_structure *stats,
&stats->objects.largest.tree_size, value_delim);
print_object_data("objects.blobs.max_size", key_delim,
&stats->objects.largest.blob_size, value_delim);
- print_object_data("objects.tags.max_size", key_delim,
- &stats->objects.largest.tag_size, value_delim);
+ if (flags & REPO_STRUCTURE_FILTER_TAGS) {
+ print_object_data("objects.tags.max_size", key_delim,
+ &stats->objects.largest.tag_size, value_delim);
+ }
print_object_data("objects.commits.max_parents", key_delim,
&stats->objects.largest.parent_count, value_delim);
@@ -739,6 +784,7 @@ static void structure_keyvalue_print(struct repo_structure *stats,
struct count_references_data {
struct ref_stats *stats;
struct rev_info *revs;
+ enum repo_structure_filter_flags flags;
struct progress *progress;
};
@@ -747,19 +793,42 @@ static int count_references(const struct reference *ref, void *cb_data)
struct count_references_data *data = cb_data;
struct ref_stats *stats = data->stats;
size_t ref_count;
+ bool add_pending = false;
switch (ref_kind_from_refname(ref->name)) {
case FILTER_REFS_BRANCHES:
- stats->branches++;
+ if (data->flags & REPO_STRUCTURE_FILTER_BRANCHES) {
+ stats->branches++;
+ add_pending = true;
+ }
break;
case FILTER_REFS_REMOTES:
- stats->remotes++;
+ if (data->flags & REPO_STRUCTURE_FILTER_REMOTES) {
+ stats->remotes++;
+ add_pending = true;
+ }
break;
case FILTER_REFS_TAGS:
- stats->tags++;
+ if (data->flags & REPO_STRUCTURE_FILTER_TAGS) {
+ stats->tags++;
+ add_pending = true;
+ }
break;
case FILTER_REFS_OTHERS:
- stats->others++;
+ if (!strcmp(ref->name, "refs/stash")) {
+ if (data->flags & REPO_STRUCTURE_FILTER_STASHES) {
+ stats->others++;
+ add_pending = true;
+ }
+ } else if (starts_with(ref->name, "refs/notes")) {
+ if (data->flags & REPO_STRUCTURE_FILTER_NOTES) {
+ stats->others++;
+ add_pending = true;
+ }
+ } else {
+ stats->others++;
+ add_pending = true;
+ }
break;
default:
BUG("unexpected reference type");
@@ -769,10 +838,11 @@ static int count_references(const struct reference *ref, void *cb_data)
* While iterating through references for counting, also add OIDs in
* preparation for the path walk.
*/
- add_pending_oid(data->revs, NULL, ref->oid, 0);
-
- ref_count = get_total_reference_count(stats);
- display_progress(data->progress, ref_count);
+ if (add_pending) {
+ add_pending_oid(data->revs, NULL, ref->oid, 0);
+ ref_count = get_total_reference_count(stats);
+ display_progress(data->progress, ref_count);
+ }
return 0;
}
@@ -780,11 +850,13 @@ static int count_references(const struct reference *ref, void *cb_data)
static void structure_count_references(struct ref_stats *stats,
struct rev_info *revs,
struct repository *repo,
+ enum repo_structure_filter_flags flags,
int show_progress)
{
struct count_references_data data = {
.stats = stats,
.revs = revs,
+ .flags = flags,
};
if (show_progress)
@@ -935,6 +1007,7 @@ static int cmd_repo_structure(int argc, const char **argv, const char *prefix,
struct repo_structure stats = { 0 };
struct rev_info revs;
int show_progress = -1;
+ int flags = REPO_STRUCTURE_FILTER_FLAGS_ALL;
struct option options[] = {
OPT_CALLBACK_F(0, "format", &format, N_("format"),
N_("output format"),
@@ -944,6 +1017,11 @@ static int cmd_repo_structure(int argc, const char **argv, const char *prefix,
PARSE_OPT_NONEG | PARSE_OPT_NOARG,
parse_format_cb),
OPT_BOOL(0, "progress", &show_progress, N_("show progress")),
+ OPT_BIT(0, "branches", &flags, N_("include branches in structure statistics"), REPO_STRUCTURE_FILTER_BRANCHES),
+ OPT_BIT(0, "tags", &flags, N_("include tags in structure statistics"), REPO_STRUCTURE_FILTER_TAGS),
+ OPT_BIT(0, "remotes", &flags, N_("include remotes in structure statistics"), REPO_STRUCTURE_FILTER_REMOTES),
+ OPT_BIT(0, "notes", &flags, N_("include notes in structure statistics"), REPO_STRUCTURE_FILTER_NOTES),
+ OPT_BIT(0, "stashes", &flags, N_("include stashes in structure statistics"), REPO_STRUCTURE_FILTER_STASHES),
OPT_END()
};
@@ -956,19 +1034,19 @@ static int cmd_repo_structure(int argc, const char **argv, const char *prefix,
if (show_progress < 0)
show_progress = isatty(2);
- structure_count_references(&stats.refs, &revs, repo, show_progress);
+ structure_count_references(&stats.refs, &revs, repo, flags, show_progress);
structure_count_objects(&stats.objects, &revs, repo, show_progress);
switch (format) {
case FORMAT_TABLE:
- stats_table_setup_structure(&table, &stats);
+ stats_table_setup_structure(&table, &stats, flags);
stats_table_print_structure(&table);
break;
case FORMAT_NEWLINE_TERMINATED:
- structure_keyvalue_print(&stats, '=', '\n');
+ structure_keyvalue_print(&stats, '=', '\n', flags);
break;
case FORMAT_NUL_TERMINATED:
- structure_keyvalue_print(&stats, '\n', '\0');
+ structure_keyvalue_print(&stats, '\n', '\0', flags);
break;
default:
BUG("invalid output format");
diff --git a/t/t1901-repo-structure.sh b/t/t1901-repo-structure.sh
index 02cc2b594a..60a82493c6 100755
--- a/t/t1901-repo-structure.sh
+++ b/t/t1901-repo-structure.sh
@@ -144,6 +144,170 @@ test_expect_success SHA1 'repository with references and objects' '
)
'
+
+test_expect_success SHA1 'repository with references and objects, filtered with --no-origins' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ test_commit_bulk 1005 &&
+ git tag -a foo -m bar &&
+
+ oid="$(git rev-parse HEAD)" &&
+ git update-ref refs/remotes/origin/foo "$oid" &&
+
+ git checkout -b other_branch &&
+ test_commit_bulk 5 &&
+
+ git checkout master &&
+
+ # Also creates a commit, tree, and blob.
+ git notes add -m foo &&
+
+ # The tags disk size is handled specially due to the
+ # git-rev-list(1) --disk-usage=human option printing the full
+ # "byte/bytes" unit string instead of just "B".
+ cat >expect <<-EOF &&
+ | Repository structure | Value |
+ | ------------------------- | ---------- |
+ | * References | |
+ | * Count | 4 |
+ | * Branches | 2 |
+ | * Tags | 1 |
+ | * Others | 1 |
+ | | |
+ | * Reachable objects | |
+ | * Count | 3.02 k |
+ | * Commits | 1.01 k |
+ | * Trees | 1.01 k |
+ | * Blobs | 1.01 k |
+ | * Tags | 1 |
+ | * Inflated size | 16.04 MiB |
+ | * Commits | 219.00 KiB |
+ | * Trees | 15.81 MiB |
+ | * Blobs | 11.68 KiB |
+ | * Tags | 132 B |
+ | * Disk size | $(object_type_disk_usage all true) |
+ | * Commits | $(object_type_disk_usage commit true) |
+ | * Trees | $(object_type_disk_usage tree true) |
+ | * Blobs | $(object_type_disk_usage blob true) |
+ | * Tags | $(object_type_disk_usage tag) B |
+ | | |
+ | * Largest objects | |
+ | * Commits | |
+ | * Maximum size [1] | 223 B |
+ | * Maximum parents [2] | 1 |
+ | * Trees | |
+ | * Maximum size [3] | 32.29 KiB |
+ | * Maximum entries [4] | 1.01 k |
+ | * Blobs | |
+ | * Maximum size [5] | 13 B |
+ | * Tags | |
+ | * Maximum size [6] | 132 B |
+
+ [1] 0dc91eb18580102a3a216c8bfecedeba2b9f9b9a
+ [2] 0a8f6a47f34078bb7c4b2bb4377c2133157f6703
+ [3] 60665251ab71dbd8c18d9bf2174f4ee0d58aa06c
+ [4] 60665251ab71dbd8c18d9bf2174f4ee0d58aa06c
+ [5] 97d808e45116bf02103490294d3d46dad7a2ac62
+ [6] 4dae4f5954f5e6feb3577cfb1b181daa3fd3afd2
+ EOF
+ git repo structure --no-remotes >actual 2>err &&
+ test_cmp expect actual &&
+ test_line_count = 0 err
+ )
+'
+
+test_expect_success SHA1 'repository with references and objects, filtered with "--no-branches"' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ test_commit_bulk 1005 &&
+ git tag -a foo -m bar &&
+
+ oid="$(git rev-parse HEAD)" &&
+ git update-ref refs/remotes/origin/foo "$oid" &&
+
+ git checkout -b other_branch &&
+ test_commit_bulk 5 &&
+
+ git checkout master &&
+
+ # Also creates a commit, tree, and blob.
+ git notes add -m foo &&
+
+ git repo structure --no-branches >actual 2>err &&
+ test_line_count = 0 err &&
+ test_grep "| \* Count | 3 |" actual &&
+ test_grep "| \* Others | 1 |" actual &&
+ test_grep ! "Branches" actual
+ )
+'
+
+test_expect_success SHA1 'repository with references and objects, filtered with "--no-notes"' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ test_commit_bulk 1005 &&
+ git tag -a foo -m bar &&
+
+ oid="$(git rev-parse HEAD)" &&
+ git update-ref refs/remotes/origin/foo "$oid" &&
+
+ git checkout -b other_branch &&
+ test_commit_bulk 5 &&
+
+ git checkout master &&
+
+ # Also creates a commit, tree, and blob.
+ git notes add -m foo &&
+
+ git repo structure --no-notes >actual 2>err &&
+ test_line_count = 0 err &&
+ test_grep "| \* Count | 4 |" actual &&
+ test_grep "| \* Others | 0 |" actual &&
+ test_grep "| \* Commits | 218.81 KiB |" actual
+ )
+'
+
+test_expect_success SHA1 'repository with references and objects, filtered with multiple flags' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ test_commit_bulk 1005 &&
+ git tag -a foo -m bar &&
+
+ oid="$(git rev-parse HEAD)" &&
+ git update-ref refs/remotes/origin/foo "$oid" &&
+
+ git checkout -b other_branch &&
+ test_commit_bulk 5 &&
+
+ git checkout master &&
+
+ # Also creates a commit, tree, and blob.
+ git notes add -m foo &&
+
+ git repo structure --no-notes --no-branches >actual 2>err &&
+ test_line_count = 0 err &&
+ test_grep "| \* Count | 2 |" actual &&
+ test_grep "| \* Others | 0 |" actual &&
+ test_grep "| \* Commits | 217.73 KiB |" actual &&
+ test_grep ! "Branches" actual &&
+
+ git repo structure --no-notes --no-branches --no-remotes >actual 2>err &&
+ test_line_count = 0 err &&
+ test_grep "| \* Count | 1 |" actual &&
+ test_grep "| \* Others | 0 |" actual &&
+ test_grep "| \* Commits | 217.73 KiB |" actual &&
+ test_grep ! "Branches" actual &&
+ test_grep ! "Remotes" actual
+ )
+'
+
test_expect_success SHA1 'lines and nul format' '
test_when_finished "rm -rf repo" &&
git init repo &&
@@ -203,6 +367,118 @@ test_expect_success SHA1 'lines and nul format' '
test_line_count = 0 err
)
'
+test_expect_success SHA1 'lines and nul format with --no-tags filter' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ test_commit_bulk 42 &&
+ git tag -a foo -m bar &&
+
+ cat >expect <<-EOF &&
+ references.branches.count=1
+ references.remotes.count=0
+ references.others.count=0
+ objects.commits.count=42
+ objects.trees.count=42
+ objects.blobs.count=42
+ objects.commits.inflated_size=9225
+ objects.trees.inflated_size=28554
+ objects.blobs.inflated_size=453
+ objects.commits.disk_size=$(object_type_disk_usage commit)
+ objects.trees.disk_size=$(object_type_disk_usage tree)
+ objects.blobs.disk_size=$(object_type_disk_usage blob)
+ objects.commits.max_size=221
+ objects.commits.max_size_oid=de3508174b5c2ace6993da67cae9be9069e2df39
+ objects.trees.max_size=1335
+ objects.trees.max_size_oid=09931deea9d81ec21300d3e13c74412f32eacec5
+ objects.blobs.max_size=11
+ objects.blobs.max_size_oid=eaeeedced46482bd4281fda5a5f05ce24854151f
+ objects.commits.max_parents=1
+ objects.commits.max_parents_oid=de3508174b5c2ace6993da67cae9be9069e2df39
+ objects.trees.max_entries=42
+ objects.trees.max_entries_oid=09931deea9d81ec21300d3e13c74412f32eacec5
+ EOF
+
+ git repo structure --format=lines --no-tags >actual 2>err &&
+ test_cmp expect actual &&
+ test_line_count = 0 err &&
+
+ git repo structure --format=nul --no-tags >out 2>err &&
+ tr "\012\000" "=\012" <out >actual &&
+
+ test_cmp expect actual &&
+ test_line_count = 0 err &&
+
+ # "-z", as a synonym to "--format=nul", participates in the
+ # usual "last one wins" rule.
+ git repo structure --format=table -z --no-tags >out 2>err &&
+ tr "\012\000" "=\012" <out >actual &&
+
+ test_cmp expect actual &&
+ test_line_count = 0 err
+ )
+'
+
+test_expect_success SHA1 'lines and nul format with --no-branches filter' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ test_commit_bulk 42 &&
+ git tag -a foo -m bar &&
+
+ cat >expect <<-EOF &&
+ references.tags.count=1
+ references.remotes.count=0
+ references.others.count=0
+ objects.commits.count=42
+ objects.trees.count=42
+ objects.blobs.count=42
+ objects.tags.count=1
+ objects.commits.inflated_size=9225
+ objects.trees.inflated_size=28554
+ objects.blobs.inflated_size=453
+ objects.tags.inflated_size=132
+ objects.commits.disk_size=$(object_type_disk_usage commit)
+ objects.trees.disk_size=$(object_type_disk_usage tree)
+ objects.blobs.disk_size=$(object_type_disk_usage blob)
+ objects.tags.disk_size=$(object_type_disk_usage tag)
+ objects.commits.max_size=221
+ objects.commits.max_size_oid=de3508174b5c2ace6993da67cae9be9069e2df39
+ objects.trees.max_size=1335
+ objects.trees.max_size_oid=09931deea9d81ec21300d3e13c74412f32eacec5
+ objects.blobs.max_size=11
+ objects.blobs.max_size_oid=eaeeedced46482bd4281fda5a5f05ce24854151f
+ objects.tags.max_size=132
+ objects.tags.max_size_oid=1ee0f2b16ea37d895dbe9dbd76cd2ac70446176c
+ objects.commits.max_parents=1
+ objects.commits.max_parents_oid=de3508174b5c2ace6993da67cae9be9069e2df39
+ objects.trees.max_entries=42
+ objects.trees.max_entries_oid=09931deea9d81ec21300d3e13c74412f32eacec5
+ EOF
+
+ git repo structure --format=lines --no-branches >actual 2>err &&
+ cp expect /tmp/expect &&
+ cp actual /tmp/actual &&
+ test_cmp expect actual &&
+ test_line_count = 0 err &&
+
+ git repo structure --format=nul --no-branches >out 2>err &&
+ tr "\012\000" "=\012" <out >actual &&
+
+ test_cmp expect actual &&
+ test_line_count = 0 err &&
+
+ # "-z", as a synonym to "--format=nul", participates in the
+ # usual "last one wins" rule.
+ git repo structure --format=table -z --no-branches >out 2>err &&
+ tr "\012\000" "=\012" <out >actual &&
+
+ test_cmp expect actual &&
+ test_line_count = 0 err
+ )
+'
test_expect_success 'progress meter option' '
test_when_finished "rm -rf repo" &&
--
2.53.0
next prev parent reply other threads:[~2026-09-24 16:45 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-24 16:45 [PATCH 0/1] repo: add filtering options to "repo structure" Mark C. Chu-Carroll
2026-09-24 16:45 ` Mark C. Chu-Carroll [this message]
2026-09-30 16:28 ` [PATCH 1/1] " Patrick Steinhardt
2026-10-05 18:52 ` Mark C. Chu-Carroll
2026-10-05 17:40 ` [PATCH v2 0/1] " Mark C. Chu-Carroll
2026-10-05 17:40 ` [PATCH v2 1/1] " Mark C. Chu-Carroll
2026-10-06 5:51 ` Patrick Steinhardt
2026-10-08 15:46 ` Kaartic Sivaraam
2026-10-09 15:49 ` Mark C. Chu-Carroll
2026-10-09 18:09 ` [PATCH v3 0/1] repo: add revision " Mark C. Chu-Carroll
2026-10-09 18:09 ` [PATCH v3 1/1] repo: add " Mark C. Chu-Carroll
2026-10-09 21:24 ` Junio C Hamano
2026-10-10 14:31 ` Mark C. Chu-Carroll
2026-10-10 15:05 ` [PATCH v4 0/1] repo: add revision " Mark C. Chu-Carroll
2026-10-10 15:05 ` [PATCH v4 1/1] repo: add " Mark C. Chu-Carroll
2026-10-13 11:50 ` Patrick Steinhardt
2026-10-13 13:56 ` Mark C. Chu-Carroll
2026-10-13 14:05 ` Patrick Steinhardt
2026-10-13 17:28 ` [PATCH v5 0/1] repo: add revision " Mark C. Chu-Carroll
2026-10-13 17:28 ` [PATCH v5 1/1] repo: add " Mark C. Chu-Carroll
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=20260924164503.119506-2-markchucarroll@fastmail.com \
--to=markchucarroll@fastmail.com \
--cc=git@vger.kernel.org \
--cc=jltobler@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.