changeset 40512:4fe63b573791

merge with stable
author Augie Fackler <augie@google.com>
date Fri, 02 Nov 2018 14:24:29 -0400
parents c2a0bc6412db (diff) 5eaa5eb0db4e (current diff)
children c7618901584d
files hgext/sqlitestore.py mercurial/cext/revlog.c mercurial/configitems.py mercurial/help.py mercurial/revlog.py mercurial/utils/storageutil.py
diffstat 43 files changed, 699 insertions(+), 324 deletions(-) [+]
line wrap: on
line diff
--- a/contrib/python3-whitelist	Fri Nov 02 14:18:29 2018 -0400
+++ b/contrib/python3-whitelist	Fri Nov 02 14:24:29 2018 -0400
@@ -261,6 +261,7 @@
 test-identify.t
 test-impexp-branch.t
 test-import-bypass.t
+test-import-context.t
 test-import-eol.t
 test-import-merge.t
 test-import-unknown.t
@@ -308,6 +309,7 @@
 test-linerange.py
 test-locate.t
 test-lock-badness.t
+test-log-exthook.t
 test-log-linerange.t
 test-log.t
 test-logexchange.t
--- a/hgext/beautifygraph.py	Fri Nov 02 14:18:29 2018 -0400
+++ b/hgext/beautifygraph.py	Fri Nov 02 14:24:29 2018 -0400
@@ -31,8 +31,6 @@
 def prettyedge(before, edge, after):
     if edge == '~':
         return '\xE2\x95\xA7' # U+2567 ╧
-    if edge == 'X':
-        return '\xE2\x95\xB3' # U+2573 ╳
     if edge == '/':
         return '\xE2\x95\xB1' # U+2571 ╱
     if edge == '-':
--- a/hgext/blackbox.py	Fri Nov 02 14:18:29 2018 -0400
+++ b/hgext/blackbox.py	Fri Nov 02 14:24:29 2018 -0400
@@ -33,6 +33,11 @@
   # rotate up to N log files when the current one gets too big
   maxfiles = 3
 
+  [blackbox]
+  # Include nanoseconds in log entries with %f (see Python function
+  # datetime.datetime.strftime)
+  date-format = '%Y-%m-%d @ %H:%M:%S.%f'
+
 """
 
 from __future__ import absolute_import
@@ -82,6 +87,9 @@
 configitem('blackbox', 'track',
     default=lambda: ['*'],
 )
+configitem('blackbox', 'date-format',
+    default='%Y/%m/%d %H:%M:%S',
+)
 
 lastui = None
 
@@ -169,7 +177,8 @@
                 return
             ui._bbinlog = True
             default = self.configdate('devel', 'default-date')
-            date = dateutil.datestr(default, '%Y/%m/%d %H:%M:%S')
+            date = dateutil.datestr(default,
+                                    ui.config('blackbox', 'date-format'))
             user = procutil.getuser()
             pid = '%d' % procutil.getpid()
             formattedmsg = msg[0] % msg[1:]
--- a/hgext/extdiff.py	Fri Nov 02 14:18:29 2018 -0400
+++ b/hgext/extdiff.py	Fri Nov 02 14:24:29 2018 -0400
@@ -139,7 +139,7 @@
         repo.ui.setconfig("ui", "archivemeta", False)
 
         archival.archive(repo, base, node, 'files',
-                         matchfn=scmutil.matchfiles(repo, files),
+                         match=scmutil.matchfiles(repo, files),
                          subrepos=listsubrepos)
 
         for fn in sorted(files):
--- a/hgext/largefiles/overrides.py	Fri Nov 02 14:18:29 2018 -0400
+++ b/hgext/largefiles/overrides.py	Fri Nov 02 14:24:29 2018 -0400
@@ -929,12 +929,12 @@
     finally:
         web.repo.lfstatus = False
 
-def overridearchive(orig, repo, dest, node, kind, decode=True, matchfn=None,
+def overridearchive(orig, repo, dest, node, kind, decode=True, match=None,
             prefix='', mtime=None, subrepos=None):
     # For some reason setting repo.lfstatus in hgwebarchive only changes the
     # unfiltered repo's attr, so check that as well.
     if not repo.lfstatus and not repo.unfiltered().lfstatus:
-        return orig(repo, dest, node, kind, decode, matchfn, prefix, mtime,
+        return orig(repo, dest, node, kind, decode, match, prefix, mtime,
                     subrepos)
 
     # No need to lock because we are only reading history and
@@ -955,7 +955,7 @@
         prefix = archival.tidyprefix(dest, kind, prefix)
 
     def write(name, mode, islink, getdata):
-        if matchfn and not matchfn(name):
+        if match and not match(name):
             return
         data = getdata()
         if decode:
@@ -991,7 +991,7 @@
     if subrepos:
         for subpath in sorted(ctx.substate):
             sub = ctx.workingsub(subpath)
-            submatch = matchmod.subdirmatcher(subpath, matchfn)
+            submatch = matchmod.subdirmatcher(subpath, match)
             sub._repo.lfstatus = True
             sub.archive(archiver, prefix, submatch)
 
--- a/hgext/narrow/narrowcommands.py	Fri Nov 02 14:18:29 2018 -0400
+++ b/hgext/narrow/narrowcommands.py	Fri Nov 02 14:24:29 2018 -0400
@@ -392,9 +392,21 @@
     removedincludes = narrowspec.parsepatterns(opts['removeinclude'])
     addedexcludes = narrowspec.parsepatterns(opts['addexclude'])
     removedexcludes = narrowspec.parsepatterns(opts['removeexclude'])
+
+    only_show = not (addedincludes or removedincludes or addedexcludes or
+                     removedexcludes or newrules)
+
+    oldincludes, oldexcludes = repo.narrowpats
+
+    # filter the user passed additions and deletions into actual additions and
+    # deletions of excludes and includes
+    addedincludes -= oldincludes
+    removedincludes &= oldincludes
+    addedexcludes -= oldexcludes
+    removedexcludes &= oldexcludes
+
     widening = addedincludes or removedexcludes
     narrowing = removedincludes or addedexcludes
-    only_show = not widening and not narrowing
 
     # Only print the current narrowspec.
     if only_show:
@@ -413,6 +425,10 @@
         fm.end()
         return 0
 
+    if not widening and not narrowing:
+        ui.status(_("nothing to widen or narrow\n"))
+        return 0
+
     with repo.wlock(), repo.lock():
         cmdutil.bailifchanged(repo)
 
@@ -432,7 +448,6 @@
 
         commoninc = discovery.findcommonincoming(repo, remote)
 
-        oldincludes, oldexcludes = repo.narrowpats
         if narrowing:
             newincludes = oldincludes - removedincludes
             newexcludes = oldexcludes | addedexcludes
--- a/hgext/sqlitestore.py	Fri Nov 02 14:18:29 2018 -0400
+++ b/hgext/sqlitestore.py	Fri Nov 02 14:24:29 2018 -0400
@@ -63,6 +63,7 @@
 from mercurial import (
     ancestor,
     dagop,
+    encoding,
     error,
     extensions,
     localrepo,
@@ -558,7 +559,8 @@
         return not storageutil.filedataequivalent(self, node, fulltext)
 
     def emitrevisions(self, nodes, nodesorder=None, revisiondata=False,
-                      assumehaveparentrevisions=False, deltaprevious=False):
+                      assumehaveparentrevisions=False,
+                      deltamode=repository.CG_DELTAMODE_STD):
         if nodesorder not in ('nodes', 'storage', 'linear', None):
             raise error.ProgrammingError('unhandled value for nodesorder: %s' %
                                          nodesorder)
@@ -589,7 +591,7 @@
             deltaparentfn=deltabases.__getitem__,
             revisiondata=revisiondata,
             assumehaveparentrevisions=assumehaveparentrevisions,
-            deltaprevious=deltaprevious):
+            deltamode=deltamode):
 
             yield delta
 
@@ -1020,7 +1022,7 @@
 def makedb(path):
     """Construct a database handle for a database at path."""
 
-    db = sqlite3.connect(path)
+    db = sqlite3.connect(encoding.strfromlocal(path))
     db.text_factory = bytes
 
     res = db.execute(r'PRAGMA user_version').fetchone()[0]
--- a/mercurial/archival.py	Fri Nov 02 14:18:29 2018 -0400
+++ b/mercurial/archival.py	Fri Nov 02 14:24:29 2018 -0400
@@ -274,7 +274,7 @@
     'zip': zipit,
     }
 
-def archive(repo, dest, node, kind, decode=True, matchfn=None,
+def archive(repo, dest, node, kind, decode=True, match=None,
             prefix='', mtime=None, subrepos=False):
     '''create archive of repo as it was at node.
 
@@ -286,7 +286,7 @@
     decode tells whether to put files through decode filters from
     hgrc.
 
-    matchfn is function to filter names of files to write to archive.
+    match is a matcher to filter names of files to write to archive.
 
     prefix is name of path to put before every archive member.
 
@@ -313,15 +313,15 @@
     ctx = repo[node]
     archiver = archivers[kind](dest, mtime or ctx.date()[0])
 
+    if not match:
+        match = scmutil.matchall(repo)
+
     if repo.ui.configbool("ui", "archivemeta"):
         name = '.hg_archival.txt'
-        if not matchfn or matchfn(name):
+        if match(name):
             write(name, 0o644, False, lambda: buildmetadata(ctx))
 
-    if matchfn:
-        files = [f for f in ctx.manifest().keys() if matchfn(f)]
-    else:
-        files = ctx.manifest().keys()
+    files = [f for f in ctx.manifest().matches(match)]
     total = len(files)
     if total:
         files.sort()
@@ -339,7 +339,7 @@
     if subrepos:
         for subpath in sorted(ctx.substate):
             sub = ctx.workingsub(subpath)
-            submatch = matchmod.subdirmatcher(subpath, matchfn)
+            submatch = matchmod.subdirmatcher(subpath, match)
             total += sub.archive(archiver, prefix, submatch, decode)
 
     if total == 0:
--- a/mercurial/branchmap.py	Fri Nov 02 14:18:29 2018 -0400
+++ b/mercurial/branchmap.py	Fri Nov 02 14:24:29 2018 -0400
@@ -281,7 +281,7 @@
         newbranches = {}
         getbranchinfo = repo.revbranchcache().branchinfo
         for r in revgen:
-            branch, closesbranch = getbranchinfo(r, changelog=cl)
+            branch, closesbranch = getbranchinfo(r)
             newbranches.setdefault(branch, []).append(r)
             if closesbranch:
                 self._closednodes.add(cl.node(r))
@@ -407,10 +407,10 @@
         self._rbcrevslen = len(self._repo.changelog)
         self._rbcrevs = bytearray(self._rbcrevslen * _rbcrecsize)
 
-    def branchinfo(self, rev, changelog=None):
+    def branchinfo(self, rev):
         """Return branch name and close flag for rev, using and updating
         persistent cache."""
-        changelog = changelog or self._repo.changelog
+        changelog = self._repo.changelog
         rbcrevidx = rev * _rbcrecsize
 
         # avoid negative index, changelog.read(nullrev) is fast without cache
@@ -419,7 +419,7 @@
 
         # if requested rev isn't allocated, grow and cache the rev info
         if len(self._rbcrevs) < rbcrevidx + _rbcrecsize:
-            return self._branchinfo(rev, changelog=changelog)
+            return self._branchinfo(rev)
 
         # fast path: extract data from cache, use it if node is matching
         reponode = changelog.node(rev)[:_rbcnodelen]
@@ -447,11 +447,11 @@
             self._rbcrevslen = min(self._rbcrevslen, truncate)
 
         # fall back to slow path and make sure it will be written to disk
-        return self._branchinfo(rev, changelog=changelog)
+        return self._branchinfo(rev)
 
-    def _branchinfo(self, rev, changelog=None):
+    def _branchinfo(self, rev):
         """Retrieve branch info from changelog and update _rbcrevs"""
-        changelog = changelog or self._repo.changelog
+        changelog = self._repo.changelog
         b, close = changelog.branchinfo(rev)
         if b in self._namesreverse:
             branchidx = self._namesreverse[b]
@@ -462,7 +462,7 @@
         reponode = changelog.node(rev)
         if close:
             branchidx |= _rbccloseflag
-        self._setcachedata(rev, reponode, branchidx, changelog)
+        self._setcachedata(rev, reponode, branchidx)
         return b, close
 
     def setdata(self, branch, rev, node, close):
@@ -485,16 +485,14 @@
         if r'branchinfo' in vars(self):
             del self.branchinfo
 
-    def _setcachedata(self, rev, node, branchidx, changelog=None):
+    def _setcachedata(self, rev, node, branchidx):
         """Writes the node's branch data to the in-memory cache data."""
         if rev == nullrev:
             return
