changeset 5722:61d2f1cf90f0

branching: merge stable into default
author Pierre-Yves David <pierre-yves.david@octobus.net>
date Fri, 22 Jan 2021 11:04:55 +0100
parents 9f8ff149f258 (diff) ceaa85c47973 (current diff)
children e6b0ed34bc18
files CHANGELOG hgext3rd/evolve/evolvecmd.py hgext3rd/topic/__init__.py tests/test-evolve-content-divergent-stack.t tests/test-evolve-continue.t tests/test-evolve-issue5966.t tests/test-evolve-issue5967.t tests/test-evolve-phase.t tests/test-evolve-progress.t tests/test-evolve-public-content-divergent-discard.t tests/test-evolve-public-content-divergent-main.t tests/test-evolve-stop-orphan.t tests/test-evolve-topic.t tests/test-evolve.t tests/test-issue-5720.t tests/test-obsolete.t tests/test-prev-next.t tests/test-prune.t tests/test-topic-rebase.t tests/test-topic.t
diffstat 18 files changed, 274 insertions(+), 206 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGELOG	Wed Jan 20 14:47:22 2021 +0800
+++ b/CHANGELOG	Fri Jan 22 11:04:55 2021 +0100
@@ -10,6 +10,13 @@
 
   * rebase: prevent in-memory rebase to silently drop topic (by disable the feature)
 
+10.2.0 - in progress
+--------------------
+
+  * strip: remove experimental.prunestrip option
+
+  * performance: speed up various operations using an in-memory cache for topic
+
 10.1.0 -- 2020-10-31
 --------------------
 
--- a/hgext3rd/evolve/__init__.py	Wed Jan 20 14:47:22 2021 +0800
+++ b/hgext3rd/evolve/__init__.py	Fri Jan 22 11:04:55 2021 +0100
@@ -266,11 +266,9 @@
     help,
     hg,
     lock as lockmod,
-    logcmdutil,
-    node,
+    node as nodemod,
     pycompat,
     revset,
-    scmutil,
 )
 
 from mercurial.i18n import _
@@ -350,7 +348,6 @@
 # Configuration
 eh.configitem(b'experimental', b'evolutioncommands', [])
 eh.configitem(b'experimental', b'evolution.allnewcommands', None)
-eh.configitem(b'experimental', b'prunestrip', False)
 
 #####################################################################
 ### Option configuration                                          ###
@@ -434,7 +431,7 @@
     @eh.command(b'pstatus', pstatusopts,
                 **compat.helpcategorykwargs('CATEGORY_WORKING_DIRECTORY'))
     def pstatus(ui, repo, *args, **kwargs):
-        """show status combining committed and uncommited changes
+        """show status combining committed and uncommitted changes
 
         This show the combined status of the current working copy parent commit and
         the uncommitted change in the working copy itself. The status displayed
@@ -450,7 +447,7 @@
     @eh.command(b'pdiff', pdiffopts,
                 **compat.helpcategorykwargs('CATEGORY_WORKING_DIRECTORY'))
     def pdiff(ui, repo, *args, **kwargs):
-        """show diff combining committed and uncommited changes
+        """show diff combining committed and uncommitted changes
 
         This show the combined diff of the current working copy parent commit and
         the uncommitted change in the working copy itself. The diff displayed
@@ -655,7 +652,7 @@
     if rev.node() == prevnode and wasobs:
         return
     msg = _(b"working directory parent is obsolete! (%s)\n")
-    shortnode = node.short(rev.node())
+    shortnode = nodemod.short(rev.node())
 
     ui.warn(msg % shortnode)
 
@@ -758,7 +755,7 @@
 def _getnodefrompatch(patch, dest):
     patchnode = patch.get(b'nodeid')
     if patchnode is not None:
-        dest[b'node'] = node.bin(patchnode)
+        dest[b'node'] = nodemod.bin(patchnode)
 
 @eh.wrapfunction(mercurial.cmdutil, 'tryimportone')
 def tryimportone(orig, ui, repo, hunk, parents, opts, *args, **kwargs):
@@ -831,7 +828,7 @@
 def _getcurrenttopic(repo):
     return getattr(repo, 'currenttopic', b'')
 
-def _prevupdate(repo, displayer, target, bookmark, dryrun, mergeopt):
+def _prevupdate(repo, display, target, bookmark, dryrun, mergeopt):
     if dryrun:
         repo.ui.write(_(b'hg update %s;\n') % target)
         if bookmark is not None:
@@ -865,9 +862,9 @@
                 lockmod.release(tr, lock)
 
     if not repo.ui.quiet:
-        displayer.show(target)
+        display(target)
 
