(command.CommandList children: [ (command.ShAssignment pairs: [ (assign_pair lhs: (sh_lhs_expr.Name name:test_description) op: assign_op.Equal rhs: { (SQ (Token id: Id.Lit_Chars val: 'test handling of inter-pack delta cycles during repack\n' span_id: 6 ) (Token id:Id.Lit_Chars val:'\n' span_id:7) (Token id: Id.Lit_Chars val: 'The goal here is to create a situation where we have two blobs, A and B, with A\n' span_id: 8 ) (Token id: Id.Lit_Chars val: 'as a delta against B in one pack, and vice versa in the other. Then if we can\n' span_id: 9 ) (Token id: Id.Lit_Chars val: 'persuade a full repack to find A from one pack and B from the other, that will\n' span_id: 10 ) (Token id:Id.Lit_Chars val:'give us a cycle when we attempt to reuse those deltas.\n' span_id:11) (Token id:Id.Lit_Chars val:'\n' span_id:12) (Token id: Id.Lit_Chars val: 'The trick is in the "persuade" step, as it depends on the internals of how\n' span_id: 13 ) (Token id: Id.Lit_Chars val: 'pack-objects picks which pack to reuse the deltas from. But we can assume\n' span_id: 14 ) (Token id:Id.Lit_Chars val:'that it does so in one of two general strategies:\n' span_id:15) (Token id:Id.Lit_Chars val:'\n' span_id:16) (Token id: Id.Lit_Chars val: ' 1. Using a static ordering of packs. In this case, no inter-pack cycles can\n' span_id: 17 ) (Token id: Id.Lit_Chars val: ' happen. Any objects with a delta relationship must be present in the same\n' span_id: 18 ) (Token id: Id.Lit_Chars val: ' pack (i.e., no "--thin" packs on disk), so we will find all related objects\n' span_id: 19 ) (Token id: Id.Lit_Chars val: ' from that pack. So assuming there are no cycles within a single pack (and\n' span_id: 20 ) (Token id: Id.Lit_Chars val: ' we avoid generating them via pack-objects or importing them via\n' span_id: 21 ) (Token id:Id.Lit_Chars val:' index-pack), then our result will have no cycles.\n' span_id:22) (Token id:Id.Lit_Chars val:'\n' span_id:23) (Token id: Id.Lit_Chars val: ' So this case should pass the tests no matter how we arrange things.\n' span_id: 24 ) (Token id:Id.Lit_Chars val:'\n' span_id:25) (Token id: Id.Lit_Chars val: ' 2. Picking the next pack to examine based on locality (i.e., where we found\n' span_id: 26 ) (Token id:Id.Lit_Chars val:' something else recently).\n' span_id:27) (Token id:Id.Lit_Chars val:'\n' span_id:28) (Token id: Id.Lit_Chars val: ' In this case, we want to make sure that we find the delta versions of A and\n' span_id: 29 ) (Token id: Id.Lit_Chars val: ' B and not their base versions. We can do this by putting two blobs in each\n' span_id: 30 ) (Token id: Id.Lit_Chars val: ' pack. The first is a "dummy" blob that can only be found in the pack in\n' span_id: 31 ) (Token id: Id.Lit_Chars val: ' question. And then the second is the actual delta we want to find.\n' span_id: 32 ) (Token id:Id.Lit_Chars val:'\n' span_id:33) (Token id: Id.Lit_Chars val: ' The two blobs must be present in the same tree, not present in other trees,\n' span_id: 34 ) (Token id: Id.Lit_Chars val: ' and the dummy pathname must sort before the delta path.\n' span_id: 35 ) (Token id:Id.Lit_Chars val:'\n' span_id:36) (Token id: Id.Lit_Chars val: 'The setup below focuses on case 2. We have two commits HEAD and HEAD^, each\n' span_id: 37 ) (Token id: Id.Lit_Chars val: 'which has two files: "dummy" and "file". Then we can make two packs which\n' span_id: 38 ) (Token id:Id.Lit_Chars val:'contain:\n' span_id:39) (Token id:Id.Lit_Chars val:'\n' span_id:40) (Token id:Id.Lit_Chars val:' [pack one]\n' span_id:41) (Token id:Id.Lit_Chars val:' HEAD:dummy\n' span_id:42) (Token id: Id.Lit_Chars val: ' HEAD:file (as delta against HEAD^:file)\n' span_id: 43 ) (Token id:Id.Lit_Chars val:' HEAD^:file (as base)\n' span_id:44) (Token id:Id.Lit_Chars val:'\n' span_id:45) (Token id:Id.Lit_Chars val:' [pack two]\n' span_id:46) (Token id:Id.Lit_Chars val:' HEAD^:dummy\n' span_id:47) (Token id:Id.Lit_Chars val:' HEAD^:file (as delta against HEAD:file)\n' span_id:48) (Token id:Id.Lit_Chars val:' HEAD:file (as base)\n' span_id:49) (Token id:Id.Lit_Chars val:'\n' span_id:50) (Token id: Id.Lit_Chars val: 'Then no matter which order we start looking at the packs in, we know that we\n' span_id: 51 ) (Token id: Id.Lit_Chars val: 'will always find a delta for "file", because its lookup will always come\n' span_id: 52 ) (Token id:Id.Lit_Chars val:'immediately after the lookup for "dummy".\n' span_id:53) ) } spids: [4] ) ] ) (C {(.)} {(./test-lib.sh)}) (command.ShFunction name: make_pack body: (command.BraceGroup children: [ (command.Pipeline children: [ (command.BraceGroup children: [ (C {(printf)} {(SQ (Token id:Id.Lit_Chars val:'%s\\n' span_id:104))} { (DQ (-) (command_sub left_token: (Token id:Id.Left_DollarParen val:'$(' span_id:109) command_list: (command.CommandList children: [(C {(git)} {(rev-parse)} {($ Id.VSub_Number '$2')})] ) ) ) } ) (C {(printf)} {(SQ (Token id:Id.Lit_Chars val:'%s dummy\\n' span_id:122))} { (DQ (command_sub left_token: (Token id:Id.Left_DollarParen val:'$(' span_id:126) command_list: (command.CommandList children: [ (C {(git)} {(rev-parse)} {($ Id.VSub_Number '$1') (Id.Lit_Other ':') (dummy)} ) ] ) ) ) } ) (C {(printf)} {(SQ (Token id:Id.Lit_Chars val:'%s file\\n' span_id:141))} { (DQ (command_sub left_token: (Token id:Id.Left_DollarParen val:'$(' span_id:145) command_list: (command.CommandList children: [ (C {(git)} {(rev-parse)} {($ Id.VSub_Number '$1') (Id.Lit_Other ':') (file)} ) ] ) ) ) } ) ] ) (C {(git)} {(pack-objects)} {(--stdout)}) (C {(git)} {(index-pack)} {(--stdin)} {(--fix-thin)}) ] negated: F ) ] ) ) (C {(test_expect_success)} {(SQ (Token id:Id.Lit_Chars val:setup span_id:185))} { (SQ (Token id:Id.Lit_Chars val:'\n' span_id:189) (Token id:Id.Lit_Chars val:'\ttest-genrandom base 4096 >base &&\n' span_id:190) (Token id:Id.Lit_Chars val:'\tfor i in one two\n' span_id:191) (Token id:Id.Lit_Chars val:'\tdo\n' span_id:192) (Token id:Id.Lit_Chars val:'\t\t# we want shared content here to encourage deltas...\n' span_id:193) (Token id:Id.Lit_Chars val:'\t\tcp base file &&\n' span_id:194) (Token id:Id.Lit_Chars val:'\t\techo $i >>file &&\n' span_id:195) (Token id:Id.Lit_Chars val:'\n' span_id:196) (Token id: Id.Lit_Chars val: '\t\t# ...whereas dummy should be short, because we do not want\n' span_id: 197 ) (Token id: Id.Lit_Chars val: '\t\t# deltas that would create duplicates when we --fix-thin\n' span_id: 198 ) (Token id:Id.Lit_Chars val:'\t\techo $i >dummy &&\n' span_id:199) (Token id:Id.Lit_Chars val:'\n' span_id:200) (Token id:Id.Lit_Chars val:'\t\tgit add file dummy &&\n' span_id:201) (Token id:Id.Lit_Chars val:'\t\ttest_tick &&\n' span_id:202) (Token id:Id.Lit_Chars val:'\t\tgit commit -m $i ||\n' span_id:203) (Token id:Id.Lit_Chars val:'\t\treturn 1\n' span_id:204) (Token id:Id.Lit_Chars val:'\tdone &&\n' span_id:205) (Token id:Id.Lit_Chars val:'\n' span_id:206) (Token id:Id.Lit_Chars val:'\tmake_pack HEAD^ HEAD &&\n' span_id:207) (Token id:Id.Lit_Chars val:'\tmake_pack HEAD HEAD^\n' span_id:208) ) } ) (C {(test_expect_success)} {(SQ (Token id:Id.Lit_Chars val:repack span_id:215))} { (SQ (Token id:Id.Lit_Chars val:'\n' span_id:219) (Token id: Id.Lit_Chars val: '\t# We first want to check that we do not have any internal errors,\n' span_id: 220 ) (Token id: Id.Lit_Chars val: '\t# and also that we do not hit the last-ditch cycle-breaking code\n' span_id: 221 ) (Token id: Id.Lit_Chars val: '\t# in write_object(), which will issue a warning to stderr.\n' span_id: 222 ) (Token id:Id.Lit_Chars val:'\t>expect &&\n' span_id:223) (Token id:Id.Lit_Chars val:'\tgit repack -ad 2>stderr &&\n' span_id:224) (Token id:Id.Lit_Chars val:'\ttest_cmp expect stderr &&\n' span_id:225) (Token id:Id.Lit_Chars val:'\n' span_id:226) (Token id: Id.Lit_Chars val: '\t# And then double-check that the resulting pack is usable (i.e.,\n' span_id: 227 ) (Token id: Id.Lit_Chars val: '\t# we did not fail to notice any cycles). We know we are accessing\n' span_id: 228 ) (Token id: Id.Lit_Chars val: '\t# the objects via the new pack here, because "repack -d" will have\n' span_id: 229 ) (Token id:Id.Lit_Chars val:'\t# removed the others.\n' span_id:230) (Token id: Id.Lit_Chars val: '\tgit cat-file blob HEAD:file >/dev/null &&\n' span_id: 231 ) (Token id:Id.Lit_Chars val:'\tgit cat-file blob HEAD^:file >/dev/null\n' span_id:232) ) } ) (C {(test_done)}) ] )