From da81688cc5639c9c482a89a4b732737f7aa0d61d Mon Sep 17 00:00:00 2001 From: Markus Heidelberg Date: Mon, 6 Apr 2009 01:31:16 -0700 Subject: doc/merge-config: list ecmerge as a built-in merge tool Signed-off-by: Markus Heidelberg Signed-off-by: Junio C Hamano diff --git a/Documentation/merge-config.txt b/Documentation/merge-config.txt index 1ff08ff..9c44af8 100644 --- a/Documentation/merge-config.txt +++ b/Documentation/merge-config.txt @@ -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", + "ecmerge" and "opendiff". Any other value is treated is custom merge tool and there must be a corresponding mergetool..cmd option. -- cgit v0.10.2-6-g49f6 From bad42732008cb0c1e77046d716e4446b1545d4d0 Mon Sep 17 00:00:00 2001 From: Markus Heidelberg Date: Mon, 6 Apr 2009 01:31:17 -0700 Subject: git-mergetool/difftool: make (g)vimdiff workable under Windows Under Windows vimdiff and gvimdiff are not available as symbolic links, but as batch files vimdiff.bat and gvimdiff.bat. These files weren't found by 'type vimdiff' which led to the following error: The merge tool vimdiff is not available as 'vimdiff' Even if they were found, it wouldn't work to invoke these batch files from git-mergetool. To solve this, use vim and gvim (vim.exe and gvim.exe) and pass the -d command line switch over to them. Signed-off-by: Markus Heidelberg Signed-off-by: Junio C Hamano diff --git a/contrib/difftool/git-difftool-helper b/contrib/difftool/git-difftool-helper index 9c0a134..e481913 100755 --- a/contrib/difftool/git-difftool-helper +++ b/contrib/difftool/git-difftool-helper @@ -86,11 +86,11 @@ launch_merge_tool () { ;; vimdiff) - "$merge_tool_path" -c "wincmd l" "$LOCAL" "$REMOTE" + "$merge_tool_path" -d -c "wincmd l" "$LOCAL" "$REMOTE" ;; gvimdiff) - "$merge_tool_path" -c "wincmd l" -f "$LOCAL" "$REMOTE" + "$merge_tool_path" -d -c "wincmd l" -f "$LOCAL" "$REMOTE" ;; xxdiff) @@ -160,6 +160,12 @@ init_merge_tool_path() { merge_tool_path=$(git config mergetool."$1".path) if test -z "$merge_tool_path"; then case "$1" in + vimdiff) + merge_tool_path=vim + ;; + gvimdiff) + merge_tool_path=gvim + ;; emerge) merge_tool_path=emacs ;; diff --git a/git-mergetool.sh b/git-mergetool.sh index 87fa88a..6e611e9 100755 --- a/git-mergetool.sh +++ b/git-mergetool.sh @@ -214,12 +214,12 @@ merge_file () { ;; vimdiff) touch "$BACKUP" - "$merge_tool_path" -c "wincmd l" "$LOCAL" "$MERGED" "$REMOTE" + "$merge_tool_path" -d -c "wincmd l" "$LOCAL" "$MERGED" "$REMOTE" check_unchanged ;; gvimdiff) touch "$BACKUP" - "$merge_tool_path" -c "wincmd l" -f "$LOCAL" "$MERGED" "$REMOTE" + "$merge_tool_path" -d -c "wincmd l" -f "$LOCAL" "$MERGED" "$REMOTE" check_unchanged ;; xxdiff) @@ -359,6 +359,12 @@ init_merge_tool_path() { merge_tool_path=`git config mergetool.$1.path` if test -z "$merge_tool_path" ; then case "$1" in + vimdiff) + merge_tool_path=vim + ;; + gvimdiff) + merge_tool_path=gvim + ;; emerge) merge_tool_path=emacs ;; -- cgit v0.10.2-6-g49f6 From b98c212a9fd97300a8cf39015b8d693f319fd71c Mon Sep 17 00:00:00 2001 From: Markus Heidelberg Date: Mon, 6 Apr 2009 01:31:18 -0700 Subject: git-mergetool: add new merge tool TortoiseMerge TortoiseMerge comes with TortoiseSVN or TortoiseGit for Windows. It can only be used as a merge tool with an existing base file. It cannot be used without a base nor as a diff tool. The documentation only mentions the slash '/' as command line option prefix, which refused to work, but the parser also accepts the dash '-' See http://code.google.com/p/msysgit/issues/detail?id=226 Signed-off-by: Markus Heidelberg Signed-off-by: Junio C Hamano diff --git a/Documentation/git-mergetool.txt b/Documentation/git-mergetool.txt index 5d3c632..5edac4d 100644 --- a/Documentation/git-mergetool.txt +++ b/Documentation/git-mergetool.txt @@ -26,7 +26,8 @@ OPTIONS --tool=:: Use the merge resolution program specified by . Valid merge tools are: - kdiff3, tkdiff, meld, xxdiff, emerge, vimdiff, gvimdiff, ecmerge, and opendiff + kdiff3, tkdiff, meld, xxdiff, emerge, vimdiff, gvimdiff, ecmerge, + tortoisemerge and opendiff + If a merge resolution program is not specified, 'git-mergetool' will use the configuration variable `merge.tool`. If the diff --git a/Documentation/merge-config.txt b/Documentation/merge-config.txt index 9c44af8..8c10f66 100644 --- a/Documentation/merge-config.txt +++ b/Documentation/merge-config.txt @@ -23,7 +23,7 @@ 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", - "ecmerge" and + "ecmerge", tortoisemerge and "opendiff". Any other value is treated is custom merge tool and there must be a corresponding mergetool..cmd option. diff --git a/git-mergetool.sh b/git-mergetool.sh index 6e611e9..be9717a 100755 --- a/git-mergetool.sh +++ b/git-mergetool.sh @@ -265,6 +265,16 @@ merge_file () { fi status=$? ;; + 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 + ;; *) if test -n "$merge_tool_cmd"; then if test "$merge_tool_trust_exit_code" = "false"; then @@ -345,7 +355,7 @@ valid_custom_tool() valid_tool() { case "$1" in - kdiff3 | tkdiff | xxdiff | meld | opendiff | emerge | vimdiff | gvimdiff | ecmerge) + kdiff3 | tkdiff | xxdiff | meld | opendiff | emerge | vimdiff | gvimdiff | ecmerge | tortoisemerge) ;; # happy *) if ! valid_custom_tool "$1"; then @@ -404,9 +414,9 @@ 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" + merge_tool_candidates="meld kdiff3 tkdiff xxdiff tortoisemerge gvimdiff" else - merge_tool_candidates="kdiff3 tkdiff xxdiff meld gvimdiff" + merge_tool_candidates="kdiff3 tkdiff xxdiff meld tortoisemerge gvimdiff" fi fi if echo "${VISUAL:-$EDITOR}" | grep 'emacs' > /dev/null 2>&1; then -- cgit v0.10.2-6-g49f6 From 76ca653842057766773776bffc6a415b39d5a147 Mon Sep 17 00:00:00 2001 From: David Aguilar Date: Mon, 6 Apr 2009 01:31:19 -0700 Subject: difftool: remove merge options for opendiff, tkdiff, kdiff3 and xxdiff We shouldn't try to merge files when using difftool, so remove any merge-specific options. Signed-off-by: David Aguilar Signed-off-by: Junio C Hamano diff --git a/contrib/difftool/git-difftool-helper b/contrib/difftool/git-difftool-helper index e481913..ef684b6 100755 --- a/contrib/difftool/git-difftool-helper +++ b/contrib/difftool/git-difftool-helper @@ -69,7 +69,7 @@ launch_merge_tool () { "$merge_tool_path" --auto \ --L1 "$basename (A)" \ --L2 "$basename (B)" \ - -o "$MERGED" "$LOCAL" "$REMOTE" \ + "$LOCAL" "$REMOTE" \ > /dev/null 2>&1 ;; @@ -78,7 +78,7 @@ launch_merge_tool () { ;; tkdiff) - "$merge_tool_path" -o "$MERGED" "$LOCAL" "$REMOTE" + "$merge_tool_path" "$LOCAL" "$REMOTE" ;; meld) @@ -95,17 +95,13 @@ launch_merge_tool () { 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 + "$merge_tool_path" "$LOCAL" "$REMOTE" | cat ;; ecmerge) -- cgit v0.10.2-6-g49f6 From 2e8af7e42b15d4f2d573329ea2593a19f45f18d3 Mon Sep 17 00:00:00 2001 From: David Aguilar Date: Mon, 6 Apr 2009 01:31:20 -0700 Subject: difftool: remove the backup file feature Most users find the backup file feature annoying and there's no need for it since diff is supposed to be a read-only operation. Signed-off-by: David Aguilar Signed-off-by: Junio C Hamano diff --git a/contrib/difftool/git-difftool-helper b/contrib/difftool/git-difftool-helper index ef684b6..e74a274 100755 --- a/contrib/difftool/git-difftool-helper +++ b/contrib/difftool/git-difftool-helper @@ -9,31 +9,7 @@ # 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 + test -z "$GIT_DIFFTOOL_NO_PROMPT" } # This function prepares temporary files and launches the appropriate @@ -47,12 +23,6 @@ launch_merge_tool () { 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. @@ -120,8 +90,6 @@ launch_merge_tool () { fi ;; esac - - cleanup_temp_files } # Verifies that (difftool|mergetool)..cmd exists -- cgit v0.10.2-6-g49f6 From 46ae156d6c8c48d521e4d858ed84d93259cfc61f Mon Sep 17 00:00:00 2001 From: David Aguilar Date: Mon, 6 Apr 2009 01:31:21 -0700 Subject: difftool: use perl built-ins when testing for msys I don't even know what $COMSPEC means so let's be safe and use the same perly $^O test add--interactive uses. While we're at it, make git-difftool match the prevalent git-perl style. Signed-off-by: David Aguilar Signed-off-by: Junio C Hamano diff --git a/contrib/difftool/git-difftool b/contrib/difftool/git-difftool index 0deda3a..207dd50 100755 --- a/contrib/difftool/git-difftool +++ b/contrib/difftool/git-difftool @@ -33,7 +33,10 @@ sub setup_environment 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 +50,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; -- cgit v0.10.2-6-g49f6 From 8b7332221db8522fe23bf8cf25d058acea6b9142 Mon Sep 17 00:00:00 2001 From: David Aguilar Date: Tue, 7 Apr 2009 01:21:19 -0700 Subject: difftool: add a -y shortcut for --no-prompt This is another consistency cleanup to make git-difftool's options match git-mergetool. Signed-off-by: David Aguilar Signed-off-by: Junio C Hamano diff --git a/contrib/difftool/git-difftool b/contrib/difftool/git-difftool index 207dd50..8c160e5 100755 --- a/contrib/difftool/git-difftool +++ b/contrib/difftool/git-difftool @@ -18,7 +18,7 @@ my $DIR = abs_path(dirname($0)); sub usage { print << 'USAGE'; -usage: git difftool [--tool=] [--no-prompt] ["git diff" options] +usage: git difftool [--tool=] [-y|--no-prompt] ["git diff" options] USAGE exit 1; } @@ -60,11 +60,11 @@ 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'; next; } - if ($arg eq '-h' or $arg eq '--help') { + if ($arg eq '-h' || $arg eq '--help') { usage(); } push @command, $arg; diff --git a/contrib/difftool/git-difftool.txt b/contrib/difftool/git-difftool.txt index 2b7bc03..a00e943 100644 --- a/contrib/difftool/git-difftool.txt +++ b/contrib/difftool/git-difftool.txt @@ -3,35 +3,32 @@ git-difftool(1) NAME ---- -git-difftool - compare changes using common merge tools +git-difftool - Show changes using common diff tools SYNOPSIS -------- -'git difftool' [--tool=] [--no-prompt] ['git diff' options] +'git difftool' [--tool=] [-y|--no-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. + -t :: --tool=:: - Use the merge resolution program specified by . + Use the diff tool specified by . Valid merge tools are: kdiff3, kompare, tkdiff, meld, xxdiff, emerge, vimdiff, gvimdiff, ecmerge, 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 +39,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..cmd`. @@ -56,8 +53,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,21 +61,17 @@ CONFIG VARIABLES difftool equivalents have not been defined. diff.tool:: - The default merge tool to use. + The default diff tool to use. difftool..path:: Override the path for the given tool. This is useful in case your tool is not in the PATH. difftool..cmd:: - Specify the command to invoke the specified merge tool. + Specify the command to invoke the specified diff tool. + See the `--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). - SEE ALSO -------- linkgit:git-diff[1]:: -- cgit v0.10.2-6-g49f6 From 1c0f3d224eff2ff8ca8442811edb5a6830adba1a Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Mon, 6 Apr 2009 01:31:23 -0700 Subject: difftool/mergetool: add diffuse as merge and diff tool This adds diffuse as a built-in merge tool. Signed-off-by: Sebastian Pipping Signed-off-by: David Aguilar Signed-off-by: Junio C Hamano diff --git a/Documentation/git-mergetool.txt b/Documentation/git-mergetool.txt index 5edac4d..ff9700d 100644 --- a/Documentation/git-mergetool.txt +++ b/Documentation/git-mergetool.txt @@ -27,7 +27,7 @@ OPTIONS Use the merge resolution program specified by . Valid merge tools are: kdiff3, tkdiff, meld, xxdiff, emerge, vimdiff, gvimdiff, ecmerge, - tortoisemerge and opendiff + diffuse, tortoisemerge and opendiff + If a merge resolution program is not specified, 'git-mergetool' will use the configuration variable `merge.tool`. If the diff --git a/Documentation/merge-config.txt b/Documentation/merge-config.txt index 8c10f66..4832bc7 100644 --- a/Documentation/merge-config.txt +++ b/Documentation/merge-config.txt @@ -23,7 +23,7 @@ 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", - "ecmerge", tortoisemerge and + "diffuse", "ecmerge", "tortoisemerge", and "opendiff". Any other value is treated is custom merge tool and there must be a corresponding mergetool..cmd option. diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index d3d8203..e099ed4 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -1174,7 +1174,8 @@ _git_mergetool () --tool=*) __gitcomp " kdiff3 tkdiff meld xxdiff emerge - vimdiff gvimdiff ecmerge opendiff + vimdiff gvimdiff ecmerge diffuse + opendiff " "" "${cur##--tool=}" return ;; diff --git a/contrib/difftool/git-difftool-helper b/contrib/difftool/git-difftool-helper index e74a274..4b0daec 100755 --- a/contrib/difftool/git-difftool-helper +++ b/contrib/difftool/git-difftool-helper @@ -1,7 +1,5 @@ #!/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. # @@ -55,6 +53,10 @@ launch_merge_tool () { "$merge_tool_path" "$LOCAL" "$REMOTE" ;; + diffuse) + "$merge_tool_path" "$LOCAL" "$REMOTE" | cat + ;; + vimdiff) "$merge_tool_path" -d -c "wincmd l" "$LOCAL" "$REMOTE" ;; @@ -164,9 +166,9 @@ if test -z "$merge_tool"; then 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" + merge_tool_candidates="meld kdiff3 kompare tkdiff xxdiff gvimdiff diffuse" else - merge_tool_candidates="kdiff3 kompare tkdiff xxdiff meld gvimdiff" + merge_tool_candidates="kdiff3 kompare tkdiff xxdiff meld gvimdiff diffuse" fi fi if echo "${VISUAL:-$EDITOR}" | grep 'emacs' > /dev/null 2>&1; then diff --git a/contrib/difftool/git-difftool.txt b/contrib/difftool/git-difftool.txt index a00e943..af68466 100644 --- a/contrib/difftool/git-difftool.txt +++ b/contrib/difftool/git-difftool.txt @@ -25,8 +25,8 @@ OPTIONS --tool=:: Use the diff tool specified by . 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 diff tool is not specified, 'git-difftool' will use the configuration variable `diff.tool`. If the diff --git a/git-mergetool.sh b/git-mergetool.sh index be9717a..b4d2432 100755 --- a/git-mergetool.sh +++ b/git-mergetool.sh @@ -414,9 +414,9 @@ 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 tortoisemerge gvimdiff" + merge_tool_candidates="meld kdiff3 tkdiff xxdiff tortoisemerge gvimdiff diffuse" else - merge_tool_candidates="kdiff3 tkdiff xxdiff meld tortoisemerge gvimdiff" + merge_tool_candidates="kdiff3 tkdiff xxdiff meld tortoisemerge gvimdiff diffuse" fi fi if echo "${VISUAL:-$EDITOR}" | grep 'emacs' > /dev/null 2>&1; then -- cgit v0.10.2-6-g49f6 From afcbc8e7ecb18a3ee542e808f02f5df7d56d5bdc Mon Sep 17 00:00:00 2001 From: David Aguilar Date: Tue, 7 Apr 2009 01:21:20 -0700 Subject: difftool: move 'git-difftool' out of contrib This prepares 'git-difftool' and its documentation for mainstream use. 'git-difftool-helper' became 'git-difftool--helper' since users should not use it directly. 'git-difftool' was added to the list of commands as an ancillaryinterrogator. Signed-off-by: David Aguilar Signed-off-by: Junio C Hamano diff --git a/.gitignore b/.gitignore index 1c57d4c..a36da9d 100644 --- a/.gitignore +++ b/.gitignore @@ -35,6 +35,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 diff --git a/Documentation/config.txt b/Documentation/config.txt index 3afd124..94ef1a6 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -667,6 +667,24 @@ 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..path:: + Override the path for the given tool. This is useful in case + your tool is not in the PATH. + +difftool..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. + diff.wordRegex:: A POSIX Extended Regular Expression used to determine what is a "word" when performing word-by-word difference calculations. Character diff --git a/Documentation/git-difftool.txt b/Documentation/git-difftool.txt new file mode 100644 index 0000000..af68466 --- /dev/null +++ b/Documentation/git-difftool.txt @@ -0,0 +1,97 @@ +git-difftool(1) +=============== + +NAME +---- +git-difftool - Show changes using common diff tools + +SYNOPSIS +-------- +'git difftool' [--tool=] [-y|--no-prompt] [<'git diff' options>] + +DESCRIPTION +----------- +'git-difftool' is a git command that allows you to compare and edit files +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. + +-t :: +--tool=:: + Use the diff tool specified by . + Valid merge tools are: + kdiff3, kompare, tkdiff, meld, xxdiff, emerge, vimdiff, gvimdiff, + ecmerge, diffuse and opendiff ++ +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. ++ +You can explicitly provide a full path to the tool by setting the +configuration variable `difftool..path`. For example, you +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 diff tools, +'git-difftool' can be customized to run an alternative program +by specifying the command line to invoke in a configuration +variable `difftool..cmd`. ++ +When 'git-difftool' is invoked with this tool (either through the +`-t` or `--tool` option or the `diff.tool` configuration variable) +the configured command line will be invoked 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. `$BASE` is provided for compatibility +with custom merge tool commands and has the same value as `$LOCAL`. + +See linkgit:git-diff[1] for the full list of supported options. + +CONFIG VARIABLES +---------------- +'git-difftool' falls back to 'git-mergetool' config variables when the +difftool equivalents have not been defined. + +diff.tool:: + The default diff tool to use. + +difftool..path:: + Override the path for the given tool. This is useful in case + your tool is not in the PATH. + +difftool..cmd:: + Specify the command to invoke the specified diff tool. ++ +See the `--tool=` option above for more details. + +SEE ALSO +-------- +linkgit:git-diff[1]:: + Show changes between commits, commit and working tree, etc + +linkgit:git-mergetool[1]:: + Run merge conflict resolution tools to resolve merge conflicts + +linkgit:git-config[1]:: + Get and set repository or global options + + +AUTHOR +------ +Written by David Aguilar . + +Documentation +-------------- +Documentation by David Aguilar and the git-list . + +GIT +--- +Part of the linkgit:git[1] suite diff --git a/Makefile b/Makefile index 7867eac..a80055f 100644 --- a/Makefile +++ b/Makefile @@ -277,6 +277,7 @@ 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 @@ -296,6 +297,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 diff --git a/command-list.txt b/command-list.txt index 3583a33..fb03a2e 100644 --- a/command-list.txt +++ b/command-list.txt @@ -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 diff --git a/contrib/difftool/git-difftool b/contrib/difftool/git-difftool deleted file mode 100755 index 8c160e5..0000000 --- a/contrib/difftool/git-difftool +++ /dev/null @@ -1,76 +0,0 @@ -#!/usr/bin/env perl -# 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. -# Any arguments that are unknown to this script are forwarded to 'git diff'. - -use strict; -use warnings; -use Cwd qw(abs_path); -use File::Basename qw(dirname); - -my $DIR = abs_path(dirname($0)); - - -sub usage -{ - print << 'USAGE'; -usage: git difftool [--tool=] [-y|--no-prompt] ["git diff" options] -USAGE - exit 1; -} - -sub setup_environment -{ - $ENV{PATH} = "$DIR:$ENV{PATH}"; - $ENV{GIT_PAGER} = ''; - $ENV{GIT_EXTERNAL_DIFF} = 'git-difftool-helper'; -} - -sub exe -{ - my $exe = shift; - if ($^O eq 'MSWin32' || $^O eq 'msys') { - return "$exe.exe"; - } - return $exe; -} - -sub generate_command -{ - my @command = (exe('git'), 'diff'); - my $skip_next = 0; - my $idx = -1; - for my $arg (@ARGV) { - $idx++; - if ($skip_next) { - $skip_next = 0; - next; - } - if ($arg eq '-t' || $arg eq '--tool') { - usage() if $#ARGV <= $idx; - $ENV{GIT_DIFF_TOOL} = $ARGV[$idx + 1]; - $skip_next = 1; - next; - } - if ($arg =~ /^--tool=/) { - $ENV{GIT_DIFF_TOOL} = substr($arg, 7); - next; - } - if ($arg eq '-y' || $arg eq '--no-prompt') { - $ENV{GIT_DIFFTOOL_NO_PROMPT} = 'true'; - next; - } - if ($arg eq '-h' || $arg eq '--help') { - usage(); - } - push @command, $arg; - } - return @command -} - -setup_environment(); -exec(generate_command()); diff --git a/contrib/difftool/git-difftool-helper b/contrib/difftool/git-difftool-helper deleted file mode 100755 index 4b0daec..0000000 --- a/contrib/difftool/git-difftool-helper +++ /dev/null @@ -1,221 +0,0 @@ -#!/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 - -# Set GIT_DIFFTOOL_NO_PROMPT to bypass the per-file prompt. -should_prompt () { - test -z "$GIT_DIFFTOOL_NO_PROMPT" -} - -# 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" - - # $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)" \ - "$LOCAL" "$REMOTE" \ - > /dev/null 2>&1 - ;; - - kompare) - "$merge_tool_path" "$LOCAL" "$REMOTE" - ;; - - tkdiff) - "$merge_tool_path" "$LOCAL" "$REMOTE" - ;; - - meld) - "$merge_tool_path" "$LOCAL" "$REMOTE" - ;; - - diffuse) - "$merge_tool_path" "$LOCAL" "$REMOTE" | cat - ;; - - vimdiff) - "$merge_tool_path" -d -c "wincmd l" "$LOCAL" "$REMOTE" - ;; - - gvimdiff) - "$merge_tool_path" -d -c "wincmd l" -f "$LOCAL" "$REMOTE" - ;; - - xxdiff) - "$merge_tool_path" \ - -R 'Accel.Search: "Ctrl+F"' \ - -R 'Accel.SearchForward: "Ctrl-G"' \ - "$LOCAL" "$REMOTE" - ;; - - opendiff) - "$merge_tool_path" "$LOCAL" "$REMOTE" | 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 -} - -# Verifies that (difftool|mergetool)..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..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 - vimdiff) - merge_tool_path=vim - ;; - gvimdiff) - merge_tool_path=gvim - ;; - 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 diffuse" - else - merge_tool_candidates="kdiff3 kompare tkdiff xxdiff meld gvimdiff diffuse" - 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 diff --git a/contrib/difftool/git-difftool.txt b/contrib/difftool/git-difftool.txt deleted file mode 100644 index af68466..0000000 --- a/contrib/difftool/git-difftool.txt +++ /dev/null @@ -1,97 +0,0 @@ -git-difftool(1) -=============== - -NAME ----- -git-difftool - Show changes using common diff tools - -SYNOPSIS --------- -'git difftool' [--tool=] [-y|--no-prompt] [<'git diff' options>] - -DESCRIPTION ------------ -'git-difftool' is a git command that allows you to compare and edit files -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. - --t :: ---tool=:: - Use the diff tool specified by . - Valid merge tools are: - kdiff3, kompare, tkdiff, meld, xxdiff, emerge, vimdiff, gvimdiff, - ecmerge, diffuse and opendiff -+ -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. -+ -You can explicitly provide a full path to the tool by setting the -configuration variable `difftool..path`. For example, you -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 diff tools, -'git-difftool' can be customized to run an alternative program -by specifying the command line to invoke in a configuration -variable `difftool..cmd`. -+ -When 'git-difftool' is invoked with this tool (either through the -`-t` or `--tool` option or the `diff.tool` configuration variable) -the configured command line will be invoked 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. `$BASE` is provided for compatibility -with custom merge tool commands and has the same value as `$LOCAL`. - -See linkgit:git-diff[1] for the full list of supported options. - -CONFIG VARIABLES ----------------- -'git-difftool' falls back to 'git-mergetool' config variables when the -difftool equivalents have not been defined. - -diff.tool:: - The default diff tool to use. - -difftool..path:: - Override the path for the given tool. This is useful in case - your tool is not in the PATH. - -difftool..cmd:: - Specify the command to invoke the specified diff tool. -+ -See the `--tool=` option above for more details. - -SEE ALSO --------- -linkgit:git-diff[1]:: - Show changes between commits, commit and working tree, etc - -linkgit:git-mergetool[1]:: - Run merge conflict resolution tools to resolve merge conflicts - -linkgit:git-config[1]:: - Get and set repository or global options - - -AUTHOR ------- -Written by David Aguilar . - -Documentation --------------- -Documentation by David Aguilar and the git-list . - -GIT ---- -Part of the linkgit:git[1] suite diff --git a/git-difftool--helper.sh b/git-difftool--helper.sh new file mode 100755 index 0000000..fc61416 --- /dev/null +++ b/git-difftool--helper.sh @@ -0,0 +1,221 @@ +#!/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 + +# Set GIT_DIFFTOOL_NO_PROMPT to bypass the per-file prompt. +should_prompt () { + test -z "$GIT_DIFFTOOL_NO_PROMPT" +} + +# 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" + + # $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)" \ + "$LOCAL" "$REMOTE" \ + > /dev/null 2>&1 + ;; + + kompare) + "$merge_tool_path" "$LOCAL" "$REMOTE" + ;; + + tkdiff) + "$merge_tool_path" "$LOCAL" "$REMOTE" + ;; + + meld) + "$merge_tool_path" "$LOCAL" "$REMOTE" + ;; + + diffuse) + "$merge_tool_path" "$LOCAL" "$REMOTE" | cat + ;; + + vimdiff) + "$merge_tool_path" -d -c "wincmd l" "$LOCAL" "$REMOTE" + ;; + + gvimdiff) + "$merge_tool_path" -d -c "wincmd l" -f "$LOCAL" "$REMOTE" + ;; + + xxdiff) + "$merge_tool_path" \ + -R 'Accel.Search: "Ctrl+F"' \ + -R 'Accel.SearchForward: "Ctrl-G"' \ + "$LOCAL" "$REMOTE" + ;; + + opendiff) + "$merge_tool_path" "$LOCAL" "$REMOTE" | 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 +} + +# Verifies that (difftool|mergetool)..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..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 + vimdiff) + merge_tool_path=vim + ;; + gvimdiff) + merge_tool_path=gvim + ;; + 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 diffuse" + else + merge_tool_candidates="kdiff3 kompare tkdiff xxdiff meld gvimdiff diffuse" + 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 diff --git a/git-difftool.perl b/git-difftool.perl new file mode 100755 index 0000000..8857ac8 --- /dev/null +++ b/git-difftool.perl @@ -0,0 +1,76 @@ +#!/usr/bin/env perl +# 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. +# Any arguments that are unknown to this script are forwarded to 'git diff'. + +use strict; +use warnings; +use Cwd qw(abs_path); +use File::Basename qw(dirname); + +my $DIR = abs_path(dirname($0)); + + +sub usage +{ + print << 'USAGE'; +usage: git difftool [--tool=] [-y|--no-prompt] ["git diff" options] +USAGE + exit 1; +} + +sub setup_environment +{ + $ENV{PATH} = "$DIR:$ENV{PATH}"; + $ENV{GIT_PAGER} = ''; + $ENV{GIT_EXTERNAL_DIFF} = 'git-difftool--helper'; +} + +sub exe +{ + my $exe = shift; + if ($^O eq 'MSWin32' || $^O eq 'msys') { + return "$exe.exe"; + } + return $exe; +} + +sub generate_command +{ + my @command = (exe('git'), 'diff'); + my $skip_next = 0; + my $idx = -1; + for my $arg (@ARGV) { + $idx++; + if ($skip_next) { + $skip_next = 0; + next; + } + if ($arg eq '-t' || $arg eq '--tool') { + usage() if $#ARGV <= $idx; + $ENV{GIT_DIFF_TOOL} = $ARGV[$idx + 1]; + $skip_next = 1; + next; + } + if ($arg =~ /^--tool=/) { + $ENV{GIT_DIFF_TOOL} = substr($arg, 7); + next; + } + if ($arg eq '-y' || $arg eq '--no-prompt') { + $ENV{GIT_DIFFTOOL_NO_PROMPT} = 'true'; + next; + } + if ($arg eq '-h' || $arg eq '--help') { + usage(); + } + push @command, $arg; + } + return @command +} + +setup_environment(); +exec(generate_command()); -- cgit v0.10.2-6-g49f6 From f92f2038a5192ac5fc1bb4f38c49906aa45b3f1e Mon Sep 17 00:00:00 2001 From: David Aguilar Date: Tue, 7 Apr 2009 16:30:53 -0700 Subject: difftool: add various git-difftool tests t7800-difftool.sh tests the various command-line flags, git-config variables, and environment settings supported by git-difftool. Signed-off-by: David Aguilar Signed-off-by: Junio C Hamano diff --git a/t/t7800-difftool.sh b/t/t7800-difftool.sh new file mode 100755 index 0000000..2699226 --- /dev/null +++ b/t/t7800-difftool.sh @@ -0,0 +1,147 @@ +#!/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 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_NO_PROMPT + git config diff.tool test-tool && + git config difftool.test-tool.cmd 'cat $LOCAL' +} + +# 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..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 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..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 -- cgit v0.10.2-6-g49f6 From a904392eaeee1629c0ac14dae8e579bb8497636a Mon Sep 17 00:00:00 2001 From: David Aguilar Date: Tue, 7 Apr 2009 01:21:22 -0700 Subject: difftool: add support for a difftool.prompt config variable difftool now supports difftool.prompt so that users do not have to pass --no-prompt or hit enter each time a diff tool is launched. The --prompt flag overrides the configuration variable. Signed-off-by: David Aguilar Signed-off-by: Junio C Hamano diff --git a/Documentation/config.txt b/Documentation/config.txt index 94ef1a6..d427daf 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -685,6 +685,9 @@ difftool..cmd:: 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 diff --git a/Documentation/git-difftool.txt b/Documentation/git-difftool.txt index af68466..15b247b 100644 --- a/Documentation/git-difftool.txt +++ b/Documentation/git-difftool.txt @@ -7,7 +7,7 @@ git-difftool - Show changes using common diff tools SYNOPSIS -------- -'git difftool' [--tool=] [-y|--no-prompt] [<'git diff' options>] +'git difftool' [--tool=] [-y|--no-prompt|--prompt] [<'git diff' options>] DESCRIPTION ----------- @@ -21,6 +21,11 @@ OPTIONS --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=:: Use the diff tool specified by . @@ -72,6 +77,9 @@ difftool..cmd:: + See the `--tool=` option above for more details. +difftool.prompt:: + Prompt before each invocation of the diff tool. + SEE ALSO -------- linkgit:git-diff[1]:: diff --git a/git-difftool--helper.sh b/git-difftool--helper.sh index fc61416..f3c27d8 100755 --- a/git-difftool--helper.sh +++ b/git-difftool--helper.sh @@ -5,9 +5,15 @@ # # Copyright (c) 2009 David Aguilar -# Set GIT_DIFFTOOL_NO_PROMPT to bypass the per-file prompt. +# difftool.prompt controls the default prompt/no-prompt behavior +# and is overridden with $GIT_DIFFTOOL*_PROMPT. should_prompt () { - test -z "$GIT_DIFFTOOL_NO_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 } # This function prepares temporary files and launches the appropriate diff --git a/git-difftool.perl b/git-difftool.perl index 8857ac8..948ff7f 100755 --- a/git-difftool.perl +++ b/git-difftool.perl @@ -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; @@ -62,6 +65,12 @@ sub generate_command } if ($arg eq '-y' || $arg eq '--no-prompt') { $ENV{GIT_DIFFTOOL_NO_PROMPT} = 'true'; + delete $ENV{GIT_DIFFTOOL_PROMPT}; + next; + } + if ($arg eq '--prompt') { + $ENV{GIT_DIFFTOOL_PROMPT} = 'true'; + delete $ENV{GIT_DIFFTOOL_NO_PROMPT}; next; } if ($arg eq '-h' || $arg eq '--help') { diff --git a/t/t7800-difftool.sh b/t/t7800-difftool.sh index 2699226..2586f86 100755 --- a/t/t7800-difftool.sh +++ b/t/t7800-difftool.sh @@ -15,6 +15,7 @@ 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 @@ -26,11 +27,18 @@ restore_test_defaults() 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 && @@ -116,6 +124,62 @@ test_expect_success 'GIT_DIFFTOOL_NO_PROMPT variable' ' 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' ' -- cgit v0.10.2-6-g49f6 From e2dc2de917778a0601564e238c3cd61614f55e5f Mon Sep 17 00:00:00 2001 From: David Aguilar Date: Mon, 6 Apr 2009 01:31:27 -0700 Subject: bash completion: add git-difftool This adds completion for difftool's --tool flag. The known diff tool names were also consolidated into a single variable. Signed-off-by: David Aguilar Signed-off-by: Junio C Hamano diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index e099ed4..069e19e 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -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,11 +1192,7 @@ _git_mergetool () local cur="${COMP_WORDS[COMP_CWORD]}" case "$cur" in --tool=*) - __gitcomp " - kdiff3 tkdiff meld xxdiff emerge - vimdiff gvimdiff ecmerge diffuse - opendiff - " "" "${cur##--tool=}" + __gitcomp "$__git_mergetools_common tortoisemerge" "" "${cur##--tool=}" return ;; --*) @@ -1901,6 +1917,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 ;; -- cgit v0.10.2-6-g49f6 From 9a62d72dfa833f98dd0730b3d5136f56d637a5c3 Mon Sep 17 00:00:00 2001 From: David Aguilar Date: Mon, 6 Apr 2009 01:31:28 -0700 Subject: mergetool: use $( ... ) instead of `backticks` This makes mergetool consistent with Documentation/CodingGuidelines. Signed-off-by: David Aguilar Signed-off-by: Junio C Hamano diff --git a/git-mergetool.sh b/git-mergetool.sh index b4d2432..cceebb7 100755 --- a/git-mergetool.sh +++ b/git-mergetool.sh @@ -137,7 +137,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 +156,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" @@ -318,7 +318,7 @@ do -t|--tool*) case "$#,$1" in *,*=*) - merge_tool=`expr "z$1" : 'z-[^=]*=\(.*\)'` + merge_tool=$(expr "z$1" : 'z-[^=]*=\(.*\)') ;; 1,*) usage ;; @@ -366,7 +366,7 @@ valid_tool() { } init_merge_tool_path() { - merge_tool_path=`git config mergetool.$1.path` + merge_tool_path=$(git config mergetool.$1.path) if test -z "$merge_tool_path" ; then case "$1" in vimdiff) @@ -403,7 +403,7 @@ prompt_after_failed_merge() { } if test -z "$merge_tool"; then - merge_tool=`git config merge.tool` + 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..." @@ -463,7 +463,7 @@ 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 -- cgit v0.10.2-6-g49f6 From 21d0ba7ebb0c6b6c6ad844f8a40fff8dd4c0b105 Mon Sep 17 00:00:00 2001 From: David Aguilar Date: Wed, 8 Apr 2009 00:17:20 -0700 Subject: difftool/mergetool: refactor commands to use git-mergetool--lib This consolidates the common functionality from git-mergetool and git-difftool--helper into a single git-mergetool--lib scriptlet. Signed-off-by: David Aguilar Signed-off-by: Junio C Hamano diff --git a/.gitignore b/.gitignore index a36da9d..757c7f0 100644 --- a/.gitignore +++ b/.gitignore @@ -80,6 +80,7 @@ git-merge-recursive git-merge-resolve git-merge-subtree git-mergetool +git-mergetool--lib git-mktag git-mktree git-name-rev diff --git a/Documentation/git-mergetool--lib.txt b/Documentation/git-mergetool--lib.txt new file mode 100644 index 0000000..3d57031 --- /dev/null +++ b/Documentation/git-mergetool--lib.txt @@ -0,0 +1,56 @@ +git-mergetool--lib(1) +===================== + +NAME +---- +git-mergetool--lib - Common git merge tool shell scriptlets + +SYNOPSIS +-------- +'. "$(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 it, your script should set up a few variables; +`TOOL_MODE` is used to define the operation mode for various +functions. '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. + '$merge_tool', '$merge_tool_path', and for custom commands, + '$merge_tool_cmd', must be defined prior to calling + run_merge_tool. Additionally, '$MERGED', '$LOCAL', '$REMOTE', + and '$BASE' must be defined for use by the merge tool. + +Author +------ +Written by David Aguilar + +Documentation +-------------- +Documentation by David Aguilar and the git-list . + +GIT +--- +Part of the linkgit:git[1] suite diff --git a/Makefile b/Makefile index a80055f..3e56274 100644 --- a/Makefile +++ b/Makefile @@ -284,6 +284,7 @@ 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 diff --git a/git-difftool--helper.sh b/git-difftool--helper.sh index f3c27d8..b450036 100755 --- a/git-difftool--helper.sh +++ b/git-difftool--helper.sh @@ -5,6 +5,10 @@ # # 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 () { @@ -16,8 +20,7 @@ should_prompt () { fi } -# This function prepares temporary files and launches the appropriate -# merge tool. +# 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 @@ -37,187 +40,16 @@ launch_merge_tool () { 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)" \ - "$LOCAL" "$REMOTE" \ - > /dev/null 2>&1 - ;; - - kompare) - "$merge_tool_path" "$LOCAL" "$REMOTE" - ;; - - tkdiff) - "$merge_tool_path" "$LOCAL" "$REMOTE" - ;; - - meld) - "$merge_tool_path" "$LOCAL" "$REMOTE" - ;; - - diffuse) - "$merge_tool_path" "$LOCAL" "$REMOTE" | cat - ;; - - vimdiff) - "$merge_tool_path" -d -c "wincmd l" "$LOCAL" "$REMOTE" - ;; - - gvimdiff) - "$merge_tool_path" -d -c "wincmd l" -f "$LOCAL" "$REMOTE" - ;; - - xxdiff) - "$merge_tool_path" \ - -R 'Accel.Search: "Ctrl+F"' \ - -R 'Accel.SearchForward: "Ctrl-G"' \ - "$LOCAL" "$REMOTE" - ;; - - opendiff) - "$merge_tool_path" "$LOCAL" "$REMOTE" | 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 -} - -# Verifies that (difftool|mergetool)..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..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 - vimdiff) - merge_tool_path=vim - ;; - gvimdiff) - merge_tool_path=gvim - ;; - emerge) - merge_tool_path=emacs - ;; - *) - merge_tool_path="$1" - ;; - esac - fi + 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 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 diffuse" - else - merge_tool_candidates="kdiff3 kompare tkdiff xxdiff meld gvimdiff diffuse" - 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 - +merge_tool=$(get_merge_tool "$merge_tool") || exit +merge_tool_cmd="$(get_merge_tool_cmd "$merge_tool")" +merge_tool_path="$(get_merge_tool_path "$merge_tool")" || exit # Launch the merge tool on each path provided by 'git diff' while test $# -gt 6 diff --git a/git-mergetool--lib.sh b/git-mergetool--lib.sh new file mode 100644 index 0000000..c5db24e --- /dev/null +++ b/git-mergetool--lib.sh @@ -0,0 +1,378 @@ +# 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 () { + if test -n "$2"; then + echo "$2" + else + case "$1" in + vimdiff) + path=vim + ;; + gvimdiff) + path=gvim + ;; + emerge) + path=emacs + ;; + *) + path="$1" + ;; + esac + echo "$path" + fi +} + +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 () { + diff_mode && + custom_cmd="$(git config difftool.$1.cmd)" + test -z "$custom_cmd" && + custom_cmd="$(git config mergetool.$1.cmd)" + test -n "$custom_cmd" && + echo "$custom_cmd" +} + +run_merge_tool () { + 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 + ;; + *) + if test -z "$merge_tool_cmd"; then + if merge_mode; then + status=1 + fi + break + fi + if merge_mode; 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 + 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 + merge_tool="$i" + break + fi + done + + if test -z "$merge_tool" ; then + echo >&2 "No known merge resolution program available." + return 1 + fi + echo "$merge_tool" +} + +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 + tool=$(git config diff.tool) + fi + if test -z "$tool"; then + 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 "$tool" +} + +get_merge_tool_path () { + # 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 + if diff_mode; then + merge_tool_path=$(git config difftool."$merge_tool".path) + fi + if test -z "$merge_tool_path"; then + merge_tool_path=$(git config mergetool."$merge_tool".path) + fi + merge_tool_path="$(translate_merge_tool_path "$merge_tool" "$merge_tool_path")" + if test -z "$merge_tool_cmd" && ! 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 () { + merge_tool="$1" + # Check if a merge tool has been configured + if test -z "$merge_tool"; then + merge_tool=$(get_configured_merge_tool) + fi + # 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" +} diff --git a/git-mergetool.sh b/git-mergetool.sh index cceebb7..efa31a2 100755 --- a/git-mergetool.sh +++ b/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")" : '\([^ ]*\) ') @@ -188,107 +174,11 @@ 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" -d -c "wincmd l" "$LOCAL" "$MERGED" "$REMOTE" - check_unchanged - ;; - gvimdiff) - touch "$BACKUP" - "$merge_tool_path" -d -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=$? - ;; - 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 - ;; - *) - 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 + present=false + base_present && + present=true + + if ! run_merge_tool "$merge_tool" "$present"; then echo "merge of $MERGED failed" 1>&2 mv -- "$BACKUP" "$MERGED" @@ -347,44 +237,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 | tortoisemerge) - ;; # 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 - vimdiff) - merge_tool_path=vim - ;; - gvimdiff) - merge_tool_path=gvim - ;; - 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) ? " @@ -402,62 +254,12 @@ prompt_after_failed_merge() { done } -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 tortoisemerge gvimdiff diffuse" - else - merge_tool_candidates="kdiff3 tkdiff xxdiff meld tortoisemerge gvimdiff diffuse" - 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 -fi +merge_tool=$(get_merge_tool "$merge_tool") || exit +merge_tool_cmd="$(get_merge_tool_cmd "$merge_tool")" +merge_tool_path="$(get_merge_tool_path "$merge_tool")" || exit +merge_keep_backup="$(git config --bool merge.keepBackup || echo true)" +merge_keep_temporaries="$(git config --bool mergetool.keepTemporaries || echo false)" +merge_tool_trust_exit_code="$(git config --bool mergetool."$merge_tool".trustExitCode || echo false)" last_status=0 rollup_status=0 -- cgit v0.10.2-6-g49f6 From 70af4e9bef988a98061237c78cbd0a71d8de48bb Mon Sep 17 00:00:00 2001 From: Ferry Huberts Date: Fri, 10 Apr 2009 21:33:57 +0200 Subject: Fix misspelled mergetool.keepBackup In several places mergetool.keepBackup was misspelled as merge.keepBackup. Signed-off-by: Ferry Huberts Signed-off-by: Junio C Hamano diff --git a/git-mergetool.sh b/git-mergetool.sh index efa31a2..2e3e02b 100755 --- a/git-mergetool.sh +++ b/git-mergetool.sh @@ -257,7 +257,7 @@ prompt_after_failed_merge() { merge_tool=$(get_merge_tool "$merge_tool") || exit merge_tool_cmd="$(get_merge_tool_cmd "$merge_tool")" merge_tool_path="$(get_merge_tool_path "$merge_tool")" || exit -merge_keep_backup="$(git config --bool merge.keepBackup || echo true)" +merge_keep_backup="$(git config --bool mergetool.keepBackup || echo true)" merge_keep_temporaries="$(git config --bool mergetool.keepTemporaries || echo false)" merge_tool_trust_exit_code="$(git config --bool mergetool."$merge_tool".trustExitCode || echo false)" -- cgit v0.10.2-6-g49f6 From 47d65924a69576bd9f3254f7055de6b37a359596 Mon Sep 17 00:00:00 2001 From: David Aguilar Date: Sat, 11 Apr 2009 20:41:56 -0700 Subject: mergetool--lib: simplify API usage by removing more global variables The mergetool--lib scriplet was tricky to use because it relied upon the existance of several global shell variables. This removes more global variables so that things are simpler for callers. A side effect is that some variables are recomputed each time run_merge_tool() is called, but the overhead for recomputing them is justified by the simpler implementation. Signed-off-by: David Aguilar Signed-off-by: Junio C Hamano diff --git a/Documentation/git-mergetool--lib.txt b/Documentation/git-mergetool--lib.txt index 3d57031..78eb03f 100644 --- a/Documentation/git-mergetool--lib.txt +++ b/Documentation/git-mergetool--lib.txt @@ -7,7 +7,7 @@ git-mergetool--lib - Common git merge tool shell scriptlets SYNOPSIS -------- -'. "$(git --exec-path)/git-mergetool--lib"' +'TOOL_MODE=(diff|merge) . "$(git --exec-path)/git-mergetool--lib"' DESCRIPTION ----------- @@ -20,14 +20,14 @@ 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 it, your script should set up a few variables; -`TOOL_MODE` is used to define the operation mode for various -functions. 'diff' and 'merge' are valid values. +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 + returns a merge tool. get_merge_tool_cmd:: returns the custom command for a merge tool. @@ -38,10 +38,8 @@ get_merge_tool_path:: run_merge_tool:: launches a merge tool given the tool name and a true/false flag to indicate whether a merge base is present. - '$merge_tool', '$merge_tool_path', and for custom commands, - '$merge_tool_cmd', must be defined prior to calling - run_merge_tool. Additionally, '$MERGED', '$LOCAL', '$REMOTE', - and '$BASE' must be defined for use by the merge tool. + '$MERGED', '$LOCAL', '$REMOTE', and '$BASE' must be defined + for use by the merge tool. Author ------ diff --git a/git-difftool--helper.sh b/git-difftool--helper.sh index b450036..57e8e32 100755 --- a/git-difftool--helper.sh +++ b/git-difftool--helper.sh @@ -47,9 +47,9 @@ launch_merge_tool () { test -n "$GIT_MERGE_TOOL" && merge_tool="$GIT_MERGE_TOOL" test -n "$GIT_DIFF_TOOL" && merge_tool="$GIT_DIFF_TOOL" -merge_tool=$(get_merge_tool "$merge_tool") || exit -merge_tool_cmd="$(get_merge_tool_cmd "$merge_tool")" -merge_tool_path="$(get_merge_tool_path "$merge_tool")" || exit +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 diff --git a/git-mergetool--lib.sh b/git-mergetool--lib.sh index c5db24e..a16a279 100644 --- a/git-mergetool--lib.sh +++ b/git-mergetool--lib.sh @@ -8,25 +8,20 @@ merge_mode() { } translate_merge_tool_path () { - if test -n "$2"; then - echo "$2" - else - case "$1" in - vimdiff) - path=vim - ;; - gvimdiff) - path=gvim - ;; - emerge) - path=emacs - ;; - *) - path="$1" - ;; - esac - echo "$path" - fi + case "$1" in + vimdiff) + echo vim + ;; + gvimdiff) + echo gvim + ;; + emerge) + echo emacs + ;; + *) + echo "$1" + ;; + esac } check_unchanged () { @@ -69,15 +64,22 @@ valid_tool () { } get_merge_tool_cmd () { - diff_mode && - custom_cmd="$(git config difftool.$1.cmd)" - test -z "$custom_cmd" && - custom_cmd="$(git config mergetool.$1.cmd)" - test -n "$custom_cmd" && - echo "$custom_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 @@ -103,9 +105,9 @@ run_merge_tool () { status=$? else ("$merge_tool_path" --auto \ - --L1 "$MERGED (A)" \ - --L2 "$MERGED (B)" "$LOCAL" "$REMOTE" \ - > /dev/null 2>&1) + --L1 "$MERGED (A)" \ + --L2 "$MERGED (B)" "$LOCAL" "$REMOTE" \ + > /dev/null 2>&1) fi ;; kompare) @@ -262,6 +264,7 @@ run_merge_tool () { fi ;; *) + merge_tool_cmd="$(get_merge_tool_cmd "$1")" if test -z "$merge_tool_cmd"; then if merge_mode; then status=1 @@ -269,7 +272,9 @@ run_merge_tool () { break fi if merge_mode; then - if test "$merge_tool_trust_exit_code" = "false"; 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 @@ -315,64 +320,66 @@ guess_merge_tool () { do merge_tool_path="$(translate_merge_tool_path "$i")" if type "$merge_tool_path" > /dev/null 2>&1; then - merge_tool="$i" - break + echo "$i" + return 0 fi done - if test -z "$merge_tool" ; then - echo >&2 "No known merge resolution program available." - return 1 - fi - echo "$merge_tool" + 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 - tool=$(git config diff.tool) - fi - if test -z "$tool"; then - tool=$(git config merge.tool) + 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 "$tool" + 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) + 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=$(git config mergetool."$merge_tool".path) + merge_tool_path="$(translate_merge_tool_path "$merge_tool")" fi - merge_tool_path="$(translate_merge_tool_path "$merge_tool" "$merge_tool_path")" - if test -z "$merge_tool_cmd" && ! type "$merge_tool_path" > /dev/null 2>&1; then - echo >&2 "The $TOOL_MODE tool $merge_tool is not available as '$merge_tool_path'" + 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 () { - merge_tool="$1" # Check if a merge tool has been configured - if test -z "$merge_tool"; then - merge_tool=$(get_configured_merge_tool) - fi + 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 + merge_tool="$(guess_merge_tool)" || exit fi echo "$merge_tool" } diff --git a/git-mergetool.sh b/git-mergetool.sh index 2e3e02b..b52a741 100755 --- a/git-mergetool.sh +++ b/git-mergetool.sh @@ -174,9 +174,11 @@ merge_file () { read ans fi - present=false - base_present && - present=true + 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 @@ -254,12 +256,11 @@ prompt_after_failed_merge() { done } -merge_tool=$(get_merge_tool "$merge_tool") || exit -merge_tool_cmd="$(get_merge_tool_cmd "$merge_tool")" -merge_tool_path="$(get_merge_tool_path "$merge_tool")" || exit +if test -z "$merge_tool"; then + 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)" -merge_tool_trust_exit_code="$(git config --bool mergetool."$merge_tool".trustExitCode || echo false)" last_status=0 rollup_status=0 -- cgit v0.10.2-6-g49f6