Mercurial > hg
changeset 19969:ad9db007656f stable
rebase: fix selection of base used when rebasing merge (issue4041)
Prior this changeset, rebasing a merge whose 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.
author | Pierre-Yves David <pierre-yves.david@ens-lyon.org> |
---|---|
date | Wed, 30 Oct 2013 19:45:14 +0100 |
parents | 7bec3f697d76 |
children | 065e6f1c9259 |
files | hgext/rebase.py tests/bundles/issue4041.hg tests/test-rebase-conflicts.t |
diffstat | 3 files changed, 218 insertions(+), 2 deletions(-) [+] |
line wrap: on
line diff
--- a/hgext/rebase.py Tue Oct 29 21:54:49 2013 +0200 +++ b/hgext/rebase.py Wed Oct 30 19:45:14 2013 +0100 @@ -447,9 +447,44 @@ 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)
--- a/tests/test-rebase-conflicts.t Tue Oct 29 21:54:49 2013 +0200 +++ b/tests/test-rebase-conflicts.t Wed Oct 30 19:45:14 2013 +0100 @@ -124,3 +124,184 @@ * 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