Git development
 help / color / mirror / Atom feed
From: "Mark C. Chu-Carroll" <markchucarroll@fastmail.com>
To: git@vger.kernel.org
Cc: jltobler@gmail.com, ps@pks.im,
	"Mark C. Chu-Carroll" <markchucarroll@fastmail.com>
Subject: [PATCH v2 1/1] repo: add filtering options to "repo structure"
Date: Mon,  5 Oct 2026 13:40:44 -0400	[thread overview]
Message-ID: <20261005174045.1900391-2-markchucarroll@fastmail.com> (raw)
In-Reply-To: <20261005174045.1900391-1-markchucarroll@fastmail.com>

Implement filtering for repo structure, imitating the mechanism
used in "git log".

Signed-off-by: Mark C. Chu-Carroll <markchucarroll@fastmail.com>
---
 Documentation/git-repo.adoc | 41 ++++++++++++++++--
 builtin/repo.c              | 16 +++++--
 t/t1901-repo-structure.sh   | 84 +++++++++++++++++++++++++++++++++++++
 3 files changed, 133 insertions(+), 8 deletions(-)

diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc
index ed7d80c690..5cbdf8e727 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] [<include|^exclude>...]
 
 DESCRIPTION
 -----------
@@ -56,9 +56,10 @@ supported:
 `nul`:::
 	Similar to `lines`, but using a _NUL_ character after each value.
 
