Mercurial > hg
changeset 18447:7159426c8d13
rebase: properly handle unrebased revision between rebased one
With rebase taking multiple roots it is possible to have revision in the "rebase
domain" not rebased themself. We do not want rebased revision above them to be
detached. We want such revision to be rebased on the nearest rebased ancestors.
This allows to preserve the topology of the rebase set as much a possible
To achieve this we introduce a new state `revignored` which informs
`defineparents` of the situation.
The test in `test-rebase-obsolete.t` was actually wrote and his now fixed.
author | Pierre-Yves David <pierre-yves.david@ens-lyon.org> |
---|---|
date | Fri, 18 Jan 2013 23:41:48 +0100 |
parents | c83d36b81df1 |
children | e760414be201 |
files | hgext/rebase.py tests/test-rebase-obsolete.t |
diffstat | 2 files changed, 34 insertions(+), 6 deletions(-) [+] |
line wrap: on
line diff
--- a/hgext/rebase.py Fri Jan 18 23:21:32 2013 +0100 +++ b/hgext/rebase.py Fri Jan 18 23:41:48 2013 +0100 @@ -23,6 +23,7 @@ import os, errno nullmerge = -2 +revignored = -3 cmdtable = {} command = cmdutil.command(cmdtable) @@ -392,6 +393,15 @@ # have to allow merging with it. return merge.update(repo, rev, True, True, False, base, collapse) +def nearestrebased(repo, rev, state): + """return the nearest ancestors of rev in the rebase result""" + rebased = [r for r in state if state[r] > nullmerge] + candidates = repo.revs('max(%ld and (::%d))', rebased, rev) + if candidates: + return state[candidates[0]] + else: + return None + def defineparents(repo, rev, target, state, targetancestors): 'Return the new parent relationship of the revision that will be rebased' parents = repo[rev].parents() @@ -403,6 +413,10 @@ elif P1n in state: if state[P1n] == nullmerge: p1 = target + elif state[P1n] == revignored: + p1 = nearestrebased(repo, P1n, state) + if p1 is None: + p1 = target else: p1 = state[P1n] else: # P1n external @@ -415,6 +429,11 @@ if P2n in state: if p1 == target: # P1n in targetancestors or external p1 = state[P2n] + elif state[P2n] == revignored: + p2 = nearestrebased(repo, P2n, state) + if p2 is None: + # no ancestors rebased yet, detach + p2 = target else: p2 = state[P2n] else: # P2n external @@ -532,10 +551,10 @@ keepbranches = bool(int(l)) else: oldrev, newrev = l.split(':') - if newrev != str(nullmerge): + if newrev in (str(nullmerge), str(revignored)): + state[repo[oldrev].rev()] = int(newrev) + else: state[repo[oldrev].rev()] = repo[newrev].rev() - else: - state[repo[oldrev].rev()] = int(newrev) skipped = set() # recompute the set of skipped revs if not collapse: @@ -658,6 +677,15 @@ for r in detachset: if r not in state: state[r] = nullmerge + if len(roots) > 1: + # If we have multiple roots, we may have "hole" in the rebase set. + # Rebase roots that descend from those "hole" should not be detached as + # other root are. We use the special `revignored` to inform rebase that + # the revision should be ignored but that `defineparent` should search + # a rebase destination that make sense regarding rebaset topology. + rebasedomain = set(repo.revs('%ld::%ld', rebaseset, rebaseset)) + for ignored in set(rebasedomain) - set(rebaseset): + state[ignored] = revignored return repo['.'].rev(), dest.rev(), state def clearrebased(ui, repo, state, skipped, collapsedas=None):
--- a/tests/test-rebase-obsolete.t Fri Jan 18 23:21:32 2013 +0100 +++ b/tests/test-rebase-obsolete.t Fri Jan 18 23:41:48 2013 +0100 @@ -366,11 +366,11 @@ $ hg rebase --dest 4 --rev '7+11+9' $ hg log -G - @ 14:00891d85fcfc C + @ 14:1e8370e38cca C | | o 13:102b4c1d889b D - |/ - | o 12:bfe264faf697 H + | | + o | 12:bfe264faf697 H |/ | o 10:7c6027df6a99 B | |