Skip to content

Commit eb5cf58

Browse files
jltoblergitster
authored andcommitted
builtin/repo: add object counts in structure output
The amount of objects in a repository can provide insight regarding its shape. To surface this information, use the path-walk API to count the number of reachable objects in the repository by object type. All regular references are used to determine the reachable set of objects. The object counts are appended to the same table containing the reference information. Signed-off-by: Justin Tobler <jltobler@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent bbb2b93 commit eb5cf58

File tree

3 files changed

+117
-8
lines changed

3 files changed

+117
-8
lines changed

Documentation/git-repo.adoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ supported:
4949
following kinds of information are reported:
5050
+
5151
* Reference counts categorized by type
52+
* Reachable object counts categorized by type
5253

5354
+
5455
The table output format may change and is not intended for machine parsing.

builtin/repo.c

Lines changed: 99 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@
33
#include "builtin.h"
44
#include "environment.h"
55
#include "parse-options.h"
6+
#include "path-walk.h"
67
#include "quote.h"
78
#include "ref-filter.h"
89
#include "refs.h"
10+
#include "revision.h"
911
#include "strbuf.h"
1012
#include "string-list.h"
1113
#include "shallow.h"
@@ -167,6 +169,18 @@ struct ref_stats {
167169
size_t others;
168170
};
169171

172+
struct object_stats {
173+
size_t tags;
174+
size_t commits;
175+
size_t trees;
176+
size_t blobs;
177+
};
178+
179+
struct repo_structure {
180+
struct ref_stats refs;
181+
struct object_stats objects;
182+
};
183+
170184
struct stats_table {
171185
struct string_list rows;
172186

@@ -234,9 +248,17 @@ static inline size_t get_total_reference_count(struct ref_stats *stats)
234248
return stats->branches + stats->remotes + stats->tags + stats->others;
235249
}
236250

251+
static inline size_t get_total_object_count(struct object_stats *stats)
252+
{
253+
return stats->tags + stats->commits + stats->trees + stats->blobs;
254+
}
255+
237256
static void stats_table_setup_structure(struct stats_table *table,
238-
struct ref_stats *refs)
257+
struct repo_structure *stats)
239258
{
259+
struct object_stats *objects = &stats->objects;
260+
struct ref_stats *refs = &stats->refs;
261+
size_t object_total;
240262
size_t ref_total;
241263

242264
ref_total = get_total_reference_count(refs);
@@ -246,6 +268,15 @@ static void stats_table_setup_structure(struct stats_table *table,
246268
stats_table_count_addf(table, refs->tags, " * %s", _("Tags"));
247269
stats_table_count_addf(table, refs->remotes, " * %s", _("Remotes"));
248270
stats_table_count_addf(table, refs->others, " * %s", _("Others"));
271+
272+
object_total = get_total_object_count(objects);
273+
stats_table_addf(table, "");
274+
stats_table_addf(table, "* %s", _("Reachable objects"));
275+
stats_table_count_addf(table, object_total, " * %s", _("Count"));
276+
stats_table_count_addf(table, objects->commits, " * %s", _("Commits"));
277+
stats_table_count_addf(table, objects->trees, " * %s", _("Trees"));
278+
stats_table_count_addf(table, objects->blobs, " * %s", _("Blobs"));
279+
stats_table_count_addf(table, objects->tags, " * %s", _("Tags"));
249280
}
250281

251282
static void stats_table_print_structure(const struct stats_table *table)
@@ -299,12 +330,18 @@ static void stats_table_clear(struct stats_table *table)
299330
string_list_clear(&table->rows, 1);
300331
}
301332

