Skip to content

Commit 18973d8

Browse files
committed
Merge branch 'jk/difftool-dir-diff-edit-fix'
"git difftool --dir-diff" made symlinks to working tree files when preparing a temporary directory structure, so that accidental edits of these files in the difftool are reflected back to the working tree, but the logic to decide when to do so was not quite right. * jk/difftool-dir-diff-edit-fix: difftool --dir-diff: symlink all files matching the working tree difftool: avoid double slashes in symlink targets git-difftool(1): fix formatting of --symlink description
2 parents d8355e5 + 02c5631 commit 18973d8

File tree

3 files changed

+48
-7
lines changed

3 files changed

+48
-7
lines changed

Documentation/git-difftool.txt

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,10 +72,12 @@ with custom merge tool commands and has the same value as `$MERGED`.
7272
--symlinks::
7373
--no-symlinks::
7474
'git difftool''s default behavior is create symlinks to the
75-
working tree when run in `--dir-diff` mode.
75+
working tree when run in `--dir-diff` mode and the right-hand
76+
side of the comparison yields the same content as the file in
77+
the working tree.
7678
+
77-
Specifying `--no-symlinks` instructs 'git difftool' to create
78-
copies instead. `--no-symlinks` is the default on Windows.
79+
Specifying `--no-symlinks` instructs 'git difftool' to create copies
80+
instead. `--no-symlinks` is the default on Windows.
7981

8082
-x <command>::
8183
--extcmd=<command>::

git-difftool.perl

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,21 @@ sub exit_cleanup
8383
exit($status | ($status >> 8));
8484
}
8585

86+
sub use_wt_file
87+
{
88+
my ($repo, $workdir, $file, $sha1, $symlinks) = @_;
89+
my $null_sha1 = '0' x 40;
90+
91+
if ($sha1 eq $null_sha1) {
92+
return 1;
93+
} elsif (not $symlinks) {
94+
return 0;
95+
}
96+
97+
my $wt_sha1 = $repo->command_oneline('hash-object', "$workdir/$file");
98+
return $sha1 eq $wt_sha1;
99+
}
100+
86101
sub setup_dir_diff
87102
{
88103
my ($repo, $workdir, $symlinks) = @_;
@@ -159,10 +174,10 @@ sub setup_dir_diff
159174
}
160175

161176
if ($rmode ne $null_mode) {
162-
if ($rsha1 ne $null_sha1) {
163-
$rindex .= "$rmode $rsha1\t$dst_path\0";
164-
} else {
177+
if (use_wt_file($repo, $workdir, $dst_path, $rsha1, $symlinks)) {
165178
push(@working_tree, $dst_path);
179+
} else {
180+
$rindex .= "$rmode $rsha1\t$dst_path\0";
166181
}
167182
}
168183
}
@@ -209,7 +224,9 @@ sub setup_dir_diff
209224
delete($ENV{GIT_INDEX_FILE});
210225

211226
# Changes in the working tree need special treatment since they are
212-
# not part of the index
227+
# not part of the index. Remove any trailing slash from $workdir
228+
# before starting to avoid double slashes in symlink targets.
229+
$workdir =~ s|/$||;
213230
for my $file (@working_tree) {
214231
my $dir = dirname($file);
215232
unless (-d "$rdir/$dir") {

t/t7800-difftool.sh

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,28 @@ test_expect_success PERL 'difftool --dir-diff' '
340340
stdin_contains file <output
341341
'
342342

343+
write_script .git/CHECK_SYMLINKS <<\EOF
344+
for f in file file2 sub/sub
345+
do
346+
echo "$f"
347+
readlink "$2/$f"
348+
done >actual
349+
EOF
350+
351+
test_expect_success PERL,SYMLINKS 'difftool --dir-diff --symlink without unstaged changes' '
352+
cat >expect <<-EOF &&
353+
file
354+
$(pwd)/file
355+
file2
356+
$(pwd)/file2
357+
sub/sub
358+
$(pwd)/sub/sub
359+
EOF
360+
git difftool --dir-diff --symlink \
361+
--extcmd "./.git/CHECK_SYMLINKS" branch HEAD &&
362+
test_cmp actual expect
363+
'
364+
343365
test_expect_success PERL 'difftool --dir-diff ignores --prompt' '
344366
git difftool --dir-diff --prompt --extcmd ls branch >output &&
345367
stdin_contains sub <output &&

0 commit comments

Comments
 (0)