difftool --dir-diff: symlink all files matching the working tree

Some users like to edit files in their diff tool when using "git difftool --dir-diff --symlink" to compare against the working tree but difftool currently only created symlinks when a file contains unstaged changes. Change this behaviour so that symlinks are created whenever the right-hand side of the comparison has the same SHA1 as the file in the working tree. Note that textconv filters are handled in the same way as by git-diff and if a clean filter is not the inverse of its smudge filter we already get a null SHA1 from "diff --raw" and will symlink the file without going through the new hash-object based check. Signed-off-by: John Keeping <john@keeping.me.uk> Signed-off-by: Junio C Hamano <gitster@pobox.com>

John Keeping committed Mar 14, 2013 at 20:19 UTC 02c56314aab9474827cd7831518a970f0341e4fd
3 files changed +43 -4
Documentation/git-difftool.txt
+3 -1
@@ -72,7 +72,9 @@ with custom merge tool commands and has the same value as `$MERGED`.
72 --symlinks::
73 --no-symlinks::
74 '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.
78 +
79 Specifying `--no-symlinks` instructs 'git difftool' to create copies
80 instead. `--no-symlinks` is the default on Windows.
git-difftool.perl
+18 -3
@@ -83,6 +83,21 @@ sub exit_cleanup
83 exit($status | ($status >> 8));
84 }
85
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 +
101 sub setup_dir_diff
102 {
103 my ($repo, $workdir, $symlinks) = @_;
@@ -159,10 +174,10 @@ EOF
174 }
175
176 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)) {
178 push(@working_tree, $dst_path);
179 + } else {
180 + $rindex .= "$rmode $rsha1\t$dst_path\0";
181 }
182 }
183 }
t/t7800-difftool.sh
+22
@@ -370,6 +370,28 @@ test_expect_success PERL 'difftool --dir-diff' '
370 echo "$diff" | stdin_contains file
371 '
372
373 +write_script .git/CHECK_SYMLINKS <<\EOF
374 +for f in file file2 sub/sub
375 +do
376 + echo "$f"
377 + readlink "$2/$f"
378 +done >actual
379 +EOF
380 +
381 +test_expect_success PERL,SYMLINKS 'difftool --dir-diff --symlink without unstaged changes' '
382 + cat >expect <<-EOF &&
383 + file
384 + $(pwd)/file
385 + file2
386 + $(pwd)/file2
387 + sub/sub
388 + $(pwd)/sub/sub
389 + EOF
390 + git difftool --dir-diff --symlink \
391 + --extcmd "./.git/CHECK_SYMLINKS" branch HEAD &&
392 + test_cmp actual expect
393 +'
394 +
395 test_expect_success PERL 'difftool --dir-diff ignores --prompt' '
396 diff=$(git difftool --dir-diff --prompt --extcmd ls branch) &&
397 echo "$diff" | stdin_contains sub &&