#!/bin/sh # # hgmerge - default merge helper for Mercurial # # This tries to find a way to do three-way merge on the current system. # The result ought to end up in $1. set -e # bail out quickly on failure LOCAL="$1" BASE="$2" OTHER="$3" if [ -z "$EDITOR" ]; then EDITOR="vi" fi # find decent versions of our utilities, insisting on the GNU versions where we # need to MERGE=merge DIFF3=gdiff3 DIFF=gdiff PATCH=gpatch type $MERGE >/dev/null 2>&1 || MERGE= type $DIFF3 >/dev/null 2>&1 || DIFF3=diff3 type $DIFF >/dev/null 2>&1 || DIFF=diff type $PATCH >/dev/null 2>&1 || PATCH=patch $DIFF3 --version >/dev/null 2>&1 || DIFF3= # find optional visual utilities FILEMERGE='/Developer/Applications/Utilities/FileMerge.app/Contents/MacOS/FileMerge' KDIFF3=kdiff3 TKDIFF=tkdiff type $FILEMERGE >/dev/null 2>&1 || FILEMERGE= type $KDIFF3 >/dev/null 2>&1 || KDIFF3= type $TKDIFF >/dev/null 2>&1 || TKDIFF= # temporary directory for diff+patch merge HGTMP="${TMPDIR-/tmp}/hgmerge.$RANDOM.$RANDOM.$RANDOM.$$" # put all your required cleanup here cleanup() { rm -f "$LOCAL.orig" rm -rf "$HGTMP" } # functions concerning program exit success() { cleanup exit 0 } failure() { echo "merge failed" 1>&2 cp "$LOCAL.orig" "$LOCAL" cleanup exit 1 } # Clean up when interrupted trap "failure" 1 2 3 6 15 # HUP INT QUIT ABRT TERM # Back up our file cp "$LOCAL" "$LOCAL.orig" # Attempt to do a non-interactive merge if [ -n "$MERGE" ]; then $MERGE "$LOCAL" "$BASE" "$OTHER" 2> /dev/null && success cp "$LOCAL.orig" "$LOCAL" elif [ -n "$DIFF3" ]; then echo $DIFF3 -m "$LOCAL.orig" "$BASE" "$OTHER" $DIFF3 -m "$LOCAL.orig" "$BASE" "$OTHER" > "$LOCAL" && success if [ $? -eq 2 ]; then echo "$DIFF3 failed! Exiting." 1>&2 cp "$LOCAL.orig" "$LOCAL" failure fi cp "$LOCAL.orig" "$LOCAL" fi # on MacOS X try FileMerge.app, shipped with Apple's developer tools # TODO: make proper temp files. foo.orig and foo.link are dangerous if [ -n "$FILEMERGE" ]; then cp "$LOCAL.orig" "$LOCAL" ln "$LOCAL" "$LOCAL.link" # filemerge prefers the right by default if ! "$FILEMERGE" -left "$OTHER" -right "$LOCAL" -ancestor "$BASE" -merge "$LOCAL" then echo "FileMerge failed to launch" failure fi if ! test "$LOCAL" -ef "$LOCAL.link" then rm "$LOCAL.orig" "$LOCAL.link" success else rm "$LOCAL.link" echo "$LOCAL is unchanged. Was the merge successful?" select answer in yes no do if test "$answer" == "yes" then rm "$LOCAL.orig" success else failure fi done failure fi fi if [ -n "$DISPLAY" ]; then # try using kdiff3, which is fairly nice if [ -n "$KDIFF3" ]; then $KDIFF3 --auto "$BASE" "$LOCAL" "$OTHER" -o "$LOCAL" || failure success fi # try using tkdiff, which is a bit less sophisticated if [ -n "$TKDIFF" ]; then $TKDIFF "$LOCAL" "$OTHER" -a "$BASE" -o "$LOCAL" || failure success fi fi # Attempt to do a merge with $EDITOR if [ -n "$MERGE" ]; then echo "conflicts detected in $LOCAL" $MERGE "$LOCAL" "$BASE" "$OTHER" 2>/dev/null || $EDITOR "$LOCAL" success fi if [ -n "$DIFF3" ]; then echo "conflicts detected in $LOCAL" $DIFF3 -m "$LOCAL.orig" "$BASE" "$OTHER" > "$LOCAL" || { case $? in 1) $EDITOR "$LOCAL" ;; 2) echo "$DIFF3 failed! Exiting." 1>&2 cp "$LOCAL.orig" "$LOCAL" failure ;; esac success } fi # attempt to manually merge with diff and patch if [ -n "$DIFF" -a -n "$PATCH" ]; then (umask 077 && mkdir "$HGTMP") || { echo "Could not create temporary directory $HGTMP" 1>&2 failure } $DIFF -u "$BASE" "$OTHER" > "$HGTMP/diff" || : if $PATCH "$LOCAL" < "$HGTMP/diff"; then success else # If rejects are empty after using the editor, merge was ok $EDITOR "$LOCAL" "$LOCAL.rej" && test -s "$LOCAL.rej" || success fi failure fi echo "hgmerge: unable to find merge, tkdiff, kdiff3, or diff+patch!" failure