--- a/mercurial/merge.py Tue Jan 31 03:20:07 2017 +0100
+++ b/mercurial/merge.py Tue Jan 31 03:25:59 2017 +0100
@@ -997,6 +997,7 @@
# Pick the best bid for each file
repo.ui.note(_('\nauction for merging merge bids\n'))
actions = {}
+ dms = [] # filenames that have dm actions
for f, bids in sorted(fbids.items()):
# bids is a mapping from action method to list af actions
# Consensus?
@@ -1005,6 +1006,8 @@
if all(a == l[0] for a in l[1:]): # len(bids) is > 1
repo.ui.note(_(" %s: consensus for %s\n") % (f, m))
actions[f] = l[0]
+ if m == 'dm':
+ dms.append(f)
continue
# If keep is an option, just do it.
if 'k' in bids:
@@ -1029,7 +1032,19 @@
repo.ui.warn(_(' %s: ambiguous merge - picked %s action\n') %
(f, m))
actions[f] = l[0]
+ if m == 'dm':
+ dms.append(f)
continue
+ # Work around 'dm' that can cause multiple actions for the same file
+ for f in dms:
+ dm, (f0, flags), msg = actions[f]
+ assert dm == 'dm', dm
+ m, args, msg = actions[f0]
+ if m == 'r':
+ # We have one bid for removing a file and another for moving it.
+ # These two could be merged as first move and then delete ...
+ # but instead drop moving and just delete.
+ del actions[f]
repo.ui.note(_('end of auction\n\n'))
_resolvetrivial(repo, wctx, mctx, ancestors[0], actions)
--- a/tests/test-merge-criss-cross.t Tue Jan 31 03:20:07 2017 +0100
+++ b/tests/test-merge-criss-cross.t Tue Jan 31 03:25:59 2017 +0100
@@ -11,9 +11,15 @@
$ hg up -qr0
$ echo '2 first change' > f2
+ $ mkdir d1
+ $ echo '0 base' > d1/f3
+ $ echo '0 base' > d1/f4
+ $ hg add -q d1
$ hg ci -qm '2 first change f2'
$ hg merge -qr 1
+ $ hg rm d1/f3
+ $ hg mv -q d1 d2
$ hg ci -m '3 merge'
$ hg up -qr2
@@ -24,38 +30,38 @@
$ hg ci -m '5 second change f1'
$ hg up -r3
- 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ 2 files updated, 0 files merged, 2 files removed, 0 files unresolved
$ echo '6 second change' > f2
$ hg ci -m '6 second change f2'
$ hg log -G
- @ changeset: 6:3b08d01b0ab5
+ @ changeset: 6:6373bbfdae1d
| tag: tip
- | parent: 3:cf89f02107e5
+ | parent: 3:c202c8af058d
| user: test
| date: Thu Jan 01 00:00:00 1970 +0000
| summary: 6 second change f2
|
- | o changeset: 5:adfe50279922
+ | o changeset: 5:e673248094b1
| | user: test
| | date: Thu Jan 01 00:00:00 1970 +0000
| | summary: 5 second change f1
| |
- | o changeset: 4:7d3e55501ae6
- | |\ parent: 2:40663881a6dd
+ | o changeset: 4:177f58377c06
+ | |\ parent: 2:d1d156401c1b
| | | parent: 1:0f6b37dbe527
| | | user: test
| | | date: Thu Jan 01 00:00:00 1970 +0000
| | | summary: 4 merge
| | |
- o---+ changeset: 3:cf89f02107e5
- | | | parent: 2:40663881a6dd
+ o---+ changeset: 3:c202c8af058d
+ | | | parent: 2:d1d156401c1b
|/ / parent: 1:0f6b37dbe527
| | user: test
| | date: Thu Jan 01 00:00:00 1970 +0000
| | summary: 3 merge
| |
- | o changeset: 2:40663881a6dd
+ | o changeset: 2:d1d156401c1b
| | parent: 0:40494bf2444c
| | user: test
| | date: Thu Jan 01 00:00:00 1970 +0000
@@ -73,27 +79,51 @@
$ hg merge -v --debug --tool internal:dump 5 --config merge.preferancestor='!'
- note: using 0f6b37dbe527 as ancestor of 3b08d01b0ab5 and adfe50279922
- alternatively, use --config merge.preferancestor=40663881a6dd
+ note: using 0f6b37dbe527 as ancestor of 6373bbfdae1d and e673248094b1
+ alternatively, use --config merge.preferancestor=d1d156401c1b
searching for copies back to rev 3
+ unmatched files in local:
+ d2/f4
+ unmatched files in other:
+ d1/f3
+ d1/f4
+ all copies found (* = to merge, ! = divergent, % = renamed and deleted):
+ src: 'd1/f4' -> dst: 'd2/f4'
+ checking for directory renames
+ discovered dir src: 'd1/' -> dst: 'd2/'
+ pending file src: 'd1/f3' -> dst: 'd2/f3'
+ pending file src: 'd1/f4' -> dst: 'd2/f4'
resolving manifests
branchmerge: True, force: False, partial: False
- ancestor: 0f6b37dbe527, local: 3b08d01b0ab5+, remote: adfe50279922
+ ancestor: 0f6b37dbe527, local: 6373bbfdae1d+, remote: e673248094b1
+ preserving d2/f4 for resolve of d2/f4
preserving f2 for resolve of f2
f1: remote is newer -> g
getting f1
+ d2/f3: local directory rename - get from d1/f3 -> dg
+ getting d1/f3 to d2/f3
+ d2/f4: local directory rename, both created -> m (premerge)
f2: versions differ -> m (premerge)
picked tool ':dump' for f2 (binary False symlink False changedelete False)
merging f2
- my f2@3b08d01b0ab5+ other f2@adfe50279922 ancestor f2@0f6b37dbe527
+ my f2@6373bbfdae1d+ other f2@e673248094b1 ancestor f2@0f6b37dbe527
f2: versions differ -> m (merge)
picked tool ':dump' for f2 (binary False symlink False changedelete False)
- my f2@3b08d01b0ab5+ other f2@adfe50279922 ancestor f2@0f6b37dbe527
- 1 files updated, 0 files merged, 0 files removed, 1 files unresolved
+ my f2@6373bbfdae1d+ other f2@e673248094b1 ancestor f2@0f6b37dbe527
+ 3 files updated, 0 files merged, 0 files removed, 1 files unresolved
use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
[1]
- $ f --dump *
+ $ f --dump --recurse *
+ d2: directory with 2 files
+ d2/f3:
+ >>>
+ 0 base
+ <<<
+ d2/f4:
+ >>>
+ 0 base
+ <<<
f1:
>>>
5 second change
@@ -121,11 +151,13 @@
$ hg up -qC .
$ hg merge -v --tool internal:dump 5 --config merge.preferancestor="null 40663881 3b08d"
- note: using 40663881a6dd as ancestor of 3b08d01b0ab5 and adfe50279922
- alternatively, use --config merge.preferancestor=0f6b37dbe527
+ note: using 0f6b37dbe527 as ancestor of 6373bbfdae1d and e673248094b1
+ alternatively, use --config merge.preferancestor=d1d156401c1b
resolving manifests
- merging f1
- 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
+ getting f1
+ getting d1/f3 to d2/f3
+ merging f2
+ 3 files updated, 0 files merged, 0 files removed, 1 files unresolved
use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
[1]
@@ -134,36 +166,70 @@
$ rm f*
$ hg up -qC .
$ hg merge -v --debug --tool internal:dump 5 --config merge.preferancestor="*"
- note: merging 3b08d01b0ab5+ and adfe50279922 using bids from ancestors 0f6b37dbe527 and 40663881a6dd
+ note: merging 6373bbfdae1d+ and e673248094b1 using bids from ancestors 0f6b37dbe527 and d1d156401c1b
calculating bids for ancestor 0f6b37dbe527
searching for copies back to rev 3
+ unmatched files in local:
+ d2/f4
+ unmatched files in other:
+ d1/f3
+ d1/f4
+ all copies found (* = to merge, ! = divergent, % = renamed and deleted):
+ src: 'd1/f4' -> dst: 'd2/f4'
+ checking for directory renames
+ discovered dir src: 'd1/' -> dst: 'd2/'
+ pending file src: 'd1/f3' -> dst: 'd2/f3'
+ pending file src: 'd1/f4' -> dst: 'd2/f4'
resolving manifests
branchmerge: True, force: False, partial: False
- ancestor: 0f6b37dbe527, local: 3b08d01b0ab5+, remote: adfe50279922
+ ancestor: 0f6b37dbe527, local: 6373bbfdae1d+, remote: e673248094b1
+ d2/f3: local directory rename - get from d1/f3 -> dg
+ d2/f4: local directory rename, both created -> m
f1: remote is newer -> g
f2: versions differ -> m
- calculating bids for ancestor 40663881a6dd
+ calculating bids for ancestor d1d156401c1b
searching for copies back to rev 3
+ unmatched files in local:
+ d2/f4
+ all copies found (* = to merge, ! = divergent, % = renamed and deleted):
+ src: 'd1/f4' -> dst: 'd2/f4'
+ checking for directory renames
+ discovered dir src: 'd1/' -> dst: 'd2/'
resolving manifests
branchmerge: True, force: False, partial: False
- ancestor: 40663881a6dd, local: 3b08d01b0ab5+, remote: adfe50279922
+ ancestor: d1d156401c1b, local: 6373bbfdae1d+, remote: e673248094b1
f1: versions differ -> m
f2: remote unchanged -> k
auction for merging merge bids
+ d2/f3: consensus for dg
+ d2/f4: consensus for m
f1: picking 'get' action
f2: picking 'keep' action
end of auction
+ preserving d2/f4 for resolve of d2/f4
f1: remote is newer -> g
getting f1
f2: remote unchanged -> k
- 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ d2/f3: local directory rename - get from d1/f3 -> dg
+ getting d1/f3 to d2/f3
+ d2/f4: local directory rename, both created -> m (premerge)
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
(branch merge, don't forget to commit)
- $ f --dump *
+ $ f --dump --recurse *
+ d2: directory with 2 files
+ d2/f3:
+ >>>
+ 0 base
+ <<<
+ d2/f4:
+ >>>
+ 0 base
+ <<<
f1:
>>>
5 second change
@@ -177,38 +243,79 @@
The other way around:
$ hg up -C -r5
- 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ 4 files updated, 0 files merged, 1 files removed, 0 files unresolved
$ hg merge -v --debug --config merge.preferancestor="*"
- note: merging adfe50279922+ and 3b08d01b0ab5 using bids from ancestors 0f6b37dbe527 and 40663881a6dd
+ note: merging e673248094b1+ and 6373bbfdae1d using bids from ancestors 0f6b37dbe527 and d1d156401c1b
calculating bids for ancestor 0f6b37dbe527
searching for copies back to rev 3
+ unmatched files in local:
+ d1/f3
+ d1/f4
+ unmatched files in other:
+ d2/f4
+ all copies found (* = to merge, ! = divergent, % = renamed and deleted):
+ src: 'd1/f4' -> dst: 'd2/f4'
+ checking for directory renames
+ discovered dir src: 'd1/' -> dst: 'd2/'
+ pending file src: 'd1/f3' -> dst: 'd2/f3'
+ pending file src: 'd1/f4' -> dst: 'd2/f4'
resolving manifests
branchmerge: True, force: False, partial: False
- ancestor: 0f6b37dbe527, local: adfe50279922+, remote: 3b08d01b0ab5
+ ancestor: 0f6b37dbe527, local: e673248094b1+, remote: 6373bbfdae1d
+ d2/f3: remote directory rename - move from d1/f3 -> dm
+ d2/f4: remote directory rename, both created -> m
f1: remote unchanged -> k
f2: versions differ -> m
- calculating bids for ancestor 40663881a6dd
+ calculating bids for ancestor d1d156401c1b
searching for copies back to rev 3
+ unmatched files in other:
+ d2/f4
+ all copies found (* = to merge, ! = divergent, % = renamed and deleted):
+ src: 'd1/f4' -> dst: 'd2/f4'
+ checking for directory renames
+ discovered dir src: 'd1/' -> dst: 'd2/'
resolving manifests
branchmerge: True, force: False, partial: False
- ancestor: 40663881a6dd, local: adfe50279922+, remote: 3b08d01b0ab5
+ ancestor: d1d156401c1b, local: e673248094b1+, remote: 6373bbfdae1d
+ d1/f3: other deleted -> r
+ d1/f4: other deleted -> r
+ d2/f4: remote created -> g
f1: versions differ -> m
f2: remote is newer -> g
auction for merging merge bids
+ d1/f3: consensus for r
+ d1/f4: consensus for r
+ d2/f3: consensus for dm
+ d2/f4: picking 'get' action
f1: picking 'keep' action
f2: picking 'get' action
end of auction
+ d1/f3: other deleted -> r
+ removing d1/f3
+ d1/f4: other deleted -> r
+ removing d1/f4
+ d2/f4: remote created -> g
+ getting d2/f4
f2: remote is newer -> g
getting f2
f1: remote unchanged -> k
- 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ 2 files updated, 0 files merged, 2 files removed, 0 files unresolved
(branch merge, don't forget to commit)
- $ f --dump *
+ $ f --dump --recurse *
+ d2: directory with 2 files
+ d2/f3:
+ >>>
+ 0 base
+ <<<
+ d2/f4:
+ >>>
+ 0 base
+ <<<
f1:
>>>
5 second change
@@ -222,57 +329,85 @@
$ hg up -qC
$ hg merge
- 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ 2 files updated, 0 files merged, 2 files removed, 0 files unresolved
(branch merge, don't forget to commit)
$ hg up -qC tip
$ hg merge -v
- note: merging 3b08d01b0ab5+ and adfe50279922 using bids from ancestors 0f6b37dbe527 and 40663881a6dd
+ note: merging 6373bbfdae1d+ and e673248094b1 using bids from ancestors 0f6b37dbe527 and d1d156401c1b
calculating bids for ancestor 0f6b37dbe527
resolving manifests
- calculating bids for ancestor 40663881a6dd
+ calculating bids for ancestor d1d156401c1b
resolving manifests
auction for merging merge bids
+ d2/f3: consensus for dg
+ d2/f4: consensus for m
f1: picking 'get' action
f2: picking 'keep' action
end of auction
getting f1
- 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ getting d1/f3 to d2/f3
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
(branch merge, don't forget to commit)
$ hg up -qC
$ hg merge -v --debug --config merge.preferancestor="*"
- note: merging 3b08d01b0ab5+ and adfe50279922 using bids from ancestors 0f6b37dbe527 and 40663881a6dd
+ note: merging 6373bbfdae1d+ and e673248094b1 using bids from ancestors 0f6b37dbe527 and d1d156401c1b
calculating bids for ancestor 0f6b37dbe527
searching for copies back to rev 3
+ unmatched files in local:
+ d2/f4
+ unmatched files in other:
+ d1/f3
+ d1/f4
+ all copies found (* = to merge, ! = divergent, % = renamed and deleted):
+ src: 'd1/f4' -> dst: 'd2/f4'
+ checking for directory renames
+ discovered dir src: 'd1/' -> dst: 'd2/'
+ pending file src: 'd1/f3' -> dst: 'd2/f3'
+ pending file src: 'd1/f4' -> dst: 'd2/f4'
resolving manifests
branchmerge: True, force: False, partial: False
- ancestor: 0f6b37dbe527, local: 3b08d01b0ab5+, remote: adfe50279922
+ ancestor: 0f6b37dbe527, local: 6373bbfdae1d+, remote: e673248094b1
+ d2/f3: local directory rename - get from d1/f3 -> dg
+ d2/f4: local directory rename, both created -> m
f1: remote is newer -> g
f2: versions differ -> m
- calculating bids for ancestor 40663881a6dd
+ calculating bids for ancestor d1d156401c1b
searching for copies back to rev 3
+ unmatched files in local:
+ d2/f4
+ all copies found (* = to merge, ! = divergent, % = renamed and deleted):
+ src: 'd1/f4' -> dst: 'd2/f4'
+ checking for directory renames
+ discovered dir src: 'd1/' -> dst: 'd2/'
resolving manifests
branchmerge: True, force: False, partial: False
- ancestor: 40663881a6dd, local: 3b08d01b0ab5+, remote: adfe50279922
+ ancestor: d1d156401c1b, local: 6373bbfdae1d+, remote: e673248094b1
f1: versions differ -> m
f2: remote unchanged -> k
auction for merging merge bids
+ d2/f3: consensus for dg
+ d2/f4: consensus for m
f1: picking 'get' action
f2: picking 'keep' action
end of auction
+ preserving d2/f4 for resolve of d2/f4
f1: remote is newer -> g
getting f1
f2: remote unchanged -> k
- 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ d2/f3: local directory rename - get from d1/f3 -> dg
+ getting d1/f3 to d2/f3
+ d2/f4: local directory rename, both created -> m (premerge)
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
(branch merge, don't forget to commit)
$ cd ..