]>
Commit | Line | Data |
---|---|---|
57db2a09 PS |
1 | #!/bin/sh |
2 | # | |
3 | # Copyright (c) 2020 Google LLC | |
4 | # | |
5 | ||
6 | test_description='reftable basics' | |
7 | GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main | |
8 | export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME | |
9 | ||
10 | . ./test-lib.sh | |
11 | ||
12 | if ! test_have_prereq REFTABLE | |
13 | then | |
14 | skip_all='skipping reftable tests; set GIT_TEST_DEFAULT_REF_FORMAT=reftable' | |
15 | test_done | |
16 | fi | |
17 | ||
18 | INVALID_OID=$(test_oid 001) | |
19 | ||
20 | test_expect_success 'init: creates basic reftable structures' ' | |
21 | test_when_finished "rm -rf repo" && | |
22 | git init repo && | |
23 | test_path_is_dir repo/.git/reftable && | |
24 | test_path_is_file repo/.git/reftable/tables.list && | |
25 | echo reftable >expect && | |
26 | git -C repo rev-parse --show-ref-format >actual && | |
27 | test_cmp expect actual | |
28 | ' | |
29 | ||
30 | test_expect_success 'init: sha256 object format via environment variable' ' | |
31 | test_when_finished "rm -rf repo" && | |
32 | GIT_DEFAULT_HASH=sha256 git init repo && | |
33 | cat >expect <<-EOF && | |
34 | sha256 | |
35 | reftable | |
36 | EOF | |
37 | git -C repo rev-parse --show-object-format --show-ref-format >actual && | |
38 | test_cmp expect actual | |
39 | ' | |
40 | ||
41 | test_expect_success 'init: sha256 object format via option' ' | |
42 | test_when_finished "rm -rf repo" && | |
43 | git init --object-format=sha256 repo && | |
44 | cat >expect <<-EOF && | |
45 | sha256 | |
46 | reftable | |
47 | EOF | |
48 | git -C repo rev-parse --show-object-format --show-ref-format >actual && | |
49 | test_cmp expect actual | |
50 | ' | |
51 | ||
52 | test_expect_success 'init: reinitializing reftable backend succeeds' ' | |
53 | test_when_finished "rm -rf repo" && | |
54 | git init repo && | |
55 | test_commit -C repo A && | |
56 | ||
57 | git -C repo for-each-ref >expect && | |
58 | git init --ref-format=reftable repo && | |
59 | git -C repo for-each-ref >actual && | |
60 | test_cmp expect actual | |
61 | ' | |
62 | ||
63 | test_expect_success 'init: reinitializing files with reftable backend fails' ' | |
64 | test_when_finished "rm -rf repo" && | |
65 | git init --ref-format=files repo && | |
66 | test_commit -C repo file && | |
67 | ||
68 | cp repo/.git/HEAD expect && | |
69 | test_must_fail git init --ref-format=reftable repo && | |
70 | test_cmp expect repo/.git/HEAD | |
71 | ' | |
72 | ||
73 | test_expect_success 'init: reinitializing reftable with files backend fails' ' | |
74 | test_when_finished "rm -rf repo" && | |
75 | git init --ref-format=reftable repo && | |
76 | test_commit -C repo file && | |
77 | ||
78 | cp repo/.git/HEAD expect && | |
79 | test_must_fail git init --ref-format=files repo && | |
80 | test_cmp expect repo/.git/HEAD | |
81 | ' | |
82 | ||
83 | test_expect_perms () { | |
84 | local perms="$1" | |
85 | local file="$2" | |
26ba7477 | 86 | local actual="$(ls -l "$file")" && |
57db2a09 PS |
87 | |
88 | case "$actual" in | |
89 | $perms*) | |
90 | : happy | |
91 | ;; | |
92 | *) | |
93 | echo "$(basename $2) is not $perms but $actual" | |
94 | false | |
95 | ;; | |
96 | esac | |
97 | } | |
98 | ||
2f960dd5 PS |
99 | test_expect_reftable_perms () { |
100 | local umask="$1" | |
101 | local shared="$2" | |
102 | local expect="$3" | |
103 | ||
104 | test_expect_success POSIXPERM "init: honors --shared=$shared with umask $umask" ' | |
57db2a09 PS |
105 | test_when_finished "rm -rf repo" && |
106 | ( | |
107 | umask $umask && | |
69d87802 | 108 | git init --shared=$shared repo |
57db2a09 | 109 | ) && |
2f960dd5 | 110 | test_expect_perms "$expect" repo/.git/reftable/tables.list && |
57db2a09 PS |
111 | for table in repo/.git/reftable/*.ref |
112 | do | |
2f960dd5 | 113 | test_expect_perms "$expect" "$table" || |
57db2a09 PS |
114 | return 1 |
115 | done | |
116 | ' | |
2f960dd5 PS |
117 | |
118 | test_expect_success POSIXPERM "pack-refs: honors --shared=$shared with umask $umask" ' | |
119 | test_when_finished "rm -rf repo" && | |
120 | ( | |
121 | umask $umask && | |
122 | git init --shared=$shared repo && | |
123 | test_commit -C repo A && | |
82a31ec3 | 124 | test_line_count = 2 repo/.git/reftable/tables.list && |
69d87802 | 125 | git -C repo pack-refs |
2f960dd5 | 126 | ) && |
2f960dd5 PS |
127 | test_expect_perms "$expect" repo/.git/reftable/tables.list && |
128 | for table in repo/.git/reftable/*.ref | |
129 | do | |
130 | test_expect_perms "$expect" "$table" || | |
131 | return 1 | |
132 | done | |
133 | ' | |
134 | } | |
135 | ||
69d87802 PS |
136 | test_expect_reftable_perms 002 umask "-rw-rw-r--" |
137 | test_expect_reftable_perms 022 umask "-rw-r--r--" | |
138 | test_expect_reftable_perms 027 umask "-rw-r-----" | |
139 | ||
140 | test_expect_reftable_perms 002 group "-rw-rw-r--" | |
141 | test_expect_reftable_perms 022 group "-rw-rw-r--" | |
142 | test_expect_reftable_perms 027 group "-rw-rw----" | |
143 | ||
144 | test_expect_reftable_perms 002 world "-rw-rw-r--" | |
145 | test_expect_reftable_perms 022 world "-rw-rw-r--" | |
146 | test_expect_reftable_perms 027 world "-rw-rw-r--" | |
57db2a09 PS |
147 | |
148 | test_expect_success 'clone: can clone reftable repository' ' | |
149 | test_when_finished "rm -rf repo clone" && | |
150 | git init repo && | |
151 | test_commit -C repo message1 file1 && | |
152 | ||
153 | git clone repo cloned && | |
154 | echo reftable >expect && | |
155 | git -C cloned rev-parse --show-ref-format >actual && | |
156 | test_cmp expect actual && | |
157 | test_path_is_file cloned/file1 | |
158 | ' | |
159 | ||
160 | test_expect_success 'clone: can clone reffiles into reftable repository' ' | |
161 | test_when_finished "rm -rf reffiles reftable" && | |
162 | git init --ref-format=files reffiles && | |
163 | test_commit -C reffiles A && | |
164 | git clone --ref-format=reftable ./reffiles reftable && | |
165 | ||
166 | git -C reffiles rev-parse HEAD >expect && | |
167 | git -C reftable rev-parse HEAD >actual && | |
168 | test_cmp expect actual && | |
169 | ||
170 | git -C reftable rev-parse --show-ref-format >actual && | |
171 | echo reftable >expect && | |
172 | test_cmp expect actual && | |
173 | ||
174 | git -C reffiles rev-parse --show-ref-format >actual && | |
175 | echo files >expect && | |
176 | test_cmp expect actual | |
177 | ' | |
178 | ||
179 | test_expect_success 'clone: can clone reftable into reffiles repository' ' | |
180 | test_when_finished "rm -rf reffiles reftable" && | |
181 | git init --ref-format=reftable reftable && | |
182 | test_commit -C reftable A && | |
183 | git clone --ref-format=files ./reftable reffiles && | |
184 | ||
185 | git -C reftable rev-parse HEAD >expect && | |
186 | git -C reffiles rev-parse HEAD >actual && | |
187 | test_cmp expect actual && | |
188 | ||
189 | git -C reftable rev-parse --show-ref-format >actual && | |
190 | echo reftable >expect && | |
191 | test_cmp expect actual && | |
192 | ||
193 | git -C reffiles rev-parse --show-ref-format >actual && | |
194 | echo files >expect && | |
195 | test_cmp expect actual | |
196 | ' | |
197 | ||
198 | test_expect_success 'ref transaction: corrupted tables cause failure' ' | |
199 | test_when_finished "rm -rf repo" && | |
200 | git init repo && | |
201 | ( | |
202 | cd repo && | |
203 | test_commit file1 && | |
204 | for f in .git/reftable/*.ref | |
205 | do | |
206 | : >"$f" || return 1 | |
207 | done && | |
208 | test_must_fail git update-ref refs/heads/main HEAD | |
209 | ) | |
210 | ' | |
211 | ||
212 | test_expect_success 'ref transaction: corrupted tables.list cause failure' ' | |
213 | test_when_finished "rm -rf repo" && | |
214 | git init repo && | |
215 | ( | |
216 | cd repo && | |
217 | test_commit file1 && | |
218 | echo garbage >.git/reftable/tables.list && | |
219 | test_must_fail git update-ref refs/heads/main HEAD | |
220 | ) | |
221 | ' | |
222 | ||
223 | test_expect_success 'ref transaction: refuses to write ref causing F/D conflict' ' | |
224 | test_when_finished "rm -rf repo" && | |
225 | git init repo && | |
226 | test_commit -C repo file && | |
227 | test_must_fail git -C repo update-ref refs/heads/main/forbidden | |
228 | ' | |
229 | ||
230 | test_expect_success 'ref transaction: deleting ref with invalid name fails' ' | |
231 | test_when_finished "rm -rf repo" && | |
232 | git init repo && | |
233 | test_commit -C repo file && | |
234 | test_must_fail git -C repo update-ref -d ../../my-private-file | |
235 | ' | |
236 | ||
237 | test_expect_success 'ref transaction: can skip object ID verification' ' | |
238 | test_when_finished "rm -rf repo" && | |
239 | git init repo && | |
240 | test_must_fail test-tool -C repo ref-store main update-ref msg refs/heads/branch $INVALID_OID $ZERO_OID 0 && | |
241 | test-tool -C repo ref-store main update-ref msg refs/heads/branch $INVALID_OID $ZERO_OID REF_SKIP_OID_VERIFICATION | |
242 | ' | |
243 | ||
244 | test_expect_success 'ref transaction: updating same ref multiple times fails' ' | |
245 | test_when_finished "rm -rf repo" && | |
246 | git init repo && | |
247 | test_commit -C repo A && | |
248 | cat >updates <<-EOF && | |
249 | update refs/heads/main $A | |
250 | update refs/heads/main $A | |
251 | EOF | |
252 | cat >expect <<-EOF && | |
253 | fatal: multiple updates for ref ${SQ}refs/heads/main${SQ} not allowed | |
254 | EOF | |
255 | test_must_fail git -C repo update-ref --stdin <updates 2>err && | |
256 | test_cmp expect err | |
257 | ' | |
258 | ||
259 | test_expect_success 'ref transaction: can delete symbolic self-reference with git-symbolic-ref(1)' ' | |
260 | test_when_finished "rm -rf repo" && | |
261 | git init repo && | |
262 | git -C repo symbolic-ref refs/heads/self refs/heads/self && | |
263 | git -C repo symbolic-ref -d refs/heads/self | |
264 | ' | |
265 | ||
266 | test_expect_success 'ref transaction: deleting symbolic self-reference without --no-deref fails' ' | |
267 | test_when_finished "rm -rf repo" && | |
268 | git init repo && | |
269 | git -C repo symbolic-ref refs/heads/self refs/heads/self && | |
270 | cat >expect <<-EOF && | |
271 | error: multiple updates for ${SQ}refs/heads/self${SQ} (including one via symref ${SQ}refs/heads/self${SQ}) are not allowed | |
272 | EOF | |
273 | test_must_fail git -C repo update-ref -d refs/heads/self 2>err && | |
274 | test_cmp expect err | |
275 | ' | |
276 | ||
277 | test_expect_success 'ref transaction: deleting symbolic self-reference with --no-deref succeeds' ' | |
278 | test_when_finished "rm -rf repo" && | |
279 | git init repo && | |
280 | git -C repo symbolic-ref refs/heads/self refs/heads/self && | |
281 | git -C repo update-ref -d --no-deref refs/heads/self | |
282 | ' | |
283 | ||
284 | test_expect_success 'ref transaction: creating symbolic ref fails with F/D conflict' ' | |
285 | test_when_finished "rm -rf repo" && | |
286 | git init repo && | |
287 | test_commit -C repo A && | |
288 | cat >expect <<-EOF && | |
289 | error: unable to write symref for refs/heads: file/directory conflict | |
290 | EOF | |
291 | test_must_fail git -C repo symbolic-ref refs/heads refs/heads/foo 2>err && | |
292 | test_cmp expect err | |
293 | ' | |
294 | ||
295 | test_expect_success 'ref transaction: ref deletion' ' | |
296 | test_when_finished "rm -rf repo" && | |
297 | git init repo && | |
298 | ( | |
299 | cd repo && | |
300 | test_commit file && | |
301 | HEAD_OID=$(git show-ref -s --verify HEAD) && | |
302 | cat >expect <<-EOF && | |
303 | $HEAD_OID refs/heads/main | |
304 | $HEAD_OID refs/tags/file | |
305 | EOF | |
306 | git show-ref >actual && | |
307 | test_cmp expect actual && | |
308 | ||
309 | test_must_fail git update-ref -d refs/tags/file $INVALID_OID && | |
310 | git show-ref >actual && | |
311 | test_cmp expect actual && | |
312 | ||
313 | git update-ref -d refs/tags/file $HEAD_OID && | |
314 | echo "$HEAD_OID refs/heads/main" >expect && | |
315 | git show-ref >actual && | |
316 | test_cmp expect actual | |
317 | ) | |
318 | ' | |
319 | ||
320 | test_expect_success 'ref transaction: writes cause auto-compaction' ' | |
321 | test_when_finished "rm -rf repo" && | |
322 | ||
323 | git init repo && | |
324 | test_line_count = 1 repo/.git/reftable/tables.list && | |
325 | ||
326 | test_commit -C repo --no-tag A && | |
a949ebd3 | 327 | test_line_count = 1 repo/.git/reftable/tables.list && |
57db2a09 PS |
328 | |
329 | test_commit -C repo --no-tag B && | |
330 | test_line_count = 1 repo/.git/reftable/tables.list | |
331 | ' | |
332 | ||
7c8eb592 JT |
333 | test_expect_success 'ref transaction: env var disables compaction' ' |
334 | test_when_finished "rm -rf repo" && | |
335 | ||
336 | git init repo && | |
337 | test_commit -C repo A && | |
338 | ||
339 | start=$(wc -l <repo/.git/reftable/tables.list) && | |
340 | iterations=5 && | |
341 | expected=$((start + iterations)) && | |
342 | ||
343 | for i in $(test_seq $iterations) | |
344 | do | |
345 | GIT_TEST_REFTABLE_AUTOCOMPACTION=false \ | |
346 | git -C repo update-ref branch-$i HEAD || return 1 | |
347 | done && | |
348 | test_line_count = $expected repo/.git/reftable/tables.list && | |
349 | ||
350 | git -C repo update-ref foo HEAD && | |
351 | test_line_count -lt $expected repo/.git/reftable/tables.list | |
352 | ' | |
353 | ||
a949ebd3 JT |
354 | test_expect_success 'ref transaction: alternating table sizes are compacted' ' |
355 | test_when_finished "rm -rf repo" && | |
356 | ||
357 | git init repo && | |
358 | test_commit -C repo A && | |
359 | for i in $(test_seq 5) | |
360 | do | |
361 | git -C repo branch -f foo && | |
362 | git -C repo branch -d foo || return 1 | |
363 | done && | |
364 | test_line_count = 2 repo/.git/reftable/tables.list | |
365 | ' | |
366 | ||
57db2a09 PS |
367 | check_fsync_events () { |
368 | local trace="$1" && | |
369 | shift && | |
370 | ||
371 | cat >expect && | |
372 | sed -n \ | |
373 | -e '/^{"event":"counter",.*"category":"fsync",/ { | |
374 | s/.*"category":"fsync",//; | |
375 | s/}$//; | |
376 | p; | |
377 | }' \ | |
378 | <"$trace" >actual && | |
379 | test_cmp expect actual | |
380 | } | |
381 | ||
382 | test_expect_success 'ref transaction: writes are synced' ' | |
383 | test_when_finished "rm -rf repo" && | |
384 | git init repo && | |
385 | test_commit -C repo initial && | |
386 | ||
387 | GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \ | |
388 | GIT_TEST_FSYNC=true \ | |
389 | git -C repo -c core.fsync=reference \ | |
390 | -c core.fsyncMethod=fsync update-ref refs/heads/branch HEAD && | |
391 | check_fsync_events trace2.txt <<-EOF | |
a949ebd3 | 392 | "name":"hardware-flush","count":4 |
57db2a09 PS |
393 | EOF |
394 | ' | |
395 | ||
b0f6b6b5 PS |
396 | test_expect_success 'ref transaction: empty transaction in empty repo' ' |
397 | test_when_finished "rm -rf repo" && | |
398 | git init repo && | |
399 | test_commit -C repo --no-tag A && | |
b0f6b6b5 PS |
400 | git -C repo update-ref -d refs/heads/main && |
401 | test-tool -C repo ref-store main delete-refs REF_NO_DEREF msg HEAD && | |
402 | git -C repo update-ref --stdin <<-EOF | |
403 | prepare | |
404 | commit | |
405 | EOF | |
406 | ' | |
407 | ||
a2f711ad PS |
408 | test_expect_success 'ref transaction: fails gracefully when auto compaction fails' ' |
409 | test_when_finished "rm -rf repo" && | |
410 | git init repo && | |
411 | ( | |
412 | cd repo && | |
413 | ||
414 | test_commit A && | |
415 | for i in $(test_seq 10) | |
416 | do | |
417 | git branch branch-$i && | |
418 | for table in .git/reftable/*.ref | |
419 | do | |
420 | touch "$table.lock" || exit 1 | |
421 | done || | |
422 | exit 1 | |
423 | done && | |
a949ebd3 | 424 | test_line_count = 10 .git/reftable/tables.list |
a2f711ad PS |
425 | ) |
426 | ' | |
427 | ||
57db2a09 PS |
428 | test_expect_success 'pack-refs: compacts tables' ' |
429 | test_when_finished "rm -rf repo" && | |
430 | git init repo && | |
431 | ||
432 | test_commit -C repo A && | |
433 | ls -1 repo/.git/reftable >table-files && | |
a949ebd3 JT |
434 | test_line_count = 3 table-files && |
435 | test_line_count = 2 repo/.git/reftable/tables.list && | |
57db2a09 PS |
436 | |
437 | git -C repo pack-refs && | |
438 | ls -1 repo/.git/reftable >table-files && | |
439 | test_line_count = 2 table-files && | |
440 | test_line_count = 1 repo/.git/reftable/tables.list | |
441 | ' | |
442 | ||
4ccf7060 PS |
443 | test_expect_success 'pack-refs: compaction raises locking errors' ' |
444 | test_when_finished "rm -rf repo" && | |
445 | git init repo && | |
446 | test_commit -C repo A && | |
447 | touch repo/.git/reftable/tables.list.lock && | |
448 | cat >expect <<-EOF && | |
449 | error: unable to compact stack: data is locked | |
450 | EOF | |
451 | test_must_fail git -C repo pack-refs 2>err && | |
452 | test_cmp expect err | |
453 | ' | |
454 | ||
9f6714ab | 455 | for command in pack-refs gc "maintenance run --task=pack-refs" |
bfc2f9eb PS |
456 | do |
457 | test_expect_success "$command: auto compaction" ' | |
6dcffc68 PS |
458 | test_when_finished "rm -rf repo" && |
459 | git init repo && | |
460 | ( | |
461 | cd repo && | |
462 | ||
463 | test_commit A && | |
464 | ||
bfc2f9eb PS |
465 | # We need a bit of setup to ensure that git-gc(1) actually |
466 | # triggers, and that it does not write anything to the refdb. | |
467 | git config gc.auto 1 && | |
468 | git config gc.autoDetach 0 && | |
469 | git config gc.reflogExpire never && | |
470 | git config gc.reflogExpireUnreachable never && | |
471 | test_oid blob17_1 | git hash-object -w --stdin && | |
472 | ||
6dcffc68 PS |
473 | # The tables should have been auto-compacted, and thus auto |
474 | # compaction should not have to do anything. | |
475 | ls -1 .git/reftable >tables-expect && | |
a949ebd3 | 476 | test_line_count = 3 tables-expect && |
bfc2f9eb | 477 | git $command --auto && |
6dcffc68 PS |
478 | ls -1 .git/reftable >tables-actual && |
479 | test_cmp tables-expect tables-actual && | |
480 | ||
bfc2f9eb PS |
481 | test_oid blob17_2 | git hash-object -w --stdin && |
482 | ||
6dcffc68 PS |
483 | # Lock all tables write some refs. Auto-compaction will be |
484 | # unable to compact tables and thus fails gracefully, leaving | |
485 | # the stack in a sub-optimal state. | |
486 | ls .git/reftable/*.ref | | |
487 | while read table | |
488 | do | |
489 | touch "$table.lock" || exit 1 | |
490 | done && | |
491 | git branch B && | |
492 | git branch C && | |
493 | rm .git/reftable/*.lock && | |
a949ebd3 | 494 | test_line_count = 4 .git/reftable/tables.list && |
6dcffc68 | 495 | |
bfc2f9eb | 496 | git $command --auto && |
6dcffc68 PS |
497 | test_line_count = 1 .git/reftable/tables.list |
498 | ) | |
499 | ' | |
bfc2f9eb | 500 | done |
6dcffc68 | 501 | |
57db2a09 PS |
502 | test_expect_success 'pack-refs: prunes stale tables' ' |
503 | test_when_finished "rm -rf repo" && | |
504 | git init repo && | |
505 | touch repo/.git/reftable/stale-table.ref && | |
506 | git -C repo pack-refs && | |
507 | test_path_is_missing repo/.git/reftable/stable-ref.ref | |
508 | ' | |
509 | ||
510 | test_expect_success 'pack-refs: does not prune non-table files' ' | |
511 | test_when_finished "rm -rf repo" && | |
512 | git init repo && | |
513 | touch repo/.git/reftable/garbage && | |
514 | git -C repo pack-refs && | |
515 | test_path_is_file repo/.git/reftable/garbage | |
516 | ' | |
517 | ||
57db2a09 PS |
518 | test_expect_success 'packed-refs: writes are synced' ' |
519 | test_when_finished "rm -rf repo" && | |
520 | git init repo && | |
521 | test_commit -C repo initial && | |
522 | test_line_count = 2 table-files && | |
523 | ||
524 | : >trace2.txt && | |
525 | GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \ | |
526 | GIT_TEST_FSYNC=true \ | |
527 | git -C repo -c core.fsync=reference \ | |
528 | -c core.fsyncMethod=fsync pack-refs && | |
529 | check_fsync_events trace2.txt <<-EOF | |
530 | "name":"hardware-flush","count":2 | |
531 | EOF | |
532 | ' | |
533 | ||
534 | test_expect_success 'ref iterator: bogus names are flagged' ' | |
535 | test_when_finished "rm -rf repo" && | |
536 | git init repo && | |
537 | ( | |
538 | cd repo && | |
539 | test_commit --no-tag file && | |
540 | test-tool ref-store main update-ref msg "refs/heads/bogus..name" $(git rev-parse HEAD) $ZERO_OID REF_SKIP_REFNAME_VERIFICATION && | |
541 | ||
542 | cat >expect <<-EOF && | |
543 | $ZERO_OID refs/heads/bogus..name 0xc | |
544 | $(git rev-parse HEAD) refs/heads/main 0x0 | |
545 | EOF | |
546 | test-tool ref-store main for-each-ref "" >actual && | |
547 | test_cmp expect actual | |
548 | ) | |
549 | ' | |
550 | ||
551 | test_expect_success 'ref iterator: missing object IDs are not flagged' ' | |
552 | test_when_finished "rm -rf repo" && | |
553 | git init repo && | |
554 | ( | |
555 | cd repo && | |
556 | test-tool ref-store main update-ref msg "refs/heads/broken-hash" $INVALID_OID $ZERO_OID REF_SKIP_OID_VERIFICATION && | |
557 | ||
558 | cat >expect <<-EOF && | |
559 | $INVALID_OID refs/heads/broken-hash 0x0 | |
560 | EOF | |
561 | test-tool ref-store main for-each-ref "" >actual && | |
562 | test_cmp expect actual | |
563 | ) | |
564 | ' | |
565 | ||
566 | test_expect_success 'basic: commit and list refs' ' | |
567 | test_when_finished "rm -rf repo" && | |
568 | git init repo && | |
569 | test_commit -C repo file && | |
570 | test_write_lines refs/heads/main refs/tags/file >expect && | |
571 | git -C repo for-each-ref --format="%(refname)" >actual && | |
572 | test_cmp actual expect | |
573 | ' | |
574 | ||
575 | test_expect_success 'basic: can write large commit message' ' | |
576 | test_when_finished "rm -rf repo" && | |
577 | git init repo && | |
578 | perl -e " | |
579 | print \"this is a long commit message\" x 50000 | |
580 | " >commit-msg && | |
581 | git -C repo commit --allow-empty --file=../commit-msg | |
582 | ' | |
583 | ||
584 | test_expect_success 'basic: show-ref fails with empty repository' ' | |
585 | test_when_finished "rm -rf repo" && | |
586 | git init repo && | |
587 | test_must_fail git -C repo show-ref >actual && | |
588 | test_must_be_empty actual | |
589 | ' | |
590 | ||
591 | test_expect_success 'basic: can check out unborn branch' ' | |
592 | test_when_finished "rm -rf repo" && | |
593 | git init repo && | |
594 | git -C repo checkout -b main | |
595 | ' | |
596 | ||
597 | test_expect_success 'basic: peeled tags are stored' ' | |
598 | test_when_finished "rm -rf repo" && | |
599 | git init repo && | |
600 | test_commit -C repo file && | |
601 | git -C repo tag -m "annotated tag" test_tag HEAD && | |
602 | for ref in refs/heads/main refs/tags/file refs/tags/test_tag refs/tags/test_tag^{} | |
603 | do | |
604 | echo "$(git -C repo rev-parse "$ref") $ref" || return 1 | |
605 | done >expect && | |
606 | git -C repo show-ref -d >actual && | |
607 | test_cmp expect actual | |
608 | ' | |
609 | ||
610 | test_expect_success 'basic: for-each-ref can print symrefs' ' | |
611 | test_when_finished "rm -rf repo" && | |
612 | git init repo && | |
613 | ( | |
614 | cd repo && | |
615 | test_commit file && | |
616 | git branch && | |
617 | git symbolic-ref refs/heads/sym refs/heads/main && | |
618 | cat >expected <<-EOF && | |
619 | refs/heads/main | |
620 | EOF | |
621 | git for-each-ref --format="%(symref)" refs/heads/sym >actual && | |
622 | test_cmp expected actual | |
623 | ) | |
624 | ' | |
625 | ||
626 | test_expect_success 'basic: notes' ' | |
627 | test_when_finished "rm -rf repo" && | |
628 | git init repo && | |
629 | ( | |
630 | write_script fake_editor <<-\EOF && | |
631 | echo "$MSG" >"$1" | |
632 | echo "$MSG" >&2 | |
633 | EOF | |
634 | ||
635 | test_commit 1st && | |
636 | test_commit 2nd && | |
637 | GIT_EDITOR=./fake_editor MSG=b4 git notes add && | |
638 | GIT_EDITOR=./fake_editor MSG=b3 git notes edit && | |
639 | echo b4 >expect && | |
640 | git notes --ref commits@{1} show >actual && | |
641 | test_cmp expect actual | |
642 | ) | |
643 | ' | |
644 | ||
645 | test_expect_success 'basic: stash' ' | |
646 | test_when_finished "rm -rf repo" && | |
647 | git init repo && | |
648 | ( | |
649 | cd repo && | |
650 | test_commit file && | |
651 | git stash list >expect && | |
652 | test_line_count = 0 expect && | |
653 | ||
654 | echo hoi >>file.t && | |
655 | git stash push -m stashed && | |
656 | git stash list >expect && | |
657 | test_line_count = 1 expect && | |
658 | ||
659 | git stash clear && | |
660 | git stash list >expect && | |
661 | test_line_count = 0 expect | |
662 | ) | |
663 | ' | |
664 | ||
665 | test_expect_success 'basic: cherry-pick' ' | |
666 | test_when_finished "rm -rf repo" && | |
667 | git init repo && | |
668 | ( | |
669 | cd repo && | |
670 | test_commit message1 file1 && | |
671 | test_commit message2 file2 && | |
672 | git branch source && | |
673 | git checkout HEAD^ && | |
674 | test_commit message3 file3 && | |
675 | git cherry-pick source && | |
676 | test_path_is_file file2 | |
677 | ) | |
678 | ' | |
679 | ||
680 | test_expect_success 'basic: rebase' ' | |
681 | test_when_finished "rm -rf repo" && | |
682 | git init repo && | |
683 | ( | |
684 | cd repo && | |
685 | test_commit message1 file1 && | |
686 | test_commit message2 file2 && | |
687 | git branch source && | |
688 | git checkout HEAD^ && | |
689 | test_commit message3 file3 && | |
690 | git rebase source && | |
691 | test_path_is_file file2 | |
692 | ) | |
693 | ' | |
694 | ||
695 | test_expect_success 'reflog: can delete separate reflog entries' ' | |
696 | test_when_finished "rm -rf repo" && | |
697 | git init repo && | |
698 | ( | |
699 | cd repo && | |
700 | ||
701 | test_commit file && | |
702 | test_commit file2 && | |
703 | test_commit file3 && | |
704 | test_commit file4 && | |
705 | git reflog >actual && | |
706 | grep file3 actual && | |
707 | ||
708 | git reflog delete HEAD@{1} && | |
709 | git reflog >actual && | |
710 | ! grep file3 actual | |
711 | ) | |
712 | ' | |
713 | ||
714 | test_expect_success 'reflog: can switch to previous branch' ' | |
715 | test_when_finished "rm -rf repo" && | |
716 | git init repo && | |
717 | ( | |
718 | cd repo && | |
719 | test_commit file1 && | |
720 | git checkout -b branch1 && | |
721 | test_commit file2 && | |
722 | git checkout -b branch2 && | |
723 | git switch - && | |
724 | git rev-parse --symbolic-full-name HEAD >actual && | |
725 | echo refs/heads/branch1 >expect && | |
726 | test_cmp actual expect | |
727 | ) | |
728 | ' | |
729 | ||
730 | test_expect_success 'reflog: copying branch writes reflog entry' ' | |
731 | test_when_finished "rm -rf repo" && | |
732 | git init repo && | |
733 | ( | |
734 | cd repo && | |
735 | test_commit file1 && | |
736 | test_commit file2 && | |
737 | oid=$(git rev-parse --short HEAD) && | |
738 | git branch src && | |
739 | cat >expect <<-EOF && | |
740 | ${oid} dst@{0}: Branch: copied refs/heads/src to refs/heads/dst | |
741 | ${oid} dst@{1}: branch: Created from main | |
742 | EOF | |
743 | git branch -c src dst && | |
744 | git reflog dst >actual && | |
745 | test_cmp expect actual | |
746 | ) | |
747 | ' | |
748 | ||
749 | test_expect_success 'reflog: renaming branch writes reflog entry' ' | |
750 | test_when_finished "rm -rf repo" && | |
751 | git init repo && | |
752 | ( | |
753 | cd repo && | |
754 | git symbolic-ref HEAD refs/heads/before && | |
755 | test_commit file && | |
756 | git show-ref >expected.refs && | |
757 | sed s/before/after/g <expected.refs >expected && | |
758 | git branch -M after && | |
759 | git show-ref >actual && | |
760 | test_cmp expected actual && | |
761 | echo refs/heads/after >expected && | |
762 | git symbolic-ref HEAD >actual && | |
763 | test_cmp expected actual | |
764 | ) | |
765 | ' | |
766 | ||
767 | test_expect_success 'reflog: can store empty logs' ' | |
768 | test_when_finished "rm -rf repo" && | |
769 | git init repo && | |
770 | ( | |
771 | cd repo && | |
772 | ||
773 | test_must_fail test-tool ref-store main reflog-exists refs/heads/branch && | |
774 | test-tool ref-store main create-reflog refs/heads/branch && | |
775 | test-tool ref-store main reflog-exists refs/heads/branch && | |
776 | test-tool ref-store main for-each-reflog-ent-reverse refs/heads/branch >actual && | |
777 | test_must_be_empty actual | |
778 | ) | |
779 | ' | |
780 | ||
781 | test_expect_success 'reflog: expiry empties reflog' ' | |
782 | test_when_finished "rm -rf repo" && | |
783 | git init repo && | |
784 | ( | |
785 | cd repo && | |
786 | ||
787 | test_commit initial && | |
788 | git checkout -b branch && | |
789 | test_commit fileA && | |
790 | test_commit fileB && | |
791 | ||
792 | cat >expect <<-EOF && | |
793 | commit: fileB | |
794 | commit: fileA | |
795 | branch: Created from HEAD | |
796 | EOF | |
797 | git reflog show --format="%gs" refs/heads/branch >actual && | |
798 | test_cmp expect actual && | |
799 | ||
800 | git reflog expire branch --expire=all && | |
801 | git reflog show --format="%gs" refs/heads/branch >actual && | |
802 | test_must_be_empty actual && | |
803 | test-tool ref-store main reflog-exists refs/heads/branch | |
804 | ) | |
805 | ' | |
806 | ||
807 | test_expect_success 'reflog: can be deleted' ' | |
808 | test_when_finished "rm -rf repo" && | |
809 | git init repo && | |
810 | ( | |
811 | cd repo && | |
812 | test_commit initial && | |
813 | test-tool ref-store main reflog-exists refs/heads/main && | |
814 | test-tool ref-store main delete-reflog refs/heads/main && | |
815 | test_must_fail test-tool ref-store main reflog-exists refs/heads/main | |
816 | ) | |
817 | ' | |
818 | ||
819 | test_expect_success 'reflog: garbage collection deletes reflog entries' ' | |
820 | test_when_finished "rm -rf repo" && | |
821 | git init repo && | |
822 | ( | |
823 | cd repo && | |
824 | ||
825 | for count in $(test_seq 1 10) | |
826 | do | |
827 | test_commit "number $count" file.t $count number-$count || | |
828 | return 1 | |
829 | done && | |
830 | git reflog refs/heads/main >actual && | |
831 | test_line_count = 10 actual && | |
832 | grep "commit (initial): number 1" actual && | |
833 | grep "commit: number 10" actual && | |
834 | ||
835 | git gc && | |
836 | git reflog refs/heads/main >actual && | |
837 | test_line_count = 0 actual | |
838 | ) | |
839 | ' | |
840 | ||
841 | test_expect_success 'reflog: updates via HEAD update HEAD reflog' ' | |
842 | test_when_finished "rm -rf repo" && | |
843 | git init repo && | |
844 | ( | |
845 | cd repo && | |
846 | test_commit main-one && | |
847 | git checkout -b new-branch && | |
848 | test_commit new-one && | |
849 | test_commit new-two && | |
850 | ||
851 | echo new-one >expect && | |
852 | git log -1 --format=%s HEAD@{1} >actual && | |
853 | test_cmp expect actual | |
854 | ) | |
855 | ' | |
856 | ||
857 | test_expect_success 'worktree: adding worktree creates separate stack' ' | |
858 | test_when_finished "rm -rf repo worktree" && | |
859 | git init repo && | |
860 | test_commit -C repo A && | |
861 | ||
862 | git -C repo worktree add ../worktree && | |
863 | test_path_is_file repo/.git/worktrees/worktree/refs/heads && | |
864 | echo "ref: refs/heads/.invalid" >expect && | |
865 | test_cmp expect repo/.git/worktrees/worktree/HEAD && | |
866 | test_path_is_dir repo/.git/worktrees/worktree/reftable && | |
867 | test_path_is_file repo/.git/worktrees/worktree/reftable/tables.list | |
868 | ' | |
869 | ||
870 | test_expect_success 'worktree: pack-refs in main repo packs main refs' ' | |
871 | test_when_finished "rm -rf repo worktree" && | |
872 | git init repo && | |
873 | test_commit -C repo A && | |
a949ebd3 JT |
874 | |
875 | GIT_TEST_REFTABLE_AUTOCOMPACTION=false \ | |
57db2a09 | 876 | git -C repo worktree add ../worktree && |
a949ebd3 JT |
877 | GIT_TEST_REFTABLE_AUTOCOMPACTION=false \ |
878 | git -C worktree update-ref refs/worktree/per-worktree HEAD && | |
57db2a09 | 879 | |
a949ebd3 JT |
880 | test_line_count = 4 repo/.git/worktrees/worktree/reftable/tables.list && |
881 | test_line_count = 3 repo/.git/reftable/tables.list && | |
57db2a09 | 882 | git -C repo pack-refs && |
a949ebd3 | 883 | test_line_count = 4 repo/.git/worktrees/worktree/reftable/tables.list && |
57db2a09 PS |
884 | test_line_count = 1 repo/.git/reftable/tables.list |
885 | ' | |
886 | ||
887 | test_expect_success 'worktree: pack-refs in worktree packs worktree refs' ' | |
888 | test_when_finished "rm -rf repo worktree" && | |
889 | git init repo && | |
890 | test_commit -C repo A && | |
a949ebd3 JT |
891 | |
892 | GIT_TEST_REFTABLE_AUTOCOMPACTION=false \ | |
57db2a09 | 893 | git -C repo worktree add ../worktree && |
a949ebd3 JT |
894 | GIT_TEST_REFTABLE_AUTOCOMPACTION=false \ |
895 | git -C worktree update-ref refs/worktree/per-worktree HEAD && | |
57db2a09 | 896 | |
a949ebd3 JT |
897 | test_line_count = 4 repo/.git/worktrees/worktree/reftable/tables.list && |
898 | test_line_count = 3 repo/.git/reftable/tables.list && | |
57db2a09 PS |
899 | git -C worktree pack-refs && |
900 | test_line_count = 1 repo/.git/worktrees/worktree/reftable/tables.list && | |
a949ebd3 | 901 | test_line_count = 3 repo/.git/reftable/tables.list |
57db2a09 PS |
902 | ' |
903 | ||
904 | test_expect_success 'worktree: creating shared ref updates main stack' ' | |
905 | test_when_finished "rm -rf repo worktree" && | |
906 | git init repo && | |
907 | test_commit -C repo A && | |
908 | ||
909 | git -C repo worktree add ../worktree && | |
910 | git -C repo pack-refs && | |
911 | git -C worktree pack-refs && | |
912 | test_line_count = 1 repo/.git/worktrees/worktree/reftable/tables.list && | |
913 | test_line_count = 1 repo/.git/reftable/tables.list && | |
914 | ||
a949ebd3 | 915 | GIT_TEST_REFTABLE_AUTOCOMPACTION=false \ |
57db2a09 PS |
916 | git -C worktree update-ref refs/heads/shared HEAD && |
917 | test_line_count = 1 repo/.git/worktrees/worktree/reftable/tables.list && | |
918 | test_line_count = 2 repo/.git/reftable/tables.list | |
919 | ' | |
920 | ||
921 | test_expect_success 'worktree: creating per-worktree ref updates worktree stack' ' | |
922 | test_when_finished "rm -rf repo worktree" && | |
923 | git init repo && | |
924 | test_commit -C repo A && | |
925 | ||
926 | git -C repo worktree add ../worktree && | |
927 | git -C repo pack-refs && | |
928 | git -C worktree pack-refs && | |
929 | test_line_count = 1 repo/.git/worktrees/worktree/reftable/tables.list && | |
930 | test_line_count = 1 repo/.git/reftable/tables.list && | |
931 | ||
932 | git -C worktree update-ref refs/bisect/per-worktree HEAD && | |
933 | test_line_count = 2 repo/.git/worktrees/worktree/reftable/tables.list && | |
934 | test_line_count = 1 repo/.git/reftable/tables.list | |
935 | ' | |
936 | ||
937 | test_expect_success 'worktree: creating per-worktree ref from main repo' ' | |
938 | test_when_finished "rm -rf repo worktree" && | |
939 | git init repo && | |
940 | test_commit -C repo A && | |
941 | ||
942 | git -C repo worktree add ../worktree && | |
943 | git -C repo pack-refs && | |
944 | git -C worktree pack-refs && | |
945 | test_line_count = 1 repo/.git/worktrees/worktree/reftable/tables.list && | |
946 | test_line_count = 1 repo/.git/reftable/tables.list && | |
947 | ||
948 | git -C repo update-ref worktrees/worktree/refs/bisect/per-worktree HEAD && | |
949 | test_line_count = 2 repo/.git/worktrees/worktree/reftable/tables.list && | |
950 | test_line_count = 1 repo/.git/reftable/tables.list | |
951 | ' | |
952 | ||
953 | test_expect_success 'worktree: creating per-worktree ref from second worktree' ' | |
954 | test_when_finished "rm -rf repo wt1 wt2" && | |
955 | git init repo && | |
956 | test_commit -C repo A && | |
957 | ||
958 | git -C repo worktree add ../wt1 && | |
959 | git -C repo worktree add ../wt2 && | |
960 | git -C repo pack-refs && | |
961 | git -C wt1 pack-refs && | |
962 | git -C wt2 pack-refs && | |
963 | test_line_count = 1 repo/.git/worktrees/wt1/reftable/tables.list && | |
964 | test_line_count = 1 repo/.git/worktrees/wt2/reftable/tables.list && | |
965 | test_line_count = 1 repo/.git/reftable/tables.list && | |
966 | ||
967 | git -C wt1 update-ref worktrees/wt2/refs/bisect/per-worktree HEAD && | |
968 | test_line_count = 1 repo/.git/worktrees/wt1/reftable/tables.list && | |
969 | test_line_count = 2 repo/.git/worktrees/wt2/reftable/tables.list && | |
970 | test_line_count = 1 repo/.git/reftable/tables.list | |
971 | ' | |
972 | ||
973 | test_expect_success 'worktree: can create shared and per-worktree ref in one transaction' ' | |
974 | test_when_finished "rm -rf repo worktree" && | |
975 | git init repo && | |
976 | test_commit -C repo A && | |
977 | ||
978 | git -C repo worktree add ../worktree && | |
979 | git -C repo pack-refs && | |
980 | git -C worktree pack-refs && | |
981 | test_line_count = 1 repo/.git/worktrees/worktree/reftable/tables.list && | |
982 | test_line_count = 1 repo/.git/reftable/tables.list && | |
983 | ||
984 | cat >stdin <<-EOF && | |
985 | create worktrees/worktree/refs/bisect/per-worktree HEAD | |
986 | create refs/branches/shared HEAD | |
987 | EOF | |
988 | git -C repo update-ref --stdin <stdin && | |
989 | test_line_count = 2 repo/.git/worktrees/worktree/reftable/tables.list && | |
990 | test_line_count = 2 repo/.git/reftable/tables.list | |
991 | ' | |
992 | ||
993 | test_expect_success 'worktree: can access common refs' ' | |
994 | test_when_finished "rm -rf repo worktree" && | |
995 | git init repo && | |
996 | test_commit -C repo file1 && | |
997 | git -C repo branch branch1 && | |
998 | git -C repo worktree add ../worktree && | |
999 | ||
1000 | echo refs/heads/worktree >expect && | |
1001 | git -C worktree symbolic-ref HEAD >actual && | |
1002 | test_cmp expect actual && | |
1003 | git -C worktree checkout branch1 | |
1004 | ' | |
1005 | ||
1006 | test_expect_success 'worktree: adds worktree with detached HEAD' ' | |
1007 | test_when_finished "rm -rf repo worktree" && | |
1008 | ||
1009 | git init repo && | |
1010 | test_commit -C repo A && | |
1011 | git -C repo rev-parse main >expect && | |
1012 | ||
1013 | git -C repo worktree add --detach ../worktree main && | |
1014 | git -C worktree rev-parse HEAD >actual && | |
1015 | test_cmp expect actual | |
1016 | ' | |
1017 | ||
1018 | test_expect_success 'fetch: accessing FETCH_HEAD special ref works' ' | |
1019 | test_when_finished "rm -rf repo sub" && | |
1020 | ||
1021 | git init sub && | |
1022 | test_commit -C sub two && | |
1023 | git -C sub rev-parse HEAD >expect && | |
1024 | ||
1025 | git init repo && | |
1026 | test_commit -C repo one && | |
1027 | git -C repo fetch ../sub && | |
1028 | git -C repo rev-parse FETCH_HEAD >actual && | |
1029 | test_cmp expect actual | |
1030 | ' | |
1031 | ||
1032 | test_done |