| #!/bin/sh |
| # |
| # Copyright (c) 2018 Jiang Xin |
| # |
| |
| test_description='Test git pack-redundant |
| |
| In order to test git-pack-redundant, we will create a number of objects and |
| packs in the repository `main.git`. The relationship between packs (P1-P8) |
| and objects (T, A-R) is showed in the following chart. Objects of a pack will |
| be marked with letter x, while objects of redundant packs will be marked with |
| exclamation point, and redundant pack itself will be marked with asterisk. |
| |
| | T A B C D E F G H I J K L M N O P Q R |
| ----+-------------------------------------- |
| P1 | x x x x x x x x |
| P2* | ! ! ! ! ! ! ! |
| P3 | x x x x x x |
| P4* | ! ! ! ! ! |
| P5 | x x x x |
| P6* | ! ! ! |
| P7 | x x |
| P8* | ! |
| ----+-------------------------------------- |
| ALL | x x x x x x x x x x x x x x x x x x x |
| |
| Another repository `shared.git` has unique objects (X-Z), while other objects |
| (marked with letter s) are shared through alt-odb (of `main.git`). The |
| relationship between packs and objects is as follows: |
| |
| | T A B C D E F G H I J K L M N O P Q R X Y Z |
| ----+---------------------------------------------- |
| Px1 | s s s x x x |
| Px2 | s s s x x x |
| ' |
| |
| . ./test-lib.sh |
| |
| main_repo=main.git |
| shared_repo=shared.git |
| |
| git_pack_redundant='git pack-redundant --i-still-use-this' |
| |
| # Create commits in <repo> and assign each commit's oid to shell variables |
| # given in the arguments (A, B, and C). E.g.: |
| # |
| # create_commits_in <repo> A B C |
| # |
| # NOTE: Avoid calling this function from a subshell since variable |
| # assignments will disappear when subshell exits. |
| create_commits_in () { |
| repo="$1" && |
| if ! parent=$(git -C "$repo" rev-parse HEAD^{} 2>/dev/null) |
| then |
| parent= |
| fi && |
| T=$(git -C "$repo" write-tree) && |
| shift && |
| while test $# -gt 0 |
| do |
| name=$1 && |
| test_tick && |
| if test -z "$parent" |
| then |
| oid=$(echo $name | git -C "$repo" commit-tree $T) |
| else |
| oid=$(echo $name | git -C "$repo" commit-tree -p $parent $T) |
| fi && |
| eval $name=$oid && |
| parent=$oid && |
| shift || |
| return 1 |
| done && |
| git -C "$repo" update-ref refs/heads/main $oid |
| } |
| |
| # Create pack in <repo> and assign pack id to variable given in the 2nd argument |
| # (<name>). Commits in the pack will be read from stdin. E.g.: |
| # |
| # create_pack_in <repo> <name> <<-EOF |
| # ... |
| # EOF |
| # |
| # NOTE: commits from stdin should be given using heredoc, not using pipe, and |
| # avoid calling this function from a subshell since variable assignments will |
| # disappear when subshell exits. |
| create_pack_in () { |
| repo="$1" && |
| name="$2" && |
| pack=$(git -C "$repo/objects/pack" pack-objects -q pack) && |
| eval $name=$pack && |
| eval P$pack=$name:$pack |
| } |
| |
| format_packfiles () { |
| sed \ |
| -e "s#.*/pack-\(.*\)\.idx#\1#" \ |
| -e "s#.*/pack-\(.*\)\.pack#\1#" | |
| sort -u | |
| while read p |
| do |
| if test -z "$(eval echo \${P$p})" |
| then |
| echo $p |
| else |
| eval echo "\${P$p}" |
| fi |
| done | |
| sort |
| } |
| |
| test_expect_success 'setup main repo' ' |
| git init --bare "$main_repo" && |
| create_commits_in "$main_repo" A B C D E F G H I J K L M N O P Q R |
| ' |
| |
| test_expect_success 'main: pack-redundant works with no packfile' ' |
| ( |
| cd "$main_repo" && |
| cat >expect <<-EOF && |
| fatal: Zero packs found! |
| EOF |
| test_must_fail $git_pack_redundant --all >actual 2>&1 && |
| test_cmp expect actual |
| ) |
| ' |
| |
| ############################################################################# |
| # Chart of packs and objects for this test case |
| # |
| # | T A B C D E F G H I J K L M N O P Q R |
| # ----+-------------------------------------- |
| # P1 | x x x x x x x x |
| # ----+-------------------------------------- |
| # ALL | x x x x x x x x |
| # |
| ############################################################################# |
| test_expect_success 'main: pack-redundant works with one packfile' ' |
| create_pack_in "$main_repo" P1 <<-EOF && |
| $T |
| $A |
| $B |
| $C |
| $D |
| $E |
| $F |
| $R |
| EOF |
| ( |
| cd "$main_repo" && |
| $git_pack_redundant --all >out && |
| test_must_be_empty out |
| ) |
| ' |
| |
| ############################################################################# |
| # Chart of packs and objects for this test case |
| # |
| # | T A B C D E F G H I J K L M N O P Q R |
| # ----+-------------------------------------- |
| # P1 | x x x x x x x x |
| # P2 | x x x x x x x |
| # P3 | x x x x x x |
| # ----+-------------------------------------- |
| # ALL | x x x x x x x x x x x x x x x |
| # |
| ############################################################################# |
| test_expect_success 'main: no redundant for pack 1, 2, 3' ' |
| create_pack_in "$main_repo" P2 <<-EOF && |
| $B |
| $C |
| $D |
| $E |
| $G |
| $H |
| $I |
| EOF |
| create_pack_in "$main_repo" P3 <<-EOF && |
| $F |
| $I |
| $J |
| $K |
| $L |
| $M |
| EOF |
| ( |
| cd "$main_repo" && |
| $git_pack_redundant --all >out && |
| test_must_be_empty out |
| ) |
| ' |
| |
| ############################################################################# |
| # Chart of packs and objects for this test case |
| # |
| # | T A B C D E F G H I J K L M N O P Q R |
| # ----+-------------------------------------- |
| # P1 | x x x x x x x x |
| # P2 | x x x x x x x |
| # P3* | ! ! ! ! ! ! |
| # P4 | x x x x x |
| # P5 | x x x x |
| # ----+-------------------------------------- |
| # ALL | x x x x x x x x x x x x x x x x x x |
| # |
| ############################################################################# |
| test_expect_success 'main: one of pack-2/pack-3 is redundant' ' |
| create_pack_in "$main_repo" P4 <<-EOF && |
| $J |
| $K |
| $L |
| $M |
| $P |
| EOF |
| create_pack_in "$main_repo" P5 <<-EOF && |
| $G |
| $H |
| $N |
| $O |
| EOF |
| ( |
| cd "$main_repo" && |
| cat >expect <<-EOF && |
| P3:$P3 |
| EOF |
| $git_pack_redundant --all >out && |
| format_packfiles <out >actual && |
| test_cmp expect actual |
| ) |
| ' |
| |
| ############################################################################# |
| # Chart of packs and objects for this test case |
| # |
| # | T A B C D E F G H I J K L M N O P Q R |
| # ----+-------------------------------------- |
| # P1 | x x x x x x x x |
| # P2* | ! ! ! ! ! ! ! |
| # P3 | x x x x x x |
| # P4* | ! ! ! ! ! |
| # P5 | x x x x |
| # P6* | ! ! ! |
| # P7 | x x |
| # ----+-------------------------------------- |
| # ALL | x x x x x x x x x x x x x x x x x x x |
| # |
| ############################################################################# |
| test_expect_success 'main: pack 2, 4, and 6 are redundant' ' |
| create_pack_in "$main_repo" P6 <<-EOF && |
| $N |
| $O |
| $Q |
| EOF |
| create_pack_in "$main_repo" P7 <<-EOF && |
| $P |
| $Q |
| EOF |
| ( |
| cd "$main_repo" && |
| cat >expect <<-EOF && |
| P2:$P2 |
| P4:$P4 |
| P6:$P6 |
| EOF |
| $git_pack_redundant --all >out && |
| format_packfiles <out >actual && |
| test_cmp expect actual |
| ) |
| ' |
| |
| ############################################################################# |
| # Chart of packs and objects for this test case |
| # |
| # | T A B C D E F G H I J K L M N O P Q R |
| # ----+-------------------------------------- |
| # P1 | x x x x x x x x |
| # P2* | ! ! ! ! ! ! ! |
| # P3 | x x x x x x |
| # P4* | ! ! ! ! ! |
| # P5 | x x x x |
| # P6* | ! ! ! |
| # P7 | x x |
| # P8* | ! |
| # ----+-------------------------------------- |
| # ALL | x x x x x x x x x x x x x x x x x x x |
| # |
| ############################################################################# |
| test_expect_success 'main: pack-8 (subset of pack-1) is also redundant' ' |
| create_pack_in "$main_repo" P8 <<-EOF && |
| $A |
| EOF |
| ( |
| cd "$main_repo" && |
| cat >expect <<-EOF && |
| P2:$P2 |
| P4:$P4 |
| P6:$P6 |
| P8:$P8 |
| EOF |
| $git_pack_redundant --all >out && |
| format_packfiles <out >actual && |
| test_cmp expect actual |
| ) |
| ' |
| |
| test_expect_success 'main: clean loose objects' ' |
| ( |
| cd "$main_repo" && |
| git prune-packed && |
| find objects -type f | sed -e "/objects\/pack\//d" >out && |
| test_must_be_empty out |
| ) |
| ' |
| |
| test_expect_success 'main: remove redundant packs and pass fsck' ' |
| ( |
| cd "$main_repo" && |
| $git_pack_redundant --all | xargs rm && |
| git fsck && |
| $git_pack_redundant --all >out && |
| test_must_be_empty out |
| ) |
| ' |
| |
| # The following test cases will execute inside `shared.git`, instead of |
| # inside `main.git`. |
| test_expect_success 'setup shared.git' ' |
| git clone --mirror "$main_repo" "$shared_repo" && |
| ( |
| cd "$shared_repo" && |
| printf "../../$main_repo/objects\n" >objects/info/alternates |
| ) |
| ' |
| |
| test_expect_success 'shared: all packs are redundant, but no output without --alt-odb' ' |
| ( |
| cd "$shared_repo" && |
| $git_pack_redundant --all >out && |
| test_must_be_empty out |
| ) |
| ' |
| |
| ############################################################################# |
| # Chart of packs and objects for this test case |
| # |
| # ================= main.git ================ |
| # | T A B C D E F G H I J K L M N O P Q R <----------+ |
| # ----+-------------------------------------- | |
| # P1 | x x x x x x x x | |
| # P3 | x x x x x x | |
| # P5 | x x x x | |
| # P7 | x x | |
| # ----+-------------------------------------- | |
| # ALL | x x x x x x x x x x x x x x x x x x x | |
| # | |
| # | |
| # ================ shared.git =============== | |
| # | T A B C D E F G H I J K L M N O P Q R <objects/info/alternates> |
| # ----+-------------------------------------- |
| # P1* | s s s s s s s s |
| # P3* | s s s s s s |
| # P5* | s s s s |
| # P7* | s s |
| # ----+-------------------------------------- |
| # ALL | x x x x x x x x x x x x x x x x x x x |
| # |
| ############################################################################# |
| test_expect_success 'shared: show redundant packs in stderr for verbose mode' ' |
| ( |
| cd "$shared_repo" && |
| cat >expect <<-EOF && |
| P1:$P1 |
| P3:$P3 |
| P5:$P5 |
| P7:$P7 |
| EOF |
| $git_pack_redundant --all --verbose >out 2>out.err && |
| test_must_be_empty out && |
| grep "pack$" out.err | format_packfiles >actual && |
| test_cmp expect actual |
| ) |
| ' |
| |
| test_expect_success 'shared: remove redundant packs, no packs left' ' |
| ( |
| cd "$shared_repo" && |
| cat >expect <<-EOF && |
| fatal: Zero packs found! |
| EOF |
| $git_pack_redundant --all --alt-odb | xargs rm && |
| git fsck && |
| test_must_fail $git_pack_redundant --all --alt-odb >actual 2>&1 && |
| test_cmp expect actual |
| ) |
| ' |
| |
| test_expect_success 'shared: create new objects and packs' ' |
| create_commits_in "$shared_repo" X Y Z && |
| create_pack_in "$shared_repo" Px1 <<-EOF && |
| $X |
| $Y |
| $Z |
| $A |
| $B |
| $C |
| EOF |
| create_pack_in "$shared_repo" Px2 <<-EOF |
| $X |
| $Y |
| $Z |
| $D |
| $E |
| $F |
| EOF |
| ' |
| |
| test_expect_success 'shared: no redundant without --alt-odb' ' |
| ( |
| cd "$shared_repo" && |
| $git_pack_redundant --all >out && |
| test_must_be_empty out |
| ) |
| ' |
| |
| ############################################################################# |
| # Chart of packs and objects for this test case |
| # |
| # ================= main.git ================ |
| # | T A B C D E F G H I J K L M N O P Q R <----------------+ |
| # ----+-------------------------------------- | |
| # P1 | x x x x x x x x | |
| # P3 | x x x x x x | |
| # P5 | x x x x | |
| # P7 | x x | |
| # ----+-------------------------------------- | |
| # ALL | x x x x x x x x x x x x x x x x x x x | |
| # | |
| # | |
| # ================ shared.git ======================= | |
| # | T A B C D E F G H I J K L M N O P Q R X Y Z <objects/info/alternates> |
| # ----+---------------------------------------------- |
| # Px1 | s s s x x x |
| # Px2*| s s s ! ! ! |
| # ----+---------------------------------------------- |
| # ALL | s s s s s s s s s s s s s s s s s s s x x x |
| # |
| ############################################################################# |
| test_expect_success 'shared: one pack is redundant with --alt-odb' ' |
| ( |
| cd "$shared_repo" && |
| $git_pack_redundant --all --alt-odb >out && |
| format_packfiles <out >actual && |
| test_line_count = 1 actual |
| ) |
| ' |
| |
| ############################################################################# |
| # Chart of packs and objects for this test case |
| # |
| # ================= main.git ================ |
| # | T A B C D E F G H I J K L M N O P Q R <----------------+ |
| # ----+-------------------------------------- | |
| # P1 | x x x x x x x x | |
| # P3 | x x x x x x | |
| # P5 | x x x x | |
| # P7 | x x | |
| # ----+-------------------------------------- | |
| # ALL | x x x x x x x x x x x x x x x x x x x | |
| # | |
| # | |
| # ================ shared.git ======================= | |
| # | T A B C D E F G H I J K L M N O P Q R X Y Z <objects/info/alternates> |
| # ----+---------------------------------------------- |
| # Px1*| s s s i i i |
| # Px2*| s s s i i i |
| # ----+---------------------------------------------- |
| # ALL | s s s s s s s s s s s s s s s s s s s i i i |
| # (ignored objects, marked with i) |
| # |
| ############################################################################# |
| test_expect_success 'shared: ignore unique objects and all two packs are redundant' ' |
| ( |
| cd "$shared_repo" && |
| cat >expect <<-EOF && |
| Px1:$Px1 |
| Px2:$Px2 |
| EOF |
| $git_pack_redundant --all --alt-odb >out <<-EOF && |
| $X |
| $Y |
| $Z |
| EOF |
| format_packfiles <out >actual && |
| test_cmp expect actual |
| ) |
| ' |
| |
| test_done |