"git repo structure" computes a set of statistics that are useful for diagnosing performance issues in a git repository. But for a typical user who hasn't encountered any issues yet, it can be difficult to interpret the data - when should a value be considered concerning?
This patchset introduces a feature to "git repo structure" that reports on how concerning certain measures of storage structure are for a repository. In table mode, concern is displayed as a column containing a number of stars indicating the degree of concern; in line or nul mode, concerns are displayed as additional lines with a numeric value. This provides a functionality equivalent to the concern column provided by "git-sizer", although the implementation is different.
To select defaults for the thresholds where a value becomes concern, a (hopefully) representative selection of repositories were analyzed. Based on empirical exploration of the data, the measurement that seemed closest to accurately assessing when a repository's structure becomes concerning was based on the base 2 logarithm of the value. Across all of the sample repositories, for all of the measurements, the point at which things become concerning was when a base 2 logarithm of a statistic's value was more than 1 standard deviation from the mean of the log_2 values of that stastistic in the sample set. Based on this, the concern threshold was set for each of the measures.
While this seems like a reasonable approach for setting default thresholds, it's obviously still very ad-hoc. It's likely that over time, the default values will evolve; and in any case, some projects will want to set their own thresholds. To allow that, this includes support for configuring the thresholds on a per-repository basis.
Overview of the change:
* The first commit adds the command-line option "--concern", and creates the basic implementation of concern reporting.
* The next commit adds configurability for the concern thresholds.Signed-off-by: Mark C. Chu-Carroll <markchucarroll@fastmail.com>
---
Changes in v4:
- Reworked the history; the previous round had a history-rewrite error.
- Removed the duplication of configuration keys for the concern thresholds.
- Changed the prefix of the config keys.
- readability/quality of life naming changes.
- Link to v3: https://patch.msgid.link/20261027-b4-repo-structure-concern-v3-0-98d7a5704170@fastmail.com
Changes in v3:
- Merge the documentation commit backwards into the other two commits.
- Link to v2: https://patch.msgid.link/20261026-b4-repo-structure-concern-v2-0-e0df34228dc8@fastmail.com
Changes in v2:
- Fix memory leak in concern string generation.
- Fix CI/CD test issue involving zlib versions.
- Updating the naming of the config value prefix.
- Link to v1: https://patch.msgid.link/20261021-b4-repo-structure-concern-v1-0-e3010552292c@fastmail.com
To: git@vger.kernel.org
---
Mark C. Chu-Carroll (2):
repo: add level of concern reporting
repo: make concern thresholds configurable Documentation/config/repo.adoc | 59 ++++++
Documentation/git-repo.adoc | 27 ++-
builtin/repo.c | 408 ++++++++++++++++++++++++++++++++++++++---
repo.c | 1 +
t/t1901-repo-structure.sh | 137 ++++++++++++++
5 files changed, 602 insertions(+), 30 deletions(-)
Range-diff versus v3:
1: 0f4e75e270 ! 1: 5f67be20e2 repo: add level of concern reporting
@@ Commit message
interpret the data - when should a value be considered
concerning?
- Add an option to "git repo structure" that adds a "degree
- of concern" column to the structure report, which indicates
- when a stat values has reached a point where it might be
- concerning, and indicate how severe the concern should be.
+ Add a new option to "git repo structure" which causes it
+ to generate an additional column providing a level of concern
+ for many values.
+
+ To select defaults for the thresholds where a value becomes concern,
+ a (hopefully) representative selection of repositories were analyzed.
+ Based on empirical exploration of the data, the measurement that seemed
+ closest to accurately assessing when a repository's structure becomes
+ concerning was based on the base 2 logarithm of the value. Across all of
+ the sample repositories, for all of the measurements, the point at which
+ things become problematic was when a base 2 logarithm of a value was
+ more than 1 standard deviation from the mean of the log_2 values in
+ the sample set.
+
+ Signed-off-by: Mark C. Chu-Carroll <markchucarroll@fastmail.com>
## Documentation/git-repo.adoc ##
@@ Documentation/git-repo.adoc: SYNOPSIS
@@ Documentation/git-repo.adoc: supported:
## builtin/repo.c ##
@@
+ #include "tree.h"
+ #include "tree-walk.h"
+ #include "utf8.h"
++#include "wrapper.h"
+
+ #define REPO_INFO_USAGE \
+ "git repo info [--format=(lines|nul) | -z] [--all | <key>...]", \
"git repo info --keys [--format=(lines|nul) | -z]"
#define REPO_STRUCTURE_USAGE \
@@ builtin/repo.c: struct stats_table {
+ size_t threshold;
+};
+
-+enum concern_stat {
-+ CONCERN_STAT_COMMIT_COUNT,
-+ CONCERN_STAT_TREE_COUNT,
-+ CONCERN_STAT_BLOB_COUNT,
-+ CONCERN_STAT_TAG_COUNT,
-+ CONCERN_STAT_COMMIT_SIZE,
-+ CONCERN_STAT_TREE_SIZE,
-+ CONCERN_STAT_BLOB_SIZE,
-+ CONCERN_STAT_TAG_SIZE,
-+ CONCERN_STAT_COMMIT_LARGEST,
-+ CONCERN_STAT_TREE_LARGEST,
-+ CONCERN_STAT_BLOB_LARGEST,
-+ CONCERN_STAT_TAG_LARGEST,
-+ CONCERN_STAT_COMMIT_INFLATED_SIZE,
-+ CONCERN_STAT_TREE_INFLATED_SIZE,
-+ CONCERN_STAT_BLOB_INFLATED_SIZE,
-+ CONCERN_STAT_TAG_INFLATED_SIZE,
-+};
++#define CONCERN_STAT_COMMIT_COUNT "commit-count"
++#define CONCERN_STAT_TREE_COUNT "tree-count"
++#define CONCERN_STAT_BLOB_COUNT "blob-count"
++#define CONCERN_STAT_TAG_COUNT "tag-count"
++#define CONCERN_STAT_COMMIT_SIZE "commit-size"
++#define CONCERN_STAT_TREE_SIZE "tree-size"
++#define CONCERN_STAT_BLOB_SIZE "blob-size"
++#define CONCERN_STAT_TAG_SIZE "tag-size"
++#define CONCERN_STAT_COMMIT_LARGEST "commit-largest"
++#define CONCERN_STAT_TREE_LARGEST "tree-largest"
++#define CONCERN_STAT_BLOB_LARGEST "blob-largest"
++#define CONCERN_STAT_TAG_LARGEST "tag-largest"
++#define CONCERN_STAT_COMMIT_INFLATED_SIZE "commit-inflated-size"
++#define CONCERN_STAT_TREE_INFLATED_SIZE "tree-inflated-size"
++#define CONCERN_STAT_BLOB_INFLATED_SIZE "blob-inflated-size"
++#define CONCERN_STAT_TAG_INFLATED_SIZE "tag-inflated-size"
+
+struct concern_stat_threshold repo_structure_concern_thresholds[] = {
-+ { .name = "commit_count", .threshold = 19 },
-+ {.name = "tree_count", .threshold = 21 },
-+ { .name = "blob_count", .threshold = 22 },
-+ { .name = "tag_count", .threshold = 15 },
-+ { .name = "commit_size", .threshold = 28 },
-+ { .name = "tree_size", .threshold = 27 },
-+ { .name = "blob_size", .threshold = 36 },
-+ { .name = "tags_size", .threshold = 18 },
-+ { .name = "commit_largest", .threshold = 18 },
-+ { .name = "tree_largest", .threshold = 18 },
-+ { .name = "blob_largest", .threshold = 26 },
-+ { .name = "tag_largest", .threshold = 15 },
-+ { .name = "commit_inflated_size", .threshold = 28 },
-+ { .name = "tree_inflated_size", .threshold = 32 },
-+ { .name = "blob_inflated_size", .threshold = 34 },
-+ { .name = "tag_inflated_size", .threshold = 25}
++ { .name = CONCERN_STAT_COMMIT_COUNT, .threshold = 19 },
++ { .name = CONCERN_STAT_TREE_COUNT, .threshold = 21 },
++ { .name = CONCERN_STAT_BLOB_COUNT, .threshold = 22 },
++ { .name = CONCERN_STAT_TAG_COUNT, .threshold = 15 },
++ { .name = CONCERN_STAT_COMMIT_SIZE, .threshold = 28 },
++ { .name = CONCERN_STAT_TREE_SIZE, .threshold = 27 },
++ { .name = CONCERN_STAT_BLOB_SIZE, .threshold = 36 },
++ { .name = CONCERN_STAT_TAG_SIZE, .threshold = 18 },
++ { .name = CONCERN_STAT_COMMIT_LARGEST, .threshold = 18 },
++ { .name = CONCERN_STAT_TREE_LARGEST, .threshold = 18 },
++ { .name = CONCERN_STAT_BLOB_LARGEST, .threshold = 26 },
++ { .name = CONCERN_STAT_TAG_LARGEST, .threshold = 15 },
++ { .name = CONCERN_STAT_COMMIT_INFLATED_SIZE, .threshold = 28 },
++ { .name = CONCERN_STAT_TREE_INFLATED_SIZE, .threshold = 32 },
++ { .name = CONCERN_STAT_BLOB_INFLATED_SIZE, .threshold = 34 },
++ { .name = CONCERN_STAT_TAG_INFLATED_SIZE, .threshold = 25 },
++ { 0 }
+};
+
-+/*
-+ * Concern thresholds aren't universal. We try to set reasonable default
-+ * values, but projects may want to set these thresholds differently. To
-+ * support that, they can set the thresholds for their project in the
-+ * project's git config, in the section "repo.structure.concern".
-+ */
-+static int config_concern_thresholds(const char *prefixed_var,
-+ const char *str_val,
-+ const struct config_context *ctx,
-+ void *cb UNUSED) {
-+ const char *config_prefix = "repo.structure.concern.";
-+ if (!strncmp(config_prefix, prefixed_var, strlen(config_prefix))) {
-+ const char *concern_name = &prefixed_var[strlen(config_prefix)];
-+ for (int i = 0; concern_stat_thresholds[i].name != 0; i++) {
-+ if (!strcmp(concern_stat_thresholds[i].name, concern_name)) {
-+ int value = git_config_int(prefixed_var, str_val, ctx->kvi);
-+ if (value < 0)
-+ return -1;
-+ concern_stat_thresholds[i].threshold = value;
-+ return 0;
-+ }
++static size_t get_concern_threshold(const char *name, struct concern_stat_threshold *thresholds) {
++ for (size_t i = 0; thresholds[i].name; i++) {
++ if (!strcmp(thresholds[i].name, name)) {
++ return thresholds[i].threshold;
+ }
-+ warning(_("Invalid concern threshold name: '%s'"), concern_name);
-+ return 0;
+ }
+ return 0;
+}
+
-+static size_t approx_log2(long value) {
-+ int position = 0;
-+ if (value <= 0) {
-+ return 0;
-+ }
-+ while (value > 1) {
-+ position++;
-+ value >>= 1;
-+ }
-+ return position;
-+}
-+
-+static size_t repo_structure_concern_level(enum concern_stat stat_id,
-+ size_t value) {
++static size_t repo_structure_concern_level(const char* concern_name,
++ size_t value,
++ struct concern_stat_threshold *thresholds) {
++ const size_t threshold = get_concern_threshold(concern_name, thresholds);
+ size_t log_value;
-+ if (stat_id >= ARRAY_SIZE(concern_stat_thresholds))
-+ BUG("unexpected repository stat type");
-+ log_value = approx_log2(value);
-+ if (log_value > concern_stat_thresholds[stat_id].threshold)
-+ return log_value -
-+ concern_stat_thresholds[stat_id].threshold;
++ if (threshold == 0)
++ BUG("unexpected repository stat threshold: '%s'", concern_name);
++ log_value = log2u(value);
++ if (log_value > threshold)
++ return log_value - threshold;
+ else
+ return 0;
+}
@@ builtin/repo.c: static void stats_table_vaddf(struct stats_table *table,
int unit_width = utf8_strwidth(entry->unit);
if (unit_width > table->unit_col_width)
@@ builtin/repo.c: static void stats_table_addf(struct stats_table *table, const char *format, ...)
+ va_end(ap);
}
++// define a symbol for 'no concern value for this stat'; this will
++// make the code below easier to read.
++#define CONCERN_STAT_VALUE_NONE 0
++
static void stats_table_count_addf(struct stats_table *table, size_t value,
- const char *format, ...)
+ size_t concern, const char *format, ...)
@@ builtin/repo.c: static void stats_table_setup_structure(struct stats_table *tabl
- 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"));
-+ stats_table_count_addf(table, ref_total, 0,
+-
++ stats_table_count_addf(table, ref_total, CONCERN_STAT_VALUE_NONE,
+ " * %s", _("Count"));
-+ stats_table_count_addf(table, refs->branches, 0,
++ stats_table_count_addf(table, refs->branches, CONCERN_STAT_VALUE_NONE,
+ " * %s", _("Branches"));
+ stats_table_count_addf(table, refs->tags,
+ repo_structure_concern_level(
+ CONCERN_STAT_TAG_COUNT,
-+ refs->tags),
++ refs->tags,
++ repo_structure_concern_thresholds),
+ " * %s", _("Tags"));
-+ stats_table_count_addf(table, refs->remotes, 0,
++ stats_table_count_addf(table, refs->remotes, CONCERN_STAT_VALUE_NONE,
+ " * %s", _("Remotes"));
-+ stats_table_count_addf(table, refs->others, 0,
++ stats_table_count_addf(table, refs->others, CONCERN_STAT_VALUE_NONE,
+ " * %s", _("Others"));
-
object_count_total = get_total_object_values(&objects->type_counts);
stats_table_addf(table, "");
stats_table_addf(table, "* %s", _("Reachable objects"));
- stats_table_count_addf(table, object_count_total, " * %s", _("Count"));
-+ stats_table_count_addf(table, object_count_total, 0,
++ stats_table_count_addf(table, object_count_total, CONCERN_STAT_VALUE_NONE,
+ " * %s", _("Count"));
stats_table_count_addf(table, objects->type_counts.commits,
+ repo_structure_concern_level(
+ CONCERN_STAT_COMMIT_COUNT,
-+ objects->type_counts.commits),
++ objects->type_counts.commits,
++ repo_structure_concern_thresholds),
" * %s", _("Commits"));
stats_table_count_addf(table, objects->type_counts.trees,
+ repo_structure_concern_level(
+ CONCERN_STAT_TREE_COUNT,
-+ objects->type_counts.trees),
++ objects->type_counts.trees,
++ repo_structure_concern_thresholds),
" * %s", _("Trees"));
stats_table_count_addf(table, objects->type_counts.blobs,
+ repo_structure_concern_level(
+ CONCERN_STAT_BLOB_COUNT,
-+ objects->type_counts.blobs),
++ objects->type_counts.blobs,
++ repo_structure_concern_thresholds),
" * %s", _("Blobs"));
stats_table_count_addf(table, objects->type_counts.tags,
+ repo_structure_concern_level(
+ CONCERN_STAT_TAG_COUNT,
-+ objects->type_counts.tags),
++ objects->type_counts.tags,
++ repo_structure_concern_thresholds),
" * %s", _("Tags"));
inflated_object_total = get_total_object_values(&objects->inflated_sizes);
- stats_table_size_addf(table, inflated_object_total,
-+ stats_table_size_addf(table, inflated_object_total, 0,
++ stats_table_size_addf(table, inflated_object_total, CONCERN_STAT_VALUE_NONE,
" * %s", _("Inflated size"));
stats_table_size_addf(table, objects->inflated_sizes.commits,
+ repo_structure_concern_level(
+ CONCERN_STAT_COMMIT_INFLATED_SIZE,
-+ objects->inflated_sizes.commits),
++ objects->inflated_sizes.commits,
++ repo_structure_concern_thresholds),
" * %s", _("Commits"));
stats_table_size_addf(table, objects->inflated_sizes.trees,
+ repo_structure_concern_level(
+ CONCERN_STAT_TREE_INFLATED_SIZE,
-+ objects->inflated_sizes.trees),
++ objects->inflated_sizes.trees,
++ repo_structure_concern_thresholds),
" * %s", _("Trees"));
stats_table_size_addf(table, objects->inflated_sizes.blobs,
+ repo_structure_concern_level(
+ CONCERN_STAT_BLOB_INFLATED_SIZE,
-+ objects->inflated_sizes.blobs),
++ objects->inflated_sizes.blobs,
++ repo_structure_concern_thresholds),
" * %s", _("Blobs"));
stats_table_size_addf(table, objects->inflated_sizes.tags,
+ repo_structure_concern_level(
+ CONCERN_STAT_TAG_INFLATED_SIZE,
-+ objects->inflated_sizes.tags),
++ objects->inflated_sizes.tags,
++ repo_structure_concern_thresholds),
" * %s", _("Tags"));
disk_object_total = get_total_object_values(&objects->disk_sizes);
- stats_table_size_addf(table, disk_object_total,
-+ stats_table_size_addf(table, disk_object_total, 0,
++ stats_table_size_addf(table, disk_object_total, CONCERN_STAT_VALUE_NONE,
" * %s", _("Disk size"));
stats_table_size_addf(table, objects->disk_sizes.commits,
+ repo_structure_concern_level(
+ CONCERN_STAT_COMMIT_SIZE,
-+ objects->disk_sizes.commits),
++ objects->disk_sizes.commits,
++ repo_structure_concern_thresholds),
" * %s", _("Commits"));
stats_table_size_addf(table, objects->disk_sizes.trees,
+ repo_structure_concern_level(
+ CONCERN_STAT_TREE_SIZE,
-+ objects->disk_sizes.trees),
++ objects->disk_sizes.trees,
++ repo_structure_concern_thresholds),
" * %s", _("Trees"));
stats_table_size_addf(table, objects->disk_sizes.blobs,
+ repo_structure_concern_level(
+ CONCERN_STAT_BLOB_SIZE,
-+ objects->disk_sizes.blobs),
++ objects->disk_sizes.blobs,
++ repo_structure_concern_thresholds),
" * %s", _("Blobs"));
stats_table_size_addf(table, objects->disk_sizes.tags,
+ repo_structure_concern_level(
+ CONCERN_STAT_TAG_SIZE,
-+ objects->disk_sizes.tags),
++ objects->disk_sizes.tags,
++ repo_structure_concern_thresholds),
" * %s", _("Tags"));
stats_table_addf(table, "");
@@ builtin/repo.c: static void stats_table_setup_structure(struct stats_table *tabl
objects->largest.commit_size.value,
+ repo_structure_concern_level(
+ CONCERN_STAT_COMMIT_LARGEST,
-+ objects->largest.commit_size.value),
++ objects->largest.commit_size.value,
++ repo_structure_concern_thresholds),
" * %s", _("Maximum size"));
stats_table_object_count_addf(table,
&objects->largest.parent_count.oid,
objects->largest.parent_count.value,
-+ 0,
++ CONCERN_STAT_VALUE_NONE,
" * %s", _("Maximum parents"));
stats_table_addf(table, " * %s", _("Trees"));
stats_table_object_size_addf(table,
&objects->largest.tree_size.oid,
objects->largest.tree_size.value,
-+ repo_structure_concern_level(
-+ CONCERN_STAT_TREE_LARGEST,
-+ objects->largest.tree_size.value),
++ repo_structure_concern_level(
++ CONCERN_STAT_TREE_LARGEST,
++ objects->largest.commit_size.value,
++ repo_structure_concern_thresholds),
" * %s", _("Maximum size"));
++
stats_table_object_count_addf(table,
- &objects->largest.tree_entries.oid,
- objects->largest.tree_entries.value,
-+ 0,
- " * %s", _("Maximum entries"));
+- &objects->largest.tree_entries.oid,
+- objects->largest.tree_entries.value,
+- " * %s", _("Maximum entries"));
++ &objects->largest.tree_entries.oid,
++ objects->largest.tree_entries.value,
++ CONCERN_STAT_VALUE_NONE,
++ " * %s", _("Maximum entries"));
stats_table_addf(table, " * %s", _("Blobs"));
stats_table_object_size_addf(table,
&objects->largest.blob_size.oid,
objects->largest.blob_size.value,
+ repo_structure_concern_level(
+ CONCERN_STAT_BLOB_LARGEST,
-+ objects->largest.blob_size.value),
++ objects->largest.blob_size.value,
++ repo_structure_concern_thresholds),
" * %s", _("Maximum size"));
stats_table_addf(table, " * %s", _("Tags"));
stats_table_object_size_addf(table,
@@ builtin/repo.c: static void stats_table_setup_structure(struct stats_table *tabl
objects->largest.tag_size.value,
+ repo_structure_concern_level(
+ CONCERN_STAT_TAG_LARGEST,
-+ objects->largest.tag_size.value),
++ objects->largest.tag_size.value,
++ repo_structure_concern_thresholds),
" * %s", _("Maximum size"));
}
@@ builtin/repo.c: static void structure_keyvalue_print(struct repo_structure *stat
stats->objects.type_counts.commits, value_delim);
+ if (show_concern)
+ print_keyvalue("objects.commits.count.concern_level", key_delim,
-+ repo_structure_concern_level(CONCERN_STAT_COMMIT_COUNT,
-+ stats->objects.type_counts.commits),
-+ value_delim);
++ repo_structure_concern_level(
++ CONCERN_STAT_COMMIT_COUNT,
++ stats->objects.type_counts.commits,
++ repo_structure_concern_thresholds),
++ value_delim);
print_keyvalue("objects.trees.count", key_delim,
stats->objects.type_counts.trees, value_delim);
+ if (show_concern)
+ print_keyvalue("objects.trees.count.concern_level", key_delim,
-+ repo_structure_concern_level(CONCERN_STAT_TREE_COUNT,
-+ stats->objects.type_counts.trees),
-+ value_delim);
++ repo_structure_concern_level(
++ CONCERN_STAT_TREE_COUNT,
++ stats->objects.type_counts.trees,
++ repo_structure_concern_thresholds),
++ value_delim);
print_keyvalue("objects.blobs.count", key_delim,
stats->objects.type_counts.blobs, value_delim);
+ if (show_concern)
+ print_keyvalue("objects.blobs.count.concern_level", key_delim,
-+ repo_structure_concern_level(CONCERN_STAT_BLOB_COUNT,
-+ stats->objects.type_counts.blobs),
-+ value_delim);
++ repo_structure_concern_level(
++ CONCERN_STAT_BLOB_COUNT,
++ stats->objects.type_counts.blobs,
++ repo_structure_concern_thresholds),
++ value_delim);
print_keyvalue("objects.tags.count", key_delim,
- stats->objects.type_counts.tags, value_delim);
+- stats->objects.type_counts.tags, value_delim);
++ stats->objects.type_counts.tags, value_delim);
+ if (show_concern)
+ print_keyvalue("objects.tags.count.concern_level", key_delim,
-+ repo_structure_concern_level(CONCERN_STAT_TAG_COUNT,
-+ stats->objects.type_counts.tags),
-+ value_delim);
++ repo_structure_concern_level(
++ CONCERN_STAT_TAG_COUNT,
++ stats->objects.type_counts.tags,
++ repo_structure_concern_thresholds),
++ value_delim);
print_keyvalue("objects.commits.inflated_size", key_delim,
- stats->objects.inflated_sizes.commits, value_delim);
+- stats->objects.inflated_sizes.commits, value_delim);
++ stats->objects.inflated_sizes.commits, value_delim);
+ if (show_concern)
+ print_keyvalue("objects.commits.inflated_size.concern_level", key_delim,
-+ repo_structure_concern_level(CONCERN_STAT_COMMIT_INFLATED_SIZE,
-+ stats->objects.inflated_sizes.commits),
-+ value_delim);
++ repo_structure_concern_level(
++ CONCERN_STAT_COMMIT_INFLATED_SIZE,
++ stats->objects.inflated_sizes.commits,
++ repo_structure_concern_thresholds),
++ value_delim);
print_keyvalue("objects.trees.inflated_size", key_delim,
- stats->objects.inflated_sizes.trees, value_delim);
+- stats->objects.inflated_sizes.trees, value_delim);
++ stats->objects.inflated_sizes.trees, value_delim);
+ if (show_concern)
+ print_keyvalue("objects.trees.inflated_size.concern_level", key_delim,
-+ repo_structure_concern_level(CONCERN_STAT_TREE_INFLATED_SIZE,
-+ stats->objects.inflated_sizes.trees),
-+ value_delim);
++ repo_structure_concern_level(
++ CONCERN_STAT_TREE_INFLATED_SIZE,
++ stats->objects.inflated_sizes.trees,
++ repo_structure_concern_thresholds),
++ value_delim);
+
print_keyvalue("objects.blobs.inflated_size", key_delim,
stats->objects.inflated_sizes.blobs, value_delim);
+ if (show_concern)
+ print_keyvalue("objects.blobs.inflated_size.concern_level", key_delim,
-+ repo_structure_concern_level(CONCERN_STAT_BLOB_INFLATED_SIZE,
-+ stats->objects.inflated_sizes.blobs),
-+ value_delim);
++ repo_structure_concern_level(
++ CONCERN_STAT_BLOB_INFLATED_SIZE,
++ stats->objects.inflated_sizes.blobs,
++ repo_structure_concern_thresholds),
++ value_delim);
print_keyvalue("objects.tags.inflated_size", key_delim,
stats->objects.inflated_sizes.tags, value_delim);
+ if (show_concern)
+ print_keyvalue("objects.tags.inflated_size.concern_level", key_delim,
-+ repo_structure_concern_level(CONCERN_STAT_TAG_INFLATED_SIZE,
-+ stats->objects.inflated_sizes.tags),
-+ value_delim);
++ repo_structure_concern_level(
++ CONCERN_STAT_TAG_INFLATED_SIZE,
++ stats->objects.inflated_sizes.tags,
++ repo_structure_concern_thresholds),
++ value_delim);
print_keyvalue("objects.commits.disk_size", key_delim,
stats->objects.disk_sizes.commits, value_delim);
+ if (show_concern)
+ print_keyvalue("objects.commits.disk_size.concern_level", key_delim,
-+ repo_structure_concern_level(CONCERN_STAT_COMMIT_SIZE,
-+ stats->objects.disk_sizes.commits),
-+ value_delim);
++ repo_structure_concern_level(
++ CONCERN_STAT_COMMIT_SIZE,
++ stats->objects.disk_sizes.commits,
++ repo_structure_concern_thresholds),
++ value_delim);
print_keyvalue("objects.trees.disk_size", key_delim,
stats->objects.disk_sizes.trees, value_delim);
+ if (show_concern)
+ print_keyvalue("objects.trees.disk_size.concern_level", key_delim,
-+ repo_structure_concern_level(CONCERN_STAT_TREE_SIZE,
-+ stats->objects.disk_sizes.trees),
-+ value_delim);
++ repo_structure_concern_level(
++ CONCERN_STAT_TREE_SIZE,
++ stats->objects.disk_sizes.trees,
++ repo_structure_concern_thresholds),
++ value_delim);
print_keyvalue("objects.blobs.disk_size", key_delim,
stats->objects.disk_sizes.blobs, value_delim);
+ if (show_concern)
-+ print_keyvalue("objects.blobs.blob_size.concern_level", key_delim,
-+ repo_structure_concern_level(CONCERN_STAT_BLOB_SIZE,
-+ stats->objects.disk_sizes.blobs),
++
++ print_keyvalue("objects.blobs.disk_size.concern_level", key_delim,
++ repo_structure_concern_level(
++ CONCERN_STAT_BLOB_SIZE,
++ stats->objects.disk_sizes.blobs,
++ repo_structure_concern_thresholds),
+ value_delim);
print_keyvalue("objects.tags.disk_size", key_delim,
stats->objects.disk_sizes.tags, value_delim);
+ if (show_concern)
+ print_keyvalue("objects.tags.disk_size.concern_level", key_delim,
-+ repo_structure_concern_level(CONCERN_STAT_TAG_SIZE,
-+ stats->objects.disk_sizes.tags),
++ repo_structure_concern_level(
++ CONCERN_STAT_TAG_SIZE,
++ stats->objects.disk_sizes.tags,
++ repo_structure_concern_thresholds),
+ value_delim);
print_object_data("objects.commits.max_size", key_delim,
&stats->objects.largest.commit_size, value_delim);
+ if (show_concern)
+ print_keyvalue("objects.commits.max_size.concern_level", key_delim,
-+ repo_structure_concern_level(CONCERN_STAT_COMMIT_LARGEST,
-+ stats->objects.largest.commit_size.value),
-+ value_delim);
++ repo_structure_concern_level(
++ CONCERN_STAT_COMMIT_LARGEST,
++ stats->objects.largest.commit_size.value,
++ repo_structure_concern_thresholds),
++ value_delim);
print_object_data("objects.trees.max_size", key_delim,
&stats->objects.largest.tree_size, value_delim);
+ if (show_concern)
+ print_keyvalue("objects.trees.max_size.concern_level", key_delim,
-+ repo_structure_concern_level(CONCERN_STAT_TREE_LARGEST,
-+ stats->objects.largest.tree_size.value),
-+ value_delim);
++ repo_structure_concern_level(
++ CONCERN_STAT_TREE_LARGEST,
++ stats->objects.largest.tree_size.value,
++ repo_structure_concern_thresholds),
++ value_delim);
print_object_data("objects.blobs.max_size", key_delim,
&stats->objects.largest.blob_size, value_delim);
+ if (show_concern)
+ print_keyvalue("objects.blobs.max_size.concern_level", key_delim,
-+ repo_structure_concern_level(CONCERN_STAT_BLOB_LARGEST,
-+ stats->objects.largest.blob_size.value),
-+ value_delim);
++ repo_structure_concern_level(
++ CONCERN_STAT_BLOB_LARGEST,
++ stats->objects.largest.blob_size.value,
++ repo_structure_concern_thresholds),
++ value_delim);
print_object_data("objects.tags.max_size", key_delim,
- &stats->objects.largest.tag_size, value_delim);
+- &stats->objects.largest.tag_size, value_delim);
++ &stats->objects.largest.tag_size, value_delim);
+ if (show_concern)
+ print_keyvalue("objects.tags.max_size.concern_level", key_delim,
-+ repo_structure_concern_level(CONCERN_STAT_TAG_LARGEST,
-+ stats->objects.largest.tag_size.value),
-+ value_delim);
++ repo_structure_concern_level(
++ CONCERN_STAT_TAG_LARGEST,
++ stats->objects.largest.tag_size.value,
++ repo_structure_concern_thresholds),
++ value_delim);
print_object_data("objects.commits.max_parents", key_delim,
&stats->objects.largest.parent_count, value_delim);
@@ builtin/repo.c: static int cmd_repo_structure(int argc, const char **argv, const
OPT_END()
};
+ argc = parse_options(argc, argv, prefix, options, repo_structure_usage, 0);
+ if (argc)
+ usage(_("too many arguments"));
+-
+ repo_init_revisions(repo, &revs, prefix);
+
+ if (show_progress < 0)
@@ builtin/repo.c: static int cmd_repo_structure(int argc, const char **argv, const char *prefix,
switch (format) {
case FORMAT_TABLE:
@@ builtin/repo.c: static int cmd_repo_structure(int argc, const char **argv, const
default:
BUG("invalid output format");
- ## sideband.c ##
+ ## repo.c (new) ##
@@
--#define USE_THE_REPOSITORY_VARIABLE
-+define USE_THE_REPOSITORY_VARIABLE
- #define DISABLE_SIGN_COMPARE_WARNINGS
-
- #include "git-compat-util.h"
++#include "repo.h"
## t/t1901-repo-structure.sh ##
@@ t/t1901-repo-structure.sh: test_expect_success 'empty repository' '
EOF
git repo structure >out 2>err &&
--
-- test_cmp expect out &&
-- test_line_count = 0 err
-- )
--'
--
--test_expect_success SHA1 'repository with references and objects' '
-- test_when_finished "rm -rf repo" &&
-- git init repo &&
-- (
-- cd repo &&
-- test_commit_bulk 1005 &&
-- 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 &&
--
-- # The tags disk size is handled specially due to the
-- # git-rev-list(1) --disk-usage=human option printing the full
-- # "byte/bytes" unit string instead of just "B".
-- cat >expect <<-EOF &&
-- | Repository structure | Value |
-- | ------------------------- | ---------- |
-- | * References | |
-- | * Count | 4 |
-- | * Branches | 1 |
-- | * Tags | 1 |
-- | * Remotes | 1 |
-- | * Others | 1 |
-- | | |
-- | * Reachable objects | |
-- | * Count | 3.02 k |
-- | * Commits | 1.01 k |
-- | * Trees | 1.01 k |
-- | * Blobs | 1.01 k |
-- | * Tags | 1 |
-- | * Inflated size | 16.03 MiB |
-- | * Commits | 217.92 KiB |
-- | * Trees | 15.81 MiB |
-- | * Blobs | 11.68 KiB |
-- | * Tags | 132 B |
-- | * Disk size | $(object_type_disk_usage all true) |
-- | * Commits | $(object_type_disk_usage commit true) |
-- | * 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 [1] | 223 B |
-- | * Maximum parents [2] | 1 |
-- | * Trees | |
-- | * Maximum size [3] | 32.29 KiB |
-- | * Maximum entries [4] | 1.01 k |
-- | * Blobs | |
-- | * Maximum size [5] | 13 B |
-- | * Tags | |
-- | * Maximum size [6] | 132 B |
--
-- [1] 0dc91eb18580102a3a216c8bfecedeba2b9f9b9a
-- [2] 0dc91eb18580102a3a216c8bfecedeba2b9f9b9a
-- [3] 60665251ab71dbd8c18d9bf2174f4ee0d58aa06c
-- [4] 60665251ab71dbd8c18d9bf2174f4ee0d58aa06c
-- [5] 97d808e45116bf02103490294d3d46dad7a2ac62
-- [6] 4dae4f5954f5e6feb3577cfb1b181daa3fd3afd2
-- EOF
--
-- git repo structure >out 2>err &&
+ cp out /tmp/test1-out &&
test_cmp expect out &&
test_line_count = 0 err
-@@ t/t1901-repo-structure.sh: test_expect_success SHA1 'lines and nul format' '
- )
- '
-
-+test_expect_success SHA1 'lines format with concerns' '
-+ test_when_finished "rm -rf repo" &&
-+ git init repo &&
-+ (
-+ cd repo &&
-+ # configure thresholds to get concern indications
-+ git config repo.structure.concern.commit-count 7 &&
-+ git config repo.structure.concern.commit-size 14 &&
-+ git config repo.structure.concern.tree-size 10 &&
-+ git config repo.structure.concern.blob-size 8 &&
-+ git config repo.structure.concern.blob-inflated-size 10 &&
-+ git config repo.structure.concern.tag-size 2 &&
-+ git config repo.structure.concern.commit-largest 4 &&
-+ git config repo.structure.concern.blob-largest 2 &&
-+ touch configured &&
-+ test_commit_bulk 1005 &&
-+ 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 &&
-+
-+
-+ # The tags disk size is handled specially due to the
-+ # git-rev-list(1) --disk-usage=human option printing the full
-+ # "byte/bytes" unit string instead of just "B".
-+ cat >expect <<-EOF &&
-+ objects.commits.count.concern_level=2
-+ objects.trees.count.concern_level=0
-+ objects.blobs.count.concern_level=0
-+ objects.tags.count.concern_level=0
-+ objects.commits.inflated_size.concern_level=0
-+ objects.trees.inflated_size.concern_level=0
-+ objects.blobs.inflated_size.concern_level=3
-+ objects.tags.inflated_size.concern_level=0
-+ objects.commits.disk_size.concern_level=3
-+ objects.trees.disk_size.concern_level=8
-+ objects.blobs.blob_size.concern_level=6
-+ objects.tags.disk_size.concern_level=4
-+ objects.commits.max_size.concern_level=3
-+ objects.trees.max_size.concern_level=0
-+ objects.blobs.max_size.concern_level=1
-+ objects.tags.max_size.concern_level=0
-+ EOF
-+
-+ git repo structure --concern --format=lines >actual 2>err &&
-+ test_grep "concern_level" actual >actual-concerns &&
-+ test_cmp expect actual-concerns &&
-+ test_line_count = 0 err
-+ )
-+'
-+
- test_expect_success 'progress meter option' '
- test_when_finished "rm -rf repo" &&
- git init repo &&
2: 56fb5590ea ! 2: f0e25fae09 repo: make concern thresholds configurable
@@ Commit message
configure per-repo concern levels for "git repo structure"
concern reporting.
+ Signed-off-by: Mark C. Chu-Carroll <markchucarroll@fastmail.com>
+
## Documentation/config/repo.adoc (new) ##
@@
+`repo.concern.commit-count`::
@@ builtin/repo.c
static const char *const repo_usage[] = {
REPO_INFO_USAGE,
REPO_STRUCTURE_USAGE,
-@@ builtin/repo.c: enum concern_stat {
- CONCERN_STAT_TREE_INFLATED_SIZE,
- CONCERN_STAT_BLOB_INFLATED_SIZE,
- CONCERN_STAT_TAG_INFLATED_SIZE,
-+ CONCERN_STAT_MAXIMUM
- };
-
--struct concern_stat_threshold repo_structure_concern_thresholds[] = {
-- { .name = "commit_count", .threshold = 19 },
-- {.name = "tree_count", .threshold = 21 },
-- { .name = "blob_count", .threshold = 22 },
-- { .name = "tag_count", .threshold = 15 },
-- { .name = "commit_size", .threshold = 28 },
-- { .name = "tree_size", .threshold = 27 },
-- { .name = "blob_size", .threshold = 36 },
-- { .name = "tags_size", .threshold = 18 },
-- { .name = "commit_largest", .threshold = 18 },
-- { .name = "tree_largest", .threshold = 18 },
-- { .name = "blob_largest", .threshold = 26 },
-- { .name = "tag_largest", .threshold = 15 },
-- { .name = "commit_inflated_size", .threshold = 28 },
-- { .name = "tree_inflated_size", .threshold = 32 },
-- { .name = "blob_inflated_size", .threshold = 34 },
-- { .name = "tag_inflated_size", .threshold = 25}
-+struct concern_stat_threshold concern_stat_thresholds[] = {
-+ { .name = "commit-count", .threshold = 19 },
-+ { .name = "tree-count", .threshold = 21 },
-+ { .name = "blob-count", .threshold = 22 },
-+ { .name = "tag-count", .threshold = 15 },
-+ { .name = "commit-size", .threshold = 28 },
-+ { .name = "tree-size", .threshold = 27 },
-+ { .name = "blob-size", .threshold = 36 },
-+ { .name = "tag-size", .threshold = 18 },
-+ { .name = "commit-largest", .threshold = 18 },
-+ { .name = "tree-largest", .threshold = 18 },
-+ { .name = "blob-largest", .threshold = 26 },
-+ { .name = "tag-largest", .threshold = 15 },
-+ { .name = "commit-inflated-size", .threshold = 28 },
-+ { .name = "tree-inflated-size", .threshold = 32 },
-+ { .name = "blob-inflated-size", .threshold = 34 },
-+ { .name = "tag-inflated-size", .threshold = 25},
-+ { 0 }
- };
-
- /*
- * Concern thresholds aren't universal. We try to set reasonable default
- * values, but projects may want to set these thresholds differently. To
- * support that, they can set the thresholds for their project in the
-- * project's git config, in the section "repo.structure.concern".
-+ * project's git config, in the section "repo.concern".
- */
- static int config_concern_thresholds(const char *prefixed_var,
- const char *str_val,
- const struct config_context *ctx,
- void *cb UNUSED) {
-- const char *config_prefix = "repo.structure.concern.";
-- if (!strncmp(config_prefix, prefixed_var, strlen(config_prefix))) {
-- const char *concern_name = &prefixed_var[strlen(config_prefix)];
-+ if (!strncmp(REPO_STRUCTURE_CONFIG_PREFIX, prefixed_var,
-+ strlen(REPO_STRUCTURE_CONFIG_PREFIX))) {
-+ const char *concern_name =
-+ &prefixed_var[strlen(REPO_STRUCTURE_CONFIG_PREFIX)];
- for (int i = 0; concern_stat_thresholds[i].name != 0; i++) {
- if (!strcmp(concern_stat_thresholds[i].name, concern_name)) {
- int value = git_config_int(prefixed_var, str_val, ctx->kvi);
-@@ builtin/repo.c: static int config_concern_thresholds(const char *prefixed_var,
- return 0;
+@@ builtin/repo.c: static size_t repo_structure_concern_level(const char* concern_name,
+ return 0;
}
--static size_t approx_log2(long value) {
-+static size_t approx_log2(size_t value) {
- int position = 0;
- if (value <= 0) {
- return 0;
-@@ builtin/repo.c: static size_t approx_log2(long value) {
- static size_t repo_structure_concern_level(enum concern_stat stat_id,
- size_t value) {
- size_t log_value;
-- if (stat_id >= ARRAY_SIZE(concern_stat_thresholds))
-+ if (stat_id >= CONCERN_STAT_MAXIMUM)
- BUG("unexpected repository stat type");
- log_value = approx_log2(value);
- if (log_value > concern_stat_thresholds[stat_id].threshold)
++/*
++ * Concern thresholds aren't universal. We try to set reasonable default
++ * values, but projects may want to set these thresholds differently. To
++ * support that, they can set the thresholds for their project in the
++ * project's git config, in the section "repo.structure.concern".
++ */
++static int config_concern_thresholds(const char *prefixed_var,
++ const char *str_val,
++ const struct config_context *ctx,
++ void *cb)
++{
++ struct concern_stat_threshold *thresholds = cb;
++ if (starts_with(prefixed_var, REPO_STRUCTURE_CONFIG_PREFIX)) {
++ const char *concern_name = &prefixed_var[strlen(REPO_STRUCTURE_CONFIG_PREFIX)];
++ for (int i = 0; thresholds[i].name; i++) {
++ if (!strcmp(thresholds[i].name, concern_name)) {
++ int value = git_config_int(prefixed_var, str_val, ctx->kvi);
++ if (value < 0)
++ return -1;
++ thresholds[i].threshold = value;
++ return 0;
++ }
++ }
++ warning(_("Invalid concern threshold name: '%s'"), concern_name);
++ return 0;
++ }
++ return 0;
++}
++
+ /*
+ * Holds column data that gets stored for each row.
+ */
@@ builtin/repo.c: static void stats_table_print_structure(const struct stats_table *table,
strbuf_utf8_align(&buf, ALIGN_LEFT, concern_col_width, concern_str.buf);
strbuf_addstr(&buf, " |");
@@ builtin/repo.c: static void stats_table_print_structure(const struct stats_table
}
@@ builtin/repo.c: static void structure_keyvalue_print(struct repo_structure *stats,
- print_keyvalue("objects.blobs.disk_size", key_delim,
- stats->objects.disk_sizes.blobs, value_delim);
- if (show_concern)
-- print_keyvalue("objects.blobs.blob_size.concern_level", key_delim,
-+ print_keyvalue("objects.blobs.disk_size.concern_level", key_delim,
- repo_structure_concern_level(CONCERN_STAT_BLOB_SIZE,
- stats->objects.disk_sizes.blobs),
- value_delim);
-@@ builtin/repo.c: static void structure_keyvalue_print(struct repo_structure *stats,
- stats->objects.largest.commit_size.value),
- value_delim);
- print_object_data("objects.trees.max_size", key_delim,
-- &stats->objects.largest.tree_size, value_delim);
-+ &stats->objects.largest.tree_size, value_delim);
- if (show_concern)
- print_keyvalue("objects.trees.max_size.concern_level", key_delim,
- repo_structure_concern_level(CONCERN_STAT_TREE_LARGEST,
-@@ builtin/repo.c: static void structure_keyvalue_print(struct repo_structure *stats,
- stats->objects.largest.blob_size.value),
- value_delim);
- print_object_data("objects.tags.max_size", key_delim,
-- &stats->objects.largest.tag_size, value_delim);
-+ &stats->objects.largest.tag_size, value_delim);
- if (show_concern)
- print_keyvalue("objects.tags.max_size.concern_level", key_delim,
- repo_structure_concern_level(CONCERN_STAT_TAG_LARGEST,
+ stats->objects.largest.tag_size.value,
+ repo_structure_concern_thresholds),
+ value_delim);
+-
+ print_object_data("objects.commits.max_parents", key_delim,
+ &stats->objects.largest.parent_count, value_delim);
+ print_object_data("objects.trees.max_entries", key_delim,
@@ builtin/repo.c: static int cmd_repo_structure(int argc, const char **argv, const char *prefix,
- argc = parse_options(argc, argv, prefix, options, repo_structure_usage, 0);
- if (argc)
usage(_("too many arguments"));
--
-+ if (show_concern)
-+ repo_config(repo, &config_concern_thresholds, NULL);
repo_init_revisions(repo, &revs, prefix);
++ if (show_concern)
++ repo_config(repo, &config_concern_thresholds, &repo_structure_concern_thresholds);
++
++
if (show_progress < 0)
-
- ## sideband.c ##
-@@
--define USE_THE_REPOSITORY_VARIABLE
-+#define USE_THE_REPOSITORY_VARIABLE
- #define DISABLE_SIGN_COMPARE_WARNINGS
+ show_progress = isatty(2);
- #include "git-compat-util.h"
## t/t1901-repo-structure.sh ##
@@ t/t1901-repo-structure.sh: test_expect_success 'empty repository' '
@@ t/t1901-repo-structure.sh: test_expect_success 'empty repository' '
test_cmp expect out &&
test_line_count = 0 err
+@@ t/t1901-repo-structure.sh: test_expect_success SHA1 'repository with references and objects' '
)
'
-+test_expect_success SHA1 'repository with references and objects' '
-+ test_when_finished "rm -rf repo" &&
-+ git init repo &&
-+ (
-+ cd repo &&
-+ test_commit_bulk 1005 &&
-+ 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 &&
-+
-+ # The tags disk size is handled specially due to the
-+ # git-rev-list(1) --disk-usage=human option printing the full
-+ # "byte/bytes" unit string instead of just "B".
-+ cat >expect <<-EOF &&
-+ | Repository structure | Value |
-+ | ------------------------- | ---------- |
-+ | * References | |
-+ | * Count | 4 |
-+ | * Branches | 1 |
-+ | * Tags | 1 |
-+ | * Remotes | 1 |
-+ | * Others | 1 |
-+ | | |
-+ | * Reachable objects | |
-+ | * Count | 3.02 k |
-+ | * Commits | 1.01 k |
-+ | * Trees | 1.01 k |
-+ | * Blobs | 1.01 k |
-+ | * Tags | 1 |
-+ | * Inflated size | 16.03 MiB |
-+ | * Commits | 217.92 KiB |
-+ | * Trees | 15.81 MiB |
-+ | * Blobs | 11.68 KiB |
-+ | * Tags | 132 B |
-+ | * Disk size | $(object_type_disk_usage all true) |
-+ | * Commits | $(object_type_disk_usage commit true) |
-+ | * 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 [1] | 223 B |
-+ | * Maximum parents [2] | 1 |
-+ | * Trees | |
-+ | * Maximum size [3] | 32.29 KiB |
-+ | * Maximum entries [4] | 1.01 k |
-+ | * Blobs | |
-+ | * Maximum size [5] | 13 B |
-+ | * Tags | |
-+ | * Maximum size [6] | 132 B |
-+
-+ [1] 0dc91eb18580102a3a216c8bfecedeba2b9f9b9a
-+ [2] 0dc91eb18580102a3a216c8bfecedeba2b9f9b9a
-+ [3] 60665251ab71dbd8c18d9bf2174f4ee0d58aa06c
-+ [4] 60665251ab71dbd8c18d9bf2174f4ee0d58aa06c
-+ [5] 97d808e45116bf02103490294d3d46dad7a2ac62
-+ [6] 4dae4f5954f5e6feb3577cfb1b181daa3fd3afd2
-+ EOF
-+
-+ git repo structure >out 2>err &&
-+
-+ test_cmp expect out &&
-+ test_line_count = 0 err
-+ )
-+'
-+
+test_expect_success SHA1 'concern flagging' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
@@ t/t1901-repo-structure.sh: test_expect_success 'empty repository' '
test_expect_success SHA1 'lines and nul format' '
test_when_finished "rm -rf repo" &&
git init repo &&
-@@ t/t1901-repo-structure.sh: test_expect_success SHA1 'lines format with concerns' '
- git init repo &&
- (
- cd repo &&
-+ # differences between zlib and zlib-ng can cause this
-+ # test to fail; so we just turn it off.
+@@ t/t1901-repo-structure.sh: test_expect_success SHA1 'lines and nul format' '
+ )
+ '
+
++test_expect_success SHA1 'lines format with concerns' '
++ test_when_finished "rm -rf repo" &&
++ git init repo &&
++ (
++ cd repo &&
++ # configure thresholds to get concern indications
+ git config core.compression 0 &&
- # configure thresholds to get concern indications
-- git config repo.structure.concern.commit-count 7 &&
-- git config repo.structure.concern.commit-size 14 &&
-- git config repo.structure.concern.tree-size 10 &&
-- git config repo.structure.concern.blob-size 8 &&
-- git config repo.structure.concern.blob-inflated-size 10 &&
-- git config repo.structure.concern.tag-size 2 &&
-- git config repo.structure.concern.commit-largest 4 &&
-- git config repo.structure.concern.blob-largest 2 &&
-- touch configured &&
+ git config repo.concern.commit-count 7 &&
+ git config repo.concern.commit-size 14 &&
+ git config repo.concern.tree-size 10 &&
@@ t/t1901-repo-structure.sh: test_expect_success SHA1 'lines format with concerns'
+ git config repo.concern.tag-size 2 &&
+ git config repo.concern.commit-largest 4 &&
+ git config repo.concern.blob-largest 2 &&
- test_commit_bulk 1005 &&
- git tag -a foo -m bar &&
- oid="$(git rev-parse HEAD)" &&
-@@ t/t1901-repo-structure.sh: test_expect_success SHA1 'lines format with concerns' '
- # Also creates a commit, tree, and blob.
- git notes add -m foo &&
-
--
- # The tags disk size is handled specially due to the
- # git-rev-list(1) --disk-usage=human option printing the full
- # "byte/bytes" unit string instead of just "B".
-@@ t/t1901-repo-structure.sh: test_expect_success SHA1 'lines format with concerns' '
- objects.tags.inflated_size.concern_level=0
- objects.commits.disk_size.concern_level=3
- objects.trees.disk_size.concern_level=8
-- objects.blobs.blob_size.concern_level=6
-- objects.tags.disk_size.concern_level=4
++ touch configured &&
++ test_commit_bulk 1005 &&
++ 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 &&
++
++
++ # The tags disk size is handled specially due to the
++ # git-rev-list(1) --disk-usage=human option printing the full
++ # "byte/bytes" unit string instead of just "B".
++ cat >expect <<-EOF &&
++ objects.commits.count.concern_level=2
++ objects.trees.count.concern_level=0
++ objects.blobs.count.concern_level=0
++ objects.tags.count.concern_level=0
++ objects.commits.inflated_size.concern_level=0
++ objects.trees.inflated_size.concern_level=0
++ objects.blobs.inflated_size.concern_level=3
++ objects.tags.inflated_size.concern_level=0
++ objects.commits.disk_size.concern_level=3
++ objects.trees.disk_size.concern_level=8
+ objects.blobs.disk_size.concern_level=6
+ objects.tags.disk_size.concern_level=5
- objects.commits.max_size.concern_level=3
- objects.trees.max_size.concern_level=0
- objects.blobs.max_size.concern_level=1
++ objects.commits.max_size.concern_level=3
++ objects.trees.max_size.concern_level=0
++ objects.blobs.max_size.concern_level=1
++ objects.tags.max_size.concern_level=0
++ EOF
++
++ git repo structure --concern --format=lines >actual 2>err &&
++ test_grep "concern_level" actual >actual-concerns &&
++ test_cmp expect actual-concerns &&
++ test_line_count = 0 err
++ )
++'
++
+ test_expect_success 'progress meter option' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&--- base-commit: 3bc0341126508f78f5869cbfc0005e987efdf0c7 change-id: 20261019-b4-repo-structure-concern-f1d6f6326095