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

[PATCH 2/6] builtin/repo: humanise count values in structure output

From
Justin Tobler <jltobler@gmail.com>
Date
Dec 9, 2025, 22:58 UTC
Message-ID
<20251209225820.2861276-3-jltobler@gmail.com>
In-Reply-To
<20251209225820.2861276-1-jltobler@gmail.com>

The table output format for the git-repo(1) structure subcommand is used by default and intended to provide output to users in a human-friendly manner. When the reference/object count values in a repository are large, it becomes more cumbersome for users to read the values.

For larger values, update the table output format to instead produce more human-friendly count values that are scaled down with the appropriate unit prefix. Output for the keyvalue and nul formats remains unchanged.

Signed-off-by: Justin Tobler <jltobler@gmail.com>
---
 builtin/repo.c            | 61 +++++++++++++++++++++++++++++++-------
 t/t1901-repo-structure.sh | 62 +++++++++++++++++++--------------------
 2 files changed, 82 insertions(+), 41 deletions(-)
diff --git a/builtin/repo.c b/builtin/repo.c
index a69699857a..8fb728b3a5 100644
--- a/builtin/repo.c
+++ b/builtin/repo.c
@@ -223,6 +223,7 @@ struct stats_table {
 
 	int name_col_width;
 	int value_col_width;
+	int unit_col_width;
 };
 
 /*
@@ -230,6 +231,7 @@ struct stats_table {
  */
 struct stats_table_entry {
 	char *value;
+	const char *unit;
 };
 
 static void stats_table_vaddf(struct stats_table *table,
@@ -250,11 +252,18 @@ static void stats_table_vaddf(struct stats_table *table,
 
 	if (name_width > table->name_col_width)
 		table->name_col_width = name_width;
-	if (entry) {
+	if (!entry)
+		return;
+	if (entry->value) {
 		int value_width = utf8_strwidth(entry->value);
 		if (value_width > table->value_col_width)
 			table->value_col_width = value_width;
 	}
+	if (entry->unit) {
+		int unit_width = utf8_strwidth(entry->unit);
+		if (unit_width > table->unit_col_width)
+			table->unit_col_width = unit_width;
+	}
 }
 
 static void stats_table_addf(struct stats_table *table, const char *format, ...)
@@ -266,6 +275,10 @@ static void stats_table_addf(struct stats_table *table, const char *format, ...)
 	va_end(ap);
 }
 
+static const char *unit_k = "k";
+static const char *unit_M = "M";
+static const char *unit_G = "G";
+
 static void stats_table_count_addf(struct stats_table *table, size_t value,
 				   const char *format, ...)
 {
@@ -273,7 +286,26 @@ static void stats_table_count_addf(struct stats_table *table, size_t value,
 	va_list ap;
 
 	CALLOC_ARRAY(entry, 1);
-	entry->value = xstrfmt("%" PRIuMAX, (uintmax_t)value);
+
+	if (value >= 1000000000) {
+		uintmax_t x = (uintmax_t)value + 5000000;
+		entry->value = xstrfmt("%" PRIuMAX ".%02" PRIuMAX,
+				       x / 1000000000,
+				       x % 1000000000 / 10000000);
+		entry->unit = unit_G;
+	} else if (value >= 1000000) {
+		uintmax_t x = (uintmax_t)value + 5000;
+		entry->value = xstrfmt("%" PRIuMAX ".%02" PRIuMAX,
+				       x / 1000000, x % 1000000 / 10000);
+		entry->unit = unit_M;
+	} else if (value >= 1000) {
+		uintmax_t x = (uintmax_t)value + 5;
+		entry->value = xstrfmt("%" PRIuMAX ".%02" PRIuMAX,
+				       x / 1000, x % 1000 / 10);
+		entry->unit = unit_k;
+	} else {
+		entry->value = xstrfmt("%" PRIuMAX, (uintmax_t)value);
+	}
 
 	va_start(ap, format);
 	stats_table_vaddf(table, entry, format, ap);
@@ -324,20 +356,24 @@ static void stats_table_print_structure(const struct stats_table *table)
 {
 	const char *name_col_title = _("Repository structure");
 	const char *value_col_title = _("Value");
-	int name_col_width = utf8_strwidth(name_col_title);
-	int value_col_width = utf8_strwidth(value_col_title);
+	int title_name_width = utf8_strwidth(name_col_title);
+	int title_value_width = utf8_strwidth(value_col_title);
+	int name_col_width = table->name_col_width;
+	int value_col_width = table->value_col_width;
+	int unit_col_width = table->unit_col_width;
 	struct string_list_item *item;
 	struct strbuf buf = STRBUF_INIT;
 
-	if (table->name_col_width > name_col_width)
-		name_col_width = table->name_col_width;
-	if (table->value_col_width > value_col_width)
-		value_col_width = table->value_col_width;
+	if (title_name_width > name_col_width)
+		name_col_width = title_name_width;
+	if (title_value_width > value_col_width + unit_col_width + 1)
+		value_col_width = title_value_width - unit_col_width;
 
 	strbuf_addstr(&buf, "| ");
 	strbuf_utf8_align(&buf, ALIGN_LEFT, name_col_width, name_col_title);
 	strbuf_addstr(&buf, " | ");
-	strbuf_utf8_align(&buf, ALIGN_LEFT, value_col_width, value_col_title);
+	strbuf_utf8_align(&buf, ALIGN_LEFT,
+			  value_col_width + unit_col_width + 1, value_col_title);
 	strbuf_addstr(&buf, " |");
 	printf("%s\n", buf.buf);
 
@@ -345,17 +381,20 @@ static void stats_table_print_structure(const struct stats_table *table)
 	for (int i = 0; i < name_col_width; i++)
 		putchar('-');
 	printf(" | ");
-	for (int i = 0; i < value_col_width; i++)
+	for (int i = 0; i < value_col_width + unit_col_width + 1; i++)
 		putchar('-');
 	printf(" |\n");
 
 	for_each_string_list_item(item, &table->rows) {
 		struct stats_table_entry *entry = item->util;
 		const char *value = "";
+		const char *unit = "";
 
 		if (entry) {
 			struct stats_table_entry *entry = item->util;
 			value = entry->value;
+			if (entry->unit)
+				unit = entry->unit;
 		}
 
 		strbuf_reset(&buf);
@@ -363,6 +402,8 @@ static void stats_table_print_structure(const struct stats_table *table)
 		strbuf_utf8_align(&buf, ALIGN_LEFT, name_col_width, item->string);
 		strbuf_addstr(&buf, " | ");
 		strbuf_utf8_align(&buf, ALIGN_RIGHT, value_col_width, value);
+		strbuf_addch(&buf, ' ');
+		strbuf_utf8_align(&buf, ALIGN_LEFT, unit_col_width, unit);
 		strbuf_addstr(&buf, " |");
 		printf("%s\n", buf.buf);
 	}
diff --git a/t/t1901-repo-structure.sh b/t/t1901-repo-structure.sh
index 36a71a144e..55fd13ad1b 100755
--- a/t/t1901-repo-structure.sh
+++ b/t/t1901-repo-structure.sh
@@ -10,21 +10,21 @@ test_expect_success 'empty repository' '
 	(
 		cd repo &&
 		cat >expect <<-\EOF &&
-		| Repository structure | Value |
-		| -------------------- | ----- |
-		| * References         |       |
-		|   * Count            |     0 |
-		|     * Branches       |     0 |
-		|     * Tags           |     0 |
-		|     * Remotes        |     0 |
-		|     * Others         |     0 |
-		|                      |       |
-		| * Reachable objects  |       |
-		|   * Count            |     0 |
-		|     * Commits        |     0 |
-		|     * Trees          |     0 |
-		|     * Blobs          |     0 |
-		|     * Tags           |     0 |
+		| Repository structure | Value  |
+		| -------------------- | ------ |
+		| * References         |        |
+		|   * Count            |     0  |
+		|     * Branches       |     0  |
+		|     * Tags           |     0  |
+		|     * Remotes        |     0  |
+		|     * Others         |     0  |
+		|                      |        |
+		| * Reachable objects  |        |
+		|   * Count            |     0  |
+		|     * Commits        |     0  |
+		|     * Trees          |     0  |
+		|     * Blobs          |     0  |
+		|     * Tags           |     0  |
 		EOF
 
 		git repo structure >out 2>err &&
@@ -39,7 +39,7 @@ test_expect_success 'repository with references and objects' '
 	git init repo &&
 	(
 		cd repo &&
-		test_commit_bulk 42 &&
+		test_commit_bulk 1005 &&
 		git tag -a foo -m bar &&
 
 		oid="$(git rev-parse HEAD)" &&
@@ -49,21 +49,21 @@ test_expect_success 'repository with references and objects' '
 		git notes add -m foo &&
 
 		cat >expect <<-\EOF &&
-		| Repository structure | Value |
-		| -------------------- | ----- |
-		| * References         |       |
-		|   * Count            |     4 |
-		|     * Branches       |     1 |
-		|     * Tags           |     1 |
-		|     * Remotes        |     1 |
-		|     * Others         |     1 |
-		|                      |       |
-		| * Reachable objects  |       |
-		|   * Count            |   130 |
-		|     * Commits        |    43 |
-		|     * Trees          |    43 |
-		|     * Blobs          |    43 |
-		|     * Tags           |     1 |
+		| 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   |
 		EOF
 
 		git repo structure >out 2>err &&
-- 
2.52.0.209.ge85ae279b0
Previous: Justin ToblerNext: Patrick Steinhardt
Message 3 of 80 in “builtin/repo: add object size info to structure output”
  1. 0/6 builtin/repo: add object size info to structure outputJustin Tobler, Dec 9, 2025
  2. 1/6 builtin/repo: group per-type object values into structJustin Tobler, Dec 9, 2025
  3. 2/6 builtin/repo: humanise count values in structure outputJustin Tobler, Dec 9, 2025
  4. Patrick SteinhardtDec 10, 2025
  5. Justin ToblerDec 10, 2025
  6. Junio C HamanoDec 11, 2025
  7. Justin ToblerDec 12, 2025
  8. 3/6 builtin/repo: add inflated object info to keyvalue structure outputJustin Tobler, Dec 9, 2025
  9. 4/6 builtin/repo: add inflated object info to structure tableJustin Tobler, Dec 9, 2025
  10. Patrick SteinhardtDec 10, 2025
  11. Justin ToblerDec 10, 2025
  12. 5/6 builtin/repo: add disk size info to keyvalue stucture outputJustin Tobler, Dec 9, 2025
  13. Patrick SteinhardtDec 10, 2025
  14. Justin ToblerDec 10, 2025
  15. Justin ToblerDec 12, 2025
  16. Patrick SteinhardtDec 15, 2025
  17. Justin ToblerDec 15, 2025
  18. Junio C HamanoDec 10, 2025
  19. Lucas Seiki OshiroDec 10, 2025
  20. Justin ToblerDec 12, 2025
  21. Junio C HamanoDec 12, 2025
  22. 6/6 builtin/repo: add object disk size info to structure tableJustin Tobler, Dec 9, 2025
  23. Patrick SteinhardtDec 10, 2025
  24. Justin ToblerDec 10, 2025
  25. 0/7 builtin/repo: add object size info to structure outputJustin Tobler, Dec 12, 2025
  26. 1/7 builtin/repo: group per-type object values into structJustin Tobler, Dec 12, 2025
  27. 2/7 strbuf: split out logic to humanise byte valuesJustin Tobler, Dec 12, 2025
  28. Patrick SteinhardtDec 15, 2025
  29. Justin ToblerDec 15, 2025
  30. Junio C HamanoDec 15, 2025
  31. Justin ToblerDec 15, 2025
  32. Jiang XinDec 16, 2025
  33. Junio C HamanoDec 16, 2025
  34. Jiang XinDec 16, 2025
  35. Justin ToblerDec 16, 2025
  36. 3/7 builtin/repo: humanise count values in structure outputJustin Tobler, Dec 12, 2025
  37. Patrick SteinhardtDec 15, 2025
  38. 4/7 builtin/repo: add inflated object info to keyvalue structure outputJustin Tobler, Dec 12, 2025
  39. Patrick SteinhardtDec 15, 2025
  40. Justin ToblerDec 15, 2025
  41. 5/7 builtin/repo: add inflated object info to structure tableJustin Tobler, Dec 12, 2025
  42. 6/7 builtin/repo: add disk size info to keyvalue stucture outputJustin Tobler, Dec 12, 2025
  43. Patrick SteinhardtDec 15, 2025
  44. 7/7 builtin/repo: add object disk size info to structure tableJustin Tobler, Dec 12, 2025
  45. 0/7 builtin/repo: add object size info to structure outputJustin Tobler, Dec 15, 2025
  46. 1/7 builtin/repo: group per-type object values into structJustin Tobler, Dec 15, 2025
  47. 2/7 strbuf: split out logic to humanise byte valuesJustin Tobler, Dec 15, 2025
  48. Junio C HamanoDec 16, 2025
  49. Justin ToblerDec 16, 2025
  50. 3/7 builtin/repo: humanise count values in structure outputJustin Tobler, Dec 15, 2025
  51. Patrick SteinhardtDec 16, 2025
  52. 4/7 builtin/repo: add inflated object info to keyvalue structure outputJustin Tobler, Dec 15, 2025
  53. 5/7 builtin/repo: add inflated object info to structure tableJustin Tobler, Dec 15, 2025
  54. 6/7 builtin/repo: add disk size info to keyvalue stucture outputJustin Tobler, Dec 15, 2025
  55. 7/7 builtin/repo: add object disk size info to structure tableJustin Tobler, Dec 15, 2025
  56. Patrick SteinhardtDec 16, 2025
  57. Justin ToblerDec 16, 2025
  58. 0/7 builtin/repo: add object size info to structure outputJustin Tobler, Dec 16, 2025
  59. 1/7 builtin/repo: group per-type object values into structJustin Tobler, Dec 16, 2025
  60. 2/7 strbuf: split out logic to humanise byte valuesJustin Tobler, Dec 16, 2025
  61. Junio C HamanoDec 16, 2025
  62. Justin ToblerDec 16, 2025
  63. 4/7 builtin/repo: add inflated object info to keyvalue structure outputJustin Tobler, Dec 16, 2025
  64. Patrick SteinhardtDec 17, 2025
  65. Justin ToblerDec 17, 2025
  66. 3/7 builtin/repo: humanise count values in structure outputJustin Tobler, Dec 16, 2025
  67. 5/7 builtin/repo: add inflated object info to structure tableJustin Tobler, Dec 16, 2025
  68. 6/7 builtin/repo: add disk size info to keyvalue stucture outputJustin Tobler, Dec 16, 2025
  69. 7/7 builtin/repo: add object disk size info to structure tableJustin Tobler, Dec 16, 2025
  70. Patrick SteinhardtDec 17, 2025
  71. Justin ToblerDec 17, 2025
  72. 0/7 builtin/repo: add object size info to structure outputJustin Tobler, Dec 17, 2025
  73. 1/7 builtin/repo: group per-type object values into structJustin Tobler, Dec 17, 2025
  74. 2/7 strbuf: split out logic to humanise byte valuesJustin Tobler, Dec 17, 2025
  75. 4/7 builtin/repo: add inflated object info to keyvalue structure outputJustin Tobler, Dec 17, 2025
  76. 3/7 builtin/repo: humanise count values in structure outputJustin Tobler, Dec 17, 2025
  77. 5/7 builtin/repo: add inflated object info to structure tableJustin Tobler, Dec 17, 2025
  78. 6/7 builtin/repo: add disk size info to keyvalue stucture outputJustin Tobler, Dec 17, 2025
  79. 7/7 builtin/repo: add object disk size info to structure tableJustin Tobler, Dec 17, 2025
  80. Patrick SteinhardtDec 18, 2025

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.