-def _findprevtarget(repo, displayer, movebookmark=False, topic=True):
+def _findprevtarget(repo, display, movebookmark=False, topic=True):
     target = bookmark = None
     wkctx = repo[None]
     p1 = wkctx.p1()
@@ -881,7 +878,7 @@
         parents = [ctx for ctx in parents if ctx.topic() == currenttopic]
 
     # issue message for the various case
-    if p1.node() == node.nullid:
+    if p1.node() == nullid:
         repo.ui.warn(_(b'already at repository root\n'))
     elif not parents and currenttopic:
         repo.ui.warn(_(b'no parent in topic "%s"\n') % currenttopic)
@@ -897,7 +894,7 @@
         choosedrev = utility.revselectionprompt(repo.ui, repo, prevs, header)
         if choosedrev is None:
             for p in parents:
-                displayer.show(p)
+                display(p)
             repo.ui.warn(_(b'multiple parents, explicitly update to one\n'))
         else:
             target = repo[choosedrev]
@@ -942,10 +939,10 @@
         if topic and hastopic:
             template = utility.stacktemplate
 
-        displayer = logcmdutil.changesetdisplayer(ui, repo,
-                                                  {b'template': template})
+        display = compat.format_changeset_summary_fn(ui, repo, b'previous',
+                                                     template)
 
-        target, bookmark = _findprevtarget(repo, displayer,
+        target, bookmark = _findprevtarget(repo, display,
                                            opts.get('move_bookmark'), topic)
         if target is not None:
             configoverride = util.nullcontextmanager()
@@ -954,7 +951,7 @@
                     (b'_internal', b'keep-topic'): b'yes'
                 }, source=b'topic-extension')
             with configoverride:
-                _prevupdate(repo, displayer, target, bookmark, dryrunopt,
+                _prevupdate(repo, display, target, bookmark, dryrunopt,
                             mergeopt)
             return 0
         else:
@@ -1001,8 +998,8 @@
             children = [ctx for ctx in children if ctx not in filtered]
             template = utility.stacktemplate
             opts['stacktemplate'] = True
-        displayer = logcmdutil.changesetdisplayer(ui, repo,
-                                                  {b'template': template})
+        display = compat.format_changeset_summary_fn(ui, repo, b'next',
+                                                     template)
 
         # check if we need to evolve while updating to the next child revision
         needevolve = False
@@ -1038,7 +1035,7 @@
 
         if len(children) == 1:
             c = children[0]
-            return _updatetonext(ui, repo, c, displayer, opts)
+            return _updatetonext(ui, repo, c, display, opts)
         elif children:
             cheader = _(b"ambiguous next changeset, choose one to update:")
             crevs = [c.rev() for c in children]
@@ -1046,11 +1043,11 @@
             if choosedrev is None:
                 ui.warn(_(b"ambiguous next changeset:\n"))
                 for c in children:
-                    displayer.show(c)
+                    display(c)
                 ui.warn(_(b"explicitly update to one of them\n"))
                 return 1
             else:
-                return _updatetonext(ui, repo, repo[choosedrev], displayer, opts)
+                return _updatetonext(ui, repo, repo[choosedrev], display, opts)
         else:
             if not opts['evolve'] or not aspchildren:
                 if filtered:
@@ -1071,7 +1068,7 @@
                 if choosedrev is None:
                     ui.warn(_(b"ambiguous next (unstable) changeset:\n"))
                     for c in aspchildren:
-                        displayer.show(repo[c])
+                        display(repo[c])
                     ui.warn(_(b"(run 'hg evolve --rev REV' on one of them)\n"))
                     return 1
                 else:
@@ -1102,7 +1099,7 @@
                   % ui.label(bytes(repo[b'.']), b'evolve.node'))
     return 0
 
-def _updatetonext(ui, repo, child, displayer, opts):
+def _updatetonext(ui, repo, child, display, opts):
     """ logic for `hg next` command to update to children and move bookmarks if
     required """
     bm = repo._activebookmark
@@ -1139,7 +1136,7 @@
             finally:
                 lockmod.release(tr, lock)
     if not ui.quiet:
-        displayer.show(child)
+        display(child)
     return 0
 
 @eh.wrapcommand(b'commit')
@@ -1179,41 +1176,6 @@
     finally:
         lockmod.release(tr, lock, wlock)
 
