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

login
register
mail settings
Submitter phabricator
Date March 30, 2022, 4:19 a.m.
Message ID <differential-rev-PHID-DREV-fyaknyvdc6lan3ls6o3h-req@mercurial-scm.org>
Download mbox | patch
Permalink /patch/50764/
State New
Headers show

Comments

phabricator - March 30, 2022, 4:19 a.m.
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




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

Patch

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' "