diff -r a06aab274aef -r d706c77449f9 mercurial/changegroup.py --- 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