git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH v3 3/6] builtin/repo: collect largest inflated objects

From
Justin Tobler <jltobler@gmail.com>
Date
Mar 2, 2026, 21:45 UTC
Message-ID
<20260302214526.2034279-4-jltobler@gmail.com>
In-Reply-To
<20260302214526.2034279-1-jltobler@gmail.com>

The "structure" output for git-repo(1) shows the total inflated and disk sizes of reachable objects in the repository, but doesn't show the size of the largest individual objects. Since an individual object may be a large contributor to the overall repository size, it is useful for users to know the maximum size of individual objects.

While interating across objects, record the size and OID of the largest objects encountered for each object type to provide as output. Note that the default "table" output format only displays size information and not the corresponding OID. In a subsequent commit, the table format is updated to add table annotations that mention the OID.

Signed-off-by: Justin Tobler <jltobler@gmail.com>
---
 Documentation/git-repo.adoc |  1 +
 builtin/repo.c              | 63 +++++++++++++++++++++++++++++++++++++
 t/t1901-repo-structure.sh   | 28 +++++++++++++++++
 3 files changed, 92 insertions(+)
diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc
index 7d70270dfa..e812e59158 100644
--- a/Documentation/git-repo.adoc
+++ b/Documentation/git-repo.adoc
@@ -52,6 +52,7 @@ supported:
 * Reachable object counts categorized by type
 * Total inflated size of reachable objects by type
 * Total disk size of reachable objects by type
+* Largest reachable objects in the repository by type
 +
 The output format can be chosen through the flag `--format`. Three formats are
 supported:
diff --git a/builtin/repo.c b/builtin/repo.c
index 782194cf4c..59d5cb2551 100644
--- a/builtin/repo.c
+++ b/builtin/repo.c
@@ -2,6 +2,7 @@
 
 #include "builtin.h"
 #include "environment.h"
+#include "hash.h"
 #include "hex.h"
 #include "odb.h"
 #include "parse-options.h"
@@ -197,6 +198,18 @@ static int cmd_repo_info(int argc, const char **argv, const char *prefix,
 		return print_fields(argc, argv, repo, format);
 }
 
+struct object_data {
+	struct object_id oid;
+	size_t value;
+};
+
+struct largest_objects {
+	struct object_data tag_size;
+	struct object_data commit_size;
+	struct object_data tree_size;
+	struct object_data blob_size;
+};
+
 struct ref_stats {
 	size_t branches;
 	size_t remotes;
@@ -215,6 +228,7 @@ struct object_stats {
 	struct object_values type_counts;
 	struct object_values inflated_sizes;
 	struct object_values disk_sizes;
+	struct largest_objects largest;
 };
 
 struct repo_structure {
@@ -371,6 +385,21 @@ 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_addf(table, "");
+	stats_table_addf(table, "* %s", _("Largest objects"));
+	stats_table_addf(table, "  * %s", _("Commits"));
+	stats_table_size_addf(table, objects->largest.commit_size.value,
+			      "    * %s", _("Maximum size"));
+	stats_table_addf(table, "  * %s", _("Trees"));
+	stats_table_size_addf(table, objects->largest.tree_size.value,
+			      "    * %s", _("Maximum size"));
+	stats_table_addf(table, "  * %s", _("Blobs"));
+	stats_table_size_addf(table, objects->largest.blob_size.value,
+			      "    * %s", _("Maximum size"));
+	stats_table_addf(table, "  * %s", _("Tags"));
+	stats_table_size_addf(table, objects->largest.tag_size.value,
+			      "    * %s", _("Maximum size"));
 }
 
 static void stats_table_print_structure(const struct stats_table *table)
@@ -453,6 +482,14 @@ static inline void print_keyvalue(const char *key, char key_delim, size_t value,
 	       value_delim);
 }
 
+static void print_object_data(const char *key, char key_delim,
+			      struct object_data *data, char value_delim)
+{
+	print_keyvalue(key, key_delim, data->value, value_delim);
+	printf("%s_oid%c%s%c", key, key_delim, oid_to_hex(&data->oid),
+	       value_delim);
+}
+
 static void structure_keyvalue_print(struct repo_structure *stats,
 				     char key_delim, char value_delim)
 {
@@ -492,6 +529,15 @@ static void structure_keyvalue_print(struct repo_structure *stats,
 	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);
+	print_object_data("objects.trees.max_size", key_delim,
+			  &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);
+
 	fflush(stdout);
 }
 
@@ -560,6 +606,15 @@ struct count_objects_data {
 	struct progress *progress;
 };
 
