mirror of
https://github.com/facebook/sapling.git
synced 2024-10-08 07:49:11 +03:00
extdiff: copy back files to the working directory if the size changed
In theory, it should be enough to pay attention only to the modification time when detecting if a snapshotted working directory file changed. In practice, BeyondCompare preserves all file attributes when syncing files at the directory level. (If you open the file and sync individual hunks, then mtime does change, and everything was being copied back as desired.) I'm not sure how many other synchronization tools would trigger this issue, but it's annoyingly inconsistent (if a single file is diffed, it isn't snapshotted, so the same BeyondCompare file sync operation _is_ visible, because wdir() is updated in place. I filed a bug with them, and they stated it is on their wish list, but won't be fixed in the near term. This isn't a complete fix (there is still the case of the size not changing), but this seems like a trivial enough change to fix most of the problem. I suppose we could fool around with making files in the other snapshot readonly, and copy back if we see the readonly bit copied. That seems pretty hacky though, and only works if the external tool copies all attributes.
This commit is contained in:
parent
76f6c3e6b8
commit
36f740cc43
@ -101,7 +101,7 @@ def snapshot(ui, repo, files, node, tmproot, listsubrepos):
|
||||
dirname = '%s.%s' % (dirname, short(node))
|
||||
base = os.path.join(tmproot, dirname)
|
||||
os.mkdir(base)
|
||||
fns_and_mtime = []
|
||||
fnsandstat = []
|
||||
|
||||
if node is not None:
|
||||
ui.note(_('making snapshot of %d files from rev %s\n') %
|
||||
@ -124,9 +124,8 @@ def snapshot(ui, repo, files, node, tmproot, listsubrepos):
|
||||
if node is None:
|
||||
dest = os.path.join(base, wfn)
|
||||
|
||||
fns_and_mtime.append((dest, repo.wjoin(fn),
|
||||
os.lstat(dest).st_mtime))
|
||||
return dirname, fns_and_mtime
|
||||
fnsandstat.append((dest, repo.wjoin(fn), os.lstat(dest)))
|
||||
return dirname, fnsandstat
|
||||
|
||||
def dodiff(ui, repo, cmdline, pats, opts):
|
||||
'''Do the actual diff:
|
||||
@ -199,7 +198,7 @@ def dodiff(ui, repo, cmdline, pats, opts):
|
||||
dir1b = None
|
||||
rev1b = ''
|
||||
|
||||
fns_and_mtime = []
|
||||
fnsandstat = []
|
||||
|
||||
# If node2 in not the wc or there is >1 change, copy it
|
||||
dir2root = ''
|
||||
@ -212,8 +211,8 @@ def dodiff(ui, repo, cmdline, pats, opts):
|
||||
#the working dir in this case (because the other cases
|
||||
#are: diffing 2 revisions or single file -- in which case
|
||||
#the file is already directly passed to the diff tool).
|
||||
dir2, fns_and_mtime = snapshot(ui, repo, modadd, None, tmproot,
|
||||
subrepos)
|
||||
dir2, fnsandstat = snapshot(ui, repo, modadd, None, tmproot,
|
||||
subrepos)
|
||||
else:
|
||||
# This lets the diff tool open the changed file directly
|
||||
dir2 = ''
|
||||
@ -249,7 +248,7 @@ def dodiff(ui, repo, cmdline, pats, opts):
|
||||
dir2 = repo.vfs.reljoin(tmproot, label2)
|
||||
dir1b = None
|
||||
label1b = None
|
||||
fns_and_mtime = []
|
||||
fnsandstat = []
|
||||
|
||||
# Function to quote file/dir names in the argument string.
|
||||
# When not operating in 3-way mode, an empty string is
|
||||
@ -275,8 +274,13 @@ def dodiff(ui, repo, cmdline, pats, opts):
|
||||
ui.debug('running %r in %s\n' % (cmdline, tmproot))
|
||||
ui.system(cmdline, cwd=tmproot, blockedtag='extdiff')
|
||||
|
||||
for copy_fn, working_fn, mtime in fns_and_mtime:
|
||||
if os.lstat(copy_fn).st_mtime != mtime:
|
||||
for copy_fn, working_fn, st in fnsandstat:
|
||||
cpstat = os.lstat(copy_fn)
|
||||
# Some tools copy the file and attributes, so mtime may not detect
|
||||
# all changes. A size check will detect more cases, but not all.
|
||||
# The only certain way to detect every case is to diff all files,
|
||||
# which could be expensive.
|
||||
if cpstat.st_mtime != st.st_mtime or cpstat.st_size != st.st_size:
|
||||
ui.debug('file changed while diffing. '
|
||||
'Overwriting: %s (src: %s)\n' % (working_fn, copy_fn))
|
||||
util.copyfile(copy_fn, working_fn)
|
||||
|
@ -324,8 +324,11 @@ Test with revsets:
|
||||
|
||||
Fallback to merge-tools.tool.executable|regkey
|
||||
$ mkdir dir
|
||||
$ cat > 'dir/tool.sh' << EOF
|
||||
$ cat > 'dir/tool.sh' << 'EOF'
|
||||
> #!/bin/sh
|
||||
> # Mimic a tool that syncs all attrs, including mtime
|
||||
> cp $1/a $2/a
|
||||
> touch -r $1/a $2/a
|
||||
> echo "** custom diff **"
|
||||
> EOF
|
||||
#if execbit
|
||||
@ -344,6 +347,9 @@ of $tool (and fail).
|
||||
$ tool=`pwd`/dir/tool.sh
|
||||
#endif
|
||||
|
||||
$ cat a
|
||||
changed
|
||||
edited
|
||||
$ hg --debug tl --config extdiff.tl= --config merge-tools.tl.executable=$tool
|
||||
making snapshot of 2 files from rev * (glob)
|
||||
a
|
||||
@ -354,8 +360,11 @@ of $tool (and fail).
|
||||
running '$TESTTMP/a/dir/tool.bat a.* a' in */extdiff.* (glob) (windows !)
|
||||
running '$TESTTMP/a/dir/tool.sh a.* a' in */extdiff.* (glob) (no-windows !)
|
||||
** custom diff **
|
||||
file changed while diffing. Overwriting: $TESTTMP/a/a (src: */extdiff.*/a/a) (glob)
|
||||
cleaning up temp directory
|
||||
[1]
|
||||
$ cat a
|
||||
a
|
||||
|
||||
$ cd ..
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user