Patchwork [STABLE] rebase: fix selection of base used when rebasing merge (issue4041)

login
register
mail settings
Submitter Pierre-Yves David
Date Oct. 30, 2013, 6:48 p.m.
Message ID <f036489f6af80175aa6b.1383158895@yamac-wifi.lan>
Download mbox | patch
Permalink /patch/2834/
State Superseded
Commit 9bfa86746c9c1f6ab51deb8f174ffc482417d09f
Headers show

Comments

Pierre-Yves David - Oct. 30, 2013, 6:48 p.m.
# HG changeset patch
# User Pierre-Yves David <pierre-yves.david@ens-lyon.org>
# Date 1383158714 -3600
#      Wed Oct 30 19:45:14 2013 +0100
# Branch stable
# Node ID f036489f6af80175aa6bed3025501caaa36f83df
# Parent  1d7a36ff2615e6e12ce65681db4e07622e7b60d1
rebase: fix selection of base used when rebasing merge (issue4041)

Prior this changeset, rebasing a merge whom first parent was not in the rebase
lead to wrong and highly conflicting merge. See the in-line comment for details.

Test have been updated with the data provided by the reported.
Matt Mackall - Nov. 1, 2013, 9:24 p.m.
On Wed, 2013-10-30 at 19:48 +0100, Pierre-Yves David wrote:
> # HG changeset patch
> # User Pierre-Yves David <pierre-yves.david@ens-lyon.org>
> # Date 1383158714 -3600
> #      Wed Oct 30 19:45:14 2013 +0100
> # Branch stable
> # Node ID f036489f6af80175aa6bed3025501caaa36f83df
> # Parent  1d7a36ff2615e6e12ce65681db4e07622e7b60d1
> rebase: fix selection of base used when rebasing merge (issue4041)

Queued for stable, thanks.

Patch

