diff --git a/mercurial/changegroup.py b/mercurial/changegroup.py --- a/mercurial/changegroup.py +++ b/mercurial/changegroup.py @@ -316,6 +316,7 @@ class cg1packer(object): # for progress output msgbundling = _('bundling') + clrevorder = {} mfs = {} # needed manifests fnodes = {} # needed file nodes changedfiles = set() @@ -325,6 +326,7 @@ class cg1packer(object): # Returns the linkrev node (identity in the changelog case). def lookupcl(x): c = cl.read(x) + clrevorder[x] = len(clrevorder) changedfiles.update(c[3]) # record the first changeset introducing this manifest version mfs.setdefault(c[0], x) @@ -340,13 +342,16 @@ class cg1packer(object): # Returns the linkrev node (collected in lookupcl). def lookupmf(x): clnode = mfs[x] - if not fastpathlinkrev: + if not fastpathlinkrev or reorder: mdata = mf.readfast(x) for f, n in mdata.iteritems(): if f in changedfiles: # record the first changeset introducing this filelog # version - fnodes.setdefault(f, {}).setdefault(n, clnode) + fclnodes = fnodes.setdefault(f, {}) + fclnode = fclnodes.setdefault(n, clnode) + if clrevorder[clnode] < clrevorder[fclnode]: + fclnodes[n] = clnode return clnode mfnodes = self.prune(mf, mfs, commonrevs, source) @@ -359,7 +364,7 @@ class cg1packer(object): needed = set(cl.rev(x) for x in clnodes) def linknodes(filerevlog, fname): - if fastpathlinkrev: + if fastpathlinkrev and not reorder: llr = filerevlog.linkrev def genfilenodes(): for r in filerevlog: diff --git a/tests/test-generaldelta.t b/tests/test-generaldelta.t old mode 100755 new mode 100644 --- a/tests/test-generaldelta.t +++ b/tests/test-generaldelta.t @@ -22,3 +22,50 @@ inserted due to big distance from its pa >>> gdsize = os.stat("gdrepo/.hg/store/00manifest.i").st_size >>> if regsize < gdsize: ... print 'generaldata increased size of manifest' + +Verify rev reordering doesnt create invalid bundles (issue4462) +This requires a commit tree that when pulled will reorder manifest revs such +that the second manifest to create a file rev will be ordered before the first +manifest to create that file rev. We also need to do a partial pull to ensure +reordering happens. At the end we verify the linkrev points at the earliest +commit. + + $ hg init server --config format.generaldelta=True + $ cd server + $ touch a + $ hg commit -Aqm a + $ echo x > x + $ echo y > y + $ hg commit -Aqm xy + $ hg up -q '.^' + $ echo x > x + $ echo z > z + $ hg commit -Aqm xz + $ hg up -q 1 + $ echo b > b + $ hg commit -Aqm b + $ hg merge -q 2 + $ hg commit -Aqm merge + $ echo c > c + $ hg commit -Aqm c + $ hg log -G -T '{rev} {shortest(node)} {desc}' + @ 5 ebb8 c + | + o 4 baf7 merge + |\ + | o 3 a129 b + | | + o | 2 958c xz + | | + | o 1 f00c xy + |/ + o 0 3903 a + + $ cd .. + $ hg init client + $ cd client + $ hg pull -q ../server -r 4 + $ hg debugindex x + rev offset length base linkrev nodeid p1 p2 + 0 0 3 0 1 1406e7411862 000000000000 000000000000 +