builtin/gc: refactor to read config into structure

The git-gc(1) command knows to read a bunch of config keys to tweak its own behaviour. The values are parsed into global variables, which makes it hard to correctly manage the lifecycle of values that may require a memory allocation. Refactor the code to use a `struct gc_config` that gets populated and passed around. For one, this makes previously-implicit dependencies on these config values clear. Second, it will allow us to properly manage the lifecycle in the next commit. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Patrick Steinhardt committed Aug 16, 2024 at 12:45 UTC d1ae15d68b44af4ef6e6caedb7aa2b2dcce03c02
1 file changed +143 -112
builtin/gc.c
+143 -112
@@ -49,23 +49,7 @@ static const char * const builtin_gc_usage[] = {
49 NULL
50 };
51
52 -static int pack_refs = 1;
53 -static int prune_reflogs = 1;
54 -static int cruft_packs = 1;
55 -static unsigned long max_cruft_size;
56 -static int aggressive_depth = 50;
57 -static int aggressive_window = 250;
58 -static int gc_auto_threshold = 6700;
59 -static int gc_auto_pack_limit = 50;
60 -static int detach_auto = 1;
52 static timestamp_t gc_log_expire_time;
62 -static const char *gc_log_expire = "1.day.ago";
63 -static const char *prune_expire = "2.weeks.ago";
64 -static const char *prune_worktrees_expire = "3.months.ago";
65 -static char *repack_filter;
66 -static char *repack_filter_to;
67 -static unsigned long big_pack_threshold;
68 -static unsigned long max_delta_cache_size = DEFAULT_DELTA_CACHE_SIZE;
53
54 static struct strvec reflog = STRVEC_INIT;
55 static struct strvec repack = STRVEC_INIT;
@@ -145,37 +129,71 @@ static int gc_config_is_timestamp_never(const char *var)
129 return 0;
130 }
131
148 -static void gc_config(void)
132 +struct gc_config {
133 + int pack_refs;
134 + int prune_reflogs;
135 + int cruft_packs;
136 + unsigned long max_cruft_size;
137 + int aggressive_depth;
138 + int aggressive_window;
139 + int gc_auto_threshold;
140 + int gc_auto_pack_limit;
141 + int detach_auto;
142 + const char *gc_log_expire;
143 + const char *prune_expire;
144 + const char *prune_worktrees_expire;
145 + char *repack_filter;
146 + char *repack_filter_to;
147 + unsigned long big_pack_threshold;
148 + unsigned long max_delta_cache_size;
149 +};
150 +
151 +#define GC_CONFIG_INIT { \
152 + .pack_refs = 1, \
153 + .prune_reflogs = 1, \
154 + .cruft_packs = 1, \
155 + .aggressive_depth = 50, \
156 + .aggressive_window = 250, \
157 + .gc_auto_threshold = 6700, \
158 + .gc_auto_pack_limit = 50, \
159 + .detach_auto = 1, \
160 + .gc_log_expire = "1.day.ago", \
161 + .prune_expire = "2.weeks.ago", \
162 + .prune_worktrees_expire = "3.months.ago", \
163 + .max_delta_cache_size = DEFAULT_DELTA_CACHE_SIZE, \
164 +}
165 +
166 +static void gc_config(struct gc_config *cfg)
167 {
168 const char *value;
169
170 if (!git_config_get_value("gc.packrefs", &value)) {
171 if (value && !strcmp(value, "notbare"))
154 - pack_refs = -1;
172 + cfg->pack_refs = -1;
173 else
156 - pack_refs = git_config_bool("gc.packrefs", value);
174 + cfg->pack_refs = git_config_bool("gc.packrefs", value);
175 }
176
177 if (gc_config_is_timestamp_never("gc.reflogexpire") &&
178 gc_config_is_timestamp_never("gc.reflogexpireunreachable"))
161 - prune_reflogs = 0;
179 + cfg->prune_reflogs = 0;
180
163 - git_config_get_int("gc.aggressivewindow", &aggressive_window);
164 - git_config_get_int("gc.aggressivedepth", &aggressive_depth);
165 - git_config_get_int("gc.auto", &gc_auto_threshold);
166 - git_config_get_int("gc.autopacklimit", &gc_auto_pack_limit);
167 - git_config_get_bool("gc.autodetach", &detach_auto);
168 - git_config_get_bool("gc.cruftpacks", &cruft_packs);
169 - git_config_get_ulong("gc.maxcruftsize", &max_cruft_size);
170 - git_config_get_expiry("gc.pruneexpire", (char **) &prune_expire);
171 - git_config_get_expiry("gc.worktreepruneexpire", (char **) &prune_worktrees_expire);
172 - git_config_get_expiry("gc.logexpiry", (char **) &gc_log_expire);
181 + git_config_get_int("gc.aggressivewindow", &cfg->aggressive_window);
182 + git_config_get_int("gc.aggressivedepth", &cfg->aggressive_depth);
183 + git_config_get_int("gc.auto", &cfg->gc_auto_threshold);
184 + git_config_get_int("gc.autopacklimit", &cfg->gc_auto_pack_limit);
185 + git_config_get_bool("gc.autodetach", &cfg->detach_auto);
186 + git_config_get_bool("gc.cruftpacks", &cfg->cruft_packs);
187 + git_config_get_ulong("gc.maxcruftsize", &cfg->max_cruft_size);
188 + git_config_get_expiry("gc.pruneexpire", (char **) &cfg->prune_expire);
189 + git_config_get_expiry("gc.worktreepruneexpire", (char **) &cfg->prune_worktrees_expire);
190 + git_config_get_expiry("gc.logexpiry", (char **) &cfg->gc_log_expire);
191
174 - git_config_get_ulong("gc.bigpackthreshold", &big_pack_threshold);
175 - git_config_get_ulong("pack.deltacachesize", &max_delta_cache_size);
192 + git_config_get_ulong("gc.bigpackthreshold", &cfg->big_pack_threshold);
193 + git_config_get_ulong("pack.deltacachesize", &cfg->max_delta_cache_size);
194
177 - git_config_get_string("gc.repackfilter", &repack_filter);
178 - git_config_get_string("gc.repackfilterto", &repack_filter_to);
195 + git_config_get_string("gc.repackfilter", &cfg->repack_filter);
196 + git_config_get_string("gc.repackfilterto", &cfg->repack_filter_to);
197
198 git_config(git_default_config, NULL);
199 }
@@ -206,7 +224,7 @@ struct maintenance_run_opts {
224 enum schedule_priority schedule;
225 };
226
209 -static int pack_refs_condition(void)
227 +static int pack_refs_condition(UNUSED struct gc_config *cfg)
228 {
229 /*
230 * The auto-repacking logic for refs is handled by the ref backends and
@@ -216,7 +234,8 @@ static int pack_refs_condition(void)
234 return 1;
235 }
236
219 -static int maintenance_task_pack_refs(MAYBE_UNUSED struct maintenance_run_opts *opts)
237 +static int maintenance_task_pack_refs(MAYBE_UNUSED struct maintenance_run_opts *opts,
238 + UNUSED struct gc_config *cfg)
239 {
240 struct child_process cmd = CHILD_PROCESS_INIT;
241
@@ -228,7 +247,7 @@ static int maintenance_task_pack_refs(MAYBE_UNUSED struct maintenance_run_opts *
247 return run_command(&cmd);
248 }
249
231 -static int too_many_loose_objects(void)
250 +static int too_many_loose_objects(struct gc_config *cfg)
251 {
252 /*
253 * Quickly check if a "gc" is needed, by estimating how
@@ -247,7 +266,7 @@ static int too_many_loose_objects(void)
266 if (!dir)
267 return 0;
268
250 - auto_threshold = DIV_ROUND_UP(gc_auto_threshold, 256);
269 + auto_threshold = DIV_ROUND_UP(cfg->gc_auto_threshold, 256);
270 while ((ent = readdir(dir)) != NULL) {
271 if (strspn(ent->d_name, "0123456789abcdef") != hexsz_loose ||
272 ent->d_name[hexsz_loose] != '\0')
@@ -283,12 +302,12 @@ static struct packed_git *find_base_packs(struct string_list *packs,
302 return base;
303 }
304
286 -static int too_many_packs(void)
305 +static int too_many_packs(struct gc_config *cfg)
306 {
307 struct packed_git *p;
308 int cnt;
309
291 - if (gc_auto_pack_limit <= 0)
310 + if (cfg->gc_auto_pack_limit <= 0)
311 return 0;
312
313 for (cnt = 0, p = get_all_packs(the_repository); p; p = p->next) {
@@ -302,7 +321,7 @@ static int too_many_packs(void)
321 */
322 cnt++;
323 }
305 - return gc_auto_pack_limit < cnt;
324 + return cfg->gc_auto_pack_limit < cnt;
325 }
326
327 static uint64_t total_ram(void)
@@ -336,7 +355,8 @@ static uint64_t total_ram(void)
355 return 0;
356 }
357
339 -static uint64_t estimate_repack_memory(struct packed_git *pack)
358 +static uint64_t estimate_repack_memory(struct gc_config *cfg,
359 + struct packed_git *pack)
360 {
361 unsigned long nr_objects = repo_approximate_object_count(the_repository);
362 size_t os_cache, heap;
@@ -373,7 +393,7 @@ static uint64_t estimate_repack_memory(struct packed_git *pack)
393 */
394 heap += delta_base_cache_limit;
395 /* and of course pack-objects has its own delta cache */
376 - heap += max_delta_cache_size;
396 + heap += cfg->max_delta_cache_size;
397
398 return os_cache + heap;
399 }
@@ -384,30 +404,31 @@ static int keep_one_pack(struct string_list_item *item, void *data UNUSED)
404 return 0;
405 }
406
387 -static void add_repack_all_option(struct string_list *keep_pack)
407 +static void add_repack_all_option(struct gc_config *cfg,
408 + struct string_list *keep_pack)
409 {
389 - if (prune_expire && !strcmp(prune_expire, "now"))
410 + if (cfg->prune_expire && !strcmp(cfg->prune_expire, "now"))
411 strvec_push(&repack, "-a");
391 - else if (cruft_packs) {
412 + else if (cfg->cruft_packs) {
413 strvec_push(&repack, "--cruft");
393 - if (prune_expire)
394 - strvec_pushf(&repack, "--cruft-expiration=%s", prune_expire);
395 - if (max_cruft_size)
414 + if (cfg->prune_expire)
415 + strvec_pushf(&repack, "--cruft-expiration=%s", cfg->prune_expire);
416 + if (cfg->max_cruft_size)
417 strvec_pushf(&repack, "--max-cruft-size=%lu",
397 - max_cruft_size);
418 + cfg->max_cruft_size);
419 } else {
420 strvec_push(&repack, "-A");
400 - if (prune_expire)
401 - strvec_pushf(&repack, "--unpack-unreachable=%s", prune_expire);
421 + if (cfg->prune_expire)
422 + strvec_pushf(&repack, "--unpack-unreachable=%s", cfg->prune_expire);
423 }
424
425 if (keep_pack)
426 for_each_string_list(keep_pack, keep_one_pack, NULL);
427
407 - if (repack_filter && *repack_filter)
408 - strvec_pushf(&repack, "--filter=%s", repack_filter);
409 - if (repack_filter_to && *repack_filter_to)
410 - strvec_pushf(&repack, "--filter-to=%s", repack_filter_to);
428 + if (cfg->repack_filter && *cfg->repack_filter)
429 + strvec_pushf(&repack, "--filter=%s", cfg->repack_filter);
430 + if (cfg->repack_filter_to && *cfg->repack_filter_to)
431 + strvec_pushf(&repack, "--filter-to=%s", cfg->repack_filter_to);
432 }
433
434 static void add_repack_incremental_option(void)
@@ -415,13 +436,13 @@ static void add_repack_incremental_option(void)
436 strvec_push(&repack, "--no-write-bitmap-index");
437 }
438
418 -static int need_to_gc(void)
439 +static int need_to_gc(struct gc_config *cfg)
440 {
441 /*
442 * Setting gc.auto to 0 or negative can disable the
443 * automatic gc.
444 */
424 - if (gc_auto_threshold <= 0)
445 + if (cfg->gc_auto_threshold <= 0)
446 return 0;
447
448 /*
@@ -430,13 +451,13 @@ static int need_to_gc(void)
451 * we run "repack -A -d -l". Otherwise we tell the caller
452 * there is no need.
453 */
433 - if (too_many_packs()) {
454 + if (too_many_packs(cfg)) {
455 struct string_list keep_pack = STRING_LIST_INIT_NODUP;
456
436 - if (big_pack_threshold) {
437 - find_base_packs(&keep_pack, big_pack_threshold);
438 - if (keep_pack.nr >= gc_auto_pack_limit) {
439 - big_pack_threshold = 0;
457 + if (cfg->big_pack_threshold) {
458 + find_base_packs(&keep_pack, cfg->big_pack_threshold);
459 + if (keep_pack.nr >= cfg->gc_auto_pack_limit) {
460 + cfg->big_pack_threshold = 0;
461 string_list_clear(&keep_pack, 0);
462 find_base_packs(&keep_pack, 0);
463 }
@@ -445,7 +466,7 @@ static int need_to_gc(void)
466 uint64_t mem_have, mem_want;
467
468 mem_have = total_ram();
448 - mem_want = estimate_repack_memory(p);
469 + mem_want = estimate_repack_memory(cfg, p);
470
471 /*
472 * Only allow 1/2 of memory for pack-objects, leave
@@ -456,9 +477,9 @@ static int need_to_gc(void)
477 string_list_clear(&keep_pack, 0);
478 }
479
459 - add_repack_all_option(&keep_pack);
480 + add_repack_all_option(cfg, &keep_pack);
481 string_list_clear(&keep_pack, 0);
461 - } else if (too_many_loose_objects())
482 + } else if (too_many_loose_objects(cfg))
483 add_repack_incremental_option();
484 else
485 return 0;
@@ -585,7 +606,8 @@ done:
606 return ret;
607 }
608
588 -static void gc_before_repack(struct maintenance_run_opts *opts)
609 +static void gc_before_repack(struct maintenance_run_opts *opts,
610 + struct gc_config *cfg)
611 {
612 /*
613 * We may be called twice, as both the pre- and
@@ -596,10 +618,10 @@ static void gc_before_repack(struct maintenance_run_opts *opts)
618 if (done++)
619 return;
620
599 - if (pack_refs && maintenance_task_pack_refs(opts))
621 + if (cfg->pack_refs && maintenance_task_pack_refs(opts, cfg))
622 die(FAILED_RUN, "pack-refs");
623
602 - if (prune_reflogs) {
624 + if (cfg->prune_reflogs) {
625 struct child_process cmd = CHILD_PROCESS_INIT;
626
627 cmd.git_cmd = 1;
@@ -621,14 +643,15 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
643 timestamp_t dummy;
644 struct child_process rerere_cmd = CHILD_PROCESS_INIT;
645 struct maintenance_run_opts opts = {0};
646 + struct gc_config cfg = GC_CONFIG_INIT;
647
648 struct option builtin_gc_options[] = {
649 OPT__QUIET(&quiet, N_("suppress progress reporting")),
627 - { OPTION_STRING, 0, "prune", &prune_expire, N_("date"),
650 + { OPTION_STRING, 0, "prune", &cfg.prune_expire, N_("date"),
651 N_("prune unreferenced objects"),
629 - PARSE_OPT_OPTARG, NULL, (intptr_t)prune_expire },
630 - OPT_BOOL(0, "cruft", &cruft_packs, N_("pack unreferenced objects separately")),
631 - OPT_MAGNITUDE(0, "max-cruft-size", &max_cruft_size,
652 + PARSE_OPT_OPTARG, NULL, (intptr_t)cfg.prune_expire },
653 + OPT_BOOL(0, "cruft", &cfg.cruft_packs, N_("pack unreferenced objects separately")),
654 + OPT_MAGNITUDE(0, "max-cruft-size", &cfg.max_cruft_size,
655 N_("with --cruft, limit the size of new cruft packs")),
656 OPT_BOOL(0, "aggressive", &aggressive, N_("be more thorough (increased runtime)")),
657 OPT_BOOL_F(0, "auto", &opts.auto_flag, N_("enable auto-gc mode"),
@@ -651,27 +674,27 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
674 strvec_pushl(&rerere, "rerere", "gc", NULL);
675
676 /* default expiry time, overwritten in gc_config */
654 - gc_config();
655 - if (parse_expiry_date(gc_log_expire, &gc_log_expire_time))
656 - die(_("failed to parse gc.logExpiry value %s"), gc_log_expire);
677 + gc_config(&cfg);
678 + if (parse_expiry_date(cfg.gc_log_expire, &gc_log_expire_time))
679 + die(_("failed to parse gc.logExpiry value %s"), cfg.gc_log_expire);
680
658 - if (pack_refs < 0)
659 - pack_refs = !is_bare_repository();
681 + if (cfg.pack_refs < 0)
682 + cfg.pack_refs = !is_bare_repository();
683
684 argc = parse_options(argc, argv, prefix, builtin_gc_options,
685 builtin_gc_usage, 0);
686 if (argc > 0)
687 usage_with_options(builtin_gc_usage, builtin_gc_options);
688
666 - if (prune_expire && parse_expiry_date(prune_expire, &dummy))
667 - die(_("failed to parse prune expiry value %s"), prune_expire);
689 + if (cfg.prune_expire && parse_expiry_date(cfg.prune_expire, &dummy))
690 + die(_("failed to parse prune expiry value %s"), cfg.prune_expire);
691
692 if (aggressive) {
693 strvec_push(&repack, "-f");
671 - if (aggressive_depth > 0)
672 - strvec_pushf(&repack, "--depth=%d", aggressive_depth);
673 - if (aggressive_window > 0)
674 - strvec_pushf(&repack, "--window=%d", aggressive_window);
694 + if (cfg.aggressive_depth > 0)
695 + strvec_pushf(&repack, "--depth=%d", cfg.aggressive_depth);
696 + if (cfg.aggressive_window > 0)
697 + strvec_pushf(&repack, "--window=%d", cfg.aggressive_window);
698 }
699 if (quiet)
700 strvec_push(&repack, "-q");
@@ -680,16 +703,16 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
703 /*
704 * Auto-gc should be least intrusive as possible.
705 */
683 - if (!need_to_gc())
706 + if (!need_to_gc(&cfg))
707 return 0;
708 if (!quiet) {
686 - if (detach_auto)
709 + if (cfg.detach_auto)
710 fprintf(stderr, _("Auto packing the repository in background for optimum performance.\n"));
711 else
712 fprintf(stderr, _("Auto packing the repository for optimum performance.\n"));
713 fprintf(stderr, _("See \"git help gc\" for manual housekeeping.\n"));
714 }
692 - if (detach_auto) {
715 + if (cfg.detach_auto) {
716 int ret = report_last_gc_error();
717
718 if (ret == 1)
@@ -701,7 +724,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
724
725 if (lock_repo_for_gc(force, &pid))
726 return 0;
704 - gc_before_repack(&opts); /* dies on failure */
727 + gc_before_repack(&opts, &cfg); /* dies on failure */
728 delete_tempfile(&pidfile);
729
730 /*
@@ -716,11 +739,11 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
739 if (keep_largest_pack != -1) {
740 if (keep_largest_pack)
741 find_base_packs(&keep_pack, 0);
719 - } else if (big_pack_threshold) {
720 - find_base_packs(&keep_pack, big_pack_threshold);
742 + } else if (cfg.big_pack_threshold) {
743 + find_base_packs(&keep_pack, cfg.big_pack_threshold);
744 }
745
723 - add_repack_all_option(&keep_pack);
746 + add_repack_all_option(&cfg, &keep_pack);
747 string_list_clear(&keep_pack, 0);
748 }
749
@@ -741,7 +764,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
764 atexit(process_log_file_at_exit);
765 }
766
744 - gc_before_repack(&opts);
767 + gc_before_repack(&opts, &cfg);
768
769 if (!repository_format_precious_objects) {
770 struct child_process repack_cmd = CHILD_PROCESS_INIT;
@@ -752,11 +775,11 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
775 if (run_command(&repack_cmd))
776 die(FAILED_RUN, repack.v[0]);
777
755 - if (prune_expire) {
778 + if (cfg.prune_expire) {
779 struct child_process prune_cmd = CHILD_PROCESS_INIT;
780
781 /* run `git prune` even if using cruft packs */
759 - strvec_push(&prune, prune_expire);
782 + strvec_push(&prune, cfg.prune_expire);
783 if (quiet)
784 strvec_push(&prune, "--no-progress");
785 if (repo_has_promisor_remote(the_repository))
@@ -769,10 +792,10 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
792 }
793 }
794
772 - if (prune_worktrees_expire) {
795 + if (cfg.prune_worktrees_expire) {
796 struct child_process prune_worktrees_cmd = CHILD_PROCESS_INIT;
797
775 - strvec_push(&prune_worktrees, prune_worktrees_expire);
798 + strvec_push(&prune_worktrees, cfg.prune_worktrees_expire);
799 prune_worktrees_cmd.git_cmd = 1;
800 strvec_pushv(&prune_worktrees_cmd.args, prune_worktrees.v);
801 if (run_command(&prune_worktrees_cmd))
@@ -796,7 +819,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
819 !quiet && !daemonized ? COMMIT_GRAPH_WRITE_PROGRESS : 0,
820 NULL);
821
799 - if (opts.auto_flag && too_many_loose_objects())
822 + if (opts.auto_flag && too_many_loose_objects(&cfg))
823 warning(_("There are too many unreachable loose objects; "
824 "run 'git prune' to remove them."));
825
@@ -892,7 +915,7 @@ static int dfs_on_ref(const char *refname UNUSED,
915 return result;
916 }
917
895 -static int should_write_commit_graph(void)
918 +static int should_write_commit_graph(struct gc_config *cfg)
919 {
920 int result;
921 struct cg_auto_data data;
@@ -929,7 +952,8 @@ static int run_write_commit_graph(struct maintenance_run_opts *opts)
952 return !!run_command(&child);
953 }
954
932 -static int maintenance_task_commit_graph(struct maintenance_run_opts *opts)
955 +static int maintenance_task_commit_graph(struct maintenance_run_opts *opts,
956 + struct gc_config *cfg)
957 {
958 prepare_repo_settings(the_repository);
959 if (!the_repository->settings.core_commit_graph)
@@ -963,7 +987,8 @@ static int fetch_remote(struct remote *remote, void *cbdata)
987 return !!run_command(&child);
988 }
989
966 -static int maintenance_task_prefetch(struct maintenance_run_opts *opts)
990 +static int maintenance_task_prefetch(struct maintenance_run_opts *opts,
991 + struct gc_config *cfg)
992 {
993 if (for_each_remote(fetch_remote, opts)) {
994 error(_("failed to prefetch remotes"));
@@ -973,7 +998,8 @@ static int maintenance_task_prefetch(struct maintenance_run_opts *opts)
998 return 0;
999 }
1000
976 -static int maintenance_task_gc(struct maintenance_run_opts *opts)
1001 +static int maintenance_task_gc(struct maintenance_run_opts *opts,
1002 + struct gc_config *cfg)
1003 {
1004 struct child_process child = CHILD_PROCESS_INIT;
1005
@@ -1021,7 +1047,7 @@ static int loose_object_count(const struct object_id *oid UNUSED,
1047 return 0;
1048 }
1049
1024 -static int loose_object_auto_condition(void)
1050 +static int loose_object_auto_condition(struct gc_config *cfg)
1051 {
1052 int count = 0;
1053
@@ -1106,12 +1132,13 @@ static int pack_loose(struct maintenance_run_opts *opts)
1132 return result;
1133 }
1134
1109 -static int maintenance_task_loose_objects(struct maintenance_run_opts *opts)
1135 +static int maintenance_task_loose_objects(struct maintenance_run_opts *opts,
1136 + struct gc_config *cfg)
1137 {
1138 return prune_packed(opts) || pack_loose(opts);
1139 }
1140
1114 -static int incremental_repack_auto_condition(void)
1141 +static int incremental_repack_auto_condition(struct gc_config *cfg)
1142 {
1143 struct packed_git *p;
1144 int incremental_repack_auto_limit = 10;
@@ -1230,7 +1257,8 @@ static int multi_pack_index_repack(struct maintenance_run_opts *opts)
1257 return 0;
1258 }
1259
1233 -static int maintenance_task_incremental_repack(struct maintenance_run_opts *opts)
1260 +static int maintenance_task_incremental_repack(struct maintenance_run_opts *opts,
1261 + struct gc_config *cfg)
1262 {
1263 prepare_repo_settings(the_repository);
1264 if (!the_repository->settings.core_multi_pack_index) {
@@ -1247,14 +1275,15 @@ static int maintenance_task_incremental_repack(struct maintenance_run_opts *opts
1275 return 0;
1276 }
1277
1250 -typedef int maintenance_task_fn(struct maintenance_run_opts *opts);
1278 +typedef int maintenance_task_fn(struct maintenance_run_opts *opts,
1279 + struct gc_config *cfg);
1280
1281 /*
1282 * An auto condition function returns 1 if the task should run
1283 * and 0 if the task should NOT run. See needs_to_gc() for an
1284 * example.
1285 */
1257 -typedef int maintenance_auto_fn(void);
1286 +typedef int maintenance_auto_fn(struct gc_config *cfg);
1287
1288 struct maintenance_task {
1289 const char *name;
@@ -1321,7 +1350,8 @@ static int compare_tasks_by_selection(const void *a_, const void *b_)
1350 return b->selected_order - a->selected_order;
1351 }
1352
1324 -static int maintenance_run_tasks(struct maintenance_run_opts *opts)
1353 +static int maintenance_run_tasks(struct maintenance_run_opts *opts,
1354 + struct gc_config *cfg)
1355 {
1356 int i, found_selected = 0;
1357 int result = 0;
@@ -1360,14 +1390,14 @@ static int maintenance_run_tasks(struct maintenance_run_opts *opts)
1390
1391 if (opts->auto_flag &&
1392 (!tasks[i].auto_condition ||
1363 - !tasks[i].auto_condition()))
1393 + !tasks[i].auto_condition(cfg)))
1394 continue;
1395
1396 if (opts->schedule && tasks[i].schedule < opts->schedule)
1397 continue;
1398
1399 trace2_region_enter("maintenance", tasks[i].name, r);
1370 - if (tasks[i].fn(opts)) {
1400 + if (tasks[i].fn(opts, cfg)) {
1401 error(_("task '%s' failed"), tasks[i].name);
1402 result = 1;
1403 }
@@ -1404,7 +1434,6 @@ static void initialize_task_config(int schedule)
1434 {
1435 int i;
1436 struct strbuf config_name = STRBUF_INIT;
1407 - gc_config();
1437
1438 if (schedule)
1439 initialize_maintenance_strategy();
@@ -1468,6 +1497,7 @@ static int maintenance_run(int argc, const char **argv, const char *prefix)
1497 {
1498 int i;
1499 struct maintenance_run_opts opts;
1500 + struct gc_config cfg = GC_CONFIG_INIT;
1501 struct option builtin_maintenance_run_options[] = {
1502 OPT_BOOL(0, "auto", &opts.auto_flag,
1503 N_("run tasks based on the state of the repository")),
@@ -1496,12 +1526,13 @@ static int maintenance_run(int argc, const char **argv, const char *prefix)
1526 if (opts.auto_flag && opts.schedule)
1527 die(_("use at most one of --auto and --schedule=<frequency>"));
1528
1529 + gc_config(&cfg);
1530 initialize_task_config(opts.schedule);
1531
1532 if (argc != 0)
1533 usage_with_options(builtin_maintenance_run_usage,
1534 builtin_maintenance_run_options);
1504 - return maintenance_run_tasks(&opts);
1535 + return maintenance_run_tasks(&opts, &cfg);
1536 }
1537
1538 static char *get_maintpath(void)