diff mercurial/cmdutil.py @ 42862:3cf091843b4f

split: handle partial commit of renames when doing split or record (issue5723) When using split or record, using either interface (text or curses), selecting portions of the file to be committed/recorded did not work; the entire file was treated as having been selected. This was because the logic for handling partial application of the patches relies on knowing what files are "new with modifications" and it doesn't treat "rename destination" as "new". There was a complicating issue, however. We're relying on the patch header specifying the copy from/to information, which works as long as the 'copy from' file is there. In the case of renames, however, the 'rename from' file is *not* there, so we need to add it back. Differential Revision: https://phab.mercurial-scm.org/D6768
author Kyle Lippincott <spectral@google.com>
date Tue, 27 Aug 2019 11:56:19 -0700
parents ce52377102db
children a65c4715fb5d
line wrap: on
line diff
--- a/mercurial/cmdutil.py	Tue Aug 27 11:56:15 2019 -0700
+++ b/mercurial/cmdutil.py	Tue Aug 27 11:56:19 2019 -0700
@@ -181,11 +181,14 @@
 
 def newandmodified(chunks, originalchunks):
     newlyaddedandmodifiedfiles = set()
+    alsorestore = set()
     for chunk in chunks:
         if (ishunk(chunk) and chunk.header.isnewfile() and chunk not in
             originalchunks):
             newlyaddedandmodifiedfiles.add(chunk.header.filename())
-    return newlyaddedandmodifiedfiles
+            alsorestore.update(set(chunk.header.files()) -
+                               set([chunk.header.filename()]))
+    return newlyaddedandmodifiedfiles, alsorestore
 
 def parsealiases(cmd):
     return cmd.split("|")
@@ -326,8 +329,11 @@
 
         # We need to keep a backup of files that have been newly added and
         # modified during the recording process because there is a previous
-        # version without the edit in the workdir
-        newlyaddedandmodifiedfiles = newandmodified(chunks, originalchunks)
+        # version without the edit in the workdir. We also will need to restore
+        # files that were the sources of renames so that the patch application
+        # works.
+        newlyaddedandmodifiedfiles, alsorestore = newandmodified(chunks,
+                                                                 originalchunks)
         contenders = set()
         for h in chunks:
             try:
@@ -392,7 +398,7 @@
             # 3a. apply filtered patch to clean repo  (clean)
             if backups:
                 # Equivalent to hg.revert
-                m = scmutil.matchfiles(repo, backups.keys())
+                m = scmutil.matchfiles(repo, set(backups.keys()) | alsorestore)
                 mergemod.update(repo, repo.dirstate.p1(), branchmerge=False,
                                 force=True, matcher=m)
 
@@ -3172,7 +3178,13 @@
         except error.PatchError as err:
             raise error.Abort(_('error parsing patch: %s') % err)
 
-        newlyaddedandmodifiedfiles = newandmodified(chunks, originalchunks)
+        # FIXME: when doing an interactive revert of a copy, there's no way of
+        # performing a partial revert of the added file, the only option is
+        # "remove added file <name> (Yn)?", so we don't need to worry about the
+        # alsorestore value. Ideally we'd be able to partially revert
+        # copied/renamed files.
+        newlyaddedandmodifiedfiles, unusedalsorestore = newandmodified(
+                chunks, originalchunks)
         if tobackup is None:
             tobackup = set()
         # Apply changes