D12418: copies: add config to preserve old copies (issue5457)

martinvonz (Martin von Zweigbergk) phabricator at mercurial-scm.org
Wed Mar 30 04:19:22 UTC 2022


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

REVISION SUMMARY
  The scenario in issue 5457 gets reported every now and then by our
  users (Google developers). This patch adds a fix for it by preserving
  existing copies even if the source file no longer exists. That's a bit
  of hack, but it's effective and much simpler than the other
  alternatives we've considered (such as storing the copy information in
  obsmarkers, which would mean that copy tracing would have to follow
  both graphs).
  
  The fix only works when copies are stored in changeset extras or
  sidedata because the filelog record needs to have the old file nodeid,
  which doesn't exist in the parent manifest.

REPOSITORY
  rHG Mercurial

BRANCH
  default

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

AFFECTED FILES
  mercurial/commit.py
  mercurial/configitems.py
  mercurial/copies.py
  mercurial/metadata.py
  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
@@ -754,6 +754,7 @@
   > [experimental]
   > evolution.createmarkers = True
   > evolution.allowunstable = True
+  > copies.keep-old = True
   > EOF
   $ newrepo
   $ echo a > a
@@ -769,11 +770,17 @@
   $ hg mv b c
   $ hg ci --amend -m "added c"
   1 new orphan changesets
+#if no-filelog no-compatibility
   $ hg rebase -s 'desc("modified b")' -d .
   rebasing 2:e3e0011b43ad "modified b" (changeset !)
   rebasing 2:2612b8963c3f "modified b" (no-changeset !)
+  merging c and b to c
+#else
+  $ hg rebase -s 'desc("modified b")' -d .
+  rebasing 2:2612b8963c3f "modified b"
   file 'b' was deleted in local [dest] but was modified in other [source].
   You can use (c)hanged version, leave (d)eleted, or leave (u)nresolved.
   What do you want to do? u
   unresolved conflicts (see 'hg resolve', then 'hg rebase --continue')
   [240]
+#endif
diff --git a/mercurial/metadata.py b/mercurial/metadata.py
--- a/mercurial/metadata.py
+++ b/mercurial/metadata.py
@@ -639,6 +639,9 @@
             p1copies[dst] = src
         elif src in p2 and p2[src].filenode() == srcnode:
             p2copies[dst] = src
+        else:
+            # This case should only happen with experimental.copies.keep-old
+            p1copies[dst] = src
     return p1copies, p2copies
 
 
diff --git a/mercurial/copies.py b/mercurial/copies.py
--- a/mercurial/copies.py
+++ b/mercurial/copies.py
@@ -53,10 +53,11 @@
     # between 5 and 6, so it includes all cases in its result.
     # Cases 1, 3, and 5 are then removed by _filter().
 
+    keep_old = src.repo().ui.configbool(b'experimental', b'copies.keep-old')
     for k, v in list(t.items()):
         if k == v:  # case 3
             del t[k]
-        elif v not in src:  # case 5
+        elif not keep_old and v not in src:  # case 5
             # remove copies from files that didn't exist
             del t[k]
         elif k not in dst:  # case 1
diff --git a/mercurial/configitems.py b/mercurial/configitems.py
--- a/mercurial/configitems.py
+++ b/mercurial/configitems.py
@@ -943,6 +943,11 @@
 )
 coreconfigitem(
     b'experimental',
+    b'copies.keep-old',
+    default=False,
+)
+coreconfigitem(
+    b'experimental',
     b'crecordtest',
     default=None,
 )
diff --git a/mercurial/commit.py b/mercurial/commit.py
--- a/mercurial/commit.py
+++ b/mercurial/commit.py
@@ -390,7 +390,7 @@
                 meta[b"copy"] = cfname
                 meta[b"copyrev"] = hex(cnode)
             fparent1, fparent2 = repo.nullid, newfparent
-        else:
+        elif not repo.ui.configbool(b'experimental', b'copies.keep-old'):
             repo.ui.warn(
                 _(
                     b"warning: can't find ancestor for '%s' "



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


More information about the Mercurial-devel mailing list