#!/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). global test_description := ''check pruning of dependent objects'' source ./test-lib.sh # We care about reachability, so we do not want to use # the normal test_commit, which creates extra tags. proc add { echo $1 >$1 && git add $1 } proc commit { test_tick && add $1 && git commit -m $1 } proc maybe_repack { if test -n $repack { git repack -ad } } for repack in ['' true] { global title := $(repack:+repack) global 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 && git reflog expire --expire=all --all ' 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 ' } test_expect_success 'do not complain about existing broken links' ' cat >broken-commit <<-\EOF && tree 0000000000000000000000000000000000000001 parent 0000000000000000000000000000000000000002 author whatever 1234 -0000 committer whatever 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 (CommandList children: [ (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:test_description) op: Equal rhs: {(SQ <"check pruning of dependent objects">)} spids: [76] ) ] spids: [76] ) (C {(.)} {(./test-lib.sh)}) (FuncDef name: add body: (BraceGroup children: [ (AndOr children: [ (SimpleCommand words: [{(echo)} {(DQ ($ VSub_Number "$1"))}] redirects: [ (Redir op_id: Redir_Great fd: -1 arg_word: {(DQ ($ VSub_Number "$1"))} spids: [106] ) ] ) (C {(git)} {(add)} {(DQ ($ VSub_Number "$1"))}) ] op_id: Op_DAmp ) ] spids: [97] ) spids: [92 96] ) (FuncDef name: commit body: (BraceGroup children: [ (AndOr children: [ (C {(test_tick)}) (AndOr children: [ (C {(add)} {(DQ ($ VSub_Number "$1"))}) (C {(git)} {(commit)} {(-m)} {(DQ ($ VSub_Number "$1"))}) ] op_id: Op_DAmp ) ] op_id: Op_DAmp ) ] spids: [129] ) spids: [124 128] ) (FuncDef name: maybe_repack body: (BraceGroup children: [ (If arms: [ (if_arm cond: [ (Sentence child: (C {(test)} {(-n)} {(DQ ($ VSub_Name "$repack"))}) terminator: ) ] action: [(C {(git)} {(repack)} {(-ad)})] spids: [-1 178] ) ] spids: [-1 188] ) ] spids: [164] ) spids: [159 163] ) (ForEach iter_name: repack iter_words: [{(SQ )} {(true)}] do_arg_iter: False body: (DoGroup children: [ (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:title) op: Equal rhs: { (BracedVarSub token: suffix_op: (StringUnary op_id:VTest_ColonPlus arg_word:{(repack)}) spids: [209 213] ) } spids: [208] ) ] spids: [208] ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:title) op: Equal rhs: { (BracedVarSub token: suffix_op: (StringUnary op_id:VTest_ColonHyphen arg_word:{(loose)}) spids: [217 221] ) } spids: [216] ) ] spids: [216] ) (C {(test_expect_success)} {(DQ ("make repo completely empty (") ($ VSub_Name "$title") (")"))} {(SQ <"\n"> <"\t\trm -rf .git &&\n"> <"\t\tgit init\n"> <"\t">)} ) (C {(test_expect_success)} {(DQ ("disable reflogs (") ($ VSub_Name "$title") (")"))} { (SQ <"\n"> <"\t\tgit config core.logallrefupdates false &&\n"> <"\t\tgit reflog expire --expire=all --all\n"> <"\t"> ) } ) (C {(test_expect_success)} {(DQ ("setup basic history (") ($ VSub_Name "$title") (")"))} {(SQ <"\n"> <"\t\tcommit base\n"> <"\t">)} ) (C {(test_expect_success)} {(DQ ("create and abandon some objects (") ($ VSub_Name "$title") (")"))} { (SQ <"\n"> <"\t\tgit checkout -b experiment &&\n"> <"\t\tcommit abandon &&\n"> <"\t\tmaybe_repack &&\n"> <"\t\tgit checkout master &&\n"> <"\t\tgit branch -D experiment\n"> <"\t"> ) } ) (C {(test_expect_success)} {(DQ ("simulate time passing (") ($ VSub_Name "$title") (")"))} { (SQ <"\n"> <"\t\tfind .git/objects -type f |\n"> <"\t\txargs test-chmtime -v -86400\n"> <"\t"> ) } ) (C {(test_expect_success)} {(DQ ("start writing new commit with old blob (") ($ VSub_Name "$title") (")"))} { (SQ <"\n"> <"\t\ttree=$(\n"> <"\t\t\tGIT_INDEX_FILE=index.tmp &&\n"> <"\t\t\texport GIT_INDEX_FILE &&\n"> <"\t\t\tgit read-tree HEAD &&\n"> <"\t\t\tadd unrelated &&\n"> <"\t\t\tadd abandon &&\n"> <"\t\t\tgit write-tree\n"> <"\t\t)\n"> <"\t"> ) } ) (C {(test_expect_success)} {(DQ ("simultaneous gc (") ($ VSub_Name "$title") (")"))} {(SQ <"\n"> <"\t\tgit gc --prune=12.hours.ago\n"> <"\t">)} ) (C {(test_expect_success)} {(DQ ("finish writing out commit (") ($ VSub_Name "$title") (")"))} { (SQ <"\n"> <"\t\tcommit=$(echo foo | git commit-tree -p HEAD $tree) &&\n"> <"\t\tgit update-ref HEAD $commit\n"> <"\t"> ) } ) (C {(test_expect_success)} {(DQ ("repository passes fsck (") ($ VSub_Name "$title") (")"))} {(SQ <"\n"> <"\t\tgit fsck\n"> <"\t">)} ) (C {(test_expect_success)} {(DQ ("abandon objects again (") ($ VSub_Name "$title") (")"))} { (SQ <"\n"> <"\t\tgit reset --hard HEAD^ &&\n"> <"\t\tfind .git/objects -type f |\n"> <"\t\txargs test-chmtime -v -86400\n"> <"\t"> ) } ) (C {(test_expect_success)} {(DQ ("start writing new commit with same tree (") ($ VSub_Name "$title") (")"))} { (SQ <"\n"> <"\t\ttree=$(\n"> <"\t\t\tGIT_INDEX_FILE=index.tmp &&\n"> <"\t\t\texport GIT_INDEX_FILE &&\n"> <"\t\t\tgit read-tree HEAD &&\n"> <"\t\t\tadd abandon &&\n"> <"\t\t\tadd unrelated &&\n"> <"\t\t\tgit write-tree\n"> <"\t\t)\n"> <"\t"> ) } ) (C {(test_expect_success)} {(DQ ("simultaneous gc (") ($ VSub_Name "$title") (")"))} {(SQ <"\n"> <"\t\tgit gc --prune=12.hours.ago\n"> <"\t">)} ) (C {(test_expect_success)} {(DQ ("finish writing out commit (") ($ VSub_Name "$title") (")"))} { (SQ <"\n"> <"\t\tcommit=$(echo foo | git commit-tree -p HEAD $tree) &&\n"> <"\t\tgit update-ref HEAD $commit\n"> <"\t"> ) } ) ] spids: [205 464] ) spids: [198 203] ) (C {(test_expect_success)} {(SQ <"do not complain about existing broken links">)} { (SQ <"\n"> <"\tcat >broken-commit <<-\\EOF &&\n"> <"\ttree 0000000000000000000000000000000000000001\n"> <"\tparent 0000000000000000000000000000000000000002\n"> <"\tauthor whatever 1234 -0000\n"> <"\tcommitter whatever 1234 -0000\n"> <"\n"> <"\tsome message\n"> <"\tEOF\n"> <"\tcommit=$(git hash-object -t commit -w broken-commit) &&\n"> <"\tgit gc 2>stderr &&\n"> <"\tverbose git cat-file -e $commit &&\n"> <"\ttest_must_be_empty stderr\n"> ) } ) (C {(test_done)}) ] )