merge with security patches stable 4.5.2
authorKevin Bullock <kbullock+mercurial@ringworld.org>
Tue, 06 Mar 2018 13:17:07 -0600
branchstable
changeset 36757 8bba684efde7
parent 36750 2c49b2e7da86 (diff)
parent 36756 2ecb0fc535b1 (current diff)
child 36758 2034cf3bfc70
merge with security patches
--- a/.hgsigs	Sun Feb 18 17:20:38 2018 -0800
+++ b/.hgsigs	Tue Mar 06 13:17:07 2018 -0600
@@ -158,3 +158,4 @@
 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
+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
--- a/.hgtags	Sun Feb 18 17:20:38 2018 -0800
+++ b/.hgtags	Tue Mar 06 13:17:07 2018 -0600
@@ -171,3 +171,4 @@
 a92b9f8e11ba330614cdfd6af0e03b15c1ff3797 4.4.2
 27b6df1b5adbdf647cf5c6675b40575e1b197c60 4.5-rc
 d334afc585e29577f271c5eda03378736a16ca6b 4.5
+369aadf7a3264b03c8b09efce715bc41e6ab4a9b 4.5.1
--- a/mercurial/changegroup.py	Sun Feb 18 17:20:38 2018 -0800
+++ b/mercurial/changegroup.py	Tue Mar 06 13:17:07 2018 -0600
@@ -770,6 +770,8 @@
         progress(msgbundling, None)
 
     def deltaparent(self, revlog, rev, p1, p2, prev):
+        if not revlog.candelta(prev, rev):
+            raise error.ProgrammingError('cg1 should not be used in this case')
         return prev
 
     def revchunk(self, revlog, rev, prev, linknode):
@@ -829,16 +831,19 @@
             # expensive. The revlog caches should have prev cached, meaning
             # less CPU for changegroup generation. There is likely room to add
             # a flag and/or config option to control this behavior.
-            return prev
+            base = prev
         elif dp == nullrev:
             # revlog is configured to use full snapshot for a reason,
             # stick to full snapshot.
-            return nullrev
+            base = nullrev
         elif dp not in (p1, p2, prev):
             # Pick prev when we can't be sure remote has the base revision.
             return prev
         else:
-            return dp
+            base = dp
+        if base != nullrev and not revlog.candelta(base, rev):
+            base = nullrev
+        return base
 
     def builddeltaheader(self, node, p1n, p2n, basenode, linknode, flags):
         # Do nothing with flags, it is implicitly 0 in cg1 and cg2
--- a/mercurial/commands.py	Sun Feb 18 17:20:38 2018 -0800
+++ b/mercurial/commands.py	Tue Mar 06 13:17:07 2018 -0600
@@ -3301,9 +3301,10 @@
 
     With --graph the revisions are shown as an ASCII art DAG with the most
     recent changeset at the top.
-    'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
-    and '+' represents a fork where the changeset from the lines below is a
-    parent of the 'o' merge on the same line.
+    'o' is a changeset, '@' is a working directory parent, '_' closes a branch,
+    'x' is obsolete, '*' is unstable, and '+' represents a fork where the
+    changeset from the lines below is a parent of the 'o' merge on the same
+    line.
     Paths in the DAG are represented with '|', '/' and so forth. ':' in place
     of a '|' indicates one or more revisions in a path are omitted.
 
--- a/mercurial/context.py	Sun Feb 18 17:20:38 2018 -0800
+++ b/mercurial/context.py	Tue Mar 06 13:17:07 2018 -0600
@@ -1121,7 +1121,8 @@
                 hist[f] = curr
                 del pcache[f]
 
-        return pycompat.ziplist(hist[base][0], hist[base][1].splitlines(True))
+        lineattrs, text = hist[base]
+        return pycompat.ziplist(lineattrs, mdiff.splitnewlines(text))
 
     def ancestors(self, followfirst=False):
         visit = {}
--- a/mercurial/help/urls.txt	Sun Feb 18 17:20:38 2018 -0800
+++ b/mercurial/help/urls.txt	Tue Mar 06 13:17:07 2018 -0600
@@ -24,7 +24,7 @@
 Some notes about using SSH with Mercurial:
 
 - SSH requires an accessible shell account on the destination machine
-  and a copy of hg in the remote path or specified with as remotecmd.
+  and a copy of hg in the remote path or specified with remotecmd.
 - path is relative to the remote user's home directory by default. Use
   an extra slash at the start of a path to specify an absolute path::
 
