mercurial/changegroup.py
changeset 38890 d706c77449f9
parent 38889 a06aab274aef
child 38891 205c98e2f1ba
--- a/mercurial/changegroup.py	Thu Aug 02 12:18:35 2018 -0700
+++ b/mercurial/changegroup.py	Thu Aug 02 14:15:10 2018 -0700
@@ -657,20 +657,52 @@
         clrevorder = {}
         mfs = {} # needed manifests
         fnodes = {} # needed file nodes
+        mfl = repo.manifestlog
+        # TODO violates storage abstraction.
+        mfrevlog = mfl._revlog
         changedfiles = set()
 
-        # Callback for the changelog, used to collect changed files and manifest
-        # nodes.
+        ellipsesmode = util.safehasattr(self, 'full_nodes')
+
+        # Callback for the changelog, used to collect changed files and
+        # manifest nodes.
         # Returns the linkrev node (identity in the changelog case).
         def lookupcl(x):
             c = cl.read(x)
             clrevorder[x] = len(clrevorder)
-            n = c[0]
-            # record the first changeset introducing this manifest version
-            mfs.setdefault(n, x)
-            # Record a complete list of potentially-changed files in
-            # this manifest.
-            changedfiles.update(c[3])
+
+            if ellipsesmode:
+                # Only update mfs if x is going to be sent. Otherwise we
+                # end up with bogus linkrevs specified for manifests and
+                # we skip some manifest nodes that we should otherwise
+                # have sent.
+                if (x in self.full_nodes
+                    or cl.rev(x) in self.precomputed_ellipsis):
+                    n = c[0]
+                    # Record the first changeset introducing this manifest
+                    # version.
+                    mfs.setdefault(n, x)
+                    # Set this narrow-specific dict so we have the lowest
+                    # manifest revnum to look up for this cl revnum. (Part of
+                    # mapping changelog ellipsis parents to manifest ellipsis
+                    # parents)
+                    self.next_clrev_to_localrev.setdefault(cl.rev(x),
+                                                           mfrevlog.rev(n))
+                # We can't trust the changed files list in the changeset if the
+                # client requested a shallow clone.
+                if self.is_shallow:
+                    changedfiles.update(mfl[c[0]].read().keys())
+                else:
+                    changedfiles.update(c[3])
+            else:
+
+                n = c[0]
+                # record the first changeset introducing this manifest version
+                mfs.setdefault(n, x)
+                # Record a complete list of potentially-changed files in
+                # this manifest.
+                changedfiles.update(c[3])
+
             return x
 
         self._verbosenote(_('uncompressed size of bundle content:\n'))
@@ -705,6 +737,13 @@
         for chunk in self.generatemanifests(commonrevs, clrevorder,
                 fastpathlinkrev, mfs, fnodes, source):
             yield chunk
+
+        if ellipsesmode:
+            mfdicts = None
+            if self.is_shallow:
+                mfdicts = [(self._repo.manifestlog[n].read(), lr)
+                           for (n, lr) in mfs.iteritems()]
+
         mfs.clear()
         clrevs = set(cl.rev(x) for x in clnodes)
 
@@ -719,6 +758,14 @@
                 revs = ((r, llr(r)) for r in filerevlog)
                 return dict((fln(r), cln(lr)) for r, lr in revs if lr in clrevs)
 
+        if ellipsesmode:
+            # We need to pass the mfdicts variable down into
+            # generatefiles(), but more than one command might have
+            # wrapped generatefiles so we can't modify the function
+            # signature. Instead, we pass the data to ourselves using an
+            # instance attribute. I'm sorry.
+            self._mfdicts = mfdicts
+
         for chunk in self.generatefiles(changedfiles, linknodes, commonrevs,
                                         source):
             yield chunk