mergetool--lib: Sort tools alphabetically for easier lookup
[git/dscho.git] / git-mergetool--lib.sh
blobefca09f51f58f289815402bfe84b04e12149904b
1 #!/bin/sh
2 # git-mergetool--lib is a library for common merge tool functions
3 diff_mode() {
4 test "$TOOL_MODE" = diff
7 merge_mode() {
8 test "$TOOL_MODE" = merge
11 translate_merge_tool_path () {
12 case "$1" in
13 araxis)
14 echo compare
16 emerge)
17 echo emacs
19 gvimdiff|gvimdiff2)
20 echo gvim
22 vimdiff|vimdiff2)
23 echo vim
26 echo "$1"
28 esac
31 check_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] "
38 read answer
39 case "$answer" in
40 y*|Y*) status=0; break ;;
41 n*|N*) status=1; break ;;
42 esac
43 done
47 valid_tool () {
48 case "$1" in
49 araxis | diffuse | ecmerge | emerge | gvimdiff | gvimdiff2 | \
50 kdiff3 | meld | opendiff | p4merge | tkdiff | vimdiff | vimdiff2 | xxdiff)
51 ;; # happy
52 kompare)
53 if ! diff_mode; then
54 return 1
57 tortoisemerge)
58 if ! merge_mode; then
59 return 1
63 if test -z "$(get_merge_tool_cmd "$1")"; then
64 return 1
67 esac
70 get_merge_tool_cmd () {
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)"
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)"
85 run_merge_tool () {
86 merge_tool_path="$(get_merge_tool_path "$1")" || exit
87 base_present="$2"
88 status=0
90 case "$1" in
91 araxis)
92 if merge_mode; then
93 touch "$BACKUP"
94 if $base_present; then
95 "$merge_tool_path" -wait -merge -3 -a1 \
96 "$BASE" "$LOCAL" "$REMOTE" "$MERGED" \
97 >/dev/null 2>&1
98 else
99 "$merge_tool_path" -wait -2 \
100 "$LOCAL" "$REMOTE" "$MERGED" \
101 >/dev/null 2>&1
103 check_unchanged
104 else
105 "$merge_tool_path" -wait -2 "$LOCAL" "$REMOTE" \
106 >/dev/null 2>&1
109 diffuse)
110 if merge_mode; then
111 touch "$BACKUP"
112 if $base_present; then
113 "$merge_tool_path" \
114 "$LOCAL" "$MERGED" "$REMOTE" \
115 "$BASE" | cat
116 else
117 "$merge_tool_path" \
118 "$LOCAL" "$MERGED" "$REMOTE" | cat
120 check_unchanged
121 else
122 "$merge_tool_path" "$LOCAL" "$REMOTE" | cat
125 ecmerge)
126 if merge_mode; then
127 touch "$BACKUP"
128 if $base_present; then
129 "$merge_tool_path" "$BASE" "$LOCAL" "$REMOTE" \
130 --default --mode=merge3 --to="$MERGED"
131 else
132 "$merge_tool_path" "$LOCAL" "$REMOTE" \
133 --default --mode=merge2 --to="$MERGED"
135 check_unchanged
136 else
137 "$merge_tool_path" --default --mode=diff2 \
138 "$LOCAL" "$REMOTE"
141 emerge)
142 if merge_mode; then
143 if $base_present; then
144 "$merge_tool_path" \
145 -f emerge-files-with-ancestor-command \
146 "$LOCAL" "$REMOTE" "$BASE" \
147 "$(basename "$MERGED")"
148 else
149 "$merge_tool_path" \
150 -f emerge-files-command \
151 "$LOCAL" "$REMOTE" \
152 "$(basename "$MERGED")"
154 status=$?
155 else
156 "$merge_tool_path" -f emerge-files-command \
157 "$LOCAL" "$REMOTE"
160 gvimdiff|vimdiff)
161 if merge_mode; then
162 touch "$BACKUP"
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"
170 check_unchanged
171 else
172 "$merge_tool_path" -f -d -c "wincmd l" \
173 "$LOCAL" "$REMOTE"
176 gvimdiff2|vimdiff2)
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"
187 kdiff3)
188 if merge_mode; then
189 if $base_present; then
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)
197 else
198 ("$merge_tool_path" --auto \
199 --L1 "$MERGED (Local)" \
200 --L2 "$MERGED (Remote)" \
201 -o "$MERGED" \
202 "$LOCAL" "$REMOTE" \
203 > /dev/null 2>&1)
205 status=$?
206 else
207 ("$merge_tool_path" --auto \
208 --L1 "$MERGED (A)" \
209 --L2 "$MERGED (B)" "$LOCAL" "$REMOTE" \
210 > /dev/null 2>&1)
213 kompare)
214 "$merge_tool_path" "$LOCAL" "$REMOTE"
216 meld)
217 if merge_mode; then
218 touch "$BACKUP"
219 "$merge_tool_path" "$LOCAL" "$MERGED" "$REMOTE"
220 check_unchanged
221 else
222 "$merge_tool_path" "$LOCAL" "$REMOTE"
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
236 check_unchanged
237 else
238 "$merge_tool_path" "$LOCAL" "$REMOTE" | cat
241 p4merge)
242 if merge_mode; then
243 touch "$BACKUP"
244 if $base_present; then
245 "$merge_tool_path" "$BASE" "$LOCAL" "$REMOTE" "$MERGED"
246 else
247 "$merge_tool_path" "$LOCAL" "$LOCAL" "$REMOTE" "$MERGED"
249 check_unchanged
250 else
251 "$merge_tool_path" "$LOCAL" "$REMOTE"
254 tkdiff)
255 if merge_mode; then
256 if $base_present; then
257 "$merge_tool_path" -a "$BASE" \
258 -o "$MERGED" "$LOCAL" "$REMOTE"
259 else
260 "$merge_tool_path" \
261 -o "$MERGED" "$LOCAL" "$REMOTE"
263 status=$?
264 else
265 "$merge_tool_path" "$LOCAL" "$REMOTE"
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
280 xxdiff)
281 if merge_mode; then
282 touch "$BACKUP"
283 if $base_present; then
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"
290 else
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"
298 check_unchanged
299 else
300 "$merge_tool_path" \
301 -R 'Accel.Search: "Ctrl+F"' \
302 -R 'Accel.SearchForward: "Ctrl-G"' \
303 "$LOCAL" "$REMOTE"
307 merge_tool_cmd="$(get_merge_tool_cmd "$1")"
308 if test -z "$merge_tool_cmd"; then
309 if merge_mode; then
310 status=1
312 break
314 if merge_mode; then
315 trust_exit_code="$(git config --bool \
316 mergetool."$1".trustExitCode || echo false)"
317 if test "$trust_exit_code" = "false"; then
318 touch "$BACKUP"
319 ( eval $merge_tool_cmd )
320 check_unchanged
321 else
322 ( eval $merge_tool_cmd )
323 status=$?
325 else
326 ( eval $merge_tool_cmd )
329 esac
330 return $status
333 guess_merge_tool () {
334 if merge_mode; then
335 tools="tortoisemerge"
336 else
337 tools="kompare"
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"
345 tools="$tools gvimdiff diffuse ecmerge p4merge araxis"
347 case "${VISUAL:-$EDITOR}" in
348 *vim*)
349 tools="$tools vimdiff emerge"
352 tools="$tools emerge vimdiff"
354 esac
355 echo >&2 "merge tool candidates: $tools"
357 # Loop over each candidate and stop when a valid merge tool is found.
358 for i in $tools
360 merge_tool_path="$(translate_merge_tool_path "$i")"
361 if type "$merge_tool_path" > /dev/null 2>&1; then
362 echo "$i"
363 return 0
365 done
367 echo >&2 "No known merge resolution program available."
368 return 1
371 get_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
375 merge_tool=$(git config diff.tool || git config merge.tool)
376 else
377 merge_tool=$(git config merge.tool)
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
384 echo "$merge_tool"
387 get_merge_tool_path () {
388 # A merge tool has been set, so verify that it's valid.
389 if test -n "$1"; then
390 merge_tool="$1"
391 else
392 merge_tool="$(get_merge_tool)"
394 if ! valid_tool "$merge_tool"; then
395 echo >&2 "Unknown merge tool $merge_tool"
396 exit 1
398 if diff_mode; then
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)
404 if test -z "$merge_tool_path"; then
405 merge_tool_path="$(translate_merge_tool_path "$merge_tool")"
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'"
411 exit 1
413 echo "$merge_tool_path"
416 get_merge_tool () {
417 # Check if a merge tool has been configured
418 merge_tool=$(get_configured_merge_tool)
419 # Try to guess an appropriate merge tool if no tool has been set.
420 if test -z "$merge_tool"; then
421 merge_tool="$(guess_merge_tool)" || exit
423 echo "$merge_tool"