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

Re: [PATCH v4 4/7] builtin/repo: introduce stats subcommand

From
Justin Tobler <jltobler@gmail.com>
Date
Oct 9, 2025, 22:09 UTC
Message-ID
<qdot36lscj2jzuej2zixdlgocubiimh54dkxzl2xgcy3g2n42m@gpdi7jwc2oyd>
In-Reply-To
<xmqqfrc797pk.fsf@gitster.g>
On 25/09/27 09:32AM, Junio C Hamano wrote:
Show 15 quoted lines
> Justin Tobler <jltobler@gmail.com> writes:
> 
> > The shape of a repository's history can have huge impacts on the
> > performance and health of the repository itself. Currently, Git lacks a
> > means to surface key stats/information regarding the shape of a
> > repository via a single command.
> 
> Talking about "shape of a repository's *history*" may negatively
> affect your goal here.  If a project is overly mergy with many
> octopus merges, it would have huge impacts on the performance to run
> "git bisect" over its history, so it may be interesting to know the
> ratio of the merge commits in the total commits, and also the
> average number of merge parents.  But after you obtain such numbers,
> you cannot do anything about it, as you cannot afford to rewrite its
> history only to improve the "performance and health".

The above example is actually something I would like to add in a future series. From my perspective, if a certain repository operation is performing poorly, it is still valuable to have insight into the reason why, regardless of whether it is realistically actionable or not for the user.

I will try to better clarify the command's intent in the log message.
Show 7 quoted lines
> And that is what makes "key stats" relative to your goal.  If your
> goal is to give stats on the things you can control (e.g., how long
> a typical delta chain is, how many loose objects there are that can
> be moved to a packfile, how small would your object database would
> become if you prune all the unreachable objects), that would cut off
> some stats that may still be interesting but may not contribute to
> address "huge impacts on the performance and health".

I would say the main goal of this command is to surface interesting information about the repository and its object graph structure. Something that may make a stat "interesting" is if its value could be a potential indicator of poor repository performance. Like the max number of parents a commit has, or the max number of entries a tree has. I don't think the actual stat value needs to be concerning itself for it to be displayed though.

If there is actionable recourse a user can take to remediate a concerning stat that would be ideal, but I see the primarly goal being to just surface the information regardless.

Show 5 quoted lines
> With Devil's advocate hat on, a single command that gives a set of
> stats that are "key" to a goal of a single use case may not be as
> useful as a collection of commands, each of which gives stats on one
> aspect of the repository, that can be combined to help you address
> various different goals.

Good points. From my perspective, the benefit of having a single command here is to provide a simple means to generate a report of the general repository shape. In this context, "key stats" reflect certain charactistics about the repository that may be concerning performance wise for typical repository operations or just of interest in general.

One of the motivations here is to enable a user to easily generate such a report and be able to share it with others that may not have access to the underlying repository.

I think this still could leave room for more fine-grained commands that can surface more targeted information about a repository with other goals in mind in the future though.

Show 16 quoted lines
> > To allow users to more readily identify potential issues for a
> > repository, introduce the "stats" subcommand in git-repo(1) to output
> > stats for the repository that may be of interest to users. The goal of
> > this subcommand is to eventually provide similar functionality to
> > git-sizer(1), but natively in Git.
> 
> So, it is needless to say that the kind of "stats" obtained by such
> a single tool needs to be chosen carefully, but more importantly,
> its output should give users actionable output, as whoever designed
> such a tool and chose what "key stats" are has a clear idea on
> various aspects of repository.  "stats" measure the health of the
> repository against certain yardstick, but it should come with a
> clear instruction to make use of that measurement.  The tool may say
> "the stats indicate that you have commits that touch too many paths
> at the same time".  The users need to be know what consequence of
> that finding is, and what they can do about it.

As mentioned above, from my perspective, the git-repo-stats command itself is not about specifically targeting and diagnoising actionable issues that a repository has. It's primary focus should be to provide insight about the repository structure that may be helpful when trying to understand certain repository performance characteristics in general.

In the next version I'll rework this log message to better clarify the intent of this command.

