Skip to content

Commit 1f22934

Browse files
davvidgitster
authored andcommitted
difftool: Use symlinks when diffing against the worktree
Teach difftool's --dir-diff mode to use symlinks to represent files from the working copy, and make it the default behavior for the non-Windows platforms. Using symlinks is simpler and safer since we do not need to worry about copying files back into the worktree. The old behavior is still available as --no-symlinks. Signed-off-by: David Aguilar <davvid@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent b965e8f commit 1f22934

File tree

2 files changed

+31
-10
lines changed

2 files changed

+31
-10
lines changed

Documentation/git-difftool.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,14 @@ of the diff post-image. `$MERGED` is the name of the file which is
6666
being compared. `$BASE` is provided for compatibility
6767
with custom merge tool commands and has the same value as `$MERGED`.
6868

69+
--symlinks::
70+
--no-symlinks::
71+
'git difftool''s default behavior is create symlinks to the
72+
working tree when run in `--dir-diff` mode.
73+
+
74+
Specifying `--no-symlinks` instructs 'git difftool' to create
75+
copies instead. `--no-symlinks` is the default on Windows.
76+
6977
--tool-help::
7078
Print a list of diff tools that may be used with `--tool`.
7179

git-difftool.perl

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ sub print_tool_help
9292

9393
sub setup_dir_diff
9494
{
95-
my ($repo, $workdir) = @_;
95+
my ($repo, $workdir, $symlinks) = @_;
9696

9797
# Run the diff; exit immediately if no diff found
9898
# 'Repository' and 'WorkingCopy' must be explicitly set to insure that
@@ -209,8 +209,13 @@ sub setup_dir_diff
209209
unless (-d "$rdir/$dir") {
210210
mkpath("$rdir/$dir") or die $!;
211211
}
212-
copy("$workdir/$file", "$rdir/$file") or die $!;
213-
chmod(stat("$workdir/$file")->mode, "$rdir/$file") or die $!;
212+
if ($symlinks) {
213+
symlink("$workdir/$file", "$rdir/$file") or die $!;
214+
} else {
215+
copy("$workdir/$file", "$rdir/$file") or die $!;
216+
my $mode = stat("$workdir/$file")->mode;
217+
chmod($mode, "$rdir/$file") or die $!;
218+
}
214219
}
215220

216221
# Changes to submodules require special treatment. This loop writes a
@@ -271,13 +276,16 @@ sub main
271276
gui => undef,
272277
help => undef,
273278
prompt => undef,
279+
symlinks => $^O ne 'MSWin32' && $^O ne 'msys',
274280
tool_help => undef,
275281
);
276282
GetOptions('g|gui!' => \$opts{gui},
277283
'd|dir-diff' => \$opts{dirdiff},
278284
'h' => \$opts{help},
279285
'prompt!' => \$opts{prompt},
280286
'y' => sub { $opts{prompt} = 0; },
287+
'symlinks' => \$opts{symlinks},
288+
'no-symlinks' => sub { $opts{symlinks} = 0; },
281289
't|tool:s' => \$opts{difftool_cmd},
282290
'tool-help' => \$opts{tool_help},
283291
'x|extcmd:s' => \$opts{extcmd});
@@ -316,21 +324,21 @@ sub main
316324
# will invoke a separate instance of 'git-difftool--helper' for
317325
# each file that changed.
318326
if (defined($opts{dirdiff})) {
319-
dir_diff($opts{extcmd});
327+
dir_diff($opts{extcmd}, $opts{symlinks});
320328
} else {
321329
file_diff($opts{prompt});
322330
}
323331
}
324332

325333
sub dir_diff
326334
{
327-
my ($extcmd) = @_;
335+
my ($extcmd, $symlinks) = @_;
328336

329337
my $rc;
330338
my $repo = Git->repository();
331339

332340
my $workdir = find_worktree($repo);
333-
my ($a, $b, @working_tree) = setup_dir_diff($repo, $workdir);
341+
my ($a, $b, @worktree) = setup_dir_diff($repo, $workdir, $symlinks);
334342
if (defined($extcmd)) {
335343
$rc = system($extcmd, $a, $b);
336344
} else {
@@ -342,13 +350,18 @@ sub dir_diff
342350

343351
# If the diff including working copy files and those
344352
# files were modified during the diff, then the changes
345-
# should be copied back to the working tree
346-
for my $file (@working_tree) {
347-
if (-e "$b/$file" && compare("$b/$file", "$workdir/$file")) {
353+
# should be copied back to the working tree.
354+
# Do not copy back files when symlinks are used and the
355+
# external tool did not replace the original link with a file.
356+
for my $file (@worktree) {
357+
next if $symlinks && -l "$b/$file";
358+
if (-f "$b/$file" && compare("$b/$file", "$workdir/$file")) {
348359
copy("$b/$file", "$workdir/$file") or die $!;
349-
chmod(stat("$b/$file")->mode, "$workdir/$file") or die $!;
360+
my $mode = stat("$b/$file")->mode;
361+
chmod($mode, "$workdir/$file") or die $!;
350362
}
351363
}
364+
exit(0);
352365
}
353366

354367
sub file_diff

0 commit comments

Comments
 (0)