-
-        changelog = changelog or self._repo.changelog
         rbcrevidx = rev * _rbcrecsize
         if len(self._rbcrevs) < rbcrevidx + _rbcrecsize:
             self._rbcrevs.extend('\0' *
-                                 (len(changelog) * _rbcrecsize -
+                                 (len(self._repo.changelog) * _rbcrecsize -
                                   len(self._rbcrevs)))
         pack_into(_rbcrecfmt, self._rbcrevs, rbcrevidx, node, branchidx)
         self._rbcrevslen = min(self._rbcrevslen, rev)
--- a/mercurial/cext/revlog.c	Fri Nov 02 14:18:29 2018 -0400
+++ b/mercurial/cext/revlog.c	Fri Nov 02 14:24:29 2018 -0400
@@ -348,6 +348,7 @@
 static PyObject *index_stats(indexObject *self)
 {
 	PyObject *obj = PyDict_New();
+	PyObject *s = NULL;
 	PyObject *t = NULL;
 
 	if (obj == NULL)
@@ -355,22 +356,26 @@
 
 #define istat(__n, __d) \
 	do { \
+		s = PyBytes_FromString(__d); \
 		t = PyInt_FromSsize_t(self->__n); \
-		if (!t) \
+		if (!s || !t) \
 			goto bail; \
-		if (PyDict_SetItemString(obj, __d, t) == -1) \
+		if (PyDict_SetItem(obj, s, t) == -1) \
 			goto bail; \
-		Py_DECREF(t); \
+		Py_CLEAR(s); \
+		Py_CLEAR(t); \
 	} while (0)
 
 	if (self->added) {
 		Py_ssize_t len = PyList_GET_SIZE(self->added);
+		s = PyBytes_FromString("index entries added");
 		t = PyInt_FromSsize_t(len);
-		if (!t)
+		if (!s || !t)
 			goto bail;
-		if (PyDict_SetItemString(obj, "index entries added", t) == -1)
+		if (PyDict_SetItem(obj, s, t) == -1)
 			goto bail;
-		Py_DECREF(t);
+		Py_CLEAR(s);
+		Py_CLEAR(t);
 	}
 
 	if (self->raw_length != self->length)
@@ -392,6 +397,7 @@
 
 bail:
 	Py_XDECREF(obj);
+	Py_XDECREF(s);
 	Py_XDECREF(t);
 	return NULL;
 }
--- a/mercurial/changegroup.py	Fri Nov 02 14:18:29 2018 -0400
+++ b/mercurial/changegroup.py	Fri Nov 02 14:24:29 2018 -0400
@@ -697,12 +697,25 @@
         progress = repo.ui.makeprogress(topic, unit=_('chunks'),
                                         total=len(nodes))
 
+    configtarget = repo.ui.config('devel', 'bundle.delta')
+    if configtarget not in ('', 'p1', 'full'):
+        msg = _("""config "devel.bundle.delta" as unknown value: %s""")
+        repo.ui.warn(msg % configtarget)
+
+    deltamode = repository.CG_DELTAMODE_STD
+    if forcedeltaparentprev:
+        deltamode = repository.CG_DELTAMODE_PREV
+    elif configtarget == 'p1':
+        deltamode = repository.CG_DELTAMODE_P1
+    elif configtarget == 'full':
+        deltamode = repository.CG_DELTAMODE_FULL
+
     revisions = store.emitrevisions(
         nodes,
         nodesorder=nodesorder,
         revisiondata=True,
         assumehaveparentrevisions=not ellipses,
-        deltaprevious=forcedeltaparentprev)
+        deltamode=deltamode)
 
     for i, revision in enumerate(revisions):
         if progress:
