git/list[1] front-page[2] threads[3] people[4] search[5] about
 

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

From
MCMark C. Chu-Carroll <markchucarroll@fastmail.com>
Date
Nov 2, 2026, 16:32 UTC
Message-ID
<20261102-b4-repo-structure-concern-v5-2-2d8f37b70b75@fastmail.com>
In-Reply-To
<20261102-b4-repo-structure-concern-v5-0-2d8f37b70b75@fastmail.com>

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 <markchucarroll@fastmail.com>
---
 Documentation/config/repo.adoc |  63 +++++++++++++++++++
 Documentation/git-repo.adoc    |  11 ++++
 builtin/repo.c                 |  60 ++++++++++++++++++
 t/t1901-repo-structure.sh      | 137 +++++++++++++++++++++++++++++++++++++++++
 4 files changed, 271 insertions(+)
diff --git a/Documentation/config/repo.adoc b/Documentation/config/repo.adoc
new file mode 100644
index 0000000000..9692f8b71d
--- /dev/null
+++ b/Documentation/config/repo.adoc
@@ -0,0 +1,63 @@
+`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 for 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.
+
+Thresholds are actually computed using log values. But for human convenience,
+they're set as integer values. If the integer value supplied isn't a power of
+two, the actual value will be rounded to the nearest power of two. For example,
+if the value in the configuration setting is 80,000, the actual threshold will
+be set to 65536; if instead, the value from the configuration was set to
+100,000, the threshold will be set to 131,072.
+
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 7a50605779..5dfe813907 100644
--- a/builtin/repo.c
+++ b/builtin/repo.c
@@ -430,6 +430,8 @@ static int repo_structure_concern_level(const char *concern_name,
 		const int threshold = get_concern_threshold(concern_name, thresholds);
 		if (threshold < 0)
 			BUG("unexpected repository stat threshold: '%s'", concern_name);
+		if (!threshold)
+			return 0;
 		log_value = (size_t)log2u(value);
 		if (log_value > (size_t)threshold)
 			return log_value - threshold;
@@ -440,6 +442,60 @@ static int repo_structure_concern_level(const char *concern_name,
 	}
 }
 
+/*
+ * To make configuring thresholds as intuitive as possible, we set the
+ * internal threshold value to the _nearest_ power of two to the value
+ * the user specified. So if they set a threshold to 500, we should use
+ * a log value of 9, but log2u would return 8.
+ *
+ * A threshold value of 0 means "never flag concerns for this stat".
+ */
+static size_t nearest_log2_value(size_t v)
+{
+	size_t logval, power_of_two_floor, mid;
+	if (!v)
+		return 0;
+	logval = (size_t)log2u(v);
+	power_of_two_floor = (size_t)1 << logval;
+	mid = (power_of_two_floor + (power_of_two_floor << 1)) / 2;
+	return (v <= mid) ? logval : (logval + 1);
+}
+
+/*
+ * 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.concern".
+ *
+ * This is used by repo_config; the call site is guarded by show_concern,
+ * so the global threshold array is only modified when --concern is requested,
+ * and that will happen at most once.
+ */
+static int config_concern_thresholds(const char *config_val_name,
+				     const char *str_val,
+				     const struct config_context *ctx,
+				     void *cb)
+{
+	struct concern_stat_threshold *thresholds = cb;
+	const char *concern_name;
+	if (skip_prefix(config_val_name, REPO_STRUCTURE_CONFIG_PREFIX, &concern_name)) {
+		for (int i = 0; thresholds[i].name; i++) {
+			if (!strcmp(thresholds[i].name, concern_name)) {
+				int threshold = git_config_int(concern_name, str_val, ctx->kvi);
+				if (threshold < 0) {
+					warning(_("invalid concern threshold '%d': value must be 0 or more"),
+						threshold);
+					return 0;
+				}
+				thresholds[i].threshold = nearest_log2_value(threshold);
+				return 0;
+			}
+		}
+		warning(_("invalid concern threshold name: '%s'"), concern_name);
+	}
+	return 0;
+}
+
 /*
  * Holds column data that gets stored for each row.
  */
@@ -1300,6 +1356,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 9eafff0a36..b43b766e81 100755
--- a/t/t1901-repo-structure.sh
+++ b/t/t1901-repo-structure.sh
@@ -143,6 +143,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 120 &&
+		git config repo.concern.commit-size 16384 &&
+		git config repo.concern.tree-size 1024 &&
+		git config repo.concern.blob-size 256 &&
+		git config repo.concern.blob-inflated-size 1024 &&
+		git config repo.concern.tag-size 4 &&
+		git config repo.concern.commit-largest 16 &&
+		git config repo.concern.blob-largest 4 &&
+		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 &&
@@ -203,6 +286,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 100 &&
+		git config repo.concern.commit-size 16384 &&
+		git config repo.concern.tree-size 1024 &&
+		git config repo.concern.blob-size 256 &&
+		git config repo.concern.blob-inflated-size 1024 &&
+		git config repo.concern.tag-size 4 &&
+		git config repo.concern.commit-largest 16 &&
+		git config repo.concern.blob-largest 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.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
Previous: Mark C. Chu-Carroll
Message 23 of 23 in “repo: add degree-of-concern reporting to structure”
  1. 0/3 repo: add degree-of-concern reporting to structureMark C. Chu-Carroll, Oct 21, 2026
  2. 1/3 repo: add level of concern reportingMark C. Chu-Carroll, Oct 21, 2026
  3. 2/3 repo: make concern thresholds configurableMark C. Chu-Carroll, Oct 21, 2026
  4. 3/3 repo: add documentation for level-of-concern.Mark C. Chu-Carroll, Oct 21, 2026
  5. 0/3 repo: add degree-of-concern reporting to structureMark C. Chu-Carroll, Oct 26, 2026
  6. 1/3 repo: add level of concern reportingMark C. Chu-Carroll, Oct 26, 2026
  7. Patrick SteinhardtOct 27, 2026
  8. 2/3 repo: make concern thresholds configurableMark C. Chu-Carroll, Oct 26, 2026
  9. Patrick SteinhardtOct 27, 2026
  10. 3/3 repo: add documentation for level-of-concern.Mark C. Chu-Carroll, Oct 26, 2026
  11. Patrick SteinhardtOct 27, 2026
  12. Mark C. Chu-CarrollOct 28, 2026
  13. 0/2 repo: add degree-of-concern reporting to structureMark C. Chu-Carroll, Oct 27, 2026
  14. 1/2 repo: add level of concern reportingMark C. Chu-Carroll, Oct 27, 2026
  15. 2/2 repo: make concern thresholds configurableMark C. Chu-Carroll, Oct 27, 2026
  16. 0/2 repo: add degree-of-concern reporting to structureMark C. Chu-Carroll, Oct 29, 2026
  17. 1/2 repo: add level of concern reportingMark C. Chu-Carroll, Oct 29, 2026
  18. Junio C HamanoOct 29, 2026
  19. Mark C. Chu-CarrollOct 29, 2026
  20. 2/2 repo: make concern thresholds configurableMark C. Chu-Carroll, Oct 29, 2026
  21. 0/2 repo: add degree-of-concern reporting to structureMark C. Chu-Carroll, Nov 2, 2026
  22. 1/2 repo: add level of concern reportingMark C. Chu-Carroll, Nov 2, 2026
  23. 2/2 repo: make concern thresholds configurableMark C. Chu-Carroll, Nov 2, 2026

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.