]>
Commit | Line | Data |
---|---|---|
5c38ea31 DA |
1 | #!/bin/sh |
2 | # git-difftool-helper is a GIT_EXTERNAL_DIFF-compatible diff tool launcher. | |
384770a5 MH |
3 | # It supports kdiff3, kompare, tkdiff, xxdiff, meld, opendiff, |
4 | # emerge, ecmerge, vimdiff, gvimdiff, and custom user-configurable tools. | |
5c38ea31 DA |
5 | # This script is typically launched by using the 'git difftool' |
6 | # convenience command. | |
7 | # | |
8 | # Copyright (c) 2009 David Aguilar | |
9 | ||
10 | # Set GIT_DIFFTOOL_NO_PROMPT to bypass the per-file prompt. | |
11 | should_prompt () { | |
12 | ! test -n "$GIT_DIFFTOOL_NO_PROMPT" | |
13 | } | |
14 | ||
15 | # Should we keep the backup .orig file? | |
16 | keep_backup_mode="$(git config --bool merge.keepBackup || echo true)" | |
17 | keep_backup () { | |
18 | test "$keep_backup_mode" = "true" | |
19 | } | |
20 | ||
21 | # This function manages the backup .orig file. | |
22 | # A backup $MERGED.orig file is created if changes are detected. | |
23 | cleanup_temp_files () { | |
24 | if test -n "$MERGED"; then | |
25 | if keep_backup && test "$MERGED" -nt "$BACKUP"; then | |
26 | test -f "$BACKUP" && mv -- "$BACKUP" "$MERGED.orig" | |
27 | else | |
28 | rm -f -- "$BACKUP" | |
29 | fi | |
30 | fi | |
31 | } | |
32 | ||
33 | # This is called when users Ctrl-C out of git-difftool-helper | |
34 | sigint_handler () { | |
5c38ea31 DA |
35 | cleanup_temp_files |
36 | exit 1 | |
37 | } | |
38 | ||
39 | # This function prepares temporary files and launches the appropriate | |
40 | # merge tool. | |
41 | launch_merge_tool () { | |
42 | # Merged is the filename as it appears in the work tree | |
43 | # Local is the contents of a/filename | |
44 | # Remote is the contents of b/filename | |
45 | # Custom merge tool commands might use $BASE so we provide it | |
46 | MERGED="$1" | |
47 | LOCAL="$2" | |
48 | REMOTE="$3" | |
49 | BASE="$1" | |
50 | ext="$$$(expr "$MERGED" : '.*\(\.[^/]*\)$')" | |
51 | BACKUP="$MERGED.BACKUP.$ext" | |
52 | ||
53 | # Create and ensure that we clean up $BACKUP | |
54 | test -f "$MERGED" && cp -- "$MERGED" "$BACKUP" | |
f13bfc1b | 55 | trap sigint_handler INT |
5c38ea31 DA |
56 | |
57 | # $LOCAL and $REMOTE are temporary files so prompt | |
58 | # the user with the real $MERGED name before launching $merge_tool. | |
59 | if should_prompt; then | |
60 | printf "\nViewing: '$MERGED'\n" | |
61 | printf "Hit return to launch '%s': " "$merge_tool" | |
62 | read ans | |
63 | fi | |
64 | ||
65 | # Run the appropriate merge tool command | |
66 | case "$merge_tool" in | |
67 | kdiff3) | |
68 | basename=$(basename "$MERGED") | |
69 | "$merge_tool_path" --auto \ | |
70 | --L1 "$basename (A)" \ | |
71 | --L2 "$basename (B)" \ | |
72 | -o "$MERGED" "$LOCAL" "$REMOTE" \ | |
73 | > /dev/null 2>&1 | |
74 | ;; | |
75 | ||
384770a5 MH |
76 | kompare) |
77 | "$merge_tool_path" "$LOCAL" "$REMOTE" | |
78 | ;; | |
79 | ||
5c38ea31 DA |
80 | tkdiff) |
81 | "$merge_tool_path" -o "$MERGED" "$LOCAL" "$REMOTE" | |
82 | ;; | |
83 | ||
28da86a5 | 84 | meld) |
5c38ea31 DA |
85 | "$merge_tool_path" "$LOCAL" "$REMOTE" |
86 | ;; | |
87 | ||
28da86a5 DA |
88 | vimdiff) |
89 | "$merge_tool_path" -c "wincmd l" "$LOCAL" "$REMOTE" | |
90 | ;; | |
91 | ||
5c38ea31 | 92 | gvimdiff) |
28da86a5 | 93 | "$merge_tool_path" -c "wincmd l" -f "$LOCAL" "$REMOTE" |
5c38ea31 DA |
94 | ;; |
95 | ||
96 | xxdiff) | |
97 | "$merge_tool_path" \ | |
98 | -X \ | |
99 | -R 'Accel.SaveAsMerged: "Ctrl-S"' \ | |
100 | -R 'Accel.Search: "Ctrl+F"' \ | |
101 | -R 'Accel.SearchForward: "Ctrl-G"' \ | |
102 | --merged-file "$MERGED" \ | |
103 | "$LOCAL" "$REMOTE" | |
104 | ;; | |
105 | ||
106 | opendiff) | |
107 | "$merge_tool_path" "$LOCAL" "$REMOTE" \ | |
108 | -merge "$MERGED" | cat | |
109 | ;; | |
110 | ||
111 | ecmerge) | |
112 | "$merge_tool_path" "$LOCAL" "$REMOTE" \ | |
113 | --default --mode=merge2 --to="$MERGED" | |
114 | ;; | |
115 | ||
116 | emerge) | |
117 | "$merge_tool_path" -f emerge-files-command \ | |
118 | "$LOCAL" "$REMOTE" "$(basename "$MERGED")" | |
119 | ;; | |
120 | ||
121 | *) | |
122 | if test -n "$merge_tool_cmd"; then | |
123 | ( eval $merge_tool_cmd ) | |
124 | fi | |
125 | ;; | |
126 | esac | |
127 | ||
128 | cleanup_temp_files | |
129 | } | |
130 | ||
131 | # Verifies that mergetool.<tool>.cmd exists | |
132 | valid_custom_tool() { | |
133 | merge_tool_cmd="$(git config mergetool.$1.cmd)" | |
134 | test -n "$merge_tool_cmd" | |
135 | } | |
136 | ||
137 | # Verifies that the chosen merge tool is properly setup. | |
138 | # Built-in merge tools are always valid. | |
139 | valid_tool() { | |
140 | case "$1" in | |
384770a5 | 141 | kdiff3 | kompare | tkdiff | xxdiff | meld | opendiff | emerge | vimdiff | gvimdiff | ecmerge) |
5c38ea31 DA |
142 | ;; # happy |
143 | *) | |
144 | if ! valid_custom_tool "$1" | |
145 | then | |
146 | return 1 | |
147 | fi | |
148 | ;; | |
149 | esac | |
150 | } | |
151 | ||
152 | # Sets up the merge_tool_path variable. | |
153 | # This handles the mergetool.<tool>.path configuration. | |
154 | init_merge_tool_path() { | |
155 | merge_tool_path=$(git config mergetool."$1".path) | |
156 | if test -z "$merge_tool_path"; then | |
157 | case "$1" in | |
158 | emerge) | |
159 | merge_tool_path=emacs | |
160 | ;; | |
161 | *) | |
162 | merge_tool_path="$1" | |
163 | ;; | |
164 | esac | |
165 | fi | |
166 | } | |
167 | ||
168 | # Allow the GIT_MERGE_TOOL variable to provide a default value | |
169 | test -n "$GIT_MERGE_TOOL" && merge_tool="$GIT_MERGE_TOOL" | |
170 | ||
171 | # If not merge tool was specified then use the merge.tool | |
172 | # configuration variable. If that's invalid then reset merge_tool. | |
173 | if test -z "$merge_tool"; then | |
174 | merge_tool=$(git config merge.tool) | |
175 | if test -n "$merge_tool" && ! valid_tool "$merge_tool"; then | |
176 | echo >&2 "git config option merge.tool set to unknown tool: $merge_tool" | |
177 | echo >&2 "Resetting to default..." | |
178 | unset merge_tool | |
179 | fi | |
180 | fi | |
181 | ||
182 | # Try to guess an appropriate merge tool if no tool has been set. | |
183 | if test -z "$merge_tool"; then | |
5c38ea31 DA |
184 | # We have a $DISPLAY so try some common UNIX merge tools |
185 | if test -n "$DISPLAY"; then | |
99ccabaf DA |
186 | # If gnome then prefer meld, otherwise, prefer kdiff3 or kompare |
187 | if test -n "$GNOME_DESKTOP_SESSION_ID" ; then | |
188 | merge_tool_candidates="meld kdiff3 kompare tkdiff xxdiff gvimdiff" | |
189 | else | |
190 | merge_tool_candidates="kdiff3 kompare tkdiff xxdiff meld gvimdiff" | |
5c38ea31 DA |
191 | fi |
192 | fi | |
5c38ea31 | 193 | if echo "${VISUAL:-$EDITOR}" | grep 'emacs' > /dev/null 2>&1; then |
99ccabaf DA |
194 | # $EDITOR is emacs so add emerge as a candidate |
195 | merge_tool_candidates="$merge_tool_candidates emerge opendiff vimdiff" | |
196 | elif echo "${VISUAL:-$EDITOR}" | grep 'vim' > /dev/null 2>&1; then | |
197 | # $EDITOR is vim so add vimdiff as a candidate | |
198 | merge_tool_candidates="$merge_tool_candidates vimdiff opendiff emerge" | |
199 | else | |
200 | merge_tool_candidates="$merge_tool_candidates opendiff emerge vimdiff" | |
5c38ea31 | 201 | fi |
5c38ea31 DA |
202 | echo "merge tool candidates: $merge_tool_candidates" |
203 | ||
204 | # Loop over each candidate and stop when a valid merge tool is found. | |
205 | for i in $merge_tool_candidates | |
206 | do | |
207 | init_merge_tool_path $i | |
208 | if type "$merge_tool_path" > /dev/null 2>&1; then | |
209 | merge_tool=$i | |
210 | break | |
211 | fi | |
212 | done | |
213 | ||
214 | if test -z "$merge_tool" ; then | |
215 | echo "No known merge resolution program available." | |
216 | exit 1 | |
217 | fi | |
218 | ||
219 | else | |
220 | # A merge tool has been set, so verify that it's valid. | |
221 | if ! valid_tool "$merge_tool"; then | |
222 | echo >&2 "Unknown merge tool $merge_tool" | |
223 | exit 1 | |
224 | fi | |
225 | ||
226 | init_merge_tool_path "$merge_tool" | |
227 | ||
228 | if test -z "$merge_tool_cmd" && ! type "$merge_tool_path" > /dev/null 2>&1; then | |
229 | echo "The merge tool $merge_tool is not available as '$merge_tool_path'" | |
230 | exit 1 | |
231 | fi | |
232 | fi | |
233 | ||
234 | ||
235 | # Launch the merge tool on each path provided by 'git diff' | |
236 | while test $# -gt 6 | |
237 | do | |
238 | launch_merge_tool "$1" "$2" "$5" | |
239 | shift 7 | |
240 | done |