1#!/bin/sh
2
3test_description='Merge-recursive merging renames'
4. ./test-lib.sh
5
6modify () {
7 sed -e "$1" <"$2" >"$2.x" &&
8 mv "$2.x" "$2"
9}
10
11test_expect_success setup \
12'
13cat >A <<\EOF &&
14a aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
15b bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
16c cccccccccccccccccccccccccccccccccccccccccccccccc
17d dddddddddddddddddddddddddddddddddddddddddddddddd
18e eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
19f ffffffffffffffffffffffffffffffffffffffffffffffff
20g gggggggggggggggggggggggggggggggggggggggggggggggg
21h hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
22i iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
23j jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj
24k kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
25l llllllllllllllllllllllllllllllllllllllllllllllll
26m mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
27n nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
28o oooooooooooooooooooooooooooooooooooooooooooooooo
29EOF
30
31cat >M <<\EOF &&
32A AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
33B BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
34C CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
35D DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
36E EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
37F FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
38G GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG
39H HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
40I IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII
41J JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ
42K KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK
43L LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
44M MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
45N NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN
46O OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO
47EOF
48
49git add A M &&
50git commit -m "initial has A and M" &&
51git branch white &&
52git branch red &&
53git branch blue &&
54git branch yellow &&
55git branch change &&
56git branch change+rename &&
57
58sed -e "/^g /s/.*/g : master changes a line/" <A >A+ &&
59mv A+ A &&
60git commit -a -m "master updates A" &&
61
62git checkout yellow &&
63rm -f M &&
64git commit -a -m "yellow removes M" &&
65
66git checkout white &&
67sed -e "/^g /s/.*/g : white changes a line/" <A >B &&
68sed -e "/^G /s/.*/G : colored branch changes a line/" <M >N &&
69rm -f A M &&
70git update-index --add --remove A B M N &&
71git commit -m "white renames A->B, M->N" &&
72
73git checkout red &&
74sed -e "/^g /s/.*/g : red changes a line/" <A >B &&
75sed -e "/^G /s/.*/G : colored branch changes a line/" <M >N &&
76rm -f A M &&
77git update-index --add --remove A B M N &&
78git commit -m "red renames A->B, M->N" &&
79
80git checkout blue &&
81sed -e "/^g /s/.*/g : blue changes a line/" <A >C &&
82sed -e "/^G /s/.*/G : colored branch changes a line/" <M >N &&
83rm -f A M &&
84git update-index --add --remove A C M N &&
85git commit -m "blue renames A->C, M->N" &&
86
87git checkout change &&
88sed -e "/^g /s/.*/g : changed line/" <A >A+ &&
89mv A+ A &&
90git commit -q -a -m "changed" &&
91
92git checkout change+rename &&
93sed -e "/^g /s/.*/g : changed line/" <A >B &&
94rm A &&
95git update-index --add B &&
96git commit -q -a -m "changed and renamed" &&
97
98git checkout master'
99
100test_expect_success 'pull renaming branch into unrenaming one' \
101'
102 git show-branch
103 git pull . white && {
104 echo "BAD: should have conflicted"
105 return 1
106 }
107 git ls-files -s
108 test "$(git ls-files -u B | wc -l)" -eq 3 || {
109 echo "BAD: should have left stages for B"
110 return 1
111 }
112 test "$(git ls-files -s N | wc -l)" -eq 1 || {
113 echo "BAD: should have merged N"
114 return 1
115 }
116 sed -ne "/^g/{
117 p
118 q
119 }" B | grep master || {
120 echo "BAD: should have listed our change first"
121 return 1
122 }
123 test "$(git diff white N | wc -l)" -eq 0 || {
124 echo "BAD: should have taken colored branch"
125 return 1
126 }
127'
128
129test_expect_success 'pull renaming branch into another renaming one' \
130'
131 rm -f B
132 git reset --hard
133 git checkout red
134 git pull . white && {
135 echo "BAD: should have conflicted"
136 return 1
137 }
138 test "$(git ls-files -u B | wc -l)" -eq 3 || {
139 echo "BAD: should have left stages"
140 return 1
141 }
142 test "$(git ls-files -s N | wc -l)" -eq 1 || {
143 echo "BAD: should have merged N"
144 return 1
145 }
146 sed -ne "/^g/{
147 p
148 q
149 }" B | grep red || {
150 echo "BAD: should have listed our change first"
151 return 1
152 }
153 test "$(git diff white N | wc -l)" -eq 0 || {
154 echo "BAD: should have taken colored branch"
155 return 1
156 }
157'
158
159test_expect_success 'pull unrenaming branch into renaming one' \
160'
161 git reset --hard
162 git show-branch
163 git pull . master && {
164 echo "BAD: should have conflicted"
165 return 1
166 }
167 test "$(git ls-files -u B | wc -l)" -eq 3 || {
168 echo "BAD: should have left stages"
169 return 1
170 }
171 test "$(git ls-files -s N | wc -l)" -eq 1 || {
172 echo "BAD: should have merged N"
173 return 1
174 }
175 sed -ne "/^g/{
176 p
177 q
178 }" B | grep red || {
179 echo "BAD: should have listed our change first"
180 return 1
181 }
182 test "$(git diff white N | wc -l)" -eq 0 || {
183 echo "BAD: should have taken colored branch"
184 return 1
185 }
186'
187
188test_expect_success 'pull conflicting renames' \
189'
190 git reset --hard
191 git show-branch
192 git pull . blue && {
193 echo "BAD: should have conflicted"
194 return 1
195 }
196 test "$(git ls-files -u A | wc -l)" -eq 1 || {
197 echo "BAD: should have left a stage"
198 return 1
199 }
200 test "$(git ls-files -u B | wc -l)" -eq 1 || {
201 echo "BAD: should have left a stage"
202 return 1
203 }
204 test "$(git ls-files -u C | wc -l)" -eq 1 || {
205 echo "BAD: should have left a stage"
206 return 1
207 }
208 test "$(git ls-files -s N | wc -l)" -eq 1 || {
209 echo "BAD: should have merged N"
210 return 1
211 }
212 sed -ne "/^g/{
213 p
214 q
215 }" B | grep red || {
216 echo "BAD: should have listed our change first"
217 return 1
218 }
219 test "$(git diff white N | wc -l)" -eq 0 || {
220 echo "BAD: should have taken colored branch"
221 return 1
222 }
223'
224
225test_expect_success 'interference with untracked working tree file' '
226
227 git reset --hard
228 git show-branch
229 echo >A this file should not matter
230 git pull . white && {
231 echo "BAD: should have conflicted"
232 return 1
233 }
234 test -f A || {
235 echo "BAD: should have left A intact"
236 return 1
237 }
238'
239
240test_expect_success 'interference with untracked working tree file' '
241
242 git reset --hard
243 git checkout white
244 git show-branch
245 rm -f A
246 echo >A this file should not matter
247 git pull . red && {
248 echo "BAD: should have conflicted"
249 return 1
250 }
251 test -f A || {
252 echo "BAD: should have left A intact"
253 return 1
254 }
255'
256
257test_expect_success 'interference with untracked working tree file' '
258
259 git reset --hard
260 rm -f A M
261 git checkout -f master
262 git tag -f anchor
263 git show-branch
264 git pull . yellow || {
265 echo "BAD: should have cleanly merged"
266 return 1
267 }
268 test -f M && {
269 echo "BAD: should have removed M"
270 return 1
271 }
272 git reset --hard anchor
273'
274
275test_expect_success 'updated working tree file should prevent the merge' '
276
277 git reset --hard
278 rm -f A M
279 git checkout -f master
280 git tag -f anchor
281 git show-branch
282 echo >>M one line addition
283 cat M >M.saved
284 git pull . yellow && {
285 echo "BAD: should have complained"
286 return 1
287 }
288 test_cmp M M.saved || {
289 echo "BAD: should have left M intact"
290 return 1
291 }
292 rm -f M.saved
293'
294
295test_expect_success 'updated working tree file should prevent the merge' '
296
297 git reset --hard
298 rm -f A M
299 git checkout -f master
300 git tag -f anchor
301 git show-branch
302 echo >>M one line addition
303 cat M >M.saved
304 git update-index M
305 git pull . yellow && {
306 echo "BAD: should have complained"
307 return 1
308 }
309 test_cmp M M.saved || {
310 echo "BAD: should have left M intact"
311 return 1
312 }
313 rm -f M.saved
314'
315
316test_expect_success 'interference with untracked working tree file' '
317
318 git reset --hard
319 rm -f A M
320 git checkout -f yellow
321 git tag -f anchor
322 git show-branch
323 echo >M this file should not matter
324 git pull . master || {
325 echo "BAD: should have cleanly merged"
326 return 1
327 }
328 test -f M || {
329 echo "BAD: should have left M intact"
330 return 1
331 }
332 git ls-files -s | grep M && {
333 echo "BAD: M must be untracked in the result"
334 return 1
335 }
336 git reset --hard anchor
337'
338
339test_expect_success 'merge of identical changes in a renamed file' '
340 rm -f A M N
341 git reset --hard &&
342 git checkout change+rename &&
343 GIT_MERGE_VERBOSITY=3 git merge change | grep "^Skipped B" &&
344 git reset --hard HEAD^ &&
345 git checkout change &&
346 GIT_MERGE_VERBOSITY=3 git merge change+rename | grep "^Skipped B"
347'
348
349test_expect_success 'setup for rename + d/f conflicts' '
350 git reset --hard &&
351 git checkout --orphan dir-in-way &&
352 git rm -rf . &&
353
354 mkdir sub &&
355 mkdir dir &&
356 printf "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n" >sub/file &&
357 echo foo >dir/file-in-the-way &&
358 git add -A &&
359 git commit -m "Common commmit" &&
360
361 echo 11 >>sub/file &&
362 echo more >>dir/file-in-the-way &&
363 git add -u &&
364 git commit -m "Commit to merge, with dir in the way" &&
365
366 git checkout -b dir-not-in-way &&
367 git reset --soft HEAD^ &&
368 git rm -rf dir &&
369 git commit -m "Commit to merge, with dir removed" -- dir sub/file &&
370
371 git checkout -b renamed-file-has-no-conflicts dir-in-way~1 &&
372 git rm -rf dir &&
373 git rm sub/file &&
374 printf "1\n2\n3\n4\n5555\n6\n7\n8\n9\n10\n" >dir &&
375 git add dir &&
376 git commit -m "Independent change" &&
377
378 git checkout -b renamed-file-has-conflicts dir-in-way~1 &&
379 git rm -rf dir &&
380 git mv sub/file dir &&
381 echo 12 >>dir &&
382 git add dir &&
383 git commit -m "Conflicting change"
384'
385
386printf "1\n2\n3\n4\n5555\n6\n7\n8\n9\n10\n11\n" >expected
387
388test_expect_success 'Rename+D/F conflict; renamed file merges + dir not in way' '
389 git reset --hard &&
390 git checkout -q renamed-file-has-no-conflicts^0 &&
391 git merge --strategy=recursive dir-not-in-way &&
392 git diff --quiet &&
393 test -f dir &&
394 test_cmp expected dir
395'
396
397test_expect_failure 'Rename+D/F conflict; renamed file merges but dir in way' '
398 git reset --hard &&
399 rm -rf dir~* &&
400 git checkout -q renamed-file-has-no-conflicts^0 &&
401 test_must_fail git merge --strategy=recursive dir-in-way >output &&
402
403 grep "CONFLICT (delete/modify): dir/file-in-the-way" output &&
404 grep "Auto-merging dir" output &&
405 grep "Adding as dir~HEAD instead" output &&
406
407 test 2 = "$(git ls-files -u | wc -l)" &&
408 test 2 = "$(git ls-files -u dir/file-in-the-way | wc -l)" &&
409
410 test_must_fail git diff --quiet &&
411 test_must_fail git diff --cached --quiet &&
412
413 test -f dir/file-in-the-way &&
414 test -f dir~HEAD &&
415 test_cmp expected dir~HEAD
416'
417
418cat >expected <<\EOF &&
4191
4202
4213
4224
4235
4246
4257
4268
4279
42810
429<<<<<<< HEAD
43012
431=======
43211
433>>>>>>> dir-not-in-way
434EOF
435
436test_expect_failure 'Rename+D/F conflict; renamed file cannot merge, dir not in way' '
437 git reset --hard &&
438 rm -rf dir~* &&
439 git checkout -q renamed-file-has-conflicts^0 &&
440 test_must_fail git merge --strategy=recursive dir-not-in-way &&
441
442 test 3 = "$(git ls-files -u | wc -l)" &&
443 test 3 = "$(git ls-files -u dir | wc -l)" &&
444
445 test_must_fail git diff --quiet &&
446 test_must_fail git diff --cached --quiet &&
447
448 test -f dir &&
449 test_cmp expected dir
450'
451
452test_expect_failure 'Rename+D/F conflict; renamed file cannot merge and dir in the way' '
453 modify s/dir-not-in-way/dir-in-way/ expected &&
454
455 git reset --hard &&
456 rm -rf dir~* &&
457 git checkout -q renamed-file-has-conflicts^0 &&
458 test_must_fail git merge --strategy=recursive dir-in-way &&
459
460 test 5 = "$(git ls-files -u | wc -l)" &&
461 test 3 = "$(git ls-files -u dir | grep -v file-in-the-way | wc -l)" &&
462 test 2 = "$(git ls-files -u dir/file-in-the-way | wc -l)" &&
463
464 test_must_fail git diff --quiet &&
465 test_must_fail git diff --cached --quiet &&
466
467 test -f dir/file-in-the-way &&
468 test -f dir~HEAD &&
469 test_cmp expected dir~HEAD
470'
471
472test_done