diff --git a/hgext/rebase.py b/hgext/rebase.py
--- a/hgext/rebase.py
+++ b/hgext/rebase.py
@@ -445,13 +445,48 @@  def rebasenode(repo, rev, p1, state, col
         merge.update(repo, p1, False, True, False)
     else:
         repo.ui.debug(" already in target\n")
     repo.dirstate.write()
     repo.ui.debug(" merge against %d:%s\n" % (repo[rev].rev(), repo[rev]))
-    base = None
-    if repo[rev].rev() != repo[min(state)].rev():
+    if repo[rev].rev() == repo[min(state)].rev():
+        # Case (1) initial changeset of a non-detaching rebase.
+        # Let the merge mechanism find the base itself.
+        base = None
+    elif not repo[rev].p2():
+        # Case (2) detaching the node with a single parent, use this parent
         base = repo[rev].p1().node()
+    else:
+        # In case of merge, we need to pick the right parent as merge base.
+        #
+        # Imagine we have:
+        # - M: currently rebase revision in this step
+        # - A: one parent of M
+        # - B: second parent of M
+        # - D: destination of this merge step (p1 var)
+        #
+        # If we are rebasing on D, D is the successors of A or B. The right
+        # merge base is the one D succeed to. We pretend it is B for the rest
+        # of this comment
+        #
+        # If we pick B as the base, the merge involves:
+        # - changes from B to M (actual changeset payload)
+        # - changes from B to D (induced by rebase) as D is a rebased
+        #   version of B)
+        # Which exactly represent the rebase operation.
+        #
+        # If we pick the A as the base, the merge involves
+        # - changes from A to M (actual changeset payload)
+        # - changes from A to D (with include changes between unrelated A and B
+        #   plus changes induced by rebase)
+        # Which does not represent anything sensible and creates a lot of
+        # conflicts.
+        for p in repo[rev].parents():
+            if state.get(p.rev()) == repo[p1].rev():
+                base = p.node()
+                break
+    if base is not None:
+        repo.ui.debug("   detach base %d:%s\n" % (repo[base].rev(), repo[base]))
     # When collapsing in-place, the parent is the common ancestor, we
     # have to allow merging with it.
     return merge.update(repo, rev, True, True, False, base, collapse)
 
 def nearestrebased(repo, rev, state):
diff --git a/tests/bundles/issue4041.hg b/tests/bundles/issue4041.hg
new file mode 100644
index 0000000000000000000000000000000000000000..6a31748ad67fa7fd4b12387b32e13e68b08f8d65
GIT binary patch
literal 2216
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

diff --git a/tests/test-rebase-conflicts.t b/tests/test-rebase-conflicts.t
--- a/tests/test-rebase-conflicts.t
+++ b/tests/test-rebase-conflicts.t
@@ -122,5 +122,186 @@  Check correctness:
 Bookmark stays active after --continue
   $ hg bookmarks
    * mybook                    5:d67b21408fc0
 
   $ cd ..
+
+Check that the right ancestors is used while rebasing a merge (issue4041)
+
+  $ hg clone "$TESTDIR/bundles/issue4041.hg" issue4041
+  requesting all changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 11 changesets with 8 changes to 3 files (+1 heads)
+  updating to branch default
+  2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ cd issue4041
+  $ hg phase --draft --force 9
+  $ hg log -G
+  o    changeset:   10:2f2496ddf49d
+  |\   branch:      f1
+  | |  tag:         tip
+  | |  parent:      7:4c9fbe56a16f
+  | |  parent:      9:e31216eec445
+  | |  user:        szhang
+  | |  date:        Thu Sep 05 12:59:39 2013 -0400
+  | |  summary:     merge
+  | |
+  | o  changeset:   9:e31216eec445
+  | |  branch:      f1
+  | |  user:        szhang
+  | |  date:        Thu Sep 05 12:59:10 2013 -0400
+  | |  summary:     more changes to f1
+  | |
+  | o    changeset:   8:8e4e2c1a07ae
+  | |\   branch:      f1
+  | | |  parent:      2:4bc80088dc6b
+  | | |  parent:      6:400110238667
+  | | |  user:        szhang
+  | | |  date:        Thu Sep 05 12:57:59 2013 -0400
+  | | |  summary:     bad merge
+  | | |
+  o | |  changeset:   7:4c9fbe56a16f
+  |/ /   branch:      f1
+  | |    parent:      2:4bc80088dc6b
+  | |    user:        szhang
+  | |    date:        Thu Sep 05 12:54:00 2013 -0400
+  | |    summary:     changed f1
+  | |
+  | o  changeset:   6:400110238667
+  | |  branch:      f2
+  | |  parent:      4:12e8ec6bb010
+  | |  user:        szhang
+  | |  date:        Tue Sep 03 13:58:02 2013 -0400
+  | |  summary:     changed f2 on f2
+  | |
+  | | @  changeset:   5:d79e2059b5c0
+  | | |  parent:      3:8a951942e016
+  | | |  user:        szhang
+  | | |  date:        Tue Sep 03 13:57:39 2013 -0400
+  | | |  summary:     changed f2 on default
+  | | |
+  | o |  changeset:   4:12e8ec6bb010
+  | |/   branch:      f2
+  | |    user:        szhang
+  | |    date:        Tue Sep 03 13:57:18 2013 -0400
+  | |    summary:     created f2 branch
+  | |
+  | o  changeset:   3:8a951942e016
+  | |  parent:      0:24797d4f68de
+  | |  user:        szhang
+  | |  date:        Tue Sep 03 13:57:11 2013 -0400
+  | |  summary:     added f2.txt
+  | |
+  o |  changeset:   2:4bc80088dc6b
+  | |  branch:      f1
+  | |  user:        szhang
+  | |  date:        Tue Sep 03 13:56:20 2013 -0400
+  | |  summary:     added f1.txt
+  | |
+  o |  changeset:   1:ef53c9e6b608
+  |/   branch:      f1
+  |    user:        szhang
+  |    date:        Tue Sep 03 13:55:26 2013 -0400
+  |    summary:     created f1 branch
+  |
+  o  changeset:   0:24797d4f68de
+     user:        szhang
+     date:        Tue Sep 03 13:55:08 2013 -0400
+     summary:     added default.txt
+  
+  $ hg rebase -s9 -d2 --debug # use debug to really check merge base used
+  rebase onto 2 starting from [<changectx e31216eec445>]
+  rebasing: 9:e31216eec445 5/6 changesets (83.33%)
+   future parents are 2 and -1
+  rebase status stored
+   update to 2:4bc80088dc6b
+  resolving manifests
+   branchmerge: False, force: True, partial: False
+   ancestor: d79e2059b5c0+, local: d79e2059b5c0+, remote: 4bc80088dc6b
+   f2.txt: other deleted -> r
+   f1.txt: remote created -> g
+  removing f2.txt
+  updating: f2.txt 1/2 files (50.00%)
+  getting f1.txt
+  updating: f1.txt 2/2 files (100.00%)
+   merge against 9:e31216eec445
+     detach base 8:8e4e2c1a07ae
+    searching for copies back to rev 3
+  resolving manifests
+   branchmerge: True, force: True, partial: False
+   ancestor: 8e4e2c1a07ae, local: 4bc80088dc6b+, remote: e31216eec445
+   f1.txt: remote is newer -> g
+  getting f1.txt
+  updating: f1.txt 1/1 files (100.00%)
+  f1.txt
+  rebasing: 10:2f2496ddf49d 6/6 changesets (100.00%)
+   future parents are 11 and 7
+  rebase status stored
+   already in target
+   merge against 10:2f2496ddf49d
+     detach base 9:e31216eec445
+    searching for copies back to rev 3
+  resolving manifests
+   branchmerge: True, force: True, partial: False
+   ancestor: e31216eec445, local: 19c888675e13+, remote: 2f2496ddf49d
+   f1.txt: remote is newer -> g
+  getting f1.txt
+  updating: f1.txt 1/1 files (100.00%)
+  f1.txt
+  rebase merging completed
+  update back to initial working directory parent
+  resolving manifests
+   branchmerge: False, force: False, partial: False
+   ancestor: 2a7f09cac94c, local: 2a7f09cac94c+, remote: d79e2059b5c0
+   f1.txt: other deleted -> r
+   f2.txt: remote created -> g
+  removing f1.txt
+  updating: f1.txt 1/2 files (50.00%)
+  getting f2.txt
+  updating: f2.txt 2/2 files (100.00%)
+  3 changesets found
+  list of changesets:
+  4c9fbe56a16f30c0d5dcc40ec1a97bbe3325209c
+  e31216eec445e44352c5f01588856059466a24c9
+  2f2496ddf49d69b5ef23ad8cf9fb2e0e4faf0ac2
+  bundling: 1/3 changesets (33.33%)
+  bundling: 2/3 changesets (66.67%)
+  bundling: 3/3 changesets (100.00%)
+  bundling: 1/3 manifests (33.33%)
+  bundling: 2/3 manifests (66.67%)
+  bundling: 3/3 manifests (100.00%)
+  bundling: f1.txt 1/1 files (100.00%)
+  saved backup bundle to $TESTTMP/issue4041/.hg/strip-backup/e31216eec445-backup.hg (glob)
+  3 changesets found
+  list of changesets:
+  4c9fbe56a16f30c0d5dcc40ec1a97bbe3325209c
+  19c888675e133ab5dff84516926a65672eaf04d9
+  2a7f09cac94c7f4b73ebd5cd1a62d3b2e8e336bf
+  bundling: 1/3 changesets (33.33%)
+  bundling: 2/3 changesets (66.67%)
+  bundling: 3/3 changesets (100.00%)
+  bundling: 1/3 manifests (33.33%)
+  bundling: 2/3 manifests (66.67%)
+  bundling: 3/3 manifests (100.00%)
+  bundling: f1.txt 1/1 files (100.00%)
+  adding branch
+  adding changesets
+  changesets: 1 chunks
+  add changeset 4c9fbe56a16f
+  changesets: 2 chunks
+  add changeset 19c888675e13
+  changesets: 3 chunks
+  add changeset 2a7f09cac94c
+  adding manifests
+  manifests: 1/2 chunks (50.00%)
+  manifests: 2/2 chunks (100.00%)
+  manifests: 3/2 chunks (150.00%)
+  adding file changes
+  adding f1.txt revisions
+  files: 1/1 chunks (100.00%)
+  added 2 changesets with 2 changes to 1 files
+  removing unknown node e31216eec445 from 1-phase boundary
+  invalid branchheads cache (served): tip differs
+  rebase completed
+  updating the branch cache