--- a/mercurial/commands.py	Fri Nov 02 14:18:29 2018 -0400
+++ b/mercurial/commands.py	Fri Nov 02 14:24:29 2018 -0400
@@ -2249,6 +2249,8 @@
 @command(
     'graft',
     [('r', 'rev', [], _('revisions to graft'), _('REV')),
+     ('', 'base', '',
+      _('base revision when doing the graft merge (ADVANCED)'), _('REV')),
      ('c', 'continue', False, _('resume interrupted graft')),
      ('', 'stop', False, _('stop interrupted graft')),
      ('', 'abort', False, _('abort interrupted graft')),
@@ -2294,6 +2296,35 @@
 
     .. container:: verbose
 
+      The --base option exposes more of how graft internally uses merge with a
+      custom base revision. --base can be used to specify another ancestor than
+      the first and only parent.
+
+      The command::
+
+        hg graft -r 345 --base 234
+
+      is thus pretty much the same as::
+
+        hg diff -r 234 -r 345 | hg import
+
+      but using merge to resolve conflicts and track moved files.
+
+      The result of a merge can thus be backported as a single commit by
+      specifying one of the merge parents as base, and thus effectively
+      grafting the changes from the other side.
+
+      It is also possible to collapse multiple changesets and clean up history
+      by specifying another ancestor as base, much like rebase --collapse
+      --keep.
+
+      The commit message can be tweaked after the fact using commit --amend .
+
+      For using non-ancestors as the base to backout changes, see the backout
+      command and the hidden --parent option.
+
+    .. container:: verbose
+
       Examples:
 
       - copy a single change to the stable branch and edit its description::
@@ -2317,6 +2348,15 @@
 
           hg log -r "sort(all(), date)"
 
+      - backport the result of a merge as a single commit::
+
+          hg graft -r 123 --base 123^
+
+      - land a feature branch as one changeset::
+
+          hg up -cr default
+          hg graft -r featureX --base "ancestor('featureX', 'default')"
+
     See :hg:`help revisions` for more about specifying revisions.
 
     Returns 0 on successful completion.
@@ -2332,6 +2372,9 @@
 
     revs = list(revs)
     revs.extend(opts.get('rev'))
+    basectx = None
+    if opts.get('base'):
+        basectx = scmutil.revsingle(repo, opts['base'], None)
     # a dict of data to be stored in state file
     statedata = {}
     # list of new nodes created by ongoing graft
@@ -2411,13 +2454,16 @@
         revs = scmutil.revrange(repo, revs)
 
     skipped = set()
-    # check for merges
-    for rev in repo.revs('%ld and merge()', revs):
-        ui.warn(_('skipping ungraftable merge revision %d\n') % rev)
-        skipped.add(rev)
+    if basectx is None:
+        # check for merges
+        for rev in repo.revs('%ld and merge()', revs):
+            ui.warn(_('skipping ungraftable merge revision %d\n') % rev)
+            skipped.add(rev)
     revs = [r for r in revs if r not in skipped]
     if not revs:
         return -1
+    if basectx is not None and len(revs) != 1:
+        raise error.Abort(_('only one revision allowed with --base '))
 
     # Don't check in the --continue case, in effect retaining --force across
     # --continues. That's because without --force, any revisions we decided to
@@ -2425,7 +2471,7 @@
     # way to the graftstate. With --force, any revisions we would have otherwise
     # skipped would not have been filtered out, and if they hadn't been applied
     # already, they'd have been in the graftstate.
-    if not (cont or opts.get('force')):
+    if not (cont or opts.get('force')) and basectx is None:
         # check for ancestors of dest branch
         crev = repo['.'].rev()
         ancestors = repo.changelog.ancestors([crev], inclusive=True)
@@ -2521,8 +2567,9 @@
         if not cont:
             # perform the graft merge with p1(rev) as 'ancestor'
             overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
+            base = ctx.p1() if basectx is None else basectx
             with ui.configoverride(overrides, 'graft'):
-                stats = mergemod.graft(repo, ctx, ctx.p1(), ['local', 'graft'])
+                stats = mergemod.graft(repo, ctx, base, ['local', 'graft'])
             # report any conflicts
             if stats.unresolvedcount > 0:
                 # write out state for --continue
--- a/mercurial/configitems.py	Fri Nov 02 14:18:29 2018 -0400
+++ b/mercurial/configitems.py	Fri Nov 02 14:24:29 2018 -0400
@@ -329,6 +329,9 @@
 coreconfigitem('devel', 'bundle2.debug',
     default=False,
 )
+coreconfigitem('devel', 'bundle.delta',
+    default='',
+)
 coreconfigitem('devel', 'cache-vfs',
     default=None,
 )
@@ -699,6 +702,14 @@
 coreconfigitem('fsmonitor', 'warn_update_file_count',
     default=50000,
 )
+coreconfigitem('help', 'hidden-command\..*',
+    default=False,
+    generic=True,
+)
+coreconfigitem('help', 'hidden-topic\..*',
+    default=False,
+    generic=True,
+)
 coreconfigitem('hooks', '.*',
     default=dynamicdefault,
     generic=True,
--- a/mercurial/debugcommands.py	Fri Nov 02 14:18:29 2018 -0400
+++ b/mercurial/debugcommands.py	Fri Nov 02 14:24:29 2018 -0400
@@ -1172,7 +1172,7 @@
     if not util.safehasattr(index, 'stats'):
         raise error.Abort(_('debugindexstats only works with native code'))
     for k, v in sorted(index.stats().items()):
-        ui.write('%s: %s\n' % (k, v))
+        ui.write('%s: %d\n' % (k, v))
 
 @command('debuginstall', [] + cmdutil.formatteropts, '', norepo=True)
 def debuginstall(ui, **opts):
--- a/mercurial/dirstate.py	Fri Nov 02 14:18:29 2018 -0400
+++ b/mercurial/dirstate.py	Fri Nov 02 14:24:29 2018 -0400
@@ -317,7 +317,7 @@
         return copies
 
     def setbranch(self, branch):
-        self._branch = encoding.fromlocal(branch)
+        self.__class__._branch.set(self, encoding.fromlocal(branch))
         f = self._opener('branch', 'w', atomictemp=True, checkambig=True)
         try:
             f.write(self._branch + '\n')
--- a/mercurial/dispatch.py	Fri Nov 02 14:18:29 2018 -0400
+++ b/mercurial/dispatch.py	Fri Nov 02 14:24:29 2018 -0400
@@ -37,6 +37,7 @@
     hook,
     profiling,
     pycompat,
+    registrar,
     scmutil,
     ui as uimod,
     util,
@@ -503,6 +504,7 @@
                 return ui.system(cmd, environ=env,
                                  blockedtag='alias_%s' % self.name)
             self.fn = fn
+            self.alias = True
             self._populatehelp(ui, name, shdef, self.fn)
             return
 
@@ -530,6 +532,7 @@
                 self.fn, self.opts = tableentry
                 cmdhelp = None
 
+            self.alias = True
             self._populatehelp(ui, name, cmd, self.fn, cmdhelp)
 
         except error.UnknownCommand:
@@ -543,7 +546,7 @@
     def _populatehelp(self, ui, name, cmd, fn, defaulthelp=None):
         # confine strings to be passed to i18n.gettext()
         cfg = {}
-        for k in ('doc', 'help'):
+        for k in ('doc', 'help', 'category'):
             v = ui.config('alias', '%s:%s' % (name, k), None)
             if v is None:
                 continue
@@ -558,11 +561,14 @@
             # drop prefix in old-style help lines so hg shows the alias
             self.help = self.help[4 + len(cmd):]
 
+        self.owndoc = 'doc' in cfg
         doc = cfg.get('doc', pycompat.getdoc(fn))
         if doc is not None:
             doc = pycompat.sysstr(doc)
         self.__doc__ = doc
 
+        self.helpcategory = cfg.get('category', registrar.command.CATEGORY_NONE)
+
     @property
     def args(self):
         args = pycompat.maplist(util.expandpath, self.givenargs)
@@ -613,6 +619,7 @@
         self.definition = definition
         self.cmdtable = cmdtable.copy()
         self.source = source
+        self.alias = True
 
     @util.propertycache
     def _aliasdef(self):
--- a/mercurial/extensions.py	Fri Nov 02 14:18:29 2018 -0400
+++ b/mercurial/extensions.py	Fri Nov 02 14:24:29 2018 -0400
@@ -175,11 +175,11 @@
         return None
     if shortname in _extensions:
         return _extensions[shortname]
-    log('  - loading extension: %r\n', shortname)
+    log('  - loading extension: %s\n', shortname)
     _extensions[shortname] = None
-    with util.timedcm('load extension %r', shortname) as stats:
+    with util.timedcm('load extension %s', shortname) as stats:
         mod = _importext(name, path, bind(_reportimporterror, ui))
-    log('  > %r extension loaded in %s\n', shortname, stats)
+    log('  > %s extension loaded in %s\n', shortname, stats)
     if loadingtime is not None:
         loadingtime[shortname] += stats.elapsed
 
@@ -192,13 +192,13 @@
         ui.warn(_('(third party extension %s requires version %s or newer '
                   'of Mercurial; disabling)\n') % (shortname, minver))
         return
-    log('    - validating extension tables: %r\n', shortname)
+    log('    - validating extension tables: %s\n', shortname)
     _validatetables(ui, mod)
 
     _extensions[shortname] = mod
     _order.append(shortname)
-    log('    - invoking registered callbacks: %r\n', shortname)
-    with util.timedcm('callbacks extension %r', shortname) as stats:
+    log('    - invoking registered callbacks: %s\n', shortname)
+    with util.timedcm('callbacks extension %s', shortname) as stats:
         for fn in _aftercallbacks.get(shortname, []):
             fn(loaded=True)
     log('    > callbacks completed in %s\n', stats)
@@ -251,7 +251,7 @@
             if path:
                 if path[0:1] == '!':
                     if name not in _disabledextensions:
-                        log('  - skipping disabled extension: %r\n', name)
+                        log('  - skipping disabled extension: %s\n', name)
                     _disabledextensions[name] = path[1:]
                     continue
             try:
@@ -289,12 +289,12 @@
     log('- executing uisetup hooks\n')
     with util.timedcm('all uisetup') as alluisetupstats:
         for name in _order[newindex:]:
-            log('  - running uisetup for %r\n', name)
-            with util.timedcm('uisetup %r', name) as stats:
+            log('  - running uisetup for %s\n', name)
+            with util.timedcm('uisetup %s', name) as stats:
                 if not _runuisetup(name, ui):
-                    log('    - the %r extension uisetup failed\n', name)
+                    log('    - the %s extension uisetup failed\n', name)
                     broken.add(name)
-            log('  > uisetup for %r took %s\n', name, stats)
+            log('  > uisetup for %s took %s\n', name, stats)
             loadingtime[name] += stats.elapsed
     log('> all uisetup took %s\n', alluisetupstats)
 
@@ -303,17 +303,17 @@
         for name in _order[newindex:]:
             if name in broken:
                 continue
-            log('  - running extsetup for %r\n', name)
-            with util.timedcm('extsetup %r', name) as stats:
+            log('  - running extsetup for %s\n', name)
+            with util.timedcm('extsetup %s', name) as stats:
                 if not _runextsetup(name, ui):
-                    log('    - the %r extension extsetup failed\n', name)
+                    log('    - the %s extension extsetup failed\n', name)
                     broken.add(name)
-            log('  > extsetup for %r took %s\n', name, stats)
+            log('  > extsetup for %s took %s\n', name, stats)
             loadingtime[name] += stats.elapsed
     log('> all extsetup took %s\n', allextetupstats)
 
     for name in broken:
-        log('    - disabling broken %r extension\n', name)
+        log('    - disabling broken %s extension\n', name)
         _extensions[name] = None
 
     # Call aftercallbacks that were never met.
@@ -324,7 +324,7 @@
                 continue
 
             for fn in _aftercallbacks[shortname]:
-                log('  - extension %r not loaded, notify callbacks\n',
+                log('  - extension %s not loaded, notify callbacks\n',
                     shortname)
                 fn(loaded=False)
     log('> remaining aftercallbacks completed in %s\n', stats)
--- a/mercurial/filelog.py	Fri Nov 02 14:18:29 2018 -0400
+++ b/mercurial/filelog.py	Fri Nov 02 14:24:29 2018 -0400
@@ -92,11 +92,11 @@
 
     def emitrevisions(self, nodes, nodesorder=None,
                       revisiondata=False, assumehaveparentrevisions=False,
-                      deltaprevious=False):
+                      deltamode=repository.CG_DELTAMODE_STD):
         return self._revlog.emitrevisions(
             nodes, nodesorder=nodesorder, revisiondata=revisiondata,
             assumehaveparentrevisions=assumehaveparentrevisions,
-            deltaprevious=deltaprevious)
+            deltamode=deltamode)
 
     def addrevision(self, revisiondata, transaction, linkrev, p1, p2,
                     node=None, flags=revlog.REVIDX_DEFAULT_FLAGS,
--- a/mercurial/help.py	Fri Nov 02 14:18:29 2018 -0400
+++ b/mercurial/help.py	Fri Nov 02 14:24:29 2018 -0400
@@ -191,13 +191,31 @@
     if notomitted:
         rst.append('\n\n.. container:: notomitted\n\n    %s\n\n' % notomitted)
 
-def filtercmd(ui, cmd, kw, doc):
+def filtercmd(ui, cmd, func, kw, doc):
     if not ui.debugflag and cmd.startswith("debug") and kw != "debug":
+        # Debug command, and user is not looking for those.
         return True
-    if not ui.verbose and doc and any(w in doc for w in _exclkeywords):
+    if not ui.verbose:
+        if not kw and not doc:
+            # Command had no documentation, no point in showing it by default.
+            return True
+        if getattr(func, 'alias', False) and not getattr(func, 'owndoc', False):
+            # Alias didn't have its own documentation.
+            return True
+        if doc and any(w in doc for w in _exclkeywords):
+            # Documentation has excluded keywords.
+            return True
+    if kw == "shortlist" and not getattr(func, 'helpbasic', False):
+        # We're presenting the short list but the command is not basic.
+        return True
+    if ui.configbool('help', 'hidden-command.%s' % cmd):
+        # Configuration explicitly hides the command.
         return True
     return False
 
+def filtertopic(ui, topic):
+    return ui.configbool('help', 'hidden-topic.%s' % topic, False)
+
 def topicmatch(ui, commands, kw):
     """Return help topics matching kw.
 
@@ -218,20 +236,23 @@
         if (sum(map(lowercontains, names))
             or lowercontains(header)
             or (callable(doc) and lowercontains(doc(ui)))):
-            results['topics'].append((names[0], header))
+            name = names[0]
+            if not filtertopic(ui, name):
+                results['topics'].append((names[0], header))
     for cmd, entry in commands.table.iteritems():
         if len(entry) == 3:
             summary = entry[2]
         else:
             summary = ''
         # translate docs *before* searching there
-        docs = _(pycompat.getdoc(entry[0])) or ''
+        func = entry[0]
+        docs = _(pycompat.getdoc(func)) or ''
         if kw in cmd or lowercontains(summary) or lowercontains(docs):
             doclines = docs.splitlines()
             if doclines:
                 summary = doclines[0]
             cmdname = cmdutil.parsealiases(cmd)[0]
-            if filtercmd(ui, cmdname, kw, docs):
+            if filtercmd(ui, cmdname, func, kw, docs):
                 continue
             results['commands'].append((cmdname, summary))
     for name, docs in itertools.chain(
@@ -251,12 +272,13 @@
         for cmd, entry in getattr(mod, 'cmdtable', {}).iteritems():
             if kw in cmd or (len(entry) > 2 and lowercontains(entry[2])):
                 cmdname = cmdutil.parsealiases(cmd)[0]
-                cmddoc = pycompat.getdoc(entry[0])
+                func = entry[0]
+                cmddoc = pycompat.getdoc(func)
                 if cmddoc:
                     cmddoc = gettext(cmddoc).splitlines()[0]
                 else:
                     cmddoc = _('(no help text available)')
-                if filtercmd(ui, cmdname, kw, cmddoc):
+                if filtercmd(ui, cmdname, func, kw, cmddoc):
                     continue
                 results['extensioncommands'].append((cmdname, cmddoc))
     return results
@@ -530,14 +552,8 @@
             func = e[0]
             if select and not select(f):
                 continue
-            if (not select and name != 'shortlist' and
-                func.__module__ != commands.__name__):
-                continue
-            if name == "shortlist":
-                if not getattr(func, 'helpbasic', False):
-                    continue
             doc = pycompat.getdoc(func)
-            if filtercmd(ui, f, name, doc):
+            if filtercmd(ui, f, func, name, doc):
                 continue
             doc = gettext(doc)
             if not doc:
@@ -609,7 +625,10 @@
                 else:
                     category = TOPIC_CATEGORY_NONE
 
-                topiccats.setdefault(category, []).append((names[0], header))
+                topicname = names[0]
+                if not filtertopic(ui, topicname):
+                    topiccats.setdefault(category, []).append(
+                        (topicname, header))
 
             # Check that all categories have an order.
             missing_order = set(topiccats.keys()) - set(TOPIC_CATEGORY_ORDER)
--- a/mercurial/hg.py	Fri Nov 02 14:18:29 2018 -0400
+++ b/mercurial/hg.py	Fri Nov 02 14:24:29 2018 -0400
@@ -175,7 +175,7 @@
             if hook:
                 with util.timedcm('reposetup %r', name) as stats:
                     hook(ui, obj)
-                log('  > reposetup for %r took %s\n', name, stats)
+                log('  > reposetup for %s took %s\n', name, stats)
     log('> all reposetup took %s\n', allreposetupstats)
     if not obj.local():
         for f in wirepeersetupfuncs:
--- a/mercurial/hgweb/webcommands.py	Fri Nov 02 14:18:29 2018 -0400
+++ b/mercurial/hgweb/webcommands.py	Fri Nov 02 14:24:29 2018 -0400
@@ -1216,8 +1216,7 @@
 
     bodyfh = web.res.getbodyfile()
 
-    archival.archive(web.repo, bodyfh, cnode, artype, prefix=name,
-                     matchfn=match,
+    archival.archive(web.repo, bodyfh, cnode, artype, prefix=name, match=match,
                      subrepos=web.configbool("web", "archivesubrepos"))
 
     return []
--- a/mercurial/localrepo.py	Fri Nov 02 14:18:29 2018 -0400
+++ b/mercurial/localrepo.py	Fri Nov 02 14:24:29 2018 -0400
@@ -91,11 +91,16 @@
     def __get__(self, repo, type=None):
         if repo is None:
             return self
-        return super(_basefilecache, self).__get__(repo.unfiltered(), type)
-    def __set__(self, repo, value):
-        return super(_basefilecache, self).__set__(repo.unfiltered(), value)
-    def __delete__(self, repo):
-        return super(_basefilecache, self).__delete__(repo.unfiltered())
+        # proxy to unfiltered __dict__ since filtered repo has no entry
+        unfi = repo.unfiltered()
+        try:
+            return unfi.__dict__[self.sname]
+        except KeyError:
+            pass
+        return super(_basefilecache, self).__get__(unfi, type)
+
+    def set(self, repo, value):
+        return super(_basefilecache, self).set(repo.unfiltered(), value)
 
 class repofilecache(_basefilecache):
     """filecache for files in .hg but outside of .hg/store"""
--- a/mercurial/manifest.py	Fri Nov 02 14:18:29 2018 -0400
+++ b/mercurial/manifest.py	Fri Nov 02 14:24:29 2018 -0400
@@ -1575,11 +1575,11 @@
 
     def emitrevisions(self, nodes, nodesorder=None,
                       revisiondata=False, assumehaveparentrevisions=False,
-                      deltaprevious=False):
+                      deltamode=repository.CG_DELTAMODE_STD):
         return self._revlog.emitrevisions(
             nodes, nodesorder=nodesorder, revisiondata=revisiondata,
             assumehaveparentrevisions=assumehaveparentrevisions,
-            deltaprevious=deltaprevious)
+            deltamode=deltamode)
 
     def addgroup(self, deltas, linkmapper, transaction, addrevisioncb=None):
         return self._revlog.addgroup(deltas, linkmapper, transaction,
--- a/mercurial/registrar.py	Fri Nov 02 14:18:29 2018 -0400
+++ b/mercurial/registrar.py	Fri Nov 02 14:24:29 2018 -0400
@@ -169,6 +169,10 @@
     """
 
     # Command categories for grouping them in help output.
+    # These can also be specified for aliases, like:
+    # [alias]
+    # myalias = something
+    # myalias:category = repo
     CATEGORY_REPO_CREATION = 'repo'
     CATEGORY_REMOTE_REPO_MANAGEMENT = 'remote'
     CATEGORY_COMMITTING = 'commit'
--- a/mercurial/repository.py	Fri Nov 02 14:18:29 2018 -0400
+++ b/mercurial/repository.py	Fri Nov 02 14:24:29 2018 -0400
@@ -39,6 +39,11 @@
 REVISION_FLAGS_KNOWN = (
     REVISION_FLAG_CENSORED | REVISION_FLAG_ELLIPSIS | REVISION_FLAG_EXTSTORED)
 
+CG_DELTAMODE_STD = b'default'
+CG_DELTAMODE_PREV = b'previous'
+CG_DELTAMODE_FULL = b'fulltext'
+CG_DELTAMODE_P1 = b'p1'
+
 class ipeerconnection(interfaceutil.Interface):
     """Represents a "connection" to a repository.
 
@@ -614,7 +619,7 @@
                       nodesorder=None,
                       revisiondata=False,
                       assumehaveparentrevisions=False,
-                      deltaprevious=False):
+                      deltamode=CG_DELTAMODE_STD):
         """Produce ``irevisiondelta`` for revisions.
 
         Given an iterable of nodes, emits objects conforming to the
@@ -657,10 +662,10 @@
         The ``linknode`` attribute on the returned ``irevisiondelta`` may not
         be set and it is the caller's responsibility to resolve it, if needed.
 
-        If ``deltaprevious`` is True and revision data is requested, all
-        revision data should be emitted as deltas against the revision
-        emitted just prior. The initial revision should be a delta against
-        its 1st parent.
+        If ``deltamode`` is CG_DELTAMODE_PREV and revision data is requested,
+        all revision data should be emitted as deltas against the revision
+        emitted just prior. The initial revision should be a delta against its
+        1st parent.
         """
 
 class ifilemutation(interfaceutil.Interface):
--- a/mercurial/revlog.py	Fri Nov 02 14:18:29 2018 -0400
+++ b/mercurial/revlog.py	Fri Nov 02 14:24:29 2018 -0400
@@ -2205,7 +2205,8 @@
         return res
 
     def emitrevisions(self, nodes, nodesorder=None, revisiondata=False,
-                      assumehaveparentrevisions=False, deltaprevious=False):
+                      assumehaveparentrevisions=False,
+                      deltamode=repository.CG_DELTAMODE_STD):
         if nodesorder not in ('nodes', 'storage', 'linear', None):
             raise error.ProgrammingError('unhandled value for nodesorder: %s' %
                                          nodesorder)
@@ -2213,6 +2214,10 @@
         if nodesorder is None and not self._generaldelta:
             nodesorder = 'storage'
 
+        if (not self._storedeltachains and
+                deltamode != repository.CG_DELTAMODE_PREV):
+            deltamode = repository.CG_DELTAMODE_FULL
+
         return storageutil.emitrevisions(
             self, nodes, nodesorder, revlogrevisiondelta,
             deltaparentfn=self.deltaparent,
@@ -2220,10 +2225,9 @@
             rawsizefn=self.rawsize,
             revdifffn=self.revdiff,
             flagsfn=self.flags,
-            sendfulltext=not self._storedeltachains,
+            deltamode=deltamode,
             revisiondata=revisiondata,
-            assumehaveparentrevisions=assumehaveparentrevisions,
-            deltaprevious=deltaprevious)
+            assumehaveparentrevisions=assumehaveparentrevisions)
 
     DELTAREUSEALWAYS = 'always'
     DELTAREUSESAMEREVS = 'samerevs'
--- a/mercurial/scmutil.py	Fri Nov 02 14:18:29 2018 -0400
+++ b/mercurial/scmutil.py	Fri Nov 02 14:24:29 2018 -0400
@@ -1249,16 +1249,15 @@
     results cached. The decorated function is called. The results are stashed
     away in a ``_filecache`` dict on the object whose method is decorated.
 
-    On subsequent access, the cached result is returned.
-
-    On external property set operations, stat() calls are performed and the new
-    value is cached.
+    On subsequent access, the cached result is used as it is set to the
+    instance dictionary.
 
-    On property delete operations, cached data is removed.
+    On external property set/delete operations, the caller must update the
+    corresponding _filecache entry appropriately. Use __class__.<attr>.set()
+    instead of directly setting <attr>.
 
-    When using the property API, cached data is always returned, if available:
-    no stat() is performed to check if the file has changed and if the function
-    needs to be called to reflect file changes.
+    When using the property API, the cached data is always used if available.
+    No stat() is performed to check if the file has changed.
 
     Others can muck about with the state of the ``_filecache`` dict. e.g. they
     can populate an entry before the property's getter is called. In this case,
@@ -1291,10 +1290,8 @@
         # if accessed on the class, return the descriptor itself.
         if obj is None:
             return self
-        # do we need to check if the file changed?
-        if self.sname in obj.__dict__:
-            assert self.name in obj._filecache, self.name
-            return obj.__dict__[self.sname]
+
+        assert self.sname not in obj.__dict__
 
         entry = obj._filecache.get(self.name)
 
@@ -1314,7 +1311,10 @@
         obj.__dict__[self.sname] = entry.obj
         return entry.obj
 
-    def __set__(self, obj, value):
+    # don't implement __set__(), which would make __dict__ lookup as slow as
+    # function call.
+
+    def set(self, obj, value):
         if self.name not in obj._filecache:
             # we add an entry for the missing value because X in __dict__
             # implies X in _filecache
@@ -1327,12 +1327,6 @@
         ce.obj = value # update cached copy
         obj.__dict__[self.sname] = value # update copy returned by obj.x
 
-    def __delete__(self, obj):
-        try:
-            del obj.__dict__[self.sname]
-        except KeyError:
-            raise AttributeError(self.sname)
-
 def extdatasource(repo, source):
     """Gather a map of rev -> value dict from the specified source
 
--- a/mercurial/testing/storage.py	Fri Nov 02 14:18:29 2018 -0400
+++ b/mercurial/testing/storage.py	Fri Nov 02 14:24:29 2018 -0400
@@ -741,7 +741,8 @@
 
         # forceprevious=True forces a delta against the previous revision.
         # Special case for initial revision.
-        gen = f.emitrevisions([node0], revisiondata=True, deltaprevious=True)
+        gen = f.emitrevisions([node0], revisiondata=True,
+                              deltamode=repository.CG_DELTAMODE_PREV)
 
         rev = next(gen)
         self.assertEqual(rev.node, node0)
@@ -758,7 +759,7 @@
             next(gen)
 
         gen = f.emitrevisions([node0, node2], revisiondata=True,
-                              deltaprevious=True)
+                              deltamode=repository.CG_DELTAMODE_PREV)
 
         rev = next(gen)
         self.assertEqual(rev.node, node0)
--- a/mercurial/utils/storageutil.py	Fri Nov 02 14:18:29 2018 -0400
+++ b/mercurial/utils/storageutil.py	Fri Nov 02 14:24:29 2018 -0400
@@ -22,6 +22,7 @@
     error,
     mdiff,
     pycompat,
+    repository,
 )
 
 _nullhash = hashlib.sha1(nullid)
@@ -269,9 +270,8 @@
 
 def emitrevisions(store, nodes, nodesorder, resultcls, deltaparentfn=None,
                   candeltafn=None, rawsizefn=None, revdifffn=None, flagsfn=None,
-                  sendfulltext=False,
-                  revisiondata=False, assumehaveparentrevisions=False,
-                  deltaprevious=False):
+                  deltamode=repository.CG_DELTAMODE_STD,
+                  revisiondata=False, assumehaveparentrevisions=False):
     """Generic implementation of ifiledata.emitrevisions().
 
     Emitting revision data is subtly complex. This function attempts to
@@ -322,14 +322,17 @@
        Callable receiving a revision number and returns the integer flags
        value for it. If not defined, flags value will be 0.
 
-    ``sendfulltext``
+    ``deltamode``
+       constaint on delta to be sent:
+       * CG_DELTAMODE_STD  - normal mode, try to reuse storage deltas,
+       * CG_DELTAMODE_PREV - only delta against "prev",
+       * CG_DELTAMODE_FULL - only issue full snapshot.
+
        Whether to send fulltext revisions instead of deltas, if allowed.
 
     ``nodesorder``
     ``revisiondata``
     ``assumehaveparentrevisions``
-    ``deltaprevious``
-       See ``ifiledata.emitrevisions()`` interface documentation.
     """
 
     fnode = store.node
