Merge branch 'jk/difftool-in-subdir' into maint
authorJunio C Hamano <gitster@pobox.com>
Tue, 17 Jan 2017 23:11:08 +0000 (15:11 -0800)
committerJunio C Hamano <gitster@pobox.com>
Tue, 17 Jan 2017 23:14:40 +0000 (15:14 -0800)
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

1  2 
git-difftool.perl
diff --combined git-difftool.perl
index 959822d5f31f60c3b3366292c973e26f0948c45a,4e4f5d8138a68e52e5ec0b787c1d7a09ba3e6658..e26294feab988d1bfc15d10acbe2774b29b5ec6f
@@@ -59,14 -59,14 +59,14 @@@ sub exit_cleanu
  
  sub use_wt_file
  {
-       my ($workdir, $file, $sha1) = @_;
+       my ($file, $sha1) = @_;
        my $null_sha1 = '0' x 40;
  
-       if (-l "$workdir/$file" || ! -e _) {
+       if (-l $file || ! -e _) {
                return (0, $null_sha1);
        }
  
-       my $wt_sha1 = Git::command_oneline('hash-object', "$workdir/$file");
+       my $wt_sha1 = Git::command_oneline('hash-object', $file);
        my $use = ($sha1 eq $null_sha1) || ($sha1 eq $wt_sha1);
        return ($use, $wt_sha1);
  }
@@@ -100,11 -100,17 +100,17 @@@ sub changed_file
  
  sub setup_dir_diff
  {
-       my ($workdir, $symlinks) = @_;
+       my ($worktree, $symlinks) = @_;
        my @gitargs = ('diff', '--raw', '--no-abbrev', '-z', @ARGV);
        my $diffrtn = Git::command_oneline(@gitargs);
        exit(0) unless defined($diffrtn);
  
+       # Go to the root of the worktree now that we've captured the list of
+       # changed files.  The paths returned by diff --raw are relative to the
+       # top-level of the repository, but we defer changing directories so
+       # that @ARGV can perform pathspec limiting in the current directory.
+       chdir($worktree);
        # Build index info for left and right sides of the diff
        my $submodule_mode = '160000';
        my $symlink_mode = '120000';
        my $wtindex = '';
        my %submodule;
        my %symlink;
-       my @working_tree = ();
+       my @files = ();
        my %working_tree_dups = ();
        my @rawdiff = split('\0', $diffrtn);
  
@@@ -167,14 -173,14 +173,14 @@@ EO
                }
  
                if ($rmode ne $null_mode) {
-                       # Avoid duplicate working_tree entries
+                       # Avoid duplicate entries
                        if ($working_tree_dups{$dst_path}++) {
                                next;
                        }
                        my ($use, $wt_sha1) =
-                               use_wt_file($workdir, $dst_path, $rsha1);
+                               use_wt_file($dst_path, $rsha1);
                        if ($use) {
-                               push @working_tree, $dst_path;
+                               push @files, $dst_path;
                                $wtindex .= "$rmode $wt_sha1\t$dst_path\0";
                        } else {
                                $rindex .= "$rmode $rsha1\t$dst_path\0";
                }
        }
  
-       chdir($workdir);
 +      # Go to the root of the worktree so that the left index files
 +      # are properly setup -- the index is toplevel-relative.
++      chdir($worktree);
 +
        # Setup temp directories
        my $tmpdir = tempdir('git-difftool.XXXXX', CLEANUP => 0, TMPDIR => 1);
        my $ldir = "$tmpdir/left";
        delete($ENV{GIT_INDEX_FILE});
  
        # Changes in the working tree need special treatment since they are
-       # not part of the index. Remove any trailing slash from $workdir
-       # before starting to avoid double slashes in symlink targets.
-       $workdir =~ s|/$||;
-       for my $file (@working_tree) {
+       # not part of the index.
+       for my $file (@files) {
                my $dir = dirname($file);
                unless (-d "$rdir/$dir") {
                        mkpath("$rdir/$dir") or
                        exit_cleanup($tmpdir, 1);
                }
                if ($symlinks) {
-                       symlink("$workdir/$file", "$rdir/$file") or
+                       symlink("$worktree/$file", "$rdir/$file") or
                        exit_cleanup($tmpdir, 1);
                } else {
-                       copy("$workdir/$file", "$rdir/$file") or
+                       copy($file, "$rdir/$file") or
                        exit_cleanup($tmpdir, 1);
  
-                       my $mode = stat("$workdir/$file")->mode;
+                       my $mode = stat($file)->mode;
                        chmod($mode, "$rdir/$file") or
                        exit_cleanup($tmpdir, 1);
                }
                exit_cleanup($tmpdir, 1) if not $ok;
        }
  
-       return ($ldir, $rdir, $tmpdir, @working_tree);
+       return ($ldir, $rdir, $tmpdir, @files);
  }
  
  sub write_to_file
@@@ -388,8 -388,9 +392,9 @@@ sub dir_dif
        my $error = 0;
        my $repo = Git->repository();
        my $repo_path = $repo->repo_path();
-       my $workdir = $repo->wc_path();
-       my ($a, $b, $tmpdir, @worktree) = setup_dir_diff($workdir, $symlinks);
+       my $worktree = $repo->wc_path();
+       $worktree =~ s|/$||; # Avoid double slashes in symlink targets
+       my ($a, $b, $tmpdir, @files) = setup_dir_diff($worktree, $symlinks);
  
        if (defined($extcmd)) {
                $rc = system($extcmd, $a, $b);
        my %tmp_modified;
        my $indices_loaded = 0;
  
-       for my $file (@worktree) {
+       for my $file (@files) {
                next if $symlinks && -l "$b/$file";
                next if ! -f "$b/$file";
  
                if (!$indices_loaded) {
                        %wt_modified = changed_files(
-                               $repo_path, "$tmpdir/wtindex", $workdir);
+                               $repo_path, "$tmpdir/wtindex", $worktree);
                        %tmp_modified = changed_files(
                                $repo_path, "$tmpdir/wtindex", $b);
                        $indices_loaded = 1;
  
                if (exists $wt_modified{$file} and exists $tmp_modified{$file}) {
                        my $errmsg = "warning: Both files modified: ";
-                       $errmsg .= "'$workdir/$file' and '$b/$file'.\n";
+                       $errmsg .= "'$worktree/$file' and '$b/$file'.\n";
                        $errmsg .= "warning: Working tree file has been left.\n";
                        $errmsg .= "warning:\n";
                        warn $errmsg;
                        $error = 1;
                } elsif (exists $tmp_modified{$file}) {
                        my $mode = stat("$b/$file")->mode;
-                       copy("$b/$file", "$workdir/$file") or
+                       copy("$b/$file", $file) or
                        exit_cleanup($tmpdir, 1);
  
-                       chmod($mode, "$workdir/$file") or
+                       chmod($mode, $file) or
                        exit_cleanup($tmpdir, 1);
                }
        }