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