@@ -345,7 +348,7 @@
 
     prevrev = None
 
-    if deltaprevious or assumehaveparentrevisions:
+    if deltamode == repository.CG_DELTAMODE_PREV or assumehaveparentrevisions:
         prevrev = store.parentrevs(revs[0])[0]
 
     # Set of revs available to delta against.
@@ -364,12 +367,15 @@
             deltaparentrev = nullrev
 
         # Forced delta against previous mode.
-        if deltaprevious:
+        if deltamode == repository.CG_DELTAMODE_PREV:
             baserev = prevrev
 
         # We're instructed to send fulltext. Honor that.
-        elif sendfulltext:
+        elif deltamode == repository.CG_DELTAMODE_FULL:
             baserev = nullrev
+        # We're instructed to use p1. Honor that
+        elif deltamode == repository.CG_DELTAMODE_P1:
+            baserev = p1rev
 
         # There is a delta in storage. We try to use that because it
         # amounts to effectively copying data from storage and is
@@ -427,7 +433,8 @@
                         baserevisionsize = len(store.revision(baserev,
                                                               raw=True))
 
-            elif baserev == nullrev and not deltaprevious:
+            elif (baserev == nullrev
+                    and deltamode != repository.CG_DELTAMODE_PREV):
                 revision = store.revision(node, raw=True)
                 available.add(rev)
             else:
