diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py --- a/mercurial/localrepo.py +++ b/mercurial/localrepo.py @@ -1578,6 +1578,20 @@ class localrepository(repo.repository): the linkrev. """ + if extranodes is None: + # can we go through the fast path ? + heads.sort() + allheads = self.heads() + allheads.sort() + if heads == allheads: + common = [] + # parents of bases are known from both sides + for n in bases: + for p in self.changelog.parents(n): + if p != nullid: + common.append(p) + return self._changegroup(common, source) + self.hook('preoutgoing', throw=True, source=source) # Set up some initial variables @@ -1854,16 +1868,22 @@ class localrepository(repo.repository): return util.chunkbuffer(gengroup()) def changegroup(self, basenodes, source): + # to avoid a race we use changegroupsubset() (issue1320) + return self.changegroupsubset(basenodes, self.heads(), source) + + def _changegroup(self, common, source): """Generate a changegroup of all nodes that we have that a recipient doesn't. This is much easier than the previous function as we can assume that - the recipient has any changenode we aren't sending them.""" + the recipient has any changenode we aren't sending them. + + common is the set of common nodes between remote and self""" self.hook('preoutgoing', throw=True, source=source) cl = self.changelog - nodes = cl.nodesbetween(basenodes, None)[0] + nodes = cl.findmissing(common) revset = dict.fromkeys([cl.rev(n) for n in nodes]) self.changegroupinfo(nodes, source) diff --git a/mercurial/revlog.py b/mercurial/revlog.py --- a/mercurial/revlog.py +++ b/mercurial/revlog.py @@ -590,6 +590,46 @@ class revlog(object): yield i break + def findmissing(self, common=None, heads=None): + ''' + returns the topologically sorted list of nodes from the set: + missing = (ancestors(heads) \ ancestors(common)) + + where ancestors() is the set of ancestors from heads, heads included + + if heads is None, the heads of the revlog are used + if common is None, nullid is assumed to be a common node + ''' + if common is None: + common = [nullid] + if heads is None: + heads = self.heads() + + common = [self.rev(n) for n in common] + heads = [self.rev(n) for n in heads] + + # we want the ancestors, but inclusive + has = dict.fromkeys(self.ancestors(*common)) + has[nullrev] = None + for r in common: + has[r] = None + + # take all ancestors from heads that aren't in has + missing = {} + visit = [r for r in heads if r not in has] + while visit: + r = visit.pop(0) + if r in missing: + continue + else: + missing[r] = None + for p in self.parentrevs(r): + if p not in has: + visit.append(p) + missing = missing.keys() + missing.sort() + return [self.node(r) for r in missing] + def nodesbetween(self, roots=None, heads=None): """Return a tuple containing three elements. Elements 1 and 2 contain a final list bases and heads after all the unreachable ones have been diff --git a/tests/test-clone-cgi.out b/tests/test-clone-cgi.out --- a/tests/test-clone-cgi.out +++ b/tests/test-clone-cgi.out @@ -2,4 +2,4 @@ adding a % try hgweb request 0 -54086fe9a47b47d83204f38bda0b90c2 page1 +1f424bb22ec05c3c6bc866b6e67efe43 page1 diff --git a/tests/test-fetch.out b/tests/test-fetch.out --- a/tests/test-fetch.out +++ b/tests/test-fetch.out @@ -100,7 +100,7 @@ searching for changes adding changesets adding manifests adding file changes -added 1 changesets with 1 changes to 1 files +added 1 changesets with 1 changes to 2 files % parent should be 2 (no automatic update) 2 diff --git a/tests/test-hgweb-commands.out b/tests/test-hgweb-commands.out index 577476c62c1b24cbd56fff71bd689ca53504026b..14bc4c0b7206ed7e9237068423388639b6f4e81a GIT binary patch literal 22828 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