diff --git a/hgext/rebase.py b/hgext/rebase.py index c83d36b81df131640281c20e7100e6e8a33bc009_aGdleHQvcmViYXNlLnB5..7159426c8d13647679e47f4692d5aeb7cdf31baa_aGdleHQvcmViYXNlLnB5 100644 --- a/hgext/rebase.py +++ b/hgext/rebase.py @@ -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,5 +551,7 @@ 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() @@ -536,6 +557,4 @@ 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): diff --git a/tests/test-rebase-obsolete.t b/tests/test-rebase-obsolete.t index c83d36b81df131640281c20e7100e6e8a33bc009_dGVzdHMvdGVzdC1yZWJhc2Utb2Jzb2xldGUudA==..7159426c8d13647679e47f4692d5aeb7cdf31baa_dGVzdHMvdGVzdC1yZWJhc2Utb2Jzb2xldGUudA== 100644 --- a/tests/test-rebase-obsolete.t +++ b/tests/test-rebase-obsolete.t @@ -366,6 +366,6 @@ $ hg rebase --dest 4 --rev '7+11+9' $ hg log -G - @ 14:00891d85fcfc C + @ 14:1e8370e38cca C | | o 13:102b4c1d889b D @@ -370,7 +370,7 @@ | | o 13:102b4c1d889b D - |/ - | o 12:bfe264faf697 H + | | + o | 12:bfe264faf697 H |/ | o 10:7c6027df6a99 B | |