2 # git-difftool-helper is a GIT_EXTERNAL_DIFF-compatible diff tool launcher.
3 # It supports kdiff3, tkdiff, xxdiff, meld, opendiff, emerge, ecmerge,
4 # vimdiff, gvimdiff, and custom user-configurable tools.
5 # This script is typically launched by using the 'git difftool'
8 # Copyright (c) 2009 David Aguilar
10 # Set GIT_DIFFTOOL_NO_PROMPT to bypass the per-file prompt.
12 ! test -n "$GIT_DIFFTOOL_NO_PROMPT"
15 # Should we keep the backup .orig file?
16 keep_backup_mode
="$(git config --bool merge.keepBackup || echo true)"
18 test "$keep_backup_mode" = "true"
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"
33 # This is called when users Ctrl-C out of git-difftool-helper
40 # This function prepares temporary files and launches the appropriate
42 launch_merge_tool
() {
43 # Merged is the filename as it appears in the work tree
44 # Local is the contents of a/filename
45 # Remote is the contents of b/filename
46 # Custom merge tool commands might use $BASE so we provide it
51 ext
="$$$(expr "$MERGED" : '.*\(\.[^/]*\)$')"
52 BACKUP
="$MERGED.BACKUP.$ext"
54 # Create and ensure that we clean up $BACKUP
55 test -f "$MERGED" && cp -- "$MERGED" "$BACKUP"
56 trap sigint_handler SIGINT
58 # $LOCAL and $REMOTE are temporary files so prompt
59 # the user with the real $MERGED name before launching $merge_tool.
60 if should_prompt
; then
61 printf "\nViewing: '$MERGED'\n"
62 printf "Hit return to launch '%s': " "$merge_tool"
66 # Run the appropriate merge tool command
69 basename=$
(basename "$MERGED")
70 "$merge_tool_path" --auto \
71 --L1 "$basename (A)" \
72 --L2 "$basename (B)" \
73 -o "$MERGED" "$LOCAL" "$REMOTE" \
78 "$merge_tool_path" -o "$MERGED" "$LOCAL" "$REMOTE"
82 "$merge_tool_path" "$LOCAL" "$REMOTE"
86 "$merge_tool_path" -f "$LOCAL" "$REMOTE"
92 -R 'Accel.SaveAsMerged: "Ctrl-S"' \
93 -R 'Accel.Search: "Ctrl+F"' \
94 -R 'Accel.SearchForward: "Ctrl-G"' \
95 --merged-file "$MERGED" \
100 "$merge_tool_path" "$LOCAL" "$REMOTE" \
101 -merge "$MERGED" |
cat
105 "$merge_tool_path" "$LOCAL" "$REMOTE" \
106 --default --mode=merge2
--to="$MERGED"
110 "$merge_tool_path" -f emerge-files-command \
111 "$LOCAL" "$REMOTE" "$(basename "$MERGED")"
115 if test -n "$merge_tool_cmd"; then
116 ( eval $merge_tool_cmd )
124 # Verifies that mergetool.<tool>.cmd exists
125 valid_custom_tool
() {
126 merge_tool_cmd
="$(git config mergetool.$1.cmd)"
127 test -n "$merge_tool_cmd"
130 # Verifies that the chosen merge tool is properly setup.
131 # Built-in merge tools are always valid.
134 kdiff3 | tkdiff | xxdiff | meld | opendiff | emerge | vimdiff | gvimdiff | ecmerge
)
137 if ! valid_custom_tool
"$1"
145 # Sets up the merge_tool_path variable.
146 # This handles the mergetool.<tool>.path configuration.
147 init_merge_tool_path
() {
148 merge_tool_path
=$
(git config mergetool.
"$1".path
)
149 if test -z "$merge_tool_path"; then
152 merge_tool_path
=emacs
161 # Allow the GIT_MERGE_TOOL variable to provide a default value
162 test -n "$GIT_MERGE_TOOL" && merge_tool
="$GIT_MERGE_TOOL"
164 # If not merge tool was specified then use the merge.tool
165 # configuration variable. If that's invalid then reset merge_tool.
166 if test -z "$merge_tool"; then
167 merge_tool
=$
(git config merge.tool
)
168 if test -n "$merge_tool" && ! valid_tool
"$merge_tool"; then
169 echo >&2 "git config option merge.tool set to unknown tool: $merge_tool"
170 echo >&2 "Resetting to default..."
175 # Try to guess an appropriate merge tool if no tool has been set.
176 if test -z "$merge_tool"; then
178 # We have a $DISPLAY so try some common UNIX merge tools
179 if test -n "$DISPLAY"; then
180 merge_tool_candidates
="kdiff3 tkdiff xxdiff meld gvimdiff"
181 # If gnome then prefer meld
182 if test -n "$GNOME_DESKTOP_SESSION_ID"; then
183 merge_tool_candidates
="meld $merge_tool_candidates"
185 # If KDE then prefer kdiff3
186 if test "$KDE_FULL_SESSION" = "true"; then
187 merge_tool_candidates
="kdiff3 $merge_tool_candidates"
191 # $EDITOR is emacs so add emerge as a candidate
192 if echo "${VISUAL:-$EDITOR}" |
grep 'emacs' > /dev
/null
2>&1; then
193 merge_tool_candidates
="$merge_tool_candidates emerge"
196 # $EDITOR is vim so add vimdiff as a candidate
197 if echo "${VISUAL:-$EDITOR}" |
grep 'vim' > /dev
/null
2>&1; then
198 merge_tool_candidates
="$merge_tool_candidates vimdiff"
201 merge_tool_candidates
="$merge_tool_candidates opendiff emerge vimdiff"
202 echo "merge tool candidates: $merge_tool_candidates"
204 # Loop over each candidate and stop when a valid merge tool is found.
205 for i
in $merge_tool_candidates
207 init_merge_tool_path
$i
208 if type "$merge_tool_path" > /dev
/null
2>&1; then
214 if test -z "$merge_tool" ; then
215 echo "No known merge resolution program available."
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"
226 init_merge_tool_path
"$merge_tool"
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'"
235 # Launch the merge tool on each path provided by 'git diff'
238 launch_merge_tool
"$1" "$2" "$5"