##// END OF EJS Templates
Safer version of FileMerge merge
Brendan Cully -
r1664:4338e33c default
parent child Browse files
Show More
@@ -1,120 +1,143 b''
1 #!/bin/sh
1 #!/bin/sh
2 #
2 #
3 # hgmerge - default merge helper for Mercurial
3 # hgmerge - default merge helper for Mercurial
4 #
4 #
5 # This tries to find a way to do three-way merge on the current system.
5 # This tries to find a way to do three-way merge on the current system.
6 # The result ought to end up in $1.
6 # The result ought to end up in $1.
7
7
8 set -e # bail out quickly on failure
8 set -e # bail out quickly on failure
9
9
10 LOCAL="$1"
10 LOCAL="$1"
11 BASE="$2"
11 BASE="$2"
12 OTHER="$3"
12 OTHER="$3"
13
13
14 if [ -z "$EDITOR" ]; then
14 if [ -z "$EDITOR" ]; then
15 EDITOR="vi"
15 EDITOR="vi"
16 fi
16 fi
17
17
18 # find decent versions of our utilities, insisting on the GNU versions where we
18 # find decent versions of our utilities, insisting on the GNU versions where we
19 # need to
19 # need to
20 DIFF3=gdiff3
20 DIFF3=gdiff3
21 DIFF=gdiff
21 DIFF=gdiff
22 PATCH=gpatch
22 PATCH=gpatch
23
23
24 type $DIFF3 >/dev/null 2>&1 || DIFF3=diff3
24 type $DIFF3 >/dev/null 2>&1 || DIFF3=diff3
25 type $DIFF >/dev/null 2>&1 || DIFF=diff
25 type $DIFF >/dev/null 2>&1 || DIFF=diff
26 type $PATCH >/dev/null 2>&1 || PATCH=patch
26 type $PATCH >/dev/null 2>&1 || PATCH=patch
27 $DIFF3 --version >/dev/null 2>&1 || DIFF3=
27 $DIFF3 --version >/dev/null 2>&1 || DIFF3=
28
28
29 # Back up our file
29 # Back up our file
30 cp "$LOCAL" "$LOCAL.orig"
30 cp "$LOCAL" "$LOCAL.orig"
31
31
32 # Attempt to do a non-interactive merge
32 # Attempt to do a non-interactive merge
33 if type merge > /dev/null 2>&1; then
33 if type merge > /dev/null 2>&1; then
34 merge "$LOCAL" "$BASE" "$OTHER" 2> /dev/null && exit 0
34 merge "$LOCAL" "$BASE" "$OTHER" 2> /dev/null && exit 0
35 cp "$LOCAL.orig" "$LOCAL"
35 cp "$LOCAL.orig" "$LOCAL"
36 elif [ -n "$DIFF3" ]; then
36 elif [ -n "$DIFF3" ]; then
37 echo $DIFF3 -m "$LOCAL.orig" "$BASE" "$OTHER"
37 echo $DIFF3 -m "$LOCAL.orig" "$BASE" "$OTHER"
38 $DIFF3 -m "$LOCAL.orig" "$BASE" "$OTHER" > "$LOCAL" && exit 0
38 $DIFF3 -m "$LOCAL.orig" "$BASE" "$OTHER" > "$LOCAL" && exit 0
39 if [ $? -eq 2 ]; then
39 if [ $? -eq 2 ]; then
40 echo "$DIFF3 failed! Exiting." 1>&2
40 echo "$DIFF3 failed! Exiting." 1>&2
41 cp "$LOCAL.orig" "$LOCAL"
41 cp "$LOCAL.orig" "$LOCAL"
42 exit 1
42 exit 1
43 fi
43 fi
44 cp "$LOCAL.orig" "$LOCAL"
44 cp "$LOCAL.orig" "$LOCAL"
45 fi
45 fi
46
46
47 # on MacOS X try opendiff
47 # on MacOS X try FileMerge.app, shipped with Apple's developer tools
48 # (uses FileMerge.app, shipped with Apple's developer tools)
48 # TODO: make proper temp files. foo.orig and foo.link are dangerous
49 if type opendiff > /dev/null 2>&1; then
49 FILEMERGE='/Developer/Applications/Utilities/FileMerge.app/Contents/MacOS/FileMerge'
50 opendiff "$LOCAL.orig" "$OTHER" -ancestor "$BASE" -merge "$LOCAL" || exit 1
50 if type "$FILEMERGE" > /dev/null 2>&1; then
51 # prevent $OTHER from being removed too early
51 cp "$LOCAL.orig" "$LOCAL"
52 # can surely be done in a more elegant way
52 ln "$LOCAL" "$LOCAL.link"
53 sleep 1
53 # filemerge prefers the right by default
54 exit 0
54 if ! "$FILEMERGE" -left "$OTHER" -right "$LOCAL" -ancestor "$BASE" -merge "$LOCAL"
55 then
56 echo "FileMerge failed to launch"
57 exit 1
58 fi
59 if ! test "$LOCAL" -ef "$LOCAL.link"
60 then
61 rm "$LOCAL.orig" "$LOCAL.link"
62 exit 0
63 else
64 rm "$LOCAL.link"
65 echo "$LOCAL is unchanged. Was the merge successful?"
66 select answer in yes no
67 do
68 if test "$answer" == "yes"
69 then
70 rm "$LOCAL.orig"
71 exit 0
72 else
73 exit 1
74 fi
75 done
76 exit 1
77 fi
55 fi
78 fi
56
79
57 if [ -n "$DISPLAY" ]; then
80 if [ -n "$DISPLAY" ]; then
58 # try using kdiff3, which is fairly nice
81 # try using kdiff3, which is fairly nice
59 if type kdiff3 > /dev/null 2>&1; then
82 if type kdiff3 > /dev/null 2>&1; then
60 kdiff3 --auto "$BASE" "$LOCAL" "$OTHER" -o "$LOCAL" || exit 1
83 kdiff3 --auto "$BASE" "$LOCAL" "$OTHER" -o "$LOCAL" || exit 1
61 exit 0
84 exit 0
62 fi
85 fi
63
86
64 # try using tkdiff, which is a bit less sophisticated
87 # try using tkdiff, which is a bit less sophisticated
65 if type tkdiff > /dev/null 2>&1; then
88 if type tkdiff > /dev/null 2>&1; then
66 tkdiff "$LOCAL" "$OTHER" -a "$BASE" -o "$LOCAL" || exit 1
89 tkdiff "$LOCAL" "$OTHER" -a "$BASE" -o "$LOCAL" || exit 1
67 exit 0
90 exit 0
68 fi
91 fi
69 fi
92 fi
70
93
71 # Attempt to do a merge with $EDITOR
94 # Attempt to do a merge with $EDITOR
72 if type merge > /dev/null 2>&1; then
95 if type merge > /dev/null 2>&1; then
73 echo "conflicts detected in $LOCAL"
96 echo "conflicts detected in $LOCAL"
74 merge "$LOCAL" "$BASE" "$OTHER" 2>/dev/null || $EDITOR "$LOCAL"
97 merge "$LOCAL" "$BASE" "$OTHER" 2>/dev/null || $EDITOR "$LOCAL"
75 exit 0
98 exit 0
76 fi
99 fi
77
100
78 if [ -n "$DIFF3" ]; then
101 if [ -n "$DIFF3" ]; then
79 echo "conflicts detected in $LOCAL"
102 echo "conflicts detected in $LOCAL"
80 $DIFF3 -m "$LOCAL.orig" "$BASE" "$OTHER" > "$LOCAL" || {
103 $DIFF3 -m "$LOCAL.orig" "$BASE" "$OTHER" > "$LOCAL" || {
81 case $? in
104 case $? in
82 1)
105 1)
83 $EDITOR "$LOCAL" ;;
106 $EDITOR "$LOCAL" ;;
84 2) echo "$DIFF3 failed! Exiting." 1>&2
107 2) echo "$DIFF3 failed! Exiting." 1>&2
85 cp "$LOCAL.orig" "$LOCAL"
108 cp "$LOCAL.orig" "$LOCAL"
86 exit 1 ;;
109 exit 1 ;;
87 esac
110 esac
88 exit 0
111 exit 0
89 }
112 }
90 fi
113 fi
91
114
92 HGTMP=""
115 HGTMP=""
93 cleanup_exit() {
116 cleanup_exit() {
94 rm -rf "$HGTMP"
117 rm -rf "$HGTMP"
95 }
118 }
96
119
97 # attempt to manually merge with diff and patch
120 # attempt to manually merge with diff and patch
98 if [ -n "$DIFF" -a -n "$PATCH" ]; then
121 if [ -n "$DIFF" -a -n "$PATCH" ]; then
99 # Remove temporary files even if we get interrupted
122 # Remove temporary files even if we get interrupted
100 trap "cleanup_exit" 0 # normal exit
123 trap "cleanup_exit" 0 # normal exit
101 trap "exit 1" 1 2 3 6 15 # HUP INT QUIT ABRT TERM
124 trap "exit 1" 1 2 3 6 15 # HUP INT QUIT ABRT TERM
102
125
103 HGTMP="${TMPDIR-/tmp}/hgmerge.$RANDOM.$RANDOM.$RANDOM.$$"
126 HGTMP="${TMPDIR-/tmp}/hgmerge.$RANDOM.$RANDOM.$RANDOM.$$"
104 (umask 077 && mkdir "$HGTMP") || {
127 (umask 077 && mkdir "$HGTMP") || {
105 echo "Could not create temporary directory! Exiting." 1>&2
128 echo "Could not create temporary directory! Exiting." 1>&2
106 exit 1
129 exit 1
107 }
130 }
108
131
109 $DIFF -u "$BASE" "$OTHER" > "$HGTMP/diff" || :
132 $DIFF -u "$BASE" "$OTHER" > "$HGTMP/diff" || :
110 if $PATCH "$LOCAL" < "$HGTMP/diff"; then
133 if $PATCH "$LOCAL" < "$HGTMP/diff"; then
111 exit 0
134 exit 0
112 else
135 else
113 # If rejects are empty after using the editor, merge was ok
136 # If rejects are empty after using the editor, merge was ok
114 $EDITOR "$LOCAL" "$LOCAL.rej" && test -s "$LOCAL.rej" || exit 0
137 $EDITOR "$LOCAL" "$LOCAL.rej" && test -s "$LOCAL.rej" || exit 0
115 fi
138 fi
116 exit 1
139 exit 1
117 fi
140 fi
118
141
119 echo "hgmerge: unable to find merge, tkdiff, kdiff3, or diff+patch!"
142 echo "hgmerge: unable to find merge, tkdiff, kdiff3, or diff+patch!"
120 exit 1
143 exit 1
General Comments 0
You need to be logged in to leave comments. Login now