Patchwork [v2] graft: support grafting changes to new file in renamed directory (issue5436)

login
register
mail settings
Submitter Gábor Stefanik
Date Dec. 6, 2016, 5:09 p.m.
Message ID <6472c33e16326b8c817a.1481044180@GSTEFANIK.NavnGo.local>
Download mbox | patch
Permalink /patch/17839/
State Accepted
Headers show

Comments

Gábor Stefanik - Dec. 6, 2016, 5:09 p.m.
# HG changeset patch
# User Gábor Stefanik <gabor.stefanik@nng.com>
# Date 1480956001 -3600
#      Mon Dec 05 17:40:01 2016 +0100
# Node ID 6472c33e16326b8c817a8bae0e75053b19badb2c
# Parent  cbeb54ec0481a4bf9723ba4b80a5861a813c8531
graft: support grafting changes to new file in renamed directory (issue5436)
Yuya Nishihara - Dec. 13, 2016, 1:52 p.m.
On Tue, 06 Dec 2016 18:09:40 +0100, Gábor Stefanik wrote:
> # HG changeset patch
> # User Gábor Stefanik <gabor.stefanik@nng.com>
> # Date 1480956001 -3600
> #      Mon Dec 05 17:40:01 2016 +0100
> # Node ID 6472c33e16326b8c817a8bae0e75053b19badb2c
> # Parent  cbeb54ec0481a4bf9723ba4b80a5861a813c8531
> graft: support grafting changes to new file in renamed directory (issue5436)

No problem spotted by comparing to the other "move" handling, so queued,
thanks.

> --- a/tests/test-graft.t	Wed Nov 30 19:23:04 2016 +0000
> +++ b/tests/test-graft.t	Mon Dec 05 17:40:01 2016 +0100
> @@ -1286,3 +1286,22 @@
>    $ hg ci -qAmc
>    $ hg up -q .~2
>    $ hg graft tip -qt:fail

Inserted "cd .." here.

> +Graft a change into a new file previously grafted into a renamed directory
> +
> +  $ hg init dirmovenewfile
> +  $ cd dirmovenewfile
> +  $ mkdir a
> +  $ echo a > a/a
> +  $ hg ci -qAma
> +  $ echo x > a/x
> +  $ hg ci -qAmx
> +  $ hg up -q 0
> +  $ hg mv -q a b
> +  $ hg ci -qAmb
> +  $ hg graft -q 1 # a/x grafted as b/x, but no copy information recorded
> +  $ hg up -q 1
> +  $ echo y > a/x
> +  $ hg ci -qAmy
> +  $ hg up -q 3
> +  $ hg graft -q 4

and added "hg status --change ." to make sure b/x is modified by the grafted
changeset.

Patch

diff -r cbeb54ec0481 -r 6472c33e1632 mercurial/copies.py
--- a/mercurial/copies.py	Wed Nov 30 19:23:04 2016 +0000
+++ b/mercurial/copies.py	Mon Dec 05 17:40:01 2016 +0100
@@ -310,8 +310,8 @@ 
     Find moves and copies between context c1 and c2 that are relevant
     for merging. 'base' will be used as the merge base.
 
-    Returns four dicts: "copy", "movewithdir", "diverge", and
-    "renamedelete".
+    Returns five dicts: "copy", "movewithdir", "diverge", "renamedelete" and
+    "dirmove".
 
     "copy" is a mapping from destination name -> source name,
     where source is in c1 and destination is in c2 or vice-versa.
@@ -326,20 +326,24 @@ 
 
     "renamedelete" is a mapping of source name -> list of destination
     names for files deleted in c1 that were renamed in c2 or vice-versa.
