|  | #!/bin/sh | 
|  | # | 
|  | # This test covers the handling of objects which might have old | 
|  | # mtimes in the filesystem (because they were used previously) | 
|  | # and are just now becoming referenced again. | 
|  | # | 
|  | # We're going to do two things that are a little bit "fake" to | 
|  | # help make our simulation easier: | 
|  | # | 
|  | #   1. We'll turn off reflogs. You can still run into | 
|  | #      problems with reflogs on, but your objects | 
|  | #      don't get pruned until both the reflog expiration | 
|  | #      has passed on their references, _and_ they are out | 
|  | #      of prune's expiration period. Dropping reflogs | 
|  | #      means we only have to deal with one variable in our tests, | 
|  | #      but the results generalize. | 
|  | # | 
|  | #   2. We'll use a temporary index file to create our | 
|  | #      works-in-progress. Most workflows would mention | 
|  | #      referenced objects in the index, which prune takes | 
|  | #      into account. However, many operations don't. For | 
|  | #      example, a partial commit with "git commit foo" | 
|  | #      will use a temporary index. Or they may not need | 
|  | #      an index at all (e.g., creating a new commit | 
|  | #      to refer to an existing tree). | 
|  |  | 
|  | test_description='check pruning of dependent objects' | 
|  | . ./test-lib.sh | 
|  |  | 
|  | # We care about reachability, so we do not want to use | 
|  | # the normal test_commit, which creates extra tags. | 
|  | add () { | 
|  | echo "$1" >"$1" && | 
|  | git add "$1" | 
|  | } | 
|  | commit () { | 
|  | test_tick && | 
|  | add "$1" && | 
|  | git commit -m "$1" | 
|  | } | 
|  |  | 
|  | maybe_repack () { | 
|  | if test -n "$repack"; then | 
|  | git repack -ad | 
|  | fi | 
|  | } | 
|  |  | 
|  | for repack in '' true; do | 
|  | title=${repack:+repack} | 
|  | title=${title:-loose} | 
|  |  | 
|  | test_expect_success "make repo completely empty ($title)" ' | 
|  | rm -rf .git && | 
|  | git init | 
|  | ' | 
|  |  | 
|  | test_expect_success "disable reflogs ($title)" ' | 
|  | git config core.logallrefupdates false && | 
|  | rm -rf .git/logs | 
|  | ' | 
|  |  | 
|  | test_expect_success "setup basic history ($title)" ' | 
|  | commit base | 
|  | ' | 
|  |  | 
|  | test_expect_success "create and abandon some objects ($title)" ' | 
|  | git checkout -b experiment && | 
|  | commit abandon && | 
|  | maybe_repack && | 
|  | git checkout master && | 
|  | git branch -D experiment | 
|  | ' | 
|  |  | 
|  | test_expect_success "simulate time passing ($title)" ' | 
|  | find .git/objects -type f | | 
|  | xargs test-chmtime -v -86400 | 
|  | ' | 
|  |  | 
|  | test_expect_success "start writing new commit with old blob ($title)" ' | 
|  | tree=$( | 
|  | GIT_INDEX_FILE=index.tmp && | 
|  | export GIT_INDEX_FILE && | 
|  | git read-tree HEAD && | 
|  | add unrelated && | 
|  | add abandon && | 
|  | git write-tree | 
|  | ) | 
|  | ' | 
|  |  | 
|  | test_expect_success "simultaneous gc ($title)" ' | 
|  | git gc --prune=12.hours.ago | 
|  | ' | 
|  |  | 
|  | test_expect_success "finish writing out commit ($title)" ' | 
|  | commit=$(echo foo | git commit-tree -p HEAD $tree) && | 
|  | git update-ref HEAD $commit | 
|  | ' | 
|  |  | 
|  | # "abandon" blob should have been rescued by reference from new tree | 
|  | test_expect_success "repository passes fsck ($title)" ' | 
|  | git fsck | 
|  | ' | 
|  |  | 
|  | test_expect_success "abandon objects again ($title)" ' | 
|  | git reset --hard HEAD^ && | 
|  | find .git/objects -type f | | 
|  | xargs test-chmtime -v -86400 | 
|  | ' | 
|  |  | 
|  | test_expect_success "start writing new commit with same tree ($title)" ' | 
|  | tree=$( | 
|  | GIT_INDEX_FILE=index.tmp && | 
|  | export GIT_INDEX_FILE && | 
|  | git read-tree HEAD && | 
|  | add abandon && | 
|  | add unrelated && | 
|  | git write-tree | 
|  | ) | 
|  | ' | 
|  |  | 
|  | test_expect_success "simultaneous gc ($title)" ' | 
|  | git gc --prune=12.hours.ago | 
|  | ' | 
|  |  | 
|  | # tree should have been refreshed by write-tree | 
|  | test_expect_success "finish writing out commit ($title)" ' | 
|  | commit=$(echo foo | git commit-tree -p HEAD $tree) && | 
|  | git update-ref HEAD $commit | 
|  | ' | 
|  | done | 
|  |  | 
|  | test_expect_success 'do not complain about existing broken links' ' | 
|  | cat >broken-commit <<-\EOF && | 
|  | tree 0000000000000000000000000000000000000001 | 
|  | parent 0000000000000000000000000000000000000002 | 
|  | author whatever <whatever@example.com> 1234 -0000 | 
|  | committer whatever <whatever@example.com> 1234 -0000 | 
|  |  | 
|  | some message | 
|  | EOF | 
|  | commit=$(git hash-object -t commit -w broken-commit) && | 
|  | git gc 2>stderr && | 
|  | verbose git cat-file -e $commit && | 
|  | test_must_be_empty stderr | 
|  | ' | 
|  |  | 
|  | test_done |