--- a/mercurial/worker.py	Fri Nov 02 14:18:29 2018 -0400
+++ b/mercurial/worker.py	Fri Nov 02 14:24:29 2018 -0400
@@ -250,10 +250,9 @@
 
 def _windowsworker(ui, func, staticargs, args):
     class Worker(threading.Thread):
-        def __init__(self, taskqueue, resultqueue, func, staticargs,
-                     group=None, target=None, name=None, verbose=None):
-            threading.Thread.__init__(self, group=group, target=target,
-                                      name=name, verbose=verbose)
+        def __init__(self, taskqueue, resultqueue, func, staticargs, *args,
+                     **kwargs):
+            threading.Thread.__init__(self, *args, **kwargs)
             self._taskqueue = taskqueue
             self._resultqueue = resultqueue
             self._func = func
--- a/tests/test-alias.t	Fri Nov 02 14:18:29 2018 -0400
+++ b/tests/test-alias.t	Fri Nov 02 14:24:29 2018 -0400
@@ -68,17 +68,17 @@
 help
 
   $ hg help -c | grep myinit
-   myinit             This is my documented alias for init.
+   myinit       This is my documented alias for init.
   $ hg help -c | grep mycommit
-   mycommit           This is my alias with only doc.
+   mycommit     This is my alias with only doc.
   $ hg help -c | grep cleanstatus
