--- 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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
--- 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