]> git.ipfire.org Git - thirdparty/git.git/blob - t/t4200-rerere.sh
Merge branch 'jk/rev-list-disk-usage'
[thirdparty/git.git] / t / t4200-rerere.sh
1 #!/bin/sh
2 #
3 # Copyright (c) 2006 Johannes E. Schindelin
4 #
5
6 test_description='git rerere
7
8 ! [fifth] version1
9 ! [first] first
10 ! [fourth] version1
11 ! [main] initial
12 ! [second] prefer first over second
13 ! [third] version2
14 ------
15 + [third] version2
16 + [fifth] version1
17 + [fourth] version1
18 + + + [third^] third
19 - [second] prefer first over second
20 + + [first] first
21 + [second^] second
22 ++++++ [main] initial
23 '
24
25 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
26 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
27
28 . ./test-lib.sh
29
30 test_expect_success 'setup' '
31 cat >a1 <<-\EOF &&
32 Some title
33 ==========
34 Whether '\''tis nobler in the mind to suffer
35 The slings and arrows of outrageous fortune,
36 Or to take arms against a sea of troubles,
37 And by opposing end them? To die: to sleep;
38 No more; and by a sleep to say we end
39 The heart-ache and the thousand natural shocks
40 That flesh is heir to, '\''tis a consummation
41 Devoutly to be wish'\''d.
42 EOF
43
44 git add a1 &&
45 test_tick &&
46 git commit -q -a -m initial &&
47
48 cat >>a1 <<-\EOF &&
49 Some title
50 ==========
51 To die, to sleep;
52 To sleep: perchance to dream: ay, there'\''s the rub;
53 For in that sleep of death what dreams may come
54 When we have shuffled off this mortal coil,
55 Must give us pause: there'\''s the respect
56 That makes calamity of so long life;
57 EOF
58
59 git checkout -b first &&
60 test_tick &&
61 git commit -q -a -m first &&
62
63 git checkout -b second main &&
64 git show first:a1 |
65 sed -e "s/To die, t/To die! T/" -e "s/Some title/Some Title/" >a1 &&
66 echo "* END *" >>a1 &&
67 test_tick &&
68 git commit -q -a -m second
69 '
70
71 test_expect_success 'nothing recorded without rerere' '
72 rm -rf .git/rr-cache &&
73 git config rerere.enabled false &&
74 test_must_fail git merge first &&
75 ! test -d .git/rr-cache
76 '
77
78 test_expect_success 'activate rerere, old style (conflicting merge)' '
79 git reset --hard &&
80 mkdir .git/rr-cache &&
81 test_might_fail git config --unset rerere.enabled &&
82 test_must_fail git merge first &&
83
84 sha1=$(perl -pe "s/ .*//" .git/MERGE_RR) &&
85 rr=.git/rr-cache/$sha1 &&
86 grep "^=======\$" $rr/preimage &&
87 ! test -f $rr/postimage &&
88 ! test -f $rr/thisimage
89 '
90
91 test_expect_success 'rerere.enabled works, too' '
92 rm -rf .git/rr-cache &&
93 git config rerere.enabled true &&
94 git reset --hard &&
95 test_must_fail git merge first &&
96
97 sha1=$(perl -pe "s/ .*//" .git/MERGE_RR) &&
98 rr=.git/rr-cache/$sha1 &&
99 grep ^=======$ $rr/preimage
100 '
101
102 test_expect_success 'set up rr-cache' '
103 rm -rf .git/rr-cache &&
104 git config rerere.enabled true &&
105 git reset --hard &&
106 test_must_fail git merge first &&
107 sha1=$(perl -pe "s/ .*//" .git/MERGE_RR) &&
108 rr=.git/rr-cache/$sha1
109 '
110
111 test_expect_success 'rr-cache looks sane' '
112 # no postimage or thisimage yet
113 ! test -f $rr/postimage &&
114 ! test -f $rr/thisimage &&
115
116 # preimage has right number of lines
117 cnt=$(sed -ne "/^<<<<<<</,/^>>>>>>>/p" $rr/preimage | wc -l) &&
118 echo $cnt &&
119 test $cnt = 13
120 '
121
122 test_expect_success 'rerere diff' '
123 git show first:a1 >a1 &&
124 cat >expect <<-\EOF &&
125 --- a/a1
126 +++ b/a1
127 @@ -1,4 +1,4 @@
128 -Some Title
129 +Some title
130 ==========
131 Whether '\''tis nobler in the mind to suffer
132 The slings and arrows of outrageous fortune,
133 @@ -8,21 +8,11 @@
134 The heart-ache and the thousand natural shocks
135 That flesh is heir to, '\''tis a consummation
136 Devoutly to be wish'\''d.
137 -<<<<<<<
138 -Some Title
139 -==========
140 -To die! To sleep;
141 -=======
142 Some title
143 ==========
144 To die, to sleep;
145 ->>>>>>>
146 To sleep: perchance to dream: ay, there'\''s the rub;
147 For in that sleep of death what dreams may come
148 When we have shuffled off this mortal coil,
149 Must give us pause: there'\''s the respect
150 That makes calamity of so long life;
151 -<<<<<<<
152 -=======
153 -* END *
154 ->>>>>>>
155 EOF
156 git rerere diff >out &&
157 test_cmp expect out
158 '
159
160 test_expect_success 'rerere status' '
161 echo a1 >expect &&
162 git rerere status >out &&
163 test_cmp expect out
164 '
165
166 test_expect_success 'first postimage wins' '
167 git show first:a1 | sed "s/To die: t/To die! T/" >expect &&
168
169 git commit -q -a -m "prefer first over second" &&
170 test -f $rr/postimage &&
171
172 oldmtimepost=$(test-tool chmtime --get -60 $rr/postimage) &&
173
174 git checkout -b third main &&
175 git show second^:a1 | sed "s/To die: t/To die! T/" >a1 &&
176 git commit -q -a -m third &&
177
178 test_must_fail git merge first &&
179 # rerere kicked in
180 ! grep "^=======\$" a1 &&
181 test_cmp expect a1
182 '
183
184 test_expect_success 'rerere updates postimage timestamp' '
185 newmtimepost=$(test-tool chmtime --get $rr/postimage) &&
186 test $oldmtimepost -lt $newmtimepost
187 '
188
189 test_expect_success 'rerere clear' '
190 mv $rr/postimage .git/post-saved &&
191 echo "$sha1 a1" | perl -pe "y/\012/\000/" >.git/MERGE_RR &&
192 git rerere clear &&
193 ! test -d $rr
194 '
195
196 test_expect_success 'leftover directory' '
197 git reset --hard &&
198 mkdir -p $rr &&
199 test_must_fail git merge first &&
200 test -f $rr/preimage
201 '
202
203 test_expect_success 'missing preimage' '
204 git reset --hard &&
205 mkdir -p $rr &&
206 cp .git/post-saved $rr/postimage &&
207 test_must_fail git merge first &&
208 test -f $rr/preimage
209 '
210
211 test_expect_success 'set up for garbage collection tests' '
212 mkdir -p $rr &&
213 echo Hello >$rr/preimage &&
214 echo World >$rr/postimage &&
215
216 sha2=$(test_oid deadbeef) &&
217 rr2=.git/rr-cache/$sha2 &&
218 mkdir $rr2 &&
219 echo Hello >$rr2/preimage &&
220
221 almost_15_days_ago=$((60-15*86400)) &&
222 just_over_15_days_ago=$((-1-15*86400)) &&
223 almost_60_days_ago=$((60-60*86400)) &&
224 just_over_60_days_ago=$((-1-60*86400)) &&
225
226 test-tool chmtime =$just_over_60_days_ago $rr/preimage &&
227 test-tool chmtime =$almost_60_days_ago $rr/postimage &&
228 test-tool chmtime =$almost_15_days_ago $rr2/preimage
229 '
230
231 test_expect_success 'gc preserves young or recently used records' '
232 git rerere gc &&
233 test -f $rr/preimage &&
234 test -f $rr2/preimage
235 '
236
237 test_expect_success 'old records rest in peace' '
238 test-tool chmtime =$just_over_60_days_ago $rr/postimage &&
239 test-tool chmtime =$just_over_15_days_ago $rr2/preimage &&
240 git rerere gc &&
241 ! test -f $rr/preimage &&
242 ! test -f $rr2/preimage
243 '
244
245 rerere_gc_custom_expiry_test () {
246 five_days="$1" right_now="$2"
247 test_expect_success "rerere gc with custom expiry ($five_days, $right_now)" '
248 rm -fr .git/rr-cache &&
249 rr=.git/rr-cache/$ZERO_OID &&
250 mkdir -p "$rr" &&
251 >"$rr/preimage" &&
252 >"$rr/postimage" &&
253
254 two_days_ago=$((-2*86400)) &&
255 test-tool chmtime =$two_days_ago "$rr/preimage" &&
256 test-tool chmtime =$two_days_ago "$rr/postimage" &&
257
258 find .git/rr-cache -type f | sort >original &&
259
260 git -c "gc.rerereresolved=$five_days" \
261 -c "gc.rerereunresolved=$five_days" rerere gc &&
262 find .git/rr-cache -type f | sort >actual &&
263 test_cmp original actual &&
264
265 git -c "gc.rerereresolved=$five_days" \
266 -c "gc.rerereunresolved=$right_now" rerere gc &&
267 find .git/rr-cache -type f | sort >actual &&
268 test_cmp original actual &&
269
270 git -c "gc.rerereresolved=$right_now" \
271 -c "gc.rerereunresolved=$right_now" rerere gc &&
272 find .git/rr-cache -type f | sort >actual &&
273 test_must_be_empty actual
274 '
275 }
276
277 rerere_gc_custom_expiry_test 5 0
278
279 rerere_gc_custom_expiry_test 5.days.ago now
280
281 test_expect_success 'setup: file2 added differently in two branches' '
282 git reset --hard &&
283
284 git checkout -b fourth &&
285 echo Hallo >file2 &&
286 git add file2 &&
287 test_tick &&
288 git commit -m version1 &&
289
290 git checkout third &&
291 echo Bello >file2 &&
292 git add file2 &&
293 test_tick &&
294 git commit -m version2 &&
295
296 test_must_fail git merge fourth &&
297 echo Cello >file2 &&
298 git add file2 &&
299 git commit -m resolution
300 '
301
302 test_expect_success 'resolution was recorded properly' '
303 echo Cello >expected &&
304
305 git reset --hard HEAD~2 &&
306 git checkout -b fifth &&
307
308 echo Hallo >file3 &&
309 git add file3 &&
310 test_tick &&
311 git commit -m version1 &&
312
313 git checkout third &&
314 echo Bello >file3 &&
315 git add file3 &&
316 test_tick &&
317 git commit -m version2 &&
318 git tag version2 &&
319
320 test_must_fail git merge fifth &&
321 test_cmp expected file3 &&
322 test_must_fail git update-index --refresh
323 '
324
325 test_expect_success 'rerere.autoupdate' '
326 git config rerere.autoupdate true &&
327 git reset --hard &&
328 git checkout version2 &&
329 test_must_fail git merge fifth &&
330 git update-index --refresh
331 '
332
333 test_expect_success 'merge --rerere-autoupdate' '
334 test_might_fail git config --unset rerere.autoupdate &&
335 git reset --hard &&
336 git checkout version2 &&
337 test_must_fail git merge --rerere-autoupdate fifth &&
338 git update-index --refresh
339 '
340
341 test_expect_success 'merge --no-rerere-autoupdate' '
342 headblob=$(git rev-parse version2:file3) &&
343 mergeblob=$(git rev-parse fifth:file3) &&
344 cat >expected <<-EOF &&
345 100644 $headblob 2 file3
346 100644 $mergeblob 3 file3
347 EOF
348
349 git config rerere.autoupdate true &&
350 git reset --hard &&
351 git checkout version2 &&
352 test_must_fail git merge --no-rerere-autoupdate fifth &&
353 git ls-files -u >actual &&
354 test_cmp expected actual
355 '
356
357 test_expect_success 'set up an unresolved merge' '
358 headblob=$(git rev-parse version2:file3) &&
359 mergeblob=$(git rev-parse fifth:file3) &&
360 cat >expected.unresolved <<-EOF &&
361 100644 $headblob 2 file3
362 100644 $mergeblob 3 file3
363 EOF
364
365 test_might_fail git config --unset rerere.autoupdate &&
366 git reset --hard &&
367 git checkout version2 &&
368 fifth=$(git rev-parse fifth) &&
369 echo "$fifth branch fifth of ." |
370 git fmt-merge-msg >msg &&
371 ancestor=$(git merge-base version2 fifth) &&
372 test_must_fail git merge-recursive "$ancestor" -- HEAD fifth &&
373
374 git ls-files --stage >failedmerge &&
375 cp file3 file3.conflict &&
376
377 git ls-files -u >actual &&
378 test_cmp expected.unresolved actual
379 '
380
381 test_expect_success 'explicit rerere' '
382 test_might_fail git config --unset rerere.autoupdate &&
383 git rm -fr --cached . &&
384 git update-index --index-info <failedmerge &&
385 cp file3.conflict file3 &&
386 test_must_fail git update-index --refresh -q &&
387
388 git rerere &&
389 git ls-files -u >actual &&
390 test_cmp expected.unresolved actual
391 '
392
393 test_expect_success 'explicit rerere with autoupdate' '
394 git config rerere.autoupdate true &&
395 git rm -fr --cached . &&
396 git update-index --index-info <failedmerge &&
397 cp file3.conflict file3 &&
398 test_must_fail git update-index --refresh -q &&
399
400 git rerere &&
401 git update-index --refresh
402 '
403
404 test_expect_success 'explicit rerere --rerere-autoupdate overrides' '
405 git config rerere.autoupdate false &&
406 git rm -fr --cached . &&
407 git update-index --index-info <failedmerge &&
408 cp file3.conflict file3 &&
409 git rerere &&
410 git ls-files -u >actual1 &&
411
412 git rm -fr --cached . &&
413 git update-index --index-info <failedmerge &&
414 cp file3.conflict file3 &&
415 git rerere --rerere-autoupdate &&
416 git update-index --refresh &&
417
418 git rm -fr --cached . &&
419 git update-index --index-info <failedmerge &&
420 cp file3.conflict file3 &&
421 git rerere --rerere-autoupdate --no-rerere-autoupdate &&
422 git ls-files -u >actual2 &&
423
424 git rm -fr --cached . &&
425 git update-index --index-info <failedmerge &&
426 cp file3.conflict file3 &&
427 git rerere --rerere-autoupdate --no-rerere-autoupdate --rerere-autoupdate &&
428 git update-index --refresh &&
429
430 test_cmp expected.unresolved actual1 &&
431 test_cmp expected.unresolved actual2
432 '
433
434 test_expect_success 'rerere --no-no-rerere-autoupdate' '
435 git rm -fr --cached . &&
436 git update-index --index-info <failedmerge &&
437 cp file3.conflict file3 &&
438 test_must_fail git rerere --no-no-rerere-autoupdate 2>err &&
439 test_i18ngrep [Uu]sage err &&
440 test_must_fail git update-index --refresh
441 '
442
443 test_expect_success 'rerere -h' '
444 test_must_fail git rerere -h >help &&
445 test_i18ngrep [Uu]sage help
446 '
447
448 concat_insert () {
449 last=$1
450 shift
451 cat early && printf "%s\n" "$@" && cat late "$last"
452 }
453
454 count_pre_post () {
455 find .git/rr-cache/ -type f -name "preimage*" >actual &&
456 test_line_count = "$1" actual &&
457 find .git/rr-cache/ -type f -name "postimage*" >actual &&
458 test_line_count = "$2" actual
459 }
460
461 merge_conflict_resolve () {
462 git reset --hard &&
463 test_must_fail git merge six.1 &&
464 # Resolution is to replace 7 with 6.1 and 6.2 (i.e. take both)
465 concat_insert short 6.1 6.2 >file1 &&
466 concat_insert long 6.1 6.2 >file2
467 }
468
469 test_expect_success 'multiple identical conflicts' '
470 rm -fr .git/rr-cache &&
471 mkdir .git/rr-cache &&
472 git reset --hard &&
473
474 test_seq 1 6 >early &&
475 >late &&
476 test_seq 11 15 >short &&
477 test_seq 111 120 >long &&
478 concat_insert short >file1 &&
479 concat_insert long >file2 &&
480 git add file1 file2 &&
481 git commit -m base &&
482 git tag base &&
483 git checkout -b six.1 &&
484 concat_insert short 6.1 >file1 &&
485 concat_insert long 6.1 >file2 &&
486 git add file1 file2 &&
487 git commit -m 6.1 &&
488 git checkout -b six.2 HEAD^ &&
489 concat_insert short 6.2 >file1 &&
490 concat_insert long 6.2 >file2 &&
491 git add file1 file2 &&
492 git commit -m 6.2 &&
493
494 # At this point, six.1 and six.2
495 # - derive from common ancestor that has two files
496 # 1...6 7 11..15 (file1) and 1...6 7 111..120 (file2)
497 # - six.1 replaces these 7s with 6.1
498 # - six.2 replaces these 7s with 6.2
499
500 merge_conflict_resolve &&
501
502 # Check that rerere knows that file1 and file2 have conflicts
503
504 printf "%s\n" file1 file2 >expect &&
505 git ls-files -u | sed -e "s/^.* //" | sort -u >actual &&
506 test_cmp expect actual &&
507
508 git rerere status | sort >actual &&
509 test_cmp expect actual &&
510
511 git rerere remaining >actual &&
512 test_cmp expect actual &&
513
514 count_pre_post 2 0 &&
515
516 # Pretend that the conflicts were made quite some time ago
517 test-tool chmtime -172800 $(find .git/rr-cache/ -type f) &&
518
519 # Unresolved entries have not expired yet
520 git -c gc.rerereresolved=5 -c gc.rerereunresolved=5 rerere gc &&
521 count_pre_post 2 0 &&
522
523 # Unresolved entries have expired
524 git -c gc.rerereresolved=5 -c gc.rerereunresolved=1 rerere gc &&
525 count_pre_post 0 0 &&
526
527 # Recreate the conflicted state
528 merge_conflict_resolve &&
529 count_pre_post 2 0 &&
530
531 # Clear it
532 git rerere clear &&
533 count_pre_post 0 0 &&
534
535 # Recreate the conflicted state
536 merge_conflict_resolve &&
537 count_pre_post 2 0 &&
538
539 # We resolved file1 and file2
540 git rerere &&
541 git rerere remaining >actual &&
542 test_must_be_empty actual &&
543
544 # We must have recorded both of them
545 count_pre_post 2 2 &&
546
547 # Now we should be able to resolve them both
548 git reset --hard &&
549 test_must_fail git merge six.1 &&
550 git rerere &&
551
552 git rerere remaining >actual &&
553 test_must_be_empty actual &&
554
555 concat_insert short 6.1 6.2 >file1.expect &&
556 concat_insert long 6.1 6.2 >file2.expect &&
557 test_cmp file1.expect file1 &&
558 test_cmp file2.expect file2 &&
559
560 # Forget resolution for file2
561 git rerere forget file2 &&
562 echo file2 >expect &&
563 git rerere status >actual &&
564 test_cmp expect actual &&
565 count_pre_post 2 1 &&
566
567 # file2 already has correct resolution, so record it again
568 git rerere &&
569
570 # Pretend that the resolutions are old again
571 test-tool chmtime -172800 $(find .git/rr-cache/ -type f) &&
572
573 # Resolved entries have not expired yet
574 git -c gc.rerereresolved=5 -c gc.rerereunresolved=5 rerere gc &&
575
576 count_pre_post 2 2 &&
577
578 # Resolved entries have expired
579 git -c gc.rerereresolved=1 -c gc.rerereunresolved=5 rerere gc &&
580 count_pre_post 0 0
581 '
582
583 test_expect_success 'rerere with unexpected conflict markers does not crash' '
584 git reset --hard &&
585
586 git checkout -b branch-1 main &&
587 echo "bar" >test &&
588 git add test &&
589 git commit -q -m two &&
590
591 git reset --hard &&
592 git checkout -b branch-2 main &&
593 echo "foo" >test &&
594 git add test &&
595 git commit -q -a -m one &&
596
597 test_must_fail git merge branch-1 &&
598 echo "<<<<<<< a" >test &&
599 git rerere &&
600
601 git rerere clear
602 '
603
604 test_expect_success 'rerere with inner conflict markers' '
605 git reset --hard &&
606
607 git checkout -b A main &&
608 echo "bar" >test &&
609 git add test &&
610 git commit -q -m two &&
611 echo "baz" >test &&
612 git add test &&
613 git commit -q -m three &&
614
615 git reset --hard &&
616 git checkout -b B main &&
617 echo "foo" >test &&
618 git add test &&
619 git commit -q -a -m one &&
620
621 test_must_fail git merge A~ &&
622 git add test &&
623 git commit -q -m "will solve conflicts later" &&
624 test_must_fail git merge A &&
625
626 echo "resolved" >test &&
627 git add test &&
628 git commit -q -m "solved conflict" &&
629
630 echo "resolved" >expect &&
631
632 git reset --hard HEAD~~ &&
633 test_must_fail git merge A~ &&
634 git add test &&
635 git commit -q -m "will solve conflicts later" &&
636 test_must_fail git merge A &&
637 cat test >actual &&
638 test_cmp expect actual &&
639
640 git add test &&
641 git commit -m "rerere solved conflict" &&
642 git reset --hard HEAD~ &&
643 test_must_fail git merge A &&
644 cat test >actual &&
645 test_cmp expect actual
646 '
647
648 test_expect_success 'setup simple stage 1 handling' '
649 test_create_repo stage_1_handling &&
650 (
651 cd stage_1_handling &&
652
653 test_seq 1 10 >original &&
654 git add original &&
655 git commit -m original &&
656
657 git checkout -b A main &&
658 git mv original A &&
659 git commit -m "rename to A" &&
660
661 git checkout -b B main &&
662 git mv original B &&
663 git commit -m "rename to B"
664 )
665 '
666
667 test_expect_success 'test simple stage 1 handling' '
668 (
669 cd stage_1_handling &&
670
671 git config rerere.enabled true &&
672 git checkout A^0 &&
673 test_must_fail git merge B^0
674 )
675 '
676
677 test_done