Skip to content

Commit 9b601ea

Browse files
committed
Merge branch 'jk/difftool-in-subdir' into maint
"git difftool <paths>..." started in a subdirectory failed to interpret the paths relative to that directory, which has been fixed. * jk/difftool-in-subdir: difftool: use Git::* functions instead of passing around state difftool: avoid $GIT_DIR and $GIT_WORK_TREE difftool: fix argument handling in subdirs
2 parents f4fd627 + 32b8c58 commit 9b601ea

File tree

2 files changed

+41
-59
lines changed

2 files changed

+41
-59
lines changed

git-difftool.perl

Lines changed: 27 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,6 @@ sub usage
3737
exit($exitcode);
3838
}
3939

40-
sub find_worktree
41-
{
42-
# Git->repository->wc_path() does not honor changes to the working
43-
# tree location made by $ENV{GIT_WORK_TREE} or the 'core.worktree'
44-
# config variable.
45-
return Git::command_oneline('rev-parse', '--show-toplevel');
46-
}
47-
4840
sub print_tool_help
4941
{
5042
# See the comment at the bottom of file_diff() for the reason behind
@@ -67,14 +59,14 @@ sub exit_cleanup
6759

6860
sub use_wt_file
6961
{
70-
my ($repo, $workdir, $file, $sha1) = @_;
62+
my ($workdir, $file, $sha1) = @_;
7163
my $null_sha1 = '0' x 40;
7264

7365
if (-l "$workdir/$file" || ! -e _) {
7466
return (0, $null_sha1);
7567
}
7668

77-
my $wt_sha1 = $repo->command_oneline('hash-object', "$workdir/$file");
69+
my $wt_sha1 = Git::command_oneline('hash-object', "$workdir/$file");
7870
my $use = ($sha1 eq $null_sha1) || ($sha1 eq $wt_sha1);
7971
return ($use, $wt_sha1);
8072
}
@@ -83,20 +75,17 @@ sub changed_files
8375
{
8476
my ($repo_path, $index, $worktree) = @_;
8577
$ENV{GIT_INDEX_FILE} = $index;
86-
$ENV{GIT_WORK_TREE} = $worktree;
87-
my $must_unset_git_dir = 0;
88-
if (not defined($ENV{GIT_DIR})) {
89-
$must_unset_git_dir = 1;
90-
$ENV{GIT_DIR} = $repo_path;
91-
}
9278

93-
my @refreshargs = qw/update-index --really-refresh -q --unmerged/;
94-
my @gitargs = qw/diff-files --name-only -z/;
79+
my @gitargs = ('--git-dir', $repo_path, '--work-tree', $worktree);
80+
my @refreshargs = (
81+
@gitargs, 'update-index',
82+
'--really-refresh', '-q', '--unmerged');
9583
try {
9684
Git::command_oneline(@refreshargs);
9785
} catch Git::Error::Command with {};
9886

99-
my $line = Git::command_oneline(@gitargs);
87+
my @diffargs = (@gitargs, 'diff-files', '--name-only', '-z');
88+
my $line = Git::command_oneline(@diffargs);
10089
my @files;
10190
if (defined $line) {
10291
@files = split('\0', $line);
@@ -105,26 +94,15 @@ sub changed_files
10594
}
10695

10796
delete($ENV{GIT_INDEX_FILE});
108-
delete($ENV{GIT_WORK_TREE});
109-
delete($ENV{GIT_DIR}) if ($must_unset_git_dir);
11097

11198
return map { $_ => 1 } @files;
11299
}
113100

114101
sub setup_dir_diff
115102
{
116-
my ($repo, $workdir, $symlinks) = @_;
117-
118-
# Run the diff; exit immediately if no diff found
119-
# 'Repository' and 'WorkingCopy' must be explicitly set to insure that
120-
# if $GIT_DIR and $GIT_WORK_TREE are set in ENV, they are actually used
121-
# by Git->repository->command*.
122-
my $repo_path = $repo->repo_path();
123-
my %repo_args = (Repository => $repo_path, WorkingCopy => $workdir);
124-
my $diffrepo = Git->repository(%repo_args);
125-
103+
my ($workdir, $symlinks) = @_;
126104
my @gitargs = ('diff', '--raw', '--no-abbrev', '-z', @ARGV);
127-
my $diffrtn = $diffrepo->command_oneline(@gitargs);
105+
my $diffrtn = Git::command_oneline(@gitargs);
128106
exit(0) unless defined($diffrtn);
129107

130108
# Build index info for left and right sides of the diff
@@ -176,12 +154,12 @@ sub setup_dir_diff
176154

177155
if ($lmode eq $symlink_mode) {
178156
$symlink{$src_path}{left} =
179-
$diffrepo->command_oneline('show', "$lsha1");
157+
Git::command_oneline('show', $lsha1);
180158
}
181159

182160
if ($rmode eq $symlink_mode) {
183161
$symlink{$dst_path}{right} =
184-
$diffrepo->command_oneline('show', "$rsha1");
162+
Git::command_oneline('show', $rsha1);
185163
}
186164

187165
if ($lmode ne $null_mode and $status !~ /^C/) {
@@ -193,8 +171,8 @@ sub setup_dir_diff
193171
if ($working_tree_dups{$dst_path}++) {
194172
next;
195173
}
196-
my ($use, $wt_sha1) = use_wt_file($repo, $workdir,
197-
$dst_path, $rsha1);
174+
my ($use, $wt_sha1) =
175+
use_wt_file($workdir, $dst_path, $rsha1);
198176
if ($use) {
199177
push @working_tree, $dst_path;
200178
$wtindex .= "$rmode $wt_sha1\t$dst_path\0";
@@ -211,44 +189,34 @@ sub setup_dir_diff
211189
mkpath($ldir) or exit_cleanup($tmpdir, 1);
212190
mkpath($rdir) or exit_cleanup($tmpdir, 1);
213191

214-
# If $GIT_DIR is not set prior to calling 'git update-index' and
215-
# 'git checkout-index', then those commands will fail if difftool
216-
# is called from a directory other than the repo root.
217-
my $must_unset_git_dir = 0;
218-
if (not defined($ENV{GIT_DIR})) {
219-
$must_unset_git_dir = 1;
220-
$ENV{GIT_DIR} = $repo_path;
221-
}
222-
223192
# Populate the left and right directories based on each index file
224193
my ($inpipe, $ctx);
225194
$ENV{GIT_INDEX_FILE} = "$tmpdir/lindex";
226195
($inpipe, $ctx) =
227-
$repo->command_input_pipe(qw(update-index -z --index-info));
196+
Git::command_input_pipe('update-index', '-z', '--index-info');
228197
print($inpipe $lindex);
229-
$repo->command_close_pipe($inpipe, $ctx);
198+
Git::command_close_pipe($inpipe, $ctx);
230199

231200
my $rc = system('git', 'checkout-index', '--all', "--prefix=$ldir/");
232201
exit_cleanup($tmpdir, $rc) if $rc != 0;
233202

234203
$ENV{GIT_INDEX_FILE} = "$tmpdir/rindex";
235204
($inpipe, $ctx) =
236-
$repo->command_input_pipe(qw(update-index -z --index-info));
205+
Git::command_input_pipe('update-index', '-z', '--index-info');
237206
print($inpipe $rindex);
238-
$repo->command_close_pipe($inpipe, $ctx);
207+
Git::command_close_pipe($inpipe, $ctx);
239208

240209
$rc = system('git', 'checkout-index', '--all', "--prefix=$rdir/");
241210
exit_cleanup($tmpdir, $rc) if $rc != 0;
242211

243212
$ENV{GIT_INDEX_FILE} = "$tmpdir/wtindex";
244213
($inpipe, $ctx) =
245-
$repo->command_input_pipe(qw(update-index --info-only -z --index-info));
214+
Git::command_input_pipe('update-index', '--info-only', '-z', '--index-info');
246215
print($inpipe $wtindex);
247-
$repo->command_close_pipe($inpipe, $ctx);
216+
Git::command_close_pipe($inpipe, $ctx);
248217

249218
# If $GIT_DIR was explicitly set just for the update/checkout
250219
# commands, then it should be unset before continuing.
251-
delete($ENV{GIT_DIR}) if ($must_unset_git_dir);
252220
delete($ENV{GIT_INDEX_FILE});
253221

254222
# Changes in the working tree need special treatment since they are
@@ -415,9 +383,9 @@ sub dir_diff
415383
my $rc;
416384
my $error = 0;
417385
my $repo = Git->repository();
418-
my $workdir = find_worktree();
419-
my ($a, $b, $tmpdir, @worktree) =
420-
setup_dir_diff($repo, $workdir, $symlinks);
386+
my $repo_path = $repo->repo_path();
387+
my $workdir = $repo->wc_path();
388+
my ($a, $b, $tmpdir, @worktree) = setup_dir_diff($workdir, $symlinks);
421389

422390
if (defined($extcmd)) {
423391
$rc = system($extcmd, $a, $b);
@@ -443,10 +411,10 @@ sub dir_diff
443411
next if ! -f "$b/$file";
444412

445413
if (!$indices_loaded) {
446-
%wt_modified = changed_files($repo->repo_path(),
447-
"$tmpdir/wtindex", "$workdir");
448-
%tmp_modified = changed_files($repo->repo_path(),
449-
"$tmpdir/wtindex", "$b");
414+
%wt_modified = changed_files(
415+
$repo_path, "$tmpdir/wtindex", $workdir);
416+
%tmp_modified = changed_files(
417+
$repo_path, "$tmpdir/wtindex", $b);
450418
$indices_loaded = 1;
451419
}
452420

t/t7800-difftool.sh

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,20 @@ run_dir_diff_test 'difftool --dir-diff from subdirectory' '
412412
)
413413
'
414414

415+
run_dir_diff_test 'difftool --dir-diff from subdirectory with GIT_DIR set' '
416+
(
417+
GIT_DIR=$(pwd)/.git &&
418+
export GIT_DIR &&
419+
GIT_WORK_TREE=$(pwd) &&
420+
export GIT_WORK_TREE &&
421+
cd sub &&
422+
git difftool --dir-diff $symlinks --extcmd ls \
423+
branch -- sub >output &&
424+
grep sub output &&
425+
! grep file output
426+
)
427+
'
428+
415429
run_dir_diff_test 'difftool --dir-diff when worktree file is missing' '
416430
test_when_finished git reset --hard &&
417431
rm file2 &&

0 commit comments

Comments
 (0)