--- a/mercurial/revlog.py	Sun Feb 18 17:20:38 2018 -0800
+++ b/mercurial/revlog.py	Tue Mar 06 13:17:07 2018 -0600
@@ -77,6 +77,8 @@
     REVIDX_EXTSTORED,
 ]
 REVIDX_KNOWN_FLAGS = util.bitsfrom(REVIDX_FLAGS_ORDER)
+# bitmark for flags that could cause rawdata content change
+REVIDX_RAWTEXT_CHANGING_FLAGS = REVIDX_ISCENSORED | REVIDX_EXTSTORED
 
 # max size of revlog with inline data
 _maxinline = 131072
@@ -96,7 +98,8 @@
     """Register a flag processor on a revision data flag.
 
     Invariant:
-    - Flags need to be defined in REVIDX_KNOWN_FLAGS and REVIDX_FLAGS_ORDER.
+    - Flags need to be defined in REVIDX_KNOWN_FLAGS and REVIDX_FLAGS_ORDER,
+      and REVIDX_RAWTEXT_CHANGING_FLAGS if they can alter rawtext.
     - Only one flag processor can be registered on a specific flag.
     - flagprocessors must be 3-tuples of functions (read, write, raw) with the
       following signatures:
@@ -333,7 +336,9 @@
                                                    len(delta) - hlen):
             btext[0] = delta[hlen:]
         else:
-            basetext = revlog.revision(baserev, _df=fh, raw=True)
+            # deltabase is rawtext before changed by flag processors, which is
+            # equivalent to non-raw text
+            basetext = revlog.revision(baserev, _df=fh, raw=False)
             btext[0] = mdiff.patch(basetext, delta)
 
         try:
@@ -404,6 +409,9 @@
         for candidaterevs in self._getcandidaterevs(p1, p2, cachedelta):
             nominateddeltas = []
             for candidaterev in candidaterevs:
+                # no delta for rawtext-changing revs (see "candelta" for why)
+                if revlog.flags(candidaterev) & REVIDX_RAWTEXT_CHANGING_FLAGS:
+                    continue
                 candidatedelta = self._builddeltainfo(revinfo, candidaterev, fh)
                 if revlog._isgooddeltainfo(candidatedelta, revinfo.textlen):
                     nominateddeltas.append(candidatedelta)
@@ -713,6 +721,18 @@
         except KeyError:
             return False
 
+    def candelta(self, baserev, rev):
+        """whether two revisions (baserev, rev) can be delta-ed or not"""
+        # Disable delta if either rev requires a content-changing flag
+        # processor (ex. LFS). This is because such flag processor can alter
+        # the rawtext content that the delta will be based on, and two clients
+        # could have a same revlog node with different flags (i.e. different
+        # rawtext contents) and the delta could be incompatible.
+        if ((self.flags(baserev) & REVIDX_RAWTEXT_CHANGING_FLAGS)
+            or (self.flags(rev) & REVIDX_RAWTEXT_CHANGING_FLAGS)):
+            return False
+        return True
+
     def clearcaches(self):
         self._cache = None
         self._chainbasecache.clear()
@@ -2066,7 +2086,10 @@
         # full versions are inserted when the needed deltas
         # become comparable to the uncompressed text
         if rawtext is None:
-            textlen = mdiff.patchedsize(self.rawsize(cachedelta[0]),
+            # need rawtext size, before changed by flag processors, which is
+            # the non-raw size. use revlog explicitly to avoid filelog's extra
+            # logic that might remove metadata size.
+            textlen = mdiff.patchedsize(revlog.size(self, cachedelta[0]),
                                         cachedelta[1])
         else:
             textlen = len(rawtext)
@@ -2075,7 +2098,14 @@
             deltacomputer = _deltacomputer(self)
 
         revinfo = _revisioninfo(node, p1, p2, btext, textlen, cachedelta, flags)
-        deltainfo = deltacomputer.finddeltainfo(revinfo, fh)
+
+        # no delta for flag processor revision (see "candelta" for why)
+        # not calling candelta since only one revision needs test, also to
+        # avoid overhead fetching flags again.
+        if flags & REVIDX_RAWTEXT_CHANGING_FLAGS:
+            deltainfo = None
+        else:
+            deltainfo = deltacomputer.finddeltainfo(revinfo, fh)
 
         if deltainfo is not None:
             base = deltainfo.base
--- a/mercurial/subrepo.py	Sun Feb 18 17:20:38 2018 -0800
+++ b/mercurial/subrepo.py	Tue Mar 06 13:17:07 2018 -0600
@@ -982,7 +982,13 @@
         if len(self._repo) == 0:
             # use self._repo.vfs instead of self.wvfs to remove .hg only
             self._repo.vfs.rmtree()
-            if parentrepo.shared():
+
+            # A remote subrepo could be shared if there is a local copy
+            # relative to the parent's share source.  But clone pooling doesn't
+            # assemble the repos in a tree, so that can't be consistently done.
+            # A simpler option is for the user to configure clone pooling, and
+            # work with that.
+            if parentrepo.shared() and hg.islocal(srcurl):
                 self.ui.status(_('sharing subrepo %s from %s\n')
                                % (subrelpath(self), srcurl))
                 shared = hg.share(self._repo._subparent.baseui,
@@ -990,11 +996,25 @@
                                   update=False, bookmarks=False)
                 self._repo = shared.local()
             else:
+                # TODO: find a common place for this and this code in the
+                # share.py wrap of the clone command.
+                if parentrepo.shared():
+                    pool = self.ui.config('share', 'pool')
+                    if pool:
+                        pool = util.expandpath(pool)
+
+                    shareopts = {
+                        'pool': pool,
+                        'mode': self.ui.config('share', 'poolnaming'),
+                    }
+                else:
+                    shareopts = {}
+
                 self.ui.status(_('cloning subrepo %s from %s\n')
                                % (subrelpath(self), srcurl))
                 other, cloned = hg.clone(self._repo._subparent.baseui, {},
                                          other, self._repo.root,
-                                         update=False)
+                                         update=False, shareopts=shareopts)
                 self._repo = cloned.local()
             self._initrepo(parentrepo, source, create=True)
             self._cachestorehash(srcurl)
--- a/setup.py	Sun Feb 18 17:20:38 2018 -0800
+++ b/setup.py	Tue Mar 06 13:17:07 2018 -0600
@@ -67,6 +67,26 @@
     printf(error, file=sys.stderr)
     sys.exit(1)
 
+# We don't yet officially support Python 3. But we want to allow developers to
+# hack on. Detect and disallow running on Python 3 by default. But provide a
+# backdoor to enable working on Python 3.
+if sys.version_info[0] != 2:
+    badpython = True
+
+    # Allow Python 3 from source checkouts.
+    if os.path.isdir('.hg'):
+        badpython = False
+
+    if badpython:
+        error = """
+Mercurial only supports Python 2.7.
+Python {py} detected.
+Please re-run with Python 2.7.
+""".format(py=sys.version_info)
+
+        printf(error, file=sys.stderr)
+        sys.exit(1)
+
 # Solaris Python packaging brain damage
 try:
     import hashlib
--- a/tests/drawdag.py	Sun Feb 18 17:20:38 2018 -0800
+++ b/tests/drawdag.py	Tue Mar 06 13:17:07 2018 -0600
@@ -371,7 +371,8 @@
     comments = list(_getcomments(text))
     filere = re.compile(br'^(\w+)/([\w/]+)\s*=\s*(.*)$', re.M)
     for name, path, content in filere.findall(b'\n'.join(comments)):
-        files[name][path] = content.replace(br'\n', b'\n')
+        content = content.replace(br'\n', b'\n').replace(br'\1', b'\1')
+        files[name][path] = content
 
     committed = {None: node.nullid}  # {name: node}
 
--- a/tests/test-annotate.t	Sun Feb 18 17:20:38 2018 -0800
+++ b/tests/test-annotate.t	Tue Mar 06 13:17:07 2018 -0600
@@ -895,6 +895,44 @@
 
   $ cd ..
 
+Annotate with orphaned CR (issue5798)
+-------------------------------------
+
+  $ hg init repo-cr
+  $ cd repo-cr
+
+  $ cat <<'EOF' >> "$TESTTMP/substcr.py"
+  > import sys
+  > from mercurial import util
+  > util.setbinary(sys.stdin)
+  > util.setbinary(sys.stdout)
+  > stdin = getattr(sys.stdin, 'buffer', sys.stdin)
+  > stdout = getattr(sys.stdout, 'buffer', sys.stdout)
+  > stdout.write(stdin.read().replace(b'\r', b'[CR]'))
+  > EOF
+
+  >>> with open('a', 'wb') as f:
+  ...     f.write(b'0a\r0b\r\n0c\r0d\r\n0e\n0f\n0g')
+  $ hg ci -qAm0
+  >>> with open('a', 'wb') as f:
+  ...     f.write(b'0a\r0b\r\n1c\r1d\r\n0e\n1f\n0g')
+  $ hg ci -m1
+
+  $ hg annotate -r0 a | $PYTHON "$TESTTMP/substcr.py"
+  0: 0a[CR]0b[CR]
+  0: 0c[CR]0d[CR]
+  0: 0e
+  0: 0f
+  0: 0g
+  $ hg annotate -r1 a | $PYTHON "$TESTTMP/substcr.py"
+  0: 0a[CR]0b[CR]
+  1: 1c[CR]1d[CR]
+  0: 0e
+  1: 1f
+  0: 0g
+
+  $ cd ..
+
 Annotate with linkrev pointing to another branch
 ------------------------------------------------
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-lfs-bundle.t	Tue Mar 06 13:17:07 2018 -0600
@@ -0,0 +1,97 @@
+In this test, we want to test LFS bundle application on both LFS and non-LFS
+repos.
+
+To make it more interesting, the file revisions will contain hg filelog
+metadata ('\1\n'). The bundle will have 1 file revision overlapping with the
+destination repo.
+
+#  rev      1          2         3
+#  repo:    yes        yes       no
+#  bundle:  no (base)  yes       yes (deltabase: 2 if possible)
+
+It is interesting because rev 2 could have been stored as LFS in the repo, and
+non-LFS in the bundle; or vice-versa.
+
+Init
+
+  $ cat >> $HGRCPATH << EOF
+  > [extensions]
+  > lfs=
+  > drawdag=$TESTDIR/drawdag.py
+  > [lfs]
+  > url=file:$TESTTMP/lfs-remote
+  > EOF
+
+Helper functions
+
+  $ commitxy() {
+  > hg debugdrawdag "$@" <<'EOS'
+  >  Y  # Y/X=\1\nAAAA\nE\nF
+  >  |  # Y/Y=\1\nAAAA\nG\nH
+  >  X  # X/X=\1\nAAAA\nC\n
+  >     # X/Y=\1\nAAAA\nD\n
+  > EOS
+  > }
+
+  $ commitz() {
+  > hg debugdrawdag "$@" <<'EOS'
+  >  Z  # Z/X=\1\nAAAA\nI\n
+  >  |  # Z/Y=\1\nAAAA\nJ\n
+  >  |  # Z/Z=\1\nZ
+  >  Y
+  > EOS
+  > }
+
+  $ enablelfs() {
+  >   cat >> .hg/hgrc <<EOF
+  > [lfs]
+  > track=all()
+  > EOF
+  > }
+
+Generate bundles
+
+  $ for i in normal lfs; do
+  >   NAME=src-$i
+  >   hg init $TESTTMP/$NAME
+  >   cd $TESTTMP/$NAME
+  >   [ $i = lfs ] && enablelfs
+  >   commitxy
+  >   commitz
+  >   hg bundle -q --base X -r Y+Z $TESTTMP/$NAME.bundle
+  >   SRCNAMES="$SRCNAMES $NAME"
+  > done
+
+Prepare destination repos
+
+  $ for i in normal lfs; do
+  >   NAME=dst-$i
+  >   hg init $TESTTMP/$NAME
+  >   cd $TESTTMP/$NAME
+  >   [ $i = lfs ] && enablelfs
+  >   commitxy
+  >   DSTNAMES="$DSTNAMES $NAME"
+  > done
+
+Apply bundles
+
+  $ for i in $SRCNAMES; do
+  >   for j in $DSTNAMES; do
+  >     echo ---- Applying $i.bundle to $j ----
+  >     cp -R $TESTTMP/$j $TESTTMP/tmp-$i-$j
+  >     cd $TESTTMP/tmp-$i-$j
+  >     if hg unbundle $TESTTMP/$i.bundle -q 2>/dev/null; then
+  >       hg verify -q && echo OK
+  >     else
+  >       echo CRASHED
+  >     fi
+  >   done
+  > done
+  ---- Applying src-normal.bundle to dst-normal ----
+  OK
+  ---- Applying src-normal.bundle to dst-lfs ----
+  OK
+  ---- Applying src-lfs.bundle to dst-normal ----
+  OK
+  ---- Applying src-lfs.bundle to dst-lfs ----
+  OK
--- a/tests/test-lfs.t	Sun Feb 18 17:20:38 2018 -0800
+++ b/tests/test-lfs.t	Tue Mar 06 13:17:07 2018 -0600
@@ -349,7 +349,7 @@
   uncompressed size of bundle content:
        * (changelog) (glob)
        * (manifests) (glob)
-       *  a (glob)
+      * a (glob)
   $ hg --config extensions.strip= strip -r 2 --no-backup --force -q
   $ hg -R bundle.hg log -p -T '{rev} {desc}\n' a
   5 branching
--- a/tests/test-revlog-raw.py	Sun Feb 18 17:20:38 2018 -0800
+++ b/tests/test-revlog-raw.py	Tue Mar 06 13:17:07 2018 -0600
@@ -114,6 +114,8 @@
             else:
                 # suboptimal deltaparent
                 deltaparent = min(0, parentrev)
+            if not rlog.candelta(deltaparent, r):
+                deltaparent = -1
             return {'node': rlog.node(r), 'p1': pnode, 'p2': node.nullid,
                     'cs': rlog.node(rlog.linkrev(r)), 'flags': rlog.flags(r),
                     'deltabase': rlog.node(deltaparent),
@@ -151,12 +153,14 @@
     for r in rlog:
         p1 = rlog.node(r - 1)
         p2 = node.nullid
-        if r == 0:
+        if r == 0 or (rlog.flags(r) & revlog.REVIDX_EXTSTORED):
             text = rlog.revision(r, raw=True)
             cachedelta = None
         else:
-            # deltaparent is more interesting if it has the EXTSTORED flag.
-            deltaparent = max([0] + [p for p in range(r - 2) if rlog.flags(p)])
+            # deltaparent cannot have EXTSTORED flag.
+            deltaparent = max([-1] +
+                              [p for p in range(r)
+                               if rlog.flags(p) & revlog.REVIDX_EXTSTORED == 0])
             text = None
             cachedelta = (deltaparent, rlog.revdiff(deltaparent, r))
         flags = rlog.flags(r)
@@ -262,8 +266,9 @@
         result.append((text, rawtext))
 
         # Verify flags like isdelta, isext work as expected
-        if bool(rlog.deltaparent(rev) > -1) != isdelta:
-            abort('rev %d: isdelta is ineffective' % rev)
+        # isdelta can be overridden to False if this or p1 has isext set
+        if bool(rlog.deltaparent(rev) > -1) and not isdelta:
+            abort('rev %d: isdelta is unexpected' % rev)
         if bool(rlog.flags(rev)) != isext:
             abort('rev %d: isext is ineffective' % rev)
     return result
--- a/tests/test-subrepo-recursion.t	Sun Feb 18 17:20:38 2018 -0800
+++ b/tests/test-subrepo-recursion.t	Tue Mar 06 13:17:07 2018 -0600
@@ -292,6 +292,43 @@
   z2
   z3
 
+Clone pooling from a remote URL will share the top level repo and the subrepos,
+even if they are referenced by remote URL.
+
+  $ hg --config extensions.share= --config share.pool=$TESTTMP/pool \
+  >    clone http://localhost:$HGPORT shared
+  (sharing from new pooled repository 23376cbba0d87c15906bb3652584927c140907bf)
+  requesting all changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 3 changesets with 5 changes to 3 files
+  new changesets 23376cbba0d8:1326fa26d0c0
+  searching for changes
+  no changes found
+  updating working directory
+  cloning subrepo foo from http://localhost:$HGPORT/foo
+  (sharing from new pooled repository af048e97ade2e236f754f05d07013e586af0f8bf)
+  requesting all changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 4 changesets with 7 changes to 3 files
+  new changesets af048e97ade2:65903cebad86
+  searching for changes
+  no changes found
+  cloning subrepo foo/bar from http://localhost:$HGPORT/foo/bar
+  (sharing from new pooled repository 4904098473f96c900fec436dad267edd4da59fad)
+  requesting all changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 3 changesets with 3 changes to 1 files
+  new changesets 4904098473f9:31ecbdafd357
+  searching for changes
+  no changes found
+  3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
   $ cat access.log
   * "GET /?cmd=capabilities HTTP/1.1" 200 - (glob)
   * "GET /?cmd=batch HTTP/1.1" 200 - * (glob)
@@ -302,6 +339,27 @@
   * "GET /foo/bar?cmd=capabilities HTTP/1.1" 200 - (glob)
   * "GET /foo/bar?cmd=batch HTTP/1.1" 200 - * (glob)
   * "GET /foo/bar?cmd=getbundle HTTP/1.1" 200 - * (glob)
+  $LOCALIP - - [$LOGDATE$] "GET /?cmd=capabilities HTTP/1.1" 200 - (glob)
+  $LOCALIP - - [$LOGDATE$] "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=0 x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ (glob)
+  $LOCALIP - - [$LOGDATE$] "GET /?cmd=capabilities HTTP/1.1" 200 - (glob)
+  $LOCALIP - - [$LOGDATE$] "GET /?cmd=batch HTTP/1.1" 200 - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ (glob)
+  $LOCALIP - - [$LOGDATE$] "GET /?cmd=getbundle HTTP/1.1" 200 - x-hgarg-1:bookmarks=1&$USUAL_BUNDLE_CAPS$&cg=1&common=0000000000000000000000000000000000000000&heads=1326fa26d0c00d2146c63b56bb6a45149d7325ac&listkeys=bookmarks&phases=1 x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ (glob)
+  $LOCALIP - - [$LOGDATE$] "GET /?cmd=batch HTTP/1.1" 200 - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D1326fa26d0c00d2146c63b56bb6a45149d7325ac x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ (glob)
+  $LOCALIP - - [$LOGDATE$] "GET /?cmd=getbundle HTTP/1.1" 200 - x-hgarg-1:bookmarks=1&$USUAL_BUNDLE_CAPS$&cg=0&common=1326fa26d0c00d2146c63b56bb6a45149d7325ac&heads=1326fa26d0c00d2146c63b56bb6a45149d7325ac&listkeys=bookmarks&phases=1 x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ (glob)
+  $LOCALIP - - [$LOGDATE$] "GET /foo?cmd=capabilities HTTP/1.1" 200 - (glob)
+  $LOCALIP - - [$LOGDATE$] "GET /foo?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=0 x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ (glob)
+  $LOCALIP - - [$LOGDATE$] "GET /foo?cmd=capabilities HTTP/1.1" 200 - (glob)
+  $LOCALIP - - [$LOGDATE$] "GET /foo?cmd=batch HTTP/1.1" 200 - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ (glob)
+  $LOCALIP - - [$LOGDATE$] "GET /foo?cmd=getbundle HTTP/1.1" 200 - x-hgarg-1:bookmarks=1&$USUAL_BUNDLE_CAPS$&cg=1&common=0000000000000000000000000000000000000000&heads=65903cebad86f1a84bd4f1134f62fa7dcb7a1c98&listkeys=bookmarks&phases=1 x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ (glob)
+  $LOCALIP - - [$LOGDATE$] "GET /foo?cmd=batch HTTP/1.1" 200 - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D65903cebad86f1a84bd4f1134f62fa7dcb7a1c98 x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ (glob)
+  $LOCALIP - - [$LOGDATE$] "GET /foo?cmd=getbundle HTTP/1.1" 200 - x-hgarg-1:bookmarks=1&$USUAL_BUNDLE_CAPS$&cg=0&common=65903cebad86f1a84bd4f1134f62fa7dcb7a1c98&heads=65903cebad86f1a84bd4f1134f62fa7dcb7a1c98&listkeys=bookmarks&phases=1 x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ (glob)
+  $LOCALIP - - [$LOGDATE$] "GET /foo/bar?cmd=capabilities HTTP/1.1" 200 - (glob)
+  $LOCALIP - - [$LOGDATE$] "GET /foo/bar?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=0 x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ (glob)
+  $LOCALIP - - [$LOGDATE$] "GET /foo/bar?cmd=capabilities HTTP/1.1" 200 - (glob)
+  $LOCALIP - - [$LOGDATE$] "GET /foo/bar?cmd=batch HTTP/1.1" 200 - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ (glob)
+  $LOCALIP - - [$LOGDATE$] "GET /foo/bar?cmd=getbundle HTTP/1.1" 200 - x-hgarg-1:bookmarks=1&$USUAL_BUNDLE_CAPS$&cg=1&common=0000000000000000000000000000000000000000&heads=31ecbdafd357f54b281c9bd1d681bb90de219e22&listkeys=bookmarks&phases=1 x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ (glob)
+  $LOCALIP - - [$LOGDATE$] "GET /foo/bar?cmd=batch HTTP/1.1" 200 - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D31ecbdafd357f54b281c9bd1d681bb90de219e22 x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ (glob)
+  $LOCALIP - - [$LOGDATE$] "GET /foo/bar?cmd=getbundle HTTP/1.1" 200 - x-hgarg-1:bookmarks=1&$USUAL_BUNDLE_CAPS$&cg=0&common=31ecbdafd357f54b281c9bd1d681bb90de219e22&heads=31ecbdafd357f54b281c9bd1d681bb90de219e22&listkeys=bookmarks&phases=1 x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ (glob)
 
   $ killdaemons.py
   $ rm hg1.pid error.log access.log
@@ -485,6 +543,22 @@
   commit: (clean)
   update: 4 new changesets (update)
 
+Sharing a local repo without the locally referenced subrepo (i.e. it was never
+updated from null), fails the same as a clone operation.
+
+  $ hg --config progress.disable=True clone -U ../empty ../empty2
+
+  $ hg --config extensions.share= --config progress.disable=True \
+  >    share ../empty2 ../empty_share
+  updating working directory
+  abort: repository $TESTTMP/empty2/foo not found!
+  [255]
+
+  $ hg --config progress.disable=True clone ../empty2 ../empty_clone
+  updating to branch default
+  abort: repository $TESTTMP/empty2/foo not found!
+  [255]
+
 Disable progress extension and cleanup:
 
   $ mv $HGRCPATH.no-progress $HGRCPATH
--- a/tests/test-subrepo-relative-path.t	Sun Feb 18 17:20:38 2018 -0800
+++ b/tests/test-subrepo-relative-path.t	Tue Mar 06 13:17:07 2018 -0600
@@ -72,6 +72,87 @@
    source   ../sub
    revision 863c1745b441bd97a8c4a096e87793073f4fb215
 
+Test sharing with a remote URL reference
+
+  $ hg init absolute_subrepo
+  $ cd absolute_subrepo
+  $ echo foo > foo.txt
+  $ hg ci -Am 'initial commit'
+  adding foo.txt
+  $ echo "sub = http://localhost:$HGPORT/sub" > .hgsub
+  $ hg ci -Am 'add absolute subrepo'
+  adding .hgsub
+  $ cd ..
+
+Clone pooling works for local clones with a remote subrepo reference.  The
+subrepo is cloned to the pool and shared from there, so that all clones will
+share the same subrepo.
+
+  $ hg --config extensions.share= --config share.pool=$TESTTMP/pool \
+  >    clone absolute_subrepo cloned_from_abs
+  (sharing from new pooled repository 8d6a2f1e993b34b6557de0042cfe825ae12a8dae)
+  requesting all changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 2 changesets with 3 changes to 3 files
+  new changesets 8d6a2f1e993b:* (glob)
+  searching for changes
+  no changes found
+  updating working directory
+  cloning subrepo sub from http://localhost:$HGPORT/sub
+  (sharing from new pooled repository 863c1745b441bd97a8c4a096e87793073f4fb215)
+  requesting all changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 1 changes to 1 files
+  new changesets 863c1745b441
+  searching for changes
+  no changes found
+  3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+Vanilla sharing with a subrepo remote path reference will clone the subrepo.
+Each share of these top level repos will end up with independent subrepo copies
+(potentially leaving the shared parent with dangling cset references).
+
+  $ hg --config extensions.share= share absolute_subrepo shared_from_abs
+  updating working directory
+  cloning subrepo sub from http://localhost:$HGPORT/sub
+  requesting all changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 1 changes to 1 files
+  new changesets 863c1745b441
+  3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+  $ hg --config extensions.share= share -U absolute_subrepo shared_from_abs2
+  $ hg -R shared_from_abs2 update -r tip
+  cloning subrepo sub from http://localhost:$HGPORT/sub
+  requesting all changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 1 changes to 1 files
+  new changesets 863c1745b441
+  3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+A parent repo without its subrepo available locally can be shared if the
+subrepo is referenced by absolute path.
+
+  $ hg clone -U absolute_subrepo cloned_null_from_abs
+  $ hg --config extensions.share= share cloned_null_from_abs shared_from_null_abs
+  updating working directory
+  cloning subrepo sub from http://localhost:$HGPORT/sub
+  requesting all changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 1 changes to 1 files
+  new changesets 863c1745b441
+  3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
   $ killdaemons.py
 
 subrepo paths with ssh urls