Merge branch 'rs/copy-array'
[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 #############################################################################
116 # Chart of packs and objects for this test case
117 #
118 #         | T A B C D E F G H I J K L M N O P Q R
119 #     ----+--------------------------------------
120 #     P1  | x x x x x x x                       x
121 #     P2  |     x x x x   x x x
122 #     P3  |             x     x x x x x
123 #     ----+--------------------------------------
124 #     ALL | x x x x x x x x x x x x x x         x
125 #
126 #############################################################################
127 test_expect_success 'master: no redundant for pack 1, 2, 3' '
128         create_pack_in "$master_repo" P1 <<-EOF &&
129                 $T
130                 $A
131                 $B
132                 $C
133                 $D
134                 $E
135                 $F
136                 $R
137                 EOF
138         create_pack_in "$master_repo" P2 <<-EOF &&
139                 $B
140                 $C
141                 $D
142                 $E
143                 $G
144                 $H
145                 $I
146                 EOF
147         create_pack_in "$master_repo" P3 <<-EOF &&
148                 $F
149                 $I
150                 $J
151                 $K
152                 $L
153                 $M
154                 EOF
155         (
156                 cd "$master_repo" &&
157                 git pack-redundant --all >out &&
158                 test_must_be_empty out
159         )
160 '
161
162 #############################################################################
163 # Chart of packs and objects for this test case
164 #
165 #         | T A B C D E F G H I J K L M N O P Q R
166 #     ----+--------------------------------------
167 #     P1  | x x x x x x x                       x
168 #     P2  |     x x x x   x x x
169 #     P3* |             !     ! ! ! ! !
170 #     P4  |                     x x x x     x
171 #     P5  |               x x           x x
172 #     ----+--------------------------------------
173 #     ALL | x x x x x x x x x x x x x x x x x   x
174 #
175 #############################################################################
176 test_expect_success 'master: one of pack-2/pack-3 is redundant' '
177         create_pack_in "$master_repo" P4 <<-EOF &&
178                 $J
179                 $K
180                 $L
181                 $M
182                 $P
183                 EOF
184         create_pack_in "$master_repo" P5 <<-EOF &&
185                 $G
186                 $H
187                 $N
188                 $O
189                 EOF
190         (
191                 cd "$master_repo" &&
192                 cat >expect <<-EOF &&
193                         P3:$P3
194                         EOF
195                 git pack-redundant --all >out &&
196                 format_packfiles <out >actual &&
197                 test_cmp expect actual
198         )
199 '
200
201 #############################################################################
202 # Chart of packs and objects for this test case
203 #
204 #         | T A B C D E F G H I J K L M N O P Q R
205 #     ----+--------------------------------------
206 #     P1  | x x x x x x x                       x
207 #     P2* |     ! ! ! !   ! ! !
208 #     P3  |             x     x x x x x
209 #     P4* |                     ! ! ! !     !
210 #     P5  |               x x           x x
211 #     P6* |                             ! !   !
212 #     P7  |                                 x x
213 #     ----+--------------------------------------
214 #     ALL | x x x x x x x x x x x x x x x x x x x
215 #
216 #############################################################################
217 test_expect_success 'master: pack 2, 4, and 6 are redundant' '
218         create_pack_in "$master_repo" P6 <<-EOF &&
219                 $N
220                 $O
221                 $Q
222                 EOF
223         create_pack_in "$master_repo" P7 <<-EOF &&
224                 $P
225                 $Q
226                 EOF
227         (
228                 cd "$master_repo" &&
229                 cat >expect <<-EOF &&
230                         P2:$P2
231                         P4:$P4
232                         P6:$P6
233                         EOF
234                 git pack-redundant --all >out &&
235                 format_packfiles <out >actual &&
236                 test_cmp expect actual
237         )
238 '
239
240 #############################################################################
241 # Chart of packs and objects for this test case
242 #
243 #         | T A B C D E F G H I J K L M N O P Q R
244 #     ----+--------------------------------------
245 #     P1  | x x x x x x x                       x
246 #     P2* |     ! ! ! !   ! ! !
247 #     P3  |             x     x x x x x
248 #     P4* |                     ! ! ! !     !
249 #     P5  |               x x           x x
250 #     P6* |                             ! !   !
251 #     P7  |                                 x x
252 #     P8* |   !
253 #     ----+--------------------------------------
254 #     ALL | x x x x x x x x x x x x x x x x x x x
255 #
256 #############################################################################
257 test_expect_success 'master: pack-8 (subset of pack-1) is also redundant' '
258         create_pack_in "$master_repo" P8 <<-EOF &&
259                 $A
260                 EOF
261         (
262                 cd "$master_repo" &&
263                 cat >expect <<-EOF &&
264                         P2:$P2
265                         P4:$P4
266                         P6:$P6
267                         P8:$P8
268                         EOF
269                 git pack-redundant --all >out &&
270                 format_packfiles <out >actual &&
271                 test_cmp expect actual
272         )
273 '
274
275 test_expect_success 'master: clean loose objects' '
276         (
277                 cd "$master_repo" &&
278                 git prune-packed &&
279                 find objects -type f | sed -e "/objects\/pack\//d" >out &&
280                 test_must_be_empty out
281         )
282 '
283
284 test_expect_success 'master: remove redundant packs and pass fsck' '
285         (
286                 cd "$master_repo" &&
287                 git pack-redundant --all | xargs rm &&
288                 git fsck &&
289                 git pack-redundant --all >out &&
290                 test_must_be_empty out
291         )
292 '
293
294 # The following test cases will execute inside `shared.git`, instead of
295 # inside `master.git`.
296 test_expect_success 'setup shared.git' '
297         git clone --mirror "$master_repo" "$shared_repo" &&
298         (
299                 cd "$shared_repo" &&
300                 printf "../../$master_repo/objects\n" >objects/info/alternates
301         )
302 '
303
304 test_expect_success 'shared: all packs are redundant, but no output without --alt-odb' '
305         (
306                 cd "$shared_repo" &&
307                 git pack-redundant --all >out &&
308                 test_must_be_empty out
309         )
310 '
311
312 #############################################################################
313 # Chart of packs and objects for this test case
314 #
315 #     ================ master.git ===============
316 #         | T A B C D E F G H I J K L M N O P Q R  <----------+
317 #     ----+--------------------------------------             |
318 #     P1  | x x x x x x x                       x             |
319 #     P3  |             x     x x x x x                       |
320 #     P5  |               x x           x x                   |
321 #     P7  |                                 x x               |
322 #     ----+--------------------------------------             |
323 #     ALL | x x x x x x x x x x x x x x x x x x x             |
324 #                                                             |
325 #                                                             |
326 #     ================ shared.git ===============             |
327 #         | T A B C D E F G H I J K L M N O P Q R  <objects/info/alternates>
328 #     ----+--------------------------------------
329 #     P1* | s s s s s s s                       s
330 #     P3* |             s     s s s s s
331 #     P5* |               s s           s s
332 #     P7* |                                 s s
333 #     ----+--------------------------------------
334 #     ALL | x x x x x x x x x x x x x x x x x x x
335 #
336 #############################################################################
337 test_expect_success 'shared: show redundant packs in stderr for verbose mode' '
338         (
339                 cd "$shared_repo" &&
340                 cat >expect <<-EOF &&
341                         P1:$P1
342                         P3:$P3
343                         P5:$P5
344                         P7:$P7
345                         EOF
346                 git pack-redundant --all --verbose >out 2>out.err &&
347                 test_must_be_empty out &&
348                 grep "pack$" out.err | format_packfiles >actual &&
349                 test_cmp expect actual
350         )
351 '
352
353 test_expect_success 'shared: remove redundant packs, no packs left' '
354         (
355                 cd "$shared_repo" &&
356                 cat >expect <<-EOF &&
357                         fatal: Zero packs found!
358                         EOF
359                 git pack-redundant --all --alt-odb | xargs rm &&
360                 git fsck &&
361                 test_must_fail git pack-redundant --all --alt-odb >actual 2>&1 &&
362                 test_cmp expect actual
363         )
364 '
365
366 test_expect_success 'shared: create new objects and packs' '
367         create_commits_in "$shared_repo" X Y Z &&
368         create_pack_in "$shared_repo" Px1 <<-EOF &&
369                 $X
370                 $Y
371                 $Z
372                 $A
373                 $B
374                 $C
375                 EOF
376         create_pack_in "$shared_repo" Px2 <<-EOF
377                 $X
378                 $Y
379                 $Z
380                 $D
381                 $E
382                 $F
383                 EOF
384 '
385
386 test_expect_success 'shared: no redundant without --alt-odb' '
387         (
388                 cd "$shared_repo" &&
389                 git pack-redundant --all >out &&
390                 test_must_be_empty out
391         )
392 '
393
394 #############################################################################
395 # Chart of packs and objects for this test case
396 #
397 #     ================ master.git ===============
398 #         | T A B C D E F G H I J K L M N O P Q R  <----------------+
399 #     ----+--------------------------------------                   |
400 #     P1  | x x x x x x x                       x                   |
401 #     P3  |             x     x x x x x                             |
402 #     P5  |               x x           x x                         |
403 #     P7  |                                 x x                     |
404 #     ----+--------------------------------------                   |
405 #     ALL | x x x x x x x x x x x x x x x x x x x                   |
406 #                                                                   |
407 #                                                                   |
408 #     ================ shared.git =======================           |
409 #         | 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>
410 #     ----+----------------------------------------------
411 #     Px1 |   s s s                                 x x x
412 #     Px2*|         s s s                           ! ! !
413 #     ----+----------------------------------------------
414 #     ALL | s s s s s s s s s s s s s s s s s s s   x x x
415 #
416 #############################################################################
417 test_expect_success 'shared: one pack is redundant with --alt-odb' '
418         (
419                 cd "$shared_repo" &&
420                 git pack-redundant --all --alt-odb >out &&
421                 format_packfiles <out >actual &&
422                 test_line_count = 1 actual
423         )
424 '
425
426 #############################################################################
427 # Chart of packs and objects for this test case
428 #
429 #     ================ master.git ===============
430 #         | T A B C D E F G H I J K L M N O P Q R  <----------------+
431 #     ----+--------------------------------------                   |
432 #     P1  | x x x x x x x                       x                   |
433 #     P3  |             x     x x x x x                             |
434 #     P5  |               x x           x x                         |
435 #     P7  |                                 x x                     |
436 #     ----+--------------------------------------                   |
437 #     ALL | x x x x x x x x x x x x x x x x x x x                   |
438 #                                                                   |
439 #                                                                   |
440 #     ================ shared.git =======================           |
441 #         | 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>
442 #     ----+----------------------------------------------
443 #     Px1*|   s s s                                 i i i
444 #     Px2*|         s s s                           i i i
445 #     ----+----------------------------------------------
446 #     ALL | s s s s s s s s s s s s s s s s s s s   i i i
447 #                                                  (ignored objects, marked with i)
448 #
449 #############################################################################
450 test_expect_success 'shared: ignore unique objects and all two packs are redundant' '
451         (
452                 cd "$shared_repo" &&
453                 cat >expect <<-EOF &&
454                         Px1:$Px1
455                         Px2:$Px2
456                         EOF
457                 git pack-redundant --all --alt-odb >out <<-EOF &&
458                         $X
459                         $Y
460                         $Z
461                         EOF
462                 format_packfiles <out >actual &&
463                 test_cmp expect actual
464         )
465 '
466
467 test_done