(command.CommandList children: [ (command.ShAssignment pairs: [ (assign_pair lhs: (sh_lhs_expr.Name name:test_description) op: assign_op.Equal rhs: {(SQ <prune>)} spids: [13] ) ] ) (C {<.>} {<'./test-lib.sh'>}) (command.ShAssignment pairs: [ (assign_pair lhs: (sh_lhs_expr.Name name:day) op: assign_op.Equal rhs: { (word_part.ArithSub anode: (arith_expr.Binary op_id: Id.Arith_Star left: (arith_expr.Binary op_id: Id.Arith_Star left: {<Id.Lit_Digits 60>} right: {<Id.Lit_Digits 60>} ) right: {<Id.Lit_Digits 24>} ) ) } spids: [23] ) ] ) (command.ShAssignment pairs: [ (assign_pair lhs: (sh_lhs_expr.Name name:week) op: assign_op.Equal rhs: { (word_part.ArithSub anode: (arith_expr.Binary op_id: Id.Arith_Star left: {($ Id.VSub_DollarName '$day')} right: {<Id.Lit_Digits 7>} ) ) } spids: [33] ) ] ) (command.ShFunction name: add_blob body: (BraceGroup children: [ (command.AndOr ops: [Id.Op_DAmp Id.Op_DAmp Id.Op_DAmp Id.Op_DAmp Id.Op_DAmp] children: [ (command.ShAssignment pairs: [ (assign_pair lhs: (sh_lhs_expr.Name name:before) op: assign_op.Equal rhs: { (command_sub left_token: <Id.Left_DollarParen '$('> child: (command.Pipeline children: [(C {<git>} {<count-objects>}) (C {<sed>} {(DQ <'s/ .*//'>)})] negated: F ) ) } spids: [49] ) ] ) (command.ShAssignment pairs: [ (assign_pair lhs: (sh_lhs_expr.Name name:BLOB) op: assign_op.Equal rhs: { (command_sub left_token: <Id.Left_DollarParen '$('> child: (command.Pipeline children: [ (C {<echo>} {<aleph_0>}) (C {<git>} {<hash-object>} {<-w>} {<--stdin>}) ] negated: F ) ) } spids: [67] ) ] ) (command.ShAssignment pairs: [ (assign_pair lhs: (sh_lhs_expr.Name name:BLOB_FILE) op: assign_op.Equal rhs: {<'.git/objects/'> (command_sub left_token: <Id.Left_DollarParen '$('> child: (command.Pipeline children: [ (C {<echo>} {($ Id.VSub_DollarName '$BLOB')}) (C {<sed>} {(DQ <'s/^../&'> <Id.Lit_Other '\\'> <'//'>)}) ] negated: F ) ) } spids: [87] ) ] ) (C {<verbose>} {<test>} { (word_part.ArithSub anode: (arith_expr.Binary op_id: Id.Arith_Plus left: {<Id.Lit_Digits 1>} right: {($ Id.VSub_DollarName '$before')} ) ) } {<Id.Lit_Equals '='>} { (command_sub left_token: <Id.Left_DollarParen '$('> child: (command.Pipeline children: [(C {<git>} {<count-objects>}) (C {<sed>} {(DQ <'s/ .*//'>)})] negated: F ) ) } ) (C {<test_path_is_file>} {($ Id.VSub_DollarName '$BLOB_FILE')}) (C {<test-chmtime>} {<Id.Lit_Equals '='> <Id.Lit_Other '+'> <0>} {($ Id.VSub_DollarName '$BLOB_FILE')} ) ] ) ] ) ) (C {<test_expect_success>} {<setup>} { (SQ <'\n'> <'\n'> <'\t: > file &&\n'> <'\tgit add file &&\n'> <'\ttest_tick &&\n'> <'\tgit commit -m initial &&\n'> <'\tgit gc\n'> <'\n'> ) } ) (C {<test_expect_success>} {(SQ <'prune stale packs'>)} { (SQ <'\n'> <'\n'> <'\torig_pack=$(echo .git/objects/pack/*.pack) &&\n'> <'\t: > .git/objects/tmp_1.pack &&\n'> <'\t: > .git/objects/tmp_2.pack &&\n'> <'\ttest-chmtime =-86501 .git/objects/tmp_1.pack &&\n'> <'\tgit prune --expire 1.day &&\n'> <'\ttest_path_is_file $orig_pack &&\n'> <'\ttest_path_is_file .git/objects/tmp_2.pack &&\n'> <'\ttest_path_is_missing .git/objects/tmp_1.pack\n'> <'\n'> ) } ) (C {<test_expect_success>} {(SQ <'prune --expire'>)} { (SQ <'\n'> <'\n'> <'\tadd_blob &&\n'> <'\tgit prune --expire=1.hour.ago &&\n'> <'\tverbose test $((1 + $before)) = $(git count-objects | sed "s/ .*//") &&\n'> <'\ttest_path_is_file $BLOB_FILE &&\n'> <'\ttest-chmtime =-86500 $BLOB_FILE &&\n'> <'\tgit prune --expire 1.day &&\n'> <'\tverbose test $before = $(git count-objects | sed "s/ .*//") &&\n'> <'\ttest_path_is_missing $BLOB_FILE\n'> <'\n'> ) } ) (C {<test_expect_success>} {(SQ <'gc: implicit prune --expire'>)} { (SQ <'\n'> <'\n'> <'\tadd_blob &&\n'> <'\ttest-chmtime =-$((2*$week-30)) $BLOB_FILE &&\n'> <'\tgit gc &&\n'> <'\tverbose test $((1 + $before)) = $(git count-objects | sed "s/ .*//") &&\n'> <'\ttest_path_is_file $BLOB_FILE &&\n'> <'\ttest-chmtime =-$((2*$week+1)) $BLOB_FILE &&\n'> <'\tgit gc &&\n'> <'\tverbose test $before = $(git count-objects | sed "s/ .*//") &&\n'> <'\ttest_path_is_missing $BLOB_FILE\n'> <'\n'> ) } ) (C {<test_expect_success>} {(SQ <'gc: refuse to start with invalid gc.pruneExpire'>)} { (SQ <'\n'> <'\n'> <'\tgit config gc.pruneExpire invalid &&\n'> <'\ttest_must_fail git gc\n'> <'\n'> ) } ) (C {<test_expect_success>} {(SQ <'gc: start with ok gc.pruneExpire'>)} {(SQ <'\n'> <'\n'> <'\tgit config gc.pruneExpire 2.days.ago &&\n'> <'\tgit gc\n'> <'\n'>)} ) (C {<test_expect_success>} {(SQ <'prune: prune nonsense parameters'>)} { (SQ <'\n'> <'\n'> <'\ttest_must_fail git prune garbage &&\n'> <'\ttest_must_fail git prune --- &&\n'> <'\ttest_must_fail git prune --no-such-option\n'> <'\n'> ) } ) (C {<test_expect_success>} {(SQ <'prune: prune unreachable heads'>)} { (SQ <'\n'> <'\n'> <'\tgit config core.logAllRefUpdates false &&\n'> <'\tmv .git/logs .git/logs.old &&\n'> <'\t: > file2 &&\n'> <'\tgit add file2 &&\n'> <'\tgit commit -m temporary &&\n'> <'\ttmp_head=$(git rev-list -1 HEAD) &&\n'> <'\tgit reset HEAD^ &&\n'> <'\tgit prune &&\n'> <'\ttest_must_fail git reset $tmp_head --\n'> <'\n'> ) } ) (C {<test_expect_success>} {(SQ <'prune: do not prune detached HEAD with no reflog'>)} { (SQ <'\n'> <'\n'> <'\tgit checkout --detach --quiet &&\n'> <'\tgit commit --allow-empty -m "detached commit" &&\n'> <'\t# verify that there is no reflogs\n'> <'\t# (should be removed and disabled by previous test)\n'> <'\ttest_path_is_missing .git/logs &&\n'> <'\tgit prune -n >prune_actual &&\n'> <'\t: >prune_expected &&\n'> <'\ttest_cmp prune_actual prune_expected\n'> <'\n'> ) } ) (C {<test_expect_success>} {(SQ <'prune: prune former HEAD after checking out branch'>)} { (SQ <'\n'> <'\n'> <'\thead_sha1=$(git rev-parse HEAD) &&\n'> <'\tgit checkout --quiet master &&\n'> <'\tgit prune -v >prune_actual &&\n'> <'\tgrep "$head_sha1" prune_actual\n'> <'\n'> ) } ) (C {<test_expect_success>} {(SQ <'prune: do not prune heads listed as an argument'>)} { (SQ <'\n'> <'\n'> <'\t: > file2 &&\n'> <'\tgit add file2 &&\n'> <'\tgit commit -m temporary &&\n'> <'\ttmp_head=$(git rev-list -1 HEAD) &&\n'> <'\tgit reset HEAD^ &&\n'> <'\tgit prune -- $tmp_head &&\n'> <'\tgit reset $tmp_head --\n'> <'\n'> ) } ) (C {<test_expect_success>} {(SQ <'gc --no-prune'>)} { (SQ <'\n'> <'\n'> <'\tadd_blob &&\n'> <'\ttest-chmtime =-$((5001*$day)) $BLOB_FILE &&\n'> <'\tgit config gc.pruneExpire 2.days.ago &&\n'> <'\tgit gc --no-prune &&\n'> <'\tverbose test 1 = $(git count-objects | sed "s/ .*//") &&\n'> <'\ttest_path_is_file $BLOB_FILE\n'> <'\n'> ) } ) (C {<test_expect_success>} {(SQ <'gc respects gc.pruneExpire'>)} { (SQ <'\n'> <'\n'> <'\tgit config gc.pruneExpire 5002.days.ago &&\n'> <'\tgit gc &&\n'> <'\ttest_path_is_file $BLOB_FILE &&\n'> <'\tgit config gc.pruneExpire 5000.days.ago &&\n'> <'\tgit gc &&\n'> <'\ttest_path_is_missing $BLOB_FILE\n'> <'\n'> ) } ) (C {<test_expect_success>} {(SQ <'gc --prune=<date>'>)} { (SQ <'\n'> <'\n'> <'\tadd_blob &&\n'> <'\ttest-chmtime =-$((5001*$day)) $BLOB_FILE &&\n'> <'\tgit gc --prune=5002.days.ago &&\n'> <'\ttest_path_is_file $BLOB_FILE &&\n'> <'\tgit gc --prune=5000.days.ago &&\n'> <'\ttest_path_is_missing $BLOB_FILE\n'> <'\n'> ) } ) (C {<test_expect_success>} {(SQ <'gc --prune=never'>)} { (SQ <'\n'> <'\n'> <'\tadd_blob &&\n'> <'\tgit gc --prune=never &&\n'> <'\ttest_path_is_file $BLOB_FILE &&\n'> <'\tgit gc --prune=now &&\n'> <'\ttest_path_is_missing $BLOB_FILE\n'> <'\n'> ) } ) (C {<test_expect_success>} {(SQ <'gc respects gc.pruneExpire=never'>)} { (SQ <'\n'> <'\n'> <'\tgit config gc.pruneExpire never &&\n'> <'\tadd_blob &&\n'> <'\tgit gc &&\n'> <'\ttest_path_is_file $BLOB_FILE &&\n'> <'\tgit config gc.pruneExpire now &&\n'> <'\tgit gc &&\n'> <'\ttest_path_is_missing $BLOB_FILE\n'> <'\n'> ) } ) (C {<test_expect_success>} {(SQ <'prune --expire=never'>)} { (SQ <'\n'> <'\n'> <'\tadd_blob &&\n'> <'\tgit prune --expire=never &&\n'> <'\ttest_path_is_file $BLOB_FILE &&\n'> <'\tgit prune &&\n'> <'\ttest_path_is_missing $BLOB_FILE\n'> <'\n'> ) } ) (C {<test_expect_success>} {(SQ <'gc: prune old objects after local clone'>)} { (SQ <'\n'> <'\tadd_blob &&\n'> <'\ttest-chmtime =-$((2*$week+1)) $BLOB_FILE &&\n'> <'\tgit clone --no-hardlinks . aclone &&\n'> <'\t(\n'> <'\t\tcd aclone &&\n'> <'\t\tverbose test 1 = $(git count-objects | sed "s/ .*//") &&\n'> <'\t\ttest_path_is_file $BLOB_FILE &&\n'> <'\t\tgit gc --prune &&\n'> <'\t\tverbose test 0 = $(git count-objects | sed "s/ .*//") &&\n'> <'\t\ttest_path_is_missing $BLOB_FILE\n'> <'\t)\n'> ) } ) (C {<test_expect_success>} {(SQ <'garbage report in count-objects -v'>)} { (SQ <'\n'> <'\ttest_when_finished "rm -f .git/objects/pack/fake*" &&\n'> <'\ttest_when_finished "rm -f .git/objects/pack/foo*" &&\n'> <'\t: >.git/objects/pack/foo &&\n'> <'\t: >.git/objects/pack/foo.bar &&\n'> <'\t: >.git/objects/pack/foo.keep &&\n'> <'\t: >.git/objects/pack/foo.pack &&\n'> <'\t: >.git/objects/pack/fake.bar &&\n'> <'\t: >.git/objects/pack/fake.keep &&\n'> <'\t: >.git/objects/pack/fake.pack &&\n'> <'\t: >.git/objects/pack/fake.idx &&\n'> <'\t: >.git/objects/pack/fake2.keep &&\n'> <'\t: >.git/objects/pack/fake3.idx &&\n'> <'\tgit count-objects -v 2>stderr &&\n'> <'\tgrep "index file .git/objects/pack/fake.idx is too small" stderr &&\n'> <'\tgrep "^warning:" stderr | sort >actual &&\n'> <'\tcat >expected <<\\EOF &&\n'> <'warning: garbage found: .git/objects/pack/fake.bar\n'> <'warning: garbage found: .git/objects/pack/foo\n'> <'warning: garbage found: .git/objects/pack/foo.bar\n'> <'warning: no corresponding .idx or .pack: .git/objects/pack/fake2.keep\n'> <'warning: no corresponding .idx: .git/objects/pack/foo.keep\n'> <'warning: no corresponding .idx: .git/objects/pack/foo.pack\n'> <'warning: no corresponding .pack: .git/objects/pack/fake3.idx\n'> <'EOF\n'> <'\ttest_cmp expected actual\n'> ) } ) (C {<test_expect_success>} {(SQ <'clean pack garbage with gc'>)} { (SQ <'\n'> <'\ttest_when_finished "rm -f .git/objects/pack/fake*" &&\n'> <'\ttest_when_finished "rm -f .git/objects/pack/foo*" &&\n'> <'\t: >.git/objects/pack/foo.keep &&\n'> <'\t: >.git/objects/pack/foo.pack &&\n'> <'\t: >.git/objects/pack/fake.idx &&\n'> <'\t: >.git/objects/pack/fake2.keep &&\n'> <'\t: >.git/objects/pack/fake2.idx &&\n'> <'\t: >.git/objects/pack/fake3.keep &&\n'> <'\tgit gc &&\n'> <'\tgit count-objects -v 2>stderr &&\n'> <'\tgrep "^warning:" stderr | sort >actual &&\n'> <'\tcat >expected <<\\EOF &&\n'> <'warning: no corresponding .idx or .pack: .git/objects/pack/fake3.keep\n'> <'warning: no corresponding .idx: .git/objects/pack/foo.keep\n'> <'warning: no corresponding .idx: .git/objects/pack/foo.pack\n'> <'EOF\n'> <'\ttest_cmp expected actual\n'> ) } ) (C {<test_expect_success>} {(SQ <'prune .git/shallow'>)} { (SQ <'\n'> <'\tSHA1=$(echo hi|git commit-tree HEAD^{tree}) &&\n'> <'\techo $SHA1 >.git/shallow &&\n'> <'\tgit prune --dry-run >out &&\n'> <'\tgrep $SHA1 .git/shallow &&\n'> <'\tgrep $SHA1 out &&\n'> <'\tgit prune &&\n'> <'\ttest_path_is_missing .git/shallow\n'> ) } ) (C {<test_expect_success>} {(SQ <'prune: handle alternate object database'>)} { (SQ <'\n'> <'\ttest_create_repo A &&\n'> <'\tgit -C A commit --allow-empty -m "initial commit" &&\n'> <'\tgit clone --shared A B &&\n'> <'\tgit -C B commit --allow-empty -m "next commit" &&\n'> <'\tgit -C B prune\n'> ) } ) (C {<test_done>}) ] )