+static void check_largest(struct object_data *data, struct object_id *oid,
+			  size_t value)
+{
+	if (value > data->value || is_null_oid(&data->oid)) {
+		oidcpy(&data->oid, oid);
+		data->value = value;
+	}
+}
+
 static int count_objects(const char *path UNUSED, struct oid_array *oids,
 			 enum object_type type, void *cb_data)
 {
@@ -585,21 +640,29 @@ static int count_objects(const char *path UNUSED, struct oid_array *oids,
 			stats->type_counts.tags++;
 			stats->inflated_sizes.tags += inflated;
 			stats->disk_sizes.tags += disk;
+			check_largest(&stats->largest.tag_size, &oids->oid[i],
+				      inflated);
 			break;
 		case OBJ_COMMIT:
 			stats->type_counts.commits++;
 			stats->inflated_sizes.commits += inflated;
 			stats->disk_sizes.commits += disk;
+			check_largest(&stats->largest.commit_size, &oids->oid[i],
+				      inflated);
 			break;
 		case OBJ_TREE:
 			stats->type_counts.trees++;
 			stats->inflated_sizes.trees += inflated;
 			stats->disk_sizes.trees += disk;
+			check_largest(&stats->largest.tree_size, &oids->oid[i],
+				      inflated);
 			break;
 		case OBJ_BLOB:
 			stats->type_counts.blobs++;
 			stats->inflated_sizes.blobs += inflated;
 			stats->disk_sizes.blobs += disk;
+			check_largest(&stats->largest.blob_size, &oids->oid[i],
+				      inflated);
 			break;
 		default:
 			BUG("invalid object type");
diff --git a/t/t1901-repo-structure.sh b/t/t1901-repo-structure.sh
index 17ff164b05..1999f325d0 100755
--- a/t/t1901-repo-structure.sh
+++ b/t/t1901-repo-structure.sh
@@ -52,6 +52,16 @@ test_expect_success 'empty repository' '
 		|     * Trees          |    0 B |
 		|     * Blobs          |    0 B |
 		|     * Tags           |    0 B |
+		|                      |        |
+		| * Largest objects    |        |
+		|   * Commits          |        |
+		|     * Maximum size   |    0 B |
+		|   * Trees            |        |
+		|     * Maximum size   |    0 B |
+		|   * Blobs            |        |
+		|     * Maximum size   |    0 B |
+		|   * Tags             |        |
+		|     * Maximum size   |    0 B |
 		EOF
 
 		git repo structure >out 2>err &&
@@ -104,6 +114,16 @@ test_expect_success SHA1 'repository with references and objects' '
 		|     * 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   |    223 B   |
+		|   * Trees            |            |
+		|     * Maximum size   |  32.29 KiB |
+		|   * Blobs            |            |
+		|     * Maximum size   |     13 B   |
+		|   * Tags             |            |
+		|     * Maximum size   |    132 B   |
 		EOF
 
 		git repo structure >out 2>err &&
@@ -138,6 +158,14 @@ test_expect_success SHA1 'keyvalue and nul format' '
 		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
 		EOF
 
 		git repo structure --format=keyvalue >out 2>err &&
-- 
2.53.0
Previous: Justin ToblerNext: Patrick Steinhardt
Message 43 of 50 in “builtin/repo: include largest object information”
  1. 0/5 builtin/repo: include largest object informationJustin Tobler, Feb 3, 2026
  2. 1/5 builtin/repo: update stats for each objectJustin Tobler, Feb 3, 2026
  3. Junio C HamanoFeb 3, 2026
  4. Justin ToblerFeb 18, 2026
  5. Junio C HamanoFeb 26, 2026
  6. Justin ToblerFeb 26, 2026
  7. 2/5 builtin/repo: collect largest inflated objectsJustin Tobler, Feb 3, 2026
  8. Junio C HamanoFeb 3, 2026
  9. Justin ToblerFeb 18, 2026
  10. 3/5 builtin/repo: add OID annotations to table outputJustin Tobler, Feb 3, 2026
  11. Patrick SteinhardtFeb 13, 2026
  12. Justin ToblerFeb 18, 2026
  13. 4/5 builtin/repo: find commit with most parentsJustin Tobler, Feb 3, 2026
  14. Junio C HamanoFeb 3, 2026
  15. Kristoffer HaugsbakkFeb 3, 2026
  16. Junio C HamanoFeb 3, 2026
  17. Justin ToblerFeb 18, 2026
  18. 5/5 builtin/repo: find tree with most entriesJustin Tobler, Feb 3, 2026
  19. Junio C HamanoFeb 3, 2026
  20. Patrick SteinhardtFeb 4, 2026
  21. Junio C HamanoFeb 4, 2026
  22. 0/5 builtin/repo: include largest object informationJustin Tobler, Feb 23, 2026
  23. 1/5 builtin/repo: update stats for each objectJustin Tobler, Feb 23, 2026
  24. 2/5 builtin/repo: collect largest inflated objectsJustin Tobler, Feb 23, 2026
  25. Junio C HamanoFeb 26, 2026
  26. Justin ToblerMar 2, 2026
  27. Lucas Seiki OshiroFeb 28, 2026
  28. Justin ToblerMar 2, 2026
  29. 3/5 builtin/repo: add OID annotations to table outputJustin Tobler, Feb 23, 2026
  30. Junio C HamanoFeb 26, 2026
  31. Justin ToblerMar 2, 2026
  32. 4/5 builtin/repo: find commit with most parentsJustin Tobler, Feb 23, 2026
  33. 5/5 builtin/repo: find tree with most entriesJustin Tobler, Feb 23, 2026
  34. Patrick SteinhardtFeb 24, 2026
  35. Lucas Seiki OshiroFeb 28, 2026
  36. Justin ToblerMar 1, 2026
  37. 0/6 builtin/repo: include largest object informationJustin Tobler, Mar 2, 2026
  38. 1/6 builtin/repo: update stats for each objectJustin Tobler, Mar 2, 2026
  39. 2/6 builtin/repo: add helper for printing keyvalue outputJustin Tobler, Mar 2, 2026
  40. Patrick SteinhardtMar 3, 2026
  41. Junio C HamanoMar 3, 2026
  42. Justin ToblerMar 3, 2026
  43. 3/6 builtin/repo: collect largest inflated objectsJustin Tobler, Mar 2, 2026
  44. Patrick SteinhardtMar 3, 2026
  45. 4/6 builtin/repo: add OID annotations to table outputJustin Tobler, Mar 2, 2026
  46. 5/6 builtin/repo: find commit with most parentsJustin Tobler, Mar 2, 2026
  47. 6/6 builtin/repo: find tree with most entriesJustin Tobler, Mar 2, 2026
  48. Junio C HamanoMar 2, 2026
  49. Junio C HamanoMar 6, 2026
  50. Justin ToblerMar 8, 2026

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.