summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 1c0f3d2)
raw | patch | inline | side by side (parent: 1c0f3d2)
author | David Aguilar <davvid@gmail.com> | |
Tue, 7 Apr 2009 08:21:20 +0000 (01:21 -0700) | ||
committer | Junio C Hamano <gitster@pobox.com> | |
Wed, 8 Apr 2009 05:19:56 +0000 (22:19 -0700) |
This prepares 'git-difftool' and its documentation for
mainstream use.
'git-difftool-helper' became 'git-difftool--helper'
since users should not use it directly.
'git-difftool' was added to the list of commands as
an ancillaryinterrogator.
Signed-off-by: David Aguilar <davvid@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
mainstream use.
'git-difftool-helper' became 'git-difftool--helper'
since users should not use it directly.
'git-difftool' was added to the list of commands as
an ancillaryinterrogator.
Signed-off-by: David Aguilar <davvid@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
.gitignore | patch | blob | history | |
Documentation/config.txt | patch | blob | history | |
Documentation/git-difftool.txt | [new file with mode: 0644] | patch | blob |
Makefile | patch | blob | history | |
command-list.txt | patch | blob | history | |
contrib/difftool/git-difftool | [deleted file] | patch | blob | history |
contrib/difftool/git-difftool-helper | [deleted file] | patch | blob | history |
contrib/difftool/git-difftool.txt | [deleted file] | patch | blob | history |
git-difftool--helper.sh | [new file with mode: 0755] | patch | blob |
git-difftool.perl | [new file with mode: 0755] | patch | blob |
diff --git a/.gitignore b/.gitignore
index 1c57d4c958bc5e8ff539c5f5ddb1c784d923271b..a36da9d981e4153b0cd20d0737f958b3da1f4efc 100644 (file)
--- a/.gitignore
+++ b/.gitignore
git-diff-files
git-diff-index
git-diff-tree
+git-difftool
+git-difftool--helper
git-describe
git-fast-export
git-fast-import
index 3afd124749fc6301069a0832071000a769e5053b..94ef1a62f98961eaa7028c1aa3bc95b9c48e85c9 100644 (file)
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
A boolean to inhibit the standard behavior of printing a space
before each empty output line. Defaults to false.
+diff.tool::
+ Controls which diff tool is used. `diff.tool` overrides
+ `merge.tool` when used by linkgit:git-difftool[1] and has
+ the same valid values as `merge.tool` minus "tortoisemerge"
+ and plus "kompare".
+
+difftool.<tool>.path::
+ Override the path for the given tool. This is useful in case
+ your tool is not in the PATH.
+
+difftool.<tool>.cmd::
+ Specify the command to invoke the specified diff tool.
+ The specified command is evaluated in shell with the following
+ variables available: 'LOCAL' is set to the name of the temporary
+ file containing the contents of the diff pre-image and 'REMOTE'
+ is set to the name of the temporary file containing the contents
+ of the diff post-image.
+
diff.wordRegex::
A POSIX Extended Regular Expression used to determine what is a "word"
when performing word-by-word difference calculations. Character
diff --git a/Documentation/git-difftool.txt b/Documentation/git-difftool.txt
--- /dev/null
@@ -0,0 +1,97 @@
+git-difftool(1)
+===============
+
+NAME
+----
+git-difftool - Show changes using common diff tools
+
+SYNOPSIS
+--------
+'git difftool' [--tool=<tool>] [-y|--no-prompt] [<'git diff' options>]
+
+DESCRIPTION
+-----------
+'git-difftool' is a git command that allows you to compare and edit files
+between revisions using common diff tools. 'git difftool' is a frontend
+to 'git-diff' and accepts the same options and arguments.
+
+OPTIONS
+-------
+-y::
+--no-prompt::
+ Do not prompt before launching a diff tool.
+
+-t <tool>::
+--tool=<tool>::
+ Use the diff tool specified by <tool>.
+ Valid merge tools are:
+ kdiff3, kompare, tkdiff, meld, xxdiff, emerge, vimdiff, gvimdiff,
+ ecmerge, diffuse and opendiff
++
+If a diff tool is not specified, 'git-difftool'
+will use the configuration variable `diff.tool`. If the
+configuration variable `diff.tool` is not set, 'git-difftool'
+will pick a suitable default.
++
+You can explicitly provide a full path to the tool by setting the
+configuration variable `difftool.<tool>.path`. For example, you
+can configure the absolute path to kdiff3 by setting
+`difftool.kdiff3.path`. Otherwise, 'git-difftool' assumes the
+tool is available in PATH.
++
+Instead of running one of the known diff tools,
+'git-difftool' can be customized to run an alternative program
+by specifying the command line to invoke in a configuration
+variable `difftool.<tool>.cmd`.
++
+When 'git-difftool' is invoked with this tool (either through the
+`-t` or `--tool` option or the `diff.tool` configuration variable)
+the configured command line will be invoked with the following
+variables available: `$LOCAL` is set to the name of the temporary
+file containing the contents of the diff pre-image and `$REMOTE`
+is set to the name of the temporary file containing the contents
+of the diff post-image. `$BASE` is provided for compatibility
+with custom merge tool commands and has the same value as `$LOCAL`.
+
+See linkgit:git-diff[1] for the full list of supported options.
+
+CONFIG VARIABLES
+----------------
+'git-difftool' falls back to 'git-mergetool' config variables when the
+difftool equivalents have not been defined.
+
+diff.tool::
+ The default diff tool to use.
+
+difftool.<tool>.path::
+ Override the path for the given tool. This is useful in case
+ your tool is not in the PATH.
+
+difftool.<tool>.cmd::
+ Specify the command to invoke the specified diff tool.
++
+See the `--tool=<tool>` option above for more details.
+
+SEE ALSO
+--------
+linkgit:git-diff[1]::
+ Show changes between commits, commit and working tree, etc
+
+linkgit:git-mergetool[1]::
+ Run merge conflict resolution tools to resolve merge conflicts
+
+linkgit:git-config[1]::
+ Get and set repository or global options
+
+
+AUTHOR
+------
+Written by David Aguilar <davvid@gmail.com>.
+
+Documentation
+--------------
+Documentation by David Aguilar and the git-list <git@vger.kernel.org>.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Makefile b/Makefile
index 7867eaccdb90729aef26dc9f67a45a5a74961aae..a80055f38d8d3e080fffe0164752b5819c0379fa 100644 (file)
--- a/Makefile
+++ b/Makefile
SCRIPT_SH += git-am.sh
SCRIPT_SH += git-bisect.sh
+SCRIPT_SH += git-difftool--helper.sh
SCRIPT_SH += git-filter-branch.sh
SCRIPT_SH += git-lost-found.sh
SCRIPT_SH += git-merge-octopus.sh
SCRIPT_SH += git-web--browse.sh
SCRIPT_PERL += git-add--interactive.perl
+SCRIPT_PERL += git-difftool.perl
SCRIPT_PERL += git-archimport.perl
SCRIPT_PERL += git-cvsexportcommit.perl
SCRIPT_PERL += git-cvsimport.perl
diff --git a/command-list.txt b/command-list.txt
index 3583a33ee90647d8e6ded02643eb75753760d94f..fb03a2ebb5d51f46d00fad3b3f6b1794d4fdad2b 100644 (file)
--- a/command-list.txt
+++ b/command-list.txt
git-diff-files plumbinginterrogators
git-diff-index plumbinginterrogators
git-diff-tree plumbinginterrogators
+git-difftool ancillaryinterrogators
git-fast-export ancillarymanipulators
git-fast-import ancillarymanipulators
git-fetch mainporcelain common
diff --git a/contrib/difftool/git-difftool b/contrib/difftool/git-difftool
+++ /dev/null
@@ -1,76 +0,0 @@
-#!/usr/bin/env perl
-# Copyright (c) 2009 David Aguilar
-#
-# This is a wrapper around the GIT_EXTERNAL_DIFF-compatible
-# git-difftool-helper script. This script exports
-# GIT_EXTERNAL_DIFF and GIT_PAGER for use by git, and
-# GIT_DIFFTOOL_NO_PROMPT and GIT_DIFF_TOOL for use by git-difftool-helper.
-# Any arguments that are unknown to this script are forwarded to 'git diff'.
-
-use strict;
-use warnings;
-use Cwd qw(abs_path);
-use File::Basename qw(dirname);
-
-my $DIR = abs_path(dirname($0));
-
-
-sub usage
-{
- print << 'USAGE';
-usage: git difftool [--tool=<tool>] [-y|--no-prompt] ["git diff" options]
-USAGE
- exit 1;
-}
-
-sub setup_environment
-{
- $ENV{PATH} = "$DIR:$ENV{PATH}";
- $ENV{GIT_PAGER} = '';
- $ENV{GIT_EXTERNAL_DIFF} = 'git-difftool-helper';
-}
-
-sub exe
-{
- my $exe = shift;
- if ($^O eq 'MSWin32' || $^O eq 'msys') {
- return "$exe.exe";
- }
- return $exe;
-}
-
-sub generate_command
-{
- my @command = (exe('git'), 'diff');
- my $skip_next = 0;
- my $idx = -1;
- for my $arg (@ARGV) {
- $idx++;
- if ($skip_next) {
- $skip_next = 0;
- next;
- }
- if ($arg eq '-t' || $arg eq '--tool') {
- usage() if $#ARGV <= $idx;
- $ENV{GIT_DIFF_TOOL} = $ARGV[$idx + 1];
- $skip_next = 1;
- next;
- }
- if ($arg =~ /^--tool=/) {
- $ENV{GIT_DIFF_TOOL} = substr($arg, 7);
- next;
- }
- if ($arg eq '-y' || $arg eq '--no-prompt') {
- $ENV{GIT_DIFFTOOL_NO_PROMPT} = 'true';
- next;
- }
- if ($arg eq '-h' || $arg eq '--help') {
- usage();
- }
- push @command, $arg;
- }
- return @command
-}
-
-setup_environment();
-exec(generate_command());
diff --git a/contrib/difftool/git-difftool-helper b/contrib/difftool/git-difftool-helper
+++ /dev/null
@@ -1,221 +0,0 @@
-#!/bin/sh
-# git-difftool-helper is a GIT_EXTERNAL_DIFF-compatible diff tool launcher.
-# This script is typically launched by using the 'git difftool'
-# convenience command.
-#
-# Copyright (c) 2009 David Aguilar
-
-# Set GIT_DIFFTOOL_NO_PROMPT to bypass the per-file prompt.
-should_prompt () {
- test -z "$GIT_DIFFTOOL_NO_PROMPT"
-}
-
-# This function prepares temporary files and launches the appropriate
-# merge tool.
-launch_merge_tool () {
- # Merged is the filename as it appears in the work tree
- # Local is the contents of a/filename
- # Remote is the contents of b/filename
- # Custom merge tool commands might use $BASE so we provide it
- MERGED="$1"
- LOCAL="$2"
- REMOTE="$3"
- BASE="$1"
-
- # $LOCAL and $REMOTE are temporary files so prompt
- # the user with the real $MERGED name before launching $merge_tool.
- if should_prompt; then
- printf "\nViewing: '$MERGED'\n"
- printf "Hit return to launch '%s': " "$merge_tool"
- read ans
- fi
-
- # Run the appropriate merge tool command
- case "$merge_tool" in
- kdiff3)
- basename=$(basename "$MERGED")
- "$merge_tool_path" --auto \
- --L1 "$basename (A)" \
- --L2 "$basename (B)" \
- "$LOCAL" "$REMOTE" \
- > /dev/null 2>&1
- ;;
-
- kompare)
- "$merge_tool_path" "$LOCAL" "$REMOTE"
- ;;
-
- tkdiff)
- "$merge_tool_path" "$LOCAL" "$REMOTE"
- ;;
-
- meld)
- "$merge_tool_path" "$LOCAL" "$REMOTE"
- ;;
-
- diffuse)
- "$merge_tool_path" "$LOCAL" "$REMOTE" | cat
- ;;
-
- vimdiff)
- "$merge_tool_path" -d -c "wincmd l" "$LOCAL" "$REMOTE"
- ;;
-
- gvimdiff)
- "$merge_tool_path" -d -c "wincmd l" -f "$LOCAL" "$REMOTE"
- ;;
-
- xxdiff)
- "$merge_tool_path" \
- -R 'Accel.Search: "Ctrl+F"' \
- -R 'Accel.SearchForward: "Ctrl-G"' \
- "$LOCAL" "$REMOTE"
- ;;
-
- opendiff)
- "$merge_tool_path" "$LOCAL" "$REMOTE" | cat
- ;;
-
- ecmerge)
- "$merge_tool_path" "$LOCAL" "$REMOTE" \
- --default --mode=merge2 --to="$MERGED"
- ;;
-
- emerge)
- "$merge_tool_path" -f emerge-files-command \
- "$LOCAL" "$REMOTE" "$(basename "$MERGED")"
- ;;
-
- *)
- if test -n "$merge_tool_cmd"; then
- ( eval $merge_tool_cmd )
- fi
- ;;
- esac
-}
-
-# Verifies that (difftool|mergetool).<tool>.cmd exists
-valid_custom_tool() {
- merge_tool_cmd="$(git config difftool.$1.cmd)"
- test -z "$merge_tool_cmd" &&
- merge_tool_cmd="$(git config mergetool.$1.cmd)"
- test -n "$merge_tool_cmd"
-}
-
-# Verifies that the chosen merge tool is properly setup.
-# Built-in merge tools are always valid.
-valid_tool() {
- case "$1" in
- kdiff3 | kompare | tkdiff | xxdiff | meld | opendiff | emerge | vimdiff | gvimdiff | ecmerge)
- ;; # happy
- *)
- if ! valid_custom_tool "$1"
- then
- return 1
- fi
- ;;
- esac
-}
-
-# Sets up the merge_tool_path variable.
-# This handles the difftool.<tool>.path configuration.
-# This also falls back to mergetool defaults.
-init_merge_tool_path() {
- merge_tool_path=$(git config difftool."$1".path)
- test -z "$merge_tool_path" &&
- merge_tool_path=$(git config mergetool."$1".path)
- if test -z "$merge_tool_path"; then
- case "$1" in
- vimdiff)
- merge_tool_path=vim
- ;;
- gvimdiff)
- merge_tool_path=gvim
- ;;
- emerge)
- merge_tool_path=emacs
- ;;
- *)
- merge_tool_path="$1"
- ;;
- esac
- fi
-}
-
-# Allow GIT_DIFF_TOOL and GIT_MERGE_TOOL to provide default values
-test -n "$GIT_MERGE_TOOL" && merge_tool="$GIT_MERGE_TOOL"
-test -n "$GIT_DIFF_TOOL" && merge_tool="$GIT_DIFF_TOOL"
-
-# If merge tool was not specified then use the diff.tool
-# configuration variable. If that's invalid then reset merge_tool.
-# Fallback to merge.tool.
-if test -z "$merge_tool"; then
- merge_tool=$(git config diff.tool)
- test -z "$merge_tool" &&
- merge_tool=$(git config merge.tool)
- if test -n "$merge_tool" && ! valid_tool "$merge_tool"; then
- echo >&2 "git config option diff.tool set to unknown tool: $merge_tool"
- echo >&2 "Resetting to default..."
- unset merge_tool
- fi
-fi
-
-# Try to guess an appropriate merge tool if no tool has been set.
-if test -z "$merge_tool"; then
- # We have a $DISPLAY so try some common UNIX merge tools
- if test -n "$DISPLAY"; then
- # If gnome then prefer meld, otherwise, prefer kdiff3 or kompare
- if test -n "$GNOME_DESKTOP_SESSION_ID" ; then
- merge_tool_candidates="meld kdiff3 kompare tkdiff xxdiff gvimdiff diffuse"
- else
- merge_tool_candidates="kdiff3 kompare tkdiff xxdiff meld gvimdiff diffuse"
- fi
- fi
- if echo "${VISUAL:-$EDITOR}" | grep 'emacs' > /dev/null 2>&1; then
- # $EDITOR is emacs so add emerge as a candidate
- merge_tool_candidates="$merge_tool_candidates emerge opendiff vimdiff"
- elif echo "${VISUAL:-$EDITOR}" | grep 'vim' > /dev/null 2>&1; then
- # $EDITOR is vim so add vimdiff as a candidate
- merge_tool_candidates="$merge_tool_candidates vimdiff opendiff emerge"
- else
- merge_tool_candidates="$merge_tool_candidates opendiff emerge vimdiff"
- fi
- echo "merge tool candidates: $merge_tool_candidates"
-
- # Loop over each candidate and stop when a valid merge tool is found.
- for i in $merge_tool_candidates
- do
- init_merge_tool_path $i
- if type "$merge_tool_path" > /dev/null 2>&1; then
- merge_tool=$i
- break
- fi
- done
-
- if test -z "$merge_tool" ; then
- echo "No known merge resolution program available."
- exit 1
- fi
-
-else
- # A merge tool has been set, so verify that it's valid.
- if ! valid_tool "$merge_tool"; then
- echo >&2 "Unknown merge tool $merge_tool"
- exit 1
- fi
-
- init_merge_tool_path "$merge_tool"
-
- if test -z "$merge_tool_cmd" && ! type "$merge_tool_path" > /dev/null 2>&1; then
- echo "The merge tool $merge_tool is not available as '$merge_tool_path'"
- exit 1
- fi
-fi
-
-
-# Launch the merge tool on each path provided by 'git diff'
-while test $# -gt 6
-do
- launch_merge_tool "$1" "$2" "$5"
- shift 7
-done
diff --git a/contrib/difftool/git-difftool.txt b/contrib/difftool/git-difftool.txt
+++ /dev/null
@@ -1,97 +0,0 @@
-git-difftool(1)
-===============
-
-NAME
-----
-git-difftool - Show changes using common diff tools
-
-SYNOPSIS
---------
-'git difftool' [--tool=<tool>] [-y|--no-prompt] [<'git diff' options>]
-
-DESCRIPTION
------------
-'git-difftool' is a git command that allows you to compare and edit files
-between revisions using common diff tools. 'git difftool' is a frontend
-to 'git-diff' and accepts the same options and arguments.
-
-OPTIONS
--------
--y::
---no-prompt::
- Do not prompt before launching a diff tool.
-
--t <tool>::
---tool=<tool>::
- Use the diff tool specified by <tool>.
- Valid merge tools are:
- kdiff3, kompare, tkdiff, meld, xxdiff, emerge, vimdiff, gvimdiff,
- ecmerge, diffuse and opendiff
-+
-If a diff tool is not specified, 'git-difftool'
-will use the configuration variable `diff.tool`. If the
-configuration variable `diff.tool` is not set, 'git-difftool'
-will pick a suitable default.
-+
-You can explicitly provide a full path to the tool by setting the
-configuration variable `difftool.<tool>.path`. For example, you
-can configure the absolute path to kdiff3 by setting
-`difftool.kdiff3.path`. Otherwise, 'git-difftool' assumes the
-tool is available in PATH.
-+
-Instead of running one of the known diff tools,
-'git-difftool' can be customized to run an alternative program
-by specifying the command line to invoke in a configuration
-variable `difftool.<tool>.cmd`.
-+
-When 'git-difftool' is invoked with this tool (either through the
-`-t` or `--tool` option or the `diff.tool` configuration variable)
-the configured command line will be invoked with the following
-variables available: `$LOCAL` is set to the name of the temporary
-file containing the contents of the diff pre-image and `$REMOTE`
-is set to the name of the temporary file containing the contents
-of the diff post-image. `$BASE` is provided for compatibility
-with custom merge tool commands and has the same value as `$LOCAL`.
-
-See linkgit:git-diff[1] for the full list of supported options.
-
-CONFIG VARIABLES
-----------------
-'git-difftool' falls back to 'git-mergetool' config variables when the
-difftool equivalents have not been defined.
-
-diff.tool::
- The default diff tool to use.
-
-difftool.<tool>.path::
- Override the path for the given tool. This is useful in case
- your tool is not in the PATH.
-
-difftool.<tool>.cmd::
- Specify the command to invoke the specified diff tool.
-+
-See the `--tool=<tool>` option above for more details.
-
-SEE ALSO
---------
-linkgit:git-diff[1]::
- Show changes between commits, commit and working tree, etc
-
-linkgit:git-mergetool[1]::
- Run merge conflict resolution tools to resolve merge conflicts
-
-linkgit:git-config[1]::
- Get and set repository or global options
-
-
-AUTHOR
-------
-Written by David Aguilar <davvid@gmail.com>.
-
-Documentation
---------------
-Documentation by David Aguilar and the git-list <git@vger.kernel.org>.
-
-GIT
----
-Part of the linkgit:git[1] suite
diff --git a/git-difftool--helper.sh b/git-difftool--helper.sh
--- /dev/null
+++ b/git-difftool--helper.sh
@@ -0,0 +1,221 @@
+#!/bin/sh
+# git-difftool--helper is a GIT_EXTERNAL_DIFF-compatible diff tool launcher.
+# This script is typically launched by using the 'git difftool'
+# convenience command.
+#
+# Copyright (c) 2009 David Aguilar
+
+# Set GIT_DIFFTOOL_NO_PROMPT to bypass the per-file prompt.
+should_prompt () {
+ test -z "$GIT_DIFFTOOL_NO_PROMPT"
+}
+
+# This function prepares temporary files and launches the appropriate
+# merge tool.
+launch_merge_tool () {
+ # Merged is the filename as it appears in the work tree
+ # Local is the contents of a/filename
+ # Remote is the contents of b/filename
+ # Custom merge tool commands might use $BASE so we provide it
+ MERGED="$1"
+ LOCAL="$2"
+ REMOTE="$3"
+ BASE="$1"
+
+ # $LOCAL and $REMOTE are temporary files so prompt
+ # the user with the real $MERGED name before launching $merge_tool.
+ if should_prompt; then
+ printf "\nViewing: '$MERGED'\n"
+ printf "Hit return to launch '%s': " "$merge_tool"
+ read ans
+ fi
+
+ # Run the appropriate merge tool command
+ case "$merge_tool" in
+ kdiff3)
+ basename=$(basename "$MERGED")
+ "$merge_tool_path" --auto \
+ --L1 "$basename (A)" \
+ --L2 "$basename (B)" \
+ "$LOCAL" "$REMOTE" \
+ > /dev/null 2>&1
+ ;;
+
+ kompare)
+ "$merge_tool_path" "$LOCAL" "$REMOTE"
+ ;;
+
+ tkdiff)
+ "$merge_tool_path" "$LOCAL" "$REMOTE"
+ ;;
+
+ meld)
+ "$merge_tool_path" "$LOCAL" "$REMOTE"
+ ;;
+
+ diffuse)
+ "$merge_tool_path" "$LOCAL" "$REMOTE" | cat
+ ;;
+
+ vimdiff)
+ "$merge_tool_path" -d -c "wincmd l" "$LOCAL" "$REMOTE"
+ ;;
+
+ gvimdiff)
+ "$merge_tool_path" -d -c "wincmd l" -f "$LOCAL" "$REMOTE"
+ ;;
+
+ xxdiff)
+ "$merge_tool_path" \
+ -R 'Accel.Search: "Ctrl+F"' \
+ -R 'Accel.SearchForward: "Ctrl-G"' \
+ "$LOCAL" "$REMOTE"
+ ;;
+
+ opendiff)
+ "$merge_tool_path" "$LOCAL" "$REMOTE" | cat
+ ;;
+
+ ecmerge)
+ "$merge_tool_path" "$LOCAL" "$REMOTE" \
+ --default --mode=merge2 --to="$MERGED"
+ ;;
+
+ emerge)
+ "$merge_tool_path" -f emerge-files-command \
+ "$LOCAL" "$REMOTE" "$(basename "$MERGED")"
+ ;;
+
+ *)
+ if test -n "$merge_tool_cmd"; then
+ ( eval $merge_tool_cmd )
+ fi
+ ;;
+ esac
+}
+
+# Verifies that (difftool|mergetool).<tool>.cmd exists
+valid_custom_tool() {
+ merge_tool_cmd="$(git config difftool.$1.cmd)"
+ test -z "$merge_tool_cmd" &&
+ merge_tool_cmd="$(git config mergetool.$1.cmd)"
+ test -n "$merge_tool_cmd"
+}
+
+# Verifies that the chosen merge tool is properly setup.
+# Built-in merge tools are always valid.
+valid_tool() {
+ case "$1" in
+ kdiff3 | kompare | tkdiff | xxdiff | meld | opendiff | emerge | vimdiff | gvimdiff | ecmerge)
+ ;; # happy
+ *)
+ if ! valid_custom_tool "$1"
+ then
+ return 1
+ fi
+ ;;
+ esac
+}
+
+# Sets up the merge_tool_path variable.
+# This handles the difftool.<tool>.path configuration.
+# This also falls back to mergetool defaults.
+init_merge_tool_path() {
+ merge_tool_path=$(git config difftool."$1".path)
+ test -z "$merge_tool_path" &&
+ merge_tool_path=$(git config mergetool."$1".path)
+ if test -z "$merge_tool_path"; then
+ case "$1" in
+ vimdiff)
+ merge_tool_path=vim
+ ;;
+ gvimdiff)
+ merge_tool_path=gvim
+ ;;
+ emerge)
+ merge_tool_path=emacs
+ ;;
+ *)
+ merge_tool_path="$1"
+ ;;
+ esac
+ fi
+}
+
+# Allow GIT_DIFF_TOOL and GIT_MERGE_TOOL to provide default values
+test -n "$GIT_MERGE_TOOL" && merge_tool="$GIT_MERGE_TOOL"
+test -n "$GIT_DIFF_TOOL" && merge_tool="$GIT_DIFF_TOOL"
+
+# If merge tool was not specified then use the diff.tool
+# configuration variable. If that's invalid then reset merge_tool.
+# Fallback to merge.tool.
+if test -z "$merge_tool"; then
+ merge_tool=$(git config diff.tool)
+ test -z "$merge_tool" &&
+ merge_tool=$(git config merge.tool)
+ if test -n "$merge_tool" && ! valid_tool "$merge_tool"; then
+ echo >&2 "git config option diff.tool set to unknown tool: $merge_tool"
+ echo >&2 "Resetting to default..."
+ unset merge_tool
+ fi
+fi
+
+# Try to guess an appropriate merge tool if no tool has been set.
+if test -z "$merge_tool"; then
+ # We have a $DISPLAY so try some common UNIX merge tools
+ if test -n "$DISPLAY"; then
+ # If gnome then prefer meld, otherwise, prefer kdiff3 or kompare
+ if test -n "$GNOME_DESKTOP_SESSION_ID" ; then
+ merge_tool_candidates="meld kdiff3 kompare tkdiff xxdiff gvimdiff diffuse"
+ else
+ merge_tool_candidates="kdiff3 kompare tkdiff xxdiff meld gvimdiff diffuse"
+ fi
+ fi
+ if echo "${VISUAL:-$EDITOR}" | grep 'emacs' > /dev/null 2>&1; then
+ # $EDITOR is emacs so add emerge as a candidate
+ merge_tool_candidates="$merge_tool_candidates emerge opendiff vimdiff"
+ elif echo "${VISUAL:-$EDITOR}" | grep 'vim' > /dev/null 2>&1; then
+ # $EDITOR is vim so add vimdiff as a candidate
+ merge_tool_candidates="$merge_tool_candidates vimdiff opendiff emerge"
+ else
+ merge_tool_candidates="$merge_tool_candidates opendiff emerge vimdiff"
+ fi
+ echo "merge tool candidates: $merge_tool_candidates"
+
+ # Loop over each candidate and stop when a valid merge tool is found.
+ for i in $merge_tool_candidates
+ do
+ init_merge_tool_path $i
+ if type "$merge_tool_path" > /dev/null 2>&1; then
+ merge_tool=$i
+ break
+ fi
+ done
+
+ if test -z "$merge_tool" ; then
+ echo "No known merge resolution program available."
+ exit 1
+ fi
+
+else
+ # A merge tool has been set, so verify that it's valid.
+ if ! valid_tool "$merge_tool"; then
+ echo >&2 "Unknown merge tool $merge_tool"
+ exit 1
+ fi
+
+ init_merge_tool_path "$merge_tool"
+
+ if test -z "$merge_tool_cmd" && ! type "$merge_tool_path" > /dev/null 2>&1; then
+ echo "The merge tool $merge_tool is not available as '$merge_tool_path'"
+ exit 1
+ fi
+fi
+
+
+# Launch the merge tool on each path provided by 'git diff'
+while test $# -gt 6
+do
+ launch_merge_tool "$1" "$2" "$5"
+ shift 7
+done
diff --git a/git-difftool.perl b/git-difftool.perl
--- /dev/null
+++ b/git-difftool.perl
@@ -0,0 +1,76 @@
+#!/usr/bin/env perl
+# Copyright (c) 2009 David Aguilar
+#
+# This is a wrapper around the GIT_EXTERNAL_DIFF-compatible
+# git-difftool--helper script. This script exports
+# GIT_EXTERNAL_DIFF and GIT_PAGER for use by git, and
+# GIT_DIFFTOOL_NO_PROMPT and GIT_DIFF_TOOL for use by git-difftool--helper.
+# Any arguments that are unknown to this script are forwarded to 'git diff'.
+
+use strict;
+use warnings;
+use Cwd qw(abs_path);
+use File::Basename qw(dirname);
+
+my $DIR = abs_path(dirname($0));
+
+
+sub usage
+{
+ print << 'USAGE';
+usage: git difftool [--tool=<tool>] [-y|--no-prompt] ["git diff" options]
+USAGE
+ exit 1;
+}
+
+sub setup_environment
+{
+ $ENV{PATH} = "$DIR:$ENV{PATH}";
+ $ENV{GIT_PAGER} = '';
+ $ENV{GIT_EXTERNAL_DIFF} = 'git-difftool--helper';
+}
+
+sub exe
+{
+ my $exe = shift;
+ if ($^O eq 'MSWin32' || $^O eq 'msys') {
+ return "$exe.exe";
+ }
+ return $exe;
+}
+
+sub generate_command
+{
+ my @command = (exe('git'), 'diff');
+ my $skip_next = 0;
+ my $idx = -1;
+ for my $arg (@ARGV) {
+ $idx++;
+ if ($skip_next) {
+ $skip_next = 0;
+ next;
+ }
+ if ($arg eq '-t' || $arg eq '--tool') {
+ usage() if $#ARGV <= $idx;
+ $ENV{GIT_DIFF_TOOL} = $ARGV[$idx + 1];
+ $skip_next = 1;
+ next;
+ }
+ if ($arg =~ /^--tool=/) {
+ $ENV{GIT_DIFF_TOOL} = substr($arg, 7);
+ next;
+ }
+ if ($arg eq '-y' || $arg eq '--no-prompt') {
+ $ENV{GIT_DIFFTOOL_NO_PROMPT} = 'true';
+ next;
+ }
+ if ($arg eq '-h' || $arg eq '--help') {
+ usage();
+ }
+ push @command, $arg;
+ }
+ return @command
+}
+
+setup_environment();
+exec(generate_command());