Merge branch 'dl/difftool-mergetool'

Update "git difftool" and "git mergetool" so that the combinations
of {diff,merge}.{tool,guitool} configuration variables serve as
fallback settings of each other in a sensible order.

* dl/difftool-mergetool:
  difftool: fallback on merge.guitool
  difftool: make --gui, --tool and --extcmd mutually exclusive
  mergetool: fallback to tool when guitool unavailable
  mergetool--lib: create gui_mode function
  mergetool: use get_merge_tool function
  t7610: add mergetool --gui tests
  t7610: unsuppress output
This commit is contained in:
Junio C Hamano 2019-05-19 16:45:30 +09:00
Родитель fed9391fba 6c22d715e7
Коммит 85ac27e04f
9 изменённых файлов: 180 добавлений и 93 удалений

Просмотреть файл

@ -90,7 +90,9 @@ instead. `--no-symlinks` is the default on Windows.
When 'git-difftool' is invoked with the `-g` or `--gui` option
the default diff tool will be read from the configured
`diff.guitool` variable instead of `diff.tool`. The `--no-gui`
option can be used to override this setting.
option can be used to override this setting. If `diff.guitool`
is not set, we will fallback in the order of `merge.guitool`,
`diff.tool`, `merge.tool` until a tool is found.
--[no-]trust-exit-code::
'git-difftool' invokes a diff tool individually on each file.

Просмотреть файл

@ -28,7 +28,9 @@ to define the operation mode for the functions listed below.
FUNCTIONS
---------
get_merge_tool::
returns a merge tool.
returns a merge tool. the return code is 1 if we returned a guessed
merge tool, else 0. '$GIT_MERGETOOL_GUI' may be set to 'true' to
search for the appropriate guitool.
get_merge_tool_cmd::
returns the custom command for a merge tool.

Просмотреть файл

@ -83,7 +83,9 @@ success of the resolution after the custom tool has exited.
--gui::
When 'git-mergetool' is invoked with the `-g` or `--gui` option
the default merge tool will be read from the configured
`merge.guitool` variable instead of `merge.tool`.
`merge.guitool` variable instead of `merge.tool`. If
`merge.guitool` is not set, we will fallback to the tool
configured under `merge.tool`.
--no-gui::
This overrides a previous `-g` or `--gui` setting and reads the

Просмотреть файл