-`structure [--format=(table|lines|nul) | -z]`::
-	Retrieve statistics about the current repository structure. The
-	following kinds of information are reported:
+`structure [--format=(table|lines|nul) | -z] [<include|^exclude>...]::
++
+Retrieve statistics about the current repository structure. The
+following kinds of information are reported:
 +
 * Reference counts categorized by type
 * Reachable object counts categorized by type
@@ -66,6 +67,16 @@ supported:
 * Total disk size of reachable objects by type
 * Largest reachable objects in the repository by type
 +
+The set of objects counted can be filtered by specifying a
+collection of query clauses to select which objects will be
+counted. These parameters follow the same syntax as the parameters
+to similar commands like `git log`. Semantically, these parameters
+are treated as a collection of include and exclude specifiers. Th
+set of objects counted will consist of all objects reachable from
+an object included by one of the include specifiers via a path that
+does not include an object in an exclude clause. If no includes
+are specified, then the include set is all reachable objects. 
++
 The output format can be chosen through the flag `--format`. Three formats are
 supported:
 +
@@ -141,6 +152,28 @@ 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
+the branch "foo":
++
+------------
+git repo structure ^foo 
+------------
++
+* Generates information about repository objects reachable from
+the references "x" and "y", but omitting anything that can
+only be reached on a path including "xchild":
++
+------------
+git repo structure x y ^xchild
+------------
++
 SEE ALSO
 --------
 linkgit:git-rev-parse[1]
diff --git a/builtin/repo.c b/builtin/repo.c
index 84e012f83f..b3aca71298 100644
--- a/builtin/repo.c
+++ b/builtin/repo.c
@@ -27,7 +27,7 @@
 	"git repo info --keys [--format=(lines|nul) | -z]"
 
 #define REPO_STRUCTURE_USAGE \
-	"git repo structure [--format=(table|lines|nul) | -z]"
+	"git repo structure [--format=(table|lines|nul) | -z] [<include|^exclude>...]"
 
 static const char *const repo_usage[] = {
 	REPO_INFO_USAGE,
@@ -946,12 +946,20 @@ static int cmd_repo_structure(int argc, const char **argv, const char *prefix,
 		OPT_BOOL(0, "progress", &show_progress, N_("show progress")),
 		OPT_END()
 	};
+	struct setup_revision_opt s_r_opt;
+	memset(&s_r_opt, 0, sizeof(s_r_opt));
+	s_r_opt.def = "HEAD";
+	s_r_opt.revarg_opt = REVARG_COMMITTISH;
 
-	argc = parse_options(argc, argv, prefix, options, repo_structure_usage, 0);
-	if (argc)
-		usage(_("too many arguments"));
+	argc = parse_options(argc, argv, prefix, options, repo_structure_usage,
+			     PARSE_OPT_KEEP_ARGV0 | PARSE_OPT_KEEP_UNKNOWN_OPT);
 
 	repo_init_revisions(repo, &revs, prefix);
+	if (argc > 1) {
+		argc = setup_revisions(argc, argv, &revs, &s_r_opt);
+		if (argc > 1)
+			usage(_("too many arguments"));
+	}
 
 	if (show_progress < 0)
 		show_progress = isatty(2);
diff --git a/t/t1901-repo-structure.sh b/t/t1901-repo-structure.sh
index 02cc2b594a..eb2c595955 100755
--- a/t/t1901-repo-structure.sh
+++ b/t/t1901-repo-structure.sh
@@ -144,6 +144,90 @@ test_expect_success SHA1 'repository with references and objects' '
 	)
 '
 
+test_expect_success SHA1 'repository with references and objects, filtered' '
+	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 grobble &&
+		test_commit_bulk --ref=refs/heads/grobble 20 &&
+		git checkout master &&
+ 		test_commit_bulk 20 &&
+		# Also creates a commit, tree, and blob.
+		git notes add -m foo &&
+
+		# 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                 |      5     |
+		|     * Branches            |      2     |
+		|     * Tags                |      1     |
+		|     * Remotes             |      1     |
+		|     * Others              |      1     |
+		|                           |            |
+		| * Reachable objects       |            |
+		|   * Count                 |   3.06 k   |
+		|     * Commits             |   1.05 k   |
+		|     * Trees               |   1.01 k   |
+		|     * Blobs               |   1.01 k   |
+		|     * Tags                |      1     |
+		|   * Inflated size         |  16.04 MiB |
+		|     * Commits             | 226.54 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] df6400c01440c329f1011669c4c26cc0c7852887
+		[3] 60665251ab71dbd8c18d9bf2174f4ee0d58aa06c
+		[4] 60665251ab71dbd8c18d9bf2174f4ee0d58aa06c
+		[5] 97d808e45116bf02103490294d3d46dad7a2ac62
+		[6] 4dae4f5954f5e6feb3577cfb1b181daa3fd3afd2
+		EOF
+
+		git repo structure  >actual 2>actual-err &&
+		cp actual /tmp/actual &&
+		cp expect /tmp/expect &&
+		test_cmp expect actual &&
+		test_line_count = 0 actual-err &&
+
+		git repo structure grobble ^master >actual 2>actual-err &&
+		cp actual /tmp &&
+		cp actual-err /tmp &&
+		test_grep "|     \* Commits             |    21     |" actual &&
+		test_grep "|     \* Trees               |     2     |" actual &&
+		test_grep "|     \* Commits             |  4.50 KiB |" actual &&
+		test_grep "|     \* Trees               | 32.35 KiB |" actual &&
+		test_grep "|     \* Blobs               | 11.68 KiB |" actual &&
+		test_line_count = 0 actual-err
+	)
+'
+
 test_expect_success SHA1 'lines and nul format' '
 	test_when_finished "rm -rf repo" &&
 	git init repo &&
-- 
2.53.0


  reply	other threads:[~2026-10-05 17:40 UTC|newest]

Thread overview: 12+ 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 ` [PATCH 1/1] " Mark C. Chu-Carroll
2026-09-30 16:28   ` 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     ` Mark C. Chu-Carroll [this message]
2026-10-06  5:51       ` [PATCH v2 1/1] " 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

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=20261005174045.1900391-2-markchucarroll@fastmail.com \
    --to=markchucarroll@fastmail.com \
    --cc=git@vger.kernel.org \
    --cc=jltobler@gmail.com \
    --cc=ps@pks.im \
    /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