333+
struct count_references_data {
334+
struct ref_stats *stats;
335+
struct rev_info *revs;
336+
};
337+
302338
static int count_references(const char *refname,
303339
const char *referent UNUSED,
304-
const struct object_id *oid UNUSED,
340+
const struct object_id *oid,
305341
int flags UNUSED, void *cb_data)
306342
{
307-
struct ref_stats *stats = cb_data;
343+
struct count_references_data *data = cb_data;
344+
struct ref_stats *stats = data->stats;
308345

309346
switch (ref_kind_from_refname(refname)) {
310347
case FILTER_REFS_BRANCHES:
@@ -323,13 +360,64 @@ static int count_references(const char *refname,
323360
BUG("unexpected reference type");
324361
}
325362

363+
/*
364+
* While iterating through references for counting, also add OIDs in
365+
* preparation for the path walk.
366+
*/
367+
add_pending_oid(data->revs, NULL, oid, 0);
368+
326369
return 0;
327370
}
328371

329372
static void structure_count_references(struct ref_stats *stats,
373+
struct rev_info *revs,
330374
struct repository *repo)
331375
{
332-
refs_for_each_ref(get_main_ref_store(repo), count_references, &stats);
376+
struct count_references_data data = {
377+
.stats = stats,
378+
.revs = revs,
379+
};
380+
381+
refs_for_each_ref(get_main_ref_store(repo), count_references, &data);
382+
}
383+
384+
385+
static int count_objects(const char *path UNUSED, struct oid_array *oids,
386+
enum object_type type, void *cb_data)
387+
{
388+
struct object_stats *stats = cb_data;
389+
390+
switch (type) {
391+
case OBJ_TAG:
392+
stats->tags += oids->nr;
393+
break;
394+
case OBJ_COMMIT:
395+
stats->commits += oids->nr;
396+
break;
397+
case OBJ_TREE:
398+
stats->trees += oids->nr;
399+
break;
400+
case OBJ_BLOB:
401+
stats->blobs += oids->nr;
402+
break;
403+
default:
404+
BUG("invalid object type");
405+
}
406+
407+
return 0;
408+
}
409+
410+
static void structure_count_objects(struct object_stats *stats,
411+
struct rev_info *revs)
412+
{
413+
struct path_walk_info info = PATH_WALK_INFO_INIT;
414+
415+
info.revs = revs;
416+
info.path_fn = count_objects;
417+
info.path_fn_data = stats;
418+
419+
walk_objects_by_path(&info);
420+
path_walk_info_clear(&info);
333421
}
334422

335423
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,
338426
struct stats_table table = {
339427
.rows = STRING_LIST_INIT_DUP,
340428
};
341-
struct ref_stats stats = { 0 };
429+
struct repo_structure stats = { 0 };
430+
struct rev_info revs;
342431
struct option options[] = { 0 };
343432

344433
argc = parse_options(argc, argv, prefix, options, repo_usage, 0);
345434
if (argc)
346435
usage(_("too many arguments"));
347436

348-
structure_count_references(&stats, repo);
437+
repo_init_revisions(repo, &revs, prefix);
438+
439+
structure_count_references(&stats.refs, &revs, repo);
440+
structure_count_objects(&stats.objects, &revs);
349441

350442
stats_table_setup_structure(&table, &stats);
351443
stats_table_print_structure(&table);
352444

353445
stats_table_clear(&table);
446+
release_revisions(&revs);
354447

355448
return 0;
356449
}

t/t1901-repo-structure.sh

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,13 @@ test_expect_success 'empty repository' '
1818
| * Tags | 0 |
1919
| * Remotes | 0 |
2020
| * Others | 0 |
21+
| | |
22+
| * Reachable objects | |
23+
| * Count | 0 |
24+
| * Commits | 0 |
25+
| * Trees | 0 |
26+
| * Blobs | 0 |
27+
| * Tags | 0 |
2128
EOF
2229
2330
git repo structure >out 2>err &&
@@ -27,17 +34,18 @@ test_expect_success 'empty repository' '
2734
)
2835
'
2936

30-
test_expect_success 'repository with references' '
37+
test_expect_success 'repository with references and objects' '
3138
test_when_finished "rm -rf repo" &&
3239
git init repo &&
3340
(
3441
cd repo &&
35-
git commit --allow-empty -m init &&
42+
test_commit_bulk 42 &&
3643
git tag -a foo -m bar &&
3744
3845
oid="$(git rev-parse HEAD)" &&
3946
git update-ref refs/remotes/origin/foo "$oid" &&
4047
48+
# Also creates a commit, tree, and blob.
4149
git notes add -m foo &&
4250
4351
cat >expect <<-\EOF &&
@@ -49,6 +57,13 @@ test_expect_success 'repository with references' '
4957
| * Tags | 1 |
5058
| * Remotes | 1 |
5159
| * Others | 1 |
60+
| | |
61+
| * Reachable objects | |
62+
| * Count | 130 |
63+
| * Commits | 43 |
64+
| * Trees | 43 |
65+
| * Blobs | 43 |
66+
| * Tags | 1 |
5267
EOF
5368
5469
git repo structure >out 2>err &&

0 commit comments

Comments
 (0)