{"thread":{"id":"31089","subject":"[PATCH v4 0/5] difftool: Use symlinks in dir-diff mode","startedAt":"2012-07-25T02:59:28Z","lastAt":"2012-07-25T02:59:33Z","messageCount":6,"participants":["David Aguilar"],"isPatch":true,"patchVersion":4,"patchTotal":5},"messages":[{"id":"195684","messageId":"1343185173-48278-1-git-send-email-davvid@gmail.com","threadId":"31089","inReplyTo":null,"subject":"[PATCH v4 0/5] difftool: Use symlinks in dir-diff mode","fromName":"David Aguilar","fromEmail":"davvid@gmail.com","sentAt":"2012-07-25T02:59:28Z","receivedAt":"2012-07-25T02:59:28Z","isPatch":true,"sender":{"key":"davvid@gmail.com","avatar":"https://avatars.githubusercontent.com/u/13196?v=4"},"body":"Teach difftool to use symlinks when diffing against the worktree.\n\nDavid Aguilar (5):\n  difftool: print_tool_help() globals\n  difftool: Eliminate global variables\n  difftool: Move option values into a hash\n  difftool: Call the temp directory \"git-difftool\"\n  difftool: Use symlinks when diffing against the worktree\n\n Documentation/git-difftool.txt |   8 ++\n git-difftool.perl              | 180 ++++++++++++++++++++++++++---------------\n 2 files changed, 124 insertions(+), 64 deletions(-)\n\n-- \n1.7.12.rc0.15.g8157c39\n"},{"id":"195685","messageId":"1343185173-48278-2-git-send-email-davvid@gmail.com","threadId":"31089","inReplyTo":"1343185173-48278-1-git-send-email-davvid@gmail.com","subject":"[PATCH v4 1/5] difftool: print_tool_help() globals","fromName":"David Aguilar","fromEmail":"davvid@gmail.com","sentAt":"2012-07-25T02:59:29Z","receivedAt":"2012-07-25T02:59:29Z","isPatch":true,"sender":{"key":"davvid@gmail.com","avatar":"https://avatars.githubusercontent.com/u/13196?v=4"},"body":"Replace a global variable with a closure.\n\nSigned-off-by: David Aguilar <davvid@gmail.com>\n---\nDifferences from last time:\n\nThis keeps the original File::Find implementation and wraps the\nglobal variable in a closure as the first step in the\nglobals-elimination cleanup.\n\n git-difftool.perl | 8 ++++----\n 1 file changed, 4 insertions(+), 4 deletions(-)\n\ndiff --git a/git-difftool.perl b/git-difftool.perl\nindex c079854..d4737e1 100755\n--- a/git-difftool.perl\n+++ b/git-difftool.perl\n@@ -23,7 +23,6 @@ use File::Temp qw(tempdir);\n use Getopt::Long qw(:config pass_through);\n use Git;\n \n-my @tools;\n my @working_tree;\n my $rc;\n my $repo = Git->repository();\n@@ -67,6 +66,7 @@ my $workdir = find_worktree();\n \n sub filter_tool_scripts\n {\n+\tmy ($tools) = @_;\n \tif (-d $_) {\n \t\tif ($_ ne \".\") {\n \t\t\t# Ignore files in subdirectories\n@@ -74,17 +74,17 @@ sub filter_tool_scripts\n \t\t}\n \t} else {\n \t\tif ((-f $_) && ($_ ne \"defaults\")) {\n-\t\t\tpush(@tools, $_);\n+\t\t\tpush(@$tools, $_);\n \t\t}\n \t}\n }\n \n sub print_tool_help\n {\n-\tmy ($cmd, @found, @notfound);\n+\tmy ($cmd, @found, @notfound, @tools);\n \tmy $gitpath = Git::exec_path();\n \n-\tfind(\\&filter_tool_scripts, \"$gitpath/mergetools\");\n+\tfind(sub { filter_tool_scripts(\\@tools) }, \"$gitpath/mergetools\");\n \n \tforeach my $tool (@tools) {\n \t\t$cmd  = \"TOOL_MODE=diff\";\n-- \n1.7.12.rc0.15.g8157c39\n"},{"id":"195689","messageId":"1343185173-48278-3-git-send-email-davvid@gmail.com","threadId":"31089","inReplyTo":"1343185173-48278-1-git-send-email-davvid@gmail.com","subject":"[PATCH v4 2/5] difftool: Eliminate global variables","fromName":"David Aguilar","fromEmail":"davvid@gmail.com","sentAt":"2012-07-25T02:59:30Z","receivedAt":"2012-07-25T02:59:30Z","isPatch":true,"sender":{"key":"davvid@gmail.com","avatar":"https://avatars.githubusercontent.com/u/13196?v=4"},"body":"Organize the script so that it has a single main() function which\ncalls out to dir_diff() and file_diff() functions. This eliminates\n\"dir-diff\"-specific variables that do not need to be calculated when\nperforming a regular file-diff.\n\nSigned-off-by: David Aguilar <davvid@gmail.com>\n---\nSame as last time, but rebased against the new 1/5\n\n git-difftool.perl | 128 ++++++++++++++++++++++++++++++++----------------------\n 1 file changed, 75 insertions(+), 53 deletions(-)\n\ndiff --git a/git-difftool.perl b/git-difftool.perl\nindex d4737e1..fa787d6 100755\n--- a/git-difftool.perl\n+++ b/git-difftool.perl\n@@ -23,11 +23,6 @@ use File::Temp qw(tempdir);\n use Getopt::Long qw(:config pass_through);\n use Git;\n \n-my @working_tree;\n-my $rc;\n-my $repo = Git->repository();\n-my $repo_path = $repo->repo_path();\n-\n sub usage\n {\n \tmy $exitcode = shift;\n@@ -44,6 +39,8 @@ USAGE\n \n sub find_worktree\n {\n+\tmy ($repo) = @_;\n+\n \t# Git->repository->wc_path() does not honor changes to the working\n \t# tree location made by $ENV{GIT_WORK_TREE} or the 'core.worktree'\n \t# config variable.\n@@ -62,8 +59,6 @@ sub find_worktree\n \treturn $worktree;\n }\n \n-my $workdir = find_worktree();\n-\n sub filter_tool_scripts\n {\n \tmy ($tools) = @_;\n@@ -112,10 +107,13 @@ sub print_tool_help\n \n sub setup_dir_diff\n {\n+\tmy ($repo, $workdir) = @_;\n+\n \t# Run the diff; exit immediately if no diff found\n \t# 'Repository' and 'WorkingCopy' must be explicitly set to insure that\n \t# if $GIT_DIR and $GIT_WORK_TREE are set in ENV, they are actually used\n \t# by Git->repository->command*.\n+\tmy $repo_path = $repo->repo_path();\n \tmy $diffrepo = Git->repository(Repository => $repo_path, WorkingCopy => $workdir);\n \tmy $diffrtn = $diffrepo->command_oneline('diff', '--raw', '--no-abbrev', '-z', @ARGV);\n \texit(0) if (length($diffrtn) == 0);\n@@ -136,6 +134,7 @@ sub setup_dir_diff\n \tmy $rindex = '';\n \tmy %submodule;\n \tmy %symlink;\n+\tmy @working_tree = ();\n \tmy @rawdiff = split('\\0', $diffrtn);\n \n \tmy $i = 0;\n@@ -203,7 +202,7 @@ sub setup_dir_diff\n \t($inpipe, $ctx) = $repo->command_input_pipe(qw/update-index -z --index-info/);\n \tprint($inpipe $lindex);\n \t$repo->command_close_pipe($inpipe, $ctx);\n-\t$rc = system('git', 'checkout-index', '--all', \"--prefix=$ldir/\");\n+\tmy $rc = system('git', 'checkout-index', '--all', \"--prefix=$ldir/\");\n \texit($rc | ($rc >> 8)) if ($rc != 0);\n \n \t$ENV{GIT_INDEX_FILE} = \"$tmpdir/rindex\";\n@@ -253,7 +252,7 @@ sub setup_dir_diff\n \t\t}\n \t}\n \n-\treturn ($ldir, $rdir);\n+\treturn ($ldir, $rdir, @working_tree);\n }\n \n sub write_to_file\n@@ -276,54 +275,70 @@ sub write_to_file\n \tclose($fh);\n }\n \n-# parse command-line options. all unrecognized options and arguments\n-# are passed through to the 'git diff' command.\n-my ($difftool_cmd, $dirdiff, $extcmd, $gui, $help, $prompt, $tool_help);\n-GetOptions('g|gui!' => \\$gui,\n-\t'd|dir-diff' => \\$dirdiff,\n-\t'h' => \\$help,\n-\t'prompt!' => \\$prompt,\n-\t'y' => sub { $prompt = 0; },\n-\t't|tool:s' => \\$difftool_cmd,\n-\t'tool-help' => \\$tool_help,\n-\t'x|extcmd:s' => \\$extcmd);\n-\n-if (defined($help)) {\n-\tusage(0);\n-}\n-if (defined($tool_help)) {\n-\tprint_tool_help();\n-}\n-if (defined($difftool_cmd)) {\n-\tif (length($difftool_cmd) > 0) {\n-\t\t$ENV{GIT_DIFF_TOOL} = $difftool_cmd;\n-\t} else {\n-\t\tprint \"No <tool> given for --tool=<tool>\\n\";\n-\t\tusage(1);\n+sub main\n+{\n+\t# parse command-line options. all unrecognized options and arguments\n+\t# are passed through to the 'git diff' command.\n+\tmy ($difftool_cmd, $dirdiff, $extcmd, $gui, $help, $prompt, $tool_help);\n+\tGetOptions('g|gui!' => \\$gui,\n+\t\t'd|dir-diff' => \\$dirdiff,\n+\t\t'h' => \\$help,\n+\t\t'prompt!' => \\$prompt,\n+\t\t'y' => sub { $prompt = 0; },\n+\t\t't|tool:s' => \\$difftool_cmd,\n+\t\t'tool-help' => \\$tool_help,\n+\t\t'x|extcmd:s' => \\$extcmd);\n+\n+\tif (defined($help)) {\n+\t\tusage(0);\n \t}\n-}\n-if (defined($extcmd)) {\n-\tif (length($extcmd) > 0) {\n-\t\t$ENV{GIT_DIFFTOOL_EXTCMD} = $extcmd;\n-\t} else {\n-\t\tprint \"No <cmd> given for --extcmd=<cmd>\\n\";\n-\t\tusage(1);\n+\tif (defined($tool_help)) {\n+\t\tprint_tool_help();\n \t}\n-}\n-if ($gui) {\n-\tmy $guitool = '';\n-\t$guitool = Git::config('diff.guitool');\n-\tif (length($guitool) > 0) {\n-\t\t$ENV{GIT_DIFF_TOOL} = $guitool;\n+\tif (defined($difftool_cmd)) {\n+\t\tif (length($difftool_cmd) > 0) {\n+\t\t\t$ENV{GIT_DIFF_TOOL} = $difftool_cmd;\n+\t\t} else {\n+\t\t\tprint \"No <tool> given for --tool=<tool>\\n\";\n+\t\t\tusage(1);\n+\t\t}\n+\t}\n+\tif (defined($extcmd)) {\n+\t\tif (length($extcmd) > 0) {\n+\t\t\t$ENV{GIT_DIFFTOOL_EXTCMD} = $extcmd;\n+\t\t} else {\n+\t\t\tprint \"No <cmd> given for --extcmd=<cmd>\\n\";\n+\t\t\tusage(1);\n+\t\t}\n+\t}\n+\tif ($gui) {\n+\t\tmy $guitool = '';\n+\t\t$guitool = Git::config('diff.guitool');\n+\t\tif (length($guitool) > 0) {\n+\t\t\t$ENV{GIT_DIFF_TOOL} = $guitool;\n+\t\t}\n+\t}\n+\n+\t# In directory diff mode, 'git-difftool--helper' is called once\n+\t# to compare the a/b directories.  In file diff mode, 'git diff'\n+\t# will invoke a separate instance of 'git-difftool--helper' for\n+\t# each file that changed.\n+\tif (defined($dirdiff)) {\n+\t\tdir_diff($extcmd);\n+\t} else {\n+\t\tfile_diff($prompt);\n \t}\n }\n \n-# In directory diff mode, 'git-difftool--helper' is called once\n-# to compare the a/b directories.  In file diff mode, 'git diff'\n-# will invoke a separate instance of 'git-difftool--helper' for\n-# each file that changed.\n-if (defined($dirdiff)) {\n-\tmy ($a, $b) = setup_dir_diff();\n+sub dir_diff\n+{\n+\tmy ($extcmd) = @_;\n+\n+\tmy $rc;\n+\tmy $repo = Git->repository();\n+\n+\tmy $workdir = find_worktree($repo);\n+\tmy ($a, $b, @working_tree) = setup_dir_diff($repo, $workdir);\n \tif (defined($extcmd)) {\n \t\t$rc = system($extcmd, $a, $b);\n \t} else {\n@@ -342,7 +357,12 @@ if (defined($dirdiff)) {\n \t\t\tchmod(stat(\"$b/$file\")->mode, \"$workdir/$file\") or die $!;\n \t\t}\n \t}\n-} else {\n+}\n+\n+sub file_diff\n+{\n+\tmy ($prompt) = @_;\n+\n \tif (defined($prompt)) {\n \t\tif ($prompt) {\n \t\t\t$ENV{GIT_DIFFTOOL_PROMPT} = 'true';\n@@ -362,3 +382,5 @@ if (defined($dirdiff)) {\n \tmy $rc = system('git', 'diff', @ARGV);\n \texit($rc | ($rc >> 8));\n }\n+\n+main();\n-- \n1.7.12.rc0.15.g8157c39\n"},{"id":"195686","messageId":"1343185173-48278-4-git-send-email-davvid@gmail.com","threadId":"31089","inReplyTo":"1343185173-48278-1-git-send-email-davvid@gmail.com","subject":"[PATCH v4 3/5] difftool: Move option values into a hash","fromName":"David Aguilar","fromEmail":"davvid@gmail.com","sentAt":"2012-07-25T02:59:31Z","receivedAt":"2012-07-25T02:59:31Z","isPatch":true,"sender":{"key":"davvid@gmail.com","avatar":"https://avatars.githubusercontent.com/u/13196?v=4"},"body":"Shorten the \"my\" declaration for all of the option-specific variables\nby wrapping all of them in a hash.  This also gives us a place to\nspecify default values, should we need them.\n\nSigned-off-by: David Aguilar <davvid@gmail.com>\n---\nSame as last time, rebased\n\n git-difftool.perl | 55 +++++++++++++++++++++++++++++++------------------------\n 1 file changed, 31 insertions(+), 24 deletions(-)\n\ndiff --git a/git-difftool.perl b/git-difftool.perl\nindex fa787d6..685887d 100755\n--- a/git-difftool.perl\n+++ b/git-difftool.perl\n@@ -279,41 +279,48 @@ sub main\n {\n \t# parse command-line options. all unrecognized options and arguments\n \t# are passed through to the 'git diff' command.\n-\tmy ($difftool_cmd, $dirdiff, $extcmd, $gui, $help, $prompt, $tool_help);\n-\tGetOptions('g|gui!' => \\$gui,\n-\t\t'd|dir-diff' => \\$dirdiff,\n-\t\t'h' => \\$help,\n-\t\t'prompt!' => \\$prompt,\n-\t\t'y' => sub { $prompt = 0; },\n-\t\t't|tool:s' => \\$difftool_cmd,\n-\t\t'tool-help' => \\$tool_help,\n-\t\t'x|extcmd:s' => \\$extcmd);\n-\n-\tif (defined($help)) {\n+\tmy %opts = (\n+\t\tdifftool_cmd => undef,\n+\t\tdirdiff => undef,\n+\t\textcmd => undef,\n+\t\tgui => undef,\n+\t\thelp => undef,\n+\t\tprompt => undef,\n+\t\ttool_help => undef,\n+\t);\n+\tGetOptions('g|gui!' => \\$opts{gui},\n+\t\t'd|dir-diff' => \\$opts{dirdiff},\n+\t\t'h' => \\$opts{help},\n+\t\t'prompt!' => \\$opts{prompt},\n+\t\t'y' => sub { $opts{prompt} = 0; },\n+\t\t't|tool:s' => \\$opts{difftool_cmd},\n+\t\t'tool-help' => \\$opts{tool_help},\n+\t\t'x|extcmd:s' => \\$opts{extcmd});\n+\n+\tif (defined($opts{help})) {\n \t\tusage(0);\n \t}\n-\tif (defined($tool_help)) {\n+\tif (defined($opts{tool_help})) {\n \t\tprint_tool_help();\n \t}\n-\tif (defined($difftool_cmd)) {\n-\t\tif (length($difftool_cmd) > 0) {\n-\t\t\t$ENV{GIT_DIFF_TOOL} = $difftool_cmd;\n+\tif (defined($opts{difftool_cmd})) {\n+\t\tif (length($opts{difftool_cmd}) > 0) {\n+\t\t\t$ENV{GIT_DIFF_TOOL} = $opts{difftool_cmd};\n \t\t} else {\n \t\t\tprint \"No <tool> given for --tool=<tool>\\n\";\n \t\t\tusage(1);\n \t\t}\n \t}\n-\tif (defined($extcmd)) {\n-\t\tif (length($extcmd) > 0) {\n-\t\t\t$ENV{GIT_DIFFTOOL_EXTCMD} = $extcmd;\n+\tif (defined($opts{extcmd})) {\n+\t\tif (length($opts{extcmd}) > 0) {\n+\t\t\t$ENV{GIT_DIFFTOOL_EXTCMD} = $opts{extcmd};\n \t\t} else {\n \t\t\tprint \"No <cmd> given for --extcmd=<cmd>\\n\";\n \t\t\tusage(1);\n \t\t}\n \t}\n-\tif ($gui) {\n-\t\tmy $guitool = '';\n-\t\t$guitool = Git::config('diff.guitool');\n+\tif ($opts{gui}) {\n+\t\tmy $guitool = Git::config('diff.guitool');\n \t\tif (length($guitool) > 0) {\n \t\t\t$ENV{GIT_DIFF_TOOL} = $guitool;\n \t\t}\n@@ -323,10 +330,10 @@ sub main\n \t# to compare the a/b directories.  In file diff mode, 'git diff'\n \t# will invoke a separate instance of 'git-difftool--helper' for\n \t# each file that changed.\n-\tif (defined($dirdiff)) {\n-\t\tdir_diff($extcmd);\n+\tif (defined($opts{dirdiff})) {\n+\t\tdir_diff($opts{extcmd});\n \t} else {\n-\t\tfile_diff($prompt);\n+\t\tfile_diff($opts{prompt});\n \t}\n }\n \n-- \n1.7.12.rc0.15.g8157c39\n"},{"id":"195687","messageId":"1343185173-48278-5-git-send-email-davvid@gmail.com","threadId":"31089","inReplyTo":"1343185173-48278-1-git-send-email-davvid@gmail.com","subject":"[PATCH v4 4/5] difftool: Call the temp directory \"git-difftool\"","fromName":"David Aguilar","fromEmail":"davvid@gmail.com","sentAt":"2012-07-25T02:59:32Z","receivedAt":"2012-07-25T02:59:32Z","isPatch":true,"sender":{"key":"davvid@gmail.com","avatar":"https://avatars.githubusercontent.com/u/13196?v=4"},"body":"The \"diffall\" name was left over from when this functionality was part of\nthe \"git-diffall\" script in contrib/.  Make the naming consistent.\n\nSigned-off-by: David Aguilar <davvid@gmail.com>\n---\nSame as last time, rebased\n\n git-difftool.perl | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/git-difftool.perl b/git-difftool.perl\nindex 685887d..b4f2fc6 100755\n--- a/git-difftool.perl\n+++ b/git-difftool.perl\n@@ -119,7 +119,7 @@ sub setup_dir_diff\n \texit(0) if (length($diffrtn) == 0);\n \n \t# Setup temp directories\n-\tmy $tmpdir = tempdir('git-diffall.XXXXX', CLEANUP => 1, TMPDIR => 1);\n+\tmy $tmpdir = tempdir('git-difftool.XXXXX', CLEANUP => 1, TMPDIR => 1);\n \tmy $ldir = \"$tmpdir/left\";\n \tmy $rdir = \"$tmpdir/right\";\n \tmkpath($ldir) or die $!;\n-- \n1.7.12.rc0.15.g8157c39\n"},{"id":"195688","messageId":"1343185173-48278-6-git-send-email-davvid@gmail.com","threadId":"31089","inReplyTo":"1343185173-48278-1-git-send-email-davvid@gmail.com","subject":"[PATCH v4 5/5] difftool: Use symlinks when diffing against the worktree","fromName":"David Aguilar","fromEmail":"davvid@gmail.com","sentAt":"2012-07-25T02:59:33Z","receivedAt":"2012-07-25T02:59:33Z","isPatch":true,"sender":{"key":"davvid@gmail.com","avatar":"https://avatars.githubusercontent.com/u/13196?v=4"},"body":"Teach difftool's --dir-diff mode to use symlinks to represent\nfiles from the working copy, and make it the default behavior\nfor the non-Windows platforms.\n\nUsing symlinks is safer since we avoid needing to copy temporary\nfiles into the worktree.\n\nThe original behavior is available as --no-symlinks.\n\nSigned-off-by: David Aguilar <davvid@gmail.com>\n---\nDifferences:\n\nThis version checks for compare() returning -1 and emit a warning.\n\n Documentation/git-difftool.txt |  8 ++++++++\n git-difftool.perl              | 43 ++++++++++++++++++++++++++++++++----------\n 2 files changed, 41 insertions(+), 10 deletions(-)\n\ndiff --git a/Documentation/git-difftool.txt b/Documentation/git-difftool.txt\nindex 31fc2e3..313d54e 100644\n--- a/Documentation/git-difftool.txt\n+++ b/Documentation/git-difftool.txt\n@@ -66,6 +66,14 @@ of the diff post-image.  `$MERGED` is the name of the file which is\n being compared. `$BASE` is provided for compatibility\n with custom merge tool commands and has the same value as `$MERGED`.\n \n+--symlinks::\n+--no-symlinks::\n+\t'git difftool''s default behavior is create symlinks to the\n+\tworking tree when run in `--dir-diff` mode.\n++\n+\tSpecifying `--no-symlinks` instructs 'git difftool' to create\n+\tcopies instead.  `--no-symlinks` is the default on Windows.\n+\n --tool-help::\n \tPrint a list of diff tools that may be used with `--tool`.\n \ndiff --git a/git-difftool.perl b/git-difftool.perl\nindex b4f2fc6..10d3d97 100755\n--- a/git-difftool.perl\n+++ b/git-difftool.perl\n@@ -107,7 +107,7 @@ sub print_tool_help\n \n sub setup_dir_diff\n {\n-\tmy ($repo, $workdir) = @_;\n+\tmy ($repo, $workdir, $symlinks) = @_;\n \n \t# Run the diff; exit immediately if no diff found\n \t# 'Repository' and 'WorkingCopy' must be explicitly set to insure that\n@@ -224,8 +224,13 @@ sub setup_dir_diff\n \t\tunless (-d \"$rdir/$dir\") {\n \t\t\tmkpath(\"$rdir/$dir\") or die $!;\n \t\t}\n-\t\tcopy(\"$workdir/$file\", \"$rdir/$file\") or die $!;\n-\t\tchmod(stat(\"$workdir/$file\")->mode, \"$rdir/$file\") or die $!;\n+\t\tif ($symlinks) {\n+\t\t\tsymlink(\"$workdir/$file\", \"$rdir/$file\") or die $!;\n+\t\t} else {\n+\t\t\tcopy(\"$workdir/$file\", \"$rdir/$file\") or die $!;\n+\t\t\tmy $mode = stat(\"$workdir/$file\")->mode;\n+\t\t\tchmod($mode, \"$rdir/$file\") or die $!;\n+\t\t}\n \t}\n \n \t# Changes to submodules require special treatment. This loop writes a\n@@ -286,6 +291,8 @@ sub main\n \t\tgui => undef,\n \t\thelp => undef,\n \t\tprompt => undef,\n+\t\tsymlinks => $^O ne 'cygwin' &&\n+\t\t\t\t$^O ne 'MSWin32' && $^O ne 'msys',\n \t\ttool_help => undef,\n \t);\n \tGetOptions('g|gui!' => \\$opts{gui},\n@@ -293,6 +300,8 @@ sub main\n \t\t'h' => \\$opts{help},\n \t\t'prompt!' => \\$opts{prompt},\n \t\t'y' => sub { $opts{prompt} = 0; },\n+\t\t'symlinks' => \\$opts{symlinks},\n+\t\t'no-symlinks' => sub { $opts{symlinks} = 0; },\n \t\t't|tool:s' => \\$opts{difftool_cmd},\n \t\t'tool-help' => \\$opts{tool_help},\n \t\t'x|extcmd:s' => \\$opts{extcmd});\n@@ -331,7 +340,7 @@ sub main\n \t# will invoke a separate instance of 'git-difftool--helper' for\n \t# each file that changed.\n \tif (defined($opts{dirdiff})) {\n-\t\tdir_diff($opts{extcmd});\n+\t\tdir_diff($opts{extcmd}, $opts{symlinks});\n \t} else {\n \t\tfile_diff($opts{prompt});\n \t}\n@@ -339,13 +348,13 @@ sub main\n \n sub dir_diff\n {\n-\tmy ($extcmd) = @_;\n+\tmy ($extcmd, $symlinks) = @_;\n \n \tmy $rc;\n \tmy $repo = Git->repository();\n \n \tmy $workdir = find_worktree($repo);\n-\tmy ($a, $b, @working_tree) = setup_dir_diff($repo, $workdir);\n+\tmy ($a, $b, @worktree) = setup_dir_diff($repo, $workdir, $symlinks);\n \tif (defined($extcmd)) {\n \t\t$rc = system($extcmd, $a, $b);\n \t} else {\n@@ -357,13 +366,27 @@ sub dir_diff\n \n \t# If the diff including working copy files and those\n \t# files were modified during the diff, then the changes\n-\t# should be copied back to the working tree\n-\tfor my $file (@working_tree) {\n-\t\tif (-e \"$b/$file\" && compare(\"$b/$file\", \"$workdir/$file\")) {\n+\t# should be copied back to the working tree.\n+\t# Do not copy back files when symlinks are used and the\n+\t# external tool did not replace the original link with a file.\n+\tfor my $file (@worktree) {\n+\t\tnext if $symlinks && -l \"$b/$file\";\n+\t\tnext if ! -f \"$b/$file\";\n+\n+\t\tmy $diff = compare(\"$b/$file\", \"$workdir/$file\");\n+\t\tif ($diff == 0) {\n+\t\t\tnext;\n+\t\t} elsif ($diff == -1 ) {\n+\t\t\tmy $errmsg = \"warning: could not compare \";\n+\t\t\t$errmsg += \"'$b/$file' with '$workdir/$file'\\n\";\n+\t\t\twarn $errmsg;\n+\t\t} elsif ($diff == 1) {\n \t\t\tcopy(\"$b/$file\", \"$workdir/$file\") or die $!;\n-\t\t\tchmod(stat(\"$b/$file\")->mode, \"$workdir/$file\") or die $!;\n+\t\t\tmy $mode = stat(\"$b/$file\")->mode;\n+\t\t\tchmod($mode, \"$workdir/$file\") or die $!;\n \t\t}\n \t}\n+\texit(0);\n }\n \n sub file_diff\n-- \n1.7.12.rc0.15.g8157c39\n"}]}