diff --git a/hgext/rebase.py b/hgext/rebase.py --- a/hgext/rebase.py +++ b/hgext/rebase.py @@ -495,11 +495,21 @@ merging = p2 != nullrev editform = cmdutil.mergeeditform(merging, 'rebase') editor = cmdutil.getcommiteditor(editform=editform, **opts) - newnode = concludenode(repo, rev, p1, p2, - extrafn=_makeextrafn(self.extrafns), - editor=editor, - keepbranches=self.keepbranchesf, - date=self.date) + if self.wctx.isinmemory(): + newnode = concludememorynode(repo, rev, p1, p2, + wctx=self.wctx, + extrafn=_makeextrafn(self.extrafns), + editor=editor, + keepbranches=self.keepbranchesf, + date=self.date) + mergemod.mergestate.clean(repo) + else: + newnode = concludenode(repo, rev, p1, p2, + extrafn=_makeextrafn(self.extrafns), + editor=editor, + keepbranches=self.keepbranchesf, + date=self.date) + if newnode is None: # If it ended up being a no-op commit, then the normal # merge state clean-up path doesn't happen, so do it @@ -552,13 +562,22 @@ 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 self.inmemory: + newnode = concludememorynode(repo, revtoreuse, p1, + self.external, + commitmsg=commitmsg, + extrafn=_makeextrafn(self.extrafns), + editor=editor, + keepbranches=self.keepbranchesf, + date=self.date, wctx=self.wctx) + else: + 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 not None: newrev = repo[newnode].rev() for oldrev in self.state.iterkeys(): @@ -964,6 +983,44 @@ (max(destancestors), ', '.join(str(p) for p in sorted(parents)))) +def concludememorynode(repo, rev, p1, p2, wctx=None, + commitmsg=None, editor=None, extrafn=None, + keepbranches=False, date=None): + '''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.''' + 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) + + destphase = max(ctx.phase(), phases.draft) + overrides = {('phases', 'new-commit'): destphase} + with repo.ui.configoverride(overrides, 'rebase'): + if keepbranch: + repo.ui.setconfig('ui', 'allowemptycommit', True) + # Replicates the empty check in ``repo.commit``. + if not wctx.isempty() or repo.ui.configbool('ui', 'allowemptycommit'): + return None + + if date is None: + date = ctx.date() + + # By convention, ``extra['branch']`` (set by extrafn) clobbers + # ``branch`` (used when passing ``--keepbranches``). + branch = repo[p1].branch() + if 'branch' in extra: + branch = extra['branch'] + + memctx = wctx.tomemctx(commitmsg, parents=(p1, p2), date=date, + extra=extra, user=ctx.user(), branch=branch, editor=editor) + commitres = repo.commitctx(memctx) + wctx.clean() # Might be reused + return commitres + def concludenode(repo, rev, p1, p2, commitmsg=None, editor=None, extrafn=None, keepbranches=False, date=None): '''Commit the wd changes with parents p1 and p2. Reuse commit info from rev diff --git a/mercurial/context.py b/mercurial/context.py --- a/mercurial/context.py +++ b/mercurial/context.py @@ -2224,6 +2224,12 @@ def isdirty(self, path): return path in self._cache + + def isempty(self): + # We need to discard any keys that are actually clean before the empty + # commit check. + self._compact() + return len(self._cache) == 0 def clean(self): self._cache = {}