builtin/gc: make repack arguments self-contained
When optimizing the object database most of the heavy-lifting is done by git-repack(1). The arguments we pass to this function are assembled in global scope, which is hard to follow. Refactor the logic by moving the vector into `maintenance_task_odb()`. While that means we have to pass more arguments to this function, it has the upside that the logic becomes self-contained without any kind of global interdependencies. This is a pure refactoring with no intended functional change. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Patrick Steinhardt committed
Jul 13, 2026 at 07:52 UTC
4d93bf9873696a33a9959c912e7a3fa4fb56a82b
1 file changed
+75
-81
builtin/gc.c
+75
-81
@@ -661,7 +661,7 @@ static void add_repack_incremental_option(struct strvec *args)
661
strvec_push(args, "--no-write-bitmap-index");
662
}
663
664
-static int need_to_gc(struct gc_config *cfg, struct strvec *repack_args)
664
+static int need_to_gc(struct gc_config *cfg)
665
{
666
/*
667
* Setting gc.auto to 0 or negative can disable the
@@ -669,46 +669,8 @@ static int need_to_gc(struct gc_config *cfg, struct strvec *repack_args)
669
*/
670
if (cfg->gc_auto_threshold <= 0)
671
return 0;
672
-
673
- /*
674
- * If there are too many loose objects, but not too many
675
- * packs, we run "repack -d -l". If there are too many packs,
676
- * we run "repack -A -d -l". Otherwise we tell the caller
677
- * there is no need.
678
- */
679
- if (too_many_packs(cfg)) {
680
- struct string_list keep_pack = STRING_LIST_INIT_NODUP;
681
-
682
- if (cfg->big_pack_threshold) {
683
- find_base_packs(&keep_pack, cfg->big_pack_threshold);
684
- if (keep_pack.nr >= cfg->gc_auto_pack_limit) {
685
- cfg->big_pack_threshold = 0;
686
- string_list_clear(&keep_pack, 0);
687
- find_base_packs(&keep_pack, 0);
688
- }
689
- } else {
690
- struct packed_git *p = find_base_packs(&keep_pack, 0);
691
- uint64_t mem_have, mem_want;
692
-
693
- mem_have = total_ram();
694
- mem_want = estimate_repack_memory(cfg, p);
695
-
696
- /*
697
- * Only allow 1/2 of memory for pack-objects, leave
698
- * the rest for the OS and other processes in the
699
- * system.
700
- */
701
- if (!mem_have || mem_want < mem_have / 2)
702
- string_list_clear(&keep_pack, 0);
703
- }
704
-
705
- add_repack_all_option(cfg, &keep_pack, repack_args);
706
- string_list_clear(&keep_pack, 0);
707
- } else if (too_many_loose_objects(cfg->gc_auto_threshold))
708
- add_repack_incremental_option(repack_args);
709
- else
672
+ if (!too_many_packs(cfg) && !too_many_loose_objects(cfg->gc_auto_threshold))
673
return 0;
711
-
674
return 1;
675
}
676
@@ -841,7 +803,8 @@ static int gc_foreground_tasks(struct maintenance_run_opts *opts,
803
804
static int maintenance_task_odb(struct maintenance_run_opts *opts,
805
struct gc_config *cfg,
844
- struct strvec *repack_args)
806
+ int keep_largest_pack,
807
+ int aggressive)
808
{
809
struct child_process repack_cmd = CHILD_PROCESS_INIT;
810
int ret;
@@ -851,9 +814,75 @@ static int maintenance_task_odb(struct maintenance_run_opts *opts,
814
815
repack_cmd.git_cmd = 1;
816
repack_cmd.odb_to_close = the_repository->objects;
854
- strvec_pushv(&repack_cmd.args, repack_args->v);
817
+
818
+ strvec_pushl(&repack_cmd.args, "repack", "-d", "-l", NULL);
819
+ if (aggressive) {
820
+ strvec_push(&repack_cmd.args, "-f");
821
+ if (cfg->aggressive_depth > 0)
822
+ strvec_pushf(&repack_cmd.args, "--depth=%d", cfg->aggressive_depth);
823
+ if (cfg->aggressive_window > 0)
824
+ strvec_pushf(&repack_cmd.args, "--window=%d", cfg->aggressive_window);
825
+ }
826
+ if (opts->quiet)
827
+ strvec_push(&repack_cmd.args, "-q");
828
+
829
+ /*
830
+ * There's three cases we need to consider:
831
+ *
832
+ * - If we're invoked without `--auto` we'll need to perform a full
833
+ * repack.
834
+ *
835
+ * - If we're invoked with `--auto` and there's too many packs, then
836
+ * we perform a full repack, as well.
837
+ *
838
+ * - Otherwise we perform an incremental repack.
839
+ */
840
+ if (!opts->auto_flag) {
841
+ struct string_list keep_pack = STRING_LIST_INIT_NODUP;
842
+
843
+ if (keep_largest_pack != -1) {
844
+ if (keep_largest_pack)
845
+ find_base_packs(&keep_pack, 0);
846
+ } else if (cfg->big_pack_threshold) {
847
+ find_base_packs(&keep_pack, cfg->big_pack_threshold);
848
+ }
849
+
850
+ add_repack_all_option(cfg, &keep_pack, &repack_cmd.args);
851
+ string_list_clear(&keep_pack, 0);
852
+ } else if (too_many_packs(cfg)) {
853
+ struct string_list keep_pack = STRING_LIST_INIT_NODUP;
854
+
855
+ if (cfg->big_pack_threshold) {
856
+ find_base_packs(&keep_pack, cfg->big_pack_threshold);
857
+ if (keep_pack.nr >= cfg->gc_auto_pack_limit) {
858
+ cfg->big_pack_threshold = 0;
859
+ string_list_clear(&keep_pack, 0);
860
+ find_base_packs(&keep_pack, 0);
861
+ }
862
+ } else {
863
+ struct packed_git *p = find_base_packs(&keep_pack, 0);
864
+ uint64_t mem_have, mem_want;
865
+
866
+ mem_have = total_ram();
867
+ mem_want = estimate_repack_memory(cfg, p);
868
+
869
+ /*
870
+ * Only allow 1/2 of memory for pack-objects, leave
871
+ * the rest for the OS and other processes in the
872
+ * system.
873
+ */
874
+ if (!mem_have || mem_want < mem_have / 2)
875
+ string_list_clear(&keep_pack, 0);
876
+ }
877
+
878
+ add_repack_all_option(cfg, &keep_pack, &repack_cmd.args);
879
+ string_list_clear(&keep_pack, 0);
880
+ } else {
881
+ add_repack_incremental_option(&repack_cmd.args);
882
+ }
883
+
884
if (run_command(&repack_cmd)) {
856
- ret = error(FAILED_RUN, repack_args->v[0]);
885
+ ret = error(FAILED_RUN, repack_cmd.args.v[0]);
886
goto out;
887
}
888
@@ -899,7 +928,6 @@ int cmd_gc(int argc,
928
int keep_largest_pack = -1;
929
int skip_foreground_tasks = 0;
930
timestamp_t dummy;
902
- struct strvec repack_args = STRVEC_INIT;
931
struct maintenance_run_opts opts = MAINTENANCE_RUN_OPTS_INIT;
932
struct gc_config cfg = GC_CONFIG_INIT;
933
const char *prune_expire_sentinel = "sentinel";
@@ -939,8 +967,6 @@ int cmd_gc(int argc,
967
show_usage_with_options_if_asked(argc, argv,
968
builtin_gc_usage, builtin_gc_options);
969
942
- strvec_pushl(&repack_args, "repack", "-d", "-l", NULL);
943
-
970
gc_config(&cfg);
971
972
if (parse_expiry_date(cfg.gc_log_expire, &gc_log_expire_time))
@@ -961,16 +987,6 @@ int cmd_gc(int argc,
987
if (cfg.prune_expire && parse_expiry_date(cfg.prune_expire, &dummy))
988
die(_("failed to parse prune expiry value %s"), cfg.prune_expire);
989
964
- if (aggressive) {
965
- strvec_push(&repack_args, "-f");
966
- if (cfg.aggressive_depth > 0)
967
- strvec_pushf(&repack_args, "--depth=%d", cfg.aggressive_depth);
968
- if (cfg.aggressive_window > 0)
969
- strvec_pushf(&repack_args, "--window=%d", cfg.aggressive_window);
970
- }
971
- if (opts.quiet)
972
- strvec_push(&repack_args, "-q");
973
-
990
if (opts.auto_flag) {
991
if (cfg.detach_auto && opts.detach < 0)
992
opts.detach = 1;
@@ -978,8 +994,7 @@ int cmd_gc(int argc,
994
/*
995
* Auto-gc should be least intrusive as possible.
996
*/
981
- if (!need_to_gc(&cfg, &repack_args) ||
982
- run_hooks(the_repository, "pre-auto-gc")) {
997
+ if (!need_to_gc(&cfg) || run_hooks(the_repository, "pre-auto-gc")) {
998
ret = 0;
999
goto out;
1000
}
@@ -991,18 +1006,6 @@ int cmd_gc(int argc,
1006
fprintf(stderr, _("Auto packing the repository for optimum performance.\n"));
1007
fprintf(stderr, _("See \"git help gc\" for manual housekeeping.\n"));
1008
}
994
- } else {
995
- struct string_list keep_pack = STRING_LIST_INIT_NODUP;
996
-
997
- if (keep_largest_pack != -1) {
998
- if (keep_largest_pack)
999
- find_base_packs(&keep_pack, 0);
1000
- } else if (cfg.big_pack_threshold) {
1001
- find_base_packs(&keep_pack, cfg.big_pack_threshold);
1002
- }
1003
-
1004
- add_repack_all_option(&cfg, &keep_pack, &repack_args);
1005
- string_list_clear(&keep_pack, 0);
1009
}
1010
1011
if (opts.detach > 0) {
@@ -1065,7 +1068,7 @@ int cmd_gc(int argc,
1068
if (maintenance_task_rerere_gc(&opts, &cfg))
1069
die(FAILED_RUN, "rerere");
1070
1068
- if (maintenance_task_odb(&opts, &cfg, &repack_args))
1071
+ if (maintenance_task_odb(&opts, &cfg, keep_largest_pack, aggressive))
1072
die(NULL);
1073
1074
report_garbage = report_pack_garbage;
@@ -1088,7 +1091,6 @@ int cmd_gc(int argc,
1091
1092
out:
1093
maintenance_run_opts_release(&opts);
1091
- strvec_clear(&repack_args);
1094
gc_config_release(&cfg);
1095
return 0;
1096
}
@@ -1291,15 +1293,7 @@ static int maintenance_task_gc_background(struct maintenance_run_opts *opts,
1293
1294
static int gc_condition(struct gc_config *cfg)
1295
{
1294
- /*
1295
- * Note that it's fine to drop the repack arguments here, as we execute
1296
- * git-gc(1) as a separate child process anyway. So it knows to compute
1297
- * these arguments again.
1298
- */
1299
- struct strvec repack_args = STRVEC_INIT;
1300
- int ret = need_to_gc(cfg, &repack_args);
1301
- strvec_clear(&repack_args);
1302
- return ret;
1296
+ return need_to_gc(cfg);
1297
}
1298
1299
static int prune_packed(struct maintenance_run_opts *opts)