#!/bin/sh global test_description := '' Test pruning of repositories with minor corruptions. The goal here is that we should always be erring on the side of safety. So if we see, for example, a ref with a bogus name, it is OK either to bail out or to proceed using it as a reachable tip, but it is _not_ OK to proceed as if it did not exist. Otherwise we might silently delete objects that cannot be recovered. '' source ./test-lib.sh test_expect_success 'disable reflogs' ' git config core.logallrefupdates false && git reflog expire --expire=all --all ' test_expect_success 'create history reachable only from a bogus-named ref' ' test_tick && git commit --allow-empty -m master && base=$(git rev-parse HEAD) && test_tick && git commit --allow-empty -m bogus && bogus=$(git rev-parse HEAD) && git cat-file commit $bogus >saved && echo $bogus >.git/refs/heads/bogus..name && git reset --hard HEAD^ ' test_expect_success 'pruning does not drop bogus object' ' test_when_finished "git hash-object -w -t commit saved" && test_might_fail git prune --expire=now && verbose git cat-file -e $bogus ' test_expect_success 'put bogus object into pack' ' git tag reachable $bogus && git repack -ad && git tag -d reachable && verbose git cat-file -e $bogus ' test_expect_success 'destructive repack keeps packed object' ' test_might_fail git repack -Ad --unpack-unreachable=now && verbose git cat-file -e $bogus && test_might_fail git repack -ad && verbose git cat-file -e $bogus ' # subsequent tests will have different corruptions test_expect_success 'clean up bogus ref' ' rm .git/refs/heads/bogus..name ' # We create two new objects here, "one" and "two". Our # master branch points to "two", which is deleted, # corrupting the repository. But we'd like to make sure # that the otherwise unreachable "one" is not pruned # (since it is the user's best bet for recovering # from the corruption). # # Note that we also point HEAD somewhere besides "two", # as we want to make sure we test the case where we # pick up the reference to "two" by iterating the refs, # not by resolving HEAD. test_expect_success 'create history with missing tip commit' ' test_tick && git commit --allow-empty -m one && recoverable=$(git rev-parse HEAD) && git cat-file commit $recoverable >saved && test_tick && git commit --allow-empty -m two && missing=$(git rev-parse HEAD) && git checkout --detach $base && rm .git/objects/$(echo $missing | sed "s,..,&/,") && test_must_fail git cat-file -e $missing ' test_expect_success 'pruning with a corrupted tip does not drop history' ' test_when_finished "git hash-object -w -t commit saved" && test_might_fail git prune --expire=now && verbose git cat-file -e $recoverable ' test_expect_success 'pack-refs does not silently delete broken loose ref' ' git pack-refs --all --prune && echo $missing >expect && git rev-parse refs/heads/master >actual && test_cmp expect actual ' # we do not want to count on running pack-refs to # actually pack it, as it is perfectly reasonable to # skip processing a broken ref test_expect_success 'create packed-refs file with broken ref' ' rm -f .git/refs/heads/master && cat >.git/packed-refs <<-EOF && $missing refs/heads/master $recoverable refs/heads/other EOF echo $missing >expect && git rev-parse refs/heads/master >actual && test_cmp expect actual ' test_expect_success 'pack-refs does not silently delete broken packed ref' ' git pack-refs --all --prune && git rev-parse refs/heads/master >actual && test_cmp expect actual ' test_expect_success 'pack-refs does not drop broken refs during deletion' ' git update-ref -d refs/heads/other && git rev-parse refs/heads/master >actual && test_cmp expect actual ' test_done (CommandList children: [ (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:test_description) op: Equal rhs: { (SQ <"\n"> <"Test pruning of repositories with minor corruptions. The goal\n"> <"here is that we should always be erring on the side of safety. So\n"> <"if we see, for example, a ref with a bogus name, it is OK either to\n"> <"bail out or to proceed using it as a reachable tip, but it is _not_\n"> <"OK to proceed as if it did not exist. Otherwise we might silently\n"> <"delete objects that cannot be recovered.\n"> ) } spids: [4] ) ] spids: [4] ) (C {(.)} {(./test-lib.sh)}) (C {(test_expect_success)} {(SQ <"disable reflogs">)} { (SQ <"\n"> <"\tgit config core.logallrefupdates false &&\n"> <"\tgit reflog expire --expire=all --all\n"> ) } ) (C {(test_expect_success)} {(SQ <"create history reachable only from a bogus-named ref">)} { (SQ <"\n"> <"\ttest_tick && git commit --allow-empty -m master &&\n"> <"\tbase=$(git rev-parse HEAD) &&\n"> <"\ttest_tick && git commit --allow-empty -m bogus &&\n"> <"\tbogus=$(git rev-parse HEAD) &&\n"> <"\tgit cat-file commit $bogus >saved &&\n"> <"\techo $bogus >.git/refs/heads/bogus..name &&\n"> <"\tgit reset --hard HEAD^\n"> ) } ) (C {(test_expect_success)} {(SQ <"pruning does not drop bogus object">)} { (SQ <"\n"> <"\ttest_when_finished \"git hash-object -w -t commit saved\" &&\n"> <"\ttest_might_fail git prune --expire=now &&\n"> <"\tverbose git cat-file -e $bogus\n"> ) } ) (C {(test_expect_success)} {(SQ <"put bogus object into pack">)} { (SQ <"\n"> <"\tgit tag reachable $bogus &&\n"> <"\tgit repack -ad &&\n"> <"\tgit tag -d reachable &&\n"> <"\tverbose git cat-file -e $bogus\n"> ) } ) (C {(test_expect_success)} {(SQ <"destructive repack keeps packed object">)} { (SQ <"\n"> <"\ttest_might_fail git repack -Ad --unpack-unreachable=now &&\n"> <"\tverbose git cat-file -e $bogus &&\n"> <"\ttest_might_fail git repack -ad &&\n"> <"\tverbose git cat-file -e $bogus\n"> ) } ) (C {(test_expect_success)} {(SQ <"clean up bogus ref">)} {(SQ <"\n"> <"\trm .git/refs/heads/bogus..name\n">)} ) (C {(test_expect_success)} {(SQ <"create history with missing tip commit">)} { (SQ <"\n"> <"\ttest_tick && git commit --allow-empty -m one &&\n"> <"\trecoverable=$(git rev-parse HEAD) &&\n"> <"\tgit cat-file commit $recoverable >saved &&\n"> <"\ttest_tick && git commit --allow-empty -m two &&\n"> <"\tmissing=$(git rev-parse HEAD) &&\n"> <"\tgit checkout --detach $base &&\n"> <"\trm .git/objects/$(echo $missing | sed \"s,..,&/,\") &&\n"> <"\ttest_must_fail git cat-file -e $missing\n"> ) } ) (C {(test_expect_success)} {(SQ <"pruning with a corrupted tip does not drop history">)} { (SQ <"\n"> <"\ttest_when_finished \"git hash-object -w -t commit saved\" &&\n"> <"\ttest_might_fail git prune --expire=now &&\n"> <"\tverbose git cat-file -e $recoverable\n"> ) } ) (C {(test_expect_success)} {(SQ <"pack-refs does not silently delete broken loose ref">)} { (SQ <"\n"> <"\tgit pack-refs --all --prune &&\n"> <"\techo $missing >expect &&\n"> <"\tgit rev-parse refs/heads/master >actual &&\n"> <"\ttest_cmp expect actual\n"> ) } ) (C {(test_expect_success)} {(SQ <"create packed-refs file with broken ref">)} { (SQ <"\n"> <"\trm -f .git/refs/heads/master &&\n"> <"\tcat >.git/packed-refs <<-EOF &&\n"> <"\t$missing refs/heads/master\n"> <"\t$recoverable refs/heads/other\n"> <"\tEOF\n"> <"\techo $missing >expect &&\n"> <"\tgit rev-parse refs/heads/master >actual &&\n"> <"\ttest_cmp expect actual\n"> ) } ) (C {(test_expect_success)} {(SQ <"pack-refs does not silently delete broken packed ref">)} { (SQ <"\n"> <"\tgit pack-refs --all --prune &&\n"> <"\tgit rev-parse refs/heads/master >actual &&\n"> <"\ttest_cmp expect actual\n"> ) } ) (C {(test_expect_success)} {(SQ <"pack-refs does not drop broken refs during deletion">)} { (SQ <"\n"> <"\tgit update-ref -d refs/heads/other &&\n"> <"\tgit rev-parse refs/heads/master >actual &&\n"> <"\ttest_cmp expect actual\n"> ) } ) (C {(test_done)}) ] )