Show 9 quoted lines
> For example, what would the user do with the new knowledge that the
> repository has 100x as many local branches as there are
> remote-tracking branches?  Without breaking down these numerous
> local branches into those that are still used in active development
> (hint: peek into their reflog), kept as historical landmarks, past
> development that has already been merged (hint: "git branch --list
> --merged origin/master"), or abandoned cruft that hasn't been
> touched with some changes that are not merged anywhere, the users
> would not know what to do.

In a future series, I would like to introduce a "level of concern" meter for the outputted stats. As you mentioned earlier, this could provide a measure of health for a repository stat against a certain yardstick. At that point in time, I think it would also make sense to provide documentation on actions that a user could potentially take to address specific stats that are marked with a higher level of concern. Certain stats that get identified as concerning may not be realistically actionable though.

For now, I think it's fine to omit this though because the outputted stats are presented agnostically without any concern level.

Show 11 quoted lines
> > +`stats`::
> > +	Retrieve statistics about the current repository. The following kinds
> > +	of information are reported:
> > ++
> > +* Reference counts categorized by type
> > +
> > ++
> > +The table output format may change and is not intended for machine parsing.
> 
> Do we eventually want to give another format that is intended for
> machine parsing?

Yes, and we introduce a key-value and NUL format later in this series. I will mention this in the log message.

> In a format meant for human consumption, is it still sensible to
> target fixed-column terminals these days?  Rather, would they want
> prettier-formatted html, or csv that they can easily import to
> spreadsheet?  (these are not objections but genuine questions).

From my perspective, having an output format that can be immediately viewed in the same place the command is run is still quite valuable and is still common in similar tooling.

I think there may also be value in additional formats, such as the ones mentioned above, but I think those should be implemented as a separate series if demand presents itself.

Show 18 quoted lines
> > +static void stats_table_print(const struct stats_table *table)
> > +{
> > +	const char *name_col_title = _("Repository stats");
> > +	const char *value_col_title = _("Value");
> > +	size_t name_title_len = utf8_strwidth(name_col_title);
> > +	size_t value_title_len = utf8_strwidth(value_col_title);
> > +	struct string_list_item *item;
> > +	int name_col_width;
> > +	int value_col_width;
> > +
> > +	name_col_width = cast_size_t_to_int(
> > +		max_size_t(table->name_col_width, name_title_len));
> > +	value_col_width = cast_size_t_to_int(
> > +		max_size_t(table->value_col_width, value_title_len));
> 
> If table->name_col_width and table->value_col_width were int to
> begin with, none of these casts would have been necessary.  Aren't
> we overusing size_t to count things that are not memory allocations?

Yes. Storing the column widths as size_t in this scenario doesn't make much sense because they need to be an int for the format string anyways. Furthermore, the number of columns will always be a relatively small number.

I'll fix this in the next version. :)
Show 16 quoted lines
> > +	printf("| %-*s | %-*s |\n", name_col_width, name_col_title,
> > +	       value_col_width, value_col_title);
> > +	printf("| ");
> > +	for (int i = 0; i < name_col_width; i++)
> > +		putchar('-');
> > +	printf(" | ");
> > +	for (int i = 0; i < value_col_width; i++)
> > +		putchar('-');
> > +	printf(" |\n");
> 
> I wonder if people want to use unicode "Box Drawing" block and other
> fancier things, as we assume utf8 for names and values, in which
> case these printf would need to be "translatable", but locale
> administrators should not have more say than others what kind of
> line drawing elements are to be used, so perhaps the above is good
> enough at least for now.

I think the current table is probably sufficient for now. I do forsee iteration on this format in future series though.

-Justin
Previous: Junio C HamanoNext: Justin Tobler
Message 57 of 92 in “builtin/repo: introduce stats subcommand”
  1. 0/4 builtin/repo: introduce stats subcommandJustin Tobler, Sep 23, 2025
  2. 1/4 builtin/repo: introduce stats subcommandJustin Tobler, Sep 23, 2025
  3. Patrick SteinhardtSep 23, 2025
  4. Justin ToblerSep 23, 2025
  5. Patrick SteinhardtSep 23, 2025
  6. Karthik NayakSep 23, 2025
  7. Justin ToblerSep 23, 2025
  8. 2/4 builtin/repo: add object counts in stats outputJustin Tobler, Sep 23, 2025
  9. Patrick SteinhardtSep 23, 2025
  10. Justin ToblerSep 23, 2025
  11. Karthik NayakSep 23, 2025
  12. Justin ToblerSep 23, 2025
  13. 3/4 builtin/repo: add keyvalue format for statsJustin Tobler, Sep 23, 2025
  14. Patrick SteinhardtSep 23, 2025
  15. Justin ToblerSep 23, 2025
  16. Karthik NayakSep 23, 2025
  17. Justin ToblerSep 23, 2025
  18. 4/4 builtin/repo: add nul format for statsJustin Tobler, Sep 23, 2025
  19. Patrick SteinhardtSep 23, 2025
  20. Justin ToblerSep 23, 2025
  21. Patrick SteinhardtSep 24, 2025
  22. Karthik NayakSep 23, 2025
  23. Justin ToblerSep 23, 2025
  24. 0/6 builtin/repo: introduce stats subcommandJustin Tobler, Sep 24, 2025
  25. 1/6 builtin/repo: rename repo_info() to cmd_repo_info()Justin Tobler, Sep 24, 2025
  26. 2/6 ref-filter: allow NULL filter patternJustin Tobler, Sep 24, 2025
  27. 3/6 builtin/repo: introduce stats subcommandJustin Tobler, Sep 24, 2025
  28. Patrick SteinhardtSep 25, 2025
  29. Justin ToblerSep 25, 2025
  30. 4/6 builtin/repo: add object counts in stats outputJustin Tobler, Sep 24, 2025
  31. 5/6 builtin/repo: add keyvalue and nul format for statsJustin Tobler, Sep 24, 2025
  32. Patrick SteinhardtSep 25, 2025
  33. Justin ToblerSep 25, 2025
  34. Patrick SteinhardtSep 25, 2025
  35. 6/6 builtin/repo: add progress meter for statsJustin Tobler, Sep 24, 2025
  36. Patrick SteinhardtSep 25, 2025
  37. Justin ToblerSep 25, 2025
  38. 0/7 builtin/repo: introduce stats subcommandJustin Tobler, Sep 25, 2025
  39. 1/7 builtin/repo: rename repo_info() to cmd_repo_info()Justin Tobler, Sep 25, 2025
  40. 2/7 ref-filter: allow NULL filter patternJustin Tobler, Sep 25, 2025
  41. 3/7 clang-format: exclude control macros from SpaceBeforeParensJustin Tobler, Sep 25, 2025
  42. 4/7 builtin/repo: introduce stats subcommandJustin Tobler, Sep 25, 2025
  43. Eric SunshineSep 25, 2025
  44. Justin ToblerSep 26, 2025
  45. 5/7 builtin/repo: add object counts in stats outputJustin Tobler, Sep 25, 2025
  46. 6/7 builtin/repo: add keyvalue and nul format for statsJustin Tobler, Sep 25, 2025
  47. 7/7 builtin/repo: add progress meter for statsJustin Tobler, Sep 25, 2025
  48. 0/7 builtin/repo: introduce stats subcommandJustin Tobler, Sep 27, 2025
  49. 1/7 builtin/repo: rename repo_info() to cmd_repo_info()Justin Tobler, Sep 27, 2025
  50. 2/7 ref-filter: allow NULL filter patternJustin Tobler, Sep 27, 2025
  51. 3/7 clang-format: exclude control macros from SpaceBeforeParensJustin Tobler, Sep 27, 2025
  52. Junio C HamanoSep 27, 2025
  53. Justin ToblerSep 27, 2025
  54. Junio C HamanoSep 27, 2025
  55. 4/7 builtin/repo: introduce stats subcommandJustin Tobler, Sep 27, 2025
  56. Junio C HamanoSep 27, 2025
  57. Justin ToblerOct 9, 2025
  58. Justin ToblerOct 10, 2025
  59. Patrick SteinhardtOct 10, 2025
  60. Justin ToblerOct 10, 2025
  61. Patrick SteinhardtOct 13, 2025
  62. 6/7 builtin/repo: add keyvalue and nul format for statsJustin Tobler, Sep 27, 2025
  63. 5/7 builtin/repo: add object counts in stats outputJustin Tobler, Sep 27, 2025
  64. 7/7 builtin/repo: add progress meter for statsJustin Tobler, Sep 27, 2025
  65. Junio C HamanoSep 27, 2025
  66. 0/6 builtin/repo: introduce structure subcommandJustin Tobler, Oct 15, 2025
  67. 1/6 builtin/repo: rename repo_info() to cmd_repo_info()Justin Tobler, Oct 15, 2025
  68. 2/6 ref-filter: allow NULL filter patternJustin Tobler, Oct 15, 2025
  69. 3/6 builtin/repo: introduce structure subcommandJustin Tobler, Oct 15, 2025
  70. Patrick SteinhardtOct 16, 2025
  71. Justin ToblerOct 21, 2025
  72. 4/6 builtin/repo: add object counts in structure outputJustin Tobler, Oct 15, 2025
  73. 5/6 builtin/repo: add keyvalue and nul format for structure statsJustin Tobler, Oct 15, 2025
  74. 6/6 builtin/repo: add progress meter for structure statsJustin Tobler, Oct 15, 2025
  75. 0/7 builtin/repo: introduce structure subcommandJustin Tobler, Oct 21, 2025
  76. 1/7 builtin/repo: rename repo_info() to cmd_repo_info()Justin Tobler, Oct 21, 2025
  77. 2/7 ref-filter: allow NULL filter patternJustin Tobler, Oct 21, 2025
  78. 3/7 ref-filter: export ref_kind_from_refname()Justin Tobler, Oct 21, 2025
  79. 4/7 builtin/repo: introduce structure subcommandJustin Tobler, Oct 21, 2025
  80. Patrick SteinhardtOct 22, 2025
  81. Justin ToblerOct 22, 2025
  82. Lucas Seiki OshiroOct 22, 2025
  83. Justin ToblerOct 22, 2025
  84. 5/7 builtin/repo: add object counts in structure outputJustin Tobler, Oct 21, 2025
  85. 6/7 builtin/repo: add keyvalue and nul format for structure statsJustin Tobler, Oct 21, 2025
  86. Lucas Seiki OshiroOct 22, 2025
  87. Justin ToblerOct 23, 2025
  88. 7/7 builtin/repo: add progress meter for structure statsJustin Tobler, Oct 21, 2025
  89. Lucas Seiki OshiroOct 22, 2025
  90. Justin ToblerOct 23, 2025
  91. Junio C HamanoOct 23, 2025
  92. Patrick SteinhardtOct 24, 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.