Code

4b0daec5a7d0d90c18967974b87afbcc5fb6dc8b
[git.git] / contrib / difftool / git-difftool-helper
1 #!/bin/sh
2 # git-difftool-helper is a GIT_EXTERNAL_DIFF-compatible diff tool launcher.
3 # This script is typically launched by using the 'git difftool'
4 # convenience command.
5 #
6 # Copyright (c) 2009 David Aguilar
8 # Set GIT_DIFFTOOL_NO_PROMPT to bypass the per-file prompt.
9 should_prompt () {
10         test -z "$GIT_DIFFTOOL_NO_PROMPT"
11 }
13 # This function prepares temporary files and launches the appropriate
14 # merge tool.
15 launch_merge_tool () {
16         # Merged is the filename as it appears in the work tree
17         # Local is the contents of a/filename
18         # Remote is the contents of b/filename
19         # Custom merge tool commands might use $BASE so we provide it
20         MERGED="$1"
21         LOCAL="$2"
22         REMOTE="$3"
23         BASE="$1"
25         # $LOCAL and $REMOTE are temporary files so prompt
26         # the user with the real $MERGED name before launching $merge_tool.
27         if should_prompt; then
28                 printf "\nViewing: '$MERGED'\n"
29                 printf "Hit return to launch '%s': " "$merge_tool"
30                 read ans
31         fi
33         # Run the appropriate merge tool command
34         case "$merge_tool" in
35         kdiff3)
36                 basename=$(basename "$MERGED")
37                 "$merge_tool_path" --auto \
38                         --L1 "$basename (A)" \
39                         --L2 "$basename (B)" \
40                         "$LOCAL" "$REMOTE" \
41                         > /dev/null 2>&1
42                 ;;
44         kompare)
45                 "$merge_tool_path" "$LOCAL" "$REMOTE"
46                 ;;
48         tkdiff)
49                 "$merge_tool_path" "$LOCAL" "$REMOTE"
50                 ;;
52         meld)
53                 "$merge_tool_path" "$LOCAL" "$REMOTE"
54                 ;;
56         diffuse)
57                 "$merge_tool_path" "$LOCAL" "$REMOTE" | cat
58                 ;;
60         vimdiff)
61                 "$merge_tool_path" -d -c "wincmd l" "$LOCAL" "$REMOTE"
62                 ;;
64         gvimdiff)
65                 "$merge_tool_path" -d -c "wincmd l" -f "$LOCAL" "$REMOTE"
66                 ;;
68         xxdiff)
69                 "$merge_tool_path" \
70                         -R 'Accel.Search: "Ctrl+F"' \
71                         -R 'Accel.SearchForward: "Ctrl-G"' \
72                         "$LOCAL" "$REMOTE"
73                 ;;
75         opendiff)
76                 "$merge_tool_path" "$LOCAL" "$REMOTE" | cat
77                 ;;
79         ecmerge)
80                 "$merge_tool_path" "$LOCAL" "$REMOTE" \
81                         --default --mode=merge2 --to="$MERGED"
82                 ;;
84         emerge)
85                 "$merge_tool_path" -f emerge-files-command \
86                         "$LOCAL" "$REMOTE" "$(basename "$MERGED")"
87                 ;;
89         *)
90                 if test -n "$merge_tool_cmd"; then
91                         ( eval $merge_tool_cmd )
92                 fi
93                 ;;
94         esac
95 }
97 # Verifies that (difftool|mergetool).<tool>.cmd exists
98 valid_custom_tool() {
99         merge_tool_cmd="$(git config difftool.$1.cmd)"
100         test -z "$merge_tool_cmd" &&
101         merge_tool_cmd="$(git config mergetool.$1.cmd)"
102         test -n "$merge_tool_cmd"
105 # Verifies that the chosen merge tool is properly setup.
106 # Built-in merge tools are always valid.
107 valid_tool() {
108         case "$1" in
109         kdiff3 | kompare | tkdiff | xxdiff | meld | opendiff | emerge | vimdiff | gvimdiff | ecmerge)
110                 ;; # happy
111         *)
112                 if ! valid_custom_tool "$1"
113                 then
114                         return 1
115                 fi
116                 ;;
117         esac
120 # Sets up the merge_tool_path variable.
121 # This handles the difftool.<tool>.path configuration.
122 # This also falls back to mergetool defaults.
123 init_merge_tool_path() {
124         merge_tool_path=$(git config difftool."$1".path)
125         test -z "$merge_tool_path" &&
126         merge_tool_path=$(git config mergetool."$1".path)
127         if test -z "$merge_tool_path"; then
128                 case "$1" in
129                 vimdiff)
130                         merge_tool_path=vim
131                         ;;
132                 gvimdiff)
133                         merge_tool_path=gvim
134                         ;;
135                 emerge)
136                         merge_tool_path=emacs
137                         ;;
138                 *)
139                         merge_tool_path="$1"
140                         ;;
141                 esac
142         fi
145 # Allow GIT_DIFF_TOOL and GIT_MERGE_TOOL to provide default values
146 test -n "$GIT_MERGE_TOOL" && merge_tool="$GIT_MERGE_TOOL"
147 test -n "$GIT_DIFF_TOOL" && merge_tool="$GIT_DIFF_TOOL"
149 # If merge tool was not specified then use the diff.tool
150 # configuration variable.  If that's invalid then reset merge_tool.
151 # Fallback to merge.tool.
152 if test -z "$merge_tool"; then
153         merge_tool=$(git config diff.tool)
154         test -z "$merge_tool" &&
155         merge_tool=$(git config merge.tool)
156         if test -n "$merge_tool" && ! valid_tool "$merge_tool"; then
157                 echo >&2 "git config option diff.tool set to unknown tool: $merge_tool"
158                 echo >&2 "Resetting to default..."
159                 unset merge_tool
160         fi
161 fi
163 # Try to guess an appropriate merge tool if no tool has been set.
164 if test -z "$merge_tool"; then
165         # We have a $DISPLAY so try some common UNIX merge tools
166         if test -n "$DISPLAY"; then
167                 # If gnome then prefer meld, otherwise, prefer kdiff3 or kompare
168                 if test -n "$GNOME_DESKTOP_SESSION_ID" ; then
169                         merge_tool_candidates="meld kdiff3 kompare tkdiff xxdiff gvimdiff diffuse"
170                 else
171                         merge_tool_candidates="kdiff3 kompare tkdiff xxdiff meld gvimdiff diffuse"
172                 fi
173         fi
174         if echo "${VISUAL:-$EDITOR}" | grep 'emacs' > /dev/null 2>&1; then
175                 # $EDITOR is emacs so add emerge as a candidate
176                 merge_tool_candidates="$merge_tool_candidates emerge opendiff vimdiff"
177         elif echo "${VISUAL:-$EDITOR}" | grep 'vim' > /dev/null 2>&1; then
178                 # $EDITOR is vim so add vimdiff as a candidate
179                 merge_tool_candidates="$merge_tool_candidates vimdiff opendiff emerge"
180         else
181                 merge_tool_candidates="$merge_tool_candidates opendiff emerge vimdiff"
182         fi
183         echo "merge tool candidates: $merge_tool_candidates"
185         # Loop over each candidate and stop when a valid merge tool is found.
186         for i in $merge_tool_candidates
187         do
188                 init_merge_tool_path $i
189                 if type "$merge_tool_path" > /dev/null 2>&1; then
190                         merge_tool=$i
191                         break
192                 fi
193         done
195         if test -z "$merge_tool" ; then
196                 echo "No known merge resolution program available."
197                 exit 1
198         fi
200 else
201         # A merge tool has been set, so verify that it's valid.
202         if ! valid_tool "$merge_tool"; then
203                 echo >&2 "Unknown merge tool $merge_tool"
204                 exit 1
205         fi
207         init_merge_tool_path "$merge_tool"
209         if test -z "$merge_tool_cmd" && ! type "$merge_tool_path" > /dev/null 2>&1; then
210                 echo "The merge tool $merge_tool is not available as '$merge_tool_path'"
211                 exit 1
212         fi
213 fi
216 # Launch the merge tool on each path provided by 'git diff'
217 while test $# -gt 6
218 do
219         launch_merge_tool "$1" "$2" "$5"
220         shift 7
221 done