Raw
1 #!/bin/sh
2 #
3 # Copyright (c) 2007 Junio C Hamano
4 #
5
6 test_description='per path merge controlled by merge attribute'
7
8 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
9 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
10
11 . ./test-lib.sh
12
13 test_expect_success setup '
14
15 for f in text binary union
16 do
17 echo Initial >$f && git add $f || return 1
18 done &&
19 test_tick &&
20 git commit -m Initial &&
21
22 git branch side &&
23 for f in text binary union
24 do
25 echo Main >>$f && git add $f || return 1
26 done &&
27 test_tick &&
28 git commit -m Main &&
29
30 git checkout side &&
31 for f in text binary union
32 do
33 echo Side >>$f && git add $f || return 1
34 done &&
35 test_tick &&
36 git commit -m Side &&
37
38 git tag anchor &&
39
40 cat >./custom-merge <<-\EOF &&
41 #!/bin/sh
42
43 orig="$1" ours="$2" theirs="$3" exit="$4" path=$5
44 orig_name="$6" our_name="$7" their_name="$8"
45 (
46 echo "orig is $orig"
47 echo "ours is $ours"
48 echo "theirs is $theirs"
49 echo "path is $path"
50 echo "orig_name is $orig_name"
51 echo "our_name is $our_name"
52 echo "their_name is $their_name"
53 echo "=== orig ==="
54 cat "$orig"
55 echo "=== ours ==="
56 cat "$ours"
57 echo "=== theirs ==="
58 cat "$theirs"
59 ) >"$ours+"
60 cat "$ours+" >"$ours"
61 rm -f "$ours+"
62
63 if test -f ./please-abort
64 then
65 echo >>./please-abort killing myself
66 kill -9 $$
67 fi
68 exit "$exit"
69 EOF
70 chmod +x ./custom-merge
71 '
72
73 test_expect_success merge '
74
75 cat >.gitattributes <<-\EOF &&
76 binary -merge
77 union merge=union
78 EOF
79
80 if git merge main
81 then
82 echo Gaah, should have conflicted
83 false
84 else
85 echo Ok, conflicted.
86 fi
87 '
88
89 test_expect_success 'check merge result in index' '
90
91 git ls-files -u | grep binary &&
92 git ls-files -u | grep text &&
93 ! (git ls-files -u | grep union)
94
95 '
96
97 test_expect_success 'check merge result in working tree' '
98
99 git cat-file -p HEAD:binary >binary-orig &&
100 test_grep "<<<<<<<" text &&
101 cmp binary-orig binary &&
102 test_grep ! "<<<<<<<" union &&
103 test_grep Main union &&
104 test_grep Side union
105
106 '
107
108 test_expect_success 'retry the merge with longer context' '
109 echo text conflict-marker-size=32 >>.gitattributes &&
110 git checkout -m text &&
111 sed -ne "/^\([<=>]\)\1\1\1*/{
112 s/ .*$//
113 p
114 }" >actual text &&
115 test_grep ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>" actual &&
116 test_grep "================================" actual &&
117 test_grep "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<" actual
118 '
119
120 test_expect_success 'invalid conflict-marker-size 3a' '
121 cp .gitattributes .gitattributes.bak &&
122 echo "text conflict-marker-size=3a" >>.gitattributes &&
123 test_when_finished "mv .gitattributes.bak .gitattributes" &&
124 git checkout -m text 2>err &&
125 test_grep "warning: invalid marker-size ${SQ}3a${SQ}, expecting an integer" err
126 '
127
128 test_expect_success 'custom merge backend' '
129
130 echo "* merge=union" >.gitattributes &&
131 echo "text merge=custom" >>.gitattributes &&
132
133 git reset --hard anchor &&
134 git config --replace-all \
135 merge.custom.driver "./custom-merge %O %A %B 0 %P %S %X %Y" &&
136 git config --replace-all \
137 merge.custom.name "custom merge driver for testing" &&
138
139 git merge main &&
140
141 cmp binary union &&
142 sed -e 1,3d text >check-1 &&
143 o=$(git unpack-file main^:text) &&
144 a=$(git unpack-file side^:text) &&
145 b=$(git unpack-file main:text) &&
146 base_revid=$(git rev-parse --short main^) &&
147 sh -c "./custom-merge $o $a $b 0 text $base_revid HEAD main" &&
148 sed -e 1,3d $a >check-2 &&
149 cmp check-1 check-2 &&
150 rm -f $o $a $b
151 '
152
153 test_expect_success 'custom merge backend' '
154
155 git reset --hard anchor &&
156 git config --replace-all \
157 merge.custom.driver "./custom-merge %O %A %B 1 %P %S %X %Y" &&
158 git config --replace-all \
159 merge.custom.name "custom merge driver for testing" &&
160
161 if git merge main
162 then
163 echo "Eh? should have conflicted"
164 false
165 else
166 echo "Ok, conflicted"
167 fi &&
168
169 cmp binary union &&
170 sed -e 1,3d text >check-1 &&
171 o=$(git unpack-file main^:text) &&
172 a=$(git unpack-file anchor:text) &&
173 b=$(git unpack-file main:text) &&
174 base_revid=$(git rev-parse --short main^) &&
175 sh -c "./custom-merge $o $a $b 0 text $base_revid HEAD main" &&
176 sed -e 1,3d $a >check-2 &&
177 cmp check-1 check-2 &&
178 sed -e 1,3d -e 4q $a >check-3 &&
179 echo "path is text" >expect &&
180 cmp expect check-3 &&
181 rm -f $o $a $b
182 '
183
184 test_expect_success !WINDOWS 'custom merge driver that is killed with a signal' '
185 test_when_finished "rm -f output please-abort" &&
186
187 git reset --hard anchor &&
188 git config --replace-all \
189 merge.custom.driver "./custom-merge %O %A %B 0 %P %S %X %Y" &&
190 git config --replace-all \
191 merge.custom.name "custom merge driver for testing" &&
192
193 >./please-abort &&
194 echo "* merge=custom" >.gitattributes &&
195 test_expect_code 2 git merge main 2>err &&
196 test_grep "^error: failed to execute internal merge" err &&
197 git ls-files -u >output &&
198 git diff --name-only HEAD >>output &&
199 test_must_be_empty output
200 '
201
202 test_expect_success 'up-to-date merge without common ancestor' '
203 git init repo1 &&
204 git init repo2 &&
205 test_tick &&
206 (
207 cd repo1 &&
208 >a &&
209 git add a &&
210 git commit -m initial
211 ) &&
212 test_tick &&
213 (
214 cd repo2 &&
215 git commit --allow-empty -m initial
216 ) &&
217 test_tick &&
218 (
219 cd repo1 &&
220 git fetch ../repo2 main &&
221 git merge --allow-unrelated-histories FETCH_HEAD
222 )
223 '
224
225 test_expect_success 'custom merge does not lock index' '
226 git reset --hard anchor &&
227 write_script sleep-an-hour.sh <<-\EOF &&
228 sleep 3600 &
229 echo $! >sleep.pid
230 EOF
231
232 test_write_lines >.gitattributes \
233 "* merge=ours" "text merge=sleep-an-hour" &&
234 test_config merge.ours.driver true &&
235 test_config merge.sleep-an-hour.driver ./sleep-an-hour.sh &&
236
237 # We are testing that the custom merge driver does not block
238 # index.lock on Windows due to an inherited file handle.
239 # To ensure that the backgrounded process ran sufficiently
240 # long (and has been started in the first place), we do not
241 # ignore the result of the kill command.
242 # By packaging the command in test_when_finished, we get both
243 # the correctness check and the clean-up.
244 test_when_finished "kill \$(cat sleep.pid)" &&
245 git merge main
246 '
247
248 test_expect_success 'binary files with union attribute' '
249 git checkout -b bin-main &&
250 printf "base\0" >bin.txt &&
251 echo "bin.txt merge=union" >.gitattributes &&
252 git add bin.txt .gitattributes &&
253 git commit -m base &&
254
255 printf "one\0" >bin.txt &&
256 git commit -am one &&
257
258 git checkout -b bin-side HEAD^ &&
259 printf "two\0" >bin.txt &&
260 git commit -am two &&
261
262 test_must_fail git merge bin-main >output &&
263 test_grep -i "warning.*cannot merge.*HEAD vs. bin-main" output
264 '
265
266 test_expect_success !WINDOWS 'custom merge driver that is killed with a signal on recursive merge' '
267 test_when_finished "rm -f output please-abort" &&
268 test_when_finished "git checkout side" &&
269
270 git reset --hard anchor &&
271
272 git checkout -b base-a main^ &&
273 echo base-a >text &&
274 git commit -m base-a text &&
275
276 git checkout -b base-b main^ &&
277 echo base-b >text &&
278 git commit -m base-b text &&
279
280 git checkout -b recursive-a base-a &&
281 test_must_fail git merge base-b &&
282 echo recursive-a >text &&
283 git add text &&
284 git commit -m recursive-a &&
285
286 git checkout -b recursive-b base-b &&
287 test_must_fail git merge base-a &&
288 echo recursive-b >text &&
289 git add text &&
290 git commit -m recursive-b &&
291
292 git config --replace-all \
293 merge.custom.driver "./custom-merge %O %A %B 0 %P %S %X %Y" &&
294 git config --replace-all \
295 merge.custom.name "custom merge driver for testing" &&
296
297 >./please-abort &&
298 echo "* merge=custom" >.gitattributes &&
299 test_expect_code 2 git merge recursive-a 2>err &&
300 test_grep "error: failed to execute internal merge" err &&
301 git ls-files -u >output &&
302 git diff --name-only HEAD >>output &&
303 test_must_be_empty output
304 '
305
306 test_done