All of lore.kernel.org
 help / color / mirror / Atom feed
From: 'Ben Boeckel' <ben.boeckel@kitware.com>
To: Jeff King <peff@peff.net>
Cc: rsbecker@nexbridge.com, 'Junio C Hamano' <gitster@pobox.com>,
	git@vger.kernel.org
Subject: Re: [BUG] `git describe` doesn't traverse the graph in topological order
Date: Sat, 28 Feb 2026 01:11:43 -0500	[thread overview]
Message-ID: <aaKHH6Mf_oKJ9H6M@rotor.dev.benboeckel.internal> (raw)
In-Reply-To: <20251120080525.GB1283645@coredump.intra.peff.net>

On Thu, Nov 20, 2025 at 03:05:25 -0500, Jeff King wrote:
> 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…

> 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

  reply	other threads:[~2026-02-28  6:11 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-08-12 19:36 [BUG] `git describe` doesn't traverse the graph in topological order Ben Boeckel
2023-09-22 15:39 ` Ben Boeckel
2023-09-22 16:13   ` rsbecker
2023-09-22 16:51     ` 'Ben Boeckel'
2023-09-22 17:14       ` rsbecker
2023-09-22 17:38         ` 'Ben Boeckel'
2023-09-22 17:51         ` Junio C Hamano
2023-09-22 18:12           ` rsbecker
2023-09-22 18:44             ` 'Ben Boeckel'
2023-09-22 18:49               ` rsbecker
2023-09-22 19:05                 ` 'Ben Boeckel'
2023-09-22 19:27                   ` rsbecker
2025-11-20  2:48                     ` 'Ben Boeckel'
2025-11-20  8:05                       ` Jeff King
2026-02-28  6:11                         ` 'Ben Boeckel' [this message]
2023-09-22 18:41           ` 'Ben Boeckel'
2023-09-23 12:32         ` 'Ben Boeckel'
2023-09-22 17:11     ` Kristoffer Haugsbakk
2023-09-22 17:35   ` Kristoffer Haugsbakk
2023-09-22 17:43     ` 'Ben Boeckel'

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=aaKHH6Mf_oKJ9H6M@rotor.dev.benboeckel.internal \
    --to=ben.boeckel@kitware.com \
    --cc=git@vger.kernel.org \
    --cc=gitster@pobox.com \
    --cc=peff@peff.net \
    --cc=rsbecker@nexbridge.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.