Skip to content

Commit 5a5d3f1

Browse files
committed
Merge branch 'jk/difftool-in-subdir'
Even though an fix was attempted in Git 2.9.3 days, but running "git difftool --dir-diff" from a subdirectory never worked. This has been fixed. * jk/difftool-in-subdir: difftool: rename variables for consistency difftool: chdir as early as possible difftool: sanitize $workdir as early as possible difftool: fix dir-diff index creation when in a subdirectory
2 parents f723df5 + ce69269 commit 5a5d3f1

File tree

1 file changed

+29
-24
lines changed

1 file changed

+29
-24
lines changed

git-difftool.perl

Lines changed: 29 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -60,14 +60,14 @@ sub exit_cleanup
6060

6161
sub use_wt_file
6262
{
63-
my ($workdir, $file, $sha1) = @_;
63+
my ($file, $sha1) = @_;
6464
my $null_sha1 = '0' x 40;
6565

66-
if (-l "$workdir/$file" || ! -e _) {
66+
if (-l $file || ! -e _) {
6767
return (0, $null_sha1);
6868
}
6969

70-
my $wt_sha1 = Git::command_oneline('hash-object', "$workdir/$file");
70+
my $wt_sha1 = Git::command_oneline('hash-object', $file);
7171
my $use = ($sha1 eq $null_sha1) || ($sha1 eq $wt_sha1);
7272
return ($use, $wt_sha1);
7373
}
@@ -101,11 +101,17 @@ sub changed_files
101101

102102
sub setup_dir_diff
103103
{
104-
my ($workdir, $symlinks) = @_;
104+
my ($worktree, $symlinks) = @_;
105105
my @gitargs = ('diff', '--raw', '--no-abbrev', '-z', @ARGV);
106106
my $diffrtn = Git::command_oneline(@gitargs);
107107
exit(0) unless defined($diffrtn);
108108

109+
# Go to the root of the worktree now that we've captured the list of
110+
# changed files. The paths returned by diff --raw are relative to the
111+
# top-level of the repository, but we defer changing directories so
112+
# that @ARGV can perform pathspec limiting in the current directory.
113+
chdir($worktree);
114+
109115
# Build index info for left and right sides of the diff
110116
my $submodule_mode = '160000';
111117
my $symlink_mode = '120000';
@@ -116,7 +122,7 @@ sub setup_dir_diff
116122
my $wtindex = '';
117123
my %submodule;
118124
my %symlink;
119-
my @working_tree = ();
125+
my @files = ();
120126
my %working_tree_dups = ();
121127
my @rawdiff = split('\0', $diffrtn);
122128

@@ -168,14 +174,14 @@ sub setup_dir_diff
168174
}
169175

170176
if ($rmode ne $null_mode) {
171-
# Avoid duplicate working_tree entries
177+
# Avoid duplicate entries
172178
if ($working_tree_dups{$dst_path}++) {
173179
next;
174180
}
175181
my ($use, $wt_sha1) =
176-
use_wt_file($workdir, $dst_path, $rsha1);
182+
use_wt_file($dst_path, $rsha1);
177183
if ($use) {
178-
push @working_tree, $dst_path;
184+
push @files, $dst_path;
179185
$wtindex .= "$rmode $wt_sha1\t$dst_path\0";
180186
} else {
181187
$rindex .= "$rmode $rsha1\t$dst_path\0";
@@ -185,7 +191,7 @@ sub setup_dir_diff
185191

186192
# Go to the root of the worktree so that the left index files
187193
# are properly setup -- the index is toplevel-relative.
188-
chdir($workdir);
194+
chdir($worktree);
189195

190196
# Setup temp directories
191197
my $tmpdir = tempdir('git-difftool.XXXXX', CLEANUP => 0, TMPDIR => 1);
@@ -225,23 +231,21 @@ sub setup_dir_diff
225231
delete($ENV{GIT_INDEX_FILE});
226232

227233
# Changes in the working tree need special treatment since they are
228-
# not part of the index. Remove any trailing slash from $workdir
229-
# before starting to avoid double slashes in symlink targets.
230-
$workdir =~ s|/$||;
231-
for my $file (@working_tree) {
234+
# not part of the index.
235+
for my $file (@files) {
232236
my $dir = dirname($file);
233237
unless (-d "$rdir/$dir") {
234238
mkpath("$rdir/$dir") or
235239
exit_cleanup($tmpdir, 1);
236240
}
237241
if ($symlinks) {
238-
symlink("$workdir/$file", "$rdir/$file") or
242+
symlink("$worktree/$file", "$rdir/$file") or
239243
exit_cleanup($tmpdir, 1);
240244
} else {
241-
copy("$workdir/$file", "$rdir/$file") or
245+
copy($file, "$rdir/$file") or
242246
exit_cleanup($tmpdir, 1);
243247

244-
my $mode = stat("$workdir/$file")->mode;
248+
my $mode = stat($file)->mode;
245249
chmod($mode, "$rdir/$file") or
246250
exit_cleanup($tmpdir, 1);
247251
}
@@ -279,7 +283,7 @@ sub setup_dir_diff
279283
exit_cleanup($tmpdir, 1) if not $ok;
280284
}
281285

282-
return ($ldir, $rdir, $tmpdir, @working_tree);
286+
return ($ldir, $rdir, $tmpdir, @files);
283287
}
284288

285289
sub write_to_file
@@ -389,8 +393,9 @@ sub dir_diff
389393
my $error = 0;
390394
my $repo = Git->repository();
391395
my $repo_path = $repo->repo_path();
392-
my $workdir = $repo->wc_path();
393-
my ($a, $b, $tmpdir, @worktree) = setup_dir_diff($workdir, $symlinks);
396+
my $worktree = $repo->wc_path();
397+
$worktree =~ s|/$||; # Avoid double slashes in symlink targets
398+
my ($a, $b, $tmpdir, @files) = setup_dir_diff($worktree, $symlinks);
394399

395400
if (defined($extcmd)) {
396401
$rc = system($extcmd, $a, $b);
@@ -411,13 +416,13 @@ sub dir_diff
411416
my %tmp_modified;
412417
my $indices_loaded = 0;
413418

414-
for my $file (@worktree) {
419+
for my $file (@files) {
415420
next if $symlinks && -l "$b/$file";
416421
next if ! -f "$b/$file";
417422

418423
if (!$indices_loaded) {
419424
%wt_modified = changed_files(
420-
$repo_path, "$tmpdir/wtindex", $workdir);
425+
$repo_path, "$tmpdir/wtindex", $worktree);
421426
%tmp_modified = changed_files(
422427
$repo_path, "$tmpdir/wtindex", $b);
423428
$indices_loaded = 1;
@@ -428,14 +433,14 @@ sub dir_diff
428433
"warning: Both files modified:\n" .
429434
"'%s/%s' and '%s/%s'.\n" .
430435
"warning: Working tree file has been left.\n" .
431-
"warning:\n"), $workdir, $file, $b, $file);
436+
"warning:\n"), $worktree, $file, $b, $file);
432437
$error = 1;
433438
} elsif (exists $tmp_modified{$file}) {
434439
my $mode = stat("$b/$file")->mode;
435-
copy("$b/$file", "$workdir/$file") or
440+
copy("$b/$file", $file) or
436441
exit_cleanup($tmpdir, 1);
437442

438-
chmod($mode, "$workdir/$file") or
443+
chmod($mode, $file) or
439444
exit_cleanup($tmpdir, 1);
440445
}
441446
}

0 commit comments

Comments
 (0)