+
+    "dirmove" is a mapping of detected source dir -> destination dir renames.
+    This is needed for handling changes to new files previously grafted into
+    renamed directories.
     """
     # avoid silly behavior for update from empty dir
     if not c1 or not c2 or c1 == c2:
-        return {}, {}, {}, {}
+        return {}, {}, {}, {}, {}
 
     # avoid silly behavior for parent -> working dir
     if c2.node() is None and c1.node() == repo.dirstate.p1():
-        return repo.dirstate.copies(), {}, {}, {}
+        return repo.dirstate.copies(), {}, {}, {}, {}
 
     # Copy trace disabling is explicitly below the node == p1 logic above
     # because the logic above is required for a simple copy to be kept across a
     # rebase.
     if repo.ui.configbool('experimental', 'disablecopytrace'):
-        return {}, {}, {}, {}
+        return {}, {}, {}, {}, {}
 
     # In certain scenarios (e.g. graft, update or rebase), base can be
     # overridden We still need to know a real common ancestor in this case We
@@ -365,7 +369,7 @@ 
     limit = _findlimit(repo, c1.rev(), c2.rev())
     if limit is None:
         # no common ancestor, no copies
-        return {}, {}, {}, {}
+        return {}, {}, {}, {}, {}
     repo.ui.debug("  searching for copies back to rev %d\n" % limit)
 
     m1 = c1.manifest()
@@ -503,7 +507,7 @@ 
     del divergeset
 
     if not fullcopy:
-        return copy, {}, diverge, renamedelete
+        return copy, {}, diverge, renamedelete, {}
 
     repo.ui.debug("  checking for directory renames\n")
 
@@ -541,7 +545,7 @@ 
     del d1, d2, invalid
 
     if not dirmove:
-        return copy, {}, diverge, renamedelete
+        return copy, {}, diverge, renamedelete, {}
 
     for d in dirmove:
         repo.ui.debug("   discovered dir src: '%s' -> dst: '%s'\n" %
@@ -561,7 +565,7 @@ 
                                        "dst: '%s'\n") % (f, df))
                     break
 
-    return copy, movewithdir, diverge, renamedelete
+    return copy, movewithdir, diverge, renamedelete, dirmove
 
 def _related(f1, f2, limit):
     """return True if f1 and f2 filectx have a common ancestor
diff -r cbeb54ec0481 -r 6472c33e1632 mercurial/merge.py
--- a/mercurial/merge.py	Wed Nov 30 19:23:04 2016 +0000
+++ b/mercurial/merge.py	Mon Dec 05 17:40:01 2016 +0100
@@ -794,7 +794,7 @@ 
     if matcher is not None and matcher.always():
         matcher = None
 
-    copy, movewithdir, diverge, renamedelete = {}, {}, {}, {}
+    copy, movewithdir, diverge, renamedelete, dirmove = {}, {}, {}, {}, {}
 
     # manifests fetched in order are going to be faster, so prime the caches
     [x.manifest() for x in
@@ -802,7 +802,7 @@ 
 
     if followcopies:
         ret = copies.mergecopies(repo, wctx, p2, pa)
-        copy, movewithdir, diverge, renamedelete = ret
+        copy, movewithdir, diverge, renamedelete, dirmove = ret
 
     repo.ui.note(_("resolving manifests\n"))
     repo.ui.debug(" branchmerge: %s, force: %s, partial: %s\n"
@@ -921,7 +921,16 @@ 
                     actions[f] = ('cm', (fl2, pa.node()),
                                   "remote created, get or merge")
             elif n2 != ma[f]:
-                if acceptremote:
+                df = None
+                for d in dirmove:
+                    if f.startswith(d):
+                        # new file added in a directory that was moved
+                        df = dirmove[d] + f[len(d):]
+                        break
+                if df in m1:
+                    actions[df] = ('m', (df, f, f, False, pa.node()),
+                            "local directory rename - respect move from " + f)
+                elif acceptremote:
                     actions[f] = ('c', (fl2,), "remote recreating")
                 else:
                     actions[f] = ('dc', (None, f, f, False, pa.node()),
diff -r cbeb54ec0481 -r 6472c33e1632 tests/test-graft.t
--- a/tests/test-graft.t	Wed Nov 30 19:23:04 2016 +0000
+++ b/tests/test-graft.t	Mon Dec 05 17:40:01 2016 +0100
@@ -1286,3 +1286,22 @@ 
   $ hg ci -qAmc
   $ hg up -q .~2
   $ hg graft tip -qt:fail
+
+Graft a change into a new file previously grafted into a renamed directory
+
+  $ hg init dirmovenewfile
+  $ cd dirmovenewfile
+  $ mkdir a
+  $ echo a > a/a
+  $ hg ci -qAma
+  $ echo x > a/x
+  $ hg ci -qAmx
+  $ hg up -q 0
+  $ hg mv -q a b
+  $ hg ci -qAmb
+  $ hg graft -q 1 # a/x grafted as b/x, but no copy information recorded
+  $ hg up -q 1
+  $ echo y > a/x
+  $ hg ci -qAmy
+  $ hg up -q 3
+  $ hg graft -q 4