465
)
466
'
467
468
+run_and_verify_geometric_pack () {
469
+ EXPECTED_PACKS="$1" &&
470
+
471
+ # Verify that we perform a geometric repack.
472
+ rm -f "trace2.txt" &&
473
+ GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \
474
+ git maintenance run --task=geometric-repack 2>/dev/null &&
475
+ test_subcommand git repack -d -l --geometric=2 \
476
+ --quiet --write-midx <trace2.txt &&
477
+
478
+ # Verify that the number of packfiles matches our expectation.
479
+ ls -l .git/objects/pack/*.pack >packfiles &&
480
+ test_line_count = "$EXPECTED_PACKS" packfiles &&
481
+
482
+ # And verify that there are no loose objects anymore.
483
+ git count-objects -v >count &&
484
+ test_grep '^count: 0$' count
485
+}
486
+
487
+test_expect_success 'geometric repacking task' '
488
+ test_when_finished "rm -rf repo" &&
489
+ git init repo &&
490
+ (
491
+ cd repo &&
492
+ git config set maintenance.auto false &&
493
+ test_commit initial &&
494
+
495
+ # The initial repack causes an all-into-one repack.
496
+ GIT_TRACE2_EVENT="$(pwd)/initial-repack.txt" \
497
+ git maintenance run --task=geometric-repack 2>/dev/null &&
498
+ test_subcommand git repack -d -l --cruft --cruft-expiration=2.weeks.ago \
499
+ --quiet --write-midx <initial-repack.txt &&
500
+
501
+ # Repacking should now cause a no-op geometric repack because
502
+ # no packfiles need to be combined.
503
+ ls -l .git/objects/pack >before &&
504
+ run_and_verify_geometric_pack 1 &&
505
+ ls -l .git/objects/pack >after &&
506
+ test_cmp before after &&
507
+
508
+ # This incremental change creates a new packfile that only
509
+ # soaks up loose objects. The packfiles are not getting merged
510
+ # at this point.
511
+ test_commit loose &&
512
+ run_and_verify_geometric_pack 2 &&
513
+
514
+ # Both packfiles have 3 objects, so the next run would cause us
515
+ # to merge all packfiles together. This should be turned into
516
+ # an all-into-one-repack.
517
+ GIT_TRACE2_EVENT="$(pwd)/all-into-one-repack.txt" \
518
+ git maintenance run --task=geometric-repack 2>/dev/null &&
519
+ test_subcommand git repack -d -l --cruft --cruft-expiration=2.weeks.ago \
520
+ --quiet --write-midx <all-into-one-repack.txt &&
521
+
522
+ # The geometric repack soaks up unreachable objects.
523
+ echo blob-1 | git hash-object -w --stdin -t blob &&
524
+ run_and_verify_geometric_pack 2 &&
525
+
526
+ # A second unreachable object should be written into another packfile.
527
+ echo blob-2 | git hash-object -w --stdin -t blob &&
528
+ run_and_verify_geometric_pack 3 &&
529
+
530
+ # And these two small packs should now be merged via the
531
+ # geometric repack. The large packfile should remain intact.
532
+ run_and_verify_geometric_pack 2 &&
533
+
534
+ # If we now add two more objects and repack twice we should
535
+ # then see another all-into-one repack. This time around
536
+ # though, as we have unreachable objects, we should also see a
537
+ # cruft pack.
538
+ echo blob-3 | git hash-object -w --stdin -t blob &&
539
+ echo blob-4 | git hash-object -w --stdin -t blob &&
540
+ run_and_verify_geometric_pack 3 &&
541
+ GIT_TRACE2_EVENT="$(pwd)/cruft-repack.txt" \
542
+ git maintenance run --task=geometric-repack 2>/dev/null &&
543
+ test_subcommand git repack -d -l --cruft --cruft-expiration=2.weeks.ago \
544
+ --quiet --write-midx <cruft-repack.txt &&
545
+ ls .git/objects/pack/*.pack >packs &&
546
+ test_line_count = 2 packs &&
547
+ ls .git/objects/pack/*.mtimes >cruft &&
548
+ test_line_count = 1 cruft
549
+ )
550
+'
551
+
552
+test_geometric_repack_needed () {
553
+ NEEDED="$1"
554
+ GEOMETRIC_CONFIG="$2" &&
555
+ rm -f trace2.txt &&
556
+ GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \
557
+ git ${GEOMETRIC_CONFIG:+-c maintenance.geometric-repack.$GEOMETRIC_CONFIG} \
558
+ maintenance run --auto --task=geometric-repack 2>/dev/null &&
559
+ case "$NEEDED" in
560
+ true)
561
+ test_grep "\[\"git\",\"repack\"," trace2.txt;;
562
+ false)
563
+ ! test_grep "\[\"git\",\"repack\"," trace2.txt;;
564
+ *)
565
+ BUG "invalid parameter: $NEEDED";;
566
+ esac
567
+}
568
+
569
+test_expect_success 'geometric repacking with --auto' '
570
+ test_when_finished "rm -rf repo" &&
571
+ git init repo &&
572
+ (
573
+ cd repo &&
574
+
575
+ # An empty repository does not need repacking, except when
576
+ # explicitly told to do it.
577
+ test_geometric_repack_needed false &&
578
+ test_geometric_repack_needed false auto=0 &&
579
+ test_geometric_repack_needed false auto=1 &&
580
+ test_geometric_repack_needed true auto=-1 &&
581
+
582
+ test_oid_init &&
583
+
584
+ # Loose objects cause a repack when crossing the limit. Note
585
+ # that the number of objects gets extrapolated by having a look
586
+ # at the "objects/17/" shard.
587
+ test_commit "$(test_oid blob17_1)" &&
588
+ test_geometric_repack_needed false &&
589
+ test_commit "$(test_oid blob17_2)" &&
590
+ test_geometric_repack_needed false auto=257 &&
591
+ test_geometric_repack_needed true auto=256 &&
592
+
593
+ # Force another repack.
594
+ test_commit first &&
595
+ test_commit second &&
596
+ test_geometric_repack_needed true auto=-1 &&
597
+
598
+ # We now have two packfiles that would be merged together. As
599
+ # such, the repack should always happen unless the user has
600
+ # disabled the auto task.
601
+ test_geometric_repack_needed false auto=0 &&
602
+ test_geometric_repack_needed true auto=9000
603
+ )
604
+'
605
+
606
test_expect_success 'pack-refs task' '
607
for n in $(test_seq 1 5)
608
do