D6603: copies: filter invalid copies only at end of pathcopies() (issue6163)

martinvonz (Martin von Zweigbergk) phabricator at mercurial-scm.org
Thu Jul 4 11:00:30 EDT 2019


martinvonz created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  copies._filter() filters out copies whose source file does not exist
  in the start commit or whose target file does not exist in the end
  commit. We do that after chaining copies with dirstate copies or
  backward renames from another branch. We also do at the end of the
  changeset-centric copy tracing. The filtering means that we will
  remove copies to/from files that did not exist in some intermediate
  commit. That is inconsistent with what we do if a file has been
  deleted and then re-added (we allow updating across that).
  
  Copying the two first examples from issue6163:
  
    @  4 'rename x to y'
    |
    o  3 'add x again'
    |
    o  2 'remove x'
    |
    | o  1 'modify x'
    |/
    o  0 'add x'
    
    @  4 'rename x to y'
    |
    o  3 'add x again'
    |
    | o  2 'modify x'
    | |
    | o  1 'add x'
    |/
    o  0 'base'
  
  When doing `hg rebase -r 1 -d 4` in the first case, it succeeds, but
  `hg rebase -r 2 -d 4` in the second case does not. That's because we
  chain and filter via commit 0, which does not have file 'x' in the
  second case. IMO, that's clearly inconsistent. So this patch removes
  the filtering step so it only happens at the end. If a file was
  temporarily removed, whether via a merge base or not, it will now
  still be considered the same file. That fixes issue6163 for the
  changeset-centric case.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D6603

AFFECTED FILES
  mercurial/copies.py
  tests/test-copies-unrelated.t
  tests/test-copies.t

CHANGE DETAILS

diff --git a/tests/test-copies.t b/tests/test-copies.t
--- a/tests/test-copies.t
+++ b/tests/test-copies.t
@@ -354,8 +354,7 @@
   $ hg debugpathcopies 1 3
   x -> z
 
-Copy x to y on one side of merge, create y and rename to z on the other side. Pathcopies from the
-first side should not include the y->z rename since y didn't exist in the merge base.
+Copy x to y on one side of merge, create y and rename to z on the other side.
   $ newrepo
   $ echo x > x
   $ hg ci -Aqm 'add x'
@@ -385,6 +384,7 @@
   $ hg debugpathcopies 2 3
   y -> z
   $ hg debugpathcopies 1 3
+  y -> z (no-filelog !)
 
 Create x and y, then rename x to z on one side of merge, and rename y to z and
 modify z on the other side. When storing copies in the changeset, we don't
diff --git a/tests/test-copies-unrelated.t b/tests/test-copies-unrelated.t
--- a/tests/test-copies-unrelated.t
+++ b/tests/test-copies-unrelated.t
@@ -299,6 +299,8 @@
   o  0 base
      a
   $ hg debugpathcopies 1 4
+  x -> y (no-filelog !)
+#if filelog
 BROKEN: This should succeed and merge the changes from x into y
   $ hg graft -r 2
   grafting 2:* "modify x" (glob)
@@ -308,6 +310,11 @@
   abort: unresolved conflicts, can't continue
   (use 'hg resolve' and 'hg graft --continue')
   [255]
+#else
+  $ hg graft -r 2
+  grafting 2:* "modify x" (glob)
+  merging y and x to y
+#endif
   $ hg co -qC 2
   $ hg graft -r 4
   grafting 4:* "rename x to y"* (glob)
@@ -345,6 +352,8 @@
   o  0 base
      a
   $ hg debugpathcopies 1 5
+  x -> y (no-filelog !)
+#if filelog
 BROKEN: This should succeed and merge the changes from x into y
   $ hg graft -r 2
   grafting 2:* "modify x" (glob)
@@ -354,6 +363,11 @@
   abort: unresolved conflicts, can't continue
   (use 'hg resolve' and 'hg graft --continue')
   [255]
+#else
+  $ hg graft -r 2
+  grafting 2:* "modify x" (glob)
+  merging y and x to y
+#endif
   $ hg co -qC 2
 BROKEN: This should succeed and merge the changes from x into y
   $ hg graft -r 5
diff --git a/mercurial/copies.py b/mercurial/copies.py
--- a/mercurial/copies.py
+++ b/mercurial/copies.py
@@ -285,7 +285,6 @@
                     # that side, even if it was also copied on the p2 side.
                     copies[dst] = copies2[dst]
         if r == b.rev():
-            _filter(a, b, copies)
             return copies
         for i, c in enumerate(children[r]):
             childctx = repo[c]
@@ -321,7 +320,6 @@
         cm = _committedforwardcopies(a, b.p1(), match)
         # combine copies from dirstate if necessary
         copies = _chain(cm, _dirstatecopies(b._repo, match))
-        _filter(a, b, copies)
     else:
         copies  = _committedforwardcopies(a, b, match)
     return copies
@@ -373,7 +371,7 @@
             repo.ui.debug('debug.copies: search mode: combined\n')
         copies = _chain(_backwardrenames(x, a, match=match),
                         _forwardcopies(a, y, match=match))
-        _filter(x, y, copies)
+    _filter(x, y, copies)
     return copies
 
 def mergecopies(repo, c1, c2, base):



To: martinvonz, #hg-reviewers
Cc: mercurial-devel


More information about the Mercurial-devel mailing list