This is an archive of the discontinued Mercurial Phabricator instance.

log: add config for making `hg log -G` always topo-sorted
ClosedPublic

Authored by martinvonz on May 1 2019, 1:22 PM.

Details

Summary

I (and everyone else at Google) have an log alias that adds graph mode
and templating. I have another one that builds on the first and also
restricts the set of revisions to only show those I'm most likely to
care about. This second alias also adds topological sorting. I still
sometimes use the first one. When I do, it very often bothers me that
it's not topologically sorted (branches are interleaved). This patch
adds a config option for always using topological sorting with graph
log.

The revision set is sorted eagerly, which seems like a bad idea, but
it doesn't seem to make a big difference in the hg repo (150ms). I
initially tried to instead wrap the user's revset in sort(...,topo),
but that seemed much harder.

Diff Detail

Repository
rHG Mercurial
Lint
Automatic diff as part of commit; lint not applicable.
Unit
Automatic diff as part of commit; unit tests not applicable.

Event Timeline

martinvonz created this revision.May 1 2019, 1:22 PM
yuja added a subscriber: yuja.May 14 2019, 8:35 AM

+def _maybetoposort(repo, revs, opts):
+ if opts.get('graph') and repo.ui.configbool('experimental', 'log.topo'):
+ revs = dagop.toposort(revs, repo.changelog.parentrevs)
+ # TODO: try to iterate the set lazily
+ revs = revset.baseset(list(revs))
+ return revs
+
def getrevs(repo, pats, opts):

"""Return (revs, differ) where revs is a smartset

@@ -727,7 +734,7 @@

limit = getlimit(opts)
revs = _initialrevs(repo, opts)
if not revs:
  • return smartset.baseset(), None

+ return _maybetoposort(repo, smartset.baseset(), opts), None

Nit: no need to sort an empty set.

@@ -756,7 +763,7 @@

differ = changesetdiffer()
differ._makefilematcher = filematcher
  • return revs, differ

+ return _maybetoposort(repo, revs, opts), differ

Maybe this can be merged with the if opts.get('graph') block above.

# I think "and opts.get('rev')" can be removed since revs.isdescending()
# would be true if --follow without --rev.
if opts.get('graph'):
    if experimental.log.topo:
        if not topo yet:
            toposort(revs)
    elif not (revs.isdescending() or revs.istopo()):
        revs.sort(reverse=True)

There used to be a experimental.graph-group-branches (that tortoise-hg
still use) that got removed at some point. Did you check the rational
behind the removal ?

If we reintroduce the option, I would be in favor of defining a path to
a non-experimental version of it.

There used to be a experimental.graph-group-branches (that tortoise-hg
still use) that got removed at some point. Did you check the rational
behind the removal ?

I didn't remember that option, so no. It was removed in 2188f170f5b6 (revset: add new topographical sort, 2016-06-13). All the rationale I could find is right there in the subject line (i.e. "add new topographical sort"). Was there more to it that you can remember?

If we reintroduce the option, I would be in favor of defining a path to
a non-experimental version of it.

I'd be fine with simply not marking it experimental from the beginning even though we know that it's not as fast/lazy as it should be.

In D6331#92619, @yuja wrote:

+def _maybetoposort(repo, revs, opts):
+ if opts.get('graph') and repo.ui.configbool('experimental', 'log.topo'):
+ revs = dagop.toposort(revs, repo.changelog.parentrevs)
+ # TODO: try to iterate the set lazily
+ revs = revset.baseset(list(revs))
+ return revs
+
def getrevs(repo, pats, opts):

"""Return (revs, differ) where revs is a smartset

@@ -727,7 +734,7 @@

limit = getlimit(opts)
revs = _initialrevs(repo, opts)
if not revs:
  • return smartset.baseset(), None

+ return _maybetoposort(repo, smartset.baseset(), opts), None

Nit: no need to sort an empty set.

Heh, true. I'l fix that.

@@ -756,7 +763,7 @@

differ = changesetdiffer()
differ._makefilematcher = filematcher
  • return revs, differ

+ return _maybetoposort(repo, revs, opts), differ

Maybe this can be merged with the if opts.get('graph') block above.

# I think "and opts.get('rev')" can be removed since revs.isdescending()
# would be true if --follow without --rev.
if opts.get('graph'):
    if experimental.log.topo:
        if not topo yet:
            toposort(revs)
    elif not (revs.isdescending() or revs.istopo()):
        revs.sort(reverse=True)

Good idea, that looks much better.

martinvonz updated this revision to Diff 15076.May 14 2019, 1:47 PM
pulkit accepted this revision.May 15 2019, 2:00 PM
This revision was automatically updated to reflect the committed changes.