-   cleanstatus        show changed files in the working directory
+  [1]
   $ hg help -c | grep lognull
-   lognull            Logs the null rev
+   lognull      Logs the null rev
   $ hg help -c | grep dln
-   dln                Logs the null rev
+  [1]
   $ hg help -c | grep recursivedoc
-   recursivedoc       Logs the null rev in debug mode
+   recursivedoc Logs the null rev in debug mode
   $ hg help myinit
   hg myinit [OPTIONS] [BLA] [BLE]
   
@@ -602,7 +602,7 @@
 help for a shell alias
 
   $ hg help -c | grep rebate
-   rebate             This is my alias which just prints something.
+   rebate       This is my alias which just prints something.
   $ hg help rebate
   hg rebate [MYARGS]
   
--- a/tests/test-bad-extension.t	Fri Nov 02 14:18:29 2018 -0400
+++ b/tests/test-bad-extension.t	Fri Nov 02 14:24:29 2018 -0400
@@ -85,21 +85,21 @@
   > | egrep 'extension..[^p]|^Exception|Traceback|ImportError|not import|ModuleNotFound'
   debug.extensions: loading extensions
   debug.extensions: - processing 5 entries
-  debug.extensions:   - loading extension: 'gpg'
-  debug.extensions:   > 'gpg' extension loaded in * (glob)
-  debug.extensions:     - validating extension tables: 'gpg'
-  debug.extensions:     - invoking registered callbacks: 'gpg'
+  debug.extensions:   - loading extension: gpg
+  debug.extensions:   > gpg extension loaded in * (glob)
+  debug.extensions:     - validating extension tables: gpg
+  debug.extensions:     - invoking registered callbacks: gpg
   debug.extensions:     > callbacks completed in * (glob)
-  debug.extensions:   - loading extension: 'badext'
+  debug.extensions:   - loading extension: badext
   *** failed to import extension badext from $TESTTMP/badext.py: bit bucket overflow
   Traceback (most recent call last):
   Exception: bit bucket overflow
-  debug.extensions:   - loading extension: 'baddocext'
-  debug.extensions:   > 'baddocext' extension loaded in * (glob)
-  debug.extensions:     - validating extension tables: 'baddocext'
-  debug.extensions:     - invoking registered callbacks: 'baddocext'
+  debug.extensions:   - loading extension: baddocext
+  debug.extensions:   > baddocext extension loaded in * (glob)
+  debug.extensions:     - validating extension tables: baddocext
+  debug.extensions:     - invoking registered callbacks: baddocext
   debug.extensions:     > callbacks completed in * (glob)
-  debug.extensions:   - loading extension: 'badext2'
+  debug.extensions:   - loading extension: badext2
   debug.extensions:     - could not import hgext.badext2 (No module named *badext2*): trying hgext3rd.badext2 (glob)
   Traceback (most recent call last):
   ImportError: No module named badext2 (no-py3 !)
@@ -121,16 +121,16 @@
   debug.extensions: > loaded 2 extensions, total time * (glob)
   debug.extensions: - loading configtable attributes
   debug.extensions: - executing uisetup hooks
-  debug.extensions:   - running uisetup for 'gpg'
-  debug.extensions:   > uisetup for 'gpg' took * (glob)
-  debug.extensions:   - running uisetup for 'baddocext'
-  debug.extensions:   > uisetup for 'baddocext' took * (glob)
+  debug.extensions:   - running uisetup for gpg
+  debug.extensions:   > uisetup for gpg took * (glob)
+  debug.extensions:   - running uisetup for baddocext
+  debug.extensions:   > uisetup for baddocext took * (glob)
   debug.extensions: > all uisetup took * (glob)
   debug.extensions: - executing extsetup hooks
-  debug.extensions:   - running extsetup for 'gpg'
-  debug.extensions:   > extsetup for 'gpg' took * (glob)
-  debug.extensions:   - running extsetup for 'baddocext'
-  debug.extensions:   > extsetup for 'baddocext' took * (glob)
+  debug.extensions:   - running extsetup for gpg
+  debug.extensions:   > extsetup for gpg took * (glob)
+  debug.extensions:   - running extsetup for baddocext
+  debug.extensions:   > extsetup for baddocext took * (glob)
   debug.extensions: > all extsetup took * (glob)
   debug.extensions: - executing remaining aftercallbacks
   debug.extensions: > remaining aftercallbacks completed in * (glob)
--- a/tests/test-blackbox.t	Fri Nov 02 14:18:29 2018 -0400
+++ b/tests/test-blackbox.t	Fri Nov 02 14:24:29 2018 -0400
@@ -82,6 +82,16 @@
   1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> so-confusing exited 0 after * seconds (glob)
   1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> blackbox
 
+custom date format
+  $ rm ./.hg/blackbox.log
+  $ hg --config blackbox.date-format='%Y-%m-%d @ %H:%M:%S' \
+  >    --config devel.default-date='1334347993 0' --traceback status
+  A a
+  $ hg blackbox
+  2012-04-13 @ 20:13:13 bob @0000000000000000000000000000000000000000 (5000)> --config *blackbox.date-format=%Y-%m-%d @ %H:%M:%S* --config *devel.default-date=1334347993 0* --traceback status (glob)
+  2012-04-13 @ 20:13:13 bob @0000000000000000000000000000000000000000 (5000)> --config *blackbox.date-format=%Y-%m-%d @ %H:%M:%S* --config *devel.default-date=1334347993 0* --traceback status exited 0 after * seconds (glob)
+  1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> blackbox
+
 incoming change tracking
 
 create two heads to verify that we only see one change in the log later
--- a/tests/test-bundle.t	Fri Nov 02 14:18:29 2018 -0400
+++ b/tests/test-bundle.t	Fri Nov 02 14:24:29 2018 -0400
@@ -900,3 +900,12 @@
   $ hg update -R ../update2bundled.hg -r 0
   0 files updated, 0 files merged, 2 files removed, 0 files unresolved
 #endif
+
+Test the option that create slim bundle
+
+  $ hg bundle -a --config devel.bundle.delta=p1 ./slim.hg
+  3 changesets found
+
+Test the option that create and no-delta's bundle
+  $ hg bundle -a --config devel.bundle.delta=full ./full.hg
+  3 changesets found
--- a/tests/test-completion.t	Fri Nov 02 14:18:29 2018 -0400
+++ b/tests/test-completion.t	Fri Nov 02 14:24:29 2018 -0400
@@ -308,7 +308,7 @@
   export: bookmark, output, switch-parent, rev, text, git, binary, nodates, template
   files: rev, print0, include, exclude, template, subrepos
   forget: interactive, include, exclude, dry-run
-  graft: rev, continue, stop, abort, edit, log, no-commit, force, currentdate, currentuser, date, user, tool, dry-run
+  graft: rev, base, continue, stop, abort, edit, log, no-commit, force, currentdate, currentuser, date, user, tool, dry-run
   grep: print0, all, diff, text, follow, ignore-case, files-with-matches, line-number, rev, all-files, user, date, template, include, exclude
   heads: rev, topo, active, closed, style, template
   help: extension, command, keyword, system
--- a/tests/test-extension-timing.t	Fri Nov 02 14:18:29 2018 -0400
+++ b/tests/test-extension-timing.t	Fri Nov 02 14:24:29 2018 -0400
@@ -46,23 +46,23 @@
   $ hg foo --traceback --config devel.debug.extensions=yes --debug 2>&1
   debug.extensions: loading extensions
   debug.extensions: - processing 1 entries
-  debug.extensions:   - loading extension: 'foobar'
-  debug.extensions:   > 'foobar' extension loaded in * (glob)
-  debug.extensions:     - validating extension tables: 'foobar'
-  debug.extensions:     - invoking registered callbacks: 'foobar'
+  debug.extensions:   - loading extension: foobar
+  debug.extensions:   > foobar extension loaded in * (glob)
+  debug.extensions:     - validating extension tables: foobar
+  debug.extensions:     - invoking registered callbacks: foobar
   debug.extensions:     > callbacks completed in * (glob)
   debug.extensions: > loaded 1 extensions, total time * (glob)
   debug.extensions: - loading configtable attributes
   debug.extensions: - executing uisetup hooks
-  debug.extensions:   - running uisetup for 'foobar'
+  debug.extensions:   - running uisetup for foobar
   uisetup called [debug]
   uisetup called
   uisetup called [status]
-  debug.extensions:   > uisetup for 'foobar' took * (glob)
+  debug.extensions:   > uisetup for foobar took * (glob)
   debug.extensions: > all uisetup took * (glob)
   debug.extensions: - executing extsetup hooks
-  debug.extensions:   - running extsetup for 'foobar'
-  debug.extensions:   > extsetup for 'foobar' took * (glob)
+  debug.extensions:   - running extsetup for foobar
+  debug.extensions:   > extsetup for foobar took * (glob)
   debug.extensions: > all extsetup took * (glob)
   debug.extensions: - executing remaining aftercallbacks
   debug.extensions: > remaining aftercallbacks completed in * (glob)
@@ -87,7 +87,7 @@
   debug.extensions:   - running reposetup for foobar
   reposetup called for a
   ui == repo.ui
-  debug.extensions:   > reposetup for 'foobar' took * (glob)
+  debug.extensions:   > reposetup for foobar took * (glob)
   debug.extensions: > all reposetup took * (glob)
   Foo
 
