#!/bin/sh # # Copyright (C) 2006 Martin Waitz # global test_description := ''test clone --reference'' source ./test-lib.sh global base_dir := $[pwd] global U := "$base_dir/UPLOAD_LOG" # create a commit in repo $1 with name $2 proc commit_in { shell { cd $1 && echo $2 >$2 && git add $2 && git commit -m $2 } } # check that there are $2 loose objects in repo $1 proc test_objcount { echo $2 >expect && git -C $1 count-objects >actual.raw && cut -d' ' -f1 actual && test_cmp expect actual } test_expect_success 'preparing first repository' ' test_create_repo A && commit_in A file1 ' test_expect_success 'preparing second repository' ' git clone A B && commit_in B file2 && git -C B repack -ad && git -C B prune ' test_expect_success 'cloning with reference (-l -s)' ' git clone -l -s --reference B A C ' test_expect_success 'existence of info/alternates' ' test_line_count = 2 C/.git/objects/info/alternates ' test_expect_success 'pulling from reference' ' git -C C pull ../B master ' test_expect_success 'that reference gets used' ' test_objcount C 0 ' test_expect_success 'cloning with reference (no -l -s)' ' GIT_TRACE_PACKET=$U.D git clone --reference B "file://$(pwd)/A" D ' test_expect_success 'fetched no objects' ' test -s "$U.D" && ! grep " want" "$U.D" ' test_expect_success 'existence of info/alternates' ' test_line_count = 1 D/.git/objects/info/alternates ' test_expect_success 'pulling from reference' ' git -C D pull ../B master ' test_expect_success 'that reference gets used' ' test_objcount D 0 ' test_expect_success 'updating origin' ' commit_in A file3 && git -C A repack -ad && git -C A prune ' test_expect_success 'pulling changes from origin' ' git -C C pull origin ' # the 2 local objects are commit and tree from the merge test_expect_success 'that alternate to origin gets used' ' test_objcount C 2 ' test_expect_success 'pulling changes from origin' ' git -C D pull origin ' # the 5 local objects are expected; file3 blob, commit in A to add it # and its tree, and 2 are our tree and the merge commit. test_expect_success 'check objects expected to exist locally' ' test_objcount D 5 ' test_expect_success 'preparing alternate repository #1' ' test_create_repo F && commit_in F file1 ' test_expect_success 'cloning alternate repo #2 and adding changes to repo #1' ' git clone F G && commit_in F file2 ' test_expect_success 'cloning alternate repo #1, using #2 as reference' ' git clone --reference G F H ' test_expect_success 'cloning with reference being subset of source (-l -s)' ' git clone -l -s --reference A B E ' test_expect_success 'cloning with multiple references drops duplicates' ' git clone -s --reference B --reference A --reference B A dups && test_line_count = 2 dups/.git/objects/info/alternates ' test_expect_success 'clone with reference from a tagged repository' ' ( cd A && git tag -a -m tagged HEAD ) && git clone --reference=A A I ' test_expect_success 'prepare branched repository' ' git clone A J && ( cd J && git checkout -b other master^ && echo other >otherfile && git add otherfile && git commit -m other && git checkout master ) ' test_expect_success 'fetch with incomplete alternates' ' git init K && echo "$base_dir/A/.git/objects" >K/.git/objects/info/alternates && ( cd K && git remote add J "file://$base_dir/J" && GIT_TRACE_PACKET=$U.K git fetch J ) && master_object=$(cd A && git for-each-ref --format="%(objectname)" refs/heads/master) && test -s "$U.K" && ! grep " want $master_object" "$U.K" && tag_object=$(cd A && git for-each-ref --format="%(objectname)" refs/tags/HEAD) && ! grep " want $tag_object" "$U.K" ' test_expect_success 'clone using repo with gitfile as a reference' ' git clone --separate-git-dir=L A M && git clone --reference=M A N && echo "$base_dir/L/objects" >expected && test_cmp expected "$base_dir/N/.git/objects/info/alternates" ' test_expect_success 'clone using repo pointed at by gitfile as reference' ' git clone --reference=M/.git A O && echo "$base_dir/L/objects" >expected && test_cmp expected "$base_dir/O/.git/objects/info/alternates" ' test_expect_success 'clone and dissociate from reference' ' git init P && ( cd P && test_commit one ) && git clone P Q && ( cd Q && test_commit two ) && git clone --no-local --reference=P Q R && git clone --no-local --reference=P --dissociate Q S && # removing the reference P would corrupt R but not S rm -fr P && test_must_fail git -C R fsck && git -C S fsck ' test_expect_success 'clone, dissociate from partial reference and repack' ' rm -fr P Q R && git init P && ( cd P && test_commit one && git repack && test_commit two && git repack ) && git clone --bare P Q && ( cd P && git checkout -b second && test_commit three && git repack ) && git clone --bare --dissociate --reference=P Q R && ls R/objects/pack/*.pack >packs.txt && test_line_count = 1 packs.txt ' test_expect_success 'clone, dissociate from alternates' ' rm -fr A B C && test_create_repo A && commit_in A file1 && git clone --reference=A A B && test_line_count = 1 B/.git/objects/info/alternates && git clone --local --dissociate B C && ! test -f C/.git/objects/info/alternates && ( cd C && git fsck ) ' test_done (CommandList children: [ (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:test_description) op: Equal rhs: {(SQ <"test clone --reference">)} spids: [13] ) ] spids: [13] ) (C {(.)} {(./test-lib.sh)}) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:base_dir) op: Equal rhs: { (CommandSubPart command_list: (CommandList children:[(C {(pwd)})]) left_token: spids: [24 26] ) } spids: [23] ) ] spids: [23] ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:U) op: Equal rhs: {($ VSub_Name "$base_dir") (/UPLOAD_LOG)} spids: [29] ) ] spids: [29] ) (FuncDef name: commit_in body: (BraceGroup children: [ (Subshell child: (AndOr children: [ (C {(cd)} {(DQ ($ VSub_Number "$1"))}) (AndOr children: [ (SimpleCommand words: [{(echo)} {(DQ ($ VSub_Number "$2"))}] redirects: [ (Redir op_id: Redir_Great fd: -1 arg_word: {(DQ ($ VSub_Number "$2"))} spids: [63] ) ] ) (AndOr children: [ (C {(git)} {(add)} {(DQ ($ VSub_Number "$2"))}) (C {(git)} {(commit)} {(-m)} {(DQ ($ VSub_Number "$2"))}) ] op_id: Op_DAmp ) ] op_id: Op_DAmp ) ] op_id: Op_DAmp ) spids: [45 93] ) ] spids: [42] ) spids: [37 41] ) (FuncDef name: test_objcount body: (BraceGroup children: [ (AndOr children: [ (SimpleCommand words: [{(echo)} {(DQ ($ VSub_Number "$2"))}] redirects: [(Redir op_id:Redir_Great fd:-1 arg_word:{(expect)} spids:[115])] ) (AndOr children: [ (SimpleCommand words: [{(git)} {(-C)} {(DQ ($ VSub_Number "$1"))} {(count-objects)}] redirects: [(Redir op_id:Redir_Great fd:-1 arg_word:{(actual.raw)} spids:[131])] ) (AndOr children: [ (SimpleCommand words: [{(cut)} {(-d) (SQ <" ">)} {(-f1)}] redirects: [ (Redir op_id: Redir_Less fd: -1 arg_word: {(actual.raw)} spids: [146] ) (Redir op_id: Redir_Great fd: -1 arg_word: {(actual)} spids: [149] ) ] ) (C {(test_cmp)} {(expect)} {(actual)}) ] op_id: Op_DAmp ) ] op_id: Op_DAmp ) ] op_id: Op_DAmp ) ] spids: [106] ) spids: [101 105] ) (C {(test_expect_success)} {(SQ <"preparing first repository">)} {(SQ <"\n"> <"\ttest_create_repo A &&\n"> <"\tcommit_in A file1\n">)} ) (C {(test_expect_success)} {(SQ <"preparing second repository">)} { (SQ <"\n"> <"\tgit clone A B &&\n"> <"\tcommit_in B file2 &&\n"> <"\tgit -C B repack -ad &&\n"> <"\tgit -C B prune\n"> ) } ) (C {(test_expect_success)} {(SQ <"cloning with reference (-l -s)">)} {(SQ <"\n"> <"\tgit clone -l -s --reference B A C\n">)} ) (C {(test_expect_success)} {(SQ <"existence of info/alternates">)} {(SQ <"\n"> <"\ttest_line_count = 2 C/.git/objects/info/alternates\n">)} ) (C {(test_expect_success)} {(SQ <"pulling from reference">)} {(SQ <"\n"> <"\tgit -C C pull ../B master\n">)} ) (C {(test_expect_success)} {(SQ <"that reference gets used">)} {(SQ <"\n"> <"\ttest_objcount C 0\n">)} ) (C {(test_expect_success)} {(SQ <"cloning with reference (no -l -s)">)} {(SQ <"\n"> <"\tGIT_TRACE_PACKET=$U.D git clone --reference B \"file://$(pwd)/A\" D\n">)} ) (C {(test_expect_success)} {(SQ <"fetched no objects">)} {(SQ <"\n"> <"\ttest -s \"$U.D\" &&\n"> <"\t! grep \" want\" \"$U.D\"\n">)} ) (C {(test_expect_success)} {(SQ <"existence of info/alternates">)} {(SQ <"\n"> <"\ttest_line_count = 1 D/.git/objects/info/alternates\n">)} ) (C {(test_expect_success)} {(SQ <"pulling from reference">)} {(SQ <"\n"> <"\tgit -C D pull ../B master\n">)} ) (C {(test_expect_success)} {(SQ <"that reference gets used">)} {(SQ <"\n"> <"\ttest_objcount D 0\n">)} ) (C {(test_expect_success)} {(SQ <"updating origin">)} { (SQ <"\n"> <"\tcommit_in A file3 &&\n"> <"\tgit -C A repack -ad &&\n"> <"\tgit -C A prune\n">) } ) (C {(test_expect_success)} {(SQ <"pulling changes from origin">)} {(SQ <"\n"> <"\tgit -C C pull origin\n">)} ) (C {(test_expect_success)} {(SQ <"that alternate to origin gets used">)} {(SQ <"\n"> <"\ttest_objcount C 2\n">)} ) (C {(test_expect_success)} {(SQ <"pulling changes from origin">)} {(SQ <"\n"> <"\tgit -C D pull origin\n">)} ) (C {(test_expect_success)} {(SQ <"check objects expected to exist locally">)} {(SQ <"\n"> <"\ttest_objcount D 5\n">)} ) (C {(test_expect_success)} {(SQ <"preparing alternate repository #1">)} {(SQ <"\n"> <"\ttest_create_repo F &&\n"> <"\tcommit_in F file1\n">)} ) (C {(test_expect_success)} {(SQ <"cloning alternate repo #2 and adding changes to repo #1">)} {(SQ <"\n"> <"\tgit clone F G &&\n"> <"\tcommit_in F file2\n">)} ) (C {(test_expect_success)} {(SQ <"cloning alternate repo #1, using #2 as reference">)} {(SQ <"\n"> <"\tgit clone --reference G F H\n">)} ) (C {(test_expect_success)} {(SQ <"cloning with reference being subset of source (-l -s)">)} {(SQ <"\n"> <"\tgit clone -l -s --reference A B E\n">)} ) (C {(test_expect_success)} {(SQ <"cloning with multiple references drops duplicates">)} { (SQ <"\n"> <"\tgit clone -s --reference B --reference A --reference B A dups &&\n"> <"\ttest_line_count = 2 dups/.git/objects/info/alternates\n"> ) } ) (C {(test_expect_success)} {(SQ <"clone with reference from a tagged repository">)} { (SQ <"\n"> <"\t(\n"> <"\t\tcd A && git tag -a -m tagged HEAD\n"> <"\t) &&\n"> <"\tgit clone --reference=A A I\n"> ) } ) (C {(test_expect_success)} {(SQ <"prepare branched repository">)} { (SQ <"\n"> <"\tgit clone A J &&\n"> <"\t(\n"> <"\t\tcd J &&\n"> <"\t\tgit checkout -b other master^ &&\n"> <"\t\techo other >otherfile &&\n"> <"\t\tgit add otherfile &&\n"> <"\t\tgit commit -m other &&\n"> <"\t\tgit checkout master\n"> <"\t)\n"> ) } ) (C {(test_expect_success)} {(SQ <"fetch with incomplete alternates">)} { (SQ <"\n"> <"\tgit init K &&\n"> <"\techo \"$base_dir/A/.git/objects\" >K/.git/objects/info/alternates &&\n"> <"\t(\n"> <"\t\tcd K &&\n"> <"\t\tgit remote add J \"file://$base_dir/J\" &&\n"> <"\t\tGIT_TRACE_PACKET=$U.K git fetch J\n"> <"\t) &&\n"> < "\tmaster_object=$(cd A && git for-each-ref --format=\"%(objectname)\" refs/heads/master) &&\n" > <"\ttest -s \"$U.K\" &&\n"> <"\t! grep \" want $master_object\" \"$U.K\" &&\n"> < "\ttag_object=$(cd A && git for-each-ref --format=\"%(objectname)\" refs/tags/HEAD) &&\n" > <"\t! grep \" want $tag_object\" \"$U.K\"\n"> ) } ) (C {(test_expect_success)} {(SQ <"clone using repo with gitfile as a reference">)} { (SQ <"\n"> <"\tgit clone --separate-git-dir=L A M &&\n"> <"\tgit clone --reference=M A N &&\n"> <"\techo \"$base_dir/L/objects\" >expected &&\n"> <"\ttest_cmp expected \"$base_dir/N/.git/objects/info/alternates\"\n"> ) } ) (C {(test_expect_success)} {(SQ <"clone using repo pointed at by gitfile as reference">)} { (SQ <"\n"> <"\tgit clone --reference=M/.git A O &&\n"> <"\techo \"$base_dir/L/objects\" >expected &&\n"> <"\ttest_cmp expected \"$base_dir/O/.git/objects/info/alternates\"\n"> ) } ) (C {(test_expect_success)} {(SQ <"clone and dissociate from reference">)} { (SQ <"\n"> <"\tgit init P &&\n"> <"\t(\n"> <"\t\tcd P &&\ttest_commit one\n"> <"\t) &&\n"> <"\tgit clone P Q &&\n"> <"\t(\n"> <"\t\tcd Q && test_commit two\n"> <"\t) &&\n"> <"\tgit clone --no-local --reference=P Q R &&\n"> <"\tgit clone --no-local --reference=P --dissociate Q S &&\n"> <"\t# removing the reference P would corrupt R but not S\n"> <"\trm -fr P &&\n"> <"\ttest_must_fail git -C R fsck &&\n"> <"\tgit -C S fsck\n"> ) } ) (C {(test_expect_success)} {(SQ <"clone, dissociate from partial reference and repack">)} { (SQ <"\n"> <"\trm -fr P Q R &&\n"> <"\tgit init P &&\n"> <"\t(\n"> <"\t\tcd P &&\n"> <"\t\ttest_commit one &&\n"> <"\t\tgit repack &&\n"> <"\t\ttest_commit two &&\n"> <"\t\tgit repack\n"> <"\t) &&\n"> <"\tgit clone --bare P Q &&\n"> <"\t(\n"> <"\t\tcd P &&\n"> <"\t\tgit checkout -b second &&\n"> <"\t\ttest_commit three &&\n"> <"\t\tgit repack\n"> <"\t) &&\n"> <"\tgit clone --bare --dissociate --reference=P Q R &&\n"> <"\tls R/objects/pack/*.pack >packs.txt &&\n"> <"\ttest_line_count = 1 packs.txt\n"> ) } ) (C {(test_expect_success)} {(SQ <"clone, dissociate from alternates">)} { (SQ <"\n"> <"\trm -fr A B C &&\n"> <"\ttest_create_repo A &&\n"> <"\tcommit_in A file1 &&\n"> <"\tgit clone --reference=A A B &&\n"> <"\ttest_line_count = 1 B/.git/objects/info/alternates &&\n"> <"\tgit clone --local --dissociate B C &&\n"> <"\t! test -f C/.git/objects/info/alternates &&\n"> <"\t( cd C && git fsck )\n"> ) } ) (C {(test_done)}) ] )