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

Re: [BUG] `git describe` doesn't traverse the graph in topological order

From
'B'Ben Boeckel' <ben.boeckel@kitware.com>
Date
Feb 28, 2026, 06:11 UTC
Message-ID
<aaKHH6Mf_oKJ9H6M@rotor.dev.benboeckel.internal>
In-Reply-To
<20251120080525.GB1283645@coredump.intra.peff.net>
On Thu, Nov 20, 2025 at 03:05:25 -0500, Jeff King wrote:
Show 33 quoted lines
> On Wed, Nov 19, 2025 at 09:48:52PM -0500, 'Ben Boeckel' wrote:
> 
> > So I finally found some time to go back to this. The actual fix is
> > actually rather easy (patch attached). However, as guessed at previously
> > in the thread, the performance is in the tank without an up-to-date
> > commit graph ("instant" with it versus "minutes" without). On the other
> > hand, it is *accurate*. It does fix one expect-fail test case already in
> > the test suite (also included in the patch).
> 
> Minutes? Yikes. Let's look...
> 
> > +/*
> > + * Topological comparison: always return parents before children.
> > + * This is reverse topological order: children before parents.
> > + */
> > +static int compare_commits_topo(const void *a_, const void *b_, void *_unused_ UNUSED)
> > +{
> > +	struct commit *a = (struct commit *)a_;
> > +	struct commit *b = (struct commit *)b_;
> > +	if (repo_is_descendant_of(the_repository, a, &(struct commit_list){ b, NULL }))
> > +		return -1; // a is descendant, so comes before b
> > +	if (repo_is_descendant_of(the_repository, b, &(struct commit_list){ a, NULL }))
> > +		return 1; // b is descendant, so comes before a
> > +	// fallback: order by hash for determinism
> > +	return oidcmp(&a->object.oid, &b->object.oid);
> > +}
> 
> Ah. So you are doing two full traversals for each comparison. That is
> going to be expensive. You would do much better to walk all of history
> one time, marking the generation number (distance to root) of each
> commit, and then comparing generations here (if A has a lower generation
> than B, then you know that B cannot be an ancestor of A). Or if we have
> commit graphs, just use the generation numbers they already contain. ;)
Ok, so it sounds like I should, in `describe_commit`:
- check if commit graphs are enabled (and verified?): if so, use their
  generation numbers
- if they're not enabled, perform a local walk to store a generation
  number (somewhere?) that is `max(cmit->parents[].generation) + 1`
  (however the `generation` is stored)

and then in the comparator, use this to exclude one of the comparisons at least. However…

Show 5 quoted lines
> We do all of this already for the "--topo-order" option of the revision
> traversal machinery. If we have commit graphs, it can output in
> topographical order in a streaming way (see init_topo_walk() in
> revision.c). If not, then we collect all of the commits up front and
> call sort_in_topological_order().
The key here seems to be:
	if (revs->topo_order && !generation_numbers_enabled(the_repository))
		revs->limited = 1;
which then goes down the `sort_in_topological_order` path.
> Sadly, git-describe does not seem to use the traversal machinery, so it
> is not as easy as just setting revs.topo_order. Either we have to adapt
> to using the regular traversal code, or those same concepts need to be
> applied to its custom traversal.

I suppose I can try to convert it over to a proper walk following `MyFirstObjectWalk.adoc` if that is a more fruitful path than the above ideas. As long as all children of a commit are walked before the commit itself, it should slot into the existing bookkeeping fairly well.

Thanks,
--Ben
Previous: Jeff KingNext: 'Ben Boeckel'
Message 15 of 20 in “[BUG] `git describe` doesn't traverse the graph in topological order”
  1. Ben BoeckelAug 12, 2023
  2. Ben BoeckelSep 22, 2023
  3. rsbecker@nexbridge.comSep 22, 2023
  4. 'Ben Boeckel'Sep 22, 2023
  5. rsbecker@nexbridge.comSep 22, 2023
  6. 'Ben Boeckel'Sep 22, 2023
  7. Junio C HamanoSep 22, 2023
  8. rsbecker@nexbridge.comSep 22, 2023
  9. 'Ben Boeckel'Sep 22, 2023
  10. rsbecker@nexbridge.comSep 22, 2023
  11. 'Ben Boeckel'Sep 22, 2023
  12. rsbecker@nexbridge.comSep 22, 2023
  13. 'Ben Boeckel'Nov 20, 2025
  14. Jeff KingNov 20, 2025
  15. 'Ben Boeckel'Feb 28, 2026
  16. 'Ben Boeckel'Sep 22, 2023
  17. 'Ben Boeckel'Sep 23, 2023
  18. Kristoffer HaugsbakkSep 22, 2023
  19. Kristoffer HaugsbakkSep 22, 2023
  20. 'Ben Boeckel'Sep 22, 2023

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.