--- a/tests/test-filecache.py	Fri Nov 02 14:18:29 2018 -0400
+++ b/tests/test-filecache.py	Fri Nov 02 14:24:29 2018 -0400
@@ -177,7 +177,7 @@
 def setbeforeget(repo):
     os.remove('x')
     os.remove('y')
-    repo.cached = 'string set externally'
+    repo.__class__.cached.set(repo, 'string set externally')
     repo.invalidate()
     print("* neither file exists")
     print(repo.cached)
@@ -188,7 +188,7 @@
     print("* file x created")
     print(repo.cached)
 
-    repo.cached = 'string 2 set externally'
+    repo.__class__.cached.set(repo, 'string 2 set externally')
     repo.invalidate()
     print("* string set externally again")
     print(repo.cached)
--- a/tests/test-graft.t	Fri Nov 02 14:18:29 2018 -0400
+++ b/tests/test-graft.t	Fri Nov 02 14:24:29 2018 -0400
@@ -25,7 +25,7 @@
   $ echo b > e
   $ hg branch -q stable
   $ hg ci -m5
-  $ hg merge -q default --tool internal:local
+  $ hg merge -q default --tool internal:local # for conflicts in e, choose 5 and ignore 4
   $ hg branch -q default
   $ hg ci -m6
   $ hg phase --public 3
@@ -46,8 +46,40 @@
   |
   o  test@0.public: 0
   
+Test --base for grafting the merge of 4 from the perspective of 5, thus only getting the change to d
+
+  $ hg up -cqr 3
+  $ hg graft -r 6 --base 5
+  grafting 6:25a2b029d3ae "6" (tip)
+  merging e
+  $ hg st --change .
+  M d
+
+  $ hg -q strip . --config extensions.strip=
+
+Test --base for collapsing changesets 2 and 3, thus getting both b and c
+
+  $ hg up -cqr 0
+  $ hg graft -r 3 --base 1
+  grafting 3:4c60f11aa304 "3"
+  merging a and b to b
+  merging a and c to c
+  $ hg st --change .
+  A b
+  A c
+  R a
+
+  $ hg -q strip . --config extensions.strip=
+
+Specifying child as --base revision fails safely (perhaps slightly confusing, but consistent)
+
+  $ hg graft -r 2 --base 3
+  grafting 2:5c095ad7e90f "2"
+  note: graft of 2:5c095ad7e90f created no changes to commit
+
 Can't continue without starting:
 
+  $ hg -q up -cr tip
   $ hg rm -q e
   $ hg graft --continue
   abort: no graft in progress
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-help-hide.t	Fri Nov 02 14:24:29 2018 -0400
@@ -0,0 +1,255 @@
+Test hiding some commands (which also happens to hide an entire category).
+
+  $ hg --config help.hidden-command.clone=true \
+  > --config help.hidden-command.init=true help
+  Mercurial Distributed SCM
+  
+  list of commands:
+  
+  Remote repository management:
+  
+   incoming      show new changesets found in source
+   outgoing      show changesets not found in the destination
+   paths         show aliases for remote repositories
+   pull          pull changes from the specified source
+   push          push changes to the specified destination
+   serve         start stand-alone webserver
+  
+  Change creation:
+  
+   commit        commit the specified files or all outstanding changes
+  
+  Change manipulation:
+  
+   backout       reverse effect of earlier changeset
+   graft         copy changes from other branches onto the current branch
+   merge         merge another revision into working directory
+  
+  Change organization:
+  
+   bookmarks     create a new bookmark or list existing bookmarks
+   branch        set or show the current branch name
+   branches      list repository named branches
+   phase         set or show the current phase name
+   tag           add one or more tags for the current or given revision
+   tags          list repository tags
+  
+  File content management:
+  
+   annotate      show changeset information by line for each file
+   cat           output the current or given revision of files
+   copy          mark files as copied for the next commit
+   diff          diff repository (or selected files)
+   grep          search revision history for a pattern in specified files
+  
+  Change navigation:
+  
+   bisect        subdivision search of changesets
+   heads         show branch heads
+   identify      identify the working directory or specified revision
+   log           show revision history of entire repository or files
+  
+  Working directory management:
+  
+   add           add the specified files on the next commit
+   addremove     add all new files, delete all missing files
+   files         list tracked files
+   forget        forget the specified files on the next commit
+   remove        remove the specified files on the next commit
+   rename        rename files; equivalent of copy + remove
+   resolve       redo merges or set/view the merge status of files
+   revert        restore files to their checkout state
+   root          print the root (top) of the current working directory
+   status        show changed files in the working directory
+   summary       summarize working directory state
+   update        update working directory (or switch revisions)
+  
+  Change import/export:
+  
+   archive       create an unversioned archive of a repository revision
+   bundle        create a bundle file
+   export        dump the header and diffs for one or more changesets
+   import        import an ordered set of patches
+   unbundle      apply one or more bundle files
+  
+  Repository maintenance:
+  
+   manifest      output the current or given revision of the project manifest
+   recover       roll back an interrupted transaction
+   verify        verify the integrity of the repository
+  
+  Help:
+  
+   config        show combined config settings from all hgrc files
+   help          show help for a given topic or a help overview
+   version       output version and copyright information
+  
+  additional help topics:
+  
+  Mercurial identifiers:
+  
+   filesets      Specifying File Sets
+   hgignore      Syntax for Mercurial Ignore Files
+   patterns      File Name Patterns
+   revisions     Specifying Revisions
+   urls          URL Paths
+  
+  Mercurial output:
+  
+   color         Colorizing Outputs
+   dates         Date Formats
+   diffs         Diff Formats
+   templating    Template Usage
+  
+  Mercurial configuration:
+  
+   config        Configuration Files
+   environment   Environment Variables
+   extensions    Using Additional Features
+   flags         Command-line flags
+   hgweb         Configuring hgweb
+   merge-tools   Merge Tools
+   pager         Pager Support
+  
+  Concepts:
+  
+   bundlespec    Bundle File Formats
+   glossary      Glossary
+   phases        Working with Phases
+   subrepos      Subrepositories
+  
+  Miscellaneous:
+  
+   deprecated    Deprecated Features
+   internals     Technical implementation topics
+   scripting     Using Mercurial from scripts and automation
+  
+  (use 'hg help -v' to show built-in aliases and global options)
+
+Test hiding some topics.
+
+  $ hg --config help.hidden-topic.deprecated=true \
+  > --config help.hidden-topic.internals=true \
+  > --config help.hidden-topic.scripting=true help
+  Mercurial Distributed SCM
+  
+  list of commands:
+  
+  Repository creation:
+  
+   clone         make a copy of an existing repository
+   init          create a new repository in the given directory
+  
+  Remote repository management:
+  
+   incoming      show new changesets found in source
+   outgoing      show changesets not found in the destination
+   paths         show aliases for remote repositories
+   pull          pull changes from the specified source
+   push          push changes to the specified destination
+   serve         start stand-alone webserver
+  
+  Change creation:
+  
+   commit        commit the specified files or all outstanding changes
+  
+  Change manipulation:
+  
+   backout       reverse effect of earlier changeset
+   graft         copy changes from other branches onto the current branch
+   merge         merge another revision into working directory
+  
+  Change organization:
+  
+   bookmarks     create a new bookmark or list existing bookmarks
+   branch        set or show the current branch name
+   branches      list repository named branches
+   phase         set or show the current phase name
+   tag           add one or more tags for the current or given revision
+   tags          list repository tags
+  
+  File content management:
+  
+   annotate      show changeset information by line for each file
+   cat           output the current or given revision of files
+   copy          mark files as copied for the next commit
+   diff          diff repository (or selected files)
+   grep          search revision history for a pattern in specified files
+  
+  Change navigation:
+  
+   bisect        subdivision search of changesets
+   heads         show branch heads
+   identify      identify the working directory or specified revision
+   log           show revision history of entire repository or files
+  
+  Working directory management:
+  
+   add           add the specified files on the next commit
+   addremove     add all new files, delete all missing files
+   files         list tracked files
+   forget        forget the specified files on the next commit
+   remove        remove the specified files on the next commit
+   rename        rename files; equivalent of copy + remove
+   resolve       redo merges or set/view the merge status of files
+   revert        restore files to their checkout state
+   root          print the root (top) of the current working directory
+   status        show changed files in the working directory
+   summary       summarize working directory state
+   update        update working directory (or switch revisions)
+  
+  Change import/export:
+  
+   archive       create an unversioned archive of a repository revision
+   bundle        create a bundle file
+   export        dump the header and diffs for one or more changesets
+   import        import an ordered set of patches
+   unbundle      apply one or more bundle files
+  
+  Repository maintenance:
+  
+   manifest      output the current or given revision of the project manifest
+   recover       roll back an interrupted transaction
+   verify        verify the integrity of the repository
+  
+  Help:
+  
+   config        show combined config settings from all hgrc files
+   help          show help for a given topic or a help overview
+   version       output version and copyright information
+  
+  additional help topics:
+  
+  Mercurial identifiers:
+  
+   filesets      Specifying File Sets
+   hgignore      Syntax for Mercurial Ignore Files
+   patterns      File Name Patterns
+   revisions     Specifying Revisions
+   urls          URL Paths
+  
+  Mercurial output:
+  
+   color         Colorizing Outputs
+   dates         Date Formats
+   diffs         Diff Formats
+   templating    Template Usage
+  
+  Mercurial configuration:
+  
+   config        Configuration Files
+   environment   Environment Variables
+   extensions    Using Additional Features
+   flags         Command-line flags
+   hgweb         Configuring hgweb
+   merge-tools   Merge Tools
+   pager         Pager Support
+  
+  Concepts:
+  
+   bundlespec    Bundle File Formats
+   glossary      Glossary
+   phases        Working with Phases
+   subrepos      Subrepositories
+  
+  (use 'hg help -v' to show built-in aliases and global options)
--- a/tests/test-help.t	Fri Nov 02 14:18:29 2018 -0400
+++ b/tests/test-help.t	Fri Nov 02 14:24:29 2018 -0400
@@ -820,9 +820,17 @@
   > def nohelp(ui, *args, **kwargs):
   >     pass
   > 
