filemerge: when using in-memory merge, always put backup files in temp dir
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.
Differential Revision: https://phab.mercurial-scm.org/D12187
--- a/mercurial/filemerge.py Tue Feb 15 20:18:57 2022 -0800
+++ b/mercurial/filemerge.py Fri Feb 11 21:39:55 2022 -0800
@@ -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.data(), 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(fcd.data())
else:
- # 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, fcd.data())
- 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)
@contextlib.contextmanager
@@ -1065,7 +1052,7 @@
ui.warn(onfailure % fduipath)
return 1, False
- backup = _makebackup(repo, ui, wctx, fcd)
+ backup = _makebackup(repo, ui, fcd)
r = 1
try:
internalmarkerstyle = ui.config(b'ui', b'mergemarkers')