t0601: refactor tests to be shareable

In preparation for adding tests for the new `git refs optimize` command, refactor the existing t0601 test suite to make its logic shareable. Move the core test logic from `t0601-reffiles-pack-refs.sh` into a new `pack-refs-tests.sh` file. Inside this new script, replace hardcoded calls to "pack-refs" with the `$pack_refs` variable. The original `t0601-reffiles-pack-refs.sh` script now becomes a simple "driver". It is responsible for setting the default value of the variable and then sourcing the test library. This new structure follows the established pattern used for sharing tests between `git-for-each-ref` and `git-refs list` and prepares the test suite for the `refs optimize` tests to be added in a subsequent commit. Mentored-by: Patrick Steinhardt <ps@pks.im> Mentored-by: shejialuo <shejialuo@gmail.com> Signed-off-by: Meet Soni <meetsoni3017@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Meet Soni committed Sep 19, 2025 at 13:56 UTC ac0bad0af488aa25ffb2363f79b7e5728fd0cf97
2 files changed +432 -429
t/pack-refs-tests.sh new
+431
@@ -0,0 +1,431 @@
1 +pack_refs=${pack_refs:-pack-refs}
2 +
3 +test_expect_success 'enable reflogs' '
4 + git config core.logallrefupdates true
5 +'
6 +
7 +test_expect_success 'prepare a trivial repository' '
8 + echo Hello > A &&
9 + git update-index --add A &&
10 + git commit -m "Initial commit." &&
11 + HEAD=$(git rev-parse --verify HEAD)
12 +'
13 +
14 +test_expect_success '${pack_refs} --prune --all' '
15 + test_path_is_missing .git/packed-refs &&
16 + git ${pack_refs} --no-prune --all &&
17 + test_path_is_file .git/packed-refs &&
18 + N=$(find .git/refs -type f | wc -l) &&
19 + test "$N" != 0 &&
20 +
21 + git ${pack_refs} --prune --all &&
22 + test_path_is_file .git/packed-refs &&
23 + N=$(find .git/refs -type f) &&
24 + test -z "$N"
25 +'
26 +
27 +SHA1=
28 +
29 +test_expect_success 'see if git show-ref works as expected' '
30 + git branch a &&
31 + SHA1=$(cat .git/refs/heads/a) &&
32 + echo "$SHA1 refs/heads/a" >expect &&
33 + git show-ref a >result &&
34 + test_cmp expect result
35 +'
36 +
37 +test_expect_success 'see if a branch still exists when packed' '
38 + git branch b &&
39 + git ${pack_refs} --all &&
40 + rm -f .git/refs/heads/b &&
41 + echo "$SHA1 refs/heads/b" >expect &&
42 + git show-ref b >result &&
43 + test_cmp expect result
44 +'
45 +
46 +test_expect_success 'git branch c/d should barf if branch c exists' '
47 + git branch c &&
48 + git ${pack_refs} --all &&
49 + rm -f .git/refs/heads/c &&
50 + test_must_fail git branch c/d
51 +'
52 +
53 +test_expect_success 'see if a branch still exists after git ${pack_refs} --prune' '
54 + git branch e &&
55 + git ${pack_refs} --all --prune &&
56 + echo "$SHA1 refs/heads/e" >expect &&
57 + git show-ref e >result &&
58 + test_cmp expect result
59 +'
60 +
61 +test_expect_success 'see if git ${pack_refs} --prune remove ref files' '
62 + git branch f &&
63 + git ${pack_refs} --all --prune &&
64 + ! test -f .git/refs/heads/f
65 +'
66 +
67 +test_expect_success 'see if git ${pack_refs} --prune removes empty dirs' '
68 + git branch r/s/t &&
69 + git ${pack_refs} --all --prune &&
70 + ! test -e .git/refs/heads/r
71 +'
72 +
73 +test_expect_success 'git branch g should work when git branch g/h has been deleted' '
74 + git branch g/h &&
75 + git ${pack_refs} --all --prune &&
76 + git branch -d g/h &&
77 + git branch g &&
78 + git ${pack_refs} --all &&
79 + git branch -d g
80 +'
81 +
82 +test_expect_success 'git branch i/j/k should barf if branch i exists' '
83 + git branch i &&
84 + git ${pack_refs} --all --prune &&
85 + test_must_fail git branch i/j/k
86 +'
87 +
88 +test_expect_success 'test git branch k after branch k/l/m and k/lm have been deleted' '
89 + git branch k/l &&
90 + git branch k/lm &&
91 + git branch -d k/l &&
92 + git branch k/l/m &&
93 + git branch -d k/l/m &&
94 + git branch -d k/lm &&
95 + git branch k
96 +'
97 +
98 +test_expect_success 'test git branch n after some branch deletion and pruning' '
99 + git branch n/o &&
100 + git branch n/op &&
101 + git branch -d n/o &&
102 + git branch n/o/p &&
103 + git branch -d n/op &&
104 + git ${pack_refs} --all --prune &&
105 + git branch -d n/o/p &&
106 + git branch n
107 +'
108 +
109 +test_expect_success 'test excluded refs are not packed' '
110 + git branch dont_pack1 &&
111 + git branch dont_pack2 &&
112 + git branch pack_this &&
113 + git ${pack_refs} --all --exclude "refs/heads/dont_pack*" &&
114 + test -f .git/refs/heads/dont_pack1 &&
115 + test -f .git/refs/heads/dont_pack2 &&
116 + ! test -f .git/refs/heads/pack_this'
117 +
118 +test_expect_success 'test --no-exclude refs clears excluded refs' '
119 + git branch dont_pack3 &&
120 + git branch dont_pack4 &&
121 + git ${pack_refs} --all --exclude "refs/heads/dont_pack*" --no-exclude &&
122 + ! test -f .git/refs/heads/dont_pack3 &&
123 + ! test -f .git/refs/heads/dont_pack4'
124 +
125 +test_expect_success 'test only included refs are packed' '
126 + git branch pack_this1 &&
127 + git branch pack_this2 &&
128 + git tag dont_pack5 &&
129 + git ${pack_refs} --include "refs/heads/pack_this*" &&
130 + test -f .git/refs/tags/dont_pack5 &&
131 + ! test -f .git/refs/heads/pack_this1 &&
132 + ! test -f .git/refs/heads/pack_this2'
133 +
134 +test_expect_success 'test --no-include refs clears included refs' '
135 + git branch pack1 &&
136 + git branch pack2 &&
137 + git ${pack_refs} --include "refs/heads/pack*" --no-include &&
138 + test -f .git/refs/heads/pack1 &&
139 + test -f .git/refs/heads/pack2'
140 +
141 +test_expect_success 'test --exclude takes precedence over --include' '
142 + git branch dont_pack5 &&
143 + git ${pack_refs} --include "refs/heads/pack*" --exclude "refs/heads/pack*" &&
144 + test -f .git/refs/heads/dont_pack5'
145 +
146 +test_expect_success 'see if up-to-date packed refs are preserved' '
147 + git branch q &&
148 + git ${pack_refs} --all --prune &&
149 + git update-ref refs/heads/q refs/heads/q &&
150 + ! test -f .git/refs/heads/q
151 +'
152 +
153 +test_expect_success 'pack, prune and repack' '
154 + git tag foo &&
155 + git ${pack_refs} --all --prune &&
156 + git show-ref >all-of-them &&
157 + git ${pack_refs} &&
158 + git show-ref >again &&
159 + test_cmp all-of-them again
160 +'
161 +
162 +test_expect_success 'explicit ${pack_refs} with dangling packed reference' '
163 + git commit --allow-empty -m "soon to be garbage-collected" &&
164 + git ${pack_refs} --all &&
165 + git reset --hard HEAD^ &&
166 + git reflog expire --expire=all --all &&
167 + git prune --expire=all &&
168 + git ${pack_refs} --all 2>result &&
169 + test_must_be_empty result
170 +'
171 +
172 +test_expect_success 'delete ref with dangling packed version' '
173 + git checkout -b lamb &&
174 + git commit --allow-empty -m "future garbage" &&
175 + git ${pack_refs} --all &&
176 + git reset --hard HEAD^ &&
177 + git checkout main &&
178 + git reflog expire --expire=all --all &&
179 + git prune --expire=all &&
180 + git branch -d lamb 2>result &&
181 + test_must_be_empty result
182 +'
183 +
184 +test_expect_success 'delete ref while another dangling packed ref' '
185 + git branch lamb &&
186 + git commit --allow-empty -m "future garbage" &&
187 + git ${pack_refs} --all &&
188 + git reset --hard HEAD^ &&
189 + git reflog expire --expire=all --all &&
190 + git prune --expire=all &&
191 + git branch -d lamb 2>result &&
192 + test_must_be_empty result
193 +'
194 +
195 +test_expect_success 'pack ref directly below refs/' '
196 + git update-ref refs/top HEAD &&
197 + git ${pack_refs} --all --prune &&
198 + grep refs/top .git/packed-refs &&
199 + test_path_is_missing .git/refs/top
200 +'
201 +
202 +test_expect_success 'do not pack ref in refs/bisect' '
203 + git update-ref refs/bisect/local HEAD &&
204 + git ${pack_refs} --all --prune &&
205 + ! grep refs/bisect/local .git/packed-refs >/dev/null &&
206 + test_path_is_file .git/refs/bisect/local
207 +'
208 +
209 +test_expect_success 'disable reflogs' '
210 + git config core.logallrefupdates false &&
211 + rm -rf .git/logs
212 +'
213 +
214 +test_expect_success 'create packed foo/bar/baz branch' '
215 + git branch foo/bar/baz &&
216 + git ${pack_refs} --all --prune &&
217 + test_path_is_missing .git/refs/heads/foo/bar/baz &&
218 + test_must_fail git reflog exists refs/heads/foo/bar/baz
219 +'
220 +
221 +test_expect_success 'notice d/f conflict with existing directory' '
222 + test_must_fail git branch foo &&
223 + test_must_fail git branch foo/bar
224 +'
225 +
226 +test_expect_success 'existing directory reports concrete ref' '
227 + test_must_fail git branch foo 2>stderr &&
228 + test_grep refs/heads/foo/bar/baz stderr
229 +'
230 +
231 +test_expect_success 'notice d/f conflict with existing ref' '
232 + test_must_fail git branch foo/bar/baz/extra &&
233 + test_must_fail git branch foo/bar/baz/lots/of/extra/components
234 +'
235 +
236 +test_expect_success 'reject packed-refs with unterminated line' '
237 + cp .git/packed-refs .git/packed-refs.bak &&
238 + test_when_finished "mv .git/packed-refs.bak .git/packed-refs" &&
239 + printf "%s" "$HEAD refs/zzzzz" >>.git/packed-refs &&
240 + echo "fatal: unterminated line in .git/packed-refs: $HEAD refs/zzzzz" >expected_err &&
241 + test_must_fail git for-each-ref >out 2>err &&
242 + test_cmp expected_err err
243 +'
244 +
245 +test_expect_success 'reject packed-refs containing junk' '
246 + cp .git/packed-refs .git/packed-refs.bak &&
247 + test_when_finished "mv .git/packed-refs.bak .git/packed-refs" &&
248 + printf "%s\n" "bogus content" >>.git/packed-refs &&
249 + echo "fatal: unexpected line in .git/packed-refs: bogus content" >expected_err &&
250 + test_must_fail git for-each-ref >out 2>err &&
251 + test_cmp expected_err err
252 +'
253 +
254 +test_expect_success 'reject packed-refs with a short SHA-1' '
255 + cp .git/packed-refs .git/packed-refs.bak &&
256 + test_when_finished "mv .git/packed-refs.bak .git/packed-refs" &&
257 + printf "%.7s %s\n" $HEAD refs/zzzzz >>.git/packed-refs &&
258 + printf "fatal: unexpected line in .git/packed-refs: %.7s %s\n" $HEAD refs/zzzzz >expected_err &&
259 + test_must_fail git for-each-ref >out 2>err &&
260 + test_cmp expected_err err
261 +'
262 +
263 +test_expect_success 'timeout if packed-refs.lock exists' '
264 + LOCK=.git/packed-refs.lock &&
265 + >"$LOCK" &&
266 + test_when_finished "rm -f $LOCK" &&
267 + test_must_fail git ${pack_refs} --all --prune
268 +'
269 +
270 +test_expect_success 'retry acquiring packed-refs.lock' '
271 + LOCK=.git/packed-refs.lock &&
272 + >"$LOCK" &&
273 + test_when_finished "wait && rm -f $LOCK" &&
274 + {
275 + ( sleep 1 && rm -f $LOCK ) &
276 + } &&
277 + git -c core.packedrefstimeout=3000 ${pack_refs} --all --prune
278 +'
279 +
280 +test_expect_success SYMLINKS 'pack symlinked packed-refs' '
281 + # First make sure that symlinking works when reading:
282 + git update-ref refs/heads/lossy refs/heads/main &&
283 + git for-each-ref >all-refs-before &&
284 + mv .git/packed-refs .git/my-deviant-packed-refs &&
285 + ln -s my-deviant-packed-refs .git/packed-refs &&
286 + git for-each-ref >all-refs-linked &&
287 + test_cmp all-refs-before all-refs-linked &&
288 + git ${pack_refs} --all --prune &&
289 + git for-each-ref >all-refs-packed &&
290 + test_cmp all-refs-before all-refs-packed &&
291 + test -h .git/packed-refs &&
292 + test "$(test_readlink .git/packed-refs)" = "my-deviant-packed-refs"
293 +'
294 +
295 +# The 'packed-refs' file is stored directly in .git/. This means it is global
296 +# to the repository, and can only contain refs that are shared across all
297 +# worktrees.
298 +test_expect_success 'refs/worktree must not be packed' '
299 + test_commit initial &&
300 + test_commit wt1 &&
301 + test_commit wt2 &&
302 + git worktree add wt1 wt1 &&
303 + git worktree add wt2 wt2 &&
304 + git checkout initial &&
305 + git update-ref refs/worktree/foo HEAD &&
306 + git -C wt1 update-ref refs/worktree/foo HEAD &&
307 + git -C wt2 update-ref refs/worktree/foo HEAD &&
308 + git ${pack_refs} --all &&
309 + test_path_is_missing .git/refs/tags/wt1 &&
310 + test_path_is_file .git/refs/worktree/foo &&
311 + test_path_is_file .git/worktrees/wt1/refs/worktree/foo &&
312 + test_path_is_file .git/worktrees/wt2/refs/worktree/foo
313 +'
314 +
315 +# we do not want to count on running ${pack_refs} to
316 +# actually pack it, as it is perfectly reasonable to
317 +# skip processing a broken ref
318 +test_expect_success 'create packed-refs file with broken ref' '
319 + test_tick && git commit --allow-empty -m one &&
320 + recoverable=$(git rev-parse HEAD) &&
321 + test_tick && git commit --allow-empty -m two &&
322 + missing=$(git rev-parse HEAD) &&
323 + rm -f .git/refs/heads/main &&
324 + cat >.git/packed-refs <<-EOF &&
325 + $missing refs/heads/main
326 + $recoverable refs/heads/other
327 + EOF
328 + echo $missing >expect &&
329 + git rev-parse refs/heads/main >actual &&
330 + test_cmp expect actual
331 +'
332 +
333 +test_expect_success '${pack_refs} does not silently delete broken packed ref' '
334 + git ${pack_refs} --all --prune &&
335 + git rev-parse refs/heads/main >actual &&
336 + test_cmp expect actual
337 +'
338 +
339 +test_expect_success '${pack_refs} does not drop broken refs during deletion' '
340 + git update-ref -d refs/heads/other &&
341 + git rev-parse refs/heads/main >actual &&
342 + test_cmp expect actual
343 +'
344 +
345 +for command in "git ${pack_refs} --all --auto" "git maintenance run --task=${pack_refs} --auto"
346 +do
347 + test_expect_success "$command does not repack below 16 refs without packed-refs" '
348 + test_when_finished "rm -rf repo" &&
349 + git init repo &&
350 + (
351 + cd repo &&
352 + git config set maintenance.auto false &&
353 + git commit --allow-empty --message "initial" &&
354 +
355 + # Create 14 additional references, which brings us to
356 + # 15 together with the default branch.
357 + printf "create refs/heads/loose-%d HEAD\n" $(test_seq 14) >stdin &&
358 + git update-ref --stdin <stdin &&
359 + test_path_is_missing .git/packed-refs &&
360 + git ${pack_refs} --auto --all &&
361 + test_path_is_missing .git/packed-refs &&
362 +
363 + # Create the 16th reference, which should cause us to repack.
364 + git update-ref refs/heads/loose-15 HEAD &&
365 + git ${pack_refs} --auto --all &&
366 + test_path_is_file .git/packed-refs
367 + )
368 + '
369 +
370 + test_expect_success "$command does not repack below 16 refs with small packed-refs" '
371 + test_when_finished "rm -rf repo" &&
372 + git init repo &&
373 + (
374 + cd repo &&
375 + git config set maintenance.auto false &&
376 + git commit --allow-empty --message "initial" &&
377 +
378 + git ${pack_refs} --all &&
379 + test_line_count = 2 .git/packed-refs &&
380 +
381 + # Create 15 loose references.
382 + printf "create refs/heads/loose-%d HEAD\n" $(test_seq 15) >stdin &&
383 + git update-ref --stdin <stdin &&
384 + git ${pack_refs} --auto --all &&
385 + test_line_count = 2 .git/packed-refs &&
386 +
387 + # Create the 16th loose reference, which should cause us to repack.
388 + git update-ref refs/heads/loose-17 HEAD &&
389 + git ${pack_refs} --auto --all &&
390 + test_line_count = 18 .git/packed-refs
391 + )
392 + '
393 +
394 + test_expect_success "$command scales with size of packed-refs" '
395 + test_when_finished "rm -rf repo" &&
396 + git init repo &&
397 + (
398 + cd repo &&
399 + git config set maintenance.auto false &&
400 + git commit --allow-empty --message "initial" &&
401 +
402 + # Create 99 packed refs. This should cause the heuristic
403 + # to require more than the minimum amount of loose refs.
404 + test_seq 99 |
405 + while read i
406 + do
407 + printf "create refs/heads/packed-%d HEAD\n" $i || return 1
408 + done >stdin &&
409 + git update-ref --stdin <stdin &&
410 + git ${pack_refs} --all &&
411 + test_line_count = 101 .git/packed-refs &&
412 +
413 + # Create 24 loose refs, which should not yet cause us to repack.
414 + printf "create refs/heads/loose-%d HEAD\n" $(test_seq 24) >stdin &&
415 + git update-ref --stdin <stdin &&
416 + git ${pack_refs} --auto --all &&
417 + test_line_count = 101 .git/packed-refs &&
418 +
419 + # Create another handful of refs to cross the border.
420 + # Note that we explicitly do not check for strict
421 + # boundaries here, as this also depends on the size of
422 + # the object hash.
423 + printf "create refs/heads/addn-%d HEAD\n" $(test_seq 10) >stdin &&
424 + git update-ref --stdin <stdin &&
425 + git ${pack_refs} --auto --all &&
426 + test_line_count = 135 .git/packed-refs
427 + )
428 + '
429 +done
430 +
431 +test_done
t/t0601-reffiles-pack-refs.sh
+1 -429
@@ -17,432 +17,4 @@ export GIT_TEST_DEFAULT_REF_FORMAT
17
18 . ./test-lib.sh
19
20 -test_expect_success 'enable reflogs' '
21 - git config core.logallrefupdates true
22 -'
23 -
24 -test_expect_success 'prepare a trivial repository' '
25 - echo Hello > A &&
26 - git update-index --add A &&
27 - git commit -m "Initial commit." &&
28 - HEAD=$(git rev-parse --verify HEAD)
29 -'
30 -
31 -test_expect_success 'pack-refs --prune --all' '
32 - test_path_is_missing .git/packed-refs &&
33 - git pack-refs --no-prune --all &&
34 - test_path_is_file .git/packed-refs &&
35 - N=$(find .git/refs -type f | wc -l) &&
36 - test "$N" != 0 &&
37 -
38 - git pack-refs --prune --all &&
39 - test_path_is_file .git/packed-refs &&
40 - N=$(find .git/refs -type f) &&
41 - test -z "$N"
42 -'
43 -
44 -SHA1=
45 -
46 -test_expect_success 'see if git show-ref works as expected' '
47 - git branch a &&
48 - SHA1=$(cat .git/refs/heads/a) &&
49 - echo "$SHA1 refs/heads/a" >expect &&
50 - git show-ref a >result &&
51 - test_cmp expect result
52 -'
53 -
54 -test_expect_success 'see if a branch still exists when packed' '
55 - git branch b &&
56 - git pack-refs --all &&
57 - rm -f .git/refs/heads/b &&
58 - echo "$SHA1 refs/heads/b" >expect &&
59 - git show-ref b >result &&
60 - test_cmp expect result
61 -'
62 -
63 -test_expect_success 'git branch c/d should barf if branch c exists' '
64 - git branch c &&
65 - git pack-refs --all &&
66 - rm -f .git/refs/heads/c &&
67 - test_must_fail git branch c/d
68 -'
69 -
70 -test_expect_success 'see if a branch still exists after git pack-refs --prune' '
71 - git branch e &&
72 - git pack-refs --all --prune &&
73 - echo "$SHA1 refs/heads/e" >expect &&
74 - git show-ref e >result &&
75 - test_cmp expect result
76 -'
77 -
78 -test_expect_success 'see if git pack-refs --prune remove ref files' '
79 - git branch f &&
80 - git pack-refs --all --prune &&
81 - ! test -f .git/refs/heads/f
82 -'
83 -
84 -test_expect_success 'see if git pack-refs --prune removes empty dirs' '
85 - git branch r/s/t &&
86 - git pack-refs --all --prune &&
87 - ! test -e .git/refs/heads/r
88 -'
89 -
90 -test_expect_success 'git branch g should work when git branch g/h has been deleted' '
91 - git branch g/h &&
92 - git pack-refs --all --prune &&
93 - git branch -d g/h &&
94 - git branch g &&
95 - git pack-refs --all &&
96 - git branch -d g
97 -'
98 -
99 -test_expect_success 'git branch i/j/k should barf if branch i exists' '
100 - git branch i &&
101 - git pack-refs --all --prune &&
102 - test_must_fail git branch i/j/k
103 -'
104 -
105 -test_expect_success 'test git branch k after branch k/l/m and k/lm have been deleted' '
106 - git branch k/l &&
107 - git branch k/lm &&
108 - git branch -d k/l &&
109 - git branch k/l/m &&
110 - git branch -d k/l/m &&
111 - git branch -d k/lm &&
112 - git branch k
113 -'
114 -
115 -test_expect_success 'test git branch n after some branch deletion and pruning' '
116 - git branch n/o &&
117 - git branch n/op &&
118 - git branch -d n/o &&
119 - git branch n/o/p &&
120 - git branch -d n/op &&
121 - git pack-refs --all --prune &&
122 - git branch -d n/o/p &&
123 - git branch n
124 -'
125 -
126 -test_expect_success 'test excluded refs are not packed' '
127 - git branch dont_pack1 &&
128 - git branch dont_pack2 &&
129 - git branch pack_this &&
130 - git pack-refs --all --exclude "refs/heads/dont_pack*" &&
131 - test -f .git/refs/heads/dont_pack1 &&
132 - test -f .git/refs/heads/dont_pack2 &&
133 - ! test -f .git/refs/heads/pack_this'
134 -
135 -test_expect_success 'test --no-exclude refs clears excluded refs' '
136 - git branch dont_pack3 &&
137 - git branch dont_pack4 &&
138 - git pack-refs --all --exclude "refs/heads/dont_pack*" --no-exclude &&
139 - ! test -f .git/refs/heads/dont_pack3 &&
140 - ! test -f .git/refs/heads/dont_pack4'
141 -
142 -test_expect_success 'test only included refs are packed' '
143 - git branch pack_this1 &&
144 - git branch pack_this2 &&
145 - git tag dont_pack5 &&
146 - git pack-refs --include "refs/heads/pack_this*" &&
147 - test -f .git/refs/tags/dont_pack5 &&
148 - ! test -f .git/refs/heads/pack_this1 &&
149 - ! test -f .git/refs/heads/pack_this2'
150 -
151 -test_expect_success 'test --no-include refs clears included refs' '
152 - git branch pack1 &&
153 - git branch pack2 &&
154 - git pack-refs --include "refs/heads/pack*" --no-include &&
155 - test -f .git/refs/heads/pack1 &&
156 - test -f .git/refs/heads/pack2'
157 -
158 -test_expect_success 'test --exclude takes precedence over --include' '
159 - git branch dont_pack5 &&
160 - git pack-refs --include "refs/heads/pack*" --exclude "refs/heads/pack*" &&
161 - test -f .git/refs/heads/dont_pack5'
162 -
163 -test_expect_success 'see if up-to-date packed refs are preserved' '
164 - git branch q &&
165 - git pack-refs --all --prune &&
166 - git update-ref refs/heads/q refs/heads/q &&
167 - ! test -f .git/refs/heads/q
168 -'
169 -
170 -test_expect_success 'pack, prune and repack' '
171 - git tag foo &&
172 - git pack-refs --all --prune &&
173 - git show-ref >all-of-them &&
174 - git pack-refs &&
175 - git show-ref >again &&
176 - test_cmp all-of-them again
177 -'
178 -
179 -test_expect_success 'explicit pack-refs with dangling packed reference' '
180 - git commit --allow-empty -m "soon to be garbage-collected" &&
181 - git pack-refs --all &&
182 - git reset --hard HEAD^ &&
183 - git reflog expire --expire=all --all &&
184 - git prune --expire=all &&
185 - git pack-refs --all 2>result &&
186 - test_must_be_empty result
187 -'
188 -
189 -test_expect_success 'delete ref with dangling packed version' '
190 - git checkout -b lamb &&
191 - git commit --allow-empty -m "future garbage" &&
192 - git pack-refs --all &&
193 - git reset --hard HEAD^ &&
194 - git checkout main &&
195 - git reflog expire --expire=all --all &&
196 - git prune --expire=all &&
197 - git branch -d lamb 2>result &&
198 - test_must_be_empty result
199 -'
200 -
201 -test_expect_success 'delete ref while another dangling packed ref' '
202 - git branch lamb &&
203 - git commit --allow-empty -m "future garbage" &&
204 - git pack-refs --all &&
205 - git reset --hard HEAD^ &&
206 - git reflog expire --expire=all --all &&
207 - git prune --expire=all &&
208 - git branch -d lamb 2>result &&
209 - test_must_be_empty result
210 -'
211 -
212 -test_expect_success 'pack ref directly below refs/' '
213 - git update-ref refs/top HEAD &&
214 - git pack-refs --all --prune &&
215 - grep refs/top .git/packed-refs &&
216 - test_path_is_missing .git/refs/top
217 -'
218 -
219 -test_expect_success 'do not pack ref in refs/bisect' '
220 - git update-ref refs/bisect/local HEAD &&
221 - git pack-refs --all --prune &&
222 - ! grep refs/bisect/local .git/packed-refs >/dev/null &&
223 - test_path_is_file .git/refs/bisect/local
224 -'
225 -
226 -test_expect_success 'disable reflogs' '
227 - git config core.logallrefupdates false &&
228 - rm -rf .git/logs
229 -'
230 -
231 -test_expect_success 'create packed foo/bar/baz branch' '
232 - git branch foo/bar/baz &&
233 - git pack-refs --all --prune &&
234 - test_path_is_missing .git/refs/heads/foo/bar/baz &&
235 - test_must_fail git reflog exists refs/heads/foo/bar/baz
236 -'
237 -
238 -test_expect_success 'notice d/f conflict with existing directory' '
239 - test_must_fail git branch foo &&
240 - test_must_fail git branch foo/bar
241 -'
242 -
243 -test_expect_success 'existing directory reports concrete ref' '
244 - test_must_fail git branch foo 2>stderr &&
245 - test_grep refs/heads/foo/bar/baz stderr
246 -'
247 -
248 -test_expect_success 'notice d/f conflict with existing ref' '
249 - test_must_fail git branch foo/bar/baz/extra &&
250 - test_must_fail git branch foo/bar/baz/lots/of/extra/components
251 -'
252 -
253 -test_expect_success 'reject packed-refs with unterminated line' '
254 - cp .git/packed-refs .git/packed-refs.bak &&
255 - test_when_finished "mv .git/packed-refs.bak .git/packed-refs" &&
256 - printf "%s" "$HEAD refs/zzzzz" >>.git/packed-refs &&
257 - echo "fatal: unterminated line in .git/packed-refs: $HEAD refs/zzzzz" >expected_err &&
258 - test_must_fail git for-each-ref >out 2>err &&
259 - test_cmp expected_err err
260 -'
261 -
262 -test_expect_success 'reject packed-refs containing junk' '
263 - cp .git/packed-refs .git/packed-refs.bak &&
264 - test_when_finished "mv .git/packed-refs.bak .git/packed-refs" &&
265 - printf "%s\n" "bogus content" >>.git/packed-refs &&
266 - echo "fatal: unexpected line in .git/packed-refs: bogus content" >expected_err &&
267 - test_must_fail git for-each-ref >out 2>err &&
268 - test_cmp expected_err err
269 -'
270 -
271 -test_expect_success 'reject packed-refs with a short SHA-1' '
272 - cp .git/packed-refs .git/packed-refs.bak &&
273 - test_when_finished "mv .git/packed-refs.bak .git/packed-refs" &&
274 - printf "%.7s %s\n" $HEAD refs/zzzzz >>.git/packed-refs &&
275 - printf "fatal: unexpected line in .git/packed-refs: %.7s %s\n" $HEAD refs/zzzzz >expected_err &&
276 - test_must_fail git for-each-ref >out 2>err &&
277 - test_cmp expected_err err
278 -'
279 -
280 -test_expect_success 'timeout if packed-refs.lock exists' '
281 - LOCK=.git/packed-refs.lock &&
282 - >"$LOCK" &&
283 - test_when_finished "rm -f $LOCK" &&
284 - test_must_fail git pack-refs --all --prune
285 -'
286 -
287 -test_expect_success 'retry acquiring packed-refs.lock' '
288 - LOCK=.git/packed-refs.lock &&
289 - >"$LOCK" &&
290 - test_when_finished "wait && rm -f $LOCK" &&
291 - {
292 - ( sleep 1 && rm -f $LOCK ) &
293 - } &&
294 - git -c core.packedrefstimeout=3000 pack-refs --all --prune
295 -'
296 -
297 -test_expect_success SYMLINKS 'pack symlinked packed-refs' '
298 - # First make sure that symlinking works when reading:
299 - git update-ref refs/heads/lossy refs/heads/main &&
300 - git for-each-ref >all-refs-before &&
301 - mv .git/packed-refs .git/my-deviant-packed-refs &&
302 - ln -s my-deviant-packed-refs .git/packed-refs &&
303 - git for-each-ref >all-refs-linked &&
304 - test_cmp all-refs-before all-refs-linked &&
305 - git pack-refs --all --prune &&
306 - git for-each-ref >all-refs-packed &&
307 - test_cmp all-refs-before all-refs-packed &&
308 - test -h .git/packed-refs &&
309 - test "$(test_readlink .git/packed-refs)" = "my-deviant-packed-refs"
310 -'
311 -
312 -# The 'packed-refs' file is stored directly in .git/. This means it is global
313 -# to the repository, and can only contain refs that are shared across all
314 -# worktrees.
315 -test_expect_success 'refs/worktree must not be packed' '
316 - test_commit initial &&
317 - test_commit wt1 &&
318 - test_commit wt2 &&
319 - git worktree add wt1 wt1 &&
320 - git worktree add wt2 wt2 &&
321 - git checkout initial &&
322 - git update-ref refs/worktree/foo HEAD &&
323 - git -C wt1 update-ref refs/worktree/foo HEAD &&
324 - git -C wt2 update-ref refs/worktree/foo HEAD &&
325 - git pack-refs --all &&
326 - test_path_is_missing .git/refs/tags/wt1 &&
327 - test_path_is_file .git/refs/worktree/foo &&
328 - test_path_is_file .git/worktrees/wt1/refs/worktree/foo &&
329 - test_path_is_file .git/worktrees/wt2/refs/worktree/foo
330 -'
331 -
332 -# we do not want to count on running pack-refs to
333 -# actually pack it, as it is perfectly reasonable to
334 -# skip processing a broken ref
335 -test_expect_success 'create packed-refs file with broken ref' '
336 - test_tick && git commit --allow-empty -m one &&
337 - recoverable=$(git rev-parse HEAD) &&
338 - test_tick && git commit --allow-empty -m two &&
339 - missing=$(git rev-parse HEAD) &&
340 - rm -f .git/refs/heads/main &&
341 - cat >.git/packed-refs <<-EOF &&
342 - $missing refs/heads/main
343 - $recoverable refs/heads/other
344 - EOF
345 - echo $missing >expect &&
346 - git rev-parse refs/heads/main >actual &&
347 - test_cmp expect actual
348 -'
349 -
350 -test_expect_success 'pack-refs does not silently delete broken packed ref' '
351 - git pack-refs --all --prune &&
352 - git rev-parse refs/heads/main >actual &&
353 - test_cmp expect actual
354 -'
355 -
356 -test_expect_success 'pack-refs does not drop broken refs during deletion' '
357 - git update-ref -d refs/heads/other &&
358 - git rev-parse refs/heads/main >actual &&
359 - test_cmp expect actual
360 -'
361 -
362 -for command in "git pack-refs --all --auto" "git maintenance run --task=pack-refs --auto"
363 -do
364 - test_expect_success "$command does not repack below 16 refs without packed-refs" '
365 - test_when_finished "rm -rf repo" &&
366 - git init repo &&
367 - (
368 - cd repo &&
369 - git config set maintenance.auto false &&
370 - git commit --allow-empty --message "initial" &&
371 -
372 - # Create 14 additional references, which brings us to
373 - # 15 together with the default branch.
374 - printf "create refs/heads/loose-%d HEAD\n" $(test_seq 14) >stdin &&
375 - git update-ref --stdin <stdin &&
376 - test_path_is_missing .git/packed-refs &&
377 - git pack-refs --auto --all &&
378 - test_path_is_missing .git/packed-refs &&
379 -
380 - # Create the 16th reference, which should cause us to repack.
381 - git update-ref refs/heads/loose-15 HEAD &&
382 - git pack-refs --auto --all &&
383 - test_path_is_file .git/packed-refs
384 - )
385 - '
386 -
387 - test_expect_success "$command does not repack below 16 refs with small packed-refs" '
388 - test_when_finished "rm -rf repo" &&
389 - git init repo &&
390 - (
391 - cd repo &&
392 - git config set maintenance.auto false &&
393 - git commit --allow-empty --message "initial" &&
394 -
395 - git pack-refs --all &&
396 - test_line_count = 2 .git/packed-refs &&
397 -
398 - # Create 15 loose references.
399 - printf "create refs/heads/loose-%d HEAD\n" $(test_seq 15) >stdin &&
400 - git update-ref --stdin <stdin &&
401 - git pack-refs --auto --all &&
402 - test_line_count = 2 .git/packed-refs &&
403 -
404 - # Create the 16th loose reference, which should cause us to repack.
405 - git update-ref refs/heads/loose-17 HEAD &&
406 - git pack-refs --auto --all &&
407 - test_line_count = 18 .git/packed-refs
408 - )
409 - '
410 -
411 - test_expect_success "$command scales with size of packed-refs" '
412 - test_when_finished "rm -rf repo" &&
413 - git init repo &&
414 - (
415 - cd repo &&
416 - git config set maintenance.auto false &&
417 - git commit --allow-empty --message "initial" &&
418 -
419 - # Create 99 packed refs. This should cause the heuristic
420 - # to require more than the minimum amount of loose refs.
421 - test_seq 99 |
422 - while read i
423 - do
424 - printf "create refs/heads/packed-%d HEAD\n" $i || return 1
425 - done >stdin &&
426 - git update-ref --stdin <stdin &&
427 - git pack-refs --all &&
428 - test_line_count = 101 .git/packed-refs &&
429 -
430 - # Create 24 loose refs, which should not yet cause us to repack.
431 - printf "create refs/heads/loose-%d HEAD\n" $(test_seq 24) >stdin &&
432 - git update-ref --stdin <stdin &&
433 - git pack-refs --auto --all &&
434 - test_line_count = 101 .git/packed-refs &&
435 -
436 - # Create another handful of refs to cross the border.
437 - # Note that we explicitly do not check for strict
438 - # boundaries here, as this also depends on the size of
439 - # the object hash.
440 - printf "create refs/heads/addn-%d HEAD\n" $(test_seq 10) >stdin &&
441 - git update-ref --stdin <stdin &&
442 - git pack-refs --auto --all &&
443 - test_line_count = 135 .git/packed-refs
444 - )
445 - '
446 -done
447 -
448 -test_done
20 +. "$TEST_DIRECTORY"/pack-refs-tests.sh