diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py --- a/mercurial/localrepo.py +++ b/mercurial/localrepo.py @@ -354,6 +354,10 @@ class localrepository(object): manifestcachesize = self.ui.configint('format', 'manifestcachesize') if manifestcachesize is not None: self.svfs.options['manifestcachesize'] = manifestcachesize + # experimental config: format.aggressivemergedeltas + aggressivemergedeltas = self.ui.configbool('format', + 'aggressivemergedeltas', False) + self.svfs.options['aggressivemergedeltas'] = aggressivemergedeltas def _writerequirements(self): scmutil.writerequires(self.vfs, self.requirements) diff --git a/mercurial/revlog.py b/mercurial/revlog.py --- a/mercurial/revlog.py +++ b/mercurial/revlog.py @@ -210,6 +210,7 @@ class revlog(object): self._chunkcache = (0, '') self._chunkcachesize = 65536 self._maxchainlen = None + self._aggressivemergedeltas = False self.index = [] self._pcache = {} self._nodecache = {nullid: nullrev} @@ -227,6 +228,8 @@ class revlog(object): self._chunkcachesize = opts['chunkcachesize'] if 'maxchainlen' in opts: self._maxchainlen = opts['maxchainlen'] + if 'aggressivemergedeltas' in opts: + self._aggressivemergedeltas = opts['aggressivemergedeltas'] if self._chunkcachesize <= 0: raise RevlogError(_('revlog chunk cache size %r is not greater ' @@ -1343,15 +1346,34 @@ class revlog(object): # should we try to build a delta? if prev != nullrev: if self._generaldelta: - # Pick whichever parent is closer to us (to minimize the - # chance of having to build a fulltext). Since - # nullrev == -1, any non-merge commit will always pick p1r. - drev = p2r if p2r > p1r else p1r - d = builddelta(drev) - # If the chosen delta will result in us making a full text, - # give it one last try against prev. - if drev != prev and not self._isgooddelta(d, textlen): - d = builddelta(prev) + if p2r != nullrev and self._aggressivemergedeltas: + d = builddelta(p1r) + d2 = builddelta(p2r) + p1good = self._isgooddelta(d, textlen) + p2good = self._isgooddelta(d2, textlen) + if p1good and p2good: + # If both are good deltas, choose the smallest + if d2[1] < d[1]: + d = d2 + elif p2good: + # If only p2 is good, use it + d = d2 + elif p1good: + pass + else: + # Neither is good, try against prev to hopefully save us + # a fulltext. + d = builddelta(prev) + else: + # Pick whichever parent is closer to us (to minimize the + # chance of having to build a fulltext). Since + # nullrev == -1, any non-merge commit will always pick p1r. + drev = p2r if p2r > p1r else p1r + d = builddelta(drev) + # If the chosen delta will result in us making a full text, + # give it one last try against prev. + if drev != prev and not self._isgooddelta(d, textlen): + d = builddelta(prev) else: d = builddelta(prev) dist, l, data, base, chainbase, chainlen, compresseddeltalen = d diff --git a/tests/test-generaldelta.t b/tests/test-generaldelta.t --- a/tests/test-generaldelta.t +++ b/tests/test-generaldelta.t @@ -69,3 +69,37 @@ commit. rev offset length base linkrev nodeid p1 p2 0 0 3 0 1 1406e7411862 000000000000 000000000000 + $ cd .. + +Test format.aggressivemergedeltas + + $ hg init --config format.generaldelta=1 aggressive + $ cd aggressive + $ touch a b c d e + $ hg commit -Aqm side1 + $ hg up -q null + $ touch x y + $ hg commit -Aqm side2 + +- Verify non-aggressive merge uses p1 (commit 1) as delta parent + $ hg merge -q 0 + $ hg commit -q -m merge + $ hg debugindex -m + rev offset length delta linkrev nodeid p1 p2 + 0 0 59 -1 0 8dde941edb6e 000000000000 000000000000 + 1 59 59 -1 1 315c023f341d 000000000000 000000000000 + 2 118 65 1 2 2ab389a983eb 315c023f341d 8dde941edb6e + + $ hg strip -q -r . --config extensions.strip= + +- Verify aggressive merge uses p2 (commit 0) as delta parent + $ hg up -q -C 1 + $ hg merge -q 0 + $ hg commit -q -m merge --config format.aggressivemergedeltas=True + $ hg debugindex -m + rev offset length delta linkrev nodeid p1 p2 + 0 0 59 -1 0 8dde941edb6e 000000000000 000000000000 + 1 59 59 -1 1 315c023f341d 000000000000 000000000000 + 2 118 62 0 2 2ab389a983eb 315c023f341d 8dde941edb6e + + $ cd ..