diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc index 70f0a6d2e4..287eee4b93 100644 --- a/Documentation/git-repo.adoc +++ b/Documentation/git-repo.adoc @@ -50,6 +50,7 @@ supported: + * Reference counts categorized by type * Reachable object counts categorized by type +* Total inflated size of reachable objects by type + The output format can be chosen through the flag `--format`. Three formats are diff --git a/builtin/repo.c b/builtin/repo.c index 9c61bc3e17..8da321a386 100644 --- a/builtin/repo.c +++ b/builtin/repo.c @@ -2,6 +2,8 @@ #include "builtin.h" #include "environment.h" +#include "hex.h" +#include "odb.h" #include "parse-options.h" #include "path-walk.h" #include "progress.h" @@ -211,6 +213,7 @@ struct object_values { struct object_stats { struct object_values type_counts; + struct object_values inflated_sizes; }; struct repo_structure { @@ -423,6 +426,15 @@ 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.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, + (uintmax_t)stats->objects.inflated_sizes.trees, value_delim); + printf("objects.blobs.inflated_size%c%" PRIuMAX "%c", key_delim, + (uintmax_t)stats->objects.inflated_sizes.blobs, value_delim); + printf("objects.tags.inflated_size%c%" PRIuMAX "%c", key_delim, + (uintmax_t)stats->objects.inflated_sizes.tags, value_delim); + fflush(stdout); } @@ -486,6 +498,7 @@ static void structure_count_references(struct ref_stats *stats, } struct count_objects_data { + struct object_database *odb; struct object_stats *stats; struct progress *progress; }; @@ -495,20 +508,39 @@ static int count_objects(const char *path UNUSED, struct oid_array *oids, { struct count_objects_data *data = cb_data; struct object_stats *stats = data->stats; + size_t inflated_total = 0; size_t object_count; + for (size_t i = 0; i < oids->nr; i++) { + struct object_info oi = OBJECT_INFO_INIT; + unsigned long inflated; + + oi.sizep = &inflated; + + if (odb_read_object_info_extended(data->odb, &oids->oid[i], &oi, + OBJECT_INFO_SKIP_FETCH_OBJECT | + OBJECT_INFO_QUICK) < 0) + continue; + + inflated_total += inflated; + } + switch (type) { case OBJ_TAG: stats->type_counts.tags += oids->nr; + stats->inflated_sizes.tags += inflated_total; break; case OBJ_COMMIT: stats->type_counts.commits += oids->nr; + stats->inflated_sizes.commits += inflated_total; break; case OBJ_TREE: stats->type_counts.trees += oids->nr; + stats->inflated_sizes.trees += inflated_total; break; case OBJ_BLOB: stats->type_counts.blobs += oids->nr; + stats->inflated_sizes.blobs += inflated_total; break; default: BUG("invalid object type"); @@ -526,6 +558,7 @@ static void structure_count_objects(struct object_stats *stats, { struct path_walk_info info = PATH_WALK_INFO_INIT; struct count_objects_data data = { + .odb = repo->objects, .stats = stats, }; diff --git a/t/t1901-repo-structure.sh b/t/t1901-repo-structure.sh index 55fd13ad1b..33237822fd 100755 --- a/t/t1901-repo-structure.sh +++ b/t/t1901-repo-structure.sh @@ -73,7 +73,7 @@ test_expect_success 'repository with references and objects' ' ) ' -test_expect_success 'keyvalue and nul format' ' +test_expect_success SHA1 'keyvalue and nul format' ' test_when_finished "rm -rf repo" && git init repo && ( @@ -90,6 +90,10 @@ test_expect_success 'keyvalue and nul format' ' 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 EOF git repo structure --format=keyvalue >out 2>err &&