difftool/mergetool: refactor commands to use git-mergetool--lib
[git/vmiklos.git] / git-mergetool--lib.sh
blobc5db24e45dd9538528c64bcb3b0bd8ebf71a6771
1 # git-mergetool--lib is a library for common merge tool functions
2 diff_mode() {
3 test "$TOOL_MODE" = diff
6 merge_mode() {
7 test "$TOOL_MODE" = merge
10 translate_merge_tool_path () {
11 if test -n "$2"; then
12 echo "$2"
13 else
14 case "$1" in
15 vimdiff)
16 path=vim
18 gvimdiff)
19 path=gvim
21 emerge)
22 path=emacs
25 path="$1"
27 esac
28 echo "$path"
32 check_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
48 valid_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
58 kompare)
59 if ! diff_mode; then
60 return 1
64 if test -z "$(get_merge_tool_cmd "$1")"; then
65 return 1
68 esac
71 get_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"
80 run_merge_tool () {
81 base_present="$2"
82 status=0
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)
103 status=$?
104 else
105 ("$merge_tool_path" --auto \
106 --L1 "$MERGED (A)" \
107 --L2 "$MERGED (B)" "$LOCAL" "$REMOTE" \
108 > /dev/null 2>&1)
111 kompare)
112 "$merge_tool_path" "$LOCAL" "$REMOTE"
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"
123 status=$?
124 else
125 "$merge_tool_path" "$LOCAL" "$REMOTE"
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"
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
148 check_unchanged
149 else
150 "$merge_tool_path" "$LOCAL" "$REMOTE" | cat
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"
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"
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"
193 check_unchanged
194 else
195 "$merge_tool_path" \
196 -R 'Accel.Search: "Ctrl+F"' \
197 -R 'Accel.SearchForward: "Ctrl-G"' \
198 "$LOCAL" "$REMOTE"
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
212 check_unchanged
213 else
214 "$merge_tool_path" "$LOCAL" "$REMOTE" | cat
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"
227 check_unchanged
228 else
229 "$merge_tool_path" "$LOCAL" "$REMOTE" \
230 --default --mode=merge2 --to="$MERGED"
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")"
246 status=$?
247 else
248 "$merge_tool_path" -f emerge-files-command \
249 "$LOCAL" "$REMOTE" "$(basename "$MERGED")"
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
265 if test -z "$merge_tool_cmd"; then
266 if merge_mode; then
267 status=1
269 break
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=$?
280 else
281 ( eval $merge_tool_cmd )
284 esac
285 return $status
288 guess_merge_tool () {
289 if merge_mode; then
290 tools="tortoisemerge"
291 else
292 tools="kompare"
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"
300 tools="$tools gvimdiff diffuse ecmerge"
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"
311 echo >&2 "merge tool candidates: $tools"
313 # Loop over each candidate and stop when a valid merge tool is found.
314 for i in $tools
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
321 done
323 if test -z "$merge_tool" ; then
324 echo >&2 "No known merge resolution program available."
325 return 1
327 echo "$merge_tool"
330 get_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)
336 if test -z "$tool"; then
337 tool=$(git config merge.tool)
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
344 echo "$tool"
347 get_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
353 if diff_mode; then
354 merge_tool_path=$(git config difftool."$merge_tool".path)
356 if test -z "$merge_tool_path"; then
357 merge_tool_path=$(git config mergetool."$merge_tool".path)
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
364 echo "$merge_tool_path"
367 get_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)
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
377 echo "$merge_tool"