3 # Copyright (c) 2006 Johannes E. Schindelin
6 test_description
='git rerere
12 ! [second] prefer first over second
19 - [second] prefer first over second
25 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
=main
26 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
30 test_expect_success
'setup' '
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.
46 git commit -q -a -m initial &&
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;
59 git checkout -b first &&
61 git commit -q -a -m first &&
63 git checkout -b second main &&
65 sed -e "s/To die, t/To die! T/" -e "s/Some title/Some Title/" >a1 &&
66 echo "* END *" >>a1 &&
68 git commit -q -a -m second
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
78 test_expect_success
'activate rerere, old style (conflicting merge)' '
80 mkdir .git/rr-cache &&
81 test_might_fail git config --unset rerere.enabled &&
82 test_must_fail git merge first &&
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
91 test_expect_success
'rerere.enabled works, too' '
92 rm -rf .git/rr-cache &&
93 git config rerere.enabled true &&
95 test_must_fail git merge first &&
97 sha1=$(perl -pe "s/ .*//" .git/MERGE_RR) &&
98 rr=.git/rr-cache/$sha1 &&
99 grep ^=======$ $rr/preimage
102 test_expect_success
'set up rr-cache' '
103 rm -rf .git/rr-cache &&
104 git config rerere.enabled true &&
106 test_must_fail git merge first &&
107 sha1=$(perl -pe "s/ .*//" .git/MERGE_RR) &&
108 rr=.git/rr-cache/$sha1
111 test_expect_success
'rr-cache looks sane' '
112 # no postimage or thisimage yet
113 ! test -f $rr/postimage &&
114 ! test -f $rr/thisimage &&
116 # preimage has right number of lines
117 cnt=$(sed -ne "/^<<<<<<</,/^>>>>>>>/p" $rr/preimage | wc -l) &&
122 test_expect_success
'rerere diff' '
123 git show first:a1 >a1 &&
124 cat >expect <<-\EOF &&
131 Whether '\''tis nobler in the mind to suffer
132 The slings and arrows of outrageous fortune,
134 The heart-ache and the thousand natural shocks
135 That flesh is heir to, '\''tis a consummation
136 Devoutly to be wish'\''d.
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;
156 git rerere diff >out &&
160 test_expect_success
'rerere status' '
162 git rerere status >out &&
166 test_expect_success
'first postimage wins' '
167 git show first:a1 | sed "s/To die: t/To die! T/" >expect &&
169 git commit -q -a -m "prefer first over second" &&
170 test -f $rr/postimage &&
172 oldmtimepost=$(test-tool chmtime --get -60 $rr/postimage) &&
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 &&
178 test_must_fail git merge first &&
180 ! grep "^=======\$" a1 &&
184 test_expect_success
'rerere updates postimage timestamp' '
185 newmtimepost=$(test-tool chmtime --get $rr/postimage) &&
186 test $oldmtimepost -lt $newmtimepost
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 &&
196 test_expect_success
'leftover directory' '
199 test_must_fail git merge first &&
203 test_expect_success
'missing preimage' '
206 cp .git/post-saved $rr/postimage &&
207 test_must_fail git merge first &&
211 test_expect_success
'set up for garbage collection tests' '
213 echo Hello >$rr/preimage &&
214 echo World >$rr/postimage &&
216 sha2=$(test_oid deadbeef) &&
217 rr2=.git/rr-cache/$sha2 &&
219 echo Hello >$rr2/preimage &&
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)) &&
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
231 test_expect_success
'gc preserves young or recently used records' '
233 test -f $rr/preimage &&
234 test -f $rr2/preimage
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 &&
241 ! test -f $rr/preimage &&
242 ! test -f $rr2/preimage
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 &&
254 two_days_ago=$((-2*86400)) &&
255 test-tool chmtime =$two_days_ago "$rr/preimage" &&
256 test-tool chmtime =$two_days_ago "$rr/postimage" &&
258 find .git/rr-cache -type f | sort >original &&
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 &&
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 &&
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
277 rerere_gc_custom_expiry_test
5 0
279 rerere_gc_custom_expiry_test
5.days.ago now
281 test_expect_success
'setup: file2 added differently in two branches' '
284 git checkout -b fourth &&
288 git commit -m version1 &&
290 git checkout third &&
294 git commit -m version2 &&
296 test_must_fail git merge fourth &&
299 git commit -m resolution
302 test_expect_success
'resolution was recorded properly' '
303 echo Cello >expected &&
305 git reset --hard HEAD~2 &&
306 git checkout -b fifth &&
311 git commit -m version1 &&
313 git checkout third &&
317 git commit -m version2 &&
320 test_must_fail git merge fifth &&
321 test_cmp expected file3 &&
322 test_must_fail git update-index --refresh
325 test_expect_success
'rerere.autoupdate' '
326 git config rerere.autoupdate true &&
328 git checkout version2 &&
329 test_must_fail git merge fifth &&
330 git update-index --refresh
333 test_expect_success
'merge --rerere-autoupdate' '
334 test_might_fail git config --unset rerere.autoupdate &&
336 git checkout version2 &&
337 test_must_fail git merge --rerere-autoupdate fifth &&
338 git update-index --refresh
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
349 git config rerere.autoupdate true &&
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
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
365 test_might_fail git config --unset rerere.autoupdate &&
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 &&
374 git ls-files --stage >failedmerge &&
375 cp file3 file3.conflict &&
377 git ls-files -u >actual &&
378 test_cmp expected.unresolved actual
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 &&
389 git ls-files -u >actual &&
390 test_cmp expected.unresolved actual
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 &&
401 git update-index --refresh
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 &&
410 git ls-files -u >actual1 &&
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 &&
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 &&
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 &&
430 test_cmp expected.unresolved actual1 &&
431 test_cmp expected.unresolved actual2
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
443 test_expect_success
'rerere -h' '
444 test_must_fail git rerere -h >help &&
445 test_i18ngrep [Uu]sage help
451 cat early
&& printf "%s\n" "$@" && cat late
"$last"
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
461 merge_conflict_resolve
() {
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
469 test_expect_success
'multiple identical conflicts' '
470 rm -fr .git/rr-cache &&
471 mkdir .git/rr-cache &&
474 test_seq 1 6 >early &&
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 &&
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 &&
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 &&
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
500 merge_conflict_resolve &&
502 # Check that rerere knows that file1 and file2 have conflicts
504 printf "%s\n" file1 file2 >expect &&
505 git ls-files -u | sed -e "s/^.* //" | sort -u >actual &&
506 test_cmp expect actual &&
508 git rerere status | sort >actual &&
509 test_cmp expect actual &&
511 git rerere remaining >actual &&
512 test_cmp expect actual &&
514 count_pre_post 2 0 &&
516 # Pretend that the conflicts were made quite some time ago
517 test-tool chmtime -172800 $(find .git/rr-cache/ -type f) &&
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 &&
523 # Unresolved entries have expired
524 git -c gc.rerereresolved=5 -c gc.rerereunresolved=1 rerere gc &&
525 count_pre_post 0 0 &&
527 # Recreate the conflicted state
528 merge_conflict_resolve &&
529 count_pre_post 2 0 &&
533 count_pre_post 0 0 &&
535 # Recreate the conflicted state
536 merge_conflict_resolve &&
537 count_pre_post 2 0 &&
539 # We resolved file1 and file2
541 git rerere remaining >actual &&
542 test_must_be_empty actual &&
544 # We must have recorded both of them
545 count_pre_post 2 2 &&
547 # Now we should be able to resolve them both
549 test_must_fail git merge six.1 &&
552 git rerere remaining >actual &&
553 test_must_be_empty actual &&
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 &&
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 &&
567 # file2 already has correct resolution, so record it again
570 # Pretend that the resolutions are old again
571 test-tool chmtime -172800 $(find .git/rr-cache/ -type f) &&
573 # Resolved entries have not expired yet
574 git -c gc.rerereresolved=5 -c gc.rerereunresolved=5 rerere gc &&
576 count_pre_post 2 2 &&
578 # Resolved entries have expired
579 git -c gc.rerereresolved=1 -c gc.rerereunresolved=5 rerere gc &&
583 test_expect_success
'rerere with unexpected conflict markers does not crash' '
586 git checkout -b branch-1 main &&
589 git commit -q -m two &&
592 git checkout -b branch-2 main &&
595 git commit -q -a -m one &&
597 test_must_fail git merge branch-1 &&
598 echo "<<<<<<< a" >test &&
604 test_expect_success
'rerere with inner conflict markers' '
607 git checkout -b A main &&
610 git commit -q -m two &&
613 git commit -q -m three &&
616 git checkout -b B main &&
619 git commit -q -a -m one &&
621 test_must_fail git merge A~ &&
623 git commit -q -m "will solve conflicts later" &&
624 test_must_fail git merge A &&
626 echo "resolved" >test &&
628 git commit -q -m "solved conflict" &&
630 echo "resolved" >expect &&
632 git reset --hard HEAD~~ &&
633 test_must_fail git merge A~ &&
635 git commit -q -m "will solve conflicts later" &&
636 test_must_fail git merge A &&
638 test_cmp expect actual &&
641 git commit -m "rerere solved conflict" &&
642 git reset --hard HEAD~ &&
643 test_must_fail git merge A &&
645 test_cmp expect actual
648 test_expect_success
'setup simple stage 1 handling' '
649 test_create_repo stage_1_handling &&
651 cd stage_1_handling &&
653 test_seq 1 10 >original &&
655 git commit -m original &&
657 git checkout -b A main &&
659 git commit -m "rename to A" &&
661 git checkout -b B main &&
663 git commit -m "rename to B"
667 test_expect_success
'test simple stage 1 handling' '
669 cd stage_1_handling &&
671 git config rerere.enabled true &&
673 test_must_fail git merge B^0