Merge branch 'ma/doc-pack-format-varint-for-sizes'
[git] / t / t5323-pack-redundant.sh
1 #!/bin/sh
2 #
3 # Copyright (c) 2018 Jiang Xin
4 #
5
6 test_description='Test git pack-redundant
7
8 In order to test git-pack-redundant, we will create a number of objects and
9 packs in the repository `master.git`. The relationship between packs (P1-P8)
10 and objects (T, A-R) is showed in the following chart. Objects of a pack will
11 be marked with letter x, while objects of redundant packs will be marked with
12 exclamation point, and redundant pack itself will be marked with asterisk.
13
14         | T A B C D E F G H I J K L M N O P Q R
15     ----+--------------------------------------
16     P1  | x x x x x x x                       x
17     P2* |     ! ! ! !   ! ! !
18     P3  |             x     x x x x x
19     P4* |                     ! ! ! !     !
20     P5  |               x x           x x
21     P6* |                             ! !   !
22     P7  |                                 x x
23     P8* |   !
24     ----+--------------------------------------
25     ALL | x x x x x x x x x x x x x x x x x x x
26
27 Another repository `shared.git` has unique objects (X-Z), while other objects
28 (marked with letter s) are shared through alt-odb (of `master.git`). The
29 relationship between packs and objects is as follows:
30
31         | T A B C D E F G H I J K L M N O P Q R   X Y Z
32     ----+----------------------------------------------
33     Px1 |   s s s                                 x x x
34     Px2 |         s s s                           x x x
35 '
36
37 . ./test-lib.sh
38
39 master_repo=master.git
40 shared_repo=shared.git
41
42 # Create commits in <repo> and assign each commit's oid to shell variables
43 # given in the arguments (A, B, and C). E.g.:
44 #
45 #     create_commits_in <repo> A B C
46 #
47 # NOTE: Avoid calling this function from a subshell since variable
48 # assignments will disappear when subshell exits.
49 create_commits_in () {
50         repo="$1" &&
51         if ! parent=$(git -C "$repo" rev-parse HEAD^{} 2>/dev/null)
52         then
53                 parent=
54         fi &&
55         T=$(git -C "$repo" write-tree) &&
56         shift &&
57         while test $# -gt 0
58         do
59                 name=$1 &&
60                 test_tick &&
61                 if test -z "$parent"
62                 then
63                         oid=$(echo $name | git -C "$repo" commit-tree $T)
64                 else
65                         oid=$(echo $name | git -C "$repo" commit-tree -p $parent $T)
66                 fi &&
67                 eval $name=$oid &&
68                 parent=$oid &&
69                 shift ||
70                 return 1
71         done &&
72         git -C "$repo" update-ref refs/heads/master $oid
73 }
74
75 # Create pack in <repo> and assign pack id to variable given in the 2nd argument
76 # (<name>). Commits in the pack will be read from stdin. E.g.:
77 #
78 #     create_pack_in <repo> <name> <<-EOF
79 #         ...
80 #         EOF
81 #
82 # NOTE: commits from stdin should be given using heredoc, not using pipe, and
83 # avoid calling this function from a subshell since variable assignments will
84 # disappear when subshell exits.
85 create_pack_in () {
86         repo="$1" &&
87         name="$2" &&
88         pack=$(git -C "$repo/objects/pack" pack-objects -q pack) &&
89         eval $name=$pack &&
90         eval P$pack=$name:$pack
91 }
92
93 format_packfiles () {
94         sed \
95                 -e "s#.*/pack-\(.*\)\.idx#\1#" \
96                 -e "s#.*/pack-\(.*\)\.pack#\1#" |
97         sort -u |
98         while read p
99         do
100                 if test -z "$(eval echo \${P$p})"
101                 then
102                         echo $p
103                 else
104                         eval echo "\${P$p}"
105                 fi
106         done |
107         sort
108 }
109
110 test_expect_success 'setup master repo' '
111         git init --bare "$master_repo" &&
112         create_commits_in "$master_repo" A B C D E F G H I J K L M N O P Q R
113 '
114
115 test_expect_success 'master: pack-redundant works with no packfile' '
116         (
117                 cd "$master_repo" &&
118                 cat >expect <<-EOF &&
119                         fatal: Zero packs found!
120                         EOF
121                 test_must_fail git pack-redundant --all >actual 2>&1 &&
122                 test_cmp expect actual
123         )
124 '
125
126 #############################################################################
127 # Chart of packs and objects for this test case
128 #
129 #         | T A B C D E F G H I J K L M N O P Q R
130 #     ----+--------------------------------------
131 #     P1  | x x x x x x x                       x
132 #     ----+--------------------------------------
133 #     ALL | x x x x x x x                       x
134 #
135 #############################################################################
136 test_expect_success 'master: pack-redundant works with one packfile' '
137         create_pack_in "$master_repo" P1 <<-EOF &&
138                 $T
139                 $A
140                 $B
141                 $C
142                 $D
143                 $E
144                 $F
145                 $R
146                 EOF
147         (
148                 cd "$master_repo" &&
149                 git pack-redundant --all >out &&
150                 test_must_be_empty out
151         )
152 '
153
154 #############################################################################
155 # Chart of packs and objects for this test case
156 #
157 #         | T A B C D E F G H I J K L M N O P Q R
158 #     ----+--------------------------------------
159 #     P1  | x x x x x x x                       x
160 #     P2  |     x x x x   x x x
161 #     P3  |             x     x x x x x
162 #     ----+--------------------------------------
163 #     ALL | x x x x x x x x x x x x x x         x
164 #
165 #############################################################################
166 test_expect_success 'master: no redundant for pack 1, 2, 3' '
167         create_pack_in "$master_repo" P2 <<-EOF &&
168                 $B
169                 $C
170                 $D
171                 $E
172                 $G
173                 $H
174                 $I
175                 EOF
176         create_pack_in "$master_repo" P3 <<-EOF &&
177                 $F
178                 $I
179                 $J
180                 $K
181                 $L
182                 $M
183                 EOF
184         (
185                 cd "$master_repo" &&
186                 git pack-redundant --all >out &&
187                 test_must_be_empty out
188         )
189 '
190
191 #############################################################################
192 # Chart of packs and objects for this test case
193 #
194 #         | T A B C D E F G H I J K L M N O P Q R
195 #     ----+--------------------------------------
196 #     P1  | x x x x x x x                       x
197 #     P2  |     x x x x   x x x
198 #     P3* |             !     ! ! ! ! !
199 #     P4  |                     x x x x     x
200 #     P5  |               x x           x x
201 #     ----+--------------------------------------
202 #     ALL | x x x x x x x x x x x x x x x x x   x
203 #
204 #############################################################################
205 test_expect_success 'master: one of pack-2/pack-3 is redundant' '
206         create_pack_in "$master_repo" P4 <<-EOF &&
207                 $J
208                 $K
209                 $L
210                 $M
211                 $P
212                 EOF
213         create_pack_in "$master_repo" P5 <<-EOF &&
214                 $G
215                 $H
216                 $N
217                 $O
218                 EOF
219         (
220                 cd "$master_repo" &&
221                 cat >expect <<-EOF &&
222                         P3:$P3
223                         EOF
224                 git pack-redundant --all >out &&
225                 format_packfiles <out >actual &&
226                 test_cmp expect actual
227         )
228 '
229
230 #############################################################################
231 # Chart of packs and objects for this test case
232 #
233 #         | T A B C D E F G H I J K L M N O P Q R
234 #     ----+--------------------------------------
235 #     P1  | x x x x x x x                       x
236 #     P2* |     ! ! ! !   ! ! !
237 #     P3  |             x     x x x x x
238 #     P4* |                     ! ! ! !     !
239 #     P5  |               x x           x x
240 #     P6* |                             ! !   !
241 #     P7  |                                 x x
242 #     ----+--------------------------------------
243 #     ALL | x x x x x x x x x x x x x x x x x x x
244 #
245 #############################################################################
246 test_expect_success 'master: pack 2, 4, and 6 are redundant' '
247         create_pack_in "$master_repo" P6 <<-EOF &&
248                 $N
249                 $O
250                 $Q
251                 EOF
252         create_pack_in "$master_repo" P7 <<-EOF &&
253                 $P
254                 $Q
255                 EOF
256         (
257                 cd "$master_repo" &&
258                 cat >expect <<-EOF &&
259                         P2:$P2
260                         P4:$P4
261                         P6:$P6
262                         EOF
263                 git pack-redundant --all >out &&
264                 format_packfiles <out >actual &&
265                 test_cmp expect actual
266         )
267 '
268
269 #############################################################################
270 # Chart of packs and objects for this test case
271 #
272 #         | T A B C D E F G H I J K L M N O P Q R
273 #     ----+--------------------------------------
274 #     P1  | x x x x x x x                       x
275 #     P2* |     ! ! ! !   ! ! !
276 #     P3  |             x     x x x x x
277 #     P4* |                     ! ! ! !     !
278 #     P5  |               x x           x x
279 #     P6* |                             ! !   !
280 #     P7  |                                 x x
281 #     P8* |   !
282 #     ----+--------------------------------------
283 #     ALL | x x x x x x x x x x x x x x x x x x x
284 #
285 #############################################################################
286 test_expect_success 'master: pack-8 (subset of pack-1) is also redundant' '
287         create_pack_in "$master_repo" P8 <<-EOF &&
288                 $A
289                 EOF
290         (
291                 cd "$master_repo" &&
292                 cat >expect <<-EOF &&
293                         P2:$P2
294                         P4:$P4
295                         P6:$P6
296                         P8:$P8
297                         EOF
298                 git pack-redundant --all >out &&
299                 format_packfiles <out >actual &&
300                 test_cmp expect actual
301         )
302 '
303
304 test_expect_success 'master: clean loose objects' '
305         (
306                 cd "$master_repo" &&
307                 git prune-packed &&
308                 find objects -type f | sed -e "/objects\/pack\//d" >out &&
309                 test_must_be_empty out
310         )
311 '
312
313 test_expect_success 'master: remove redundant packs and pass fsck' '
314         (
315                 cd "$master_repo" &&
316                 git pack-redundant --all | xargs rm &&
317                 git fsck &&
318                 git pack-redundant --all >out &&
319                 test_must_be_empty out
320         )
321 '
322
323 # The following test cases will execute inside `shared.git`, instead of
324 # inside `master.git`.
325 test_expect_success 'setup shared.git' '
326         git clone --mirror "$master_repo" "$shared_repo" &&
327         (
328                 cd "$shared_repo" &&
329                 printf "../../$master_repo/objects\n" >objects/info/alternates
330         )
331 '
332
333 test_expect_success 'shared: all packs are redundant, but no output without --alt-odb' '
334         (
335                 cd "$shared_repo" &&
336                 git pack-redundant --all >out &&
337                 test_must_be_empty out
338         )
339 '
340
341 #############################################################################
342 # Chart of packs and objects for this test case
343 #
344 #     ================ master.git ===============
345 #         | T A B C D E F G H I J K L M N O P Q R  <----------+
346 #     ----+--------------------------------------             |
347 #     P1  | x x x x x x x                       x             |
348 #     P3  |             x     x x x x x                       |
349 #     P5  |               x x           x x                   |
350 #     P7  |                                 x x               |
351 #     ----+--------------------------------------             |
352 #     ALL | x x x x x x x x x x x x x x x x x x x             |
353 #                                                             |
354 #                                                             |
355 #     ================ shared.git ===============             |
356 #         | T A B C D E F G H I J K L M N O P Q R  <objects/info/alternates>
357 #     ----+--------------------------------------
358 #     P1* | s s s s s s s                       s
359 #     P3* |             s     s s s s s
360 #     P5* |               s s           s s
361 #     P7* |                                 s s
362 #     ----+--------------------------------------
363 #     ALL | x x x x x x x x x x x x x x x x x x x
364 #
365 #############################################################################
366 test_expect_success 'shared: show redundant packs in stderr for verbose mode' '
367         (
368                 cd "$shared_repo" &&
369                 cat >expect <<-EOF &&
370                         P1:$P1
371                         P3:$P3
372                         P5:$P5
373                         P7:$P7
374                         EOF
375                 git pack-redundant --all --verbose >out 2>out.err &&
376                 test_must_be_empty out &&
377                 grep "pack$" out.err | format_packfiles >actual &&
378                 test_cmp expect actual
379         )
380 '
381
382 test_expect_success 'shared: remove redundant packs, no packs left' '
383         (
384                 cd "$shared_repo" &&
385                 cat >expect <<-EOF &&
386                         fatal: Zero packs found!
387                         EOF
388                 git pack-redundant --all --alt-odb | xargs rm &&
389                 git fsck &&
390                 test_must_fail git pack-redundant --all --alt-odb >actual 2>&1 &&
391                 test_cmp expect actual
392         )
393 '
394
395 test_expect_success 'shared: create new objects and packs' '
396         create_commits_in "$shared_repo" X Y Z &&
397         create_pack_in "$shared_repo" Px1 <<-EOF &&
398                 $X
399                 $Y
400                 $Z
401                 $A
402                 $B
403                 $C
404                 EOF
405         create_pack_in "$shared_repo" Px2 <<-EOF
406                 $X
407                 $Y
408                 $Z
409                 $D
410                 $E
411                 $F
412                 EOF
413 '
414
415 test_expect_success 'shared: no redundant without --alt-odb' '
416         (
417                 cd "$shared_repo" &&
418                 git pack-redundant --all >out &&
419                 test_must_be_empty out
420         )
421 '
422
423 #############################################################################
424 # Chart of packs and objects for this test case
425 #
426 #     ================ master.git ===============
427 #         | T A B C D E F G H I J K L M N O P Q R  <----------------+
428 #     ----+--------------------------------------                   |
429 #     P1  | x x x x x x x                       x                   |
430 #     P3  |             x     x x x x x                             |
431 #     P5  |               x x           x x                         |
432 #     P7  |                                 x x                     |
433 #     ----+--------------------------------------                   |
434 #     ALL | x x x x x x x x x x x x x x x x x x x                   |
435 #                                                                   |
436 #                                                                   |
437 #     ================ shared.git =======================           |
438 #         | 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>
439 #     ----+----------------------------------------------
440 #     Px1 |   s s s                                 x x x
441 #     Px2*|         s s s                           ! ! !
442 #     ----+----------------------------------------------
443 #     ALL | s s s s s s s s s s s s s s s s s s s   x x x
444 #
445 #############################################################################
446 test_expect_success 'shared: one pack is redundant with --alt-odb' '
447         (
448                 cd "$shared_repo" &&
449                 git pack-redundant --all --alt-odb >out &&
450                 format_packfiles <out >actual &&
451                 test_line_count = 1 actual
452         )
453 '
454
455 #############################################################################
456 # Chart of packs and objects for this test case
457 #
458 #     ================ master.git ===============
459 #         | T A B C D E F G H I J K L M N O P Q R  <----------------+
460 #     ----+--------------------------------------                   |
461 #     P1  | x x x x x x x                       x                   |
462 #     P3  |             x     x x x x x                             |
463 #     P5  |               x x           x x                         |
464 #     P7  |                                 x x                     |
465 #     ----+--------------------------------------                   |
466 #     ALL | x x x x x x x x x x x x x x x x x x x                   |
467 #                                                                   |
468 #                                                                   |
469 #     ================ shared.git =======================           |
470 #         | 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>
471 #     ----+----------------------------------------------
472 #     Px1*|   s s s                                 i i i
473 #     Px2*|         s s s                           i i i
474 #     ----+----------------------------------------------
475 #     ALL | s s s s s s s s s s s s s s s s s s s   i i i
476 #                                                  (ignored objects, marked with i)
477 #
478 #############################################################################
479 test_expect_success 'shared: ignore unique objects and all two packs are redundant' '
480         (
481                 cd "$shared_repo" &&
482                 cat >expect <<-EOF &&
483                         Px1:$Px1
484                         Px2:$Px2
485                         EOF
486                 git pack-redundant --all --alt-odb >out <<-EOF &&
487                         $X
488                         $Y
489                         $Z
490                         EOF
491                 format_packfiles <out >actual &&
492                 test_cmp expect actual
493         )
494 '
495
496 test_done