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