+ }
+
+ # If $GIT_DIR is not set prior to calling 'git update-index' and
+ # 'git checkout-index', then those commands will fail if difftool
+ # is called from a directory other than the repo root.
+ my $must_unset_git_dir = 0;
+ if (not defined($ENV{GIT_DIR})) {
+ $must_unset_git_dir = 1;
+ $ENV{GIT_DIR} = $repo_path;
+ }
+
+ # Populate the left and right directories based on each index file
+ my ($inpipe, $ctx);
+ $ENV{GIT_INDEX_FILE} = "$tmpdir/lindex";
+ ($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/");
+ exit($rc | ($rc >> 8)) if ($rc != 0);
+
+ $ENV{GIT_INDEX_FILE} = "$tmpdir/rindex";
+ ($inpipe, $ctx) = $repo->command_input_pipe(qw/update-index -z --index-info/);
+ print($inpipe $rindex);
+ $repo->command_close_pipe($inpipe, $ctx);
+ $rc = system('git', 'checkout-index', '--all', "--prefix=$rdir/");
+ exit($rc | ($rc >> 8)) if ($rc != 0);
+
+ # If $GIT_DIR was explicitly set just for the update/checkout
+ # commands, then it should be unset before continuing.
+ delete($ENV{GIT_DIR}) if ($must_unset_git_dir);
+ delete($ENV{GIT_INDEX_FILE});
+
+ # Changes in the working tree need special treatment since they are
+ # not part of the index
+ for my $file (@working_tree) {
+ my $dir = dirname($file);
+ 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 $!;
+ }
+
+ # Changes to submodules require special treatment. This loop writes a
+ # temporary file to both the left and right directories to show the
+ # change in the recorded SHA1 for the submodule.
+ for my $path (keys %submodule) {
+ if (defined($submodule{$path}{left})) {
+ write_to_file("$ldir/$path", "Subproject commit $submodule{$path}{left}");
+ }
+ if (defined($submodule{$path}{right})) {
+ write_to_file("$rdir/$path", "Subproject commit $submodule{$path}{right}");
+ }
+ }
+
+ # Symbolic links require special treatment. The standard "git diff"
+ # shows only the link itself, not the contents of the link target.
+ # This loop replicates that behavior.
+ for my $path (keys %symlink) {
+ if (defined($symlink{$path}{left})) {
+ write_to_file("$ldir/$path", $symlink{$path}{left});
+ }
+ if (defined($symlink{$path}{right})) {
+ write_to_file("$rdir/$path", $symlink{$path}{right});