rebase: properly handle unrebased revision between rebased one
authorPierre-Yves David <pierre-yves.david@ens-lyon.org>
Fri, 18 Jan 2013 23:41:48 +0100
changeset 18447 7159426c8d13
parent 18446 c83d36b81df1
child 18448 e760414be201
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.
hgext/rebase.py
tests/test-rebase-obsolete.t
--- 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
   | |