aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/git-repo.adoc1
-rw-r--r--builtin/repo.c105
-rwxr-xr-xt/t1901-repo-structure.sh19
3 files changed, 117 insertions, 8 deletions
diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc
index 8193298dd5..ae62d2415f 100644
--- a/Documentation/git-repo.adoc
+++ b/Documentation/git-repo.adoc
@@ -49,6 +49,7 @@ supported:
following kinds of information are reported:
+
* Reference counts categorized by type
+* Reachable object counts categorized by type
+
The table output format may change and is not intended for machine parsing.
diff --git a/builtin/repo.c b/builtin/repo.c
index e77e8db563..f39f06ee8c 100644
--- a/builtin/repo.c
+++ b/builtin/repo.c
@@ -3,9 +3,11 @@
#include "builtin.h"
#include "environment.h"
#include "parse-options.h"
+#include "path-walk.h"
#include "quote.h"
#include "ref-filter.h"
#include "refs.h"
+#include "revision.h"
#include "strbuf.h"
#include "string-list.h"
#include "shallow.h"
@@ -167,6 +169,18 @@ struct ref_stats {
size_t others;
};
+struct object_stats {
+ size_t tags;
+ size_t commits;
+ size_t trees;
+ size_t blobs;
+};
+
+struct repo_structure {
+ struct ref_stats refs;
+ struct object_stats objects;
+};
+
struct stats_table {
struct string_list rows;
@@ -234,9 +248,17 @@ static inline size_t get_total_reference_count(struct ref_stats *stats)
return stats->branches + stats->remotes + stats->tags + stats->others;
}
+static inline size_t get_total_object_count(struct object_stats *stats)
+{
+ return stats->tags + stats->commits + stats->trees + stats->blobs;
+}
+
static void stats_table_setup_structure(struct stats_table *table,
- struct ref_stats *refs)
+ struct repo_structure *stats)
{
+ struct object_stats *objects = &stats->objects;
+ struct ref_stats *refs = &stats->refs;
+ size_t object_total;
size_t ref_total;
ref_total = get_total_reference_count(refs);
@@ -246,6 +268,15 @@ static void stats_table_setup_structure(struct stats_table *table,
stats_table_count_addf(table, refs->tags, " * %s", _("Tags"));
stats_table_count_addf(table, refs->remotes, " * %s", _("Remotes"));
stats_table_count_addf(table, refs->others, " * %s", _("Others"));
+
+ object_total = get_total_object_count(objects);
+ stats_table_addf(table, "");
+ stats_table_addf(table, "* %s", _("Reachable objects"));
+ stats_table_count_addf(table, object_total, " * %s", _("Count"));
+ stats_table_count_addf(table, objects->commits, " * %s", _("Commits"));
+ stats_table_count_addf(table, objects->trees, " * %s", _("Trees"));
+ stats_table_count_addf(table, objects->blobs, " * %s", _("Blobs"));
+ stats_table_count_addf(table, objects->tags, " * %s", _("Tags"));
}
static void stats_table_print_structure(const struct stats_table *table)
@@ -299,12 +330,18 @@ static void stats_table_clear(struct stats_table *table)
string_list_clear(&table->rows, 1);
}
+struct count_references_data {
+ struct ref_stats *stats;
+ struct rev_info *revs;
+};
+
static int count_references(const char *refname,
const char *referent UNUSED,
- const struct object_id *oid UNUSED,
+ const struct object_id *oid,
int flags UNUSED, void *cb_data)
{
- struct ref_stats *stats = cb_data;
+ struct count_references_data *data = cb_data;
+ struct ref_stats *stats = data->stats;
switch (ref_kind_from_refname(refname)) {
case FILTER_REFS_BRANCHES:
@@ -323,13 +360,64 @@ static int count_references(const char *refname,
BUG("unexpected reference type");
}
+ /*
+ * While iterating through references for counting, also add OIDs in
+ * preparation for the path walk.
+ */
+ add_pending_oid(data->revs, NULL, oid, 0);
+
return 0;
}
static void structure_count_references(struct ref_stats *stats,
+ struct rev_info *revs,
struct repository *repo)
{
- refs_for_each_ref(get_main_ref_store(repo), count_references, &stats);
+ struct count_references_data data = {
+ .stats = stats,
+ .revs = revs,
+ };
+
+ refs_for_each_ref(get_main_ref_store(repo), count_references, &data);
+}
+
+
+static int count_objects(const char *path UNUSED, struct oid_array *oids,
+ enum object_type type, void *cb_data)
+{
+ struct object_stats *stats = cb_data;
+
+ switch (type) {
+ case OBJ_TAG:
+ stats->tags += oids->nr;
+ break;
+ case OBJ_COMMIT:
+ stats->commits += oids->nr;
+ break;
+ case OBJ_TREE:
+ stats->trees += oids->nr;
+ break;
+ case OBJ_BLOB:
+ stats->blobs += oids->nr;
+ break;
+ default:
+ BUG("invalid object type");
+ }
+
+ return 0;
+}
+
+static void structure_count_objects(struct object_stats *stats,
+ struct rev_info *revs)
+{
+ struct path_walk_info info = PATH_WALK_INFO_INIT;
+
+ info.revs = revs;
+ info.path_fn = count_objects;
+ info.path_fn_data = stats;
+
+ walk_objects_by_path(&info);
+ path_walk_info_clear(&info);
}
static int cmd_repo_structure(int argc, const char **argv, const char *prefix,
@@ -338,19 +426,24 @@ static int cmd_repo_structure(int argc, const char **argv, const char *prefix,
struct stats_table table = {
.rows = STRING_LIST_INIT_DUP,
};
- struct ref_stats stats = { 0 };
+ struct repo_structure stats = { 0 };
+ struct rev_info revs;
struct option options[] = { 0 };
argc = parse_options(argc, argv, prefix, options, repo_usage, 0);
if (argc)
usage(_("too many arguments"));
- structure_count_references(&stats, repo);
+ repo_init_revisions(repo, &revs, prefix);
+
+ structure_count_references(&stats.refs, &revs, repo);
+ structure_count_objects(&stats.objects, &revs);
stats_table_setup_structure(&table, &stats);
stats_table_print_structure(&table);
stats_table_clear(&table);
+ release_revisions(&revs);
return 0;
}
diff --git a/t/t1901-repo-structure.sh b/t/t1901-repo-structure.sh
index e592eea0eb..c32cf4e239 100755
--- a/t/t1901-repo-structure.sh
+++ b/t/t1901-repo-structure.sh
@@ -18,6 +18,13 @@ test_expect_success 'empty repository' '
| * Tags | 0 |
| * Remotes | 0 |
| * Others | 0 |
+ | | |
+ | * Reachable objects | |
+ | * Count | 0 |
+ | * Commits | 0 |
+ | * Trees | 0 |
+ | * Blobs | 0 |
+ | * Tags | 0 |
EOF
git repo structure >out 2>err &&
@@ -27,17 +34,18 @@ test_expect_success 'empty repository' '
)
'
-test_expect_success 'repository with references' '
+test_expect_success 'repository with references and objects' '
test_when_finished "rm -rf repo" &&
git init repo &&
(
cd repo &&
- git commit --allow-empty -m init &&
+ test_commit_bulk 42 &&
git tag -a foo -m bar &&
oid="$(git rev-parse HEAD)" &&
git update-ref refs/remotes/origin/foo "$oid" &&
+ # Also creates a commit, tree, and blob.
git notes add -m foo &&
cat >expect <<-\EOF &&
@@ -49,6 +57,13 @@ test_expect_success 'repository with references' '
| * Tags | 1 |
| * Remotes | 1 |
| * Others | 1 |
+ | | |
+ | * Reachable objects | |
+ | * Count | 130 |
+ | * Commits | 43 |
+ | * Trees | 43 |
+ | * Blobs | 43 |
+ | * Tags | 1 |
EOF
git repo structure >out 2>err &&