diff --git a/hgext/rebase.py b/hgext/rebase.py --- a/hgext/rebase.py +++ b/hgext/rebase.py @@ -479,12 +479,17 @@ 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 @@ 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 @@ '''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 @@ 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 @@ # ``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 @@ 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 @@ / 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 ..