* [PATCH v4 0/5] difftool: Use symlinks in dir-diff mode
@ 2012-07-25 2:59 David Aguilar
2012-07-25 2:59 ` [PATCH v4 1/5] difftool: print_tool_help() globals David Aguilar
` (4 more replies)
0 siblings, 5 replies; 6+ messages in thread
From: David Aguilar @ 2012-07-25 2:59 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Tim Henigan, git
Teach difftool to use symlinks when diffing against the worktree.
David Aguilar (5):
difftool: print_tool_help() globals
difftool: Eliminate global variables
difftool: Move option values into a hash
difftool: Call the temp directory "git-difftool"
difftool: Use symlinks when diffing against the worktree
Documentation/git-difftool.txt | 8 ++
git-difftool.perl | 180 ++++++++++++++++++++++++++---------------
2 files changed, 124 insertions(+), 64 deletions(-)
--
1.7.12.rc0.15.g8157c39
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v4 1/5] difftool: print_tool_help() globals
2012-07-25 2:59 [PATCH v4 0/5] difftool: Use symlinks in dir-diff mode David Aguilar
@ 2012-07-25 2:59 ` David Aguilar
2012-07-25 2:59 ` [PATCH v4 2/5] difftool: Eliminate global variables David Aguilar
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: David Aguilar @ 2012-07-25 2:59 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Tim Henigan, git
Replace a global variable with a closure.
Signed-off-by: David Aguilar <davvid@gmail.com>
---
Differences from last time:
This keeps the original File::Find implementation and wraps the
global variable in a closure as the first step in the
globals-elimination cleanup.
git-difftool.perl | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/git-difftool.perl b/git-difftool.perl
index c079854..d4737e1 100755
--- a/git-difftool.perl
+++ b/git-difftool.perl
@@ -23,7 +23,6 @@ use File::Temp qw(tempdir);
use Getopt::Long qw(:config pass_through);
use Git;
-my @tools;
my @working_tree;
my $rc;
my $repo = Git->repository();
@@ -67,6 +66,7 @@ my $workdir = find_worktree();
sub filter_tool_scripts
{
+ my ($tools) = @_;
if (-d $_) {
if ($_ ne ".") {
# Ignore files in subdirectories
@@ -74,17 +74,17 @@ sub filter_tool_scripts
}
} else {
if ((-f $_) && ($_ ne "defaults")) {
- push(@tools, $_);
+ push(@$tools, $_);
}
}
}
sub print_tool_help
{
- my ($cmd, @found, @notfound);
+ my ($cmd, @found, @notfound, @tools);
my $gitpath = Git::exec_path();
- find(\&filter_tool_scripts, "$gitpath/mergetools");
+ find(sub { filter_tool_scripts(\@tools) }, "$gitpath/mergetools");
foreach my $tool (@tools) {
$cmd = "TOOL_MODE=diff";
--
1.7.12.rc0.15.g8157c39
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v4 2/5] difftool: Eliminate global variables
2012-07-25 2:59 [PATCH v4 0/5] difftool: Use symlinks in dir-diff mode David Aguilar
2012-07-25 2:59 ` [PATCH v4 1/5] difftool: print_tool_help() globals David Aguilar
@ 2012-07-25 2:59 ` David Aguilar
2012-07-25 2:59 ` [PATCH v4 3/5] difftool: Move option values into a hash David Aguilar
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: David Aguilar @ 2012-07-25 2:59 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Tim Henigan, git
Organize the script so that it has a single main() function which
calls out to dir_diff() and file_diff() functions. This eliminates
"dir-diff"-specific variables that do not need to be calculated when
performing a regular file-diff.
Signed-off-by: David Aguilar <davvid@gmail.com>
---
Same as last time, but rebased against the new 1/5
git-difftool.perl | 128 ++++++++++++++++++++++++++++++++----------------------
1 file changed, 75 insertions(+), 53 deletions(-)
diff --git a/git-difftool.perl b/git-difftool.perl
index d4737e1..fa787d6 100755
--- a/git-difftool.perl
+++ b/git-difftool.perl
@@ -23,11 +23,6 @@ use File::Temp qw(tempdir);
use Getopt::Long qw(:config pass_through);
use Git;
-my @working_tree;
-my $rc;
-my $repo = Git->repository();
-my $repo_path = $repo->repo_path();
-
sub usage
{
my $exitcode = shift;
@@ -44,6 +39,8 @@ USAGE
sub find_worktree
{
+ my ($repo) = @_;
+
# Git->repository->wc_path() does not honor changes to the working
# tree location made by $ENV{GIT_WORK_TREE} or the 'core.worktree'
# config variable.
@@ -62,8 +59,6 @@ sub find_worktree
return $worktree;
}
-my $workdir = find_worktree();
-
sub filter_tool_scripts
{
my ($tools) = @_;
@@ -112,10 +107,13 @@ sub print_tool_help
sub setup_dir_diff
{
+ my ($repo, $workdir) = @_;
+
# Run the diff; exit immediately if no diff found
# 'Repository' and 'WorkingCopy' must be explicitly set to insure that
# if $GIT_DIR and $GIT_WORK_TREE are set in ENV, they are actually used
# by Git->repository->command*.
+ my $repo_path = $repo->repo_path();
my $diffrepo = Git->repository(Repository => $repo_path, WorkingCopy => $workdir);
my $diffrtn = $diffrepo->command_oneline('diff', '--raw', '--no-abbrev', '-z', @ARGV);
exit(0) if (length($diffrtn) == 0);
@@ -136,6 +134,7 @@ sub setup_dir_diff
my $rindex = '';
my %submodule;
my %symlink;
+ my @working_tree = ();
my @rawdiff = split('\0', $diffrtn);
my $i = 0;
@@ -203,7 +202,7 @@ sub setup_dir_diff
($inpipe, $ctx) = $repo->command_input_pipe(qw/update-index -z --index-info/);
print($inpipe $lindex);
$repo->command_close_pipe($inpipe, $ctx);
- $rc = system('git', 'checkout-index', '--all', "--prefix=$ldir/");
+ my $rc = system('git', 'checkout-index', '--all', "--prefix=$ldir/");
exit($rc | ($rc >> 8)) if ($rc != 0);
$ENV{GIT_INDEX_FILE} = "$tmpdir/rindex";
@@ -253,7 +252,7 @@ sub setup_dir_diff
}
}
- return ($ldir, $rdir);
+ return ($ldir, $rdir, @working_tree);
}
sub write_to_file
@@ -276,54 +275,70 @@ sub write_to_file
close($fh);
}
-# parse command-line options. all unrecognized options and arguments
-# are passed through to the 'git diff' command.
-my ($difftool_cmd, $dirdiff, $extcmd, $gui, $help, $prompt, $tool_help);
-GetOptions('g|gui!' => \$gui,
- 'd|dir-diff' => \$dirdiff,
- 'h' => \$help,
- 'prompt!' => \$prompt,
- 'y' => sub { $prompt = 0; },
- 't|tool:s' => \$difftool_cmd,
- 'tool-help' => \$tool_help,
- 'x|extcmd:s' => \$extcmd);
-
-if (defined($help)) {
- usage(0);
-}
-if (defined($tool_help)) {
- print_tool_help();
-}
-if (defined($difftool_cmd)) {
- if (length($difftool_cmd) > 0) {
- $ENV{GIT_DIFF_TOOL} = $difftool_cmd;
- } else {
- print "No <tool> given for --tool=<tool>\n";
- usage(1);
+sub main
+{
+ # parse command-line options. all unrecognized options and arguments
+ # are passed through to the 'git diff' command.
+ my ($difftool_cmd, $dirdiff, $extcmd, $gui, $help, $prompt, $tool_help);
+ GetOptions('g|gui!' => \$gui,
+ 'd|dir-diff' => \$dirdiff,
+ 'h' => \$help,
+ 'prompt!' => \$prompt,
+ 'y' => sub { $prompt = 0; },
+ 't|tool:s' => \$difftool_cmd,
+ 'tool-help' => \$tool_help,
+ 'x|extcmd:s' => \$extcmd);
+
+ if (defined($help)) {
+ usage(0);
}
-}
-if (defined($extcmd)) {
- if (length($extcmd) > 0) {
- $ENV{GIT_DIFFTOOL_EXTCMD} = $extcmd;
- } else {
- print "No <cmd> given for --extcmd=<cmd>\n";
- usage(1);
+ if (defined($tool_help)) {
+ print_tool_help();
}
-}
-if ($gui) {
- my $guitool = '';
- $guitool = Git::config('diff.guitool');
- if (length($guitool) > 0) {
- $ENV{GIT_DIFF_TOOL} = $guitool;
+ if (defined($difftool_cmd)) {
+ if (length($difftool_cmd) > 0) {
+ $ENV{GIT_DIFF_TOOL} = $difftool_cmd;
+ } else {
+ print "No <tool> given for --tool=<tool>\n";
+ usage(1);
+ }
+ }
+ if (defined($extcmd)) {
+ if (length($extcmd) > 0) {
+ $ENV{GIT_DIFFTOOL_EXTCMD} = $extcmd;
+ } else {
+ print "No <cmd> given for --extcmd=<cmd>\n";
+ usage(1);
+ }
+ }
+ if ($gui) {
+ my $guitool = '';
+ $guitool = Git::config('diff.guitool');
+ if (length($guitool) > 0) {
+ $ENV{GIT_DIFF_TOOL} = $guitool;
+ }
+ }
+
+ # In directory diff mode, 'git-difftool--helper' is called once
+ # to compare the a/b directories. In file diff mode, 'git diff'
+ # will invoke a separate instance of 'git-difftool--helper' for
+ # each file that changed.
+ if (defined($dirdiff)) {
+ dir_diff($extcmd);
+ } else {
+ file_diff($prompt);
}
}
-# In directory diff mode, 'git-difftool--helper' is called once
-# to compare the a/b directories. In file diff mode, 'git diff'
-# will invoke a separate instance of 'git-difftool--helper' for
-# each file that changed.
-if (defined($dirdiff)) {
- my ($a, $b) = setup_dir_diff();
+sub dir_diff
+{
+ my ($extcmd) = @_;
+
+ my $rc;
+ my $repo = Git->repository();
+
+ my $workdir = find_worktree($repo);
+ my ($a, $b, @working_tree) = setup_dir_diff($repo, $workdir);
if (defined($extcmd)) {
$rc = system($extcmd, $a, $b);
} else {
@@ -342,7 +357,12 @@ if (defined($dirdiff)) {
chmod(stat("$b/$file")->mode, "$workdir/$file") or die $!;
}
}
-} else {
+}
+
+sub file_diff
+{
+ my ($prompt) = @_;
+
if (defined($prompt)) {
if ($prompt) {
$ENV{GIT_DIFFTOOL_PROMPT} = 'true';
@@ -362,3 +382,5 @@ if (defined($dirdiff)) {
my $rc = system('git', 'diff', @ARGV);
exit($rc | ($rc >> 8));
}
+
+main();
--
1.7.12.rc0.15.g8157c39
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v4 3/5] difftool: Move option values into a hash
2012-07-25 2:59 [PATCH v4 0/5] difftool: Use symlinks in dir-diff mode David Aguilar
2012-07-25 2:59 ` [PATCH v4 1/5] difftool: print_tool_help() globals David Aguilar
2012-07-25 2:59 ` [PATCH v4 2/5] difftool: Eliminate global variables David Aguilar
@ 2012-07-25 2:59 ` David Aguilar
2012-07-25 2:59 ` [PATCH v4 4/5] difftool: Call the temp directory "git-difftool" David Aguilar
2012-07-25 2:59 ` [PATCH v4 5/5] difftool: Use symlinks when diffing against the worktree David Aguilar
4 siblings, 0 replies; 6+ messages in thread
From: David Aguilar @ 2012-07-25 2:59 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Tim Henigan, git
Shorten the "my" declaration for all of the option-specific variables
by wrapping all of them in a hash. This also gives us a place to
specify default values, should we need them.
Signed-off-by: David Aguilar <davvid@gmail.com>
---
Same as last time, rebased
git-difftool.perl | 55 +++++++++++++++++++++++++++++++------------------------
1 file changed, 31 insertions(+), 24 deletions(-)
diff --git a/git-difftool.perl b/git-difftool.perl
index fa787d6..685887d 100755
--- a/git-difftool.perl
+++ b/git-difftool.perl
@@ -279,41 +279,48 @@ sub main
{
# parse command-line options. all unrecognized options and arguments
# are passed through to the 'git diff' command.
- my ($difftool_cmd, $dirdiff, $extcmd, $gui, $help, $prompt, $tool_help);
- GetOptions('g|gui!' => \$gui,
- 'd|dir-diff' => \$dirdiff,
- 'h' => \$help,
- 'prompt!' => \$prompt,
- 'y' => sub { $prompt = 0; },
- 't|tool:s' => \$difftool_cmd,
- 'tool-help' => \$tool_help,
- 'x|extcmd:s' => \$extcmd);
-
- if (defined($help)) {
+ my %opts = (
+ difftool_cmd => undef,
+ dirdiff => undef,
+ extcmd => undef,
+ gui => undef,
+ help => undef,
+ prompt => undef,
+ tool_help => undef,
+ );
+ GetOptions('g|gui!' => \$opts{gui},
+ 'd|dir-diff' => \$opts{dirdiff},
+ 'h' => \$opts{help},
+ 'prompt!' => \$opts{prompt},
+ 'y' => sub { $opts{prompt} = 0; },
+ 't|tool:s' => \$opts{difftool_cmd},
+ 'tool-help' => \$opts{tool_help},
+ 'x|extcmd:s' => \$opts{extcmd});
+
+ if (defined($opts{help})) {
usage(0);
}
- if (defined($tool_help)) {
+ if (defined($opts{tool_help})) {
print_tool_help();
}
- if (defined($difftool_cmd)) {
- if (length($difftool_cmd) > 0) {
- $ENV{GIT_DIFF_TOOL} = $difftool_cmd;
+ if (defined($opts{difftool_cmd})) {
+ if (length($opts{difftool_cmd}) > 0) {
+ $ENV{GIT_DIFF_TOOL} = $opts{difftool_cmd};
} else {
print "No <tool> given for --tool=<tool>\n";
usage(1);
}
}
- if (defined($extcmd)) {
- if (length($extcmd) > 0) {
- $ENV{GIT_DIFFTOOL_EXTCMD} = $extcmd;
+ if (defined($opts{extcmd})) {
+ if (length($opts{extcmd}) > 0) {
+ $ENV{GIT_DIFFTOOL_EXTCMD} = $opts{extcmd};
} else {
print "No <cmd> given for --extcmd=<cmd>\n";
usage(1);
}
}
- if ($gui) {
- my $guitool = '';
- $guitool = Git::config('diff.guitool');
+ if ($opts{gui}) {
+ my $guitool = Git::config('diff.guitool');
if (length($guitool) > 0) {
$ENV{GIT_DIFF_TOOL} = $guitool;
}
@@ -323,10 +330,10 @@ sub main
# to compare the a/b directories. In file diff mode, 'git diff'
# will invoke a separate instance of 'git-difftool--helper' for
# each file that changed.
- if (defined($dirdiff)) {
- dir_diff($extcmd);
+ if (defined($opts{dirdiff})) {
+ dir_diff($opts{extcmd});
} else {
- file_diff($prompt);
+ file_diff($opts{prompt});
}
}
--
1.7.12.rc0.15.g8157c39
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v4 4/5] difftool: Call the temp directory "git-difftool"
2012-07-25 2:59 [PATCH v4 0/5] difftool: Use symlinks in dir-diff mode David Aguilar
` (2 preceding siblings ...)
2012-07-25 2:59 ` [PATCH v4 3/5] difftool: Move option values into a hash David Aguilar
@ 2012-07-25 2:59 ` David Aguilar
2012-07-25 2:59 ` [PATCH v4 5/5] difftool: Use symlinks when diffing against the worktree David Aguilar
4 siblings, 0 replies; 6+ messages in thread
From: David Aguilar @ 2012-07-25 2:59 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Tim Henigan, git
The "diffall" name was left over from when this functionality was part of
the "git-diffall" script in contrib/. Make the naming consistent.
Signed-off-by: David Aguilar <davvid@gmail.com>
---
Same as last time, rebased
git-difftool.perl | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/git-difftool.perl b/git-difftool.perl
index 685887d..b4f2fc6 100755
--- a/git-difftool.perl
+++ b/git-difftool.perl
@@ -119,7 +119,7 @@ sub setup_dir_diff
exit(0) if (length($diffrtn) == 0);
# Setup temp directories
- my $tmpdir = tempdir('git-diffall.XXXXX', CLEANUP => 1, TMPDIR => 1);
+ my $tmpdir = tempdir('git-difftool.XXXXX', CLEANUP => 1, TMPDIR => 1);
my $ldir = "$tmpdir/left";
my $rdir = "$tmpdir/right";
mkpath($ldir) or die $!;
--
1.7.12.rc0.15.g8157c39
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v4 5/5] difftool: Use symlinks when diffing against the worktree
2012-07-25 2:59 [PATCH v4 0/5] difftool: Use symlinks in dir-diff mode David Aguilar
` (3 preceding siblings ...)
2012-07-25 2:59 ` [PATCH v4 4/5] difftool: Call the temp directory "git-difftool" David Aguilar
@ 2012-07-25 2:59 ` David Aguilar
4 siblings, 0 replies; 6+ messages in thread
From: David Aguilar @ 2012-07-25 2:59 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Tim Henigan, git
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 safer since we avoid needing to copy temporary
files into the worktree.
The original behavior is available as --no-symlinks.
Signed-off-by: David Aguilar <davvid@gmail.com>
---
Differences:
This version checks for compare() returning -1 and emit a warning.
Documentation/git-difftool.txt | 8 ++++++++
git-difftool.perl | 43 ++++++++++++++++++++++++++++++++----------
2 files changed, 41 insertions(+), 10 deletions(-)
diff --git a/Documentation/git-difftool.txt b/Documentation/git-difftool.txt
index 31fc2e3..313d54e 100644
--- a/Documentation/git-difftool.txt
+++ b/Documentation/git-difftool.txt
@@ -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
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::
Print a list of diff tools that may be used with `--tool`.
diff --git a/git-difftool.perl b/git-difftool.perl
index b4f2fc6..10d3d97 100755
--- a/git-difftool.perl
+++ b/git-difftool.perl
@@ -107,7 +107,7 @@ sub print_tool_help
sub setup_dir_diff
{
- my ($repo, $workdir) = @_;
+ my ($repo, $workdir, $symlinks) = @_;
# Run the diff; exit immediately if no diff found
# 'Repository' and 'WorkingCopy' must be explicitly set to insure that
@@ -224,8 +224,13 @@ sub setup_dir_diff
unless (-d "$rdir/$dir") {
mkpath("$rdir/$dir") or die $!;
}
- copy("$workdir/$file", "$rdir/$file") or die $!;
- chmod(stat("$workdir/$file")->mode, "$rdir/$file") or die $!;
+ if ($symlinks) {
+ 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
@@ -286,6 +291,8 @@ sub main
gui => undef,
help => undef,
prompt => undef,
+ symlinks => $^O ne 'cygwin' &&
+ $^O ne 'MSWin32' && $^O ne 'msys',
tool_help => undef,
);
GetOptions('g|gui!' => \$opts{gui},
@@ -293,6 +300,8 @@ sub main
'h' => \$opts{help},
'prompt!' => \$opts{prompt},
'y' => sub { $opts{prompt} = 0; },
+ 'symlinks' => \$opts{symlinks},
+ 'no-symlinks' => sub { $opts{symlinks} = 0; },
't|tool:s' => \$opts{difftool_cmd},
'tool-help' => \$opts{tool_help},
'x|extcmd:s' => \$opts{extcmd});
@@ -331,7 +340,7 @@ sub main
# will invoke a separate instance of 'git-difftool--helper' for
# each file that changed.
if (defined($opts{dirdiff})) {
- dir_diff($opts{extcmd});
+ dir_diff($opts{extcmd}, $opts{symlinks});
} else {
file_diff($opts{prompt});
}
@@ -339,13 +348,13 @@ sub main
sub dir_diff
{
- my ($extcmd) = @_;
+ my ($extcmd, $symlinks) = @_;
my $rc;
my $repo = Git->repository();
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)) {
$rc = system($extcmd, $a, $b);
} else {
@@ -357,13 +366,27 @@ sub dir_diff
# If the diff including working copy files and those
# files were modified during the diff, then the changes
- # should be copied back to the working tree
- for my $file (@working_tree) {
- if (-e "$b/$file" && compare("$b/$file", "$workdir/$file")) {
+ # should be copied back to the working tree.
+ # Do not copy back files when symlinks are used and the
+ # external tool did not replace the original link with a file.
+ for my $file (@worktree) {
+ next if $symlinks && -l "$b/$file";
+ next if ! -f "$b/$file";
+
+ my $diff = compare("$b/$file", "$workdir/$file");
+ if ($diff == 0) {
+ next;
+ } elsif ($diff == -1 ) {
+ my $errmsg = "warning: could not compare ";
+ $errmsg += "'$b/$file' with '$workdir/$file'\n";
+ warn $errmsg;
+ } elsif ($diff == 1) {
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
--
1.7.12.rc0.15.g8157c39
^ permalink raw reply related [flat|nested] 6+ messages in thread
end of thread, other threads:[~2012-07-25 2:59 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-07-25 2:59 [PATCH v4 0/5] difftool: Use symlinks in dir-diff mode David Aguilar
2012-07-25 2:59 ` [PATCH v4 1/5] difftool: print_tool_help() globals David Aguilar
2012-07-25 2:59 ` [PATCH v4 2/5] difftool: Eliminate global variables David Aguilar
2012-07-25 2:59 ` [PATCH v4 3/5] difftool: Move option values into a hash David Aguilar
2012-07-25 2:59 ` [PATCH v4 4/5] difftool: Call the temp directory "git-difftool" David Aguilar
2012-07-25 2:59 ` [PATCH v4 5/5] difftool: Use symlinks when diffing against the worktree David Aguilar
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).