# HG changeset patch # User Laurent Charignon # Date 2015-11-18 21:44:29 # Node ID 5eac7ab59b95e5c2dc8dd6a268a51c49540fcbeb # Parent 53c668dc6b1601c8bda5098df4e33030dbdb454d rebase: don't rebase obsolete commits with no successor This patch avoids unnecessary conflicts to resolve during rebase for the users of changeset evolution. This patch modifies rebase to skip obsolete commits with no successor. It introduces a new rebase state 'revpruned' for these revisions that are being skipped and a new message to inform the user of what is happening. This feature is gated behind the config flag experimental.rebaseskipobsolete When an obsolete commit is skipped, the output is: note: not rebasing 7:360bbaa7d3ce "O", it has no successor diff --git a/hgext/rebase.py b/hgext/rebase.py --- a/hgext/rebase.py +++ b/hgext/rebase.py @@ -32,6 +32,7 @@ nullmerge = -2 revignored = -3 # To do with obsolescence revprecursor = -4 +revpruned = -5 cmdtable = {} command = cmdutil.command(cmdtable) @@ -487,6 +488,9 @@ def rebase(ui, repo, **opts): targetctx.description().split('\n', 1)[0]) msg = _('note: not rebasing %s, already in destination as %s\n') ui.status(msg % (desc, desctarget)) + elif state[rev] == revpruned: + msg = _('note: not rebasing %s, it has no successor\n') + ui.status(msg % desc) else: ui.status(_('already rebased %s as %s\n') % (desc, repo[state[rev]])) @@ -676,7 +680,7 @@ def defineparents(repo, rev, target, sta elif p1n in state: if state[p1n] == nullmerge: p1 = target - elif state[p1n] in (revignored, revprecursor): + elif state[p1n] in (revignored, revprecursor, revpruned): p1 = nearestrebased(repo, p1n, state) if p1 is None: p1 = target @@ -692,7 +696,7 @@ def defineparents(repo, rev, target, sta if p2n in state: if p1 == target: # p1n in targetancestors or external p1 = state[p2n] - elif state[p2n] in (revignored, revprecursor): + elif state[p2n] in (revignored, revprecursor, revpruned): p2 = nearestrebased(repo, p2n, state) if p2 is None: # no ancestors rebased yet, detach @@ -882,7 +886,7 @@ def restorestatus(repo): else: oldrev, newrev = l.split(':') if newrev in (str(nullmerge), str(revignored), - str(revprecursor)): + str(revprecursor), str(revpruned)): state[repo[oldrev].rev()] = int(newrev) elif newrev == nullid: state[repo[oldrev].rev()] = revtodo @@ -1066,7 +1070,10 @@ def buildstate(repo, dest, rebaseset, co for ignored in set(rebasedomain) - set(rebaseset): state[ignored] = revignored for r in obsoletenotrebased: - state[r] = revprecursor + if obsoletenotrebased[r] is None: + state[r] = revpruned + else: + state[r] = revprecursor return repo['.'].rev(), dest.rev(), state def clearrebased(ui, repo, state, skipped, collapsedas=None): @@ -1180,7 +1187,9 @@ def _rebasedvisible(orig, repo): def _computeobsoletenotrebased(repo, rebasesetrevs, dest): """return a mapping obsolete => successor for all obsolete nodes to be - rebased that have a successors in the destination""" + rebased that have a successors in the destination + + obsolete => None entries in the mapping indicate nodes with no succesor""" obsoletenotrebased = {} # Build a mapping successor => obsolete nodes for the obsolete @@ -1206,6 +1215,11 @@ def _computeobsoletenotrebased(repo, reb for s in allsuccessors: if s in ancs: obsoletenotrebased[allsuccessors[s]] = s + elif (s == allsuccessors[s] and + allsuccessors.values().count(s) == 1): + # plain prune + obsoletenotrebased[s] = None + return obsoletenotrebased def summaryhook(ui, repo): diff --git a/tests/test-rebase-obsolete.t b/tests/test-rebase-obsolete.t --- a/tests/test-rebase-obsolete.t +++ b/tests/test-rebase-obsolete.t @@ -659,3 +659,29 @@ Even when the chain include missing node $ hg rebase -d 'desc(B2)' note: not rebasing 1:a8b11f55fb19 "B0", already in destination as 2:261e70097290 "B2" rebasing 5:1a79b7535141 "D" (tip) + $ hg up 4 + 1 files updated, 0 files merged, 1 files removed, 0 files unresolved + $ echo "O" > O + $ hg add O + $ hg commit -m O + $ echo "P" > P + $ hg add P + $ hg commit -m P + $ hg log -G + @ 8:8d47583e023f P + | + o 7:360bbaa7d3ce O + | + | o 6:9c48361117de D + | | + o | 4:ff2c4d47b71d C + |/ + o 2:261e70097290 B2 + | + o 0:4a2df7238c3b A + + $ hg debugobsolete `hg log -r 7 -T '{node}\n'` --config experimental.evolution=all + $ hg rebase -d 6 -r "4::" + rebasing 4:ff2c4d47b71d "C" + note: not rebasing 7:360bbaa7d3ce "O", it has no successor + rebasing 8:8d47583e023f "P" (tip)