Teach git mergetool to use custom commands defined at config time
authorCharles Bailey <charles@hashpling.org>
Thu, 21 Feb 2008 23:31:12 +0000 (23:31 +0000)
committerJunio C Hamano <gitster@pobox.com>
Wed, 5 Mar 2008 20:07:04 +0000 (12:07 -0800)
Currently git mergetool is restricted to a set of commands defined
in the script. You can subvert the mergetool.<tool>.path to force
git mergetool to use a different command, but if you have a command
whose invocation syntax does not match one of the current tools then
you would have to write a wrapper script for it.

This patch adds two git config variable patterns which allow a more
flexible choice of merge tool.

If you run git mergetool with -t/--tool or the merge.tool config
variable set to an unrecognized tool then git mergetool will query the
mergetool.<tool>.cmd config variable. If this variable exists, then git
mergetool will treat the specified tool as a custom command and will use
a shell eval to run the command with the documented shell variables set.

mergetool.<tool>.trustExitCode can be used to indicate that the exit
code of the custom command can be used to determine the success of the
merge.

Signed-off-by: Charles Bailey <charles@hashpling.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Documentation/config.txt
git-mergetool.sh
index 514169066db4504212afc062fb9a6723b183e07c..29bc51603f9a5c7f3a3c8f5389fec703072e2056 100644 (file)
@@ -749,8 +749,10 @@ merge.summary::
 
 merge.tool::
        Controls which merge resolution program is used by
 
 merge.tool::
        Controls which merge resolution program is used by
-       linkgit:git-mergetool[1].  Valid values are: "kdiff3", "tkdiff",
-       "meld", "xxdiff", "emerge", "vimdiff", "gvimdiff", and "opendiff".
+       linkgit:git-mergetool[1].  Valid built-in values are: "kdiff3",
+       "tkdiff", "meld", "xxdiff", "emerge", "vimdiff", "gvimdiff", and
+       "opendiff".  Any other value is treated is custom merge tool
+       and there must be a corresponing mergetool.<tool>.cmd option.
 
 merge.verbosity::
        Controls the amount of output shown by the recursive merge
 
 merge.verbosity::
        Controls the amount of output shown by the recursive merge
@@ -777,6 +779,25 @@ mergetool.<tool>.path::
        Override the path for the given tool.  This is useful in case
        your tool is not in the PATH.
 
        Override the path for the given tool.  This is useful in case
        your tool is not in the PATH.
 
+mergetool.<tool>.cmd::
+       Specify the command to invoke the specified merge tool.  The
+       specified command is evaluated in shell with the following
+       variables available: 'BASE' is the name of a temporary file
+       containing the common base of the files to be merged, if available;
+       'LOCAL' is the name of a temporary file containing the contents of
+       the file on the current branch; 'REMOTE' is the name of a temporary
+       file containing the contents of the file from the branch being
+       merged; 'MERGED' contains the name of the file to which the merge
+       tool should write the results of a successful merge.
+
+mergetool.<tool>.trustExitCode::
+       For a custom merge command, specify whether the exit code of
+       the merge command can be used to determine whether the merge was
+       successful.  If this is not set to true then the merge target file
+       timestamp is checked and the merge assumed to have been successful
+       if the file has been updated, otherwise the user is prompted to
+       indicate the success of the merge.
+
 mergetool.keepBackup::
        After performing a merge, the original file with conflict markers
        can be saved as a file with a `.orig` extension.  If this variable
 mergetool.keepBackup::
        After performing a merge, the original file with conflict markers
        can be saved as a file with a `.orig` extension.  If this variable
index 2199c625c6243aedacc04ec7b757a3e27b7fd7f8..5c86f69229042c16704d11ce404e43297cc7b72c 100755 (executable)
@@ -251,6 +251,18 @@ merge_file () {
            fi
            status=$?
            ;;
            fi
            status=$?
            ;;
+       *)
+           if test -n "$merge_tool_cmd"; then
+               if test "$merge_tool_trust_exit_code" = "false"; then
+                   touch "$BACKUP"
+                   ( eval $merge_tool_cmd )
+                   check_unchanged
+               else
+                   ( eval $merge_tool_cmd )
+                   status=$?
+               fi
+           fi
+           ;;
     esac
     if test "$status" -ne 0; then
        echo "merge of $MERGED failed" 1>&2
     esac
     if test "$status" -ne 0; then
        echo "merge of $MERGED failed" 1>&2
@@ -296,12 +308,20 @@ do
     shift
 done
 
     shift
 done
 
+valid_custom_tool()
+{
+    merge_tool_cmd="$(git config mergetool.$1.cmd)"
+    test -n "$merge_tool_cmd"
+}
+
 valid_tool() {
        case "$1" in
                kdiff3 | tkdiff | xxdiff | meld | opendiff | emerge | vimdiff | gvimdiff | ecmerge)
                        ;; # happy
                *)
 valid_tool() {
        case "$1" in
                kdiff3 | tkdiff | xxdiff | meld | opendiff | emerge | vimdiff | gvimdiff | ecmerge)
                        ;; # happy
                *)
-                       return 1
+                       if ! valid_custom_tool "$1"; then
+                               return 1
+                       fi
                        ;;
        esac
 }
                        ;;
        esac
 }
@@ -369,10 +389,14 @@ else
 
     merge_keep_backup="$(git config --bool merge.keepBackup || echo true)"
 
 
     merge_keep_backup="$(git config --bool merge.keepBackup || echo true)"
 
-    if ! type "$merge_tool_path" > /dev/null 2>&1; then
+    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
         echo "The merge tool $merge_tool is not available as '$merge_tool_path'"
         exit 1
     fi
+
+    if ! test -z "$merge_tool_cmd"; then
+        merge_tool_trust_exit_code="$(git config --bool mergetool.$merge_tool.trustExitCode || echo false)"
+    fi
 fi
 
 
 fi