]> git.ipfire.org Git - thirdparty/git.git/commitdiff
builtin/repo: humanise count values in structure output
authorJustin Tobler <jltobler@gmail.com>
Wed, 17 Dec 2025 17:54:00 +0000 (11:54 -0600)
committerJunio C Hamano <gitster@pobox.com>
Thu, 18 Dec 2025 00:02:31 +0000 (09:02 +0900)
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>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
builtin/repo.c
strbuf.c
strbuf.h
t/t1901-repo-structure.sh

index a69699857a5e03b719c8fbed1c262dac53fb1927..9c61bc3e173a940a28b45c1c3268194efe3c1664 100644 (file)
@@ -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, ...)
@@ -273,7 +282,7 @@ 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);
+       humanise_count(value, &entry->value, &entry->unit);
 
        va_start(ap, format);
        stats_table_vaddf(table, entry, format, ap);
@@ -324,20 +333,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 +358,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 +379,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);
        }
index 349ee9727a19209b0d1e1cfac490d4b07d11990a..995ff15169f59ead4f32abed6ed99b929220a9d8 100644 (file)
--- a/strbuf.c
+++ b/strbuf.c
@@ -836,6 +836,32 @@ void strbuf_addstr_urlencode(struct strbuf *sb, const char *s,
        strbuf_add_urlencode(sb, s, strlen(s), allow_unencoded_fn);
 }
 
+void humanise_count(size_t count, char **value, const char **unit)
+{
+       if (count >= 1000000000) {
+               size_t x = count + 5000000; /* for rounding */
+               *value = xstrfmt(_("%u.%2.2u"), (unsigned)(x / 1000000000),
+                                (unsigned)(x % 1000000000 / 10000000));
+               /* TRANSLATORS: SI decimal prefix symbol for 10^9 */
+               *unit = _("G");
+       } else if (count >= 1000000) {
+               size_t x = count + 5000; /* for rounding */
+               *value = xstrfmt(_("%u.%2.2u"), (unsigned)(x / 1000000),
+                                (unsigned)(x % 1000000 / 10000));
+               /* TRANSLATORS: SI decimal prefix symbol for 10^6 */
+               *unit = _("M");
+       } else if (count >= 1000) {
+               size_t x = count + 5; /* for rounding */
+               *value = xstrfmt(_("%u.%2.2u"), (unsigned)(x / 1000),
+                                (unsigned)(x % 1000 / 10));
+               /* TRANSLATORS: SI decimal prefix symbol for 10^3 */
+               *unit = _("k");
+       } else {
+               *value = xstrfmt("%u", (unsigned)count);
+               *unit = NULL;
+       }
+}
+
 void humanise_bytes(off_t bytes, char **value, const char **unit,
                    unsigned flags)
 {
index 698b3cc4a5136727b6d17c6b28b9094f4eb7a637..52feef4c1bb0fdd754f6a979169e471683ef8639 100644 (file)
--- a/strbuf.h
+++ b/strbuf.h
@@ -381,6 +381,12 @@ enum humanise_flags {
 void humanise_bytes(off_t bytes, char **value, const char **unit,
                    unsigned flags);
 
+/**
+ * Converts the given count into a downscaled human-readable value and
+ * corresponding unit as two separate strings.
+ */
+void humanise_count(size_t count, char **value, const char **unit);
+
 /**
  * Append the given byte size as a human-readable string (i.e. 12.23 KiB,
  * 3.50 MiB).
index 36a71a144e3f747a68b9afa11a08e305915c5437..55fd13ad1b9c4c4b5e016e232a4b2ce665a4aba2 100755 (executable)
@@ -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 &&