Merge branch 'da/difftool'
* da/difftool: mergetool--lib: simplify API usage by removing more global variables Fix misspelled mergetool.keepBackup difftool/mergetool: refactor commands to use git-mergetool--lib mergetool: use $( ... ) instead of `backticks` bash completion: add git-difftool difftool: add support for a difftool.prompt config variable difftool: add various git-difftool tests difftool: move 'git-difftool' out of contrib difftool/mergetool: add diffuse as merge and diff tool difftool: add a -y shortcut for --no-prompt difftool: use perl built-ins when testing for msys difftool: remove the backup file feature difftool: remove merge options for opendiff, tkdiff, kdiff3 and xxdiff git-mergetool: add new merge tool TortoiseMerge git-mergetool/difftool: make (g)vimdiff workable under Windows doc/merge-config: list ecmerge as a built-in merge tool
This commit is contained in:
commit
bd15ef078a
3
.gitignore
vendored
3
.gitignore
vendored
@ -36,6 +36,8 @@ git-diff
|
||||
git-diff-files
|
||||
git-diff-index
|
||||
git-diff-tree
|
||||
git-difftool
|
||||
git-difftool--helper
|
||||
git-describe
|
||||
git-fast-export
|
||||
git-fast-import
|
||||
@ -79,6 +81,7 @@ git-merge-recursive
|
||||
git-merge-resolve
|
||||
git-merge-subtree
|
||||
git-mergetool
|
||||
git-mergetool--lib
|
||||
git-mktag
|
||||
git-mktree
|
||||
git-name-rev
|
||||
|
@ -667,6 +667,27 @@ diff.suppressBlankEmpty::
|
||||
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.
|
||||
|
||||
difftool.prompt::
|
||||
Prompt before each invocation of the diff tool.
|
||||
|
||||
diff.wordRegex::
|
||||
A POSIX Extended Regular Expression used to determine what is a "word"
|
||||
when performing word-by-word difference calculations. Character
|
||||
|
@ -3,35 +3,37 @@ git-difftool(1)
|
||||
|
||||
NAME
|
||||
----
|
||||
git-difftool - compare changes using common merge tools
|
||||
git-difftool - Show changes using common diff tools
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
'git difftool' [--tool=<tool>] [--no-prompt] ['git diff' options]
|
||||
'git difftool' [--tool=<tool>] [-y|--no-prompt|--prompt] [<'git diff' options>]
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
'git-difftool' is a git command that allows you to compare and edit files
|
||||
between revisions using common merge tools. At its most basic level,
|
||||
'git-difftool' does what 'git-mergetool' does but its use is for non-merge
|
||||
situations such as when preparing commits or comparing changes against
|
||||
the index.
|
||||
|
||||
'git difftool' is a frontend to 'git diff' and accepts the same
|
||||
arguments and options.
|
||||
|
||||
See linkgit:git-diff[1] for the full list of supported options.
|
||||
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.
|
||||
|
||||
--prompt::
|
||||
Prompt before each invocation of the diff tool.
|
||||
This is the default behaviour; the option is provided to
|
||||
override any configuration settings.
|
||||
|
||||
-t <tool>::
|
||||
--tool=<tool>::
|
||||
Use the merge resolution program specified by <tool>.
|
||||
Use the diff tool specified by <tool>.
|
||||
Valid merge tools are:
|
||||
kdiff3, kompare, tkdiff, meld, xxdiff, emerge,
|
||||
vimdiff, gvimdiff, ecmerge, and opendiff
|
||||
kdiff3, kompare, tkdiff, meld, xxdiff, emerge, vimdiff, gvimdiff,
|
||||
ecmerge, diffuse and opendiff
|
||||
+
|
||||
If a merge resolution program is not specified, 'git-difftool'
|
||||
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.
|
||||
@ -42,7 +44,7 @@ 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 merge tool programs,
|
||||
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`.
|
||||
@ -56,8 +58,7 @@ 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`.
|
||||
|
||||
--no-prompt::
|
||||
Do not prompt before launching a diff tool.
|
||||
See linkgit:git-diff[1] for the full list of supported options.
|
||||
|
||||
CONFIG VARIABLES
|
||||
----------------
|
||||
@ -65,20 +66,19 @@ CONFIG VARIABLES
|
||||
difftool equivalents have not been defined.
|
||||
|
||||
diff.tool::
|
||||
The default merge tool to use.
|
||||
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 merge tool.
|
||||
Specify the command to invoke the specified diff tool.
|
||||
+
|
||||
See the `--tool=<tool>` option above for more details.
|
||||
|
||||
merge.keepBackup::
|
||||
The original, unedited file content can be saved to a file with
|
||||
a `.orig` extension. Defaults to `true` (i.e. keep the backup files).
|
||||
difftool.prompt::
|
||||
Prompt before each invocation of the diff tool.
|
||||
|
||||
SEE ALSO
|
||||
--------
|
54
Documentation/git-mergetool--lib.txt
Normal file
54
Documentation/git-mergetool--lib.txt
Normal file
@ -0,0 +1,54 @@
|
||||
git-mergetool--lib(1)
|
||||
=====================
|
||||
|
||||
NAME
|
||||
----
|
||||
git-mergetool--lib - Common git merge tool shell scriptlets
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
'TOOL_MODE=(diff|merge) . "$(git --exec-path)/git-mergetool--lib"'
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
|
||||
This is not a command the end user would want to run. Ever.
|
||||
This documentation is meant for people who are studying the
|
||||
Porcelain-ish scripts and/or are writing new ones.
|
||||
|
||||
The 'git-mergetool--lib' scriptlet is designed to be sourced (using
|
||||
`.`) by other shell scripts to set up functions for working
|
||||
with git merge tools.
|
||||
|
||||
Before sourcing 'git-mergetool--lib', your script must set `TOOL_MODE`
|
||||
to define the operation mode for the functions listed below.
|
||||
'diff' and 'merge' are valid values.
|
||||
|
||||
FUNCTIONS
|
||||
---------
|
||||
get_merge_tool::
|
||||
returns a merge tool.
|
||||
|
||||
get_merge_tool_cmd::
|
||||
returns the custom command for a merge tool.
|
||||
|
||||
get_merge_tool_path::
|
||||
returns the custom path for a merge tool.
|
||||
|
||||
run_merge_tool::
|
||||
launches a merge tool given the tool name and a true/false
|
||||
flag to indicate whether a merge base is present.
|
||||
'$MERGED', '$LOCAL', '$REMOTE', and '$BASE' must be defined
|
||||
for use by the merge tool.
|
||||
|
||||
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
|
@ -26,7 +26,8 @@ OPTIONS
|
||||
--tool=<tool>::
|
||||
Use the merge resolution program specified by <tool>.
|
||||
Valid merge tools are:
|
||||
kdiff3, tkdiff, meld, xxdiff, emerge, vimdiff, gvimdiff, ecmerge, and opendiff
|
||||
kdiff3, tkdiff, meld, xxdiff, emerge, vimdiff, gvimdiff, ecmerge,
|
||||
diffuse, tortoisemerge and opendiff
|
||||
+
|
||||
If a merge resolution program is not specified, 'git-mergetool'
|
||||
will use the configuration variable `merge.tool`. If the
|
||||
|
@ -22,7 +22,8 @@ merge.stat::
|
||||
merge.tool::
|
||||
Controls which merge resolution program is used by
|
||||
linkgit:git-mergetool[1]. Valid built-in values are: "kdiff3",
|
||||
"tkdiff", "meld", "xxdiff", "emerge", "vimdiff", "gvimdiff", and
|
||||
"tkdiff", "meld", "xxdiff", "emerge", "vimdiff", "gvimdiff",
|
||||
"diffuse", "ecmerge", "tortoisemerge", and
|
||||
"opendiff". Any other value is treated is custom merge tool
|
||||
and there must be a corresponding mergetool.<tool>.cmd option.
|
||||
|
||||
|
3
Makefile
3
Makefile
@ -279,12 +279,14 @@ TEST_PROGRAMS =
|
||||
|
||||
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-merge-one-file.sh
|
||||
SCRIPT_SH += git-merge-resolve.sh
|
||||
SCRIPT_SH += git-mergetool.sh
|
||||
SCRIPT_SH += git-mergetool--lib.sh
|
||||
SCRIPT_SH += git-parse-remote.sh
|
||||
SCRIPT_SH += git-pull.sh
|
||||
SCRIPT_SH += git-quiltimport.sh
|
||||
@ -298,6 +300,7 @@ SCRIPT_SH += git-submodule.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
|
||||
|
@ -33,6 +33,7 @@ git-diff mainporcelain common
|
||||
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
|
||||
|
@ -910,6 +910,26 @@ _git_diff ()
|
||||
__git_complete_file
|
||||
}
|
||||
|
||||
__git_mergetools_common="diffuse ecmerge emerge kdiff3 meld opendiff
|
||||
tkdiff vimdiff gvimdiff xxdiff
|
||||
"
|
||||
|
||||
_git_difftool ()
|
||||
{
|
||||
local cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
case "$cur" in
|
||||
--tool=*)
|
||||
__gitcomp "$__git_mergetools_common kompare" "" "${cur##--tool=}"
|
||||
return
|
||||
;;
|
||||
--*)
|
||||
__gitcomp "--tool="
|
||||
return
|
||||
;;
|
||||
esac
|
||||
COMPREPLY=()
|
||||
}
|
||||
|
||||
__git_fetch_options="
|
||||
--quiet --verbose --append --upload-pack --force --keep --depth=
|
||||
--tags --no-tags
|
||||
@ -1172,10 +1192,7 @@ _git_mergetool ()
|
||||
local cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
case "$cur" in
|
||||
--tool=*)
|
||||
__gitcomp "
|
||||
kdiff3 tkdiff meld xxdiff emerge
|
||||
vimdiff gvimdiff ecmerge opendiff
|
||||
" "" "${cur##--tool=}"
|
||||
__gitcomp "$__git_mergetools_common tortoisemerge" "" "${cur##--tool=}"
|
||||
return
|
||||
;;
|
||||
--*)
|
||||
@ -1901,6 +1918,7 @@ _git ()
|
||||
config) _git_config ;;
|
||||
describe) _git_describe ;;
|
||||
diff) _git_diff ;;
|
||||
difftool) _git_difftool ;;
|
||||
fetch) _git_fetch ;;
|
||||
format-patch) _git_format_patch ;;
|
||||
fsck) _git_fsck ;;
|
||||
|
@ -1,249 +0,0 @@
|
||||
#!/bin/sh
|
||||
# git-difftool-helper is a GIT_EXTERNAL_DIFF-compatible diff tool launcher.
|
||||
# It supports kdiff3, kompare, 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 () {
|
||||
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
|
||||
;;
|
||||
|
||||
kompare)
|
||||
"$merge_tool_path" "$LOCAL" "$REMOTE"
|
||||
;;
|
||||
|
||||
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 (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
|
||||
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"
|
||||
else
|
||||
merge_tool_candidates="kdiff3 kompare tkdiff xxdiff meld gvimdiff"
|
||||
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
|
59
git-difftool--helper.sh
Executable file
59
git-difftool--helper.sh
Executable file
@ -0,0 +1,59 @@
|
||||
#!/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
|
||||
|
||||
# Load common functions from git-mergetool--lib
|
||||
TOOL_MODE=diff
|
||||
. git-mergetool--lib
|
||||
|
||||
# difftool.prompt controls the default prompt/no-prompt behavior
|
||||
# and is overridden with $GIT_DIFFTOOL*_PROMPT.
|
||||
should_prompt () {
|
||||
prompt=$(git config --bool difftool.prompt || echo true)
|
||||
if test "$prompt" = true; then
|
||||
test -z "$GIT_DIFFTOOL_NO_PROMPT"
|
||||
else
|
||||
test -n "$GIT_DIFFTOOL_PROMPT"
|
||||
fi
|
||||
}
|
||||
|
||||
# Sets up shell variables and runs a 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
|
||||
run_merge_tool "$merge_tool"
|
||||
}
|
||||
|
||||
# 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 test -z "$merge_tool"; then
|
||||
merge_tool="$(get_merge_tool)" || exit
|
||||
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
|
@ -2,9 +2,12 @@
|
||||
# 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.
|
||||
# git-difftool--helper script.
|
||||
#
|
||||
# This script exports GIT_EXTERNAL_DIFF and GIT_PAGER for use by git.
|
||||
# GIT_DIFFTOOL_NO_PROMPT, GIT_DIFFTOOL_PROMPT, and GIT_DIFF_TOOL
|
||||
# are exported for use by git-difftool--helper.
|
||||
#
|
||||
# Any arguments that are unknown to this script are forwarded to 'git diff'.
|
||||
|
||||
use strict;
|
||||
@ -18,7 +21,7 @@ my $DIR = abs_path(dirname($0));
|
||||
sub usage
|
||||
{
|
||||
print << 'USAGE';
|
||||
usage: git difftool [--tool=<tool>] [--no-prompt] ["git diff" options]
|
||||
usage: git difftool [--tool=<tool>] [-y|--no-prompt] ["git diff" options]
|
||||
USAGE
|
||||
exit 1;
|
||||
}
|
||||
@ -27,13 +30,16 @@ sub setup_environment
|
||||
{
|
||||
$ENV{PATH} = "$DIR:$ENV{PATH}";
|
||||
$ENV{GIT_PAGER} = '';
|
||||
$ENV{GIT_EXTERNAL_DIFF} = 'git-difftool-helper';
|
||||
$ENV{GIT_EXTERNAL_DIFF} = 'git-difftool--helper';
|
||||
}
|
||||
|
||||
sub exe
|
||||
{
|
||||
my $exe = shift;
|
||||
return defined $ENV{COMSPEC} ? "$exe.exe" : $exe;
|
||||
if ($^O eq 'MSWin32' || $^O eq 'msys') {
|
||||
return "$exe.exe";
|
||||
}
|
||||
return $exe;
|
||||
}
|
||||
|
||||
sub generate_command
|
||||
@ -47,7 +53,7 @@ sub generate_command
|
||||
$skip_next = 0;
|
||||
next;
|
||||
}
|
||||
if ($arg eq '-t' or $arg eq '--tool') {
|
||||
if ($arg eq '-t' || $arg eq '--tool') {
|
||||
usage() if $#ARGV <= $idx;
|
||||
$ENV{GIT_DIFF_TOOL} = $ARGV[$idx + 1];
|
||||
$skip_next = 1;
|
||||
@ -57,11 +63,17 @@ sub generate_command
|
||||
$ENV{GIT_DIFF_TOOL} = substr($arg, 7);
|
||||
next;
|
||||
}
|
||||
if ($arg eq '--no-prompt') {
|
||||
if ($arg eq '-y' || $arg eq '--no-prompt') {
|
||||
$ENV{GIT_DIFFTOOL_NO_PROMPT} = 'true';
|
||||
delete $ENV{GIT_DIFFTOOL_PROMPT};
|
||||
next;
|
||||
}
|
||||
if ($arg eq '-h' or $arg eq '--help') {
|
||||
if ($arg eq '--prompt') {
|
||||
$ENV{GIT_DIFFTOOL_PROMPT} = 'true';
|
||||
delete $ENV{GIT_DIFFTOOL_NO_PROMPT};
|
||||
next;
|
||||
}
|
||||
if ($arg eq '-h' || $arg eq '--help') {
|
||||
usage();
|
||||
}
|
||||
push @command, $arg;
|
385
git-mergetool--lib.sh
Normal file
385
git-mergetool--lib.sh
Normal file
@ -0,0 +1,385 @@
|
||||
# git-mergetool--lib is a library for common merge tool functions
|
||||
diff_mode() {
|
||||
test "$TOOL_MODE" = diff
|
||||
}
|
||||
|
||||
merge_mode() {
|
||||
test "$TOOL_MODE" = merge
|
||||
}
|
||||
|
||||
translate_merge_tool_path () {
|
||||
case "$1" in
|
||||
vimdiff)
|
||||
echo vim
|
||||
;;
|
||||
gvimdiff)
|
||||
echo gvim
|
||||
;;
|
||||
emerge)
|
||||
echo emacs
|
||||
;;
|
||||
*)
|
||||
echo "$1"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
check_unchanged () {
|
||||
if test "$MERGED" -nt "$BACKUP"; then
|
||||
status=0
|
||||
else
|
||||
while true; do
|
||||
echo "$MERGED seems unchanged."
|
||||
printf "Was the merge successful? [y/n] "
|
||||
read answer < /dev/tty
|
||||
case "$answer" in
|
||||
y*|Y*) status=0; break ;;
|
||||
n*|N*) status=1; break ;;
|
||||
esac
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
valid_tool () {
|
||||
case "$1" in
|
||||
kdiff3 | tkdiff | xxdiff | meld | opendiff | \
|
||||
emerge | vimdiff | gvimdiff | ecmerge | diffuse)
|
||||
;; # happy
|
||||
tortoisemerge)
|
||||
if ! merge_mode; then
|
||||
return 1
|
||||
fi
|
||||
;;
|
||||
kompare)
|
||||
if ! diff_mode; then
|
||||
return 1
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
if test -z "$(get_merge_tool_cmd "$1")"; then
|
||||
return 1
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
get_merge_tool_cmd () {
|
||||
# Prints the custom command for a merge tool
|
||||
if test -n "$1"; then
|
||||
merge_tool="$1"
|
||||
else
|
||||
merge_tool="$(get_merge_tool)"
|
||||
fi
|
||||
if diff_mode; then
|
||||
echo "$(git config difftool.$merge_tool.cmd ||
|
||||
git config mergetool.$merge_tool.cmd)"
|
||||
else
|
||||
echo "$(git config mergetool.$merge_tool.cmd)"
|
||||
fi
|
||||
}
|
||||
|
||||
run_merge_tool () {
|
||||
merge_tool_path="$(get_merge_tool_path "$1")" || exit
|
||||
base_present="$2"
|
||||
status=0
|
||||
|
||||
case "$1" in
|
||||
kdiff3)
|
||||
if merge_mode; then
|
||||
if $base_present; then
|
||||
("$merge_tool_path" --auto \
|
||||
--L1 "$MERGED (Base)" \
|
||||
--L2 "$MERGED (Local)" \
|
||||
--L3 "$MERGED (Remote)" \
|
||||
-o "$MERGED" \
|
||||
"$BASE" "$LOCAL" "$REMOTE" \
|
||||
> /dev/null 2>&1)
|
||||
else
|
||||
("$merge_tool_path" --auto \
|
||||
--L1 "$MERGED (Local)" \
|
||||
--L2 "$MERGED (Remote)" \
|
||||
-o "$MERGED" \
|
||||
"$LOCAL" "$REMOTE" \
|
||||
> /dev/null 2>&1)
|
||||
fi
|
||||
status=$?
|
||||
else
|
||||
("$merge_tool_path" --auto \
|
||||
--L1 "$MERGED (A)" \
|
||||
--L2 "$MERGED (B)" "$LOCAL" "$REMOTE" \
|
||||
> /dev/null 2>&1)
|
||||
fi
|
||||
;;
|
||||
kompare)
|
||||
"$merge_tool_path" "$LOCAL" "$REMOTE"
|
||||
;;
|
||||
tkdiff)
|
||||
if merge_mode; then
|
||||
if $base_present; then
|
||||
"$merge_tool_path" -a "$BASE" \
|
||||
-o "$MERGED" "$LOCAL" "$REMOTE"
|
||||
else
|
||||
"$merge_tool_path" \
|
||||
-o "$MERGED" "$LOCAL" "$REMOTE"
|
||||
fi
|
||||
status=$?
|
||||
else
|
||||
"$merge_tool_path" "$LOCAL" "$REMOTE"
|
||||
fi
|
||||
;;
|
||||
meld)
|
||||
if merge_mode; then
|
||||
touch "$BACKUP"
|
||||
"$merge_tool_path" "$LOCAL" "$MERGED" "$REMOTE"
|
||||
check_unchanged
|
||||
else
|
||||
"$merge_tool_path" "$LOCAL" "$REMOTE"
|
||||
fi
|
||||
;;
|
||||
diffuse)
|
||||
if merge_mode; then
|
||||
touch "$BACKUP"
|
||||
if $base_present; then
|
||||
"$merge_tool_path" \
|
||||
"$LOCAL" "$MERGED" "$REMOTE" \
|
||||
"$BASE" | cat
|
||||
else
|
||||
"$merge_tool_path" \
|
||||
"$LOCAL" "$MERGED" "$REMOTE" | cat
|
||||
fi
|
||||
check_unchanged
|
||||
else
|
||||
"$merge_tool_path" "$LOCAL" "$REMOTE" | cat
|
||||
fi
|
||||
;;
|
||||
vimdiff)
|
||||
if merge_mode; then
|
||||
touch "$BACKUP"
|
||||
"$merge_tool_path" -d -c "wincmd l" \
|
||||
"$LOCAL" "$MERGED" "$REMOTE"
|
||||
check_unchanged
|
||||
else
|
||||
"$merge_tool_path" -d -c "wincmd l" \
|
||||
"$LOCAL" "$REMOTE"
|
||||
fi
|
||||
;;
|
||||
gvimdiff)
|
||||
if merge_mode; then
|
||||
touch "$BACKUP"
|
||||
"$merge_tool_path" -d -c "wincmd l" -f \
|
||||
"$LOCAL" "$MERGED" "$REMOTE"
|
||||
check_unchanged
|
||||
else
|
||||
"$merge_tool_path" -d -c "wincmd l" -f \
|
||||
"$LOCAL" "$REMOTE"
|
||||
fi
|
||||
;;
|
||||
xxdiff)
|
||||
if merge_mode; then
|
||||
touch "$BACKUP"
|
||||
if $base_present; then
|
||||
"$merge_tool_path" -X --show-merged-pane \
|
||||
-R 'Accel.SaveAsMerged: "Ctrl-S"' \
|
||||
-R 'Accel.Search: "Ctrl+F"' \
|
||||
-R 'Accel.SearchForward: "Ctrl-G"' \
|
||||
--merged-file "$MERGED" \
|
||||
"$LOCAL" "$BASE" "$REMOTE"
|
||||
else
|
||||
"$merge_tool_path" -X $extra \
|
||||
-R 'Accel.SaveAsMerged: "Ctrl-S"' \
|
||||
-R 'Accel.Search: "Ctrl+F"' \
|
||||
-R 'Accel.SearchForward: "Ctrl-G"' \
|
||||
--merged-file "$MERGED" \
|
||||
"$LOCAL" "$REMOTE"
|
||||
fi
|
||||
check_unchanged
|
||||
else
|
||||
"$merge_tool_path" \
|
||||
-R 'Accel.Search: "Ctrl+F"' \
|
||||
-R 'Accel.SearchForward: "Ctrl-G"' \
|
||||
"$LOCAL" "$REMOTE"
|
||||
fi
|
||||
;;
|
||||
opendiff)
|
||||
if merge_mode; then
|
||||
touch "$BACKUP"
|
||||
if $base_present; then
|
||||
"$merge_tool_path" "$LOCAL" "$REMOTE" \
|
||||
-ancestor "$BASE" \
|
||||
-merge "$MERGED" | cat
|
||||
else
|
||||
"$merge_tool_path" "$LOCAL" "$REMOTE" \
|
||||
-merge "$MERGED" | cat
|
||||
fi
|
||||
check_unchanged
|
||||
else
|
||||
"$merge_tool_path" "$LOCAL" "$REMOTE" | cat
|
||||
fi
|
||||
;;
|
||||
ecmerge)
|
||||
if merge_mode; then
|
||||
touch "$BACKUP"
|
||||
if $base_present; then
|
||||
"$merge_tool_path" "$BASE" "$LOCAL" "$REMOTE" \
|
||||
--default --mode=merge3 --to="$MERGED"
|
||||
else
|
||||
"$merge_tool_path" "$LOCAL" "$REMOTE" \
|
||||
--default --mode=merge2 --to="$MERGED"
|
||||
fi
|
||||
check_unchanged
|
||||
else
|
||||
"$merge_tool_path" "$LOCAL" "$REMOTE" \
|
||||
--default --mode=merge2 --to="$MERGED"
|
||||
fi
|
||||
;;
|
||||
emerge)
|
||||
if merge_mode; then
|
||||
if $base_present; then
|
||||
"$merge_tool_path" \
|
||||
-f emerge-files-with-ancestor-command \
|
||||
"$LOCAL" "$REMOTE" "$BASE" \
|
||||
"$(basename "$MERGED")"
|
||||
else
|
||||
"$merge_tool_path" \
|
||||
-f emerge-files-command \
|
||||
"$LOCAL" "$REMOTE" \
|
||||
"$(basename "$MERGED")"
|
||||
fi
|
||||
status=$?
|
||||
else
|
||||
"$merge_tool_path" -f emerge-files-command \
|
||||
"$LOCAL" "$REMOTE" "$(basename "$MERGED")"
|
||||
fi
|
||||
;;
|
||||
tortoisemerge)
|
||||
if $base_present; then
|
||||
touch "$BACKUP"
|
||||
"$merge_tool_path" \
|
||||
-base:"$BASE" -mine:"$LOCAL" \
|
||||
-theirs:"$REMOTE" -merged:"$MERGED"
|
||||
check_unchanged
|
||||
else
|
||||
echo "TortoiseMerge cannot be used without a base" 1>&2
|
||||
status=1
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
merge_tool_cmd="$(get_merge_tool_cmd "$1")"
|
||||
if test -z "$merge_tool_cmd"; then
|
||||
if merge_mode; then
|
||||
status=1
|
||||
fi
|
||||
break
|
||||
fi
|
||||
if merge_mode; then
|
||||
trust_exit_code="$(git config --bool \
|
||||
mergetool."$1".trustExitCode || echo false)"
|
||||
if test "$trust_exit_code" = "false"; then
|
||||
touch "$BACKUP"
|
||||
( eval $merge_tool_cmd )
|
||||
check_unchanged
|
||||
else
|
||||
( eval $merge_tool_cmd )
|
||||
status=$?
|
||||
fi
|
||||
else
|
||||
( eval $merge_tool_cmd )
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
return $status
|
||||
}
|
||||
|
||||
guess_merge_tool () {
|
||||
if merge_mode; then
|
||||
tools="tortoisemerge"
|
||||
else
|
||||
tools="kompare"
|
||||
fi
|
||||
if test -n "$DISPLAY"; then
|
||||
if test -n "$GNOME_DESKTOP_SESSION_ID" ; then
|
||||
tools="meld opendiff kdiff3 tkdiff xxdiff $tools"
|
||||
else
|
||||
tools="opendiff kdiff3 tkdiff xxdiff meld $tools"
|
||||
fi
|
||||
tools="$tools gvimdiff diffuse ecmerge"
|
||||
fi
|
||||
if echo "${VISUAL:-$EDITOR}" | grep emacs > /dev/null 2>&1; then
|
||||
# $EDITOR is emacs so add emerge as a candidate
|
||||
tools="$tools emerge vimdiff"
|
||||
elif echo "${VISUAL:-$EDITOR}" | grep vim > /dev/null 2>&1; then
|
||||
# $EDITOR is vim so add vimdiff as a candidate
|
||||
tools="$tools vimdiff emerge"
|
||||
else
|
||||
tools="$tools emerge vimdiff"
|
||||
fi
|
||||
echo >&2 "merge tool candidates: $tools"
|
||||
|
||||
# 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
|
||||
|
||||
echo >&2 "No known merge resolution program available."
|
||||
return 1
|
||||
}
|
||||
|
||||
get_configured_merge_tool () {
|
||||
# Diff mode first tries diff.tool and falls back to merge.tool.
|
||||
# Merge mode only checks merge.tool
|
||||
if diff_mode; then
|
||||
merge_tool=$(git config diff.tool || git config merge.tool)
|
||||
else
|
||||
merge_tool=$(git config merge.tool)
|
||||
fi
|
||||
if test -n "$merge_tool" && ! valid_tool "$merge_tool"; then
|
||||
echo >&2 "git config option $TOOL_MODE.tool set to unknown tool: $merge_tool"
|
||||
echo >&2 "Resetting to default..."
|
||||
return 1
|
||||
fi
|
||||
echo "$merge_tool"
|
||||
}
|
||||
|
||||
get_merge_tool_path () {
|
||||
# A merge tool has been set, so verify that it's valid.
|
||||
if test -n "$1"; then
|
||||
merge_tool="$1"
|
||||
else
|
||||
merge_tool="$(get_merge_tool)"
|
||||
fi
|
||||
if ! valid_tool "$merge_tool"; then
|
||||
echo >&2 "Unknown merge tool $merge_tool"
|
||||
exit 1
|
||||
fi
|
||||
if diff_mode; then
|
||||
merge_tool_path=$(git config difftool."$merge_tool".path ||
|
||||
git config mergetool."$merge_tool".path)
|
||||
else
|
||||
merge_tool_path=$(git config mergetool."$merge_tool".path)
|
||||
fi
|
||||
if test -z "$merge_tool_path"; then
|
||||
merge_tool_path="$(translate_merge_tool_path "$merge_tool")"
|
||||
fi
|
||||
if test -z "$(get_merge_tool_cmd "$merge_tool")" &&
|
||||
! type "$merge_tool_path" > /dev/null 2>&1; then
|
||||
echo >&2 "The $TOOL_MODE tool $merge_tool is not available as"\
|
||||
"'$merge_tool_path'"
|
||||
exit 1
|
||||
fi
|
||||
echo "$merge_tool_path"
|
||||
}
|
||||
|
||||
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"
|
||||
}
|
217
git-mergetool.sh
217
git-mergetool.sh
@ -11,7 +11,9 @@
|
||||
USAGE='[--tool=tool] [-y|--no-prompt|--prompt] [file to merge] ...'
|
||||
SUBDIRECTORY_OK=Yes
|
||||
OPTIONS_SPEC=
|
||||
TOOL_MODE=merge
|
||||
. git-sh-setup
|
||||
. git-mergetool--lib
|
||||
require_work_tree
|
||||
|
||||
# Returns true if the mode reflects a symlink
|
||||
@ -110,22 +112,6 @@ resolve_deleted_merge () {
|
||||
done
|
||||
}
|
||||
|
||||
check_unchanged () {
|
||||
if test "$MERGED" -nt "$BACKUP" ; then
|
||||
status=0;
|
||||
else
|
||||
while true; do
|
||||
echo "$MERGED seems unchanged."
|
||||
printf "Was the merge successful? [y/n] "
|
||||
read answer < /dev/tty
|
||||
case "$answer" in
|
||||
y*|Y*) status=0; break ;;
|
||||
n*|N*) status=1; break ;;
|
||||
esac
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
checkout_staged_file () {
|
||||
tmpfile=$(expr "$(git checkout-index --temp --stage="$1" "$2")" : '\([^ ]*\) ')
|
||||
|
||||
@ -137,7 +123,7 @@ checkout_staged_file () {
|
||||
merge_file () {
|
||||
MERGED="$1"
|
||||
|
||||
f=`git ls-files -u -- "$MERGED"`
|
||||
f=$(git ls-files -u -- "$MERGED")
|
||||
if test -z "$f" ; then
|
||||
if test ! -f "$MERGED" ; then
|
||||
echo "$MERGED: file not found"
|
||||
@ -156,9 +142,9 @@ merge_file () {
|
||||
mv -- "$MERGED" "$BACKUP"
|
||||
cp -- "$BACKUP" "$MERGED"
|
||||
|
||||
base_mode=`git ls-files -u -- "$MERGED" | awk '{if ($3==1) print $1;}'`
|
||||
local_mode=`git ls-files -u -- "$MERGED" | awk '{if ($3==2) print $1;}'`
|
||||
remote_mode=`git ls-files -u -- "$MERGED" | awk '{if ($3==3) print $1;}'`
|
||||
base_mode=$(git ls-files -u -- "$MERGED" | awk '{if ($3==1) print $1;}')
|
||||
local_mode=$(git ls-files -u -- "$MERGED" | awk '{if ($3==2) print $1;}')
|
||||
remote_mode=$(git ls-files -u -- "$MERGED" | awk '{if ($3==3) print $1;}')
|
||||
|
||||
base_present && checkout_staged_file 1 "$MERGED" "$BASE"
|
||||
local_present && checkout_staged_file 2 "$MERGED" "$LOCAL"
|
||||
@ -188,97 +174,13 @@ merge_file () {
|
||||
read ans
|
||||
fi
|
||||
|
||||
case "$merge_tool" in
|
||||
kdiff3)
|
||||
if base_present ; then
|
||||
("$merge_tool_path" --auto --L1 "$MERGED (Base)" --L2 "$MERGED (Local)" --L3 "$MERGED (Remote)" \
|
||||
-o "$MERGED" "$BASE" "$LOCAL" "$REMOTE" > /dev/null 2>&1)
|
||||
else
|
||||
("$merge_tool_path" --auto --L1 "$MERGED (Local)" --L2 "$MERGED (Remote)" \
|
||||
-o "$MERGED" "$LOCAL" "$REMOTE" > /dev/null 2>&1)
|
||||
fi
|
||||
status=$?
|
||||
;;
|
||||
tkdiff)
|
||||
if base_present ; then
|
||||
"$merge_tool_path" -a "$BASE" -o "$MERGED" "$LOCAL" "$REMOTE"
|
||||
else
|
||||
"$merge_tool_path" -o "$MERGED" "$LOCAL" "$REMOTE"
|
||||
fi
|
||||
status=$?
|
||||
;;
|
||||
meld)
|
||||
touch "$BACKUP"
|
||||
"$merge_tool_path" "$LOCAL" "$MERGED" "$REMOTE"
|
||||
check_unchanged
|
||||
;;
|
||||
vimdiff)
|
||||
touch "$BACKUP"
|
||||
"$merge_tool_path" -c "wincmd l" "$LOCAL" "$MERGED" "$REMOTE"
|
||||
check_unchanged
|
||||
;;
|
||||
gvimdiff)
|
||||
touch "$BACKUP"
|
||||
"$merge_tool_path" -c "wincmd l" -f "$LOCAL" "$MERGED" "$REMOTE"
|
||||
check_unchanged
|
||||
;;
|
||||
xxdiff)
|
||||
touch "$BACKUP"
|
||||
if base_present ; then
|
||||
"$merge_tool_path" -X --show-merged-pane \
|
||||
-R 'Accel.SaveAsMerged: "Ctrl-S"' \
|
||||
-R 'Accel.Search: "Ctrl+F"' \
|
||||
-R 'Accel.SearchForward: "Ctrl-G"' \
|
||||
--merged-file "$MERGED" "$LOCAL" "$BASE" "$REMOTE"
|
||||
else
|
||||
"$merge_tool_path" -X --show-merged-pane \
|
||||
-R 'Accel.SaveAsMerged: "Ctrl-S"' \
|
||||
-R 'Accel.Search: "Ctrl+F"' \
|
||||
-R 'Accel.SearchForward: "Ctrl-G"' \
|
||||
--merged-file "$MERGED" "$LOCAL" "$REMOTE"
|
||||
fi
|
||||
check_unchanged
|
||||
;;
|
||||
opendiff)
|
||||
touch "$BACKUP"
|
||||
if base_present; then
|
||||
"$merge_tool_path" "$LOCAL" "$REMOTE" -ancestor "$BASE" -merge "$MERGED" | cat
|
||||
else
|
||||
"$merge_tool_path" "$LOCAL" "$REMOTE" -merge "$MERGED" | cat
|
||||
fi
|
||||
check_unchanged
|
||||
;;
|
||||
ecmerge)
|
||||
touch "$BACKUP"
|
||||
if base_present; then
|
||||
"$merge_tool_path" "$BASE" "$LOCAL" "$REMOTE" --default --mode=merge3 --to="$MERGED"
|
||||
else
|
||||
"$merge_tool_path" "$LOCAL" "$REMOTE" --default --mode=merge2 --to="$MERGED"
|
||||
fi
|
||||
check_unchanged
|
||||
;;
|
||||
emerge)
|
||||
if base_present ; then
|
||||
"$merge_tool_path" -f emerge-files-with-ancestor-command "$LOCAL" "$REMOTE" "$BASE" "$(basename "$MERGED")"
|
||||
else
|
||||
"$merge_tool_path" -f emerge-files-command "$LOCAL" "$REMOTE" "$(basename "$MERGED")"
|
||||
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
|
||||
if base_present; then
|
||||
present=true
|
||||
else
|
||||
present=false
|
||||
fi
|
||||
|
||||
if ! run_merge_tool "$merge_tool" "$present"; then
|
||||
echo "merge of $MERGED failed" 1>&2
|
||||
mv -- "$BACKUP" "$MERGED"
|
||||
|
||||
@ -308,7 +210,7 @@ do
|
||||
-t|--tool*)
|
||||
case "$#,$1" in
|
||||
*,*=*)
|
||||
merge_tool=`expr "z$1" : 'z-[^=]*=\(.*\)'`
|
||||
merge_tool=$(expr "z$1" : 'z-[^=]*=\(.*\)')
|
||||
;;
|
||||
1,*)
|
||||
usage ;;
|
||||
@ -337,38 +239,6 @@ do
|
||||
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
|
||||
*)
|
||||
if ! valid_custom_tool "$1"; then
|
||||
return 1
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
prompt_after_failed_merge() {
|
||||
while true; do
|
||||
printf "Continue merging other unresolved paths (y/n) ? "
|
||||
@ -387,67 +257,16 @@ prompt_after_failed_merge() {
|
||||
}
|
||||
|
||||
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
|
||||
if test -n "$GNOME_DESKTOP_SESSION_ID" ; then
|
||||
merge_tool_candidates="meld kdiff3 tkdiff xxdiff gvimdiff"
|
||||
else
|
||||
merge_tool_candidates="kdiff3 tkdiff xxdiff meld gvimdiff"
|
||||
fi
|
||||
fi
|
||||
if echo "${VISUAL:-$EDITOR}" | grep 'emacs' > /dev/null 2>&1; then
|
||||
merge_tool_candidates="$merge_tool_candidates emerge opendiff vimdiff"
|
||||
elif echo "${VISUAL:-$EDITOR}" | grep 'vim' > /dev/null 2>&1; then
|
||||
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"
|
||||
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
|
||||
if ! valid_tool "$merge_tool"; then
|
||||
echo >&2 "Unknown merge_tool $merge_tool"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
init_merge_tool_path "$merge_tool"
|
||||
|
||||
merge_keep_backup="$(git config --bool merge.keepBackup || echo true)"
|
||||
merge_keep_temporaries="$(git config --bool mergetool.keepTemporaries || echo false)"
|
||||
|
||||
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
|
||||
|
||||
if ! test -z "$merge_tool_cmd"; then
|
||||
merge_tool_trust_exit_code="$(git config --bool mergetool.$merge_tool.trustExitCode || echo false)"
|
||||
fi
|
||||
merge_tool=$(get_merge_tool "$merge_tool") || exit
|
||||
fi
|
||||
merge_keep_backup="$(git config --bool mergetool.keepBackup || echo true)"
|
||||
merge_keep_temporaries="$(git config --bool mergetool.keepTemporaries || echo false)"
|
||||
|
||||
last_status=0
|
||||
rollup_status=0
|
||||
|
||||
if test $# -eq 0 ; then
|
||||
files=`git ls-files -u | sed -e 's/^[^ ]* //' | sort -u`
|
||||
files=$(git ls-files -u | sed -e 's/^[^ ]* //' | sort -u)
|
||||
if test -z "$files" ; then
|
||||
echo "No files need merging"
|
||||
exit 0
|
||||
|
211
t/t7800-difftool.sh
Executable file
211
t/t7800-difftool.sh
Executable file
@ -0,0 +1,211 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Copyright (c) 2009 David Aguilar
|
||||
#
|
||||
|
||||
test_description='git-difftool
|
||||
|
||||
Testing basic diff tool invocation
|
||||
'
|
||||
|
||||
. ./test-lib.sh
|
||||
|
||||
remove_config_vars()
|
||||
{
|
||||
# Unset all config variables used by git-difftool
|
||||
git config --unset diff.tool
|
||||
git config --unset difftool.test-tool.cmd
|
||||
git config --unset difftool.prompt
|
||||
git config --unset merge.tool
|
||||
git config --unset mergetool.test-tool.cmd
|
||||
return 0
|
||||
}
|
||||
|
||||
restore_test_defaults()
|
||||
{
|
||||
# Restores the test defaults used by several tests
|
||||
remove_config_vars
|
||||
unset GIT_DIFF_TOOL
|
||||
unset GIT_MERGE_TOOL
|
||||
unset GIT_DIFFTOOL_PROMPT
|
||||
unset GIT_DIFFTOOL_NO_PROMPT
|
||||
git config diff.tool test-tool &&
|
||||
git config difftool.test-tool.cmd 'cat $LOCAL'
|
||||
}
|
||||
|
||||
prompt_given()
|
||||
{
|
||||
prompt="$1"
|
||||
test "$prompt" = "Hit return to launch 'test-tool': branch"
|
||||
}
|
||||
|
||||
# Create a file on master and change it on branch
|
||||
test_expect_success 'setup' '
|
||||
echo master >file &&
|
||||
git add file &&
|
||||
git commit -m "added file" &&
|
||||
|
||||
git checkout -b branch master &&
|
||||
echo branch >file &&
|
||||
git commit -a -m "branch changed file" &&
|
||||
git checkout master
|
||||
'
|
||||
|
||||
# Configure a custom difftool.<tool>.cmd and use it
|
||||
test_expect_success 'custom commands' '
|
||||
restore_test_defaults &&
|
||||
git config difftool.test-tool.cmd "cat \$REMOTE" &&
|
||||
|
||||
diff=$(git difftool --no-prompt branch) &&
|
||||
test "$diff" = "master" &&
|
||||
|
||||
restore_test_defaults &&
|
||||
diff=$(git difftool --no-prompt branch) &&
|
||||
test "$diff" = "branch"
|
||||
'
|
||||
|
||||
# Ensures that git-difftool ignores bogus --tool values
|
||||
test_expect_success 'difftool ignores bad --tool values' '
|
||||
diff=$(git difftool --no-prompt --tool=bogus-tool branch)
|
||||
test "$?" = 1 &&
|
||||
test "$diff" = ""
|
||||
'
|
||||
|
||||
# Specify the diff tool using $GIT_DIFF_TOOL
|
||||
test_expect_success 'GIT_DIFF_TOOL variable' '
|
||||
git config --unset diff.tool
|
||||
GIT_DIFF_TOOL=test-tool &&
|
||||
export GIT_DIFF_TOOL &&
|
||||
|
||||
diff=$(git difftool --no-prompt branch) &&
|
||||
test "$diff" = "branch" &&
|
||||
|
||||
restore_test_defaults
|
||||
'
|
||||
|
||||
# Test the $GIT_*_TOOL variables and ensure
|
||||
# that $GIT_DIFF_TOOL always wins unless --tool is specified
|
||||
test_expect_success 'GIT_DIFF_TOOL overrides' '
|
||||
git config diff.tool bogus-tool &&
|
||||
git config merge.tool bogus-tool &&
|
||||
|
||||
GIT_MERGE_TOOL=test-tool &&
|
||||
export GIT_MERGE_TOOL &&
|
||||
diff=$(git difftool --no-prompt branch) &&
|
||||
test "$diff" = "branch" &&
|
||||
unset GIT_MERGE_TOOL &&
|
||||
|
||||
GIT_MERGE_TOOL=bogus-tool &&
|
||||
GIT_DIFF_TOOL=test-tool &&
|
||||
export GIT_MERGE_TOOL &&
|
||||
export GIT_DIFF_TOOL &&
|
||||
|
||||
diff=$(git difftool --no-prompt branch) &&
|
||||
test "$diff" = "branch" &&
|
||||
|
||||
GIT_DIFF_TOOL=bogus-tool &&
|
||||
export GIT_DIFF_TOOL &&
|
||||
|
||||
diff=$(git difftool --no-prompt --tool=test-tool branch) &&
|
||||
test "$diff" = "branch" &&
|
||||
|
||||
restore_test_defaults
|
||||
'
|
||||
|
||||
# Test that we don't have to pass --no-prompt to difftool
|
||||
# when $GIT_DIFFTOOL_NO_PROMPT is true
|
||||
test_expect_success 'GIT_DIFFTOOL_NO_PROMPT variable' '
|
||||
GIT_DIFFTOOL_NO_PROMPT=true &&
|
||||
export GIT_DIFFTOOL_NO_PROMPT &&
|
||||
|
||||
diff=$(git difftool branch) &&
|
||||
test "$diff" = "branch" &&
|
||||
|
||||
restore_test_defaults
|
||||
'
|
||||
|
||||
# git-difftool supports the difftool.prompt variable.
|
||||
# Test that GIT_DIFFTOOL_PROMPT can override difftool.prompt = false
|
||||
test_expect_success 'GIT_DIFFTOOL_PROMPT variable' '
|
||||
git config difftool.prompt false &&
|
||||
GIT_DIFFTOOL_PROMPT=true &&
|
||||
export GIT_DIFFTOOL_PROMPT &&
|
||||
|
||||
prompt=$(echo | git difftool --prompt branch | tail -1) &&
|
||||
prompt_given "$prompt" &&
|
||||
|
||||
restore_test_defaults
|
||||
'
|
||||
|
||||
# Test that we don't have to pass --no-prompt when difftool.prompt is false
|
||||
test_expect_success 'difftool.prompt config variable is false' '
|
||||
git config difftool.prompt false &&
|
||||
|
||||
diff=$(git difftool branch) &&
|
||||
test "$diff" = "branch" &&
|
||||
|
||||
restore_test_defaults
|
||||
'
|
||||
|
||||
# Test that the -y flag can override difftool.prompt = true
|
||||
test_expect_success 'difftool.prompt can overridden with -y' '
|
||||
git config difftool.prompt true &&
|
||||
|
||||
diff=$(git difftool -y branch) &&
|
||||
test "$diff" = "branch" &&
|
||||
|
||||
restore_test_defaults
|
||||
'
|
||||
|
||||
# Test that the --prompt flag can override difftool.prompt = false
|
||||
test_expect_success 'difftool.prompt can overridden with --prompt' '
|
||||
git config difftool.prompt false &&
|
||||
|
||||
prompt=$(echo | git difftool --prompt branch | tail -1) &&
|
||||
prompt_given "$prompt" &&
|
||||
|
||||
restore_test_defaults
|
||||
'
|
||||
|
||||
# Test that the last flag passed on the command-line wins
|
||||
test_expect_success 'difftool last flag wins' '
|
||||
diff=$(git difftool --prompt --no-prompt branch) &&
|
||||
test "$diff" = "branch" &&
|
||||
|
||||
restore_test_defaults &&
|
||||
|
||||
prompt=$(echo | git difftool --no-prompt --prompt branch | tail -1) &&
|
||||
prompt_given "$prompt" &&
|
||||
|
||||
restore_test_defaults
|
||||
'
|
||||
|
||||
# git-difftool falls back to git-mergetool config variables
|
||||
# so test that behavior here
|
||||
test_expect_success 'difftool + mergetool config variables' '
|
||||
remove_config_vars
|
||||
git config merge.tool test-tool &&
|
||||
git config mergetool.test-tool.cmd "cat \$LOCAL" &&
|
||||
|
||||
diff=$(git difftool --no-prompt branch) &&
|
||||
test "$diff" = "branch" &&
|
||||
|
||||
# set merge.tool to something bogus, diff.tool to test-tool
|
||||
git config merge.tool bogus-tool &&
|
||||
git config diff.tool test-tool &&
|
||||
|
||||
diff=$(git difftool --no-prompt branch) &&
|
||||
test "$diff" = "branch" &&
|
||||
|
||||
restore_test_defaults
|
||||
'
|
||||
|
||||
test_expect_success 'difftool.<tool>.path' '
|
||||
git config difftool.tkdiff.path echo &&
|
||||
diff=$(git difftool --tool=tkdiff --no-prompt branch) &&
|
||||
git config --unset difftool.tkdiff.path &&
|
||||
lines=$(echo "$diff" | grep file | wc -l) &&
|
||||
test "$lines" -eq 1
|
||||
'
|
||||
|
||||
test_done
|
Loading…
Reference in New Issue
Block a user