mergetool--lib: Sort tools alphabetically for easier lookup
[git/git.git] / git-mergetool--lib.sh
CommitLineData
02e51243 1#!/bin/sh
21d0ba7e
DA
2# git-mergetool--lib is a library for common merge tool functions
3diff_mode() {
4 test "$TOOL_MODE" = diff
5}
6
7merge_mode() {
8 test "$TOOL_MODE" = merge
9}
10
11translate_merge_tool_path () {
47d65924 12 case "$1" in
aa03f604
SS
13 araxis)
14 echo compare
47d65924
DA
15 ;;
16 emerge)
17 echo emacs
18 ;;
aa03f604
SS
19 gvimdiff|gvimdiff2)
20 echo gvim
21 ;;
22 vimdiff|vimdiff2)
23 echo vim
b6f0621a 24 ;;
47d65924
DA
25 *)
26 echo "$1"
27 ;;
28 esac
21d0ba7e
DA
29}
30
31check_unchanged () {
32 if test "$MERGED" -nt "$BACKUP"; then
33 status=0
34 else
35 while true; do
36 echo "$MERGED seems unchanged."
37 printf "Was the merge successful? [y/n] "
af314714 38 read answer
21d0ba7e
DA
39 case "$answer" in
40 y*|Y*) status=0; break ;;
41 n*|N*) status=1; break ;;
42 esac
43 done
44 fi
45}
46
47valid_tool () {
48 case "$1" in
aa03f604
SS
49 araxis | diffuse | ecmerge | emerge | gvimdiff | gvimdiff2 | \
50 kdiff3 | meld | opendiff | p4merge | tkdiff | vimdiff | vimdiff2 | xxdiff)
21d0ba7e 51 ;; # happy
aa03f604
SS
52 kompare)
53 if ! diff_mode; then
21d0ba7e
DA
54 return 1
55 fi
56 ;;
aa03f604
SS
57 tortoisemerge)
58 if ! merge_mode; then
21d0ba7e
DA
59 return 1
60 fi
61 ;;
62 *)
63 if test -z "$(get_merge_tool_cmd "$1")"; then
64 return 1
65 fi
66 ;;
67 esac
68}
69
70get_merge_tool_cmd () {
47d65924
DA
71 # Prints the custom command for a merge tool
72 if test -n "$1"; then
73 merge_tool="$1"
74 else
75 merge_tool="$(get_merge_tool)"
76 fi
77 if diff_mode; then
78 echo "$(git config difftool.$merge_tool.cmd ||
79 git config mergetool.$merge_tool.cmd)"
80 else
81 echo "$(git config mergetool.$merge_tool.cmd)"
82 fi
21d0ba7e
DA
83}
84
85run_merge_tool () {
47d65924 86 merge_tool_path="$(get_merge_tool_path "$1")" || exit
21d0ba7e
DA
87 base_present="$2"
88 status=0
89
90 case "$1" in
aa03f604 91 araxis)
21d0ba7e 92 if merge_mode; then
aa03f604 93 touch "$BACKUP"
21d0ba7e 94 if $base_present; then
aa03f604
SS
95 "$merge_tool_path" -wait -merge -3 -a1 \
96 "$BASE" "$LOCAL" "$REMOTE" "$MERGED" \
97 >/dev/null 2>&1
21d0ba7e 98 else
aa03f604
SS
99 "$merge_tool_path" -wait -2 \
100 "$LOCAL" "$REMOTE" "$MERGED" \
101 >/dev/null 2>&1
21d0ba7e 102 fi
aa03f604 103 check_unchanged
21d0ba7e 104 else
aa03f604
SS
105 "$merge_tool_path" -wait -2 "$LOCAL" "$REMOTE" \
106 >/dev/null 2>&1
21d0ba7e
DA
107 fi
108 ;;
aa03f604 109 diffuse)
21d0ba7e 110 if merge_mode; then
aa03f604 111 touch "$BACKUP"
21d0ba7e 112 if $base_present; then
aa03f604
SS
113 "$merge_tool_path" \
114 "$LOCAL" "$MERGED" "$REMOTE" \
115 "$BASE" | cat
21d0ba7e
DA
116 else
117 "$merge_tool_path" \
aa03f604 118 "$LOCAL" "$MERGED" "$REMOTE" | cat
21d0ba7e 119 fi
aa03f604 120 check_unchanged
21d0ba7e 121 else
aa03f604 122 "$merge_tool_path" "$LOCAL" "$REMOTE" | cat
21d0ba7e
DA
123 fi
124 ;;
aa03f604 125 ecmerge)
c8998b48 126 if merge_mode; then
aa03f604 127 touch "$BACKUP"
c8998b48 128 if $base_present; then
aa03f604
SS
129 "$merge_tool_path" "$BASE" "$LOCAL" "$REMOTE" \
130 --default --mode=merge3 --to="$MERGED"
c8998b48 131 else
aa03f604
SS
132 "$merge_tool_path" "$LOCAL" "$REMOTE" \
133 --default --mode=merge2 --to="$MERGED"
c8998b48
SC
134 fi
135 check_unchanged
136 else
aa03f604
SS
137 "$merge_tool_path" --default --mode=diff2 \
138 "$LOCAL" "$REMOTE"
21d0ba7e
DA
139 fi
140 ;;
aa03f604 141 emerge)
21d0ba7e 142 if merge_mode; then
21d0ba7e
DA
143 if $base_present; then
144 "$merge_tool_path" \
aa03f604
SS
145 -f emerge-files-with-ancestor-command \
146 "$LOCAL" "$REMOTE" "$BASE" \
147 "$(basename "$MERGED")"
21d0ba7e
DA
148 else
149 "$merge_tool_path" \
aa03f604
SS
150 -f emerge-files-command \
151 "$LOCAL" "$REMOTE" \
152 "$(basename "$MERGED")"
21d0ba7e 153 fi
aa03f604 154 status=$?
21d0ba7e 155 else
aa03f604
SS
156 "$merge_tool_path" -f emerge-files-command \
157 "$LOCAL" "$REMOTE"
21d0ba7e
DA
158 fi
159 ;;
aa03f604 160 gvimdiff|vimdiff)
21d0ba7e
DA
161 if merge_mode; then
162 touch "$BACKUP"
829ef383
DM
163 if $base_present; then
164 "$merge_tool_path" -f -d -c "wincmd J" \
165 "$MERGED" "$LOCAL" "$BASE" "$REMOTE"
166 else
167 "$merge_tool_path" -f -d -c "wincmd l" \
168 "$LOCAL" "$MERGED" "$REMOTE"
169 fi
21d0ba7e
DA
170 check_unchanged
171 else
ae69fd04 172 "$merge_tool_path" -f -d -c "wincmd l" \
21d0ba7e
DA
173 "$LOCAL" "$REMOTE"
174 fi
175 ;;
aa03f604 176 gvimdiff2|vimdiff2)
00086690
DM
177 if merge_mode; then
178 touch "$BACKUP"
179 "$merge_tool_path" -f -d -c "wincmd l" \
180 "$LOCAL" "$MERGED" "$REMOTE"
181 check_unchanged
182 else
183 "$merge_tool_path" -f -d -c "wincmd l" \
184 "$LOCAL" "$REMOTE"
185 fi
186 ;;
aa03f604 187 kdiff3)
21d0ba7e 188 if merge_mode; then
21d0ba7e 189 if $base_present; then
aa03f604
SS
190 ("$merge_tool_path" --auto \
191 --L1 "$MERGED (Base)" \
192 --L2 "$MERGED (Local)" \
193 --L3 "$MERGED (Remote)" \
194 -o "$MERGED" \
195 "$BASE" "$LOCAL" "$REMOTE" \
196 > /dev/null 2>&1)
21d0ba7e 197 else
aa03f604
SS
198 ("$merge_tool_path" --auto \
199 --L1 "$MERGED (Local)" \
200 --L2 "$MERGED (Remote)" \
201 -o "$MERGED" \
202 "$LOCAL" "$REMOTE" \
203 > /dev/null 2>&1)
21d0ba7e 204 fi
aa03f604
SS
205 status=$?
206 else
207 ("$merge_tool_path" --auto \
208 --L1 "$MERGED (A)" \
209 --L2 "$MERGED (B)" "$LOCAL" "$REMOTE" \
210 > /dev/null 2>&1)
211 fi
212 ;;
213 kompare)
214 "$merge_tool_path" "$LOCAL" "$REMOTE"
215 ;;
216 meld)
217 if merge_mode; then
218 touch "$BACKUP"
219 "$merge_tool_path" "$LOCAL" "$MERGED" "$REMOTE"
21d0ba7e
DA
220 check_unchanged
221 else
aa03f604 222 "$merge_tool_path" "$LOCAL" "$REMOTE"
21d0ba7e
DA
223 fi
224 ;;
225 opendiff)
226 if merge_mode; then
227 touch "$BACKUP"
228 if $base_present; then
229 "$merge_tool_path" "$LOCAL" "$REMOTE" \
230 -ancestor "$BASE" \
231 -merge "$MERGED" | cat
232 else
233 "$merge_tool_path" "$LOCAL" "$REMOTE" \
234 -merge "$MERGED" | cat
235 fi
236 check_unchanged
237 else
238 "$merge_tool_path" "$LOCAL" "$REMOTE" | cat
239 fi
240 ;;
aa03f604 241 p4merge)
21d0ba7e 242 if merge_mode; then
aa03f604 243 touch "$BACKUP"
21d0ba7e 244 if $base_present; then
aa03f604 245 "$merge_tool_path" "$BASE" "$LOCAL" "$REMOTE" "$MERGED"
21d0ba7e 246 else
aa03f604 247 "$merge_tool_path" "$LOCAL" "$LOCAL" "$REMOTE" "$MERGED"
21d0ba7e
DA
248 fi
249 check_unchanged
250 else
aa03f604 251 "$merge_tool_path" "$LOCAL" "$REMOTE"
21d0ba7e
DA
252 fi
253 ;;
aa03f604 254 tkdiff)
21d0ba7e
DA
255 if merge_mode; then
256 if $base_present; then
aa03f604
SS
257 "$merge_tool_path" -a "$BASE" \
258 -o "$MERGED" "$LOCAL" "$REMOTE"
21d0ba7e
DA
259 else
260 "$merge_tool_path" \
aa03f604 261 -o "$MERGED" "$LOCAL" "$REMOTE"
21d0ba7e
DA
262 fi
263 status=$?
264 else
aa03f604 265 "$merge_tool_path" "$LOCAL" "$REMOTE"
21d0ba7e
DA
266 fi
267 ;;
268 tortoisemerge)
269 if $base_present; then
270 touch "$BACKUP"
271 "$merge_tool_path" \
272 -base:"$BASE" -mine:"$LOCAL" \
273 -theirs:"$REMOTE" -merged:"$MERGED"
274 check_unchanged
275 else
276 echo "TortoiseMerge cannot be used without a base" 1>&2
277 status=1
278 fi
279 ;;
aa03f604 280 xxdiff)
b6f0621a
DA
281 if merge_mode; then
282 touch "$BACKUP"
283 if $base_present; then
aa03f604
SS
284 "$merge_tool_path" -X --show-merged-pane \
285 -R 'Accel.SaveAsMerged: "Ctrl-S"' \
286 -R 'Accel.Search: "Ctrl+F"' \
287 -R 'Accel.SearchForward: "Ctrl-G"' \
288 --merged-file "$MERGED" \
289 "$LOCAL" "$BASE" "$REMOTE"
b6f0621a 290 else
aa03f604
SS
291 "$merge_tool_path" -X $extra \
292 -R 'Accel.SaveAsMerged: "Ctrl-S"' \
293 -R 'Accel.Search: "Ctrl+F"' \
294 -R 'Accel.SearchForward: "Ctrl-G"' \
295 --merged-file "$MERGED" \
296 "$LOCAL" "$REMOTE"
b6f0621a
DA
297 fi
298 check_unchanged
299 else
aa03f604
SS
300 "$merge_tool_path" \
301 -R 'Accel.Search: "Ctrl+F"' \
302 -R 'Accel.SearchForward: "Ctrl-G"' \
303 "$LOCAL" "$REMOTE"
b6f0621a
DA
304 fi
305 ;;
21d0ba7e 306 *)
47d65924 307 merge_tool_cmd="$(get_merge_tool_cmd "$1")"
21d0ba7e
DA
308 if test -z "$merge_tool_cmd"; then
309 if merge_mode; then
310 status=1
311 fi
312 break
313 fi
314 if merge_mode; then
47d65924
DA
315 trust_exit_code="$(git config --bool \
316 mergetool."$1".trustExitCode || echo false)"
317 if test "$trust_exit_code" = "false"; then
21d0ba7e
DA
318 touch "$BACKUP"
319 ( eval $merge_tool_cmd )
320 check_unchanged
321 else
322 ( eval $merge_tool_cmd )
323 status=$?
324 fi
325 else
326 ( eval $merge_tool_cmd )
327 fi
328 ;;
329 esac
330 return $status
331}
332
333guess_merge_tool () {
334 if merge_mode; then
335 tools="tortoisemerge"
336 else
337 tools="kompare"
338 fi
339 if test -n "$DISPLAY"; then
340 if test -n "$GNOME_DESKTOP_SESSION_ID" ; then
341 tools="meld opendiff kdiff3 tkdiff xxdiff $tools"
342 else
343 tools="opendiff kdiff3 tkdiff xxdiff meld $tools"
344 fi
c8998b48 345 tools="$tools gvimdiff diffuse ecmerge p4merge araxis"
21d0ba7e 346 fi
7b104229
RS
347 case "${VISUAL:-$EDITOR}" in
348 *vim*)
21d0ba7e 349 tools="$tools vimdiff emerge"
7b104229
RS
350 ;;
351 *)
21d0ba7e 352 tools="$tools emerge vimdiff"
7b104229
RS
353 ;;
354 esac
21d0ba7e
DA
355 echo >&2 "merge tool candidates: $tools"
356
357 # Loop over each candidate and stop when a valid merge tool is found.
358 for i in $tools
359 do
360 merge_tool_path="$(translate_merge_tool_path "$i")"
361 if type "$merge_tool_path" > /dev/null 2>&1; then
47d65924
DA
362 echo "$i"
363 return 0
21d0ba7e
DA
364 fi
365 done
366
47d65924
DA
367 echo >&2 "No known merge resolution program available."
368 return 1
21d0ba7e
DA
369}
370
371get_configured_merge_tool () {
372 # Diff mode first tries diff.tool and falls back to merge.tool.
373 # Merge mode only checks merge.tool
374 if diff_mode; then
47d65924
DA
375 merge_tool=$(git config diff.tool || git config merge.tool)
376 else
377 merge_tool=$(git config merge.tool)
21d0ba7e
DA
378 fi
379 if test -n "$merge_tool" && ! valid_tool "$merge_tool"; then
380 echo >&2 "git config option $TOOL_MODE.tool set to unknown tool: $merge_tool"
381 echo >&2 "Resetting to default..."
382 return 1
383 fi
47d65924 384 echo "$merge_tool"
21d0ba7e
DA
385}
386
387get_merge_tool_path () {
388 # A merge tool has been set, so verify that it's valid.
47d65924
DA
389 if test -n "$1"; then
390 merge_tool="$1"
391 else
392 merge_tool="$(get_merge_tool)"
393 fi
21d0ba7e
DA
394 if ! valid_tool "$merge_tool"; then
395 echo >&2 "Unknown merge tool $merge_tool"
396 exit 1
397 fi
398 if diff_mode; then
47d65924
DA
399 merge_tool_path=$(git config difftool."$merge_tool".path ||
400 git config mergetool."$merge_tool".path)
401 else
402 merge_tool_path=$(git config mergetool."$merge_tool".path)
21d0ba7e
DA
403 fi
404 if test -z "$merge_tool_path"; then
47d65924 405 merge_tool_path="$(translate_merge_tool_path "$merge_tool")"
21d0ba7e 406 fi
47d65924
DA
407 if test -z "$(get_merge_tool_cmd "$merge_tool")" &&
408 ! type "$merge_tool_path" > /dev/null 2>&1; then
409 echo >&2 "The $TOOL_MODE tool $merge_tool is not available as"\
410 "'$merge_tool_path'"
21d0ba7e
DA
411 exit 1
412 fi
413 echo "$merge_tool_path"
414}
415
416get_merge_tool () {
21d0ba7e 417 # Check if a merge tool has been configured
47d65924 418 merge_tool=$(get_configured_merge_tool)
21d0ba7e
DA
419 # Try to guess an appropriate merge tool if no tool has been set.
420 if test -z "$merge_tool"; then
47d65924 421 merge_tool="$(guess_merge_tool)" || exit
21d0ba7e
DA
422 fi
423 echo "$merge_tool"
424}