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>
This commit is contained in:
parent
b965e8f44a
commit
1f22934575
@ -66,6 +66,14 @@ of the diff post-image. `$MERGED` is the name of the file which is
|
|||||||
being compared. `$BASE` is provided for compatibility
|
being compared. `$BASE` is provided for compatibility
|
||||||
with custom merge tool commands and has the same value as `$MERGED`.
|
with custom merge tool commands and has the same value as `$MERGED`.
|
||||||
|
|
||||||
|
--symlinks::
|
||||||
|
--no-symlinks::
|
||||||
|
'git difftool''s default behavior is create symlinks to the
|
||||||
|
working tree when run in `--dir-diff` mode.
|
||||||
|
+
|
||||||
|
Specifying `--no-symlinks` instructs 'git difftool' to create
|
||||||
|
copies instead. `--no-symlinks` is the default on Windows.
|
||||||
|
|
||||||
--tool-help::
|
--tool-help::
|
||||||
Print a list of diff tools that may be used with `--tool`.
|
Print a list of diff tools that may be used with `--tool`.
|
||||||
|
|
||||||
|
@ -92,7 +92,7 @@ sub print_tool_help
|
|||||||
|
|
||||||
sub setup_dir_diff
|
sub setup_dir_diff
|
||||||
{
|
{
|
||||||
my ($repo, $workdir) = @_;
|
my ($repo, $workdir, $symlinks) = @_;
|
||||||
|
|
||||||
# Run the diff; exit immediately if no diff found
|
# Run the diff; exit immediately if no diff found
|
||||||
# 'Repository' and 'WorkingCopy' must be explicitly set to insure that
|
# 'Repository' and 'WorkingCopy' must be explicitly set to insure that
|
||||||
@ -209,8 +209,13 @@ sub setup_dir_diff
|
|||||||
unless (-d "$rdir/$dir") {
|
unless (-d "$rdir/$dir") {
|
||||||
mkpath("$rdir/$dir") or die $!;
|
mkpath("$rdir/$dir") or die $!;
|
||||||
}
|
}
|
||||||
copy("$workdir/$file", "$rdir/$file") or die $!;
|
if ($symlinks) {
|
||||||
chmod(stat("$workdir/$file")->mode, "$rdir/$file") or die $!;
|
symlink("$workdir/$file", "$rdir/$file") or die $!;
|
||||||
|
} else {
|
||||||
|
copy("$workdir/$file", "$rdir/$file") or die $!;
|
||||||
|
my $mode = stat("$workdir/$file")->mode;
|
||||||
|
chmod($mode, "$rdir/$file") or die $!;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# Changes to submodules require special treatment. This loop writes a
|
# Changes to submodules require special treatment. This loop writes a
|
||||||
@ -271,6 +276,7 @@ sub main
|
|||||||
gui => undef,
|
gui => undef,
|
||||||
help => undef,
|
help => undef,
|
||||||
prompt => undef,
|
prompt => undef,
|
||||||
|
symlinks => $^O ne 'MSWin32' && $^O ne 'msys',
|
||||||
tool_help => undef,
|
tool_help => undef,
|
||||||
);
|
);
|
||||||
GetOptions('g|gui!' => \$opts{gui},
|
GetOptions('g|gui!' => \$opts{gui},
|
||||||
@ -278,6 +284,8 @@ sub main
|
|||||||
'h' => \$opts{help},
|
'h' => \$opts{help},
|
||||||
'prompt!' => \$opts{prompt},
|
'prompt!' => \$opts{prompt},
|
||||||
'y' => sub { $opts{prompt} = 0; },
|
'y' => sub { $opts{prompt} = 0; },
|
||||||
|
'symlinks' => \$opts{symlinks},
|
||||||
|
'no-symlinks' => sub { $opts{symlinks} = 0; },
|
||||||
't|tool:s' => \$opts{difftool_cmd},
|
't|tool:s' => \$opts{difftool_cmd},
|
||||||
'tool-help' => \$opts{tool_help},
|
'tool-help' => \$opts{tool_help},
|
||||||
'x|extcmd:s' => \$opts{extcmd});
|
'x|extcmd:s' => \$opts{extcmd});
|
||||||
@ -316,7 +324,7 @@ sub main
|
|||||||
# will invoke a separate instance of 'git-difftool--helper' for
|
# will invoke a separate instance of 'git-difftool--helper' for
|
||||||
# each file that changed.
|
# each file that changed.
|
||||||
if (defined($opts{dirdiff})) {
|
if (defined($opts{dirdiff})) {
|
||||||
dir_diff($opts{extcmd});
|
dir_diff($opts{extcmd}, $opts{symlinks});
|
||||||
} else {
|
} else {
|
||||||
file_diff($opts{prompt});
|
file_diff($opts{prompt});
|
||||||
}
|
}
|
||||||
@ -324,13 +332,13 @@ sub main
|
|||||||
|
|
||||||
sub dir_diff
|
sub dir_diff
|
||||||
{
|
{
|
||||||
my ($extcmd) = @_;
|
my ($extcmd, $symlinks) = @_;
|
||||||
|
|
||||||
my $rc;
|
my $rc;
|
||||||
my $repo = Git->repository();
|
my $repo = Git->repository();
|
||||||
|
|
||||||
my $workdir = find_worktree($repo);
|
my $workdir = find_worktree($repo);
|
||||||
my ($a, $b, @working_tree) = setup_dir_diff($repo, $workdir);
|
my ($a, $b, @worktree) = setup_dir_diff($repo, $workdir, $symlinks);
|
||||||
if (defined($extcmd)) {
|
if (defined($extcmd)) {
|
||||||
$rc = system($extcmd, $a, $b);
|
$rc = system($extcmd, $a, $b);
|
||||||
} else {
|
} else {
|
||||||
@ -342,13 +350,18 @@ sub dir_diff
|
|||||||
|
|
||||||
# If the diff including working copy files and those
|
# If the diff including working copy files and those
|
||||||
# files were modified during the diff, then the changes
|
# files were modified during the diff, then the changes
|
||||||
# should be copied back to the working tree
|
# should be copied back to the working tree.
|
||||||
for my $file (@working_tree) {
|
# Do not copy back files when symlinks are used and the
|
||||||
if (-e "$b/$file" && compare("$b/$file", "$workdir/$file")) {
|
# external tool did not replace the original link with a file.
|
||||||
|
for my $file (@worktree) {
|
||||||
|
next if $symlinks && -l "$b/$file";
|
||||||
|
if (-f "$b/$file" && compare("$b/$file", "$workdir/$file")) {
|
||||||
copy("$b/$file", "$workdir/$file") or die $!;
|
copy("$b/$file", "$workdir/$file") or die $!;
|
||||||
chmod(stat("$b/$file")->mode, "$workdir/$file") or die $!;
|
my $mode = stat("$b/$file")->mode;
|
||||||
|
chmod($mode, "$workdir/$file") or die $!;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
sub file_diff
|
sub file_diff
|
||||||
|
Loading…
Reference in New Issue
Block a user