-try:
-    from mercurial import strip
-    strip
-    stripcmd = b'debugstrip'
-    stripext = None
-except ImportError:
-    # hg <= 5.6 (d7a508a75d72)
-    stripcmd = b'strip'
-    stripext = b'strip'
-
-@eh.wrapcommand(stripcmd, extension=stripext, opts=[
-    (b'', b'bundle', None, _(b"delete the commit entirely and move it to a "
-                             b"backup bundle")),
-    ])
-def stripwrapper(orig, ui, repo, *revs, **kwargs):
-    if (not ui.configbool(b'experimental', b'prunestrip')
-        or kwargs.get('bundle', False)):
-        return orig(ui, repo, *revs, **kwargs)
-
-    if kwargs.get('force'):
-        ui.warn(_(b"warning: --force has no effect during strip with evolve "
-                  b"enabled\n"))
-    if kwargs.get('no_backup', False):
-        ui.warn(_(b"warning: --no-backup has no effect during strips with "
-                  b"evolve enabled\n"))
-
-    revs = list(revs) + kwargs.pop('rev', [])
-    revs = set(scmutil.revrange(repo, revs))
-    revs = repo.revs(b"(%ld)::", revs)
-    kwargs['rev'] = []
-    kwargs['new'] = []
-    kwargs['successor'] = []
-    kwargs['biject'] = False
-    return cmdrewrite.cmdprune(ui, repo, *revs, **kwargs)
-
 @eh.extsetup
 def oldevolveextsetup(ui):
     entry = cmdutil.findcmd(b'commit', commands.table)[1]
@@ -1230,7 +1192,7 @@
     if r'debugobsconvert' in sys.argv:
         return
     for mark in markers:
-        if node.nullid in mark[1]:
+        if nullid in mark[1]:
             msg = _(b'bad obsolescence marker detected: invalid successors nullid')
             hint = _(b'You should run `hg debugobsconvert`')
             raise error.Abort(msg, hint=hint)
--- a/hgext3rd/evolve/cmdrewrite.py	Wed Jan 20 14:47:22 2021 +0800
+++ b/hgext3rd/evolve/cmdrewrite.py	Fri Jan 22 11:04:55 2021 +0100
@@ -22,7 +22,6 @@
     error,
     hg,
     lock as lockmod,
-    logcmdutil,
     merge,
     node,
     obsolete,
@@ -1334,9 +1333,9 @@
         with ui.configoverride(overrides, b'touch'):
             rewriteutil.precheck(repo, revs, b'touch')
     tmpl = utility.shorttemplate
-    displayer = logcmdutil.changesetdisplayer(ui, repo, {b'template': tmpl})
+    display = compat.format_changeset_summary_fn(ui, repo, b'touch', tmpl)
     with repo.wlock(), repo.lock(), repo.transaction(b'touch'):
-        touchnodes(ui, repo, revs, displayer, **opts)
+        touchnodes(ui, repo, revs, display, **opts)
 
 def touchnodes(ui, repo, revs, displayer, **opts):
     duplicate = opts['duplicate']
@@ -1355,7 +1354,7 @@
 
         if not (duplicate or allowdivergence):
             if precheck_contentdiv(repo, ctx):
