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