Patchwork D12187: filemerge: when using in-memory merge, always put backup files in temp dir

mail settings
Submitter phabricator
Date Feb. 16, 2022, 4:09 a.m.
Message ID <>
Download mbox | patch
Permalink /patch/50524/
State New
Headers show


phabricator - Feb. 16, 2022, 4:09 a.m.
martinvonz created this revision.
Herald added a reviewer: hg-reviewers.
Herald added a subscriber: mercurial-patches.

  Before calling a merge tool, we create a backup of the local side of
  the merge. That file can be put in the working copy or in a temporary
  directory, depending on the user's config. When we're merging in
  memory, we don't want to write to the actual, on-disk working copy, so
  we write the file to the in-memory working copy instead. However,
  since we don't support external merge tools with in-memory merge, it
  makes no difference where the file is actually stored (and if we ever
  do add support for external merge tools, then the file clearly can't
  live in the in-memory working-copy object anyway). So, since it
  doesn't matter where the file is stored, we can simplify by always
  putting them in the system's temp directory.

  rHG Mercurial





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


diff --git a/mercurial/ b/mercurial/
--- a/mercurial/
+++ b/mercurial/
@@ -877,7 +877,7 @@ 
-def _makebackup(repo, ui, wctx, fcd):
+def _makebackup(repo, ui, fcd):
     """Makes and returns a filectx-like object for ``fcd``'s backup file.
     In addition to preserving the user's pre-existing modifications to `fcd`
@@ -894,30 +894,17 @@ 
     # merge -> filemerge). (I suspect the fileset import is the weakest link)
     from . import context
-    backup = scmutil.backuppath(ui, repo, fcd.path())
-    inworkingdir = backup.startswith(repo.wvfs.base) and not backup.startswith(
-        repo.vfs.base
-    )
-    if isinstance(fcd, context.overlayworkingfilectx) and inworkingdir:
-        # If the backup file is to be in the working directory, and we're
-        # merging in-memory, we must redirect the backup to the memory context
-        # so we don't disturb the working directory.
-        relpath = backup[len(repo.wvfs.base) + 1 :]
-        wctx[relpath].write(, fcd.flags())
-        return wctx[relpath]
+    if isinstance(fcd, context.overlayworkingfilectx):
+        # If we're merging in-memory, we're free to put the backup anywhere.
+        fd, backup = pycompat.mkstemp(b'hg-merge-backup')
+        with os.fdopen(fd, 'wb') as f:
+            f.write(
-        # Otherwise, write to wherever path the user specified the backups
-        # should go. We still need to switch based on whether the source is
-        # in-memory so we can use the fast path of ``util.copy`` if both are
-        # on disk.
-        if isinstance(fcd, context.overlayworkingfilectx):
-            util.writefile(backup,
-        else:
-            a = _workingpath(repo, fcd)
-            util.copyfile(a, backup)
-        # A arbitraryfilectx is returned, so we can run the same functions on
-        # the backup context regardless of where it lives.
-        return context.arbitraryfilectx(backup, repo=repo)
+        backup = scmutil.backuppath(ui, repo, fcd.path())
+        a = _workingpath(repo, fcd)
+        util.copyfile(a, backup)
+    return context.arbitraryfilectx(backup, repo=repo)
@@ -1065,7 +1052,7 @@ 
             ui.warn(onfailure % fduipath)
         return 1, False
-    backup = _makebackup(repo, ui, wctx, fcd)
+    backup = _makebackup(repo, ui, fcd)
     r = 1
         internalmarkerstyle = ui.config(b'ui', b'mergemarkers')