# HG changeset patch # User Gábor Stefanik # Date 1480956001 -3600 # Node ID 43a9e02a7b7fa273e110bbf2ee4629441ca61cf5 # Parent 51e7c83e05ee742a6e5c7266c6b95ffaa078e903 graft: support grafting changes to new file in renamed directory (issue5436) diff -r 51e7c83e05ee -r 43a9e02a7b7f mercurial/copies.py --- a/mercurial/copies.py Mon Nov 28 05:45:22 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 51e7c83e05ee -r 43a9e02a7b7f mercurial/merge.py --- a/mercurial/merge.py Mon Nov 28 05:45:22 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 51e7c83e05ee -r 43a9e02a7b7f tests/test-graft.t --- a/tests/test-graft.t Mon Nov 28 05:45:22 2016 +0000 +++ b/tests/test-graft.t Mon Dec 05 17:40:01 2016 +0100 @@ -1286,3 +1286,28 @@ $ hg ci -qAmc $ hg up -q .~2 $ hg graft tip -qt:fail + + $ cd .. + +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 + $ hg status --change . + M b/x + + $ cd ..