environment: move "core_sparse_checkout_cone" into `struct repo_config_values`

The `core.sparseCheckoutCone` configuration was previously stored in an uninitialized global `int` variable, risking cross‑repository state leakage. Move it into `repo_config_values`, where eagerly‑parsed repository configuration lives. `core.sparseCheckoutCone` is parsed eagerly because it determines the fundamental sparse‑checkout mode and is consulted very early during repository setup; a lazy parse could leave the sparse‑checkout state undefined and complicate libification. This preserves the existing behavior while tying the value to the repository from which it was read, avoiding cross‑ repository state leakage and continuing the effort to reduce reliance on global configuration state. Update all references to use `repo_config_values()`. Mentored-by: Christian Couder <christian.couder@gmail.com> Mentored-by: Usman Akinyemi <usmanakinyemi202@gmail.com> Signed-off-by: Olamide Caleb Bello <belkid98@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Olamide Caleb Bello committed Jun 2, 2026 at 18:09 UTC dfa01cee1cb4d5e6c8567828370eb4785f7c33a1
6 files changed +29 -21
builtin/mv.c
+1 -1
@@ -574,7 +574,7 @@ remove_entry:
574
575 if (ignore_sparse &&
576 cfg->apply_sparse_checkout &&
577 - core_sparse_checkout_cone) {
577 + cfg->core_sparse_checkout_cone) {
578 /*
579 * NEEDSWORK: we are *not* paying attention to
580 * "out-to-out" move (<source> is out-of-cone and
builtin/sparse-checkout.c
+22 -15
@@ -73,7 +73,7 @@ static int sparse_checkout_list(int argc, const char **argv, const char *prefix,
73
74 memset(&pl, 0, sizeof(pl));
75
76 - pl.use_cone_patterns = core_sparse_checkout_cone;
76 + pl.use_cone_patterns = cfg->core_sparse_checkout_cone;
77
78 sparse_filename = get_sparse_checkout_filename();
79 res = add_patterns_from_file_to_list(sparse_filename, "", 0, &pl, NULL, 0);
@@ -334,6 +334,7 @@ static int write_patterns_and_update(struct repository *repo,
334 FILE *fp;
335 struct lock_file lk = LOCK_INIT;
336 int result;
337 + struct repo_config_values *cfg = repo_config_values(the_repository);
338
339 sparse_filename = get_sparse_checkout_filename();
340
@@ -353,7 +354,7 @@ static int write_patterns_and_update(struct repository *repo,
354 if (!fp)
355 die_errno(_("unable to fdopen %s"), get_lock_file_path(&lk));
356
356 - if (core_sparse_checkout_cone)
357 + if (cfg->core_sparse_checkout_cone)
358 write_cone_to_file(fp, pl);
359 else
360 write_patterns_to_file(fp, pl);
@@ -402,15 +403,15 @@ static enum sparse_checkout_mode update_cone_mode(int *cone_mode) {
403
404 /* If not specified, use previous definition of cone mode */
405 if (*cone_mode == -1 && cfg->apply_sparse_checkout)
405 - *cone_mode = core_sparse_checkout_cone;
406 + *cone_mode = cfg->core_sparse_checkout_cone;
407
408 /* Set cone/non-cone mode appropriately */
409 cfg->apply_sparse_checkout = 1;
410 if (*cone_mode == 1 || *cone_mode == -1) {
410 - core_sparse_checkout_cone = 1;
411 + cfg->core_sparse_checkout_cone = 1;
412 return MODE_CONE_PATTERNS;
413 }
413 - core_sparse_checkout_cone = 0;
414 + cfg->core_sparse_checkout_cone = 0;
415 return MODE_ALL_PATTERNS;
416 }
417
@@ -577,7 +578,9 @@ static void add_patterns_from_input(struct pattern_list *pl,
578 FILE *file)
579 {
580 int i;
580 - if (core_sparse_checkout_cone) {
581 + struct repo_config_values *cfg = repo_config_values(the_repository);
582 +
583 + if (cfg->core_sparse_checkout_cone) {
584 struct strbuf line = STRBUF_INIT;
585
586 hashmap_init(&pl->recursive_hashmap, pl_hashmap_cmp, NULL, 0);
@@ -636,13 +639,14 @@ static void add_patterns_cone_mode(int argc, const char **argv,
639 struct pattern_entry *pe;
640 struct hashmap_iter iter;
641 struct pattern_list existing;
642 + struct repo_config_values *cfg = repo_config_values(the_repository);
643 char *sparse_filename = get_sparse_checkout_filename();
644
645 add_patterns_from_input(pl, argc, argv,
646 use_stdin ? stdin : NULL);
647
648 memset(&existing, 0, sizeof(existing));
645 - existing.use_cone_patterns = core_sparse_checkout_cone;
649 + existing.use_cone_patterns = cfg->core_sparse_checkout_cone;
650
651 if (add_patterns_from_file_to_list(sparse_filename, "", 0,
652 &existing, NULL, 0))
@@ -690,7 +694,7 @@ static int modify_pattern_list(struct repository *repo,
694
695 switch (m) {
696 case ADD:
693 - if (core_sparse_checkout_cone)
697 + if (cfg->core_sparse_checkout_cone)
698 add_patterns_cone_mode(args->nr, args->v, pl, use_stdin);
699 else
700 add_patterns_literal(args->nr, args->v, pl, use_stdin);
@@ -723,11 +727,12 @@ static void sanitize_paths(struct repository *repo,
727 const char *prefix, int skip_checks)
728 {
729 int i;
730 + struct repo_config_values *cfg = repo_config_values(the_repository);
731
732 if (!args->nr)
733 return;
734
730 - if (prefix && *prefix && core_sparse_checkout_cone) {
735 + if (prefix && *prefix && cfg->core_sparse_checkout_cone) {
736 /*
737 * The args are not pathspecs, so unfortunately we
738 * cannot imitate how cmd_add() uses parse_pathspec().
@@ -744,10 +749,10 @@ static void sanitize_paths(struct repository *repo,
749 if (skip_checks)
750 return;
751
747 - if (prefix && *prefix && !core_sparse_checkout_cone)
752 + if (prefix && *prefix && !cfg->core_sparse_checkout_cone)
753 die(_("please run from the toplevel directory in non-cone mode"));
754
750 - if (core_sparse_checkout_cone) {
755 + if (cfg->core_sparse_checkout_cone) {
756 for (i = 0; i < args->nr; i++) {
757 if (args->v[i][0] == '/')
758 die(_("specify directories rather than patterns (no leading slash)"));
@@ -769,7 +774,7 @@ static void sanitize_paths(struct repository *repo,
774 if (S_ISSPARSEDIR(ce->ce_mode))
775 continue;
776
772 - if (core_sparse_checkout_cone)
777 + if (cfg->core_sparse_checkout_cone)
778 die(_("'%s' is not a directory; to treat it as a directory anyway, rerun with --skip-checks"), args->v[i]);
779 else
780 warning(_("pass a leading slash before paths such as '%s' if you want a single file (see NON-CONE PROBLEMS in the git-sparse-checkout manual)."), args->v[i]);
@@ -836,6 +841,7 @@ static struct sparse_checkout_set_opts {
841 static int sparse_checkout_set(int argc, const char **argv, const char *prefix,
842 struct repository *repo)
843 {
844 + struct repo_config_values *cfg = repo_config_values(the_repository);
845 int default_patterns_nr = 2;
846 const char *default_patterns[] = {"/*", "!/*/", NULL};
847
@@ -873,7 +879,7 @@ static int sparse_checkout_set(int argc, const char **argv, const char *prefix,
879 * non-cone mode, if nothing is specified, manually select just the
880 * top-level directory (much as 'init' would do).
881 */
876 - if (!core_sparse_checkout_cone && !set_opts.use_stdin && argc == 0) {
882 + if (!cfg->core_sparse_checkout_cone && !set_opts.use_stdin && argc == 0) {
883 for (int i = 0; i < default_patterns_nr; i++)
884 strvec_push(&patterns, default_patterns[i]);
885 } else {
@@ -977,7 +983,7 @@ static int sparse_checkout_clean(int argc, const char **argv,
983 setup_work_tree();
984 if (!cfg->apply_sparse_checkout)
985 die(_("must be in a sparse-checkout to clean directories"));
980 - if (!core_sparse_checkout_cone)
986 + if (!cfg->core_sparse_checkout_cone)
987 die(_("must be in a cone-mode sparse-checkout to clean directories"));
988
989 argc = parse_options(argc, argv, prefix,
@@ -1141,6 +1147,7 @@ static int sparse_checkout_check_rules(int argc, const char **argv, const char *
1147 FILE *fp;
1148 int ret;
1149 struct pattern_list pl = {0};
1150 + struct repo_config_values *cfg = repo_config_values(the_repository);
1151 char *sparse_filename;
1152 check_rules_opts.cone_mode = -1;
1153
@@ -1152,7 +1159,7 @@ static int sparse_checkout_check_rules(int argc, const char **argv, const char *
1159 check_rules_opts.cone_mode = 1;
1160
1161 update_cone_mode(&check_rules_opts.cone_mode);
1155 - pl.use_cone_patterns = core_sparse_checkout_cone;
1162 + pl.use_cone_patterns = cfg->core_sparse_checkout_cone;
1163 if (check_rules_opts.rules_file) {
1164 fp = xfopen(check_rules_opts.rules_file, "r");
1165 add_patterns_from_input(&pl, argc, argv, fp);
dir.c
+2 -1
@@ -3508,8 +3508,9 @@ int get_sparse_checkout_patterns(struct pattern_list *pl)
3508 {
3509 int res;
3510 char *sparse_filename = get_sparse_checkout_filename();
3511 + struct repo_config_values *cfg = repo_config_values(the_repository);
3512
3512 - pl->use_cone_patterns = core_sparse_checkout_cone;
3513 + pl->use_cone_patterns = cfg->core_sparse_checkout_cone;
3514 res = add_patterns_from_file_to_list(sparse_filename, "", 0, pl, NULL, 0);
3515
3516 free(sparse_filename);
environment.c
+2 -2
@@ -70,7 +70,6 @@ enum push_default_type push_default = PUSH_DEFAULT_UNSPECIFIED;
70 #endif
71 enum object_creation_mode object_creation_mode = OBJECT_CREATION_MODE;
72 int grafts_keep_true_parents;
73 -int core_sparse_checkout_cone;
73 int sparse_expect_files_outside_of_patterns;
74 unsigned long pack_size_limit_cfg;
75
@@ -526,7 +525,7 @@ int git_default_core_config(const char *var, const char *value,
525 }
526
527 if (!strcmp(var, "core.sparsecheckoutcone")) {
529 - core_sparse_checkout_cone = git_config_bool(var, value);
528 + cfg->core_sparse_checkout_cone = git_config_bool(var, value);
529 return 0;
530 }
531
@@ -723,4 +722,5 @@ void repo_config_values_init(struct repo_config_values *cfg)
722 cfg->zlib_compression_level = Z_BEST_SPEED;
723 cfg->pack_compression_level = Z_DEFAULT_COMPRESSION;
724 cfg->precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */
725 + cfg->core_sparse_checkout_cone = 0;
726 }
environment.h
+1 -1
@@ -96,6 +96,7 @@ struct repo_config_values {
96 int zlib_compression_level;
97 int pack_compression_level;
98 int precomposed_unicode;
99 + int core_sparse_checkout_cone;
100
101 /* section "branch" config values */
102 enum branch_track branch_track;
@@ -178,7 +179,6 @@ extern unsigned long pack_size_limit_cfg;
179 extern int protect_hfs;
180 extern int protect_ntfs;
181
181 -extern int core_sparse_checkout_cone;
182 extern int sparse_expect_files_outside_of_patterns;
183
184 enum rebase_setup_type {
sparse-index.c
+1 -1
@@ -154,7 +154,7 @@ int is_sparse_index_allowed(struct index_state *istate, int flags)
154 {
155 struct repo_config_values *cfg = repo_config_values(the_repository);
156
157 - if (!cfg->apply_sparse_checkout || !core_sparse_checkout_cone)
157 + if (!cfg->apply_sparse_checkout || !cfg->core_sparse_checkout_cone)
158 return 0;
159
160 if (!(flags & SPARSE_INDEX_MEMORY_ONLY)) {