+  > @command(b'hashelp', [], b'hg hashelp', norepo=True)
+  > def hashelp(ui, *args, **kwargs):
+  >     """Extension command's help"""
+  >     pass
+  > 
   > def uisetup(ui):
   >     ui.setconfig(b'alias', b'shellalias', b'!echo hi', b'helpext')
   >     ui.setconfig(b'alias', b'hgalias', b'summary', b'helpext')
+  >     ui.setconfig(b'alias', b'hgalias:doc', b'My doc', b'helpext')
+  >     ui.setconfig(b'alias', b'hgalias:category', b'navigation', b'helpext')
+  >     ui.setconfig(b'alias', b'hgaliasnodoc', b'summary', b'helpext')
   > 
   > EOF
   $ echo '[extensions]' >> $HGRCPATH
@@ -830,11 +838,28 @@
 
 Test for aliases
 
+  $ hg help | grep hgalias
+   hgalias       My doc
+
   $ hg help hgalias
   hg hgalias [--remote]
   
   alias for: hg summary
   
+  My doc
+  
+  defined by: helpext
+  
+  options:
+  
+    --remote check for push and pull
+  
+  (some details hidden, use --verbose to show complete help)
+  $ hg help hgaliasnodoc
+  hg hgaliasnodoc [--remote]
+  
+  alias for: hg summary
+  
   summarize working directory state
   
       This generates a brief summary of the working directory state, including
@@ -884,6 +909,19 @@
   
   (some details hidden, use --verbose to show complete help)
 
+Test that default list of commands includes extension commands that have help,
+but not those that don't, except in verbose mode, when a keyword is passed, or
+when help about the extension is requested.
+
+#if no-extraextensions
+
+  $ hg help | grep hashelp
+   hashelp       Extension command's help
+  $ hg help | grep nohelp
+  [1]
+  $ hg help -v | grep nohelp
+   nohelp        (no help text available)
+
   $ hg help -k nohelp
   Commands:
   
@@ -893,143 +931,15 @@
   
    nohelp (no help text available)
 
-Test that default list of commands omits extension commands
-
-#if no-extraextensions
-
-  $ hg help
-  Mercurial Distributed SCM
+  $ hg help helpext
+  helpext extension - no help text available
   
   list of commands:
   
-  Repository creation:
-  
-   clone         make a copy of an existing repository
-   init          create a new repository in the given directory
-  
-  Remote repository management:
-  
-   incoming      show new changesets found in source
-   outgoing      show changesets not found in the destination
-   paths         show aliases for remote repositories
-   pull          pull changes from the specified source
-   push          push changes to the specified destination
-   serve         start stand-alone webserver
-  
-  Change creation:
-  
-   commit        commit the specified files or all outstanding changes
-  
-  Change manipulation:
-  
-   backout       reverse effect of earlier changeset
-   graft         copy changes from other branches onto the current branch
-   merge         merge another revision into working directory
-  
-  Change organization:
-  
-   bookmarks     create a new bookmark or list existing bookmarks
-   branch        set or show the current branch name
-   branches      list repository named branches
-   phase         set or show the current phase name
-   tag           add one or more tags for the current or given revision
-   tags          list repository tags
-  
-  File content management:
-  
-   annotate      show changeset information by line for each file
-   cat           output the current or given revision of files
-   copy          mark files as copied for the next commit
-   diff          diff repository (or selected files)
-   grep          search revision history for a pattern in specified files
-  
-  Change navigation:
-  
-   bisect        subdivision search of changesets
-   heads         show branch heads
-   identify      identify the working directory or specified revision
-   log           show revision history of entire repository or files
-  
-  Working directory management:
-  
-   add           add the specified files on the next commit
-   addremove     add all new files, delete all missing files
-   files         list tracked files
-   forget        forget the specified files on the next commit
-   remove        remove the specified files on the next commit
-   rename        rename files; equivalent of copy + remove
-   resolve       redo merges or set/view the merge status of files
-   revert        restore files to their checkout state
-   root          print the root (top) of the current working directory
-   status        show changed files in the working directory
-   summary       summarize working directory state
-   update        update working directory (or switch revisions)
-  
-  Change import/export:
-  
-   archive       create an unversioned archive of a repository revision
-   bundle        create a bundle file
-   export        dump the header and diffs for one or more changesets
-   import        import an ordered set of patches
-   unbundle      apply one or more bundle files
-  
-  Repository maintenance:
-  
-   manifest      output the current or given revision of the project manifest
-   recover       roll back an interrupted transaction
-   verify        verify the integrity of the repository
-  
-  Help:
-  
-   config        show combined config settings from all hgrc files
-   help          show help for a given topic or a help overview
-   version       output version and copyright information
-  
-  enabled extensions:
-  
-   helpext       (no help text available)
-  
-  additional help topics:
-  
-  Mercurial identifiers:
-  
-   filesets      Specifying File Sets
-   hgignore      Syntax for Mercurial Ignore Files
-   patterns      File Name Patterns
-   revisions     Specifying Revisions
-   urls          URL Paths
-  
-  Mercurial output:
-  
-   color         Colorizing Outputs
-   dates         Date Formats
-   diffs         Diff Formats
-   templating    Template Usage
-  
-  Mercurial configuration:
-  
-   config        Configuration Files
-   environment   Environment Variables
-   extensions    Using Additional Features
-   flags         Command-line flags
-   hgweb         Configuring hgweb
-   merge-tools   Merge Tools
-   pager         Pager Support
-  
-  Concepts:
-  
-   bundlespec    Bundle File Formats
-   glossary      Glossary
-   phases        Working with Phases
-   subrepos      Subrepositories
-  
-  Miscellaneous:
-  
-   deprecated    Deprecated Features
-   internals     Technical implementation topics
-   scripting     Using Mercurial from scripts and automation
-  
-  (use 'hg help -v' to show built-in aliases and global options)
+   hashelp       Extension command's help
+   nohelp        (no help text available)
+  
+  (use 'hg help -v helpext' to show built-in aliases and global options)
 
 #endif
 
@@ -1381,18 +1291,6 @@
       *empty chunk* at the end of each *delta group* denotes the boundary to the
       next filelog sub-segment.
 
-Test list of commands with command with no help text
-
-  $ hg help helpext
-  helpext extension - no help text available
-  
-  list of commands:
-  
-   nohelp        (no help text available)
-  
-  (use 'hg help -v helpext' to show built-in aliases and global options)
-
-
 test advanced, deprecated and experimental options are hidden in command help
   $ hg help debugoptADV
   hg debugoptADV
@@ -2644,6 +2542,13 @@
   search revision history for a pattern in specified files
   </td></tr>
   <tr><td>
+  <a href="/help/hashelp">
+  hashelp
+  </a>
+  </td><td>
+  Extension command's help
+  </td></tr>
+  <tr><td>
   <a href="/help/heads">
   heads
   </a>
@@ -2662,6 +2567,13 @@
   hgalias
   </a>
   </td><td>
+  My doc
+  </td></tr>
+  <tr><td>
+  <a href="/help/hgaliasnodoc">
+  hgaliasnodoc
+  </a>
+  </td><td>
   summarize working directory state
   </td></tr>
   <tr><td>
--- a/tests/test-log-exthook.t	Fri Nov 02 14:18:29 2018 -0400
+++ b/tests/test-log-exthook.t	Fri Nov 02 14:24:29 2018 -0400
@@ -9,10 +9,12 @@
   >   logcmdutil,
   >   repair,
   > )
+  > def brot13(b):
+  >     return codecs.encode(b.decode('utf8'), 'rot-13').encode('utf8')
   > def rot13description(self, ctx):
-  >     summary = codecs.encode("summary", 'rot-13')
-  >     description = ctx.description().strip().splitlines()[0].encode('rot13')
-  >     self.ui.write("%s:     %s\n" % (summary, description))
+  >     description = ctx.description().strip().splitlines()[0]
+  >     self.ui.write(b"%s:     %s\n" % (brot13(b"summary"),
+  >                                      brot13(description)))
   > def reposetup(ui, repo):
   >     logcmdutil.changesetprinter._exthook = rot13description
   > EOF
--- a/tests/test-narrow-clone-non-narrow-server.t	Fri Nov 02 14:18:29 2018 -0400
+++ b/tests/test-narrow-clone-non-narrow-server.t	Fri Nov 02 14:24:29 2018 -0400
@@ -58,7 +58,11 @@
   comparing with http://localhost:$HGPORT1/
   searching for changes
   looking for local changes to affected paths
+
   $ hg tracked --addinclude f1 http://localhost:$HGPORT1/
+  nothing to widen or narrow
+
+  $ hg tracked --addinclude f9 http://localhost:$HGPORT1/
   comparing with http://localhost:$HGPORT1/
   abort: server does not support narrow clones
   [255]
--- a/tests/test-narrow-widen-no-ellipsis.t	Fri Nov 02 14:18:29 2018 -0400
+++ b/tests/test-narrow-widen-no-ellipsis.t	Fri Nov 02 14:24:29 2018 -0400
@@ -140,6 +140,12 @@
   $ hg id -n
   2
 
+Test that extending already included files should not call narrow_widen
+wireprotocol command
+
+  $ hg tracked --addinclude widest/f
+  nothing to widen or narrow
+
 Pull down the newly added upstream revision.
 
   $ hg pull