Patchwork [4,of,4,V2] merge: don't overwrite conflicting file in locally renamed directory

login
register
mail settings
Submitter Martin von Zweigbergk
Date Dec. 4, 2014, 5:15 a.m.
Message ID <4a0f9d547b6212eacabd.1417670152@martinvonz.mtv.corp.google.com>
Download mbox | patch
Permalink /patch/6994/
State Accepted
Commit 39a12719ec65192cad2fe5dd808eade13dbcf350
Headers show

Comments

Martin von Zweigbergk - Dec. 4, 2014, 5:15 a.m.
# HG changeset patch
# User Martin von Zweigbergk <martinvonz@google.com>
# Date 1417633372 28800
#      Wed Dec 03 11:02:52 2014 -0800
# Node ID 4a0f9d547b6212eacabd6f2c6075e4c3afd90a7f
# Parent  a8f9e63789da94b50152dae28e2de0343c8c247a
merge: don't overwrite conflicting file in locally renamed directory

When the local side has renamed a directory from a/ to b/ and added a
file b/c in it, and the remote side has added a file a/c, we end up
overwriting the local file a/b/ with the contents of remote file
a/c. Add a check for this case and use the merge ('m') action in this
case instead of the directory rename get ('dg') action.
Matt Mackall - Dec. 5, 2014, 12:48 a.m.
On Wed, 2014-12-03 at 21:15 -0800, Martin von Zweigbergk wrote:
> # HG changeset patch
> # User Martin von Zweigbergk <martinvonz@google.com>
> # Date 1417633372 28800
> #      Wed Dec 03 11:02:52 2014 -0800
> # Node ID 4a0f9d547b6212eacabd6f2c6075e4c3afd90a7f
> # Parent  a8f9e63789da94b50152dae28e2de0343c8c247a
> merge: don't overwrite conflicting file in locally renamed directory
> 
> When the local side has renamed a directory from a/ to b/ and added a
> file b/c in it, and the remote side has added a file a/c, we end up
> overwriting the local file a/b/ with the contents of remote file

Looks like a/b/ is a typo. Fixed.

I've queued these for default as there's a bit too much refactoring
happening here for stable. But otherwise very nice, thanks.

Patch

diff --git a/mercurial/merge.py b/mercurial/merge.py
--- a/mercurial/merge.py
+++ b/mercurial/merge.py
@@ -475,8 +475,12 @@ 
                 pass # we'll deal with it on m1 side
             elif f in movewithdir:
                 f2 = movewithdir[f]
-                actions['dg'].append((f2, (f, fl2),
-                                "local directory rename - get from " + f))
+                if f2 in m1:
+                    actions['m'].append((f2, (f2, f, None, False, pa.node()),
+                                   "local directory rename, both created"))
+                else:
+                    actions['dg'].append((f2, (f, fl2),
+                                    "local directory rename - get from " + f))
             elif f in copy:
                 f2 = copy[f]
                 if f2 in m2:
diff --git a/tests/test-rename-dir-merge.t b/tests/test-rename-dir-merge.t
--- a/tests/test-rename-dir-merge.t
+++ b/tests/test-rename-dir-merge.t
@@ -127,29 +127,36 @@ 
 Local directory rename with conflicting file added in remote source directory
 and committed in local target directory.
 
-BROKEN: the local file is overwritten; it should be merged
-
   $ hg co -qC 1
   $ echo target > b/c
   $ hg add b/c
   $ hg commit -qm 'new file in target directory'
   $ hg merge 2
-  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
-  (branch merge, don't forget to commit)
+  merging b/c and a/c to b/c
+  warning: conflicts during merge.
+  merging b/c incomplete! (edit conflicts, then use 'hg resolve --mark')
+  0 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]
   $ hg st -A
-  A b/c
+  M b/c
     a/c
   ? a/d
+  ? b/c.orig
   C b/a
   C b/b
   $ cat b/c
+  <<<<<<< local: f1c50ca4f127 - test: new file in target directory
+  target
+  =======
   baz
+  >>>>>>> other: ce36d17b18fb  - test: 2 add a/c
+  $ rm b/c.orig
 
 Remote directory rename with conflicting file added in remote target directory
 and committed in local source directory.
 
   $ hg co -qC 2
-  $ rm b/c
   $ hg st -A
   ? a/d
   C a/a