[PATCH] rebase: rebase changesets with branch grouped

Xidorn Quan me at upsuper.org
Sat Sep 17 07:11:24 UTC 2016


# HG changeset patch
# User Xidorn Quan <me at upsuper.org>
# Date 1474095776 -36000
#      Sat Sep 17 17:02:56 2016 +1000
# Node ID 88184dc23ccacfc8ae450abc5d574b8b028bca79
# Parent  285a8c3e53f2183438f0cdbc238e4ab851d0d110
rebase: rebase changesets with branch grouped

diff --git a/hgext/rebase.py b/hgext/rebase.py
--- a/hgext/rebase.py
+++ b/hgext/rebase.py
@@ -330,18 +330,38 @@ class rebaseruntime(object):
                                                                inclusive=True)
 
         # Keep track of the current bookmarks in order to reset them later
         self.currentbookmarks = repo._bookmarks.copy()
         self.activebookmark = self.activebookmark or repo._activebookmark
         if self.activebookmark:
             bookmarks.deactivate(repo)
 
-        sortedrevs = sorted(self.state)
+        # Sort revisions with branches grouped
         cands = [k for k, v in self.state.iteritems() if v == revtodo]
+        remainrevs = set(self.state.iterkeys())
+        sortedrevs = []
+        # Sort based on candidates and put their ancestors with them
+        for cand in util.branchsorted(repo, cands):
+            ancestors = [cand]
+            remainrevs.remove(cand)
+            i = 0
+            while i < len(ancestors):
+                ctx = repo[ancestors[i]]
+                for p in ctx.parents():
+                    prev = p.rev()
+                    if prev in remainrevs:
+                        remainrevs.remove(prev)
+                        ancestors.append(prev)
+                i += 1
+            ancestors.reverse()
+            sortedrevs.extend(ancestors)
+        # Finally, descendents which are not rebased
+        sortedrevs.extend(sorted(remainrevs))
+
         total = len(cands)
         pos = 0
         for rev in sortedrevs:
             ctx = repo[rev]
             desc = '%d:%s "%s"' % (ctx.rev(), ctx,
                                    ctx.description().split('\n', 1)[0])
             names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
             if names:
diff --git a/mercurial/util.py b/mercurial/util.py
--- a/mercurial/util.py
+++ b/mercurial/util.py
@@ -2897,8 +2897,33 @@ decompressors = {None: lambda fh: fh,
                  'BZ': _makedecompressor(lambda: bz2.BZ2Decompressor()),
                  'GZ': _makedecompressor(lambda: zlib.decompressobj()),
                  }
 # also support the old form by courtesies
 decompressors['UN'] = decompressors[None]
 
 # convenient shortcut
 dst = debugstacktrace
+
+def branchsorted(repo, revs, sortrevs=None):
+    '''Returns a sorted list of revisions in a order that branches are
+    grouped together.'''
+    remainrevs = set(revs)
+    stack = [sorted(revs, reverse=True)]
+    result = []
+    while stack:
+        stacktop = stack[-1]
+        if not stacktop:
+            stack.pop()
+            continue
+        nextrev = stacktop.pop()
+        if nextrev not in remainrevs:
+            continue
+        ctx = repo[nextrev]
+        # If any of its parents is still in remainrevs, we can not put
+        # the changeset into result. We would traverse to it again when
+        # we resolve all its parents.
+        if any(p.rev() in remainrevs for p in ctx.parents()):
+            continue
+        remainrevs.remove(nextrev)
+        result.append(nextrev)
+        stack.append(sorted((c.rev() for c in ctx.children()), reverse=True))
+    return result
diff --git a/tests/test-rebase-branch-order.t b/tests/test-rebase-branch-order.t
new file mode 100644
--- /dev/null
+++ b/tests/test-rebase-branch-order.t
@@ -0,0 +1,89 @@
+  $ cat >> $HGRCPATH <<EOF
+  > [extensions]
+  > rebase=
+  > [alias]
+  > tglog=log -G --template "{rev}:{node|short} {desc}"
+  > EOF
+
+  $ hg init repo
+  $ cd repo
+
+  $ touch a
+  $ hg ci -Am A
+  adding a
+
+  $ touch b
+  $ hg ci -Am B
+  adding b
+
+  $ touch c
+  $ hg ci -Am C
+  adding c
+
+  $ hg up 1
+  0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+  $ touch d
+  $ hg ci -Am D
+  adding d
+  created new head
+
+  $ hg up 2
+  1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+  $ touch e
+  $ hg ci -Am E
+  adding e
+
+  $ hg up 3
+  1 files updated, 0 files merged, 2 files removed, 0 files unresolved
+  $ touch f
+  $ hg ci -Am F
+  adding f
+
+  $ hg up 0
+  0 files updated, 0 files merged, 3 files removed, 0 files unresolved
+  $ touch g
+  $ hg ci -Am G
+  adding g
+  created new head
+
+  $ hg tglog
+  @  6:124bb27b6f28 G
+  |
+  | o  5:412b391de760 F
+  | |
+  | | o  4:82ae8dc7a9b7 E
+  | | |
+  | o |  3:ab709c9f7171 D
+  | | |
+  | | o  2:d84f5cfaaf14 C
+  | |/
+  | o  1:76035bbd54bd B
+  |/
+  o  0:216878401574 A
+  
+
+Test rebasing is done with commits in branch grouped together.
+
+  $ hg rebase -s 1 -d 6
+  rebasing 1:76035bbd54bd "B"
+  rebasing 2:d84f5cfaaf14 "C"
+  rebasing 4:82ae8dc7a9b7 "E"
+  rebasing 3:ab709c9f7171 "D"
+  rebasing 5:412b391de760 "F"
+  saved backup bundle to $TESTTMP/repo/.hg/strip-backup/76035bbd54bd-e341bc99-backup.hg (glob)
+
+  $ hg tglog
+  o  6:31884cfb735e F
+  |
+  o  5:6d89fa5b0909 D
+  |
+  | o  4:de64d97c697b E
+  | |
+  | o  3:b18e4d2d0aa1 C
+  |/
+  o  2:0983daf9ff6a B
+  |
+  @  1:124bb27b6f28 G
+  |
+  o  0:216878401574 A
+  


More information about the Mercurial-devel mailing list