[PATCH v3 2/2] repo: make concern thresholds configurable
flat view
HOTtoday
From: Mark C. Chu-Carroll <hidden>
Date: 2026-10-27 15:39:46
Subsystem:
documentation, the rest · Maintainers:
Jonathan Corbet, Linus Torvalds
Revision v3 (3 revisions archived).
Revisions (3)
- v1
- v2 [diff against previous]
- v3 current [diff against previous]
The concern reporting mechanism so far provides a measure of concern based on heuristic values estimated by analyzing a collection of (hopefully) representative repositories. But for different projects/usecases, the thresholds at which a value becomes concerning may vary. Provide a mechanism using git config to allow users to configure per-repo concern levels for "git repo structure" concern reporting. --- Documentation/config/repo.adoc | 59 ++++++++++++++ Documentation/git-repo.adoc | 11 +++ builtin/repo.c | 62 +++++++------- sideband.c | 2 +- t/t1901-repo-structure.sh | 180 ++++++++++++++++++++++++++++++++++++++--- 5 files changed, 273 insertions(+), 41 deletions(-)
diff --git a/Documentation/config/repo.adoc b/Documentation/config/repo.adoc
new file mode 100644
index 0000000000..811b099d72
--- /dev/null
+++ b/Documentation/config/repo.adoc@@ -0,0 +1,59 @@ +`repo.concern.commit-count`:: + Sets the value of the concern threshold for commit count. + +`repo.concern.tree-count`:: + Sets the value of the concern threshold for tree count. + +`repo.concern.blob-count`:: + Sets the value of the concern threshold for blob count. + +`repo.concern.tag-count`:: + Sets the value of the concern threshold for tag count. + +`repo.concern.commit-size`:: + Sets the value of the concern threshold for total commit size. + +`repo.concern.tree-size`:: + Sets the value of the concern threshold for total tree size. + +`repo.concern.blob-size`:: + Sets the value of the concern threshold for total blob size. + +`repo.concern.tag-size`:: + Sets the value of the concern threshold for total tag size. + +`repo.concern.commit-inflated-size`:: + Sets the value of the concern threshold for total size + of all inflated commits. + +`repo.concern.tree-inflated-size`:: + Sets the value of the concern threshold for total size of + all inflated trees. + +`repo.concern.blob-inflated-size`:: + Sets the value of the concern threshold for total size of + all inflated blobs. + +`repo.concern.tag-inflated-size`:: + Sets the value of the concern threshold for the total size + of all inflated tags. + +`repo.concern.commit-largest`:: + Sets the value of the concern threshold the size of the largest + commit. + +`repo.concern.tree-largest`:: + Sets the value of the concern threshold for the size of the + largest tree. + +`repo.concern.blob-largest`:: + Sets the value of the concern threshold for the size of the + largest blob. + +`repo.concern.tag-largest`:: + Sets the value of the concern threshold for the size of the + largest tag. + +All of the concern thresholds are integer values for the +floor of the base-2 log of the threshold value. The default values +of each threshold are set to heuristically determined values.
diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc
index f186b27d87..516403e17d 100644
--- a/Documentation/git-repo.adoc
+++ b/Documentation/git-repo.adoc@@ -101,6 +101,8 @@ statistic value. The value is considered concerning if it exceeds a heuristicall chosen threshold value; the degree of concern is the difference between the log_2 of the value, and the log_2 of the corresponding threshold. +The threshold values are configurable; see the configuration section below. + INFO KEYS --------- In order to obtain a set of values from `git repo info`, you should provide
@@ -153,6 +155,15 @@ using the `nul` format: git repo info --format=nul layout.bare layout.shallow ------------ +CONFIGURATION +------------- + +include::includes/cmd-config-section-all.adoc[] + +:git-repo: 1 +include::config/repo.adoc[] + + SEE ALSO -------- linkgit:git-rev-parse[1]
diff --git a/builtin/repo.c b/builtin/repo.c
index a450497d4e..ed579e6685 100644
--- a/builtin/repo.c
+++ b/builtin/repo.c@@ -2,6 +2,7 @@ #include "builtin.h" #include "commit.h" +#include "config.h" #include "environment.h" #include "hash.h" #include "hex.h"
@@ -29,6 +30,8 @@ #define REPO_STRUCTURE_USAGE \ "git repo structure [--format=(table|lines|nul) | -z] [--[no-]concern]" +#define REPO_STRUCTURE_CONFIG_PREFIX "repo.concern." + static const char *const repo_usage[] = { REPO_INFO_USAGE, REPO_STRUCTURE_USAGE,
@@ -386,40 +389,43 @@ 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);
@@ -435,7 +441,7 @@ static int config_concern_thresholds(const char *prefixed_var, 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;
@@ -450,7 +456,7 @@ 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)
@@ -844,6 +850,7 @@ 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, " |"); } + strbuf_release(&concern_str); printf("%s\n", buf.buf); }
@@ -977,7 +984,7 @@ 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);
@@ -997,7 +1004,7 @@ 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,
@@ -1011,7 +1018,7 @@ 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,
@@ -1243,7 +1250,8 @@ 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_progress < 0)
diff --git a/sideband.c b/sideband.c
index 0e75ab2317..374187402e 100644
--- a/sideband.c
+++ b/sideband.c@@ -1,4 +1,4 @@ -define USE_THE_REPOSITORY_VARIABLE +#define USE_THE_REPOSITORY_VARIABLE #define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h"
diff --git a/t/t1901-repo-structure.sh b/t/t1901-repo-structure.sh
index f1e3fd2a75..e8f1269ad4 100755
--- a/t/t1901-repo-structure.sh
+++ b/t/t1901-repo-structure.sh@@ -67,13 +67,166 @@ test_expect_success 'empty repository' ' EOF git repo structure >out 2>err && - cp out /tmp/test1-out && 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 && + + test_cmp expect out && + test_line_count = 0 err + ) +' + +test_expect_success SHA1 'concern flagging' ' + test_when_finished "rm -rf repo" && + git init repo && + ( + cd repo && + # differences between zlib and zlib-ng can cause this + # test to fail; so we just turn it off. + git config core.compression 0 && + # configure thresholds to get concern indications + git config repo.concern.commit-count 7 && + git config repo.concern.commit-size 14 && + git config repo.concern.tree-size 10 && + git config repo.concern.blob-size 8 && + git config repo.concern.blob-inflated-size 10 && + 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)" && + 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 | Concern | + | ------------------------- | ---------- | -------- | + | * 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 --concern >actual 2>err && + + test_cmp expect actual && + test_line_count = 0 err + ) +' + test_expect_success SHA1 'lines and nul format' ' test_when_finished "rm -rf repo" && git init repo &&
@@ -139,16 +292,18 @@ 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. + 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 && + git config repo.concern.blob-size 8 && + git config repo.concern.blob-inflated-size 10 && + 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)" &&
@@ -157,7 +312,6 @@ 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".
@@ -172,8 +326,8 @@ 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 + 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
--
2.53.0