# HG changeset patch # User Kevin Bullock # Date 1520363827 21600 # Node ID 8bba684efde7f45add05f737952093bb2aa07155 # Parent 2c49b2e7da86580e12d01d7b986f6d39230c0de0# Parent 2ecb0fc535b1ca08e0170a5df6085c44005beeeb merge with security patches diff -r 2ecb0fc535b1 -r 8bba684efde7 .hgsigs --- 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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 diff -r 2ecb0fc535b1 -r 8bba684efde7 .hgtags --- 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 diff -r 2ecb0fc535b1 -r 8bba684efde7 mercurial/changegroup.py --- 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 diff -r 2ecb0fc535b1 -r 8bba684efde7 mercurial/commands.py --- 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. diff -r 2ecb0fc535b1 -r 8bba684efde7 mercurial/context.py --- 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 = {} diff -r 2ecb0fc535b1 -r 8bba684efde7 mercurial/help/urls.txt --- 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:: diff -r 2ecb0fc535b1 -r 8bba684efde7 mercurial/revlog.py --- 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 diff -r 2ecb0fc535b1 -r 8bba684efde7 mercurial/subrepo.py --- 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) diff -r 2ecb0fc535b1 -r 8bba684efde7 setup.py --- 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 diff -r 2ecb0fc535b1 -r 8bba684efde7 tests/drawdag.py --- 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} diff -r 2ecb0fc535b1 -r 8bba684efde7 tests/test-annotate.t --- 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 ------------------------------------------------ diff -r 2ecb0fc535b1 -r 8bba684efde7 tests/test-lfs-bundle.t --- /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 < [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 diff -r 2ecb0fc535b1 -r 8bba684efde7 tests/test-lfs.t --- 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 diff -r 2ecb0fc535b1 -r 8bba684efde7 tests/test-revlog-raw.py --- 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 diff -r 2ecb0fc535b1 -r 8bba684efde7 tests/test-subrepo-recursion.t --- 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 diff -r 2ecb0fc535b1 -r 8bba684efde7 tests/test-subrepo-relative-path.t --- 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