diff --git a/hgext/rebase.py b/hgext/rebase.py --- a/hgext/rebase.py +++ b/hgext/rebase.py @@ -479,12 +479,17 @@ class rebaseruntime(object): 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 = None + if ui.configbool('rebase', 'singletransaction'): + dsguard = dirstateguard.dirstateguard(repo, 'rebase') + with util.acceptintervention(dsguard): + newnode = concludenode(repo, revtoreuse, p1, self.external, + commitmsg=commitmsg, + extrafn=_makeextrafn(self.extrafns), + editor=editor, + keepbranches=self.keepbranchesf, + date=self.date) if newnode is None: newrev = self.dest else: @@ -711,10 +716,16 @@ def rebase(ui, repo, **opts): return retcode tr = None - if ui.configbool('rebase', 'singletransaction'): + dsguard = None + + singletr = ui.configbool('rebase', 'singletransaction') + if singletr: tr = repo.transaction('rebase') with util.acceptintervention(tr): - rbsrt._performrebase(tr) + if singletr: + dsguard = dirstateguard.dirstateguard(repo, 'rebase') + with util.acceptintervention(dsguard): + rbsrt._performrebase(tr) rbsrt._finishrebase() @@ -841,8 +852,10 @@ def concludenode(repo, rev, p1, p2, comm '''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: + dsguard = util.nullcontextmanager() + if not repo.ui.configbool('rebase', 'singletransaction'): + dsguard = dirstateguard.dirstateguard(repo, 'rebase') + with dsguard: repo.setparents(repo[p1].node(), repo[p2].node()) ctx = repo[rev] if commitmsg is None: @@ -864,10 +877,7 @@ def concludenode(repo, rev, p1, p2, comm date=date, extra=extra, editor=editor) repo.dirstate.setbranch(repo[newnode].branch()) - dsguard.close() return newnode - finally: - release(dsguard) def rebasenode(repo, rev, p1, base, state, collapse, dest): 'Rebase a single revision rev on top of p1 using base as merge ancestor' diff --git a/mercurial/dirstateguard.py b/mercurial/dirstateguard.py --- a/mercurial/dirstateguard.py +++ b/mercurial/dirstateguard.py @@ -43,6 +43,16 @@ class dirstateguard(object): # ``release(tr, ....)``. self._abort() + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + try: + if exc_type is None: + self.close() + finally: + self.release() + def close(self): if not self._active: # already inactivated msg = (_("can't close already inactivated backup: %s") diff --git a/mercurial/util.py b/mercurial/util.py --- a/mercurial/util.py +++ b/mercurial/util.py @@ -602,6 +602,10 @@ def acceptintervention(tr=None): finally: tr.release() +@contextlib.contextmanager +def nullcontextmanager(): + yield + class _lrucachenode(object): """A node in a doubly linked list. diff --git a/tests/test-rebase-base.t b/tests/test-rebase-base.t --- a/tests/test-rebase-base.t +++ b/tests/test-rebase-base.t @@ -379,3 +379,40 @@ Multiple roots. Two children share two p / o 0: A +Rebasing using a single transaction + + $ hg init singletr && cd singletr + $ cat >> .hg/hgrc < [rebase] + > singletransaction=True + > EOF + $ hg debugdrawdag <<'EOF' + > Z + > | + > | D + > | | + > | C + > | | + > Y B + > |/ + > A + > EOF +- We should only see two status stored messages. One from the start, one from +- the end. + $ hg rebase --debug -b D -d Z | grep 'status stored' + rebase status stored + rebase status stored + $ hg tglog + o 5: D + | + o 4: C + | + o 3: B + | + o 2: Z + | + o 1: Y + | + o 0: A + + $ cd ..