Mercurial > hg
changeset 31514:2519994d25ca
rebase: use one dirstateguard for entire rebase
Recently we switched rebases to run the entire rebase inside a single
transaction, which dramatically improved the speed of rebases in repos with
large working copies. Let's also move the dirstate into a single dirstateguard
to get the same benefits. This let's us avoid serializing the dirstate after
each commit.
In a large repo, rebasing 27 commits is sped up by about 20%.
I believe the test changes are because us touching the dirstate gave the
transaction something to actually rollback.
author | Durham Goode <durham@fb.com> |
---|---|
date | Sun, 19 Mar 2017 11:54:15 -0700 |
parents | 68474b72ea63 |
children | 527a247f114f |
files | hgext/rebase.py tests/test-rebase-collapse.t tests/test-rebase-scenario-global.t |
diffstat | 3 files changed, 50 insertions(+), 31 deletions(-) [+] |
line wrap: on
line diff
--- a/hgext/rebase.py Fri Mar 10 15:52:29 2017 -0800 +++ b/hgext/rebase.py Sun Mar 19 11:54:15 2017 -0700 @@ -475,12 +475,24 @@ editopt = True editor = cmdutil.getcommiteditor(edit=editopt, editform=editform) revtoreuse = max(self.state) - newnode = concludenode(repo, revtoreuse, p1, self.external, - commitmsg=commitmsg, - extrafn=_makeextrafn(self.extrafns), - editor=editor, - keepbranches=self.keepbranchesf, - date=self.date) + dsguard = dirstateguard.dirstateguard(repo, 'rebase') + try: + newnode = concludenode(repo, revtoreuse, p1, self.external, + commitmsg=commitmsg, + extrafn=_makeextrafn(self.extrafns), + editor=editor, + keepbranches=self.keepbranchesf, + date=self.date) + dsguard.close() + release(dsguard) + except error.InterventionRequired: + dsguard.close() + release(dsguard) + raise + except Exception: + release(dsguard) + raise + if newnode is None: newrev = self.target else: @@ -712,11 +724,19 @@ return retcode with repo.transaction('rebase') as tr: + dsguard = dirstateguard.dirstateguard(repo, 'rebase') try: rbsrt._performrebase(tr) + dsguard.close() + release(dsguard) except error.InterventionRequired: + dsguard.close() + release(dsguard) tr.close() raise + except Exception: + release(dsguard) + raise rbsrt._finishrebase() finally: release(lock, wlock) @@ -840,33 +860,28 @@ '''Commit the wd changes with parents p1 and p2. Reuse commit info from rev but also store useful information in extra. Return node of committed revision.''' - dsguard = dirstateguard.dirstateguard(repo, 'rebase') - try: - repo.setparents(repo[p1].node(), repo[p2].node()) - ctx = repo[rev] - if commitmsg is None: - commitmsg = ctx.description() - keepbranch = keepbranches and repo[p1].branch() != ctx.branch() - extra = {'rebase_source': ctx.hex()} - if extrafn: - extrafn(ctx, extra) + repo.setparents(repo[p1].node(), repo[p2].node()) + ctx = repo[rev] + if commitmsg is None: + commitmsg = ctx.description() + keepbranch = keepbranches and repo[p1].branch() != ctx.branch() + extra = {'rebase_source': ctx.hex()} + if extrafn: + extrafn(ctx, extra) - targetphase = max(ctx.phase(), phases.draft) - overrides = {('phases', 'new-commit'): targetphase} - with repo.ui.configoverride(overrides, 'rebase'): - if keepbranch: - repo.ui.setconfig('ui', 'allowemptycommit', True) - # Commit might fail if unresolved files exist - if date is None: - date = ctx.date() - newnode = repo.commit(text=commitmsg, user=ctx.user(), - date=date, extra=extra, editor=editor) + targetphase = max(ctx.phase(), phases.draft) + overrides = {('phases', 'new-commit'): targetphase} + with repo.ui.configoverride(overrides, 'rebase'): + if keepbranch: + repo.ui.setconfig('ui', 'allowemptycommit', True) + # Commit might fail if unresolved files exist + if date is None: + date = ctx.date() + newnode = repo.commit(text=commitmsg, user=ctx.user(), + date=date, extra=extra, editor=editor) - repo.dirstate.setbranch(repo[newnode].branch()) - dsguard.close() - return newnode - finally: - release(dsguard) + repo.dirstate.setbranch(repo[newnode].branch()) + return newnode def rebasenode(repo, rev, p1, base, state, collapse, target): 'Rebase a single revision rev on top of p1 using base as merge ancestor'
--- a/tests/test-rebase-collapse.t Fri Mar 10 15:52:29 2017 -0800 +++ b/tests/test-rebase-collapse.t Sun Mar 19 11:54:15 2017 -0700 @@ -572,6 +572,8 @@ o 0: 'A' $ hg rebase --keepbranches --collapse -s 1 -d 3 + transaction abort! + rollback completed abort: cannot collapse multiple named branches [255]
--- a/tests/test-rebase-scenario-global.t Fri Mar 10 15:52:29 2017 -0800 +++ b/tests/test-rebase-scenario-global.t Sun Mar 19 11:54:15 2017 -0700 @@ -270,6 +270,8 @@ $ hg rebase -s 6 -d 1 rebasing 6:eea13746799a "G" + transaction abort! + rollback completed abort: cannot use revision 6 as base, result would have 3 parents [255] $ hg rebase --abort