-                displayer.show(ctx)
+                displayer(ctx)
                 index = ui.promptchoice(
                     _(b"reviving this changeset will create divergence"
                       b" unless you make a duplicate.\n(a)llow divergence or"
--- a/hgext3rd/evolve/compat.py	Wed Jan 20 14:47:22 2021 +0800
+++ b/hgext3rd/evolve/compat.py	Fri Jan 22 11:04:55 2021 +0100
@@ -10,9 +10,11 @@
 import contextlib
 
 from mercurial import (
+    cmdutil,
     context,
     copies,
     hg,
+    logcmdutil,
     merge as mergemod,
     obsolete,
     pycompat,
@@ -426,3 +428,16 @@
 
     scmutil.cleanupnodes(repo, replacements=fixedreplacements, operation=operation,
                          moves=moves, metadata=metadata)
+
+if util.safehasattr(cmdutil, 'format_changeset_summary'):
+    def format_changeset_summary_fn(ui, repo, command, default_spec):
+        def show(ctx):
+            text = cmdutil.format_changeset_summary(ui, ctx, command=command,
+                                                    default_spec=default_spec)
+            ui.write(b'%s\n' % text)
+        return show
+else:
+    # hg <= 5.6 (96fcc37a9c80)
+    def format_changeset_summary_fn(ui, repo, command, default_spec):
+        logcmdutil.changesetdisplayer(ui, repo,
+                                      {b'template': default_spec}).show
--- a/hgext3rd/evolve/evolvecmd.py	Wed Jan 20 14:47:22 2021 +0800
+++ b/hgext3rd/evolve/evolvecmd.py	Fri Jan 22 11:04:55 2021 +0100
@@ -19,7 +19,6 @@
     encoding,
     error,
     hg,
-    logcmdutil,
     merge,
     mergeutil,
     node as nodemod,
@@ -67,27 +66,26 @@
     """
     tr = repo.currenttransaction()
     assert tr is not None
-    displayer = None
     template = shorttemplate
     if stacktmplt:
         template = stacktemplate
-    displayer = logcmdutil.changesetdisplayer(ui, repo,
-                                              {b'template': template})
+    display = compat.format_changeset_summary_fn(ui, repo, b'evolve',
+                                                 template)
     if b'orphan' == category:
-        result = _solveorphan(ui, repo, ctx, evolvestate, displayer,
+        result = _solveorphan(ui, repo, ctx, evolvestate, display,
                               dryrun, confirm, progresscb)
     elif b'phasedivergent' == category:
         result = _solvephasedivergence(ui, repo, ctx, evolvestate,
-                                       displayer, dryrun, confirm,
+                                       display, dryrun, confirm,
                                        progresscb)
     elif b'contentdivergent' == category:
-        result = _solvedivergent(ui, repo, ctx, evolvestate, displayer,
+        result = _solvedivergent(ui, repo, ctx, evolvestate, display,
                                  dryrun, confirm, progresscb)
     else:
         assert False, b"unknown trouble category: %s" % (category)
     return result
 
-def _solveorphan(ui, repo, orig, evolvestate, displayer, dryrun=False,
+def _solveorphan(ui, repo, orig, evolvestate, display, dryrun=False,
                  confirm=False, progresscb=None):
     """ Tries to stabilize the changeset orig which is orphan.
 
@@ -145,13 +143,13 @@
     target = repo[newer]
     if not ui.quiet or confirm:
         repo.ui.write(_(b'move:'), label=b'evolve.operation')
-        displayer.show(orig)
+        display(orig)
         # lastsolved: keep track of successor of last troubled cset we evolved
         # to confirm that if atop msg should be suppressed to remove redundancy
         lastsolved = evolvestate.get(b'lastsolved')
         if lastsolved is None or target != repo[lastsolved]:
             repo.ui.write(_(b'atop:'))
-            displayer.show(target)
+            display(target)
     if confirm and ui.prompt(b'perform evolve? [Ny]', b'n') != b'y':
         raise error.Abort(_(b'evolve aborted by user'))
     todo = b'hg rebase -r %s -d %s\n' % (orig, target)
@@ -169,7 +167,7 @@
                               keepbranch, b'orphan')
             return (True, newid)
 
-def _solvephasedivergence(ui, repo, bumped, evolvestate, displayer,
+def _solvephasedivergence(ui, repo, bumped, evolvestate, display,
                           dryrun=False, confirm=False, progresscb=None):
     """Stabilize a phase divergent changeset
 
@@ -196,9 +194,9 @@
 
     if not ui.quiet or confirm:
         repo.ui.write(_(b'recreate:'), label=b'evolve.operation')
-        displayer.show(bumped)
+        display(bumped)
         repo.ui.write(_(b'atop:'))
-        displayer.show(prec)
+        display(prec)
     if confirm and ui.prompt(_(b'perform evolve? [Ny]'), b'n') != b'y':
         raise error.Abort(_(b'evolve aborted by user'))
     if dryrun:
@@ -421,7 +419,7 @@
     with state.saver(evolvestate, {b'current': orig.node()}), configoverride:
         return _relocate(repo, orig, dest, evolvestate, keepbranch=True)
 
-def _solvedivergent(ui, repo, divergent, evolvestate, displayer, dryrun=False,
+def _solvedivergent(ui, repo, divergent, evolvestate, display, dryrun=False,
                     confirm=False, progresscb=None):
     """tries to solve content-divergence of a changeset
 
@@ -487,11 +485,11 @@
 
     if not ui.quiet or confirm:
         ui.write(_(b'merge:'), label=b'evolve.operation')
-        displayer.show(divergent)
+        display(divergent)
         ui.write(_(b'with: '))
-        displayer.show(other)
+        display(other)
         ui.write(_(b'base: '))
-        displayer.show(base)
+        display(base)
     if confirm and ui.prompt(_(b'perform evolve? [Ny]'), b'n') != b'y':
         raise error.Abort(_(b'evolve aborted by user'))
     if dryrun:
@@ -958,8 +956,6 @@
         raise error.InterventionRequired(_(b"unresolved merge conflicts"),
                                          hint=hint)
 
-    if commitmsg is None:
-        commitmsg = orig.description()
     extra = dict(orig.extra())
     if b'branch' in extra:
         del extra[b'branch']
@@ -1714,8 +1710,8 @@
     oldid = repo[b'.'].node()
     startctx = repo[b'.']
     dryrunopt = opts.get('dry_run', False)
-    displayer = logcmdutil.changesetdisplayer(ui, repo,
-                                              {b'template': shorttemplate})
+    display = compat.format_changeset_summary_fn(ui, repo, b'evolve',
+                                                 shorttemplate)
     try:
         ctx = repo[utility._singlesuccessor(repo, repo[b'.'])]
     except utility.MultipleSuccessorsError as exc:
@@ -1723,12 +1719,12 @@
                             b' successors:\n'))
         for ln in exc.successorssets:
             for n in ln:
-                displayer.show(repo[n])
+                display(repo[n])
         return 2
 
     ui.status(_(b'update:'))
     if not ui.quiet:
-        displayer.show(ctx)
+        display(ctx)
 
     if dryrunopt:
         return 0
--- a/hgext3rd/evolve/headchecking.py	Wed Jan 20 14:47:22 2021 +0800
+++ b/hgext3rd/evolve/headchecking.py	Fri Jan 22 11:04:55 2021 +0100
@@ -140,12 +140,14 @@
     while old_heads:
         rh = old_heads.pop()
         ctx = repo[rh]
-        current_name = _get_branch_name(ctx)
+
         # run this check early to skip the evaluation of the whole branch
         if not ctx.obsolete():
             new_heads.append(rh)
             continue
 
+        current_name = _get_branch_name(ctx)
+
         # Get all revs/nodes on the branch exclusive to this head
         # (already filtered heads are "ignored"))
         sections_revs = repo.revs(
--- a/hgext3rd/evolve/metadata.py	Wed Jan 20 14:47:22 2021 +0800
+++ b/hgext3rd/evolve/metadata.py	Fri Jan 22 11:04:55 2021 +0100
@@ -5,7 +5,7 @@
 # This software may be used and distributed according to the terms of the
 # GNU General Public License version 2 or any later version.
 
-__version__ = b'10.1.1.dev'
+__version__ = b'10.2.0.dev'
 testedwith = b'4.6.2 4.7 4.8 4.9 5.0 5.1 5.2 5.3 5.4 5.5 5.6'
 minimumhgversion = b'4.6'
 buglink = b'https://bz.mercurial-scm.org/'
--- a/hgext3rd/topic/__init__.py	Wed Jan 20 14:47:22 2021 +0800
+++ b/hgext3rd/topic/__init__.py	Fri Jan 22 11:04:55 2021 +0100
@@ -232,7 +232,7 @@
               b'topic.active': b'green',
               }
 
-__version__ = b'0.20.1.dev'
+__version__ = b'0.21.0.dev'
 
 testedwith = b'4.6.2 4.7 4.8 4.9 5.0 5.1 5.2 5.3 5.4 5.5 5.6'
 minimumhgversion = b'4.6'
@@ -294,7 +294,16 @@
 def _contexttopic(self, force=False):
     if not (force or self.mutable()):
         return b''
-    return self.extra().get(constants.extrakey, b'')
+    cache = getattr(self._repo, '_topiccache', None)
+    # topic loaded, but not enabled (eg: multiple repo in the same process)
+    if cache is None:
+        return b''
+    topic = cache.get(self.rev())
+    if topic is None:
+        topic = self.extra().get(constants.extrakey, b'')
+        self._repo._topiccache[self.rev()] = topic
+    return topic
+
 context.basectx.topic = _contexttopic
 
 def _contexttopicidx(self):
@@ -362,6 +371,10 @@
         return [t]
     return []
 
+def wrap_summary(orig, ui, repo, *args, **kwargs):
+    with discovery.override_context_branch(repo) as repo:
+        return orig(ui, repo, *args, **kwargs)
+
 def uisetup(ui):
     destination.modsetup(ui)
     discovery.modsetup(ui)
@@ -397,6 +410,8 @@
     # plug into logic for this into mergemod.update().
     extensions.wrapcommand(commands.table, b'update', checkt0)
 
+    extensions.wrapcommand(commands.table, b'summary', wrap_summary)
+
     try:
         evolve = extensions.find(b'evolve')
         extensions.wrapfunction(evolve.rewriteutil, "presplitupdate",
@@ -487,6 +502,10 @@
                 del ctx.extra()[constants.extrakey]
             return super(topicrepo, self).commitctx(ctx, *args, **kwargs)
 
+        @util.propertycache
+        def _topiccache(self):
+            return {}
+
         @property
         def topics(self):
             if self._topics is not None:
@@ -516,8 +535,8 @@
         def branchheads(self, branch=None, start=None, closed=False):
             if branch is None:
                 branch = self[None].branch()
-            if self.currenttopic:
-                branch = b"%s:%s" % (branch, self.currenttopic)
+                if self.currenttopic:
+                    branch = b"%s:%s" % (branch, self.currenttopic)
             return super(topicrepo, self).branchheads(branch=branch,
                                                       start=start,
                                                       closed=closed)
--- a/hgext3rd/topic/discovery.py	Wed Jan 20 14:47:22 2021 +0800
+++ b/hgext3rd/topic/discovery.py	Fri Jan 22 11:04:55 2021 +0100
@@ -1,6 +1,7 @@
 from __future__ import absolute_import
 
 import collections
+import contextlib
 import weakref
 
 from mercurial.i18n import _
@@ -20,6 +21,80 @@
 
 from mercurial import wireprotov1server
 
+@contextlib.contextmanager
+def override_context_branch(repo, publishedset=()):
+    unfi = repo.unfiltered()
+
+    class repocls(unfi.__class__):
+        # awful hack to see branch as "branch:topic"
+        def __getitem__(self, key):
+            ctx = super(repocls, self).__getitem__(key)
+            oldbranch = ctx.branch
+            oldparents = ctx.parents
+            rev = ctx.rev()
+
+            def branch():
+                branch = oldbranch()
+                if rev in publishedset:
+                    return branch
+                topic = ctx.topic()
+                if topic:
+                    branch = b"%s:%s" % (branch, topic)
+                return branch
+
+            def parents():
+                parents = oldparents()
+                for p in parents:
+                    if getattr(p, '_topic_ext_branch_hack', False):
+                        continue
+                    pbranch = p.branch
+
+                    def branch():
+                        branch = pbranch()
+                        if p.rev() in publishedset:
+                            return branch
+                        topic = p.topic()
+                        if topic:
+                            branch = b"%s:%s" % (branch, topic)
+                        return branch
+                    p.branch = branch
+                    p._topic_ext_branch_hack = True
+                return parents
+
+            ctx.branch = branch
+            ctx.parents = parents
+            return ctx
+
+        def revbranchcache(self):
+            rbc = super(repocls, self).revbranchcache()
+            localchangelog = self.changelog
+
+            def branchinfo(rev, changelog=None):
+                if changelog is None:
+                    changelog = localchangelog
+                branch, close = changelog.branchinfo(rev)
+                if rev in publishedset:
+                    return branch, close
+                topic = unfi[rev].topic()
+                if topic:
+                    branch = b"%s:%s" % (branch, topic)
+                return branch, close
+
+            rbc.branchinfo = branchinfo
+            return rbc
+
+    oldrepocls = unfi.__class__
+    try:
+        unfi.__class__ = repocls
+        if repo.filtername is not None:
+            repo = unfi.filtered(repo.filtername)
+        else:
+            repo = unfi
+        yield repo
+    finally:
+        unfi.__class__ = oldrepocls
+
+
 def _headssummary(orig, pushop, *args, **kwargs):
     repo = pushop.repo.unfiltered()
     remote = pushop.remote
@@ -61,63 +136,24 @@
             heads.sort()
         return result
 
-    class repocls(repo.__class__):
-        # awful hack to see branch as "branch:topic"
-        def __getitem__(self, key):
-            ctx = super(repocls, self).__getitem__(key)
-            oldbranch = ctx.branch
-            rev = ctx.rev()
-
-            def branch():
-                branch = oldbranch()
-                if rev in publishedset:
-                    return branch
-                topic = ctx.topic()
-                if topic:
-                    branch = b"%s:%s" % (branch, topic)
-                return branch
-
-            ctx.branch = branch
-            return ctx
-
-        def revbranchcache(self):
-            rbc = super(repocls, self).revbranchcache()
-            localchangelog = self.changelog
-
-            def branchinfo(rev, changelog=None):
-                if changelog is None:
-                    changelog = localchangelog
-                branch, close = changelog.branchinfo(rev)
-                if rev in publishedset:
-                    return branch, close
-                topic = repo[rev].topic()
-                if topic:
-                    branch = b"%s:%s" % (branch, topic)
-                return branch, close
-
-            rbc.branchinfo = branchinfo
-            return rbc
-
-    oldrepocls = repo.__class__
-    try:
-        repo.__class__ = repocls
-        if remotebranchmap is not None:
-            remote.branchmap = remotebranchmap
-        unxx = repo.filtered(b'unfiltered-topic')
-        repo.unfiltered = lambda: unxx
-        pushop.repo = repo
-        summary = orig(pushop)
-        for key, value in summary.items():
-            if b':' in key: # This is a topic
-                if value[0] is None and value[1]:
-                    summary[key] = ([value[1][0]], ) + value[1:]
-        return summary
-    finally:
-        if r'unfiltered' in vars(repo):
-            del repo.unfiltered
-        repo.__class__ = oldrepocls
-        if remotebranchmap is not None:
-            remote.branchmap = origremotebranchmap
+    with override_context_branch(repo, publishedset=publishedset):
+        try:
+            if remotebranchmap is not None:
+                remote.branchmap = remotebranchmap
+            unxx = repo.filtered(b'unfiltered-topic')
+            repo.unfiltered = lambda: unxx
+            pushop.repo = repo
+            summary = orig(pushop)
+            for key, value in summary.items():
+                if b':' in key: # This is a topic
+                    if value[0] is None and value[1]:
+                        summary[key] = ([value[1][0]], ) + value[1:]
+            return summary
+        finally:
+            if r'unfiltered' in vars(repo):
+                del repo.unfiltered
+            if remotebranchmap is not None:
+                remote.branchmap = origremotebranchmap
 
 def wireprotobranchmap(orig, repo, proto):
     if not common.hastopicext(repo):
--- a/hgext3rd/topic/evolvebits.py	Wed Jan 20 14:47:22 2021 +0800
+++ b/hgext3rd/topic/evolvebits.py	Fri Jan 22 11:04:55 2021 +0100
@@ -6,41 +6,6 @@
 
 # Copied from evolve 081605c2e9b6
 
-def _orderrevs(repo, revs):
-    """Compute an ordering to solve instability for the given revs
-
-    revs is a list of unstable revisions.
-
-    Returns the same revisions ordered to solve their instability from the
-    bottom to the top of the stack that the stabilization process will produce
-    eventually.
-
-    This ensures the minimal number of stabilizations, as we can stabilize each
-    revision on its final stabilized destination.
-    """
-    # Step 1: Build the dependency graph
-    dependencies, rdependencies = builddependencies(repo, revs)
-    # Step 2: Build the ordering
-    # Remove the revisions with no dependency(A) and add them to the ordering.
-    # Removing these revisions leads to new revisions with no dependency (the
-    # one depending on A) that we can remove from the dependency graph and add
-    # to the ordering. We progress in a similar fashion until the ordering is
-    # built
-    solvablerevs = [r for r in sorted(dependencies.keys())
-                    if not dependencies[r]]
-    ordering = []
-    while solvablerevs:
-        rev = solvablerevs.pop()
-        for dependent in rdependencies[rev]:
-            dependencies[dependent].remove(rev)
-            if not dependencies[dependent]:
-                solvablerevs.append(dependent)
-        del dependencies[rev]
-        ordering.append(rev)
-
-    ordering.extend(sorted(dependencies))
-    return ordering
-
 def builddependencies(repo, revs):
     """returns dependency graphs giving an order to solve instability of revs
     (see _orderrevs for more information on usage)"""
--- a/tests/test-evolve.t	Wed Jan 20 14:47:22 2021 +0800
+++ b/tests/test-evolve.t	Fri Jan 22 11:04:55 2021 +0100
@@ -460,6 +460,23 @@
 
 (/ninja)
 
+command-templates.oneline-summary is respected when evolving orphan
+
+  $ hg evolve -n --config 'command-templates.oneline-summary = custom {rev} {desc}'
+  move:custom 8 dansk 2!
+  atop:custom 10 dansk!
+  hg rebase -r 569625323d3e -d 9975c016fe7b
+  skipping 8163b3ed62c7, consider including orphan ancestors
+
+command-templates.oneline-summary is respected when evolving/updating working copy
+
+  $ hg co -q 7
+  working directory parent is obsolete! (aca219761afb)
+  $ hg evolve --no-all --config 'command-templates.oneline-summary = custom {rev} {desc}'
+  update:custom 10 dansk!
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  working directory is now at 9975c016fe7b
+
   $ hg evolve --all --traceback
   move:[8] dansk 2!
   atop:[10] dansk!
--- a/tests/test-prune.t	Wed Jan 20 14:47:22 2021 +0800
+++ b/tests/test-prune.t	Fri Jan 22 11:04:55 2021 +0100
@@ -257,25 +257,12 @@
   14:21b6f2f1cece[] (obsolete/draft) add n2
   12:6e8148413dd5[prune-pair-book] (draft) add nE
 
-test hg strip replacement
-
+test hg prune --keep
   $ hg up 10
   0 files updated, 0 files merged, 2 files removed, 0 files unresolved
   (leaving bookmark prune-pair-book)
   $ mkcommit n1
   created new head
-  $ mkcommit n2
-  $ hg --config extensions.strip= --config experimental.prunestrip=True strip -r .
-  0 files updated, 0 files merged, 1 files removed, 0 files unresolved
-  working directory is now at c7e58696a948
-  1 changesets pruned
-  $ hg --config extensions.strip= --config experimental.prunestrip=True strip -r . --bundle
-  0 files updated, 0 files merged, 1 files removed, 0 files unresolved
-  saved backup bundle to $TESTTMP/repo/.hg/strip-backup/c7e58696a948-69ca36d3-backup.hg (glob)
-
-test hg prune --keep
-  $ mkcommit n1
-  created new head
   $ hg diff -r .^
   diff -r aa96dc3f04c2 n1
   --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
--- a/tests/test-split.t	Wed Jan 20 14:47:22 2021 +0800
+++ b/tests/test-split.t	Fri Jan 22 11:04:55 2021 +0100
@@ -442,7 +442,7 @@
   $ hg summary
   parent: 18:26f72cfaf036 tip
    Works on mytopic
-  branch: new-branch
+  branch: new-branch:mytopic
   commit: 2 unknown (clean)
   update: (current)
   phases: 9 draft
--- a/tests/test-topic-fold.t	Wed Jan 20 14:47:22 2021 +0800
+++ b/tests/test-topic-fold.t	Fri Jan 22 11:04:55 2021 +0100
@@ -65,7 +65,7 @@
   $ hg summary
   parent: 3:4fd43e5bdc44 tip
    folded
-  branch: default
+  branch: default:myfeature
   commit: (clean)
   update: (current)
   phases: 2 draft
--- a/tests/test-topic-stack-data.t	Wed Jan 20 14:47:22 2021 +0800
+++ b/tests/test-topic-stack-data.t	Fri Jan 22 11:04:55 2021 +0100
@@ -114,7 +114,7 @@
   $ hg summary
   parent: 21:3e54b49a3113 tip
    add foo_b
-  branch: lake
+  branch: lake:foo
   commit: (clean)
   update: (current)
   phases: 22 draft
--- a/tests/test-topic-stack.t	Wed Jan 20 14:47:22 2021 +0800
+++ b/tests/test-topic-stack.t	Fri Jan 22 11:04:55 2021 +0100
@@ -313,7 +313,7 @@
   $ hg summary
   parent: 3:e629654d7050 
    c_d
-  branch: default
+  branch: default:foo
   commit: (clean)
   update: 2 new changesets (update)
   phases: 4 draft
--- a/tests/test-topic-tutorial.t	Wed Jan 20 14:47:22 2021 +0800
+++ b/tests/test-topic-tutorial.t	Fri Jan 22 11:04:55 2021 +0100
@@ -108,8 +108,8 @@
   $ hg summary
   parent: 0:38da43f0a2ea tip
    Shopping list
-  branch: default
-  commit: (clean)
+  branch: default:food
+  commit: (new branch)
   update: (current)
   topic:  food
 
--- a/tests/test-topic.t	Wed Jan 20 14:47:22 2021 +0800
+++ b/tests/test-topic.t	Fri Jan 22 11:04:55 2021 +0100
@@ -1166,4 +1166,67 @@
   tip                                3:9efc5c3ac635
   1.0                                2:3bbb3fdb2546
 
+test that being on active topic does not change output of `hg heads`
+
+  $ hg up 0
+  0 files updated, 0 files merged, 2 files removed, 0 files unresolved
+  $ echo c > c
+  $ hg ci -Am "added c" --config experimental.topic-mode=default
+  adding c
+  $ hg log -G -T '{rev} {branch}{if("{topic}", "/{topic}")}\n' --rev 'all()'
+  @  4 default
+  |
+  | o  3 default/foo
+  | |
+  | o  2 default/foo
+  |/
+  o  0 default
+  
+  $ hg heads
+  changeset:   4:29edef26570b
+  tag:         tip
+  parent:      0:9092f1db7931
+  user:        test
+  date:        Thu Jan 01 00:00:00 1970 +0000
+  summary:     added c
+  
+  changeset:   3:9efc5c3ac635
+  topic:       foo
+  user:        test
+  date:        Thu Jan 01 00:00:00 1970 +0000
+  summary:     Added tag 1.0 for changeset 3bbb3fdb2546
+  
+  $ hg topic foo
+  marked working directory as topic: foo
+  $ hg heads
+  changeset:   4:29edef26570b
+  tag:         tip
+  parent:      0:9092f1db7931
+  user:        test
+  date:        Thu Jan 01 00:00:00 1970 +0000
+  summary:     added c
+  
+  changeset:   3:9efc5c3ac635
+  topic:       foo
+  user:        test
+  date:        Thu Jan 01 00:00:00 1970 +0000
+  summary:     Added tag 1.0 for changeset 3bbb3fdb2546
+  
+
+  $ hg up foo
+  2 files updated, 0 files merged, 1 files removed, 0 files unresolved
+  $ hg heads
+  changeset:   4:29edef26570b
+  tag:         tip
+  parent:      0:9092f1db7931
+  user:        test
+  date:        Thu Jan 01 00:00:00 1970 +0000
+  summary:     added c
+  
+  changeset:   3:9efc5c3ac635
+  topic:       foo
+  user:        test
+  date:        Thu Jan 01 00:00:00 1970 +0000
+  summary:     Added tag 1.0 for changeset 3bbb3fdb2546
+  
   $ cd ..