From bb695a02529f458e43b6bbf143a08454d15d320e Mon Sep 17 00:00:00 2001 From: Olamide Caleb Bello Date: Tue, 13 Jan 2026 10:22:24 +0100 Subject: [PATCH 01/11] environment: stop storing `core.attributesFile` globally The `core.attributeFile` config value is parsed in git_default_core_config(), loaded eagerly and stored in the global variable `git_attributes_file`. Storing this value in a global variable can lead to it being overwritten by another repository when more than one Git repository run in the same Git process. Create a new struct `repo_config_values` to hold this value and other repository dependent values parsed by `git_default_config()`. This will ensure the current behaviour remains the same while also enabling the libification of Git. An accessor function 'repo_config_values()' is created. It checks if the address of the passed `repo` instance is the same as `the_repository` and also if the repository instance has been initialized before returning the struct. Suggested-by: Phillip Wood Mentored-by: Christian Couder Mentored-by: Usman Akinyemi Helped-by: Junio C Hamano Signed-off-by: Olamide Caleb Bello --- attr.c | 7 ++++--- environment.c | 12 +++++++++--- environment.h | 11 ++++++++++- oss-fuzz/fuzz-commit-graph.c | 1 + repository.c | 14 ++++++++++++++ repository.h | 7 +++++++ 6 files changed, 45 insertions(+), 7 deletions(-) diff --git a/attr.c b/attr.c index 4999b7e09da930..75369547b306d6 100644 --- a/attr.c +++ b/attr.c @@ -881,10 +881,11 @@ const char *git_attr_system_file(void) const char *git_attr_global_file(void) { - if (!git_attributes_file) - git_attributes_file = xdg_config_home("attributes"); + struct repo_config_values *cfg = repo_config_values(the_repository); + if (!cfg->attributes_file) + cfg->attributes_file = xdg_config_home("attributes"); - return git_attributes_file; + return cfg->attributes_file; } int git_attr_system_is_enabled(void) diff --git a/environment.c b/environment.c index 0026eb227487dd..76b54d99694deb 100644 --- a/environment.c +++ b/environment.c @@ -54,7 +54,6 @@ char *git_commit_encoding; char *git_log_output_encoding; char *apply_default_whitespace; char *apply_default_ignorewhitespace; -char *git_attributes_file; int zlib_compression_level = Z_BEST_SPEED; int pack_compression_level = Z_DEFAULT_COMPRESSION; int fsync_object_files = -1; @@ -304,6 +303,8 @@ static enum fsync_component parse_fsync_components(const char *var, const char * int git_default_core_config(const char *var, const char *value, const struct config_context *ctx, void *cb) { + struct repo_config_values *cfg = repo_config_values(the_repository); + /* This needs a better name */ if (!strcmp(var, "core.filemode")) { trust_executable_bit = git_config_bool(var, value); @@ -341,8 +342,8 @@ int git_default_core_config(const char *var, const char *value, } if (!strcmp(var, "core.attributesfile")) { - FREE_AND_NULL(git_attributes_file); - return git_config_pathname(&git_attributes_file, var, value); + FREE_AND_NULL(cfg->attributes_file); + return git_config_pathname(&cfg->attributes_file, var, value); } if (!strcmp(var, "core.bare")) { @@ -733,3 +734,8 @@ int git_default_config(const char *var, const char *value, /* Add other config variables here and to Documentation/config.adoc. */ return 0; } + +void repo_config_values_init(struct repo_config_values *cfg) +{ + cfg->attributes_file = NULL; +} diff --git a/environment.h b/environment.h index 27f657af046a51..0919e1d06d713e 100644 --- a/environment.h +++ b/environment.h @@ -84,6 +84,14 @@ extern const char * const local_repo_env[]; struct strvec; +struct repository; +struct repo_config_values { + /* section "core" config values */ + char *attributes_file; +}; + +struct repo_config_values *repo_config_values(struct repository *repo); + /* * Wrapper of getenv() that returns a strdup value. This value is kept * in argv to be freed later. @@ -109,6 +117,8 @@ int git_default_config(const char *, const char *, int git_default_core_config(const char *var, const char *value, const struct config_context *ctx, void *cb); +void repo_config_values_init(struct repo_config_values *cfg); + /* * TODO: All the below state either explicitly or implicitly relies on * `the_repository`. We should eventually get rid of these and make the @@ -154,7 +164,6 @@ extern int assume_unchanged; extern int warn_on_object_refname_ambiguity; extern char *apply_default_whitespace; extern char *apply_default_ignorewhitespace; -extern char *git_attributes_file; extern int zlib_compression_level; extern int pack_compression_level; extern unsigned long pack_size_limit_cfg; diff --git a/oss-fuzz/fuzz-commit-graph.c b/oss-fuzz/fuzz-commit-graph.c index fb8b8787a460f1..59bbb849d1e1c4 100644 --- a/oss-fuzz/fuzz-commit-graph.c +++ b/oss-fuzz/fuzz-commit-graph.c @@ -10,6 +10,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { struct commit_graph *g; + memset(the_repository, 0, sizeof(*the_repository)); initialize_repository(the_repository); /* diff --git a/repository.c b/repository.c index 46a7c999302a4c..0207bcb2994d9f 100644 --- a/repository.c +++ b/repository.c @@ -50,13 +50,27 @@ static void set_default_hash_algo(struct repository *repo) repo_set_hash_algo(repo, algo); } +struct repo_config_values *repo_config_values(struct repository *repo) +{ + if (repo != the_repository) + BUG("trying to read config from wrong repository instance"); + if(!repo->initialized) + BUG("config values from uninitialized repository"); + return &repo->config_values_private_; +} + void initialize_repository(struct repository *repo) { + if (repo->initialized) + BUG("repository initialized already"); + repo->initialized = true; + repo->remote_state = remote_state_new(); repo->parsed_objects = parsed_object_pool_new(repo); ALLOC_ARRAY(repo->index, 1); index_state_init(repo->index, repo); repo->check_deprecated_config = true; + repo_config_values_init(&repo->config_values_private_); /* * When a command runs inside a repository, it learns what diff --git a/repository.h b/repository.h index 7141237f97d87d..b1c69acc570429 100644 --- a/repository.h +++ b/repository.h @@ -3,6 +3,7 @@ #include "strmap.h" #include "repo-settings.h" +#include "environment.h" struct config_set; struct git_hash_algo; @@ -148,6 +149,9 @@ struct repository { /* Repository's compatibility hash algorithm. */ const struct git_hash_algo *compat_hash_algo; + /* Repository's config values parsed by git_default_config() */ + struct repo_config_values config_values_private_; + /* Repository's reference storage format, as serialized on disk. */ enum ref_storage_format ref_storage_format; @@ -172,6 +176,9 @@ struct repository { /* Should repo_config() check for deprecated settings */ bool check_deprecated_config; + + /* Has this repository instance been initialized? */ + bool initialized; }; #ifdef USE_THE_REPOSITORY_VARIABLE From 5538509e38c819c799b3826cb8fb96605f8cafba Mon Sep 17 00:00:00 2001 From: Olamide Caleb Bello Date: Sat, 24 Jan 2026 11:22:41 +0100 Subject: [PATCH 02/11] environment: stop using core.sparseCheckout globally The config value `core.sparseCheckout` is parsed in `git_default_core_config()` and stored globally in `core_apply_sparse_checkout`. This could cause it to be overwritten by another repository when different Git repositories run in the same process. Move the parsed value into `struct repo_config_values` in the_repository to retain current behaviours and move towards libifying Git. Suggested-by: Phillip Wood Mentored-by: Christian Couder Mentored-by: Usman Akinyemi Signed-off-by: Olamide Caleb Bello --- builtin/backfill.c | 3 ++- builtin/clone.c | 4 +++- builtin/grep.c | 2 +- builtin/mv.c | 3 ++- builtin/sparse-checkout.c | 31 ++++++++++++++++++++----------- builtin/worktree.c | 3 ++- dir.c | 4 +++- environment.c | 4 ++-- environment.h | 2 +- sparse-index.c | 7 +++++-- unpack-trees.c | 3 ++- wt-status.c | 4 +++- 12 files changed, 46 insertions(+), 24 deletions(-) diff --git a/builtin/backfill.c b/builtin/backfill.c index e80fc1b694df61..9b2ca57b6adec8 100644 --- a/builtin/backfill.c +++ b/builtin/backfill.c @@ -129,6 +129,7 @@ int cmd_backfill(int argc, const char **argv, const char *prefix, struct reposit N_("Restrict the missing objects to the current sparse-checkout")), OPT_END(), }; + struct repo_config_values *cfg = repo_config_values(the_repository); show_usage_with_options_if_asked(argc, argv, builtin_backfill_usage, options); @@ -139,7 +140,7 @@ int cmd_backfill(int argc, const char **argv, const char *prefix, struct reposit repo_config(repo, git_default_config, NULL); if (ctx.sparse < 0) - ctx.sparse = core_apply_sparse_checkout; + ctx.sparse = cfg->apply_sparse_checkout; result = do_backfill(&ctx); backfill_context_clear(&ctx); diff --git a/builtin/clone.c b/builtin/clone.c index b14a39a687c840..9d4dbd12abef7c 100644 --- a/builtin/clone.c +++ b/builtin/clone.c @@ -617,13 +617,15 @@ static int git_sparse_checkout_init(const char *repo) { struct child_process cmd = CHILD_PROCESS_INIT; int result = 0; + struct repo_config_values *cfg = repo_config_values(the_repository); + strvec_pushl(&cmd.args, "-C", repo, "sparse-checkout", "set", NULL); /* * We must apply the setting in the current process * for the later checkout to use the sparse-checkout file. */ - core_apply_sparse_checkout = 1; + cfg->apply_sparse_checkout = 1; cmd.git_cmd = 1; if (run_command(&cmd)) { diff --git a/builtin/grep.c b/builtin/grep.c index 5b8b87b1ac4d7a..b6cecfd9b60f05 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -482,7 +482,7 @@ static int grep_submodule(struct grep_opt *opt, * "forget" the sparse-index feature switch. As a result, the index * of these submodules are expanded unexpectedly. * - * 2. "core_apply_sparse_checkout" + * 2. "config_values_private_.apply_sparse_checkout" * When running `grep` in the superproject, this setting is * populated using the superproject's configs. However, once * initialized, this config is globally accessible and is read by diff --git a/builtin/mv.c b/builtin/mv.c index d43925097b420f..2215d34e31f29a 100644 --- a/builtin/mv.c +++ b/builtin/mv.c @@ -238,6 +238,7 @@ int cmd_mv(int argc, struct hashmap moved_dirs = HASHMAP_INIT(pathmap_cmp, NULL); struct strbuf pathbuf = STRBUF_INIT; int ret; + struct repo_config_values *cfg = repo_config_values(the_repository); repo_config(the_repository, git_default_config, NULL); @@ -572,7 +573,7 @@ int cmd_mv(int argc, rename_index_entry_at(the_repository->index, pos, dst); if (ignore_sparse && - core_apply_sparse_checkout && + cfg->apply_sparse_checkout && core_sparse_checkout_cone) { /* * NEEDSWORK: we are *not* paying attention to diff --git a/builtin/sparse-checkout.c b/builtin/sparse-checkout.c index cccf63033190d2..ab25a916cd5dbd 100644 --- a/builtin/sparse-checkout.c +++ b/builtin/sparse-checkout.c @@ -61,9 +61,10 @@ static int sparse_checkout_list(int argc, const char **argv, const char *prefix, struct pattern_list pl; char *sparse_filename; int res; + struct repo_config_values *cfg = repo_config_values(the_repository); setup_work_tree(); - if (!core_apply_sparse_checkout) + if (!cfg->apply_sparse_checkout) die(_("this worktree is not sparse")); argc = parse_options(argc, argv, prefix, @@ -398,12 +399,14 @@ static int set_config(struct repository *repo, } static enum sparse_checkout_mode update_cone_mode(int *cone_mode) { + struct repo_config_values *cfg = repo_config_values(the_repository); + /* If not specified, use previous definition of cone mode */ - if (*cone_mode == -1 && core_apply_sparse_checkout) + if (*cone_mode == -1 && cfg->apply_sparse_checkout) *cone_mode = core_sparse_checkout_cone; /* Set cone/non-cone mode appropriately */ - core_apply_sparse_checkout = 1; + cfg->apply_sparse_checkout = 1; if (*cone_mode == 1 || *cone_mode == -1) { core_sparse_checkout_cone = 1; return MODE_CONE_PATTERNS; @@ -415,9 +418,10 @@ static enum sparse_checkout_mode update_cone_mode(int *cone_mode) { static int update_modes(struct repository *repo, int *cone_mode, int *sparse_index) { int mode, record_mode; + struct repo_config_values *cfg = repo_config_values(the_repository); /* Determine if we need to record the mode; ensure sparse checkout on */ - record_mode = (*cone_mode != -1) || !core_apply_sparse_checkout; + record_mode = (*cone_mode != -1) || !cfg->apply_sparse_checkout; mode = update_cone_mode(cone_mode); if (record_mode && set_config(repo, mode)) @@ -683,6 +687,7 @@ static int modify_pattern_list(struct repository *repo, int result; int changed_config = 0; struct pattern_list *pl = xcalloc(1, sizeof(*pl)); + struct repo_config_values *cfg = repo_config_values(the_repository); switch (m) { case ADD: @@ -698,9 +703,9 @@ static int modify_pattern_list(struct repository *repo, break; } - if (!core_apply_sparse_checkout) { + if (!cfg->apply_sparse_checkout) { set_config(repo, MODE_ALL_PATTERNS); - core_apply_sparse_checkout = 1; + cfg->apply_sparse_checkout = 1; changed_config = 1; } @@ -795,9 +800,10 @@ static int sparse_checkout_add(int argc, const char **argv, const char *prefix, }; struct strvec patterns = STRVEC_INIT; int ret; + struct repo_config_values *cfg = repo_config_values(the_repository); setup_work_tree(); - if (!core_apply_sparse_checkout) + if (!cfg->apply_sparse_checkout) die(_("no sparse-checkout to add to")); repo_read_index(repo); @@ -904,9 +910,10 @@ static int sparse_checkout_reapply(int argc, const char **argv, N_("toggle the use of a sparse index")), OPT_END(), }; + struct repo_config_values *cfg = repo_config_values(the_repository); setup_work_tree(); - if (!core_apply_sparse_checkout) + if (!cfg->apply_sparse_checkout) die(_("must be in a sparse-checkout to reapply sparsity patterns")); reapply_opts.cone_mode = -1; @@ -959,6 +966,7 @@ static int sparse_checkout_clean(int argc, const char **argv, size_t worktree_len; int force = 0, dry_run = 0, verbose = 0; int require_force = 1; + struct repo_config_values *cfg = repo_config_values(the_repository); struct option builtin_sparse_checkout_clean_options[] = { OPT__DRY_RUN(&dry_run, N_("dry run")), @@ -968,7 +976,7 @@ static int sparse_checkout_clean(int argc, const char **argv, }; setup_work_tree(); - if (!core_apply_sparse_checkout) + if (!cfg->apply_sparse_checkout) die(_("must be in a sparse-checkout to clean directories")); if (!core_sparse_checkout_cone) die(_("must be in a cone-mode sparse-checkout to clean directories")); @@ -1032,9 +1040,10 @@ static int sparse_checkout_disable(int argc, const char **argv, OPT_END(), }; struct pattern_list pl; + struct repo_config_values *cfg = repo_config_values(the_repository); /* - * We do not exit early if !core_apply_sparse_checkout; due to the + * We do not exit early if !repo->config_values.apply_sparse_checkout; due to the * ability for users to manually muck things up between * direct editing of .git/info/sparse-checkout * running read-tree -m u HEAD or update-index --skip-worktree @@ -1060,7 +1069,7 @@ static int sparse_checkout_disable(int argc, const char **argv, hashmap_init(&pl.recursive_hashmap, pl_hashmap_cmp, NULL, 0); hashmap_init(&pl.parent_hashmap, pl_hashmap_cmp, NULL, 0); pl.use_cone_patterns = 0; - core_apply_sparse_checkout = 1; + cfg->apply_sparse_checkout = 1; add_pattern("/*", empty_base, 0, &pl, 0); diff --git a/builtin/worktree.c b/builtin/worktree.c index 3d6547c23b434f..ea16994c0c3d0b 100644 --- a/builtin/worktree.c +++ b/builtin/worktree.c @@ -440,6 +440,7 @@ static int add_worktree(const char *path, const char *refname, struct strbuf sb_name = STRBUF_INIT; struct worktree **worktrees, *wt = NULL; struct ref_store *wt_refs; + struct repo_config_values *cfg = repo_config_values(the_repository); worktrees = get_worktrees(); check_candidate_path(path, opts->force, worktrees, "add"); @@ -536,7 +537,7 @@ static int add_worktree(const char *path, const char *refname, * If the current worktree has sparse-checkout enabled, then copy * the sparse-checkout patterns from the current worktree. */ - if (core_apply_sparse_checkout) + if (cfg->apply_sparse_checkout) copy_sparse_checkout(sb_repo.buf); /* diff --git a/dir.c b/dir.c index b00821f294fea2..026d8516a912af 100644 --- a/dir.c +++ b/dir.c @@ -1551,7 +1551,9 @@ enum pattern_match_result path_matches_pattern_list( int init_sparse_checkout_patterns(struct index_state *istate) { - if (!core_apply_sparse_checkout) + struct repo_config_values *cfg = repo_config_values(the_repository); + + if (!cfg->apply_sparse_checkout) return 1; if (istate->sparse_checkout_patterns) return 0; diff --git a/environment.c b/environment.c index 76b54d99694deb..95d71fec2b5007 100644 --- a/environment.c +++ b/environment.c @@ -75,7 +75,6 @@ enum push_default_type push_default = PUSH_DEFAULT_UNSPECIFIED; #endif enum object_creation_mode object_creation_mode = OBJECT_CREATION_MODE; int grafts_keep_true_parents; -int core_apply_sparse_checkout; int core_sparse_checkout_cone; int sparse_expect_files_outside_of_patterns; int precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */ @@ -528,7 +527,7 @@ int git_default_core_config(const char *var, const char *value, } if (!strcmp(var, "core.sparsecheckout")) { - core_apply_sparse_checkout = git_config_bool(var, value); + cfg->apply_sparse_checkout = git_config_bool(var, value); return 0; } @@ -738,4 +737,5 @@ int git_default_config(const char *var, const char *value, void repo_config_values_init(struct repo_config_values *cfg) { cfg->attributes_file = NULL; + cfg->apply_sparse_checkout = 0; } diff --git a/environment.h b/environment.h index 0919e1d06d713e..ca770575bbfaad 100644 --- a/environment.h +++ b/environment.h @@ -88,6 +88,7 @@ struct repository; struct repo_config_values { /* section "core" config values */ char *attributes_file; + int apply_sparse_checkout; }; struct repo_config_values *repo_config_values(struct repository *repo); @@ -172,7 +173,6 @@ extern int precomposed_unicode; extern int protect_hfs; extern int protect_ntfs; -extern int core_apply_sparse_checkout; extern int core_sparse_checkout_cone; extern int sparse_expect_files_outside_of_patterns; diff --git a/sparse-index.c b/sparse-index.c index 76f90da5f5f41e..386be1d6f171a8 100644 --- a/sparse-index.c +++ b/sparse-index.c @@ -152,7 +152,9 @@ static int index_has_unmerged_entries(struct index_state *istate) int is_sparse_index_allowed(struct index_state *istate, int flags) { - if (!core_apply_sparse_checkout || !core_sparse_checkout_cone) + struct repo_config_values *cfg = repo_config_values(the_repository); + + if (!cfg->apply_sparse_checkout || !core_sparse_checkout_cone) return 0; if (!(flags & SPARSE_INDEX_MEMORY_ONLY)) { @@ -670,7 +672,8 @@ static void clear_skip_worktree_from_present_files_full(struct index_state *ista void clear_skip_worktree_from_present_files(struct index_state *istate) { - if (!core_apply_sparse_checkout || + struct repo_config_values *cfg = repo_config_values(the_repository); + if (!cfg->apply_sparse_checkout || sparse_expect_files_outside_of_patterns) return; diff --git a/unpack-trees.c b/unpack-trees.c index f38c761ab987a6..998a1e6dc70cae 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -1888,6 +1888,7 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options struct pattern_list pl; int free_pattern_list = 0; struct dir_struct dir = DIR_INIT; + struct repo_config_values *cfg = repo_config_values(the_repository); if (o->reset == UNPACK_RESET_INVALID) BUG("o->reset had a value of 1; should be UNPACK_TREES_*_UNTRACKED"); @@ -1924,7 +1925,7 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options if (o->prefix) update_sparsity_for_prefix(o->prefix, o->src_index); - if (!core_apply_sparse_checkout || !o->update) + if (!cfg->apply_sparse_checkout || !o->update) o->skip_sparse_checkout = 1; if (!o->skip_sparse_checkout) { memset(&pl, 0, sizeof(pl)); diff --git a/wt-status.c b/wt-status.c index 95942399f8cec6..521fb8a89dce8b 100644 --- a/wt-status.c +++ b/wt-status.c @@ -1787,8 +1787,10 @@ static void wt_status_check_sparse_checkout(struct repository *r, { int skip_worktree = 0; int i; + struct repo_config_values *cfg = repo_config_values(the_repository); - if (!core_apply_sparse_checkout || r->index->cache_nr == 0) { + if (!cfg->apply_sparse_checkout || + r->index->cache_nr == 0) { /* * Don't compute percentage of checked out files if we * aren't in a sparse checkout or would get division by 0. From 472f1460c602d855b31dd44a3d348880d9d616b8 Mon Sep 17 00:00:00 2001 From: Olamide Caleb Bello Date: Sat, 24 Jan 2026 11:29:54 +0100 Subject: [PATCH 03/11] environment: move "branch.autoSetupMerge" into `struct repo_config_values` The config value `branch.autoSetupMerge` is parsed in `git_default_branch_config()` and stored in the global variable `git_branch_track`. This global variable can be overwritten by another repository when multiple Git repos run in the the same process. Move this value into `struct repo_config_values` in the_repository to retain current behaviours and move towards libifying Git. Since the variable is no longer a global variable, it has been renamed to `branch_track` in the struct `repo_config_values`. Suggested-by: Phillip Wood Mentored-by: Christian Couder Mentored-by: Usman Akinyemi Signed-off-by: Olamide Caleb Bello --- branch.h | 2 -- builtin/branch.c | 3 ++- builtin/checkout.c | 3 ++- builtin/push.c | 3 ++- builtin/submodule--helper.c | 3 ++- environment.c | 12 +++++++----- environment.h | 4 ++++ 7 files changed, 19 insertions(+), 11 deletions(-) diff --git a/branch.h b/branch.h index ec2f35fda449aa..3dc6e2a0ffe635 100644 --- a/branch.h +++ b/branch.h @@ -15,8 +15,6 @@ enum branch_track { BRANCH_TRACK_SIMPLE, }; -extern enum branch_track git_branch_track; - /* Functions for acting on the information about branches. */ /** diff --git a/builtin/branch.c b/builtin/branch.c index c577b5d20f2969..a1a43380d0640b 100644 --- a/builtin/branch.c +++ b/builtin/branch.c @@ -724,6 +724,7 @@ int cmd_branch(int argc, static struct ref_sorting *sorting; struct string_list sorting_options = STRING_LIST_INIT_DUP; struct ref_format format = REF_FORMAT_INIT; + struct repo_config_values *cfg = repo_config_values(the_repository); int ret; struct option options[] = { @@ -795,7 +796,7 @@ int cmd_branch(int argc, if (!sorting_options.nr) string_list_append(&sorting_options, "refname"); - track = git_branch_track; + track = cfg->branch_track; head = refs_resolve_refdup(get_main_ref_store(the_repository), "HEAD", 0, &head_oid, NULL); diff --git a/builtin/checkout.c b/builtin/checkout.c index f7b313816e7708..2d816de583cd55 100644 --- a/builtin/checkout.c +++ b/builtin/checkout.c @@ -1590,6 +1590,7 @@ static void die_if_switching_to_a_branch_in_use(struct checkout_opts *opts, static int checkout_branch(struct checkout_opts *opts, struct branch_info *new_branch_info) { + struct repo_config_values *cfg = repo_config_values(the_repository); int noop_switch = (!new_branch_info->name && !opts->new_branch && !opts->force_detach); @@ -1633,7 +1634,7 @@ static int checkout_branch(struct checkout_opts *opts, if (opts->track != BRANCH_TRACK_UNSPECIFIED) die(_("'%s' cannot be used with '%s'"), "--detach", "-t"); } else if (opts->track == BRANCH_TRACK_UNSPECIFIED) - opts->track = git_branch_track; + opts->track = cfg->branch_track; if (new_branch_info->name && !new_branch_info->commit) die(_("Cannot switch branch to a non-commit '%s'"), diff --git a/builtin/push.c b/builtin/push.c index 5b6cebbb856cfc..7100ffba5da17e 100644 --- a/builtin/push.c +++ b/builtin/push.c @@ -151,6 +151,7 @@ static NORETURN void die_push_simple(struct branch *branch, const char *advice_pushdefault_maybe = ""; const char *advice_automergesimple_maybe = ""; const char *short_upstream = branch->merge[0]->src; + struct repo_config_values *cfg = repo_config_values(the_repository); skip_prefix(short_upstream, "refs/heads/", &short_upstream); @@ -162,7 +163,7 @@ static NORETURN void die_push_simple(struct branch *branch, advice_pushdefault_maybe = _("\n" "To choose either option permanently, " "see push.default in 'git help config'.\n"); - if (git_branch_track != BRANCH_TRACK_SIMPLE) + if (cfg->branch_track != BRANCH_TRACK_SIMPLE) advice_automergesimple_maybe = _("\n" "To avoid automatically configuring " "an upstream branch when its name\n" diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c index b621d14275c34d..143f7cb3cca7d0 100644 --- a/builtin/submodule--helper.c +++ b/builtin/submodule--helper.c @@ -3300,9 +3300,10 @@ static int module_create_branch(int argc, const char **argv, const char *prefix, N_("git submodule--helper create-branch [-f|--force] [--create-reflog] [-q|--quiet] [-t|--track] [-n|--dry-run] "), NULL }; + struct repo_config_values *cfg = repo_config_values(the_repository); repo_config(the_repository, git_default_config, NULL); - track = git_branch_track; + track = cfg->branch_track; argc = parse_options(argc, argv, prefix, options, usage, 0); if (argc != 3) diff --git a/environment.c b/environment.c index 95d71fec2b5007..3ee88e20ff62ba 100644 --- a/environment.c +++ b/environment.c @@ -67,7 +67,6 @@ enum auto_crlf auto_crlf = AUTO_CRLF_FALSE; enum eol core_eol = EOL_UNSET; int global_conv_flags_eol = CONV_EOL_RNDTRP_WARN; char *check_roundtrip_encoding; -enum branch_track git_branch_track = BRANCH_TRACK_REMOTE; enum rebase_setup_type autorebase = AUTOREBASE_NEVER; enum push_default_type push_default = PUSH_DEFAULT_UNSPECIFIED; #ifndef OBJECT_CREATION_MODE @@ -584,18 +583,20 @@ static int git_default_i18n_config(const char *var, const char *value) static int git_default_branch_config(const char *var, const char *value) { + struct repo_config_values *cfg = repo_config_values(the_repository); + if (!strcmp(var, "branch.autosetupmerge")) { if (value && !strcmp(value, "always")) { - git_branch_track = BRANCH_TRACK_ALWAYS; + cfg->branch_track = BRANCH_TRACK_ALWAYS; return 0; } else if (value && !strcmp(value, "inherit")) { - git_branch_track = BRANCH_TRACK_INHERIT; + cfg->branch_track = BRANCH_TRACK_INHERIT; return 0; } else if (value && !strcmp(value, "simple")) { - git_branch_track = BRANCH_TRACK_SIMPLE; + cfg->branch_track = BRANCH_TRACK_SIMPLE; return 0; } - git_branch_track = git_config_bool(var, value); + cfg->branch_track = git_config_bool(var, value); return 0; } if (!strcmp(var, "branch.autosetuprebase")) { @@ -738,4 +739,5 @@ void repo_config_values_init(struct repo_config_values *cfg) { cfg->attributes_file = NULL; cfg->apply_sparse_checkout = 0; + cfg->branch_track = BRANCH_TRACK_REMOTE; } diff --git a/environment.h b/environment.h index ca770575bbfaad..8c221b567bfc72 100644 --- a/environment.h +++ b/environment.h @@ -2,6 +2,7 @@ #define ENVIRONMENT_H #include "repo-settings.h" +#include "branch.h" /* Double-check local_repo_env below if you add to this list. */ #define GIT_DIR_ENVIRONMENT "GIT_DIR" @@ -89,6 +90,9 @@ struct repo_config_values { /* section "core" config values */ char *attributes_file; int apply_sparse_checkout; + + /* section "branch" config values */ + enum branch_track branch_track; }; struct repo_config_values *repo_config_values(struct repository *repo); From 90133565ce1f6a77d21410a0e3b1c6c03d660fec Mon Sep 17 00:00:00 2001 From: Olamide Caleb Bello Date: Sat, 21 Feb 2026 16:10:51 +0100 Subject: [PATCH 04/11] environment: move "trust_ctime" into `struct repo_config_values` The `core.trustctime` configuration is currently stored in the global variable `trust_ctime`, which makes it shared across repository instances in a single process. Store it instead in `repo_config_values`, so the value is tied to the repository from which it was read. This preserves existing behavior while avoiding cross-repository state leakage and continues the effort to reduce reliance on global configuration state. Update all references to use repo_config_values(). Mentored-by: Christian Couder Mentored-by: Usman Akinyemi Signed-off-by: Olamide Caleb Bello --- environment.c | 4 ++-- environment.h | 2 +- statinfo.c | 6 ++++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/environment.c b/environment.c index 3ee88e20ff62ba..1387282b2b16a5 100644 --- a/environment.c +++ b/environment.c @@ -42,7 +42,6 @@ static int pack_compression_seen; static int zlib_compression_seen; int trust_executable_bit = 1; -int trust_ctime = 1; int check_stat = 1; int has_symlinks = 1; int minimum_abbrev = 4, default_abbrev = -1; @@ -309,7 +308,7 @@ int git_default_core_config(const char *var, const char *value, return 0; } if (!strcmp(var, "core.trustctime")) { - trust_ctime = git_config_bool(var, value); + cfg->trust_ctime = git_config_bool(var, value); return 0; } if (!strcmp(var, "core.checkstat")) { @@ -740,4 +739,5 @@ void repo_config_values_init(struct repo_config_values *cfg) cfg->attributes_file = NULL; cfg->apply_sparse_checkout = 0; cfg->branch_track = BRANCH_TRACK_REMOTE; + cfg->trust_ctime = 1; } diff --git a/environment.h b/environment.h index 8c221b567bfc72..78de6a3c1c6598 100644 --- a/environment.h +++ b/environment.h @@ -90,6 +90,7 @@ struct repo_config_values { /* section "core" config values */ char *attributes_file; int apply_sparse_checkout; + int trust_ctime; /* section "branch" config values */ enum branch_track branch_track; @@ -160,7 +161,6 @@ extern char *git_work_tree_cfg; /* Environment bits from configuration mechanism */ extern int trust_executable_bit; -extern int trust_ctime; extern int check_stat; extern int has_symlinks; extern int minimum_abbrev, default_abbrev; diff --git a/statinfo.c b/statinfo.c index 30a164b0e68cf8..4fc12053f40b20 100644 --- a/statinfo.c +++ b/statinfo.c @@ -3,6 +3,7 @@ #include "git-compat-util.h" #include "environment.h" #include "statinfo.h" +#include "repository.h" /* * Munge st_size into an unsigned int. @@ -63,17 +64,18 @@ void fake_lstat_data(const struct stat_data *sd, struct stat *st) int match_stat_data(const struct stat_data *sd, struct stat *st) { int changed = 0; + struct repo_config_values *cfg = repo_config_values(the_repository); if (sd->sd_mtime.sec != (unsigned int)st->st_mtime) changed |= MTIME_CHANGED; - if (trust_ctime && check_stat && + if (cfg->trust_ctime && check_stat && sd->sd_ctime.sec != (unsigned int)st->st_ctime) changed |= CTIME_CHANGED; #ifdef USE_NSEC if (check_stat && sd->sd_mtime.nsec != ST_MTIME_NSEC(*st)) changed |= MTIME_CHANGED; - if (trust_ctime && check_stat && + if (cfg->trust_ctime && check_stat && sd->sd_ctime.nsec != ST_CTIME_NSEC(*st)) changed |= CTIME_CHANGED; #endif From de7bd2ace48ea58a8eb38290a451369446da7a57 Mon Sep 17 00:00:00 2001 From: Olamide Caleb Bello Date: Sat, 21 Feb 2026 16:37:16 +0100 Subject: [PATCH 05/11] environment: move "check_stat" into `struct repo_config_values` The `core.checkstat` configuration is currently stored in the global variable `check_stat`, which makes it shared across repository instances within a single process. Store it instead in `repo_config_values` so the value is associated with the repository from which it was read. This preserves existing behavior while avoiding cross-repository state leakage and continues the effort to reduce reliance on global configuration state. Update all references to use repo_config_values(). Mentored-by: Christian Couder Mentored-by: Usman Akinyemi Signed-off-by: Olamide Caleb Bello --- entry.c | 3 ++- environment.c | 6 +++--- environment.h | 2 +- statinfo.c | 10 +++++----- 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/entry.c b/entry.c index 7817aee362ed9e..c55e867d8a2bca 100644 --- a/entry.c +++ b/entry.c @@ -443,7 +443,8 @@ static int check_path(const char *path, int len, struct stat *st, int skiplen) static void mark_colliding_entries(const struct checkout *state, struct cache_entry *ce, struct stat *st) { - int trust_ino = check_stat; + struct repo_config_values *cfg = repo_config_values(the_repository); + int trust_ino = cfg->check_stat; #if defined(GIT_WINDOWS_NATIVE) || defined(__CYGWIN__) trust_ino = 0; diff --git a/environment.c b/environment.c index 1387282b2b16a5..a05c6e9550780f 100644 --- a/environment.c +++ b/environment.c @@ -42,7 +42,6 @@ static int pack_compression_seen; static int zlib_compression_seen; int trust_executable_bit = 1; -int check_stat = 1; int has_symlinks = 1; int minimum_abbrev = 4, default_abbrev = -1; int ignore_case; @@ -315,9 +314,9 @@ int git_default_core_config(const char *var, const char *value, if (!value) return config_error_nonbool(var); if (!strcasecmp(value, "default")) - check_stat = 1; + cfg->check_stat = 1; else if (!strcasecmp(value, "minimal")) - check_stat = 0; + cfg->check_stat = 0; else return error(_("invalid value for '%s': '%s'"), var, value); @@ -740,4 +739,5 @@ void repo_config_values_init(struct repo_config_values *cfg) cfg->apply_sparse_checkout = 0; cfg->branch_track = BRANCH_TRACK_REMOTE; cfg->trust_ctime = 1; + cfg->check_stat = 1; } diff --git a/environment.h b/environment.h index 78de6a3c1c6598..823103353d12f1 100644 --- a/environment.h +++ b/environment.h @@ -91,6 +91,7 @@ struct repo_config_values { char *attributes_file; int apply_sparse_checkout; int trust_ctime; + int check_stat; /* section "branch" config values */ enum branch_track branch_track; @@ -161,7 +162,6 @@ extern char *git_work_tree_cfg; /* Environment bits from configuration mechanism */ extern int trust_executable_bit; -extern int check_stat; extern int has_symlinks; extern int minimum_abbrev, default_abbrev; extern int ignore_case; diff --git a/statinfo.c b/statinfo.c index 4fc12053f40b20..5e00af127d657d 100644 --- a/statinfo.c +++ b/statinfo.c @@ -68,19 +68,19 @@ int match_stat_data(const struct stat_data *sd, struct stat *st) if (sd->sd_mtime.sec != (unsigned int)st->st_mtime) changed |= MTIME_CHANGED; - if (cfg->trust_ctime && check_stat && + if (cfg->trust_ctime && cfg->check_stat && sd->sd_ctime.sec != (unsigned int)st->st_ctime) changed |= CTIME_CHANGED; #ifdef USE_NSEC - if (check_stat && sd->sd_mtime.nsec != ST_MTIME_NSEC(*st)) + if (cfg->check_stat && sd->sd_mtime.nsec != ST_MTIME_NSEC(*st)) changed |= MTIME_CHANGED; - if (cfg->trust_ctime && check_stat && + if (cfg->trust_ctime && cfg->check_stat && sd->sd_ctime.nsec != ST_CTIME_NSEC(*st)) changed |= CTIME_CHANGED; #endif - if (check_stat) { + if (cfg->check_stat) { if (sd->sd_uid != (unsigned int) st->st_uid || sd->sd_gid != (unsigned int) st->st_gid) changed |= OWNER_CHANGED; @@ -94,7 +94,7 @@ int match_stat_data(const struct stat_data *sd, struct stat *st) * clients will have different views of what "device" * the filesystem is on */ - if (check_stat && sd->sd_dev != (unsigned int) st->st_dev) + if (cfg->check_stat && sd->sd_dev != (unsigned int) st->st_dev) changed |= INODE_CHANGED; #endif From ca3d834fb509fde75957e2d93625908c94b6718d Mon Sep 17 00:00:00 2001 From: Olamide Caleb Bello Date: Sat, 21 Feb 2026 16:50:28 +0100 Subject: [PATCH 06/11] environment: move `zlib_compression_level` into repo_config_values The `zlib_compression_level` configuration is currently stored in the global variable `zlib_compression_level`, which makes it shared across repository instances within a single process. Store it instead in `repo_config_values` so the value is associated with the repository from which it was read. This preserves existing behavior while avoiding cross-repository state leakage and continues the effort to reduce reliance on global configuration state. Update all references to use repo_config_values(). Mentored-by: Christian Couder Mentored-by: Usman Akinyemi Signed-off-by: Olamide Caleb Bello --- builtin/index-pack.c | 3 ++- diff.c | 3 ++- environment.c | 6 +++--- environment.h | 2 +- http-push.c | 3 ++- object-file.c | 3 ++- 6 files changed, 12 insertions(+), 8 deletions(-) diff --git a/builtin/index-pack.c b/builtin/index-pack.c index b67fb0256cc831..dd82eed76f6aa6 100644 --- a/builtin/index-pack.c +++ b/builtin/index-pack.c @@ -1416,8 +1416,9 @@ static int write_compressed(struct hashfile *f, void *in, unsigned int size) git_zstream stream; int status; unsigned char outbuf[4096]; + struct repo_config_values *cfg = repo_config_values(the_repository); - git_deflate_init(&stream, zlib_compression_level); + git_deflate_init(&stream, cfg->zlib_compression_level); stream.next_in = in; stream.avail_in = size; diff --git a/diff.c b/diff.c index 35b903a9a0966a..85bcbc1a0e1390 100644 --- a/diff.c +++ b/diff.c @@ -3358,8 +3358,9 @@ static unsigned char *deflate_it(char *data, int bound; unsigned char *deflated; git_zstream stream; + struct repo_config_values *cfg = repo_config_values(the_repository); - git_deflate_init(&stream, zlib_compression_level); + git_deflate_init(&stream, cfg->zlib_compression_level); bound = git_deflate_bound(&stream, size); deflated = xmalloc(bound); stream.next_out = deflated; diff --git a/environment.c b/environment.c index a05c6e9550780f..0474c34a9b1f23 100644 --- a/environment.c +++ b/environment.c @@ -52,7 +52,6 @@ char *git_commit_encoding; char *git_log_output_encoding; char *apply_default_whitespace; char *apply_default_ignorewhitespace; -int zlib_compression_level = Z_BEST_SPEED; int pack_compression_level = Z_DEFAULT_COMPRESSION; int fsync_object_files = -1; int use_fsync = -1; @@ -377,7 +376,7 @@ int git_default_core_config(const char *var, const char *value, level = Z_DEFAULT_COMPRESSION; else if (level < 0 || level > Z_BEST_COMPRESSION) die(_("bad zlib compression level %d"), level); - zlib_compression_level = level; + cfg->zlib_compression_level = level; zlib_compression_seen = 1; return 0; } @@ -389,7 +388,7 @@ int git_default_core_config(const char *var, const char *value, else if (level < 0 || level > Z_BEST_COMPRESSION) die(_("bad zlib compression level %d"), level); if (!zlib_compression_seen) - zlib_compression_level = level; + cfg->zlib_compression_level = level; if (!pack_compression_seen) pack_compression_level = level; return 0; @@ -740,4 +739,5 @@ void repo_config_values_init(struct repo_config_values *cfg) cfg->branch_track = BRANCH_TRACK_REMOTE; cfg->trust_ctime = 1; cfg->check_stat = 1; + cfg->zlib_compression_level = Z_BEST_SPEED; } diff --git a/environment.h b/environment.h index 823103353d12f1..a75d9b3060fbf6 100644 --- a/environment.h +++ b/environment.h @@ -92,6 +92,7 @@ struct repo_config_values { int apply_sparse_checkout; int trust_ctime; int check_stat; + int zlib_compression_level; /* section "branch" config values */ enum branch_track branch_track; @@ -169,7 +170,6 @@ extern int assume_unchanged; extern int warn_on_object_refname_ambiguity; extern char *apply_default_whitespace; extern char *apply_default_ignorewhitespace; -extern int zlib_compression_level; extern int pack_compression_level; extern unsigned long pack_size_limit_cfg; diff --git a/http-push.c b/http-push.c index 9ae6062198e14f..c6bf9ff387640c 100644 --- a/http-push.c +++ b/http-push.c @@ -369,13 +369,14 @@ static void start_put(struct transfer_request *request) int hdrlen; ssize_t size; git_zstream stream; + struct repo_config_values *cfg = repo_config_values(the_repository); unpacked = odb_read_object(the_repository->objects, &request->obj->oid, &type, &len); hdrlen = format_object_header(hdr, sizeof(hdr), type, len); /* Set it up */ - git_deflate_init(&stream, zlib_compression_level); + git_deflate_init(&stream, cfg->zlib_compression_level); size = git_deflate_bound(&stream, len + hdrlen); strbuf_grow(&request->buffer.buf, size); request->buffer.posn = 0; diff --git a/object-file.c b/object-file.c index 1b62996ef0a96f..2b10dc32d8da28 100644 --- a/object-file.c +++ b/object-file.c @@ -878,6 +878,7 @@ static int start_loose_object_common(struct odb_source *source, const struct git_hash_algo *algo = source->odb->repo->hash_algo; const struct git_hash_algo *compat = source->odb->repo->compat_hash_algo; int fd; + struct repo_config_values *cfg = repo_config_values(the_repository); fd = create_tmpfile(source->odb->repo, tmp_file, filename); if (fd < 0) { @@ -893,7 +894,7 @@ static int start_loose_object_common(struct odb_source *source, } /* Setup zlib stream for compression */ - git_deflate_init(stream, zlib_compression_level); + git_deflate_init(stream, cfg->zlib_compression_level); stream->next_out = buf; stream->avail_out = buflen; algo->init_fn(c); From 06fdec3eefdb707dfed5de3f08f74d12f101d331 Mon Sep 17 00:00:00 2001 From: Olamide Caleb Bello Date: Sat, 21 Feb 2026 17:03:00 +0100 Subject: [PATCH 07/11] environment: move "pack_compression_level" into `struct repo_config_values` The `pack_compression_level` configuration is currently stored in the global variable `pack_compression_level`, which makes it shared across repository instances within a single process. Store it instead in `repo_config_values` so the value is associated with the repository from which it was read. This preserves existing behavior while avoiding cross-repository state leakage and is another step toward eliminating repository-dependent global state. Update all references to use repo_config_values(). Mentored-by: Christian Couder Mentored-by: Usman Akinyemi Signed-off-by: Olamide Caleb Bello --- builtin/fast-import.c | 8 +++++--- builtin/pack-objects.c | 8 ++++++-- environment.c | 8 +++++--- environment.h | 2 +- object-file.c | 3 ++- 5 files changed, 19 insertions(+), 10 deletions(-) diff --git a/builtin/fast-import.c b/builtin/fast-import.c index b8a7757cfda943..6475cdae853514 100644 --- a/builtin/fast-import.c +++ b/builtin/fast-import.c @@ -963,6 +963,7 @@ static int store_object( unsigned long hdrlen, deltalen; struct git_hash_ctx c; git_zstream s; + struct repo_config_values *cfg = repo_config_values(the_repository); hdrlen = format_object_header((char *)hdr, sizeof(hdr), type, dat->len); @@ -1001,7 +1002,7 @@ static int store_object( } else delta = NULL; - git_deflate_init(&s, pack_compression_level); + git_deflate_init(&s, cfg->pack_compression_level); if (delta) { s.next_in = delta; s.avail_in = deltalen; @@ -1028,7 +1029,7 @@ static int store_object( if (delta) { FREE_AND_NULL(delta); - git_deflate_init(&s, pack_compression_level); + git_deflate_init(&s, cfg->pack_compression_level); s.next_in = (void *)dat->buf; s.avail_in = dat->len; s.avail_out = git_deflate_bound(&s, s.avail_in); @@ -1111,6 +1112,7 @@ static void stream_blob(uintmax_t len, struct object_id *oidout, uintmax_t mark) struct git_hash_ctx c; git_zstream s; struct hashfile_checkpoint checkpoint; + struct repo_config_values *cfg = repo_config_values(the_repository); int status = Z_OK; /* Determine if we should auto-checkpoint. */ @@ -1130,7 +1132,7 @@ static void stream_blob(uintmax_t len, struct object_id *oidout, uintmax_t mark) crc32_begin(pack_file); - git_deflate_init(&s, pack_compression_level); + git_deflate_init(&s, cfg->pack_compression_level); hdrlen = encode_in_pack_object_header(out_buf, out_sz, OBJ_BLOB, len); diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c index e6c8f896ab9761..ef7ff18546c749 100644 --- a/builtin/pack-objects.c +++ b/builtin/pack-objects.c @@ -383,8 +383,9 @@ static unsigned long do_compress(void **pptr, unsigned long size) git_zstream stream; void *in, *out; unsigned long maxsize; + struct repo_config_values *cfg = repo_config_values(the_repository); - git_deflate_init(&stream, pack_compression_level); + git_deflate_init(&stream, cfg->pack_compression_level); maxsize = git_deflate_bound(&stream, size); in = *pptr; @@ -410,8 +411,9 @@ static unsigned long write_large_blob_data(struct odb_read_stream *st, struct ha unsigned char ibuf[1024 * 16]; unsigned char obuf[1024 * 16]; unsigned long olen = 0; + struct repo_config_values *cfg = repo_config_values(the_repository); - git_deflate_init(&stream, pack_compression_level); + git_deflate_init(&stream, cfg->pack_compression_level); for (;;) { ssize_t readlen; @@ -4875,6 +4877,8 @@ int cmd_pack_objects(int argc, struct string_list keep_pack_list = STRING_LIST_INIT_NODUP; struct list_objects_filter_options filter_options = LIST_OBJECTS_FILTER_INIT; + struct repo_config_values *cfg = repo_config_values(the_repository); + int pack_compression_level = cfg->pack_compression_level; struct option pack_objects_options[] = { OPT_CALLBACK_F('q', "quiet", &progress, NULL, diff --git a/environment.c b/environment.c index 0474c34a9b1f23..2060cb2f80a08b 100644 --- a/environment.c +++ b/environment.c @@ -52,7 +52,6 @@ char *git_commit_encoding; char *git_log_output_encoding; char *apply_default_whitespace; char *apply_default_ignorewhitespace; -int pack_compression_level = Z_DEFAULT_COMPRESSION; int fsync_object_files = -1; int use_fsync = -1; enum fsync_method fsync_method = FSYNC_METHOD_DEFAULT; @@ -390,7 +389,7 @@ int git_default_core_config(const char *var, const char *value, if (!zlib_compression_seen) cfg->zlib_compression_level = level; if (!pack_compression_seen) - pack_compression_level = level; + cfg->pack_compression_level = level; return 0; } @@ -678,6 +677,8 @@ static int git_default_attr_config(const char *var, const char *value) int git_default_config(const char *var, const char *value, const struct config_context *ctx, void *cb) { + struct repo_config_values *cfg = repo_config_values(the_repository); + if (starts_with(var, "core.")) return git_default_core_config(var, value, ctx, cb); @@ -720,7 +721,7 @@ int git_default_config(const char *var, const char *value, level = Z_DEFAULT_COMPRESSION; else if (level < 0 || level > Z_BEST_COMPRESSION) die(_("bad pack compression level %d"), level); - pack_compression_level = level; + cfg->pack_compression_level = level; pack_compression_seen = 1; return 0; } @@ -740,4 +741,5 @@ void repo_config_values_init(struct repo_config_values *cfg) cfg->trust_ctime = 1; cfg->check_stat = 1; cfg->zlib_compression_level = Z_BEST_SPEED; + cfg->pack_compression_level = Z_DEFAULT_COMPRESSION; } diff --git a/environment.h b/environment.h index a75d9b3060fbf6..7310923fc95b9e 100644 --- a/environment.h +++ b/environment.h @@ -93,6 +93,7 @@ struct repo_config_values { int trust_ctime; int check_stat; int zlib_compression_level; + int pack_compression_level; /* section "branch" config values */ enum branch_track branch_track; @@ -170,7 +171,6 @@ extern int assume_unchanged; extern int warn_on_object_refname_ambiguity; extern char *apply_default_whitespace; extern char *apply_default_ignorewhitespace; -extern int pack_compression_level; extern unsigned long pack_size_limit_cfg; extern int precomposed_unicode; diff --git a/object-file.c b/object-file.c index 2b10dc32d8da28..f402578af94301 100644 --- a/object-file.c +++ b/object-file.c @@ -1407,8 +1407,9 @@ static int stream_blob_to_pack(struct transaction_packfile *state, int status = Z_OK; int write_object = (flags & INDEX_WRITE_OBJECT); off_t offset = 0; + struct repo_config_values *cfg = repo_config_values(the_repository); - git_deflate_init(&s, pack_compression_level); + git_deflate_init(&s, cfg->pack_compression_level); hdrlen = encode_in_pack_object_header(obuf, sizeof(obuf), OBJ_BLOB, size); s.next_out = obuf + hdrlen; From 2c524067f9eb9d9fcade224909149e27300db104 Mon Sep 17 00:00:00 2001 From: Olamide Caleb Bello Date: Sat, 21 Feb 2026 17:52:38 +0100 Subject: [PATCH 08/11] environment: move "precomposed_unicode" into `struct repo_config_values` The `core.precomposeunicode` configuration is currently stored in the global variable `precomposed_unicode`, which makes it shared across repository instances within a single process. Store it instead in `repo_config_values` so the value is associated with the repository from which it was read. This preserves existing behavior while avoiding cross-repository state leakage and is another step toward eliminating repository-dependent global state. Update all references to use repo_config_values(). Mentored-by: Christian Couder Mentored-by: Usman Akinyemi Signed-off-by: Olamide Caleb Bello --- compat/precompose_utf8.c | 20 +++++++++++++------- environment.c | 4 ++-- environment.h | 2 +- upload-pack.c | 3 ++- 4 files changed, 18 insertions(+), 11 deletions(-) diff --git a/compat/precompose_utf8.c b/compat/precompose_utf8.c index 43b3be011439ef..0e94dbd8629805 100644 --- a/compat/precompose_utf8.c +++ b/compat/precompose_utf8.c @@ -48,16 +48,18 @@ void probe_utf8_pathname_composition(void) static const char *auml_nfc = "\xc3\xa4"; static const char *auml_nfd = "\x61\xcc\x88"; int output_fd; - if (precomposed_unicode != -1) + struct repo_config_values *cfg = repo_config_values(the_repository); + + if (cfg->precomposed_unicode != -1) return; /* We found it defined in the global config, respect it */ repo_git_path_replace(the_repository, &path, "%s", auml_nfc); output_fd = open(path.buf, O_CREAT|O_EXCL|O_RDWR, 0600); if (output_fd >= 0) { close(output_fd); repo_git_path_replace(the_repository, &path, "%s", auml_nfd); - precomposed_unicode = access(path.buf, R_OK) ? 0 : 1; + cfg->precomposed_unicode = access(path.buf, R_OK) ? 0 : 1; repo_config_set(the_repository, "core.precomposeunicode", - precomposed_unicode ? "true" : "false"); + cfg->precomposed_unicode ? "true" : "false"); repo_git_path_replace(the_repository, &path, "%s", auml_nfc); if (unlink(path.buf)) die_errno(_("failed to unlink '%s'"), path.buf); @@ -69,14 +71,16 @@ const char *precompose_string_if_needed(const char *in) { size_t inlen; size_t outlen; + struct repo_config_values *cfg = repo_config_values(the_repository); + if (!in) return NULL; if (has_non_ascii(in, (size_t)-1, &inlen)) { iconv_t ic_prec; char *out; - if (precomposed_unicode < 0) - repo_config_get_bool(the_repository, "core.precomposeunicode", &precomposed_unicode); - if (precomposed_unicode != 1) + if (cfg->precomposed_unicode < 0) + repo_config_get_bool(the_repository, "core.precomposeunicode", &cfg->precomposed_unicode); + if (cfg->precomposed_unicode != 1) return in; ic_prec = iconv_open(repo_encoding, path_encoding); if (ic_prec == (iconv_t) -1) @@ -130,7 +134,9 @@ PREC_DIR *precompose_utf8_opendir(const char *dirname) struct dirent_prec_psx *precompose_utf8_readdir(PREC_DIR *prec_dir) { + struct repo_config_values *cfg = repo_config_values(the_repository); struct dirent *res; + res = readdir(prec_dir->dirp); if (res) { size_t namelenz = strlen(res->d_name) + 1; /* \0 */ @@ -149,7 +155,7 @@ struct dirent_prec_psx *precompose_utf8_readdir(PREC_DIR *prec_dir) prec_dir->dirent_nfc->d_ino = res->d_ino; prec_dir->dirent_nfc->d_type = res->d_type; - if ((precomposed_unicode == 1) && has_non_ascii(res->d_name, (size_t)-1, NULL)) { + if ((cfg->precomposed_unicode == 1) && has_non_ascii(res->d_name, (size_t)-1, NULL)) { if (prec_dir->ic_precompose == (iconv_t)-1) { die("iconv_open(%s,%s) failed, but needed:\n" " precomposed unicode is not supported.\n" diff --git a/environment.c b/environment.c index 2060cb2f80a08b..c4c689c176981c 100644 --- a/environment.c +++ b/environment.c @@ -72,7 +72,6 @@ enum object_creation_mode object_creation_mode = OBJECT_CREATION_MODE; int grafts_keep_true_parents; int core_sparse_checkout_cone; int sparse_expect_files_outside_of_patterns; -int precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */ unsigned long pack_size_limit_cfg; #ifndef PROTECT_HFS_DEFAULT @@ -532,7 +531,7 @@ int git_default_core_config(const char *var, const char *value, } if (!strcmp(var, "core.precomposeunicode")) { - precomposed_unicode = git_config_bool(var, value); + cfg->precomposed_unicode = git_config_bool(var, value); return 0; } @@ -742,4 +741,5 @@ void repo_config_values_init(struct repo_config_values *cfg) cfg->check_stat = 1; cfg->zlib_compression_level = Z_BEST_SPEED; cfg->pack_compression_level = Z_DEFAULT_COMPRESSION; + cfg->precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */ } diff --git a/environment.h b/environment.h index 7310923fc95b9e..728768496998e9 100644 --- a/environment.h +++ b/environment.h @@ -94,6 +94,7 @@ struct repo_config_values { int check_stat; int zlib_compression_level; int pack_compression_level; + int precomposed_unicode; /* section "branch" config values */ enum branch_track branch_track; @@ -173,7 +174,6 @@ extern char *apply_default_whitespace; extern char *apply_default_ignorewhitespace; extern unsigned long pack_size_limit_cfg; -extern int precomposed_unicode; extern int protect_hfs; extern int protect_ntfs; diff --git a/upload-pack.c b/upload-pack.c index 2d2b70cbf2dd0b..6e6b39a0ea78db 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -1356,6 +1356,7 @@ static int upload_pack_config(const char *var, const char *value, void *cb_data) { struct upload_pack_data *data = cb_data; + struct repo_config_values *cfg = repo_config_values(the_repository); if (!strcmp("uploadpack.allowtipsha1inwant", var)) { if (git_config_bool(var, value)) @@ -1386,7 +1387,7 @@ static int upload_pack_config(const char *var, const char *value, if (value) data->allow_packfile_uris = 1; } else if (!strcmp("core.precomposeunicode", var)) { - precomposed_unicode = git_config_bool(var, value); + cfg->precomposed_unicode = git_config_bool(var, value); } else if (!strcmp("transfer.advertisesid", var)) { data->advertise_sid = git_config_bool(var, value); } From 34169afa8dc8f41981ed5578771a843f179ce649 Mon Sep 17 00:00:00 2001 From: Olamide Caleb Bello Date: Mon, 23 Feb 2026 15:14:01 +0100 Subject: [PATCH 09/11] env: move "core_sparse_checkout_cone" into `struct repo_config_values` The `core_sparse_checkout_cone` variable was previously a global integer, uninitialized by default. Storing repository-dependent configuration in globals can lead to cross-repository state leakage. Move it into `repo_config_values` and initialize it to 0 by default. This ensures predictable behavior for repositories that do not set this configuration while preserving existing semantics. Update all references to use repo_config_values(). Mentored-by: Christian Couder Mentored-by: Usman Akinyemi Signed-off-by: Olamide Caleb Bello --- builtin/mv.c | 2 +- builtin/sparse-checkout.c | 37 ++++++++++++++++++++++--------------- dir.c | 3 ++- environment.c | 4 ++-- environment.h | 2 +- sparse-index.c | 2 +- 6 files changed, 29 insertions(+), 21 deletions(-) diff --git a/builtin/mv.c b/builtin/mv.c index 2215d34e31f29a..ef3a326c906897 100644 --- a/builtin/mv.c +++ b/builtin/mv.c @@ -574,7 +574,7 @@ int cmd_mv(int argc, if (ignore_sparse && cfg->apply_sparse_checkout && - core_sparse_checkout_cone) { + cfg->core_sparse_checkout_cone) { /* * NEEDSWORK: we are *not* paying attention to * "out-to-out" move ( is out-of-cone and diff --git a/builtin/sparse-checkout.c b/builtin/sparse-checkout.c index ab25a916cd5dbd..3d7b6942d53ee8 100644 --- a/builtin/sparse-checkout.c +++ b/builtin/sparse-checkout.c @@ -73,7 +73,7 @@ static int sparse_checkout_list(int argc, const char **argv, const char *prefix, memset(&pl, 0, sizeof(pl)); - pl.use_cone_patterns = core_sparse_checkout_cone; + pl.use_cone_patterns = cfg->core_sparse_checkout_cone; sparse_filename = get_sparse_checkout_filename(); res = add_patterns_from_file_to_list(sparse_filename, "", 0, &pl, NULL, 0); @@ -335,6 +335,7 @@ static int write_patterns_and_update(struct repository *repo, FILE *fp; struct lock_file lk = LOCK_INIT; int result; + struct repo_config_values *cfg = repo_config_values(the_repository); sparse_filename = get_sparse_checkout_filename(); @@ -354,7 +355,7 @@ static int write_patterns_and_update(struct repository *repo, if (!fp) die_errno(_("unable to fdopen %s"), get_lock_file_path(&lk)); - if (core_sparse_checkout_cone) + if (cfg->core_sparse_checkout_cone) write_cone_to_file(fp, pl); else write_patterns_to_file(fp, pl); @@ -403,15 +404,15 @@ static enum sparse_checkout_mode update_cone_mode(int *cone_mode) { /* If not specified, use previous definition of cone mode */ if (*cone_mode == -1 && cfg->apply_sparse_checkout) - *cone_mode = core_sparse_checkout_cone; + *cone_mode = cfg->core_sparse_checkout_cone; /* Set cone/non-cone mode appropriately */ cfg->apply_sparse_checkout = 1; if (*cone_mode == 1 || *cone_mode == -1) { - core_sparse_checkout_cone = 1; + cfg->core_sparse_checkout_cone = 1; return MODE_CONE_PATTERNS; } - core_sparse_checkout_cone = 0; + cfg->core_sparse_checkout_cone = 0; return MODE_ALL_PATTERNS; } @@ -578,7 +579,9 @@ static void add_patterns_from_input(struct pattern_list *pl, FILE *file) { int i; - if (core_sparse_checkout_cone) { + struct repo_config_values *cfg = repo_config_values(the_repository); + + if (cfg->core_sparse_checkout_cone) { struct strbuf line = STRBUF_INIT; hashmap_init(&pl->recursive_hashmap, pl_hashmap_cmp, NULL, 0); @@ -637,13 +640,14 @@ static void add_patterns_cone_mode(int argc, const char **argv, struct pattern_entry *pe; struct hashmap_iter iter; struct pattern_list existing; + struct repo_config_values *cfg = repo_config_values(the_repository); char *sparse_filename = get_sparse_checkout_filename(); add_patterns_from_input(pl, argc, argv, use_stdin ? stdin : NULL); memset(&existing, 0, sizeof(existing)); - existing.use_cone_patterns = core_sparse_checkout_cone; + existing.use_cone_patterns = cfg->core_sparse_checkout_cone; if (add_patterns_from_file_to_list(sparse_filename, "", 0, &existing, NULL, 0)) @@ -691,7 +695,7 @@ static int modify_pattern_list(struct repository *repo, switch (m) { case ADD: - if (core_sparse_checkout_cone) + if (cfg->core_sparse_checkout_cone) add_patterns_cone_mode(args->nr, args->v, pl, use_stdin); else add_patterns_literal(args->nr, args->v, pl, use_stdin); @@ -724,11 +728,12 @@ static void sanitize_paths(struct repository *repo, const char *prefix, int skip_checks) { int i; + struct repo_config_values *cfg = repo_config_values(the_repository); if (!args->nr) return; - if (prefix && *prefix && core_sparse_checkout_cone) { + if (prefix && *prefix && cfg->core_sparse_checkout_cone) { /* * The args are not pathspecs, so unfortunately we * cannot imitate how cmd_add() uses parse_pathspec(). @@ -745,10 +750,10 @@ static void sanitize_paths(struct repository *repo, if (skip_checks) return; - if (prefix && *prefix && !core_sparse_checkout_cone) + if (prefix && *prefix && !cfg->core_sparse_checkout_cone) die(_("please run from the toplevel directory in non-cone mode")); - if (core_sparse_checkout_cone) { + if (cfg->core_sparse_checkout_cone) { for (i = 0; i < args->nr; i++) { if (args->v[i][0] == '/') die(_("specify directories rather than patterns (no leading slash)")); @@ -770,7 +775,7 @@ static void sanitize_paths(struct repository *repo, if (S_ISSPARSEDIR(ce->ce_mode)) continue; - if (core_sparse_checkout_cone) + if (cfg->core_sparse_checkout_cone) die(_("'%s' is not a directory; to treat it as a directory anyway, rerun with --skip-checks"), args->v[i]); else 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]); @@ -837,6 +842,7 @@ static struct sparse_checkout_set_opts { static int sparse_checkout_set(int argc, const char **argv, const char *prefix, struct repository *repo) { + struct repo_config_values *cfg = repo_config_values(the_repository); int default_patterns_nr = 2; const char *default_patterns[] = {"/*", "!/*/", NULL}; @@ -874,7 +880,7 @@ static int sparse_checkout_set(int argc, const char **argv, const char *prefix, * non-cone mode, if nothing is specified, manually select just the * top-level directory (much as 'init' would do). */ - if (!core_sparse_checkout_cone && !set_opts.use_stdin && argc == 0) { + if (!cfg->core_sparse_checkout_cone && !set_opts.use_stdin && argc == 0) { for (int i = 0; i < default_patterns_nr; i++) strvec_push(&patterns, default_patterns[i]); } else { @@ -978,7 +984,7 @@ static int sparse_checkout_clean(int argc, const char **argv, setup_work_tree(); if (!cfg->apply_sparse_checkout) die(_("must be in a sparse-checkout to clean directories")); - if (!core_sparse_checkout_cone) + if (!cfg->core_sparse_checkout_cone) die(_("must be in a cone-mode sparse-checkout to clean directories")); argc = parse_options(argc, argv, prefix, @@ -1142,6 +1148,7 @@ static int sparse_checkout_check_rules(int argc, const char **argv, const char * FILE *fp; int ret; struct pattern_list pl = {0}; + struct repo_config_values *cfg = repo_config_values(the_repository); char *sparse_filename; check_rules_opts.cone_mode = -1; @@ -1153,7 +1160,7 @@ static int sparse_checkout_check_rules(int argc, const char **argv, const char * check_rules_opts.cone_mode = 1; update_cone_mode(&check_rules_opts.cone_mode); - pl.use_cone_patterns = core_sparse_checkout_cone; + pl.use_cone_patterns = cfg->core_sparse_checkout_cone; if (check_rules_opts.rules_file) { fp = xfopen(check_rules_opts.rules_file, "r"); add_patterns_from_input(&pl, argc, argv, fp); diff --git a/dir.c b/dir.c index 026d8516a912af..2744b3e5ca0732 100644 --- a/dir.c +++ b/dir.c @@ -3508,8 +3508,9 @@ int get_sparse_checkout_patterns(struct pattern_list *pl) { int res; char *sparse_filename = get_sparse_checkout_filename(); + struct repo_config_values *cfg = repo_config_values(the_repository); - pl->use_cone_patterns = core_sparse_checkout_cone; + pl->use_cone_patterns = cfg->core_sparse_checkout_cone; res = add_patterns_from_file_to_list(sparse_filename, "", 0, pl, NULL, 0); free(sparse_filename); diff --git a/environment.c b/environment.c index c4c689c176981c..24afc1603ee8cb 100644 --- a/environment.c +++ b/environment.c @@ -70,7 +70,6 @@ enum push_default_type push_default = PUSH_DEFAULT_UNSPECIFIED; #endif enum object_creation_mode object_creation_mode = OBJECT_CREATION_MODE; int grafts_keep_true_parents; -int core_sparse_checkout_cone; int sparse_expect_files_outside_of_patterns; unsigned long pack_size_limit_cfg; @@ -526,7 +525,7 @@ int git_default_core_config(const char *var, const char *value, } if (!strcmp(var, "core.sparsecheckoutcone")) { - core_sparse_checkout_cone = git_config_bool(var, value); + cfg->core_sparse_checkout_cone = git_config_bool(var, value); return 0; } @@ -742,4 +741,5 @@ void repo_config_values_init(struct repo_config_values *cfg) cfg->zlib_compression_level = Z_BEST_SPEED; cfg->pack_compression_level = Z_DEFAULT_COMPRESSION; cfg->precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */ + cfg->core_sparse_checkout_cone = 0; } diff --git a/environment.h b/environment.h index 728768496998e9..44c022d9cc87dc 100644 --- a/environment.h +++ b/environment.h @@ -95,6 +95,7 @@ struct repo_config_values { int zlib_compression_level; int pack_compression_level; int precomposed_unicode; + int core_sparse_checkout_cone; /* section "branch" config values */ enum branch_track branch_track; @@ -177,7 +178,6 @@ extern unsigned long pack_size_limit_cfg; extern int protect_hfs; extern int protect_ntfs; -extern int core_sparse_checkout_cone; extern int sparse_expect_files_outside_of_patterns; enum rebase_setup_type { diff --git a/sparse-index.c b/sparse-index.c index 386be1d6f171a8..f1b603f84ee51e 100644 --- a/sparse-index.c +++ b/sparse-index.c @@ -154,7 +154,7 @@ int is_sparse_index_allowed(struct index_state *istate, int flags) { struct repo_config_values *cfg = repo_config_values(the_repository); - if (!cfg->apply_sparse_checkout || !core_sparse_checkout_cone) + if (!cfg->apply_sparse_checkout || !cfg->core_sparse_checkout_cone) return 0; if (!(flags & SPARSE_INDEX_MEMORY_ONLY)) { From f6721434386a850ee18e5553346b95b8ab24ecd0 Mon Sep 17 00:00:00 2001 From: Olamide Caleb Bello Date: Mon, 23 Feb 2026 16:04:41 +0100 Subject: [PATCH 10/11] env: put "sparse_expect_files_outside_of_patterns" in `repo_config_values` The `sparse_expect_files_outside_of_patterns` variable was previously a global variable, which makes it shared across repository instances within a single process. Move it into `repo_config_values`, this makes the value tied to the repository from which it was read. This preserves existing behavior while avoiding cross-repository state leakage and is another step toward eliminating repository-dependent global state. Update all references to use repo_config_values(). Mentored-by: Christian Couder Mentored-by: Usman Akinyemi Signed-off-by: Olamide Caleb Bello --- environment.c | 6 ++++-- environment.h | 5 +++-- sparse-index.c | 3 ++- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/environment.c b/environment.c index 24afc1603ee8cb..e370f7e349ee65 100644 --- a/environment.c +++ b/environment.c @@ -70,7 +70,6 @@ enum push_default_type push_default = PUSH_DEFAULT_UNSPECIFIED; #endif enum object_creation_mode object_creation_mode = OBJECT_CREATION_MODE; int grafts_keep_true_parents; -int sparse_expect_files_outside_of_patterns; unsigned long pack_size_limit_cfg; #ifndef PROTECT_HFS_DEFAULT @@ -550,8 +549,10 @@ int git_default_core_config(const char *var, const char *value, static int git_default_sparse_config(const char *var, const char *value) { + struct repo_config_values *cfg = repo_config_values(the_repository); + if (!strcmp(var, "sparse.expectfilesoutsideofpatterns")) { - sparse_expect_files_outside_of_patterns = git_config_bool(var, value); + cfg->sparse_expect_files_outside_of_patterns = git_config_bool(var, value); return 0; } @@ -742,4 +743,5 @@ void repo_config_values_init(struct repo_config_values *cfg) cfg->pack_compression_level = Z_DEFAULT_COMPRESSION; cfg->precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */ cfg->core_sparse_checkout_cone = 0; + cfg->sparse_expect_files_outside_of_patterns = 0; } diff --git a/environment.h b/environment.h index 44c022d9cc87dc..b1431b293b0040 100644 --- a/environment.h +++ b/environment.h @@ -97,6 +97,9 @@ struct repo_config_values { int precomposed_unicode; int core_sparse_checkout_cone; + /* section "sparse" config values */ + int sparse_expect_files_outside_of_patterns; + /* section "branch" config values */ enum branch_track branch_track; }; @@ -178,8 +181,6 @@ extern unsigned long pack_size_limit_cfg; extern int protect_hfs; extern int protect_ntfs; -extern int sparse_expect_files_outside_of_patterns; - enum rebase_setup_type { AUTOREBASE_NEVER = 0, AUTOREBASE_LOCAL, diff --git a/sparse-index.c b/sparse-index.c index f1b603f84ee51e..1ed769b78d8de1 100644 --- a/sparse-index.c +++ b/sparse-index.c @@ -673,8 +673,9 @@ static void clear_skip_worktree_from_present_files_full(struct index_state *ista void clear_skip_worktree_from_present_files(struct index_state *istate) { struct repo_config_values *cfg = repo_config_values(the_repository); + if (!cfg->apply_sparse_checkout || - sparse_expect_files_outside_of_patterns) + cfg->sparse_expect_files_outside_of_patterns) return; if (clear_skip_worktree_from_present_files_sparse(istate)) { From cbaf8c62d178d166f905c31bc1f7fd21d7bb9afe Mon Sep 17 00:00:00 2001 From: Olamide Caleb Bello Date: Sat, 21 Feb 2026 19:32:43 +0100 Subject: [PATCH 11/11] env: move "warn_on_object_refname_ambiguity" into `repo_config_values` The `warn_on_object_refname_ambiguity` variable was previously a global integer, which makes it shared across repository instances in a single process. Move it into `repo_config_values` so the value is associated with the repository from which it was read. This preserves existing behavior while avoiding cross-repository state leakage and is another step toward eliminating repository-dependent global state. Update all references to use repo_config_values(). Mentored-by: Christian Couder Mentored-by: Usman Akinyemi Signed-off-by: Olamide Caleb Bello --- builtin/cat-file.c | 7 ++++--- builtin/pack-objects.c | 7 ++++--- environment.c | 2 +- environment.h | 2 +- object-name.c | 3 ++- revision.c | 7 ++++--- submodule.c | 7 ++++--- 7 files changed, 20 insertions(+), 15 deletions(-) diff --git a/builtin/cat-file.c b/builtin/cat-file.c index df8e87a81f5eee..d70b3420057145 100644 --- a/builtin/cat-file.c +++ b/builtin/cat-file.c @@ -875,6 +875,7 @@ static int batch_objects(struct batch_options *opt) struct strbuf input = STRBUF_INIT; struct strbuf output = STRBUF_INIT; struct expand_data data = EXPAND_DATA_INIT; + struct repo_config_values *cfg = repo_config_values(the_repository); int save_warning; int retval = 0; @@ -947,8 +948,8 @@ static int batch_objects(struct batch_options *opt) * warn) ends up dwarfing the actual cost of the object lookups * themselves. We can work around it by just turning off the warning. */ - save_warning = warn_on_object_refname_ambiguity; - warn_on_object_refname_ambiguity = 0; + save_warning = cfg->warn_on_object_refname_ambiguity; + cfg->warn_on_object_refname_ambiguity = 0; if (opt->batch_mode == BATCH_MODE_QUEUE_AND_DISPATCH) { batch_objects_command(opt, &output, &data); @@ -976,7 +977,7 @@ static int batch_objects(struct batch_options *opt) cleanup: strbuf_release(&input); strbuf_release(&output); - warn_on_object_refname_ambiguity = save_warning; + cfg->warn_on_object_refname_ambiguity = save_warning; return retval; } diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c index ef7ff18546c749..232150161598b3 100644 --- a/builtin/pack-objects.c +++ b/builtin/pack-objects.c @@ -4661,6 +4661,7 @@ static void get_object_list(struct rev_info *revs, struct strvec *argv) struct setup_revision_opt s_r_opt = { .allow_exclude_promisor_objects = 1, }; + struct repo_config_values *cfg = repo_config_values(the_repository); char line[1000]; int flags = 0; int save_warning; @@ -4671,8 +4672,8 @@ static void get_object_list(struct rev_info *revs, struct strvec *argv) /* make sure shallows are read */ is_repository_shallow(the_repository); - save_warning = warn_on_object_refname_ambiguity; - warn_on_object_refname_ambiguity = 0; + save_warning = cfg->warn_on_object_refname_ambiguity; + cfg->warn_on_object_refname_ambiguity = 0; while (fgets(line, sizeof(line), stdin) != NULL) { int len = strlen(line); @@ -4700,7 +4701,7 @@ static void get_object_list(struct rev_info *revs, struct strvec *argv) die(_("bad revision '%s'"), line); } - warn_on_object_refname_ambiguity = save_warning; + cfg->warn_on_object_refname_ambiguity = save_warning; if (use_bitmap_index && !get_object_list_from_bitmap(revs)) return; diff --git a/environment.c b/environment.c index e370f7e349ee65..bd7e5a252975fd 100644 --- a/environment.c +++ b/environment.c @@ -47,7 +47,6 @@ int minimum_abbrev = 4, default_abbrev = -1; int ignore_case; int assume_unchanged; int is_bare_repository_cfg = -1; /* unspecified */ -int warn_on_object_refname_ambiguity = 1; char *git_commit_encoding; char *git_log_output_encoding; char *apply_default_whitespace; @@ -744,4 +743,5 @@ void repo_config_values_init(struct repo_config_values *cfg) cfg->precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */ cfg->core_sparse_checkout_cone = 0; cfg->sparse_expect_files_outside_of_patterns = 0; + cfg->warn_on_object_refname_ambiguity = 1; } diff --git a/environment.h b/environment.h index b1431b293b0040..f0f0c8a227cca4 100644 --- a/environment.h +++ b/environment.h @@ -96,6 +96,7 @@ struct repo_config_values { int pack_compression_level; int precomposed_unicode; int core_sparse_checkout_cone; + int warn_on_object_refname_ambiguity; /* section "sparse" config values */ int sparse_expect_files_outside_of_patterns; @@ -173,7 +174,6 @@ extern int has_symlinks; extern int minimum_abbrev, default_abbrev; extern int ignore_case; extern int assume_unchanged; -extern int warn_on_object_refname_ambiguity; extern char *apply_default_whitespace; extern char *apply_default_ignorewhitespace; extern unsigned long pack_size_limit_cfg; diff --git a/object-name.c b/object-name.c index 7b14c3bf9b9b48..ddd863d29384ab 100644 --- a/object-name.c +++ b/object-name.c @@ -969,11 +969,12 @@ static int get_oid_basic(struct repository *r, const char *str, int len, int refs_found = 0; int at, reflog_len, nth_prior = 0; int fatal = !(flags & GET_OID_QUIETLY); + struct repo_config_values *cfg = repo_config_values(the_repository); if (len == r->hash_algo->hexsz && !get_oid_hex(str, oid)) { if (!(flags & GET_OID_SKIP_AMBIGUITY_CHECK) && repo_settings_get_warn_ambiguous_refs(r) && - warn_on_object_refname_ambiguity) { + cfg->warn_on_object_refname_ambiguity) { refs_found = repo_dwim_ref(r, str, len, &tmp_oid, &real_ref, 0); if (refs_found > 0) { warning(warn_msg, len, str); diff --git a/revision.c b/revision.c index 29972c3a19887a..cc7a1c58cf6d5b 100644 --- a/revision.c +++ b/revision.c @@ -2901,9 +2901,10 @@ static void read_revisions_from_stdin(struct rev_info *revs, int seen_end_of_options = 0; int save_warning; int flags = 0; + struct repo_config_values *cfg = repo_config_values(the_repository); - save_warning = warn_on_object_refname_ambiguity; - warn_on_object_refname_ambiguity = 0; + save_warning = cfg->warn_on_object_refname_ambiguity; + cfg->warn_on_object_refname_ambiguity = 0; strbuf_init(&sb, 1000); while (strbuf_getline(&sb, stdin) != EOF) { @@ -2937,7 +2938,7 @@ static void read_revisions_from_stdin(struct rev_info *revs, read_pathspec_from_stdin(&sb, prune); strbuf_release(&sb); - warn_on_object_refname_ambiguity = save_warning; + cfg->warn_on_object_refname_ambiguity = save_warning; } static void NORETURN diagnose_missing_default(const char *def) diff --git a/submodule.c b/submodule.c index 508938e4da5058..486b41011c8271 100644 --- a/submodule.c +++ b/submodule.c @@ -898,12 +898,13 @@ static void collect_changed_submodules(struct repository *r, struct setup_revision_opt s_r_opt = { .assume_dashdash = 1, }; + struct repo_config_values *cfg = repo_config_values(the_repository); - save_warning = warn_on_object_refname_ambiguity; - warn_on_object_refname_ambiguity = 0; + save_warning = cfg->warn_on_object_refname_ambiguity; + cfg->warn_on_object_refname_ambiguity = 0; repo_init_revisions(r, &rev, NULL); setup_revisions_from_strvec(argv, &rev, &s_r_opt); - warn_on_object_refname_ambiguity = save_warning; + cfg->warn_on_object_refname_ambiguity = save_warning; if (prepare_revision_walk(&rev)) die(_("revision walk setup failed"));