This question is based on VonC's comment at the thread.
Is Git's auto-detection for difftool or mergetool scripted or is it within some Git executable?
This question is based on VonC's comment at the thread.
Is Git's auto-detection for difftool or mergetool scripted or is it within some Git executable?
 
    
     
    
    It's scripted in git-mergetool. I found this at line 344 of my copy.
if test -z "$merge_tool"; then
    merge_tool=`git config merge.tool`
    if test -n "$merge_tool" && ! valid_tool "$merge_tool"; then
        echo >&2 "git config option merge.tool set to unknown tool: $merge_tool"
        echo >&2 "Resetting to default..."
        unset merge_tool
    fi
fi
if test -z "$merge_tool" ; then
    if test -n "$DISPLAY"; then
        merge_tool_candidates="kdiff3 tkdiff xxdiff meld gvimdiff"
        if test -n "$GNOME_DESKTOP_SESSION_ID" ; then
            merge_tool_candidates="meld $merge_tool_candidates"
        fi
        if test "$KDE_FULL_SESSION" = "true"; then
            merge_tool_candidates="kdiff3 $merge_tool_candidates"
        fi
    fi
    if echo "${VISUAL:-$EDITOR}" | grep 'emacs' > /dev/null 2>&1; then
        merge_tool_candidates="$merge_tool_candidates emerge"
    fi
(snip)
 
    
    As mentioned in the git mergetool man page,
--tool=<tool>
Use the merge resolution program specified by .
Valid merge tools are: kdiff3, tkdiff, meld, xxdiff, emerge, vimdiff, gvimdiff, ecmerge, diffuse, tortoisemerge, opendiff and araxis.
Now, where does that list comes from?
Actually, those tools (and their custom options) are used in the script:
<Git>/libexec/git-core/git-mergetool--lib
and used by the script git-mergetool, which does the selection based on git config merge.tool command.
But there is a bit of 'auto-selection' based on the valid_tool() function in git-mergetool--lib:
valid_tool ()
It uses get_merge_tool_cmd() which is based on mergetool.<aMergeToolName>.cmd.
If that setting remain in one of the git config files... that tool will be selected.
Right..., Jakub Narębski just pointed out the right section in the git-mergetool--lib script:
get_merge_tool () {
    # Check if a merge tool has been configured
    merge_tool=$(get_configured_merge_tool)
    # Try to guess an appropriate merge tool if no tool has been set.
    if test -z "$merge_tool"; then
        merge_tool="$(guess_merge_tool)" || exit
    fi
    echo "$merge_tool"
}
That function aptly named guess_merge_tool() (you think I should be able to find it!...) does amongst other thing, the following, which could explain it detects opendiff:
# Loop over each candidate and stop when a valid merge tool is found.
for i in $tools
do
    merge_tool_path="$(translate_merge_tool_path "$i")"
    if type "$merge_tool_path" > /dev/null 2>&1; then
        echo "$i"
        return 0
    fi
done
Compare to my 2009 answer, the scripts (like git-mergetool--lib.sh) have changed With Git 2.41 (Q2 2023):
"git mergetool"(man) and git difftool(man) learns a new configuration guiDefault to optionally favor configured guitool over non-gui-tool automatically when $DISPLAY is set.
See commit 42943b9 (18 Mar 2023) by Tao Klerks (TaoK).
(Merged by Junio C Hamano -- gitster -- in commit 9d8370d, 17 Apr 2023)
mergetool: new config guiDefault supports auto-toggling gui by DISPLAYSigned-off-by: Tao Klerks
Acked-by: David Aguilar
When no
merge.toolordiff.toolis configured or manually selected, the selection of a default tool is sensitive to theDISPLAYvariable; in a GUI session a gui-specific tool will be proposed if found, and otherwise a terminal-based one.
This "GUI-optimizing" behavior is important because a GUI can make a huge difference to a user's ability to understand and correctly complete a non-trivial conflicting merge.Some time ago the
merge.guitoolanddiff.guitoolconfig options were introduced to enable users to configure both a GUI tool, and a non-GUI tool (with fallback if no GUI tool configured), in the same environment.Unfortunately, the
--guiargument introduced to support the selection of the guitool is still explicit.
When using configured tools, there is no equivalent of the no-tool-configured "propose a GUI tool if we are in a GUI environment" behavior.As proposed in xmqqmtb8jsej.fsf@gitster.g, introduce new configuration options,
difftool.guiDefaultandmergetool.guiDefault, supporting a special value "auto" which causes the corresponding tool or guitool to be selected depending on the presence of a non-emptyDISPLAYvalue.
Also support "true" to say "default to the guitool (unless--no-guiis passed on the commandline)", and "false" as the previous default behavior when these new configuration options are not specified.
git config now includes in its man page:
difftool.guiDefaultSet
trueto use thediff.guitoolby default (equivalent to specifying the--guiargument), orautoto selectdiff.guitoolordiff.tooldepending on the presence of aDISPLAYenvironment variable value. The default isfalse, where the--guiargument must be provided explicitly for thediff.guitoolto be used.
git config now includes in its man page:
mergetool.guiDefaultSet
trueto use themerge.guitoolby default (equivalent to specifying the--guiargument), orautoto selectmerge.guitoolormerge.tooldepending on the presence of aDISPLAYenvironment variable value. The default isfalse, where the--guiargument must be provided explicitly for themerge.guitoolto be used.
git difftool now includes in its man page:
diff.guitoolvariable instead ofdiff.tool. This may be selected automatically using the configuration variabledifftool.guiDefault. The--no-guioption can be used to override these settings. Ifdiff.guitoolis not set, we will fallback in the order ofmerge.guitool,diff.tool,merge.tooluntil a tool is found.
git mergetool now includes in its man page:
This overrides a previous
-gor--guisetting ormergetool.guiDefaultconfiguration and reads the default merge tool from the configuredmerge.toolvariable.
Example:
git config merge.guitool myguitool
git config mergetool.myguitool.cmd "(printf \"gui \" && cat \"\$REMOTE\") >\"\$MERGED\""
git config mergetool.myguitool.trustExitCode true
