|  | #!/bin/sh | 
|  |  | 
|  | test_description='undoing resolution' | 
|  |  | 
|  | GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main | 
|  | export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME | 
|  |  | 
|  | . ./test-lib.sh | 
|  |  | 
|  | check_resolve_undo () { | 
|  | msg=$1 | 
|  | shift | 
|  | while case $# in | 
|  | 0)	break ;; | 
|  | 1|2|3)	die "Bug in check-resolve-undo test" ;; | 
|  | esac | 
|  | do | 
|  | path=$1 | 
|  | shift | 
|  | for stage in 1 2 3 | 
|  | do | 
|  | sha1=$1 | 
|  | shift | 
|  | case "$sha1" in | 
|  | '') continue ;; | 
|  | esac | 
|  | sha1=$(git rev-parse --verify "$sha1") | 
|  | printf "100644 %s %s\t%s\n" $sha1 $stage $path | 
|  | done | 
|  | done >"$msg.expect" && | 
|  | git ls-files --resolve-undo >"$msg.actual" && | 
|  | test_cmp "$msg.expect" "$msg.actual" | 
|  | } | 
|  |  | 
|  | prime_resolve_undo () { | 
|  | git reset --hard && | 
|  | git checkout second^0 && | 
|  | test_tick && | 
|  | test_must_fail git merge third^0 && | 
|  | check_resolve_undo empty && | 
|  |  | 
|  | # how should the conflict be resolved? | 
|  | case "$1" in | 
|  | remove) | 
|  | rm -f file/le && git rm fi/le | 
|  | ;; | 
|  | *) # modify | 
|  | echo different >fi/le && git add fi/le | 
|  | ;; | 
|  | esac | 
|  | check_resolve_undo recorded fi/le initial:fi/le second:fi/le third:fi/le | 
|  | } | 
|  |  | 
|  | test_expect_success setup ' | 
|  | mkdir fi && | 
|  | printf "a\0a" >binary && | 
|  | git add binary && | 
|  | test_commit initial fi/le first && | 
|  | git branch side && | 
|  | git branch another && | 
|  | printf "a\0b" >binary && | 
|  | git add binary && | 
|  | test_commit second fi/le second && | 
|  | git checkout side && | 
|  | test_commit third fi/le third && | 
|  | git branch add-add && | 
|  | git checkout another && | 
|  | test_commit fourth fi/le fourth && | 
|  | git checkout add-add && | 
|  | test_commit fifth add-differently && | 
|  | git checkout main | 
|  | ' | 
|  |  | 
|  | test_expect_success 'add records switch clears' ' | 
|  | prime_resolve_undo && | 
|  | test_tick && | 
|  | git commit -m merged && | 
|  | echo committing keeps && | 
|  | check_resolve_undo kept fi/le initial:fi/le second:fi/le third:fi/le && | 
|  | git checkout second^0 && | 
|  | echo switching clears && | 
|  | check_resolve_undo cleared | 
|  | ' | 
|  |  | 
|  | test_expect_success 'rm records reset clears' ' | 
|  | prime_resolve_undo && | 
|  | test_tick && | 
|  | git commit -m merged && | 
|  | echo committing keeps && | 
|  | check_resolve_undo kept fi/le initial:fi/le second:fi/le third:fi/le && | 
|  |  | 
|  | echo merge clears upfront && | 
|  | test_must_fail git merge fourth^0 && | 
|  | check_resolve_undo nuked && | 
|  |  | 
|  | git rm -f fi/le && | 
|  | echo resolving records && | 
|  | check_resolve_undo recorded fi/le initial:fi/le HEAD:fi/le fourth:fi/le && | 
|  |  | 
|  | git reset --hard && | 
|  | echo resetting discards && | 
|  | check_resolve_undo discarded | 
|  | ' | 
|  |  | 
|  | test_expect_success 'plumbing clears' ' | 
|  | prime_resolve_undo && | 
|  | test_tick && | 
|  | git commit -m merged && | 
|  | echo committing keeps && | 
|  | check_resolve_undo kept fi/le initial:fi/le second:fi/le third:fi/le && | 
|  |  | 
|  | echo plumbing clear && | 
|  | git update-index --clear-resolve-undo && | 
|  | check_resolve_undo cleared | 
|  | ' | 
|  |  | 
|  | test_expect_success 'add records checkout -m undoes' ' | 
|  | prime_resolve_undo && | 
|  | git diff HEAD && | 
|  | git checkout --conflict=merge fi/le && | 
|  | echo checkout used the record and removed it && | 
|  | check_resolve_undo removed && | 
|  | echo the index and the work tree is unmerged again && | 
|  | git diff >actual && | 
|  | grep "^++<<<<<<<" actual | 
|  | ' | 
|  |  | 
|  | test_expect_success 'unmerge with plumbing' ' | 
|  | prime_resolve_undo && | 
|  | git update-index --unresolve fi/le && | 
|  | git ls-files --resolve-undo fi/le >actual && | 
|  | test_must_be_empty actual && | 
|  | git ls-files -u >actual && | 
|  | test_line_count = 3 actual | 
|  | ' | 
|  |  | 
|  | test_expect_success 'unmerge can be done even after committing' ' | 
|  | prime_resolve_undo && | 
|  | git commit -m "record to nuke MERGE_HEAD" && | 
|  | git update-index --unresolve fi/le && | 
|  | git ls-files --resolve-undo fi/le >actual && | 
|  | test_must_be_empty actual && | 
|  | git ls-files -u >actual && | 
|  | test_line_count = 3 actual | 
|  | ' | 
|  |  | 
|  | test_expect_success 'unmerge removal' ' | 
|  | prime_resolve_undo remove && | 
|  | git update-index --unresolve fi/le && | 
|  | git ls-files --resolve-undo fi/le >actual && | 
|  | test_must_be_empty actual && | 
|  | git ls-files -u >actual && | 
|  | test_line_count = 3 actual | 
|  | ' | 
|  |  | 
|  | test_expect_success 'unmerge removal after committing' ' | 
|  | prime_resolve_undo remove && | 
|  | git commit -m "record to nuke MERGE_HEAD" && | 
|  | git update-index --unresolve fi/le && | 
|  | git ls-files --resolve-undo fi/le >actual && | 
|  | test_must_be_empty actual && | 
|  | git ls-files -u >actual && | 
|  | test_line_count = 3 actual | 
|  | ' | 
|  |  | 
|  | test_expect_success 'rerere and rerere forget' ' | 
|  | mkdir .git/rr-cache && | 
|  | prime_resolve_undo && | 
|  | echo record the resolution && | 
|  | git rerere && | 
|  | rerere_id=$(cd .git/rr-cache && echo */postimage) && | 
|  | rerere_id=${rerere_id%/postimage} && | 
|  | test -f .git/rr-cache/$rerere_id/postimage && | 
|  | git checkout -m fi/le && | 
|  | echo resurrect the conflict && | 
|  | grep "^=======" fi/le && | 
|  | echo reresolve the conflict && | 
|  | git rerere && | 
|  | test "z$(cat fi/le)" = zdifferent && | 
|  | echo register the resolution again && | 
|  | git add fi/le && | 
|  | check_resolve_undo kept fi/le initial:fi/le second:fi/le third:fi/le && | 
|  | test -z "$(git ls-files -u)" && | 
|  | git rerere forget fi/le && | 
|  | ! test -f .git/rr-cache/$rerere_id/postimage && | 
|  | tr "\0" "\n" <.git/MERGE_RR >actual && | 
|  | echo "$rerere_id	fi/le" >expect && | 
|  | test_cmp expect actual | 
|  | ' | 
|  |  | 
|  | test_expect_success 'rerere and rerere forget (subdirectory)' ' | 
|  | rm -fr .git/rr-cache && | 
|  | mkdir .git/rr-cache && | 
|  | prime_resolve_undo && | 
|  | echo record the resolution && | 
|  | (cd fi && git rerere) && | 
|  | rerere_id=$(cd .git/rr-cache && echo */postimage) && | 
|  | rerere_id=${rerere_id%/postimage} && | 
|  | test -f .git/rr-cache/$rerere_id/postimage && | 
|  | (cd fi && git checkout -m le) && | 
|  | echo resurrect the conflict && | 
|  | grep "^=======" fi/le && | 
|  | echo reresolve the conflict && | 
|  | (cd fi && git rerere) && | 
|  | test "z$(cat fi/le)" = zdifferent && | 
|  | echo register the resolution again && | 
|  | (cd fi && git add le) && | 
|  | check_resolve_undo kept fi/le initial:fi/le second:fi/le third:fi/le && | 
|  | test -z "$(git ls-files -u)" && | 
|  | (cd fi && git rerere forget le) && | 
|  | ! test -f .git/rr-cache/$rerere_id/postimage && | 
|  | tr "\0" "\n" <.git/MERGE_RR >actual && | 
|  | echo "$rerere_id	fi/le" >expect && | 
|  | test_cmp expect actual | 
|  | ' | 
|  |  | 
|  | test_expect_success 'rerere forget (binary)' ' | 
|  | git checkout -f side && | 
|  | test_commit --printf binary binary "a\0c" && | 
|  | test_must_fail git merge second && | 
|  | git rerere forget binary | 
|  | ' | 
|  |  | 
|  | test_expect_success 'rerere forget (add-add conflict)' ' | 
|  | git checkout -f main && | 
|  | echo main >add-differently && | 
|  | git add add-differently && | 
|  | git commit -m "add differently" && | 
|  | test_must_fail git merge fifth && | 
|  | git rerere forget add-differently 2>actual && | 
|  | test_grep "no remembered" actual | 
|  | ' | 
|  |  | 
|  | test_expect_success 'resolve-undo keeps blobs from gc' ' | 
|  | git checkout -f main && | 
|  |  | 
|  | # First make sure we do not have any cruft left in the object store | 
|  | git repack -a -d && | 
|  | git prune --expire=now && | 
|  | git prune-packed && | 
|  | git gc --prune=now && | 
|  | git fsck --unreachable >cruft && | 
|  | test_must_be_empty cruft && | 
|  |  | 
|  | # Now add three otherwise unreferenced blob objects to the index | 
|  | git reset --hard && | 
|  | B1=$(echo "resolve undo test data 1" | git hash-object -w --stdin) && | 
|  | B2=$(echo "resolve undo test data 2" | git hash-object -w --stdin) && | 
|  | B3=$(echo "resolve undo test data 3" | git hash-object -w --stdin) && | 
|  | git update-index --add --index-info <<-EOF && | 
|  | 100644 $B1 1	frotz | 
|  | 100644 $B2 2	frotz | 
|  | 100644 $B3 3	frotz | 
|  | EOF | 
|  |  | 
|  | # These three blob objects are reachable (only) from the index | 
|  | git fsck --unreachable >cruft && | 
|  | test_must_be_empty cruft && | 
|  | # and they should be protected from GC | 
|  | git gc --prune=now && | 
|  | git cat-file -e $B1 && | 
|  | git cat-file -e $B2 && | 
|  | git cat-file -e $B3 && | 
|  |  | 
|  | # Now resolve the conflicted path | 
|  | B0=$(echo "resolve undo test data 0" | git hash-object -w --stdin) && | 
|  | git update-index --add --cacheinfo 100644,$B0,frotz && | 
|  |  | 
|  | # These three blob objects are now reachable only from the resolve-undo | 
|  | git fsck --unreachable >cruft && | 
|  | test_must_be_empty cruft && | 
|  |  | 
|  | # and they should survive GC | 
|  | git gc --prune=now && | 
|  | git cat-file -e $B0 && | 
|  | git cat-file -e $B1 && | 
|  | git cat-file -e $B2 && | 
|  | git cat-file -e $B3 && | 
|  |  | 
|  | # Now we switch away, which nukes resolve-undo, and | 
|  | # blobs B0..B3 would become dangling.  fsck should | 
|  | # notice that they are now unreachable. | 
|  | git checkout -f side && | 
|  | git fsck --unreachable >cruft && | 
|  | sort cruft >actual && | 
|  | sort <<-EOF >expect && | 
|  | unreachable blob $B0 | 
|  | unreachable blob $B1 | 
|  | unreachable blob $B2 | 
|  | unreachable blob $B3 | 
|  | EOF | 
|  | test_cmp expect actual && | 
|  |  | 
|  | # And they should go away when gc runs. | 
|  | git gc --prune=now && | 
|  | git fsck --unreachable >cruft && | 
|  | test_must_be_empty cruft && | 
|  |  | 
|  | test_must_fail git cat-file -e $B0 && | 
|  | test_must_fail git cat-file -e $B1 && | 
|  | test_must_fail git cat-file -e $B2 && | 
|  | test_must_fail git cat-file -e $B3 | 
|  | ' | 
|  |  | 
|  | test_done |