@ -24,7 +24,6 @@
#include "object-store.h"
#include "dir.h"
static char *diff_gui_tool;
static int trust_exit_code;
static const char *const builtin_difftool_usage[] = {
@ -34,11 +33,6 @@ static const char *const builtin_difftool_usage[] = {
static int difftool_config(const char *var, const char *value, void *cb)
{
if (!strcmp(var, "diff.guitool")) {
diff_gui_tool = xstrdup(value);
return 0;
}
if (!strcmp(var, "difftool.trustexitcode")) {
trust_exit_code = git_config_bool(var, value);
return 0;
@ -735,8 +729,11 @@ int cmd_difftool(int argc, const char **argv, const char *prefix)
setenv(GIT_WORK_TREE_ENVIRONMENT, absolute_path(get_git_work_tree()), 1);
}
if (use_gui_tool && diff_gui_tool && *diff_gui_tool)
setenv("GIT_DIFF_TOOL", diff_gui_tool, 1);
if (use_gui_tool + !!difftool_cmd + !!extcmd > 1)
die(_("--gui, --tool and --extcmd are mutually exclusive"));
if (use_gui_tool)
setenv("GIT_MERGETOOL_GUI", "true", 1);
else if (difftool_cmd) {
if (*difftool_cmd)
setenv("GIT_DIFF_TOOL", difftool_cmd, 1);

Просмотреть файл

@ -71,7 +71,7 @@ then
then
merge_tool="$GIT_DIFF_TOOL"
else
merge_tool="$(get_merge_tool)" || exit
merge_tool="$(get_merge_tool)"
fi
fi

Просмотреть файл

@ -80,14 +80,18 @@ show_tool_names () {
}
}
diff_mode() {
diff_mode () {
test "$TOOL_MODE" = diff
}
merge_mode() {
merge_mode () {
test "$TOOL_MODE" = merge
}
gui_mode () {
test "$GIT_MERGETOOL_GUI" = true
}
translate_merge_tool_path () {
echo "$1"
}
@ -351,20 +355,36 @@ guess_merge_tool () {
}
get_configured_merge_tool () {
# If first argument is true, find the guitool instead
if test "$1" = true
then
gui_prefix=gui
fi
# Diff mode first tries diff.(gui)tool and falls back to merge.(gui)tool.
# Merge mode only checks merge.(gui)tool
keys=
if diff_mode
then
merge_tool=$(git config diff.${gui_prefix}tool || git config merge.${gui_prefix}tool)
if gui_mode
then
keys="diff.guitool merge.guitool diff.tool merge.tool"
else
keys="diff.tool merge.tool"
fi
else
merge_tool=$(git config merge.${gui_prefix}tool)
if gui_mode
then
keys="merge.guitool merge.tool"
else
keys="merge.tool"
fi
fi
merge_tool=$(
IFS=' '
for key in $keys
do
selected=$(git config $key)
if test -n "$selected"
then
echo "$selected"
return
fi
done)
if test -n "$merge_tool" && ! valid_tool "$merge_tool"
then
echo >&2 "git config option $TOOL_MODE.${gui_prefix}tool set to unknown tool: $merge_tool"
@ -404,14 +424,17 @@ get_merge_tool_path () {
}
get_merge_tool () {
is_guessed=false
# 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
is_guessed=true
fi
echo "$merge_tool"
test "$is_guessed" = false
}
mergetool_find_win32_cmd () {

Просмотреть файл

@ -389,7 +389,7 @@ print_noop_and_exit () {
main () {
prompt=$(git config --bool mergetool.prompt)
gui_tool=false
GIT_MERGETOOL_GUI=false
guessed_merge_tool=false
orderfile=
@ -416,10 +416,10 @@ main () {
esac
;;
--no-gui)
gui_tool=false
GIT_MERGETOOL_GUI=false
;;
-g|--gui)
gui_tool=true
GIT_MERGETOOL_GUI=true
;;
-y|--no-prompt)
prompt=false
@ -449,12 +449,8 @@ main () {
if test -z "$merge_tool"
then
# Check if a merge tool has been configured
merge_tool=$(get_configured_merge_tool $gui_tool)
# Try to guess an appropriate merge tool if no tool has been set.
if test -z "$merge_tool"
if ! merge_tool=$(get_merge_tool)
then
merge_tool=$(guess_merge_tool) || exit
guessed_merge_tool=true
fi
fi

Просмотреть файл

@ -130,14 +130,55 @@ test_expect_success 'custom mergetool' '
test_when_finished "git reset --hard" &&
git checkout -b test$test_count branch1 &&
git submodule update -N &&
test_must_fail git merge master >/dev/null 2>&1 &&
( yes "" | git mergetool both >/dev/null 2>&1 ) &&
test_must_fail git merge master &&
( yes "" | git mergetool both ) &&
( yes "" | git mergetool file1 file1 ) &&
( yes "" | git mergetool file2 "spaced name" >/dev/null 2>&1 ) &&
( yes "" | git mergetool subdir/file3 >/dev/null 2>&1 ) &&
( yes "d" | git mergetool file11 >/dev/null 2>&1 ) &&
( yes "d" | git mergetool file12 >/dev/null 2>&1 ) &&
( yes "l" | git mergetool submod >/dev/null 2>&1 ) &&
( yes "" | git mergetool file2 "spaced name" ) &&
( yes "" | git mergetool subdir/file3 ) &&
( yes "d" | git mergetool file11 ) &&
( yes "d" | git mergetool file12 ) &&
( yes "l" | git mergetool submod ) &&
test "$(cat file1)" = "master updated" &&
test "$(cat file2)" = "master new" &&
test "$(cat subdir/file3)" = "master new sub" &&
test "$(cat submod/bar)" = "branch1 submodule" &&
git commit -m "branch1 resolved with mergetool"
'
test_expect_success 'gui mergetool' '
test_config merge.guitool myguitool &&
test_config mergetool.myguitool.cmd "(printf \"gui \" && cat \"\$REMOTE\") >\"\$MERGED\"" &&
test_config mergetool.myguitool.trustExitCode true &&
test_when_finished "git reset --hard" &&
git checkout -b test$test_count branch1 &&
git submodule update -N &&
test_must_fail git merge master &&
( yes "" | git mergetool --gui both ) &&
( yes "" | git mergetool -g file1 file1 ) &&
( yes "" | git mergetool --gui file2 "spaced name" ) &&
( yes "" | git mergetool --gui subdir/file3 ) &&
( yes "d" | git mergetool --gui file11 ) &&
( yes "d" | git mergetool --gui file12 ) &&
( yes "l" | git mergetool --gui submod ) &&
test "$(cat file1)" = "gui master updated" &&
test "$(cat file2)" = "gui master new" &&
test "$(cat subdir/file3)" = "gui master new sub" &&
test "$(cat submod/bar)" = "branch1 submodule" &&
git commit -m "branch1 resolved with mergetool"
'
test_expect_success 'gui mergetool without merge.guitool set falls back to merge.tool' '
test_when_finished "git reset --hard" &&
git checkout -b test$test_count branch1 &&
git submodule update -N &&
test_must_fail git merge master &&
( yes "" | git mergetool --gui both ) &&
( yes "" | git mergetool -g file1 file1 ) &&
( yes "" | git mergetool --gui file2 "spaced name" ) &&
( yes "" | git mergetool --gui subdir/file3 ) &&
( yes "d" | git mergetool --gui file11 ) &&
( yes "d" | git mergetool --gui file12 ) &&
( yes "l" | git mergetool --gui submod ) &&
test "$(cat file1)" = "master updated" &&
test "$(cat file2)" = "master new" &&
test "$(cat subdir/file3)" = "master new sub" &&
@ -153,15 +194,15 @@ test_expect_success 'mergetool crlf' '
# test_when_finished is LIFO.)
test_config core.autocrlf true &&
git checkout -b test$test_count branch1 &&
test_must_fail git merge master >/dev/null 2>&1 &&
( yes "" | git mergetool file1 >/dev/null 2>&1 ) &&
( yes "" | git mergetool file2 >/dev/null 2>&1 ) &&
( yes "" | git mergetool "spaced name" >/dev/null 2>&1 ) &&
( yes "" | git mergetool both >/dev/null 2>&1 ) &&
( yes "" | git mergetool subdir/file3 >/dev/null 2>&1 ) &&
( yes "d" | git mergetool file11 >/dev/null 2>&1 ) &&
( yes "d" | git mergetool file12 >/dev/null 2>&1 ) &&
( yes "r" | git mergetool submod >/dev/null 2>&1 ) &&
test_must_fail git merge master &&
( yes "" | git mergetool file1 ) &&
( yes "" | git mergetool file2 ) &&
( yes "" | git mergetool "spaced name" ) &&
( yes "" | git mergetool both ) &&
( yes "" | git mergetool subdir/file3 ) &&
( yes "d" | git mergetool file11 ) &&
( yes "d" | git mergetool file12 ) &&
( yes "r" | git mergetool submod ) &&
test "$(printf x | cat file1 -)" = "$(printf "master updated\r\nx")" &&
test "$(printf x | cat file2 -)" = "$(printf "master new\r\nx")" &&
test "$(printf x | cat subdir/file3 -)" = "$(printf "master new sub\r\nx")" &&
@ -176,8 +217,8 @@ test_expect_success 'mergetool in subdir' '
git submodule update -N &&
(
cd subdir &&
test_must_fail git merge master >/dev/null 2>&1 &&
( yes "" | git mergetool file3 >/dev/null 2>&1 ) &&
test_must_fail git merge master &&
( yes "" | git mergetool file3 ) &&
test "$(cat file3)" = "master new sub"
)
'
@ -188,14 +229,14 @@ test_expect_success 'mergetool on file in parent dir' '
git submodule update -N &&
(
cd subdir &&
test_must_fail git merge master >/dev/null 2>&1 &&
( yes "" | git mergetool file3 >/dev/null 2>&1 ) &&
( yes "" | git mergetool ../file1 >/dev/null 2>&1 ) &&
( yes "" | git mergetool ../file2 ../spaced\ name >/dev/null 2>&1 ) &&
( yes "" | git mergetool ../both >/dev/null 2>&1 ) &&
( yes "d" | git mergetool ../file11 >/dev/null 2>&1 ) &&
( yes "d" | git mergetool ../file12 >/dev/null 2>&1 ) &&
( yes "l" | git mergetool ../submod >/dev/null 2>&1 ) &&
test_must_fail git merge master &&
( yes "" | git mergetool file3 ) &&
( yes "" | git mergetool ../file1 ) &&
( yes "" | git mergetool ../file2 ../spaced\ name ) &&
( yes "" | git mergetool ../both ) &&
( yes "d" | git mergetool ../file11 ) &&
( yes "d" | git mergetool ../file12 ) &&
( yes "l" | git mergetool ../submod ) &&
test "$(cat ../file1)" = "master updated" &&
test "$(cat ../file2)" = "master new" &&
test "$(cat ../submod/bar)" = "branch1 submodule" &&
@ -209,9 +250,9 @@ test_expect_success 'mergetool skips autoresolved' '
git submodule update -N &&
test_must_fail git merge master &&
test -n "$(git ls-files -u)" &&
( yes "d" | git mergetool file11 >/dev/null 2>&1 ) &&
( yes "d" | git mergetool file12 >/dev/null 2>&1 ) &&
( yes "l" | git mergetool submod >/dev/null 2>&1 ) &&
( yes "d" | git mergetool file11 ) &&
( yes "d" | git mergetool file12 ) &&
( yes "l" | git mergetool submod ) &&
output="$(git mergetool --no-prompt)" &&
test "$output" = "No files need merging"
'
@ -259,9 +300,9 @@ test_expect_success 'mergetool skips resolved paths when rerere is active' '
rm -rf .git/rr-cache &&
git checkout -b test$test_count branch1 &&
git submodule update -N &&
test_must_fail git merge master >/dev/null 2>&1 &&
( yes "l" | git mergetool --no-prompt submod >/dev/null 2>&1 ) &&
( yes "d" "d" | git mergetool --no-prompt >/dev/null 2>&1 ) &&
test_must_fail git merge master &&
( yes "l" | git mergetool --no-prompt submod ) &&
( yes "d" "d" | git mergetool --no-prompt ) &&
git submodule update -N &&
output="$(yes "n" | git mergetool --no-prompt)" &&
test "$output" = "No files need merging"
@ -369,9 +410,9 @@ test_expect_success 'deleted vs modified submodule' '
git checkout -b test$test_count.a test$test_count &&
test_must_fail git merge master &&
test -n "$(git ls-files -u)" &&
( yes "" | git mergetool file1 file2 spaced\ name subdir/file3 >/dev/null 2>&1 ) &&
( yes "" | git mergetool both >/dev/null 2>&1 ) &&
( yes "d" | git mergetool file11 file12 >/dev/null 2>&1 ) &&
( yes "" | git mergetool file1 file2 spaced\ name subdir/file3 ) &&
( yes "" | git mergetool both ) &&
( yes "d" | git mergetool file11 file12 ) &&
( yes "r" | git mergetool submod ) &&
rmdir submod && mv submod-movedaside submod &&
test "$(cat submod/bar)" = "branch1 submodule" &&
@ -386,9 +427,9 @@ test_expect_success 'deleted vs modified submodule' '
git submodule update -N &&
test_must_fail git merge master &&
test -n "$(git ls-files -u)" &&
( yes "" | git mergetool file1 file2 spaced\ name subdir/file3 >/dev/null 2>&1 ) &&
( yes "" | git mergetool both >/dev/null 2>&1 ) &&
( yes "d" | git mergetool file11 file12 >/dev/null 2>&1 ) &&
( yes "" | git mergetool file1 file2 spaced\ name subdir/file3 ) &&
( yes "" | git mergetool both ) &&
( yes "d" | git mergetool file11 file12 ) &&
( yes "l" | git mergetool submod ) &&
test ! -e submod &&
output="$(git mergetool --no-prompt)" &&
@ -400,9 +441,9 @@ test_expect_success 'deleted vs modified submodule' '
git submodule update -N &&
test_must_fail git merge test$test_count &&
test -n "$(git ls-files -u)" &&
( yes "" | git mergetool file1 file2 spaced\ name subdir/file3 >/dev/null 2>&1 ) &&
( yes "" | git mergetool both >/dev/null 2>&1 ) &&
( yes "d" | git mergetool file11 file12 >/dev/null 2>&1 ) &&
( yes "" | git mergetool file1 file2 spaced\ name subdir/file3 ) &&
( yes "" | git mergetool both ) &&
( yes "d" | git mergetool file11 file12 ) &&
( yes "r" | git mergetool submod ) &&
test ! -e submod &&
test -d submod.orig &&
@ -416,9 +457,9 @@ test_expect_success 'deleted vs modified submodule' '
git submodule update -N &&
test_must_fail git merge test$test_count &&
test -n "$(git ls-files -u)" &&
( yes "" | git mergetool file1 file2 spaced\ name subdir/file3 >/dev/null 2>&1 ) &&
( yes "" | git mergetool both >/dev/null 2>&1 ) &&
( yes "d" | git mergetool file11 file12 >/dev/null 2>&1 ) &&
( yes "" | git mergetool file1 file2 spaced\ name subdir/file3 ) &&
( yes "" | git mergetool both ) &&
( yes "d" | git mergetool file11 file12 ) &&
( yes "l" | git mergetool submod ) &&
test "$(cat submod/bar)" = "master submodule" &&
git submodule update -N &&
@ -440,9 +481,9 @@ test_expect_success 'file vs modified submodule' '
git checkout -b test$test_count.a branch1 &&
test_must_fail git merge master &&
test -n "$(git ls-files -u)" &&
( yes "" | git mergetool file1 file2 spaced\ name subdir/file3 >/dev/null 2>&1 ) &&
( yes "" | git mergetool both >/dev/null 2>&1 ) &&
( yes "d" | git mergetool file11 file12 >/dev/null 2>&1 ) &&
( yes "" | git mergetool file1 file2 spaced\ name subdir/file3 ) &&
( yes "" | git mergetool both ) &&
( yes "d" | git mergetool file11 file12 ) &&
( yes "r" | git mergetool submod ) &&
rmdir submod && mv submod-movedaside submod &&
test "$(cat submod/bar)" = "branch1 submodule" &&
@ -456,9 +497,9 @@ test_expect_success 'file vs modified submodule' '
git checkout -b test$test_count.b test$test_count &&
test_must_fail git merge master &&
test -n "$(git ls-files -u)" &&
( yes "" | git mergetool file1 file2 spaced\ name subdir/file3 >/dev/null 2>&1 ) &&
( yes "" | git mergetool both >/dev/null 2>&1 ) &&
( yes "d" | git mergetool file11 file12 >/dev/null 2>&1 ) &&
( yes "" | git mergetool file1 file2 spaced\ name subdir/file3 ) &&
( yes "" | git mergetool both ) &&
( yes "d" | git mergetool file11 file12 ) &&
( yes "l" | git mergetool submod ) &&
git submodule update -N &&
test "$(cat submod)" = "not a submodule" &&
@ -472,9 +513,9 @@ test_expect_success 'file vs modified submodule' '
git submodule update -N &&
test_must_fail git merge test$test_count &&
test -n "$(git ls-files -u)" &&
( yes "" | git mergetool file1 file2 spaced\ name subdir/file3 >/dev/null 2>&1 ) &&
( yes "" | git mergetool both >/dev/null 2>&1 ) &&
( yes "d" | git mergetool file11 file12 >/dev/null 2>&1 ) &&
( yes "" | git mergetool file1 file2 spaced\ name subdir/file3 ) &&
( yes "" | git mergetool both ) &&
( yes "d" | git mergetool file11 file12 ) &&
( yes "r" | git mergetool submod ) &&
test -d submod.orig &&
git submodule update -N &&
@ -488,9 +529,9 @@ test_expect_success 'file vs modified submodule' '
git submodule update -N &&
test_must_fail git merge test$test_count &&
test -n "$(git ls-files -u)" &&
( yes "" | git mergetool file1 file2 spaced\ name subdir/file3 >/dev/null 2>&1 ) &&
( yes "" | git mergetool both>/dev/null 2>&1 ) &&
( yes "d" | git mergetool file11 file12 >/dev/null 2>&1 ) &&
( yes "" | git mergetool file1 file2 spaced\ name subdir/file3 ) &&
( yes "" | git mergetool both ) &&
( yes "d" | git mergetool file11 file12 ) &&
( yes "l" | git mergetool submod ) &&
test "$(cat submod/bar)" = "master submodule" &&
git submodule update -N &&
@ -543,7 +584,7 @@ test_expect_success 'submodule in subdirectory' '
git add subdir/subdir_module &&
git commit -m "change submodule in subdirectory on test$test_count.b" &&
test_must_fail git merge test$test_count.a >/dev/null 2>&1 &&
test_must_fail git merge test$test_count.a &&
(
cd subdir &&
( yes "l" | git mergetool subdir_module )
@ -554,7 +595,7 @@ test_expect_success 'submodule in subdirectory' '
git reset --hard &&
git submodule update -N &&
test_must_fail git merge test$test_count.a >/dev/null 2>&1 &&
test_must_fail git merge test$test_count.a &&
( yes "r" | git mergetool subdir/subdir_module ) &&
test "$(cat subdir/subdir_module/file15)" = "test$test_count.b" &&
git submodule update -N &&
@ -641,7 +682,7 @@ test_expect_success 'filenames seen by tools start with ./' '
test_config mergetool.myecho.trustExitCode true &&
test_must_fail git merge master &&
git mergetool --no-prompt --tool myecho -- both >actual &&
grep ^\./both_LOCAL_ actual >/dev/null
grep ^\./both_LOCAL_ actual
'
test_lazy_prereq MKTEMP '
@ -658,8 +699,8 @@ test_expect_success MKTEMP 'temporary filenames are used with mergetool.writeToT
test_config mergetool.myecho.trustExitCode true &&
test_must_fail git merge master &&
git mergetool --no-prompt --tool myecho -- both >actual &&
! grep ^\./both_LOCAL_ actual >/dev/null &&
grep /both_LOCAL_ actual >/dev/null
! grep ^\./both_LOCAL_ actual &&
grep /both_LOCAL_ actual
'
test_expect_success 'diff.orderFile configuration is honored' '

Просмотреть файл

@ -279,11 +279,27 @@ test_expect_success 'difftool + mergetool config variables' '
echo branch >expect &&
git difftool --no-prompt branch >actual &&
test_cmp expect actual &&
git difftool --gui --no-prompt branch >actual &&
test_cmp expect actual &&
# set merge.tool to something bogus, diff.tool to test-tool
test_config merge.tool bogus-tool &&
test_config diff.tool test-tool &&
git difftool --no-prompt branch >actual &&
test_cmp expect actual &&
git difftool --gui --no-prompt branch >actual &&
test_cmp expect actual &&
# set merge.tool, diff.tool to something bogus, merge.guitool to test-tool
test_config diff.tool bogus-tool &&
test_config merge.guitool test-tool &&
git difftool --gui --no-prompt branch >actual &&
test_cmp expect actual &&
# set merge.tool, diff.tool, merge.guitool to something bogus, diff.guitool to test-tool
test_config merge.guitool bogus-tool &&
test_config diff.guitool test-tool &&
git difftool --gui --no-prompt branch >actual &&
test_cmp expect actual
'
@ -715,4 +731,12 @@ test_expect_success 'outside worktree' '
test_cmp expect actual
'
test_expect_success 'difftool --gui, --tool and --extcmd are mutually exclusive' '
difftool_test_setup &&
test_must_fail git difftool --gui --tool=test-tool &&
test_must_fail git difftool --gui --extcmd=cat &&
test_must_fail git difftool --tool=test-tool --extcmd=cat &&
test_must_fail git difftool --gui --tool=test-tool --extcmd=cat
'
test_done