mirror of
https://github.com/git/git.git
synced 2024-11-19 07:24:50 +01:00
f13bfc1be7
git-difftool worked for me on an up-to-date Gentoo Linux at home, but didn't work on a somewhat older Ubuntu Linux 7.10 at work and failed with the following error, where 'Makefile' was locally modified: trap: 244: SIGINT: bad trap external diff died, stopping at Makefile. In 'man 1p trap' there is written: "The condition can be EXIT, 0 (equivalent to EXIT), or a signal specified using a symbolic name, without the SIG prefix, [...]" "Implementations may permit names with the SIG prefix or ignore case in signal names as an extension." So now we do it the POSIX compliant way instead of using an extension. Signed-off-by: Markus Heidelberg <markus.heidelberg@web.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
244 lines
5.9 KiB
Bash
Executable file
244 lines
5.9 KiB
Bash
Executable file
#!/bin/sh
|
|
# git-difftool-helper is a GIT_EXTERNAL_DIFF-compatible diff tool launcher.
|
|
# It supports kdiff3, tkdiff, xxdiff, meld, opendiff, emerge, ecmerge,
|
|
# vimdiff, gvimdiff, and custom user-configurable tools.
|
|
# 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 -n "$GIT_DIFFTOOL_NO_PROMPT"
|
|
}
|
|
|
|
# Should we keep the backup .orig file?
|
|
keep_backup_mode="$(git config --bool merge.keepBackup || echo true)"
|
|
keep_backup () {
|
|
test "$keep_backup_mode" = "true"
|
|
}
|
|
|
|
# This function manages the backup .orig file.
|
|
# A backup $MERGED.orig file is created if changes are detected.
|
|
cleanup_temp_files () {
|
|
if test -n "$MERGED"; then
|
|
if keep_backup && test "$MERGED" -nt "$BACKUP"; then
|
|
test -f "$BACKUP" && mv -- "$BACKUP" "$MERGED.orig"
|
|
else
|
|
rm -f -- "$BACKUP"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# This is called when users Ctrl-C out of git-difftool-helper
|
|
sigint_handler () {
|
|
echo
|
|
cleanup_temp_files
|
|
exit 1
|
|
}
|
|
|
|
# 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"
|
|
ext="$$$(expr "$MERGED" : '.*\(\.[^/]*\)$')"
|
|
BACKUP="$MERGED.BACKUP.$ext"
|
|
|
|
# Create and ensure that we clean up $BACKUP
|
|
test -f "$MERGED" && cp -- "$MERGED" "$BACKUP"
|
|
trap sigint_handler INT
|
|
|
|
# $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)" \
|
|
-o "$MERGED" "$LOCAL" "$REMOTE" \
|
|
> /dev/null 2>&1
|
|
;;
|
|
|
|
tkdiff)
|
|
"$merge_tool_path" -o "$MERGED" "$LOCAL" "$REMOTE"
|
|
;;
|
|
|
|
meld)
|
|
"$merge_tool_path" "$LOCAL" "$REMOTE"
|
|
;;
|
|
|
|
vimdiff)
|
|
"$merge_tool_path" -c "wincmd l" "$LOCAL" "$REMOTE"
|
|
;;
|
|
|
|
gvimdiff)
|
|
"$merge_tool_path" -c "wincmd l" -f "$LOCAL" "$REMOTE"
|
|
;;
|
|
|
|
xxdiff)
|
|
"$merge_tool_path" \
|
|
-X \
|
|
-R 'Accel.SaveAsMerged: "Ctrl-S"' \
|
|
-R 'Accel.Search: "Ctrl+F"' \
|
|
-R 'Accel.SearchForward: "Ctrl-G"' \
|
|
--merged-file "$MERGED" \
|
|
"$LOCAL" "$REMOTE"
|
|
;;
|
|
|
|
opendiff)
|
|
"$merge_tool_path" "$LOCAL" "$REMOTE" \
|
|
-merge "$MERGED" | 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
|
|
|
|
cleanup_temp_files
|
|
}
|
|
|
|
# Verifies that mergetool.<tool>.cmd exists
|
|
valid_custom_tool() {
|
|
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 | 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 mergetool.<tool>.path configuration.
|
|
init_merge_tool_path() {
|
|
merge_tool_path=$(git config mergetool."$1".path)
|
|
if test -z "$merge_tool_path"; then
|
|
case "$1" in
|
|
emerge)
|
|
merge_tool_path=emacs
|
|
;;
|
|
*)
|
|
merge_tool_path="$1"
|
|
;;
|
|
esac
|
|
fi
|
|
}
|
|
|
|
# Allow the GIT_MERGE_TOOL variable to provide a default value
|
|
test -n "$GIT_MERGE_TOOL" && merge_tool="$GIT_MERGE_TOOL"
|
|
|
|
# If not merge tool was specified then use the merge.tool
|
|
# configuration variable. If that's invalid then reset merge_tool.
|
|
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
|
|
|
|
# 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
|
|
merge_tool_candidates="kdiff3 tkdiff xxdiff meld gvimdiff"
|
|
# If gnome then prefer meld
|
|
if test -n "$GNOME_DESKTOP_SESSION_ID"; then
|
|
merge_tool_candidates="meld $merge_tool_candidates"
|
|
fi
|
|
# If KDE then prefer kdiff3
|
|
if test "$KDE_FULL_SESSION" = "true"; then
|
|
merge_tool_candidates="kdiff3 $merge_tool_candidates"
|
|
fi
|
|
fi
|
|
|
|
# $EDITOR is emacs so add emerge as a candidate
|
|
if echo "${VISUAL:-$EDITOR}" | grep 'emacs' > /dev/null 2>&1; then
|
|
merge_tool_candidates="$merge_tool_candidates emerge"
|
|
fi
|
|
|
|
# $EDITOR is vim so add vimdiff as a candidate
|
|
if echo "${VISUAL:-$EDITOR}" | grep 'vim' > /dev/null 2>&1; then
|
|
merge_tool_candidates="$merge_tool_candidates vimdiff"
|
|
fi
|
|
|
|
merge_tool_candidates="$merge_tool_candidates opendiff emerge vimdiff"
|
|
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
|