@@ -59,14 +59,14 @@ sub exit_cleanup
5959
6060sub use_wt_file
6161{
62- my ($workdir , $ file , $sha1 ) = @_ ;
62+ my ($file , $sha1 ) = @_ ;
6363 my $null_sha1 = ' 0' x 40 ;
6464
65- if (-l " $workdir / $ file" || ! -e _) {
65+ if (-l $ file || ! -e _) {
6666 return (0, $null_sha1 );
6767 }
6868
69- my $wt_sha1 = Git::command_oneline(' hash-object' , " $workdir / $ file" );
69+ my $wt_sha1 = Git::command_oneline(' hash-object' , $ file );
7070 my $use = ($sha1 eq $null_sha1 ) || ($sha1 eq $wt_sha1 );
7171 return ($use , $wt_sha1 );
7272}
@@ -100,11 +100,17 @@ sub changed_files
100100
101101sub setup_dir_diff
102102{
103- my ($workdir , $symlinks ) = @_ ;
103+ my ($worktree , $symlinks ) = @_ ;
104104 my @gitargs = (' diff' , ' --raw' , ' --no-abbrev' , ' -z' , @ARGV );
105105 my $diffrtn = Git::command_oneline(@gitargs );
106106 exit (0) unless defined ($diffrtn );
107107
108+ # Go to the root of the worktree now that we've captured the list of
109+ # changed files. The paths returned by diff --raw are relative to the
110+ # top-level of the repository, but we defer changing directories so
111+ # that @ARGV can perform pathspec limiting in the current directory.
112+ chdir ($worktree );
113+
108114 # Build index info for left and right sides of the diff
109115 my $submodule_mode = ' 160000' ;
110116 my $symlink_mode = ' 120000' ;
@@ -115,7 +121,7 @@ sub setup_dir_diff
115121 my $wtindex = ' ' ;
116122 my %submodule ;
117123 my %symlink ;
118- my @working_tree = ();
124+ my @files = ();
119125 my %working_tree_dups = ();
120126 my @rawdiff = split (' \0' , $diffrtn );
121127
@@ -167,14 +173,14 @@ sub setup_dir_diff
167173 }
168174
169175 if ($rmode ne $null_mode ) {
170- # Avoid duplicate working_tree entries
176+ # Avoid duplicate entries
171177 if ($working_tree_dups {$dst_path }++) {
172178 next ;
173179 }
174180 my ($use , $wt_sha1 ) =
175- use_wt_file($workdir , $ dst_path , $rsha1 );
181+ use_wt_file($dst_path , $rsha1 );
176182 if ($use ) {
177- push @working_tree , $dst_path ;
183+ push @files , $dst_path ;
178184 $wtindex .= " $rmode $wt_sha1 \t $dst_path \0 " ;
179185 } else {
180186 $rindex .= " $rmode $rsha1 \t $dst_path \0 " ;
@@ -184,7 +190,7 @@ sub setup_dir_diff
184190
185191 # Go to the root of the worktree so that the left index files
186192 # are properly setup -- the index is toplevel-relative.
187- chdir ($workdir );
193+ chdir ($worktree );
188194
189195 # Setup temp directories
190196 my $tmpdir = tempdir(' git-difftool.XXXXX' , CLEANUP => 0, TMPDIR => 1);
@@ -224,23 +230,21 @@ sub setup_dir_diff
224230 delete ($ENV {GIT_INDEX_FILE });
225231
226232 # Changes in the working tree need special treatment since they are
227- # not part of the index. Remove any trailing slash from $workdir
228- # before starting to avoid double slashes in symlink targets.
229- $workdir =~ s | /$|| ;
230- for my $file (@working_tree ) {
233+ # not part of the index.
234+ for my $file (@files ) {
231235 my $dir = dirname($file );
232236 unless (-d " $rdir /$dir " ) {
233237 mkpath(" $rdir /$dir " ) or
234238 exit_cleanup($tmpdir , 1);
235239 }
236240 if ($symlinks ) {
237- symlink (" $workdir /$file " , " $rdir /$file " ) or
241+ symlink (" $worktree /$file " , " $rdir /$file " ) or
238242 exit_cleanup($tmpdir , 1);
239243 } else {
240- copy(" $workdir / $ file" , " $rdir /$file " ) or
244+ copy($ file , " $rdir /$file " ) or
241245 exit_cleanup($tmpdir , 1);
242246
243- my $mode = stat (" $workdir / $ file" )-> mode;
247+ my $mode = stat ($ file )-> mode;
244248 chmod ($mode , " $rdir /$file " ) or
245249 exit_cleanup($tmpdir , 1);
246250 }
@@ -278,7 +282,7 @@ sub setup_dir_diff
278282 exit_cleanup($tmpdir , 1) if not $ok ;
279283 }
280284
281- return ($ldir , $rdir , $tmpdir , @working_tree );
285+ return ($ldir , $rdir , $tmpdir , @files );
282286}
283287
284288sub write_to_file
@@ -388,8 +392,9 @@ sub dir_diff
388392 my $error = 0;
389393 my $repo = Git-> repository();
390394 my $repo_path = $repo -> repo_path();
391- my $workdir = $repo -> wc_path();
392- my ($a , $b , $tmpdir , @worktree ) = setup_dir_diff($workdir , $symlinks );
395+ my $worktree = $repo -> wc_path();
396+ $worktree =~ s | /$|| ; # Avoid double slashes in symlink targets
397+ my ($a , $b , $tmpdir , @files ) = setup_dir_diff($worktree , $symlinks );
393398
394399 if (defined ($extcmd )) {
395400 $rc = system ($extcmd , $a , $b );
@@ -410,31 +415,31 @@ sub dir_diff
410415 my %tmp_modified ;
411416 my $indices_loaded = 0;
412417
413- for my $file (@worktree ) {
418+ for my $file (@files ) {
414419 next if $symlinks && -l " $b /$file " ;
415420 next if ! -f " $b /$file " ;
416421
417422 if (!$indices_loaded ) {
418423 %wt_modified = changed_files(
419- $repo_path , " $tmpdir /wtindex" , $workdir );
424+ $repo_path , " $tmpdir /wtindex" , $worktree );
420425 %tmp_modified = changed_files(
421426 $repo_path , " $tmpdir /wtindex" , $b );
422427 $indices_loaded = 1;
423428 }
424429
425430 if (exists $wt_modified {$file } and exists $tmp_modified {$file }) {
426431 my $errmsg = " warning: Both files modified: " ;
427- $errmsg .= " '$workdir /$file ' and '$b /$file '.\n " ;
432+ $errmsg .= " '$worktree /$file ' and '$b /$file '.\n " ;
428433 $errmsg .= " warning: Working tree file has been left.\n " ;
429434 $errmsg .= " warning:\n " ;
430435 warn $errmsg ;
431436 $error = 1;
432437 } elsif (exists $tmp_modified {$file }) {
433438 my $mode = stat (" $b /$file " )-> mode;
434- copy(" $b /$file " , " $workdir / $ file" ) or
439+ copy(" $b /$file " , $ file ) or
435440 exit_cleanup($tmpdir , 1);
436441
437- chmod ($mode , " $workdir / $ file" ) or
442+ chmod ($mode , $ file ) or
438443 exit_cleanup($tmpdir , 1);
439444 }
440445 }
0 commit comments