Thread (20 messages) 20 messages, 3 authors, 2d ago

[PATCH v4 2/2] repo: make concern thresholds configurable

flat view
WARM2d

From: Mark C. Chu-Carroll <hidden>
Date: 2026-10-29 17:52:35
Subsystem: documentation, the rest · Maintainers: Jonathan Corbet, Linus Torvalds

Revision v4 (4 revisions archived).

Revisions (4)
  1. v1
  2. v2 [diff against previous]
  3. v3 [diff against previous]
  4. v4 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.

Signed-off-by: Mark C. Chu-Carroll <redacted>
---
 Documentation/config/repo.adoc |  59 ++++++++++++++++++
 Documentation/git-repo.adoc    |  11 ++++
 builtin/repo.c                 |  38 +++++++++++-
 t/t1901-repo-structure.sh      | 138 ++++++++++++++++++++++++++++++++++++++++-
 4 files changed, 244 insertions(+), 2 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 bd1866c5fa..4880c8b8f7 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"
@@ -30,6 +31,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,
@@ -430,6 +433,35 @@ static size_t repo_structure_concern_level(const char* concern_name,
 		return 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)
+{
+	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.
  */
@@ -835,6 +867,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);
 	}
 
@@ -1041,7 +1074,6 @@ static void structure_keyvalue_print(struct repo_structure *stats,
 				       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,
@@ -1269,6 +1301,10 @@ static int cmd_repo_structure(int argc, const char **argv, const char *prefix,
 		usage(_("too many arguments"));
 	repo_init_revisions(repo, &revs, prefix);
 
+	if (show_concern)
+                repo_config(repo, &config_concern_thresholds, &repo_structure_concern_thresholds);
+
+
 	if (show_progress < 0)
 		show_progress = isatty(2);
 
diff --git a/t/t1901-repo-structure.sh b/t/t1901-repo-structure.sh
index f92168025b..1db2cc5293 100755
--- a/t/t1901-repo-structure.sh
+++ b/t/t1901-repo-structure.sh
@@ -67,7 +67,6 @@ 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
@@ -145,6 +144,89 @@ test_expect_success SHA1 'repository with references and objects' '
 	)
 '
 
+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 &&
@@ -205,6 +287,60 @@ 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 &&
+		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 &&
+		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.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.53.0
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help