mirror of
https://github.com/git-for-windows/git.git
synced 2026-05-31 12:28:51 -05:00
survey: add object count summary
At the moment, nothing is obvious about the reason for the use of the
path-walk API, but this will become more prevelant in future iterations. For
now, use the path-walk API to sum up the counts of each kind of object.
For example, this is the reachable object summary output for my local repo:
REACHABLE OBJECT SUMMARY
========================
Object Type | Count
------------+-------
Tags | 1343
Commits | 179344
Trees | 314350
Blobs | 184030
Signed-off-by: Derrick Stolee <stolee@gmail.com>
This commit is contained in:
committed by
Johannes Schindelin
parent
3ee79f0a2b
commit
2f3acdf2c4
@@ -72,6 +72,12 @@ The references summary includes a count of each kind of reference,
|
|||||||
including branches, remote refs, and tags (split by "all" and
|
including branches, remote refs, and tags (split by "all" and
|
||||||
"annotated").
|
"annotated").
|
||||||
|
|
||||||
|
Reachable Object Summary
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
The reachable object summary shows the total number of each kind of Git
|
||||||
|
object, including tags, commits, trees, and blobs.
|
||||||
|
|
||||||
GIT
|
GIT
|
||||||
---
|
---
|
||||||
Part of the linkgit:git[1] suite
|
Part of the linkgit:git[1] suite
|
||||||
|
|||||||
131
builtin/survey.c
131
builtin/survey.c
@@ -2,13 +2,20 @@
|
|||||||
|
|
||||||
#include "builtin.h"
|
#include "builtin.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include "environment.h"
|
||||||
|
#include "hex.h"
|
||||||
#include "object.h"
|
#include "object.h"
|
||||||
|
#include "object-name.h"
|
||||||
#include "object-store-ll.h"
|
#include "object-store-ll.h"
|
||||||
#include "parse-options.h"
|
#include "parse-options.h"
|
||||||
|
#include "path-walk.h"
|
||||||
#include "progress.h"
|
#include "progress.h"
|
||||||
#include "ref-filter.h"
|
#include "ref-filter.h"
|
||||||
|
#include "refs.h"
|
||||||
|
#include "revision.h"
|
||||||
#include "strbuf.h"
|
#include "strbuf.h"
|
||||||
#include "strvec.h"
|
#include "strvec.h"
|
||||||
|
#include "tag.h"
|
||||||
#include "trace2.h"
|
#include "trace2.h"
|
||||||
|
|
||||||
static const char * const survey_usage[] = {
|
static const char * const survey_usage[] = {
|
||||||
@@ -46,12 +53,20 @@ struct survey_report_ref_summary {
|
|||||||
size_t unknown_nr;
|
size_t unknown_nr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct survey_report_object_summary {
|
||||||
|
size_t commits_nr;
|
||||||
|
size_t tags_nr;
|
||||||
|
size_t trees_nr;
|
||||||
|
size_t blobs_nr;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This struct contains all of the information that needs to be printed
|
* This struct contains all of the information that needs to be printed
|
||||||
* at the end of the exploration of the repository and its references.
|
* at the end of the exploration of the repository and its references.
|
||||||
*/
|
*/
|
||||||
struct survey_report {
|
struct survey_report {
|
||||||
struct survey_report_ref_summary refs;
|
struct survey_report_ref_summary refs;
|
||||||
|
struct survey_report_object_summary reachable_objects;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct survey_context {
|
struct survey_context {
|
||||||
@@ -74,10 +89,12 @@ struct survey_context {
|
|||||||
size_t progress_total;
|
size_t progress_total;
|
||||||
|
|
||||||
struct strvec refs;
|
struct strvec refs;
|
||||||
|
struct ref_array ref_array;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void clear_survey_context(struct survey_context *ctx)
|
static void clear_survey_context(struct survey_context *ctx)
|
||||||
{
|
{
|
||||||
|
ref_array_clear(&ctx->ref_array);
|
||||||
strvec_clear(&ctx->refs);
|
strvec_clear(&ctx->refs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,10 +145,14 @@ static const size_t section_len = 4 * SECTION_SEGMENT_LEN;
|
|||||||
static void print_table_title(const char *name, size_t *widths, size_t nr)
|
static void print_table_title(const char *name, size_t *widths, size_t nr)
|
||||||
{
|
{
|
||||||
size_t width = 3 * (nr - 1);
|
size_t width = 3 * (nr - 1);
|
||||||
|
size_t min_width = strlen(name);
|
||||||
|
|
||||||
for (size_t i = 0; i < nr; i++)
|
for (size_t i = 0; i < nr; i++)
|
||||||
width += widths[i];
|
width += widths[i];
|
||||||
|
|
||||||
|
if (width < min_width)
|
||||||
|
width = min_width;
|
||||||
|
|
||||||
if (width > section_len)
|
if (width > section_len)
|
||||||
width = section_len;
|
width = section_len;
|
||||||
|
|
||||||
@@ -228,11 +249,43 @@ static void survey_report_plaintext_refs(struct survey_context *ctx)
|
|||||||
clear_table(&table);
|
clear_table(&table);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void survey_report_plaintext_reachable_object_summary(struct survey_context *ctx)
|
||||||
|
{
|
||||||
|
struct survey_report_object_summary *objs = &ctx->report.reachable_objects;
|
||||||
|
struct survey_table table = SURVEY_TABLE_INIT;
|
||||||
|
char *fmt;
|
||||||
|
|
||||||
|
table.table_name = _("REACHABLE OBJECT SUMMARY");
|
||||||
|
|
||||||
|
strvec_push(&table.header, _("Object Type"));
|
||||||
|
strvec_push(&table.header, _("Count"));
|
||||||
|
|
||||||
|
fmt = xstrfmt("%"PRIuMAX"", (uintmax_t)objs->tags_nr);
|
||||||
|
insert_table_rowv(&table, _("Tags"), fmt, NULL);
|
||||||
|
free(fmt);
|
||||||
|
|
||||||
|
fmt = xstrfmt("%"PRIuMAX"", (uintmax_t)objs->commits_nr);
|
||||||
|
insert_table_rowv(&table, _("Commits"), fmt, NULL);
|
||||||
|
free(fmt);
|
||||||
|
|
||||||
|
fmt = xstrfmt("%"PRIuMAX"", (uintmax_t)objs->trees_nr);
|
||||||
|
insert_table_rowv(&table, _("Trees"), fmt, NULL);
|
||||||
|
free(fmt);
|
||||||
|
|
||||||
|
fmt = xstrfmt("%"PRIuMAX"", (uintmax_t)objs->blobs_nr);
|
||||||
|
insert_table_rowv(&table, _("Blobs"), fmt, NULL);
|
||||||
|
free(fmt);
|
||||||
|
|
||||||
|
print_table_plaintext(&table);
|
||||||
|
clear_table(&table);
|
||||||
|
}
|
||||||
|
|
||||||
static void survey_report_plaintext(struct survey_context *ctx)
|
static void survey_report_plaintext(struct survey_context *ctx)
|
||||||
{
|
{
|
||||||
printf("GIT SURVEY for \"%s\"\n", ctx->repo->worktree);
|
printf("GIT SURVEY for \"%s\"\n", ctx->repo->worktree);
|
||||||
printf("-----------------------------------------------------\n");
|
printf("-----------------------------------------------------\n");
|
||||||
survey_report_plaintext_refs(ctx);
|
survey_report_plaintext_refs(ctx);
|
||||||
|
survey_report_plaintext_reachable_object_summary(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -380,15 +433,13 @@ static void do_load_refs(struct survey_context *ctx,
|
|||||||
*/
|
*/
|
||||||
static void survey_phase_refs(struct survey_context *ctx)
|
static void survey_phase_refs(struct survey_context *ctx)
|
||||||
{
|
{
|
||||||
struct ref_array ref_array = { 0 };
|
|
||||||
|
|
||||||
trace2_region_enter("survey", "phase/refs", ctx->repo);
|
trace2_region_enter("survey", "phase/refs", ctx->repo);
|
||||||
do_load_refs(ctx, &ref_array);
|
do_load_refs(ctx, &ctx->ref_array);
|
||||||
|
|
||||||
ctx->report.refs.refs_nr = ref_array.nr;
|
ctx->report.refs.refs_nr = ctx->ref_array.nr;
|
||||||
for (int i = 0; i < ref_array.nr; i++) {
|
for (int i = 0; i < ctx->ref_array.nr; i++) {
|
||||||
unsigned long size;
|
unsigned long size;
|
||||||
struct ref_array_item *item = ref_array.items[i];
|
struct ref_array_item *item = ctx->ref_array.items[i];
|
||||||
|
|
||||||
switch (item->kind) {
|
switch (item->kind) {
|
||||||
case FILTER_REFS_TAGS:
|
case FILTER_REFS_TAGS:
|
||||||
@@ -418,8 +469,72 @@ static void survey_phase_refs(struct survey_context *ctx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
trace2_region_leave("survey", "phase/refs", ctx->repo);
|
trace2_region_leave("survey", "phase/refs", ctx->repo);
|
||||||
|
}
|
||||||
|
|
||||||
ref_array_clear(&ref_array);
|
static void increment_object_counts(
|
||||||
|
struct survey_report_object_summary *summary,
|
||||||
|
enum object_type type,
|
||||||
|
size_t nr)
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
case OBJ_COMMIT:
|
||||||
|
summary->commits_nr += nr;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OBJ_TREE:
|
||||||
|
summary->trees_nr += nr;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OBJ_BLOB:
|
||||||
|
summary->blobs_nr += nr;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OBJ_TAG:
|
||||||
|
summary->tags_nr += nr;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int survey_objects_path_walk_fn(const char *path,
|
||||||
|
struct oid_array *oids,
|
||||||
|
enum object_type type,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
struct survey_context *ctx = data;
|
||||||
|
|
||||||
|
increment_object_counts(&ctx->report.reachable_objects,
|
||||||
|
type, oids->nr);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void survey_phase_objects(struct survey_context *ctx)
|
||||||
|
{
|
||||||
|
struct rev_info revs = REV_INFO_INIT;
|
||||||
|
struct path_walk_info info = PATH_WALK_INFO_INIT;
|
||||||
|
unsigned int add_flags = 0;
|
||||||
|
|
||||||
|
trace2_region_enter("survey", "phase/objects", ctx->repo);
|
||||||
|
|
||||||
|
info.revs = &revs;
|
||||||
|
info.path_fn = survey_objects_path_walk_fn;
|
||||||
|
info.path_fn_data = ctx;
|
||||||
|
|
||||||
|
repo_init_revisions(ctx->repo, &revs, "");
|
||||||
|
revs.tag_objects = 1;
|
||||||
|
|
||||||
|
for (int i = 0; i < ctx->ref_array.nr; i++) {
|
||||||
|
struct ref_array_item *item = ctx->ref_array.items[i];
|
||||||
|
add_pending_oid(&revs, NULL, &item->objectname, add_flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
walk_objects_by_path(&info);
|
||||||
|
|
||||||
|
release_revisions(&revs);
|
||||||
|
trace2_region_leave("survey", "phase/objects", ctx->repo);
|
||||||
}
|
}
|
||||||
|
|
||||||
int cmd_survey(int argc, const char **argv, const char *prefix, struct repository *repo)
|
int cmd_survey(int argc, const char **argv, const char *prefix, struct repository *repo)
|
||||||
@@ -472,6 +587,8 @@ int cmd_survey(int argc, const char **argv, const char *prefix, struct repositor
|
|||||||
|
|
||||||
survey_phase_refs(&ctx);
|
survey_phase_refs(&ctx);
|
||||||
|
|
||||||
|
survey_phase_objects(&ctx);
|
||||||
|
|
||||||
survey_report_plaintext(&ctx);
|
survey_report_plaintext(&ctx);
|
||||||
|
|
||||||
clear_survey_context(&ctx);
|
clear_survey_context(&ctx);
|
||||||
|
|||||||
@@ -16,11 +16,17 @@ test_expect_success 'git survey -h shows experimental warning' '
|
|||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'create a semi-interesting repo' '
|
test_expect_success 'create a semi-interesting repo' '
|
||||||
test_commit_bulk 10
|
test_commit_bulk 10 &&
|
||||||
|
git tag -a -m one one HEAD~5 &&
|
||||||
|
git tag -a -m two two HEAD~3 &&
|
||||||
|
git tag -a -m three three two &&
|
||||||
|
git tag -a -m four four three &&
|
||||||
|
git update-ref -d refs/tags/three &&
|
||||||
|
git update-ref -d refs/tags/two
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'git survey (default)' '
|
test_expect_success 'git survey (default)' '
|
||||||
git survey >out 2>err &&
|
git survey --all-refs >out 2>err &&
|
||||||
test_line_count = 0 err &&
|
test_line_count = 0 err &&
|
||||||
|
|
||||||
tr , " " >expect <<-EOF &&
|
tr , " " >expect <<-EOF &&
|
||||||
@@ -33,8 +39,17 @@ test_expect_success 'git survey (default)' '
|
|||||||
-----------------+------
|
-----------------+------
|
||||||
, Branches | 1
|
, Branches | 1
|
||||||
Remote refs | 0
|
Remote refs | 0
|
||||||
Tags (all) | 0
|
Tags (all) | 2
|
||||||
Tags (annotated) | 0
|
Tags (annotated) | 2
|
||||||
|
|
||||||
|
REACHABLE OBJECT SUMMARY
|
||||||
|
========================
|
||||||
|
Object Type | Count
|
||||||
|
------------+------
|
||||||
|
Tags | 4
|
||||||
|
Commits | 10
|
||||||
|
Trees | 10
|
||||||
|
Blobs | 10
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
test_cmp expect out
|
test_cmp expect out
|
||||||
|
|||||||
Reference in New Issue
Block a user