[PATCH 2 of 2] rebase: skip resolved but emptied revisions

Patrick Mezard patrick at mezard.eu
Fri Apr 20 08:08:18 CDT 2012


# HG changeset patch
# User Patrick Mezard <patrick at mezard.eu>
# Date 1334927278 -7200
# Branch stable
# Node ID 22428bd2b8b0691f7fd4dd23d18a5b09d9da7d7a
# Parent  39181f76286e8b6313f35da84ecd5799941ab55b
rebase: skip resolved but emptied revisions

When rebasing, if a conflict occurs and is resolved in a way the rebased
revision becomes empty, it is not skipped, unlike revisions being emptied
without conflicts.

The reason is:
- File 'x' is merged and resolved, merge.update() marks it as 'm' in the
  dirstate.
- rebase.concludenode() calls localrepo.commit(), which calls
  localrepo.status() which calls dirstate.status(). 'x' shows up as 'm' and is
  unconditionnally added to the modified files list, instead of being checked
  again.
- localrepo.commit() detects 'x' as changed an create a new revision where only
  the manifest parents and linkrev differ.

Marking 'x' as modified without checking it makes sense for regular merges. But
in rebase case, the merge looks normal but the second parent is usually
discarded. When this happens, 'm' files in dirstate are a bit irrelevant and
should be considered 'n' possibly dirty instead. That is what the current patch
does.

Another approach, maybe more efficient, would be to pass another flag to
merge.update() saying the 'branchmerge' is a bit of a lie and recordupdate()
should call dirstate.normallookup() instead of merge().

It is also tempting to add this logic to dirstate.setparent(), moving from two
to one parent is what invalidates the 'm' markers. But this is a far bigger
change to make.

diff --git a/hgext/rebase.py b/hgext/rebase.py
--- a/hgext/rebase.py
+++ b/hgext/rebase.py
@@ -362,6 +362,14 @@
     'Commit the changes and store useful information in extra'
     try:
         repo.dirstate.setparents(repo[p1].node(), repo[p2].node())
+        if p2 == nullrev:
+            # Rebased revision has only one parent, discard merged
+            # files 'merged' flag from dirstate to force a recheck in
+            # status().
+            ds = repo.dirstate
+            for f in ds:
+                if ds[f] == 'm':
+                    ds.normallookup(f)
         ctx = repo[rev]
         if commitmsg is None:
             commitmsg = ctx.description()
diff --git a/tests/test-rebase-detach.t b/tests/test-rebase-detach.t
--- a/tests/test-rebase-detach.t
+++ b/tests/test-rebase-detach.t
@@ -380,9 +380,7 @@
   $ hg rebase -c
   saved backup bundle to $TESTTMP/a7/.hg/strip-backup/6215fafa5447-backup.hg (glob)
   $ hg  log -G --template "{rev}:{phase} '{desc}' {branches}\n"
-  @  8:secret 'H2'
-  |
-  o  7:draft 'H'
+  @  7:draft 'H'
   |
   | o  6:draft 'G'
   |/|
@@ -398,11 +396,3 @@
   |/
   o  0:draft 'A'
   
-  $ hg export 8
-  # HG changeset patch
-  # User test
-  # Date 0 0
-  # Node ID 248209b40064fe67181915fa7a4f3395520f700a
-  # Parent  02de42196ebee42ef284b6780a87cdc96e8eaab6
-  H2
-  
diff --git a/tests/test-rebase-mq-skip.t b/tests/test-rebase-mq-skip.t
--- a/tests/test-rebase-mq-skip.t
+++ b/tests/test-rebase-mq-skip.t
@@ -117,9 +117,7 @@
   saved backup bundle to $TESTTMP/b/.hg/strip-backup/*-backup.hg (glob)
 
   $ hg tglog
-  @  9: 'r5' tags: 5.diff qtip tip
-  |
-  o  8: 'r4' tags: 4.diff
+  @  8: 'r5' tags: 5.diff qtip tip
   |
   o  7: 'r2' tags: 2.diff qbase
   |
@@ -137,11 +135,3 @@
   |
   o  0: 'r0' tags:
   
-  $ hg export 4.diff
-  # HG changeset patch
-  # User test
-  # Date 0 0
-  # Node ID 315eb21a13c2b06e787f5d0000e36f8f8f3a1768
-  # Parent  1660ab13ce9aea3da22ea54926bd49aeff8a4e20
-  r4
-  


More information about the Mercurial-devel mailing list