{"thread":{"id":"65344","subject":"[PATCH v2 0/8] repo_config_values: migrate more globals","startedAt":"2026-03-24T12:39:07Z","lastAt":"2026-06-02T17:11:07Z","messageCount":72,"participants":["Olamide Caleb Bello","Karthik Nayak","Phillip Wood","Bello Olamide","Junio C Hamano","Tian Yuchen","Patrick Steinhardt","Christian Couder"],"isPatch":true,"patchVersion":2,"patchTotal":8},"messages":[{"id":"539832","messageId":"20260324123750.157143-1-belkid98@gmail.com","threadId":"65344","inReplyTo":null,"subject":"[PATCH v2 0/8] repo_config_values: migrate more globals","fromName":"Olamide Caleb Bello","fromEmail":"belkid98@gmail.com","sentAt":"2026-03-24T12:37:42Z","receivedAt":"2026-03-24T12:39:07Z","isPatch":true,"body":"Overview\n========\nThis series continues the effort to migrate repository-specific global\nvariables into struct repo_config_values, further reducing global\nstate and improving repository isolation.\n\nThe previous series introduced the infrastructure for storing\nrepository-dependent configuration in repo_config_values. This series\nextends that work by moving additional environment-related globals into\nthat struct and updating their call sites accordingly.\n\nThis helps avoid cross-repository interference when multiple\nrepositories are used within the same process, and continues preparing\nGit for improved library usage and better encapsulation of repository\nstate.\n\nChanges since v1:\n- Dropped \"Base series\" section as the dependency has been merged.\n- Fixed handling of pack_compression_level: removed use of a local copy and\n  updated code to operate directly on cfg->pack_compression_level to avoid\n  inconsistencies with option parsing.\n\nOlamide Caleb Bello (8):\n  environment: move \"trust_ctime\" into `struct repo_config_values`\n  environment: move \"check_stat\" into `struct repo_config_values`\n  environment: move `zlib_compression_level` into repo_config_values\n  environment: move \"pack_compression_level\" into `struct\n    repo_config_values`\n  environment: move \"precomposed_unicode\" into `struct\n    repo_config_values`\n  env: move \"core_sparse_checkout_cone\" into `struct repo_config_values`\n  env: put \"sparse_expect_files_outside_of_patterns\" in\n    `repo_config_values`\n  env: move \"warn_on_object_refname_ambiguity\" into `repo_config_values`\n\n builtin/cat-file.c        |  7 ++++---\n builtin/fast-import.c     |  8 +++++---\n builtin/index-pack.c      |  3 ++-\n builtin/mv.c              |  2 +-\n builtin/pack-objects.c    | 24 +++++++++++++----------\n builtin/sparse-checkout.c | 37 +++++++++++++++++++++---------------\n compat/precompose_utf8.c  | 20 +++++++++++++-------\n diff.c                    |  3 ++-\n dir.c                     |  3 ++-\n entry.c                   |  3 ++-\n environment.c             | 40 +++++++++++++++++++++------------------\n environment.h             | 19 ++++++++++---------\n http-push.c               |  3 ++-\n object-file.c             |  6 ++++--\n object-name.c             |  3 ++-\n revision.c                |  7 ++++---\n sparse-index.c            |  4 ++--\n statinfo.c                | 12 +++++++-----\n submodule.c               |  7 ++++---\n upload-pack.c             |  3 ++-\n 20 files changed, 126 insertions(+), 88 deletions(-)\n\n-- \n2.53.0.155.g9f36b15afa\n\n"},{"id":"539833","messageId":"20260324123750.157143-2-belkid98@gmail.com","threadId":"65344","inReplyTo":"20260324123750.157143-1-belkid98@gmail.com","subject":"[PATCH v2 1/8] environment: move \"trust_ctime\" into `struct repo_config_values`","fromName":"Olamide Caleb Bello","fromEmail":"belkid98@gmail.com","sentAt":"2026-03-24T12:37:43Z","receivedAt":"2026-03-24T12:39:11Z","isPatch":true,"body":"The `core.trustctime` configuration is currently stored in the global\nvariable `trust_ctime`, which makes it shared across repository\ninstances in a single process.\n\nStore it instead in `repo_config_values`, so the value is tied to the\nrepository from which it was read. This preserves existing behavior\nwhile avoiding cross-repository state leakage and continues the effort\nto reduce reliance on global configuration state.\n\nUpdate all references to use repo_config_values().\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Usman Akinyemi <usmanakinyemi202@gmail.com>\nSigned-off-by: Olamide Caleb Bello <belkid98@gmail.com>\n---\n environment.c | 4 ++--\n environment.h | 2 +-\n statinfo.c    | 6 ++++--\n 3 files changed, 7 insertions(+), 5 deletions(-)\n\ndiff --git a/environment.c b/environment.c\nindex fc3ed8bb1c..0a9067729e 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -42,7 +42,6 @@ static int pack_compression_seen;\n static int zlib_compression_seen;\n \n int trust_executable_bit = 1;\n-int trust_ctime = 1;\n int check_stat = 1;\n int has_symlinks = 1;\n int minimum_abbrev = 4, default_abbrev = -1;\n@@ -309,7 +308,7 @@ int git_default_core_config(const char *var, const char *value,\n \t\treturn 0;\n \t}\n \tif (!strcmp(var, \"core.trustctime\")) {\n-\t\ttrust_ctime = git_config_bool(var, value);\n+\t\tcfg->trust_ctime = git_config_bool(var, value);\n \t\treturn 0;\n \t}\n \tif (!strcmp(var, \"core.checkstat\")) {\n@@ -721,4 +720,5 @@ void repo_config_values_init(struct repo_config_values *cfg)\n \tcfg->attributes_file = NULL;\n \tcfg->apply_sparse_checkout = 0;\n \tcfg->branch_track = BRANCH_TRACK_REMOTE;\n+\tcfg->trust_ctime = 1;\n }\ndiff --git a/environment.h b/environment.h\nindex 123a71cdc8..64d537686e 100644\n--- a/environment.h\n+++ b/environment.h\n@@ -91,6 +91,7 @@ struct repo_config_values {\n \t/* section \"core\" config values */\n \tchar *attributes_file;\n \tint apply_sparse_checkout;\n+\tint trust_ctime;\n \n \t/* section \"branch\" config values */\n \tenum branch_track branch_track;\n@@ -161,7 +162,6 @@ extern char *git_work_tree_cfg;\n \n /* Environment bits from configuration mechanism */\n extern int trust_executable_bit;\n-extern int trust_ctime;\n extern int check_stat;\n extern int has_symlinks;\n extern int minimum_abbrev, default_abbrev;\ndiff --git a/statinfo.c b/statinfo.c\nindex 30a164b0e6..4fc12053f4 100644\n--- a/statinfo.c\n+++ b/statinfo.c\n@@ -3,6 +3,7 @@\n #include \"git-compat-util.h\"\n #include \"environment.h\"\n #include \"statinfo.h\"\n+#include \"repository.h\"\n \n /*\n  * Munge st_size into an unsigned int.\n@@ -63,17 +64,18 @@ void fake_lstat_data(const struct stat_data *sd, struct stat *st)\n int match_stat_data(const struct stat_data *sd, struct stat *st)\n {\n \tint changed = 0;\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n \tif (sd->sd_mtime.sec != (unsigned int)st->st_mtime)\n \t\tchanged |= MTIME_CHANGED;\n-\tif (trust_ctime && check_stat &&\n+\tif (cfg->trust_ctime && check_stat &&\n \t    sd->sd_ctime.sec != (unsigned int)st->st_ctime)\n \t\tchanged |= CTIME_CHANGED;\n \n #ifdef USE_NSEC\n \tif (check_stat && sd->sd_mtime.nsec != ST_MTIME_NSEC(*st))\n \t\tchanged |= MTIME_CHANGED;\n-\tif (trust_ctime && check_stat &&\n+\tif (cfg->trust_ctime && check_stat &&\n \t    sd->sd_ctime.nsec != ST_CTIME_NSEC(*st))\n \t\tchanged |= CTIME_CHANGED;\n #endif\n-- \n2.53.0.155.g9f36b15afa\n\n"},{"id":"539834","messageId":"20260324123750.157143-3-belkid98@gmail.com","threadId":"65344","inReplyTo":"20260324123750.157143-1-belkid98@gmail.com","subject":"[PATCH v2 2/8] environment: move \"check_stat\" into `struct repo_config_values`","fromName":"Olamide Caleb Bello","fromEmail":"belkid98@gmail.com","sentAt":"2026-03-24T12:37:44Z","receivedAt":"2026-03-24T12:39:13Z","isPatch":true,"body":"The `core.checkstat` configuration is currently stored in the global\nvariable `check_stat`, which makes it shared across repository\ninstances within a single process.\n\nStore it instead in `repo_config_values` so the value is associated\nwith the repository from which it was read. This preserves existing\nbehavior while avoiding cross-repository state leakage and continues\nthe effort to reduce reliance on global configuration state.\n\nUpdate all references to use repo_config_values().\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Usman Akinyemi <usmanakinyemi202@gmail.com>\nSigned-off-by: Olamide Caleb Bello <belkid98@gmail.com>\n---\n entry.c       |  3 ++-\n environment.c |  6 +++---\n environment.h |  2 +-\n statinfo.c    | 10 +++++-----\n 4 files changed, 11 insertions(+), 10 deletions(-)\n\ndiff --git a/entry.c b/entry.c\nindex 7817aee362..c55e867d8a 100644\n--- a/entry.c\n+++ b/entry.c\n@@ -443,7 +443,8 @@ static int check_path(const char *path, int len, struct stat *st, int skiplen)\n static void mark_colliding_entries(const struct checkout *state,\n \t\t\t\t   struct cache_entry *ce, struct stat *st)\n {\n-\tint trust_ino = check_stat;\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n+\tint trust_ino = cfg->check_stat;\n \n #if defined(GIT_WINDOWS_NATIVE) || defined(__CYGWIN__)\n \ttrust_ino = 0;\ndiff --git a/environment.c b/environment.c\nindex 0a9067729e..8542ac3141 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -42,7 +42,6 @@ static int pack_compression_seen;\n static int zlib_compression_seen;\n \n int trust_executable_bit = 1;\n-int check_stat = 1;\n int has_symlinks = 1;\n int minimum_abbrev = 4, default_abbrev = -1;\n int ignore_case;\n@@ -315,9 +314,9 @@ int git_default_core_config(const char *var, const char *value,\n \t\tif (!value)\n \t\t\treturn config_error_nonbool(var);\n \t\tif (!strcasecmp(value, \"default\"))\n-\t\t\tcheck_stat = 1;\n+\t\t\tcfg->check_stat = 1;\n \t\telse if (!strcasecmp(value, \"minimal\"))\n-\t\t\tcheck_stat = 0;\n+\t\t\tcfg->check_stat = 0;\n \t\telse\n \t\t\treturn error(_(\"invalid value for '%s': '%s'\"),\n \t\t\t\t     var, value);\n@@ -721,4 +720,5 @@ void repo_config_values_init(struct repo_config_values *cfg)\n \tcfg->apply_sparse_checkout = 0;\n \tcfg->branch_track = BRANCH_TRACK_REMOTE;\n \tcfg->trust_ctime = 1;\n+\tcfg->check_stat = 1;\n }\ndiff --git a/environment.h b/environment.h\nindex 64d537686e..1d3e2e4f23 100644\n--- a/environment.h\n+++ b/environment.h\n@@ -92,6 +92,7 @@ struct repo_config_values {\n \tchar *attributes_file;\n \tint apply_sparse_checkout;\n \tint trust_ctime;\n+\tint check_stat;\n \n \t/* section \"branch\" config values */\n \tenum branch_track branch_track;\n@@ -162,7 +163,6 @@ extern char *git_work_tree_cfg;\n \n /* Environment bits from configuration mechanism */\n extern int trust_executable_bit;\n-extern int check_stat;\n extern int has_symlinks;\n extern int minimum_abbrev, default_abbrev;\n extern int ignore_case;\ndiff --git a/statinfo.c b/statinfo.c\nindex 4fc12053f4..5e00af127d 100644\n--- a/statinfo.c\n+++ b/statinfo.c\n@@ -68,19 +68,19 @@ int match_stat_data(const struct stat_data *sd, struct stat *st)\n \n \tif (sd->sd_mtime.sec != (unsigned int)st->st_mtime)\n \t\tchanged |= MTIME_CHANGED;\n-\tif (cfg->trust_ctime && check_stat &&\n+\tif (cfg->trust_ctime && cfg->check_stat &&\n \t    sd->sd_ctime.sec != (unsigned int)st->st_ctime)\n \t\tchanged |= CTIME_CHANGED;\n \n #ifdef USE_NSEC\n-\tif (check_stat && sd->sd_mtime.nsec != ST_MTIME_NSEC(*st))\n+\tif (cfg->check_stat && sd->sd_mtime.nsec != ST_MTIME_NSEC(*st))\n \t\tchanged |= MTIME_CHANGED;\n-\tif (cfg->trust_ctime && check_stat &&\n+\tif (cfg->trust_ctime && cfg->check_stat &&\n \t    sd->sd_ctime.nsec != ST_CTIME_NSEC(*st))\n \t\tchanged |= CTIME_CHANGED;\n #endif\n \n-\tif (check_stat) {\n+\tif (cfg->check_stat) {\n \t\tif (sd->sd_uid != (unsigned int) st->st_uid ||\n \t\t\tsd->sd_gid != (unsigned int) st->st_gid)\n \t\t\tchanged |= OWNER_CHANGED;\n@@ -94,7 +94,7 @@ int match_stat_data(const struct stat_data *sd, struct stat *st)\n \t * clients will have different views of what \"device\"\n \t * the filesystem is on\n \t */\n-\tif (check_stat && sd->sd_dev != (unsigned int) st->st_dev)\n+\tif (cfg->check_stat && sd->sd_dev != (unsigned int) st->st_dev)\n \t\t\tchanged |= INODE_CHANGED;\n #endif\n \n-- \n2.53.0.155.g9f36b15afa\n\n"},{"id":"539835","messageId":"20260324123750.157143-4-belkid98@gmail.com","threadId":"65344","inReplyTo":"20260324123750.157143-1-belkid98@gmail.com","subject":"[PATCH v2 3/8] environment: move `zlib_compression_level` into repo_config_values","fromName":"Olamide Caleb Bello","fromEmail":"belkid98@gmail.com","sentAt":"2026-03-24T12:37:45Z","receivedAt":"2026-03-24T12:39:16Z","isPatch":true,"body":"The `zlib_compression_level` configuration is currently stored in the\nglobal variable `zlib_compression_level`, which makes it shared across\nrepository instances within a single process.\n\nStore it instead in `repo_config_values` so the value is associated\nwith the repository from which it was read. This preserves existing\nbehavior while avoiding cross-repository state leakage and continues\nthe effort to reduce reliance on global configuration state.\n\nUpdate all references to use repo_config_values().\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Usman Akinyemi <usmanakinyemi202@gmail.com>\nSigned-off-by: Olamide Caleb Bello <belkid98@gmail.com>\n---\n builtin/index-pack.c | 3 ++-\n diff.c               | 3 ++-\n environment.c        | 6 +++---\n environment.h        | 2 +-\n http-push.c          | 3 ++-\n object-file.c        | 3 ++-\n 6 files changed, 12 insertions(+), 8 deletions(-)\n\ndiff --git a/builtin/index-pack.c b/builtin/index-pack.c\nindex b67fb0256c..dd82eed76f 100644\n--- a/builtin/index-pack.c\n+++ b/builtin/index-pack.c\n@@ -1416,8 +1416,9 @@ static int write_compressed(struct hashfile *f, void *in, unsigned int size)\n \tgit_zstream stream;\n \tint status;\n \tunsigned char outbuf[4096];\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n-\tgit_deflate_init(&stream, zlib_compression_level);\n+\tgit_deflate_init(&stream, cfg->zlib_compression_level);\n \tstream.next_in = in;\n \tstream.avail_in = size;\n \ndiff --git a/diff.c b/diff.c\nindex 501648a5c4..4bc0297873 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -3365,8 +3365,9 @@ static unsigned char *deflate_it(char *data,\n \tint bound;\n \tunsigned char *deflated;\n \tgit_zstream stream;\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n-\tgit_deflate_init(&stream, zlib_compression_level);\n+\tgit_deflate_init(&stream, cfg->zlib_compression_level);\n \tbound = git_deflate_bound(&stream, size);\n \tdeflated = xmalloc(bound);\n \tstream.next_out = deflated;\ndiff --git a/environment.c b/environment.c\nindex 8542ac3141..5b0e88b65c 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -52,7 +52,6 @@ char *git_commit_encoding;\n char *git_log_output_encoding;\n char *apply_default_whitespace;\n char *apply_default_ignorewhitespace;\n-int zlib_compression_level = Z_BEST_SPEED;\n int pack_compression_level = Z_DEFAULT_COMPRESSION;\n int fsync_object_files = -1;\n int use_fsync = -1;\n@@ -377,7 +376,7 @@ int git_default_core_config(const char *var, const char *value,\n \t\t\tlevel = Z_DEFAULT_COMPRESSION;\n \t\telse if (level < 0 || level > Z_BEST_COMPRESSION)\n \t\t\tdie(_(\"bad zlib compression level %d\"), level);\n-\t\tzlib_compression_level = level;\n+\t\tcfg->zlib_compression_level = level;\n \t\tzlib_compression_seen = 1;\n \t\treturn 0;\n \t}\n@@ -389,7 +388,7 @@ int git_default_core_config(const char *var, const char *value,\n \t\telse if (level < 0 || level > Z_BEST_COMPRESSION)\n \t\t\tdie(_(\"bad zlib compression level %d\"), level);\n \t\tif (!zlib_compression_seen)\n-\t\t\tzlib_compression_level = level;\n+\t\t\tcfg->zlib_compression_level = level;\n \t\tif (!pack_compression_seen)\n \t\t\tpack_compression_level = level;\n \t\treturn 0;\n@@ -721,4 +720,5 @@ void repo_config_values_init(struct repo_config_values *cfg)\n \tcfg->branch_track = BRANCH_TRACK_REMOTE;\n \tcfg->trust_ctime = 1;\n \tcfg->check_stat = 1;\n+\tcfg->zlib_compression_level = Z_BEST_SPEED;\n }\ndiff --git a/environment.h b/environment.h\nindex 1d3e2e4f23..93201620af 100644\n--- a/environment.h\n+++ b/environment.h\n@@ -93,6 +93,7 @@ struct repo_config_values {\n \tint apply_sparse_checkout;\n \tint trust_ctime;\n \tint check_stat;\n+\tint zlib_compression_level;\n \n \t/* section \"branch\" config values */\n \tenum branch_track branch_track;\n@@ -170,7 +171,6 @@ extern int assume_unchanged;\n extern int warn_on_object_refname_ambiguity;\n extern char *apply_default_whitespace;\n extern char *apply_default_ignorewhitespace;\n-extern int zlib_compression_level;\n extern int pack_compression_level;\n extern unsigned long pack_size_limit_cfg;\n \ndiff --git a/http-push.c b/http-push.c\nindex 9ae6062198..c6bf9ff387 100644\n--- a/http-push.c\n+++ b/http-push.c\n@@ -369,13 +369,14 @@ static void start_put(struct transfer_request *request)\n \tint hdrlen;\n \tssize_t size;\n \tgit_zstream stream;\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n \tunpacked = odb_read_object(the_repository->objects, &request->obj->oid,\n \t\t\t\t   &type, &len);\n \thdrlen = format_object_header(hdr, sizeof(hdr), type, len);\n \n \t/* Set it up */\n-\tgit_deflate_init(&stream, zlib_compression_level);\n+\tgit_deflate_init(&stream, cfg->zlib_compression_level);\n \tsize = git_deflate_bound(&stream, len + hdrlen);\n \tstrbuf_grow(&request->buffer.buf, size);\n \trequest->buffer.posn = 0;\ndiff --git a/object-file.c b/object-file.c\nindex 3094140055..8b719a915c 100644\n--- a/object-file.c\n+++ b/object-file.c\n@@ -891,6 +891,7 @@ static int start_loose_object_common(struct odb_source *source,\n \tconst struct git_hash_algo *algo = source->odb->repo->hash_algo;\n \tconst struct git_hash_algo *compat = source->odb->repo->compat_hash_algo;\n \tint fd;\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n \tfd = create_tmpfile(source->odb->repo, tmp_file, filename);\n \tif (fd < 0) {\n@@ -906,7 +907,7 @@ static int start_loose_object_common(struct odb_source *source,\n \t}\n \n \t/*  Setup zlib stream for compression */\n-\tgit_deflate_init(stream, zlib_compression_level);\n+\tgit_deflate_init(stream, cfg->zlib_compression_level);\n \tstream->next_out = buf;\n \tstream->avail_out = buflen;\n \talgo->init_fn(c);\n-- \n2.53.0.155.g9f36b15afa\n\n"},{"id":"539836","messageId":"20260324123750.157143-5-belkid98@gmail.com","threadId":"65344","inReplyTo":"20260324123750.157143-1-belkid98@gmail.com","subject":"[PATCH v2 4/8] environment: move \"pack_compression_level\" into `struct repo_config_values`","fromName":"Olamide Caleb Bello","fromEmail":"belkid98@gmail.com","sentAt":"2026-03-24T12:37:46Z","receivedAt":"2026-03-24T12:39:19Z","isPatch":true,"body":"The `pack_compression_level` configuration is currently stored in the\nglobal variable `pack_compression_level`, which makes it shared across\nrepository instances within a single process.\n\nStore it instead in `repo_config_values` so the value is associated\nwith the repository from which it was read. This preserves existing\nbehavior while avoiding cross-repository state leakage and is another\nstep toward eliminating repository-dependent global state.\n\nUpdate all references to use repo_config_values().\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Usman Akinyemi <usmanakinyemi202@gmail.com>\nSigned-off-by: Olamide Caleb Bello <belkid98@gmail.com>\n---\n builtin/fast-import.c  |  8 +++++---\n builtin/pack-objects.c | 17 ++++++++++-------\n environment.c          |  8 +++++---\n environment.h          |  2 +-\n object-file.c          |  3 ++-\n 5 files changed, 23 insertions(+), 15 deletions(-)\n\ndiff --git a/builtin/fast-import.c b/builtin/fast-import.c\nindex b8a7757cfd..6475cdae85 100644\n--- a/builtin/fast-import.c\n+++ b/builtin/fast-import.c\n@@ -963,6 +963,7 @@ static int store_object(\n \tunsigned long hdrlen, deltalen;\n \tstruct git_hash_ctx c;\n \tgit_zstream s;\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n \thdrlen = format_object_header((char *)hdr, sizeof(hdr), type,\n \t\t\t\t      dat->len);\n@@ -1001,7 +1002,7 @@ static int store_object(\n \t} else\n \t\tdelta = NULL;\n \n-\tgit_deflate_init(&s, pack_compression_level);\n+\tgit_deflate_init(&s, cfg->pack_compression_level);\n \tif (delta) {\n \t\ts.next_in = delta;\n \t\ts.avail_in = deltalen;\n@@ -1028,7 +1029,7 @@ static int store_object(\n \t\tif (delta) {\n \t\t\tFREE_AND_NULL(delta);\n \n-\t\t\tgit_deflate_init(&s, pack_compression_level);\n+\t\t\tgit_deflate_init(&s, cfg->pack_compression_level);\n \t\t\ts.next_in = (void *)dat->buf;\n \t\t\ts.avail_in = dat->len;\n \t\t\ts.avail_out = git_deflate_bound(&s, s.avail_in);\n@@ -1111,6 +1112,7 @@ static void stream_blob(uintmax_t len, struct object_id *oidout, uintmax_t mark)\n \tstruct git_hash_ctx c;\n \tgit_zstream s;\n \tstruct hashfile_checkpoint checkpoint;\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \tint status = Z_OK;\n \n \t/* Determine if we should auto-checkpoint. */\n@@ -1130,7 +1132,7 @@ static void stream_blob(uintmax_t len, struct object_id *oidout, uintmax_t mark)\n \n \tcrc32_begin(pack_file);\n \n-\tgit_deflate_init(&s, pack_compression_level);\n+\tgit_deflate_init(&s, cfg->pack_compression_level);\n \n \thdrlen = encode_in_pack_object_header(out_buf, out_sz, OBJ_BLOB, len);\n \ndiff --git a/builtin/pack-objects.c b/builtin/pack-objects.c\nindex c1ee4d5ed7..7c5bc96916 100644\n--- a/builtin/pack-objects.c\n+++ b/builtin/pack-objects.c\n@@ -383,8 +383,9 @@ static unsigned long do_compress(void **pptr, unsigned long size)\n \tgit_zstream stream;\n \tvoid *in, *out;\n \tunsigned long maxsize;\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n-\tgit_deflate_init(&stream, pack_compression_level);\n+\tgit_deflate_init(&stream, cfg->pack_compression_level);\n \tmaxsize = git_deflate_bound(&stream, size);\n \n \tin = *pptr;\n@@ -410,8 +411,9 @@ static unsigned long write_large_blob_data(struct odb_read_stream *st, struct ha\n \tunsigned char ibuf[1024 * 16];\n \tunsigned char obuf[1024 * 16];\n \tunsigned long olen = 0;\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n-\tgit_deflate_init(&stream, pack_compression_level);\n+\tgit_deflate_init(&stream, cfg->pack_compression_level);\n \n \tfor (;;) {\n \t\tssize_t readlen;\n@@ -4868,6 +4870,7 @@ int cmd_pack_objects(int argc,\n \tstruct string_list keep_pack_list = STRING_LIST_INIT_NODUP;\n \tstruct list_objects_filter_options filter_options =\n \t\tLIST_OBJECTS_FILTER_INIT;\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n \tstruct option pack_objects_options[] = {\n \t\tOPT_CALLBACK_F('q', \"quiet\", &progress, NULL,\n@@ -4951,7 +4954,7 @@ int cmd_pack_objects(int argc,\n \t\t\t N_(\"ignore packs that have companion .keep file\")),\n \t\tOPT_STRING_LIST(0, \"keep-pack\", &keep_pack_list, N_(\"name\"),\n \t\t\t\tN_(\"ignore this pack\")),\n-\t\tOPT_INTEGER(0, \"compression\", &pack_compression_level,\n+\t\tOPT_INTEGER(0, \"compression\", &cfg->pack_compression_level,\n \t\t\t    N_(\"pack compression level\")),\n \t\tOPT_BOOL(0, \"keep-true-parents\", &grafts_keep_true_parents,\n \t\t\t N_(\"do not hide commits by grafts\")),\n@@ -5110,10 +5113,10 @@ int cmd_pack_objects(int argc,\n \n \tif (!reuse_object)\n \t\treuse_delta = 0;\n-\tif (pack_compression_level == -1)\n-\t\tpack_compression_level = Z_DEFAULT_COMPRESSION;\n-\telse if (pack_compression_level < 0 || pack_compression_level > Z_BEST_COMPRESSION)\n-\t\tdie(_(\"bad pack compression level %d\"), pack_compression_level);\n+\tif (cfg->pack_compression_level == -1)\n+\t\tcfg->pack_compression_level = Z_DEFAULT_COMPRESSION;\n+\telse if (cfg->pack_compression_level < 0 || cfg->pack_compression_level > Z_BEST_COMPRESSION)\n+\t\tdie(_(\"bad pack compression level %d\"), cfg->pack_compression_level);\n \n \tif (!delta_search_threads)\t/* --threads=0 means autodetect */\n \t\tdelta_search_threads = online_cpus();\ndiff --git a/environment.c b/environment.c\nindex 5b0e88b65c..d0d3a4b7d2 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -52,7 +52,6 @@ char *git_commit_encoding;\n char *git_log_output_encoding;\n char *apply_default_whitespace;\n char *apply_default_ignorewhitespace;\n-int pack_compression_level = Z_DEFAULT_COMPRESSION;\n int fsync_object_files = -1;\n int use_fsync = -1;\n enum fsync_method fsync_method = FSYNC_METHOD_DEFAULT;\n@@ -390,7 +389,7 @@ int git_default_core_config(const char *var, const char *value,\n \t\tif (!zlib_compression_seen)\n \t\t\tcfg->zlib_compression_level = level;\n \t\tif (!pack_compression_seen)\n-\t\t\tpack_compression_level = level;\n+\t\t\tcfg->pack_compression_level = level;\n \t\treturn 0;\n \t}\n \n@@ -662,6 +661,8 @@ static int git_default_attr_config(const char *var, const char *value)\n int git_default_config(const char *var, const char *value,\n \t\t       const struct config_context *ctx, void *cb)\n {\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n+\n \tif (starts_with(var, \"core.\"))\n \t\treturn git_default_core_config(var, value, ctx, cb);\n \n@@ -701,7 +702,7 @@ int git_default_config(const char *var, const char *value,\n \t\t\tlevel = Z_DEFAULT_COMPRESSION;\n \t\telse if (level < 0 || level > Z_BEST_COMPRESSION)\n \t\t\tdie(_(\"bad pack compression level %d\"), level);\n-\t\tpack_compression_level = level;\n+\t\tcfg->pack_compression_level = level;\n \t\tpack_compression_seen = 1;\n \t\treturn 0;\n \t}\n@@ -721,4 +722,5 @@ void repo_config_values_init(struct repo_config_values *cfg)\n \tcfg->trust_ctime = 1;\n \tcfg->check_stat = 1;\n \tcfg->zlib_compression_level = Z_BEST_SPEED;\n+\tcfg->pack_compression_level = Z_DEFAULT_COMPRESSION;\n }\ndiff --git a/environment.h b/environment.h\nindex 93201620af..514576b67a 100644\n--- a/environment.h\n+++ b/environment.h\n@@ -94,6 +94,7 @@ struct repo_config_values {\n \tint trust_ctime;\n \tint check_stat;\n \tint zlib_compression_level;\n+\tint pack_compression_level;\n \n \t/* section \"branch\" config values */\n \tenum branch_track branch_track;\n@@ -171,7 +172,6 @@ extern int assume_unchanged;\n extern int warn_on_object_refname_ambiguity;\n extern char *apply_default_whitespace;\n extern char *apply_default_ignorewhitespace;\n-extern int pack_compression_level;\n extern unsigned long pack_size_limit_cfg;\n \n extern int precomposed_unicode;\ndiff --git a/object-file.c b/object-file.c\nindex 8b719a915c..87179fc667 100644\n--- a/object-file.c\n+++ b/object-file.c\n@@ -1420,8 +1420,9 @@ static int stream_blob_to_pack(struct transaction_packfile *state,\n \tint status = Z_OK;\n \tint write_object = (flags & INDEX_WRITE_OBJECT);\n \toff_t offset = 0;\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n-\tgit_deflate_init(&s, pack_compression_level);\n+\tgit_deflate_init(&s, cfg->pack_compression_level);\n \n \thdrlen = encode_in_pack_object_header(obuf, sizeof(obuf), OBJ_BLOB, size);\n \ts.next_out = obuf + hdrlen;\n-- \n2.53.0.155.g9f36b15afa\n\n"},{"id":"539837","messageId":"20260324123750.157143-6-belkid98@gmail.com","threadId":"65344","inReplyTo":"20260324123750.157143-1-belkid98@gmail.com","subject":"[PATCH v2 5/8] environment: move \"precomposed_unicode\" into `struct repo_config_values`","fromName":"Olamide Caleb Bello","fromEmail":"belkid98@gmail.com","sentAt":"2026-03-24T12:37:47Z","receivedAt":"2026-03-24T12:39:21Z","isPatch":true,"body":"The `core.precomposeunicode` configuration is currently stored in the\nglobal variable `precomposed_unicode`, which makes it shared across\nrepository instances within a single process.\n\nStore it instead in `repo_config_values` so the value is associated\nwith the repository from which it was read. This preserves existing\nbehavior while avoiding cross-repository state leakage and is another\nstep toward eliminating repository-dependent global state.\n\nUpdate all references to use repo_config_values().\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Usman Akinyemi <usmanakinyemi202@gmail.com>\nSigned-off-by: Olamide Caleb Bello <belkid98@gmail.com>\n---\n compat/precompose_utf8.c | 20 +++++++++++++-------\n environment.c            |  4 ++--\n environment.h            |  2 +-\n upload-pack.c            |  3 ++-\n 4 files changed, 18 insertions(+), 11 deletions(-)\n\ndiff --git a/compat/precompose_utf8.c b/compat/precompose_utf8.c\nindex 43b3be0114..0e94dbd862 100644\n--- a/compat/precompose_utf8.c\n+++ b/compat/precompose_utf8.c\n@@ -48,16 +48,18 @@ void probe_utf8_pathname_composition(void)\n \tstatic const char *auml_nfc = \"\\xc3\\xa4\";\n \tstatic const char *auml_nfd = \"\\x61\\xcc\\x88\";\n \tint output_fd;\n-\tif (precomposed_unicode != -1)\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n+\n+\tif (cfg->precomposed_unicode != -1)\n \t\treturn; /* We found it defined in the global config, respect it */\n \trepo_git_path_replace(the_repository, &path, \"%s\", auml_nfc);\n \toutput_fd = open(path.buf, O_CREAT|O_EXCL|O_RDWR, 0600);\n \tif (output_fd >= 0) {\n \t\tclose(output_fd);\n \t\trepo_git_path_replace(the_repository, &path, \"%s\", auml_nfd);\n-\t\tprecomposed_unicode = access(path.buf, R_OK) ? 0 : 1;\n+\t\tcfg->precomposed_unicode = access(path.buf, R_OK) ? 0 : 1;\n \t\trepo_config_set(the_repository, \"core.precomposeunicode\",\n-\t\t\t\tprecomposed_unicode ? \"true\" : \"false\");\n+\t\t\t\tcfg->precomposed_unicode ? \"true\" : \"false\");\n \t\trepo_git_path_replace(the_repository, &path, \"%s\", auml_nfc);\n \t\tif (unlink(path.buf))\n \t\t\tdie_errno(_(\"failed to unlink '%s'\"), path.buf);\n@@ -69,14 +71,16 @@ const char *precompose_string_if_needed(const char *in)\n {\n \tsize_t inlen;\n \tsize_t outlen;\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n+\n \tif (!in)\n \t\treturn NULL;\n \tif (has_non_ascii(in, (size_t)-1, &inlen)) {\n \t\ticonv_t ic_prec;\n \t\tchar *out;\n-\t\tif (precomposed_unicode < 0)\n-\t\t\trepo_config_get_bool(the_repository, \"core.precomposeunicode\", &precomposed_unicode);\n-\t\tif (precomposed_unicode != 1)\n+\t\tif (cfg->precomposed_unicode < 0)\n+\t\t\trepo_config_get_bool(the_repository, \"core.precomposeunicode\", &cfg->precomposed_unicode);\n+\t\tif (cfg->precomposed_unicode != 1)\n \t\t\treturn in;\n \t\tic_prec = iconv_open(repo_encoding, path_encoding);\n \t\tif (ic_prec == (iconv_t) -1)\n@@ -130,7 +134,9 @@ PREC_DIR *precompose_utf8_opendir(const char *dirname)\n \n struct dirent_prec_psx *precompose_utf8_readdir(PREC_DIR *prec_dir)\n {\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \tstruct dirent *res;\n+\n \tres = readdir(prec_dir->dirp);\n \tif (res) {\n \t\tsize_t namelenz = strlen(res->d_name) + 1; /* \\0 */\n@@ -149,7 +155,7 @@ struct dirent_prec_psx *precompose_utf8_readdir(PREC_DIR *prec_dir)\n \t\tprec_dir->dirent_nfc->d_ino  = res->d_ino;\n \t\tprec_dir->dirent_nfc->d_type = res->d_type;\n \n-\t\tif ((precomposed_unicode == 1) && has_non_ascii(res->d_name, (size_t)-1, NULL)) {\n+\t\tif ((cfg->precomposed_unicode == 1) && has_non_ascii(res->d_name, (size_t)-1, NULL)) {\n \t\t\tif (prec_dir->ic_precompose == (iconv_t)-1) {\n \t\t\t\tdie(\"iconv_open(%s,%s) failed, but needed:\\n\"\n \t\t\t\t\t\t\"    precomposed unicode is not supported.\\n\"\ndiff --git a/environment.c b/environment.c\nindex d0d3a4b7d2..739b647ebe 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -72,7 +72,6 @@ enum object_creation_mode object_creation_mode = OBJECT_CREATION_MODE;\n int grafts_keep_true_parents;\n int core_sparse_checkout_cone;\n int sparse_expect_files_outside_of_patterns;\n-int precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */\n unsigned long pack_size_limit_cfg;\n \n #ifndef PROTECT_HFS_DEFAULT\n@@ -532,7 +531,7 @@ int git_default_core_config(const char *var, const char *value,\n \t}\n \n \tif (!strcmp(var, \"core.precomposeunicode\")) {\n-\t\tprecomposed_unicode = git_config_bool(var, value);\n+\t\tcfg->precomposed_unicode = git_config_bool(var, value);\n \t\treturn 0;\n \t}\n \n@@ -723,4 +722,5 @@ void repo_config_values_init(struct repo_config_values *cfg)\n \tcfg->check_stat = 1;\n \tcfg->zlib_compression_level = Z_BEST_SPEED;\n \tcfg->pack_compression_level = Z_DEFAULT_COMPRESSION;\n+\tcfg->precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */\n }\ndiff --git a/environment.h b/environment.h\nindex 514576b67a..508cb1afbc 100644\n--- a/environment.h\n+++ b/environment.h\n@@ -95,6 +95,7 @@ struct repo_config_values {\n \tint check_stat;\n \tint zlib_compression_level;\n \tint pack_compression_level;\n+\tint precomposed_unicode;\n \n \t/* section \"branch\" config values */\n \tenum branch_track branch_track;\n@@ -174,7 +175,6 @@ extern char *apply_default_whitespace;\n extern char *apply_default_ignorewhitespace;\n extern unsigned long pack_size_limit_cfg;\n \n-extern int precomposed_unicode;\n extern int protect_hfs;\n extern int protect_ntfs;\n \ndiff --git a/upload-pack.c b/upload-pack.c\nindex 88dac1b65c..afa3ef7655 100644\n--- a/upload-pack.c\n+++ b/upload-pack.c\n@@ -1288,6 +1288,7 @@ static int upload_pack_config(const char *var, const char *value,\n \t\t\t      void *cb_data)\n {\n \tstruct upload_pack_data *data = cb_data;\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n \tif (!strcmp(\"uploadpack.allowtipsha1inwant\", var)) {\n \t\tif (git_config_bool(var, value))\n@@ -1318,7 +1319,7 @@ static int upload_pack_config(const char *var, const char *value,\n \t\tif (value)\n \t\t\tdata->allow_packfile_uris = 1;\n \t} else if (!strcmp(\"core.precomposeunicode\", var)) {\n-\t\tprecomposed_unicode = git_config_bool(var, value);\n+\t\tcfg->precomposed_unicode = git_config_bool(var, value);\n \t} else if (!strcmp(\"transfer.advertisesid\", var)) {\n \t\tdata->advertise_sid = git_config_bool(var, value);\n \t}\n-- \n2.53.0.155.g9f36b15afa\n\n"},{"id":"539838","messageId":"20260324123750.157143-7-belkid98@gmail.com","threadId":"65344","inReplyTo":"20260324123750.157143-1-belkid98@gmail.com","subject":"[PATCH v2 6/8] env: move \"core_sparse_checkout_cone\" into `struct repo_config_values`","fromName":"Olamide Caleb Bello","fromEmail":"belkid98@gmail.com","sentAt":"2026-03-24T12:37:48Z","receivedAt":"2026-03-24T12:39:24Z","isPatch":true,"body":"The `core_sparse_checkout_cone` variable was previously a global integer,\nuninitialized by default. Storing repository-dependent configuration in\nglobals can lead to cross-repository state leakage.\n\nMove it into `repo_config_values` and initialize it to 0 by default.\nThis ensures predictable behavior for repositories that do not set\nthis configuration while preserving existing semantics.\n\nUpdate all references to use repo_config_values().\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Usman Akinyemi <usmanakinyemi202@gmail.com>\nSigned-off-by: Olamide Caleb Bello <belkid98@gmail.com>\n---\n builtin/mv.c              |  2 +-\n builtin/sparse-checkout.c | 37 ++++++++++++++++++++++---------------\n dir.c                     |  3 ++-\n environment.c             |  4 ++--\n environment.h             |  2 +-\n sparse-index.c            |  2 +-\n 6 files changed, 29 insertions(+), 21 deletions(-)\n\ndiff --git a/builtin/mv.c b/builtin/mv.c\nindex 2215d34e31..ef3a326c90 100644\n--- a/builtin/mv.c\n+++ b/builtin/mv.c\n@@ -574,7 +574,7 @@ int cmd_mv(int argc,\n \n \t\tif (ignore_sparse &&\n \t\t    cfg->apply_sparse_checkout &&\n-\t\t    core_sparse_checkout_cone) {\n+\t\t    cfg->core_sparse_checkout_cone) {\n \t\t\t/*\n \t\t\t * NEEDSWORK: we are *not* paying attention to\n \t\t\t * \"out-to-out\" move (<source> is out-of-cone and\ndiff --git a/builtin/sparse-checkout.c b/builtin/sparse-checkout.c\nindex f4aa405da9..92d017b81f 100644\n--- a/builtin/sparse-checkout.c\n+++ b/builtin/sparse-checkout.c\n@@ -73,7 +73,7 @@ static int sparse_checkout_list(int argc, const char **argv, const char *prefix,\n \n \tmemset(&pl, 0, sizeof(pl));\n \n-\tpl.use_cone_patterns = core_sparse_checkout_cone;\n+\tpl.use_cone_patterns = cfg->core_sparse_checkout_cone;\n \n \tsparse_filename = get_sparse_checkout_filename();\n \tres = add_patterns_from_file_to_list(sparse_filename, \"\", 0, &pl, NULL, 0);\n@@ -334,6 +334,7 @@ static int write_patterns_and_update(struct repository *repo,\n \tFILE *fp;\n \tstruct lock_file lk = LOCK_INIT;\n \tint result;\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n \tsparse_filename = get_sparse_checkout_filename();\n \n@@ -353,7 +354,7 @@ static int write_patterns_and_update(struct repository *repo,\n \tif (!fp)\n \t\tdie_errno(_(\"unable to fdopen %s\"), get_lock_file_path(&lk));\n \n-\tif (core_sparse_checkout_cone)\n+\tif (cfg->core_sparse_checkout_cone)\n \t\twrite_cone_to_file(fp, pl);\n \telse\n \t\twrite_patterns_to_file(fp, pl);\n@@ -402,15 +403,15 @@ static enum sparse_checkout_mode update_cone_mode(int *cone_mode) {\n \n \t/* If not specified, use previous definition of cone mode */\n \tif (*cone_mode == -1 && cfg->apply_sparse_checkout)\n-\t\t*cone_mode = core_sparse_checkout_cone;\n+\t\t*cone_mode = cfg->core_sparse_checkout_cone;\n \n \t/* Set cone/non-cone mode appropriately */\n \tcfg->apply_sparse_checkout = 1;\n \tif (*cone_mode == 1 || *cone_mode == -1) {\n-\t\tcore_sparse_checkout_cone = 1;\n+\t\tcfg->core_sparse_checkout_cone = 1;\n \t\treturn MODE_CONE_PATTERNS;\n \t}\n-\tcore_sparse_checkout_cone = 0;\n+\tcfg->core_sparse_checkout_cone = 0;\n \treturn MODE_ALL_PATTERNS;\n }\n \n@@ -577,7 +578,9 @@ static void add_patterns_from_input(struct pattern_list *pl,\n \t\t\t\t    FILE *file)\n {\n \tint i;\n-\tif (core_sparse_checkout_cone) {\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n+\n+\tif (cfg->core_sparse_checkout_cone) {\n \t\tstruct strbuf line = STRBUF_INIT;\n \n \t\thashmap_init(&pl->recursive_hashmap, pl_hashmap_cmp, NULL, 0);\n@@ -636,13 +639,14 @@ static void add_patterns_cone_mode(int argc, const char **argv,\n \tstruct pattern_entry *pe;\n \tstruct hashmap_iter iter;\n \tstruct pattern_list existing;\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \tchar *sparse_filename = get_sparse_checkout_filename();\n \n \tadd_patterns_from_input(pl, argc, argv,\n \t\t\t\tuse_stdin ? stdin : NULL);\n \n \tmemset(&existing, 0, sizeof(existing));\n-\texisting.use_cone_patterns = core_sparse_checkout_cone;\n+\texisting.use_cone_patterns = cfg->core_sparse_checkout_cone;\n \n \tif (add_patterns_from_file_to_list(sparse_filename, \"\", 0,\n \t\t\t\t\t   &existing, NULL, 0))\n@@ -690,7 +694,7 @@ static int modify_pattern_list(struct repository *repo,\n \n \tswitch (m) {\n \tcase ADD:\n-\t\tif (core_sparse_checkout_cone)\n+\t\tif (cfg->core_sparse_checkout_cone)\n \t\t\tadd_patterns_cone_mode(args->nr, args->v, pl, use_stdin);\n \t\telse\n \t\t\tadd_patterns_literal(args->nr, args->v, pl, use_stdin);\n@@ -723,11 +727,12 @@ static void sanitize_paths(struct repository *repo,\n \t\t\t   const char *prefix, int skip_checks)\n {\n \tint i;\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n \tif (!args->nr)\n \t\treturn;\n \n-\tif (prefix && *prefix && core_sparse_checkout_cone) {\n+\tif (prefix && *prefix && cfg->core_sparse_checkout_cone) {\n \t\t/*\n \t\t * The args are not pathspecs, so unfortunately we\n \t\t * cannot imitate how cmd_add() uses parse_pathspec().\n@@ -744,10 +749,10 @@ static void sanitize_paths(struct repository *repo,\n \tif (skip_checks)\n \t\treturn;\n \n-\tif (prefix && *prefix && !core_sparse_checkout_cone)\n+\tif (prefix && *prefix && !cfg->core_sparse_checkout_cone)\n \t\tdie(_(\"please run from the toplevel directory in non-cone mode\"));\n \n-\tif (core_sparse_checkout_cone) {\n+\tif (cfg->core_sparse_checkout_cone) {\n \t\tfor (i = 0; i < args->nr; i++) {\n \t\t\tif (args->v[i][0] == '/')\n \t\t\t\tdie(_(\"specify directories rather than patterns (no leading slash)\"));\n@@ -769,7 +774,7 @@ static void sanitize_paths(struct repository *repo,\n \t\tif (S_ISSPARSEDIR(ce->ce_mode))\n \t\t\tcontinue;\n \n-\t\tif (core_sparse_checkout_cone)\n+\t\tif (cfg->core_sparse_checkout_cone)\n \t\t\tdie(_(\"'%s' is not a directory; to treat it as a directory anyway, rerun with --skip-checks\"), args->v[i]);\n \t\telse\n \t\t\twarning(_(\"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]);\n@@ -836,6 +841,7 @@ static struct sparse_checkout_set_opts {\n static int sparse_checkout_set(int argc, const char **argv, const char *prefix,\n \t\t\t       struct repository *repo)\n {\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \tint default_patterns_nr = 2;\n \tconst char *default_patterns[] = {\"/*\", \"!/*/\", NULL};\n \n@@ -873,7 +879,7 @@ static int sparse_checkout_set(int argc, const char **argv, const char *prefix,\n \t * non-cone mode, if nothing is specified, manually select just the\n \t * top-level directory (much as 'init' would do).\n \t */\n-\tif (!core_sparse_checkout_cone && !set_opts.use_stdin && argc == 0) {\n+\tif (!cfg->core_sparse_checkout_cone && !set_opts.use_stdin && argc == 0) {\n \t\tfor (int i = 0; i < default_patterns_nr; i++)\n \t\t\tstrvec_push(&patterns, default_patterns[i]);\n \t} else {\n@@ -977,7 +983,7 @@ static int sparse_checkout_clean(int argc, const char **argv,\n \tsetup_work_tree();\n \tif (!cfg->apply_sparse_checkout)\n \t\tdie(_(\"must be in a sparse-checkout to clean directories\"));\n-\tif (!core_sparse_checkout_cone)\n+\tif (!cfg->core_sparse_checkout_cone)\n \t\tdie(_(\"must be in a cone-mode sparse-checkout to clean directories\"));\n \n \targc = parse_options(argc, argv, prefix,\n@@ -1141,6 +1147,7 @@ static int sparse_checkout_check_rules(int argc, const char **argv, const char *\n \tFILE *fp;\n \tint ret;\n \tstruct pattern_list pl = {0};\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \tchar *sparse_filename;\n \tcheck_rules_opts.cone_mode = -1;\n \n@@ -1152,7 +1159,7 @@ static int sparse_checkout_check_rules(int argc, const char **argv, const char *\n \t\tcheck_rules_opts.cone_mode = 1;\n \n \tupdate_cone_mode(&check_rules_opts.cone_mode);\n-\tpl.use_cone_patterns = core_sparse_checkout_cone;\n+\tpl.use_cone_patterns = cfg->core_sparse_checkout_cone;\n \tif (check_rules_opts.rules_file) {\n \t\tfp = xfopen(check_rules_opts.rules_file, \"r\");\n \t\tadd_patterns_from_input(&pl, argc, argv, fp);\ndiff --git a/dir.c b/dir.c\nindex 026d8516a9..2744b3e5ca 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -3508,8 +3508,9 @@ int get_sparse_checkout_patterns(struct pattern_list *pl)\n {\n \tint res;\n \tchar *sparse_filename = get_sparse_checkout_filename();\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n-\tpl->use_cone_patterns = core_sparse_checkout_cone;\n+\tpl->use_cone_patterns = cfg->core_sparse_checkout_cone;\n \tres = add_patterns_from_file_to_list(sparse_filename, \"\", 0, pl, NULL, 0);\n \n \tfree(sparse_filename);\ndiff --git a/environment.c b/environment.c\nindex 739b647ebe..b0e873e9f5 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -70,7 +70,6 @@ enum push_default_type push_default = PUSH_DEFAULT_UNSPECIFIED;\n #endif\n enum object_creation_mode object_creation_mode = OBJECT_CREATION_MODE;\n int grafts_keep_true_parents;\n-int core_sparse_checkout_cone;\n int sparse_expect_files_outside_of_patterns;\n unsigned long pack_size_limit_cfg;\n \n@@ -526,7 +525,7 @@ int git_default_core_config(const char *var, const char *value,\n \t}\n \n \tif (!strcmp(var, \"core.sparsecheckoutcone\")) {\n-\t\tcore_sparse_checkout_cone = git_config_bool(var, value);\n+\t\tcfg->core_sparse_checkout_cone = git_config_bool(var, value);\n \t\treturn 0;\n \t}\n \n@@ -723,4 +722,5 @@ void repo_config_values_init(struct repo_config_values *cfg)\n \tcfg->zlib_compression_level = Z_BEST_SPEED;\n \tcfg->pack_compression_level = Z_DEFAULT_COMPRESSION;\n \tcfg->precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */\n+\tcfg->core_sparse_checkout_cone = 0;\n }\ndiff --git a/environment.h b/environment.h\nindex 508cb1afbc..befad9a388 100644\n--- a/environment.h\n+++ b/environment.h\n@@ -96,6 +96,7 @@ struct repo_config_values {\n \tint zlib_compression_level;\n \tint pack_compression_level;\n \tint precomposed_unicode;\n+\tint core_sparse_checkout_cone;\n \n \t/* section \"branch\" config values */\n \tenum branch_track branch_track;\n@@ -178,7 +179,6 @@ extern unsigned long pack_size_limit_cfg;\n extern int protect_hfs;\n extern int protect_ntfs;\n \n-extern int core_sparse_checkout_cone;\n extern int sparse_expect_files_outside_of_patterns;\n \n enum rebase_setup_type {\ndiff --git a/sparse-index.c b/sparse-index.c\nindex 13629c075d..53cb8d64fc 100644\n--- a/sparse-index.c\n+++ b/sparse-index.c\n@@ -154,7 +154,7 @@ int is_sparse_index_allowed(struct index_state *istate, int flags)\n {\n \tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n-\tif (!cfg->apply_sparse_checkout || !core_sparse_checkout_cone)\n+\tif (!cfg->apply_sparse_checkout || !cfg->core_sparse_checkout_cone)\n \t\treturn 0;\n \n \tif (!(flags & SPARSE_INDEX_MEMORY_ONLY)) {\n-- \n2.53.0.155.g9f36b15afa\n\n"},{"id":"539839","messageId":"20260324123750.157143-8-belkid98@gmail.com","threadId":"65344","inReplyTo":"20260324123750.157143-1-belkid98@gmail.com","subject":"[PATCH v2 7/8] env: put \"sparse_expect_files_outside_of_patterns\" in `repo_config_values`","fromName":"Olamide Caleb Bello","fromEmail":"belkid98@gmail.com","sentAt":"2026-03-24T12:37:49Z","receivedAt":"2026-03-24T12:39:27Z","isPatch":true,"body":"The `sparse_expect_files_outside_of_patterns` variable was previously\na global variable, which makes it shared across repository\ninstances within a single process.\n\nMove it into `repo_config_values`, this makes the  value  tied to the\nrepository from which it was read. This preserves existing behavior\nwhile avoiding cross-repository state leakage and is another step\ntoward eliminating repository-dependent global state.\n\nUpdate all references to use repo_config_values().\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Usman Akinyemi <usmanakinyemi202@gmail.com>\nSigned-off-by: Olamide Caleb Bello <belkid98@gmail.com>\n---\n environment.c  | 6 ++++--\n environment.h  | 5 +++--\n sparse-index.c | 2 +-\n 3 files changed, 8 insertions(+), 5 deletions(-)\n\ndiff --git a/environment.c b/environment.c\nindex b0e873e9f5..57587ede56 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -70,7 +70,6 @@ enum push_default_type push_default = PUSH_DEFAULT_UNSPECIFIED;\n #endif\n enum object_creation_mode object_creation_mode = OBJECT_CREATION_MODE;\n int grafts_keep_true_parents;\n-int sparse_expect_files_outside_of_patterns;\n unsigned long pack_size_limit_cfg;\n \n #ifndef PROTECT_HFS_DEFAULT\n@@ -550,8 +549,10 @@ int git_default_core_config(const char *var, const char *value,\n \n static int git_default_sparse_config(const char *var, const char *value)\n {\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n+\n \tif (!strcmp(var, \"sparse.expectfilesoutsideofpatterns\")) {\n-\t\tsparse_expect_files_outside_of_patterns = git_config_bool(var, value);\n+\t\tcfg->sparse_expect_files_outside_of_patterns = git_config_bool(var, value);\n \t\treturn 0;\n \t}\n \n@@ -723,4 +724,5 @@ void repo_config_values_init(struct repo_config_values *cfg)\n \tcfg->pack_compression_level = Z_DEFAULT_COMPRESSION;\n \tcfg->precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */\n \tcfg->core_sparse_checkout_cone = 0;\n+\tcfg->sparse_expect_files_outside_of_patterns = 0;\n }\ndiff --git a/environment.h b/environment.h\nindex befad9a388..609cdaa07f 100644\n--- a/environment.h\n+++ b/environment.h\n@@ -98,6 +98,9 @@ struct repo_config_values {\n \tint precomposed_unicode;\n \tint core_sparse_checkout_cone;\n \n+\t/* section \"sparse\" config values */\n+\tint sparse_expect_files_outside_of_patterns;\n+\n \t/* section \"branch\" config values */\n \tenum branch_track branch_track;\n };\n@@ -179,8 +182,6 @@ extern unsigned long pack_size_limit_cfg;\n extern int protect_hfs;\n extern int protect_ntfs;\n \n-extern int sparse_expect_files_outside_of_patterns;\n-\n enum rebase_setup_type {\n \tAUTOREBASE_NEVER = 0,\n \tAUTOREBASE_LOCAL,\ndiff --git a/sparse-index.c b/sparse-index.c\nindex 53cb8d64fc..1ed769b78d 100644\n--- a/sparse-index.c\n+++ b/sparse-index.c\n@@ -675,7 +675,7 @@ void clear_skip_worktree_from_present_files(struct index_state *istate)\n \tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n \tif (!cfg->apply_sparse_checkout ||\n-\t    sparse_expect_files_outside_of_patterns)\n+\t    cfg->sparse_expect_files_outside_of_patterns)\n \t\treturn;\n \n \tif (clear_skip_worktree_from_present_files_sparse(istate)) {\n-- \n2.53.0.155.g9f36b15afa\n\n"},{"id":"539840","messageId":"20260324123750.157143-9-belkid98@gmail.com","threadId":"65344","inReplyTo":"20260324123750.157143-1-belkid98@gmail.com","subject":"[PATCH v2 8/8] env: move \"warn_on_object_refname_ambiguity\" into `repo_config_values`","fromName":"Olamide Caleb Bello","fromEmail":"belkid98@gmail.com","sentAt":"2026-03-24T12:37:50Z","receivedAt":"2026-03-24T12:39:30Z","isPatch":true,"body":"The `warn_on_object_refname_ambiguity` variable was previously a global\ninteger, which makes it shared across repository instances in a single\nprocess.\n\nMove it into `repo_config_values` so the value is associated with the\nrepository from which it was read. This preserves existing behavior\nwhile avoiding cross-repository state leakage and is another step\ntoward eliminating repository-dependent global state.\n\nUpdate all references to use repo_config_values().\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Usman Akinyemi <usmanakinyemi202@gmail.com>\nSigned-off-by: Olamide Caleb Bello <belkid98@gmail.com>\n---\n builtin/cat-file.c     | 7 ++++---\n builtin/pack-objects.c | 7 ++++---\n environment.c          | 2 +-\n environment.h          | 2 +-\n object-name.c          | 3 ++-\n revision.c             | 7 ++++---\n submodule.c            | 7 ++++---\n 7 files changed, 20 insertions(+), 15 deletions(-)\n\ndiff --git a/builtin/cat-file.c b/builtin/cat-file.c\nindex da059d0e26..32f60f2f64 100644\n--- a/builtin/cat-file.c\n+++ b/builtin/cat-file.c\n@@ -897,6 +897,7 @@ static int batch_objects(struct batch_options *opt)\n \tstruct strbuf input = STRBUF_INIT;\n \tstruct strbuf output = STRBUF_INIT;\n \tstruct expand_data data = EXPAND_DATA_INIT;\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \tint save_warning;\n \tint retval = 0;\n \n@@ -969,8 +970,8 @@ static int batch_objects(struct batch_options *opt)\n \t * warn) ends up dwarfing the actual cost of the object lookups\n \t * themselves. We can work around it by just turning off the warning.\n \t */\n-\tsave_warning = warn_on_object_refname_ambiguity;\n-\twarn_on_object_refname_ambiguity = 0;\n+\tsave_warning = cfg->warn_on_object_refname_ambiguity;\n+\tcfg->warn_on_object_refname_ambiguity = 0;\n \n \tif (opt->batch_mode == BATCH_MODE_QUEUE_AND_DISPATCH) {\n \t\tbatch_objects_command(opt, &output, &data);\n@@ -998,7 +999,7 @@ static int batch_objects(struct batch_options *opt)\n  cleanup:\n \tstrbuf_release(&input);\n \tstrbuf_release(&output);\n-\twarn_on_object_refname_ambiguity = save_warning;\n+\tcfg->warn_on_object_refname_ambiguity = save_warning;\n \treturn retval;\n }\n \ndiff --git a/builtin/pack-objects.c b/builtin/pack-objects.c\nindex 7c5bc96916..b972449ca1 100644\n--- a/builtin/pack-objects.c\n+++ b/builtin/pack-objects.c\n@@ -4653,6 +4653,7 @@ static void get_object_list(struct rev_info *revs, struct strvec *argv)\n \tstruct setup_revision_opt s_r_opt = {\n \t\t.allow_exclude_promisor_objects = 1,\n \t};\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \tchar line[1000];\n \tint flags = 0;\n \tint save_warning;\n@@ -4663,8 +4664,8 @@ static void get_object_list(struct rev_info *revs, struct strvec *argv)\n \t/* make sure shallows are read */\n \tis_repository_shallow(the_repository);\n \n-\tsave_warning = warn_on_object_refname_ambiguity;\n-\twarn_on_object_refname_ambiguity = 0;\n+\tsave_warning = cfg->warn_on_object_refname_ambiguity;\n+\tcfg->warn_on_object_refname_ambiguity = 0;\n \n \twhile (fgets(line, sizeof(line), stdin) != NULL) {\n \t\tint len = strlen(line);\n@@ -4692,7 +4693,7 @@ static void get_object_list(struct rev_info *revs, struct strvec *argv)\n \t\t\tdie(_(\"bad revision '%s'\"), line);\n \t}\n \n-\twarn_on_object_refname_ambiguity = save_warning;\n+\tcfg->warn_on_object_refname_ambiguity = save_warning;\n \n \tif (use_bitmap_index && !get_object_list_from_bitmap(revs))\n \t\treturn;\ndiff --git a/environment.c b/environment.c\nindex 57587ede56..ba2c60103f 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -47,7 +47,6 @@ int minimum_abbrev = 4, default_abbrev = -1;\n int ignore_case;\n int assume_unchanged;\n int is_bare_repository_cfg = -1; /* unspecified */\n-int warn_on_object_refname_ambiguity = 1;\n char *git_commit_encoding;\n char *git_log_output_encoding;\n char *apply_default_whitespace;\n@@ -725,4 +724,5 @@ void repo_config_values_init(struct repo_config_values *cfg)\n \tcfg->precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */\n \tcfg->core_sparse_checkout_cone = 0;\n \tcfg->sparse_expect_files_outside_of_patterns = 0;\n+\tcfg->warn_on_object_refname_ambiguity = 1;\n }\ndiff --git a/environment.h b/environment.h\nindex 609cdaa07f..1ff0a7ba8b 100644\n--- a/environment.h\n+++ b/environment.h\n@@ -97,6 +97,7 @@ struct repo_config_values {\n \tint pack_compression_level;\n \tint precomposed_unicode;\n \tint core_sparse_checkout_cone;\n+\tint warn_on_object_refname_ambiguity;\n \n \t/* section \"sparse\" config values */\n \tint sparse_expect_files_outside_of_patterns;\n@@ -174,7 +175,6 @@ extern int has_symlinks;\n extern int minimum_abbrev, default_abbrev;\n extern int ignore_case;\n extern int assume_unchanged;\n-extern int warn_on_object_refname_ambiguity;\n extern char *apply_default_whitespace;\n extern char *apply_default_ignorewhitespace;\n extern unsigned long pack_size_limit_cfg;\ndiff --git a/object-name.c b/object-name.c\nindex 7b14c3bf9b..ddd863d293 100644\n--- a/object-name.c\n+++ b/object-name.c\n@@ -969,11 +969,12 @@ static int get_oid_basic(struct repository *r, const char *str, int len,\n \tint refs_found = 0;\n \tint at, reflog_len, nth_prior = 0;\n \tint fatal = !(flags & GET_OID_QUIETLY);\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n \tif (len == r->hash_algo->hexsz && !get_oid_hex(str, oid)) {\n \t\tif (!(flags & GET_OID_SKIP_AMBIGUITY_CHECK) &&\n \t\t    repo_settings_get_warn_ambiguous_refs(r) &&\n-\t\t    warn_on_object_refname_ambiguity) {\n+\t\t    cfg->warn_on_object_refname_ambiguity) {\n \t\t\trefs_found = repo_dwim_ref(r, str, len, &tmp_oid, &real_ref, 0);\n \t\t\tif (refs_found > 0) {\n \t\t\t\twarning(warn_msg, len, str);\ndiff --git a/revision.c b/revision.c\nindex 402eb1b029..cff821132b 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -2904,9 +2904,10 @@ static void read_revisions_from_stdin(struct rev_info *revs,\n \tint seen_end_of_options = 0;\n \tint save_warning;\n \tint flags = 0;\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n-\tsave_warning = warn_on_object_refname_ambiguity;\n-\twarn_on_object_refname_ambiguity = 0;\n+\tsave_warning = cfg->warn_on_object_refname_ambiguity;\n+\tcfg->warn_on_object_refname_ambiguity = 0;\n \n \tstrbuf_init(&sb, 1000);\n \twhile (strbuf_getline(&sb, stdin) != EOF) {\n@@ -2940,7 +2941,7 @@ static void read_revisions_from_stdin(struct rev_info *revs,\n \t\tread_pathspec_from_stdin(&sb, prune);\n \n \tstrbuf_release(&sb);\n-\twarn_on_object_refname_ambiguity = save_warning;\n+\tcfg->warn_on_object_refname_ambiguity = save_warning;\n }\n \n static void NORETURN diagnose_missing_default(const char *def)\ndiff --git a/submodule.c b/submodule.c\nindex 508938e4da..486b41011c 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -898,12 +898,13 @@ static void collect_changed_submodules(struct repository *r,\n \tstruct setup_revision_opt s_r_opt = {\n \t\t.assume_dashdash = 1,\n \t};\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n-\tsave_warning = warn_on_object_refname_ambiguity;\n-\twarn_on_object_refname_ambiguity = 0;\n+\tsave_warning = cfg->warn_on_object_refname_ambiguity;\n+\tcfg->warn_on_object_refname_ambiguity = 0;\n \trepo_init_revisions(r, &rev, NULL);\n \tsetup_revisions_from_strvec(argv, &rev, &s_r_opt);\n-\twarn_on_object_refname_ambiguity = save_warning;\n+\tcfg->warn_on_object_refname_ambiguity = save_warning;\n \tif (prepare_revision_walk(&rev))\n \t\tdie(_(\"revision walk setup failed\"));\n \n-- \n2.53.0.155.g9f36b15afa\n\n"},{"id":"541533","messageId":"CAOLa=ZTD+qqgyB4Pn4bcOfP+Ks8Zch+AWZkzhrRRbk-eJvS-mg@mail.gmail.com","threadId":"65344","inReplyTo":"20260324123750.157143-2-belkid98@gmail.com","subject":"Re: [PATCH v2 1/8] environment: move \"trust_ctime\" into `struct repo_config_values`","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2026-04-14T08:52:54Z","receivedAt":"2026-04-14T08:52:55Z","isPatch":true,"body":"Olamide Caleb Bello <belkid98@gmail.com> writes:\n\n> The `core.trustctime` configuration is currently stored in the global\n> variable `trust_ctime`, which makes it shared across repository\n> instances in a single process.\n>\n> Store it instead in `repo_config_values`, so the value is tied to the\n> repository from which it was read. This preserves existing behavior\n> while avoiding cross-repository state leakage and continues the effort\n> to reduce reliance on global configuration state.\n>\n> Update all references to use repo_config_values().\n>\n\nNit: I was hoping you'd also shed light on why this can go into\n`repo_config_values()`. Does it need to be eagerly parsed? If so, why?\n\n> Mentored-by: Christian Couder <christian.couder@gmail.com>\n> Mentored-by: Usman Akinyemi <usmanakinyemi202@gmail.com>\n> Signed-off-by: Olamide Caleb Bello <belkid98@gmail.com>\n> ---\n>  environment.c | 4 ++--\n>  environment.h | 2 +-\n>  statinfo.c    | 6 ++++--\n>  3 files changed, 7 insertions(+), 5 deletions(-)\n>\n> diff --git a/environment.c b/environment.c\n> index fc3ed8bb1c..0a9067729e 100644\n> --- a/environment.c\n> +++ b/environment.c\n> @@ -42,7 +42,6 @@ static int pack_compression_seen;\n>  static int zlib_compression_seen;\n>\n>  int trust_executable_bit = 1;\n> -int trust_ctime = 1;\n>  int check_stat = 1;\n>  int has_symlinks = 1;\n>  int minimum_abbrev = 4, default_abbrev = -1;\n> @@ -309,7 +308,7 @@ int git_default_core_config(const char *var, const char *value,\n>  \t\treturn 0;\n>  \t}\n>  \tif (!strcmp(var, \"core.trustctime\")) {\n> -\t\ttrust_ctime = git_config_bool(var, value);\n> +\t\tcfg->trust_ctime = git_config_bool(var, value);\n>  \t\treturn 0;\n>  \t}\n>  \tif (!strcmp(var, \"core.checkstat\")) {\n> @@ -721,4 +720,5 @@ void repo_config_values_init(struct repo_config_values *cfg)\n>  \tcfg->attributes_file = NULL;\n>  \tcfg->apply_sparse_checkout = 0;\n>  \tcfg->branch_track = BRANCH_TRACK_REMOTE;\n> +\tcfg->trust_ctime = 1;\n>  }\n> diff --git a/environment.h b/environment.h\n> index 123a71cdc8..64d537686e 100644\n> --- a/environment.h\n> +++ b/environment.h\n> @@ -91,6 +91,7 @@ struct repo_config_values {\n>  \t/* section \"core\" config values */\n>  \tchar *attributes_file;\n>  \tint apply_sparse_checkout;\n> +\tint trust_ctime;\n>\n\nSince we parse it as a bool, perhaps we can make the variable to be of\ntype bool?\n\n[snip]\n"},{"id":"541534","messageId":"CAOLa=ZR3=pDXZt=vM9cSMSCc1NfWdwjde-Y05EvYfNYnr1KJMA@mail.gmail.com","threadId":"65344","inReplyTo":"20260324123750.157143-3-belkid98@gmail.com","subject":"Re: [PATCH v2 2/8] environment: move \"check_stat\" into `struct repo_config_values`","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2026-04-14T08:55:10Z","receivedAt":"2026-04-14T08:55:13Z","isPatch":true,"body":"Olamide Caleb Bello <belkid98@gmail.com> writes:\n\n> The `core.checkstat` configuration is currently stored in the global\n> variable `check_stat`, which makes it shared across repository\n> instances within a single process.\n>\n> Store it instead in `repo_config_values` so the value is associated\n> with the repository from which it was read. This preserves existing\n> behavior while avoiding cross-repository state leakage and continues\n> the effort to reduce reliance on global configuration state.\n>\n> Update all references to use repo_config_values().\n>\n\nSame comments as the first commit. Rest looks good.\n"},{"id":"541535","messageId":"CAOLa=ZRexa+uYj=F2++=vijBb760MgjdTwq3REPpxcwk02caHg@mail.gmail.com","threadId":"65344","inReplyTo":"20260324123750.157143-4-belkid98@gmail.com","subject":"Re: [PATCH v2 3/8] environment: move `zlib_compression_level` into repo_config_values","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2026-04-14T08:58:02Z","receivedAt":"2026-04-14T08:58:04Z","isPatch":true,"body":"Olamide Caleb Bello <belkid98@gmail.com> writes:\n\n> The `zlib_compression_level` configuration is currently stored in the\n> global variable `zlib_compression_level`, which makes it shared across\n> repository instances within a single process.\n>\n> Store it instead in `repo_config_values` so the value is associated\n> with the repository from which it was read. This preserves existing\n> behavior while avoiding cross-repository state leakage and continues\n> the effort to reduce reliance on global configuration state.\n>\n> Update all references to use repo_config_values().\n>\n> Mentored-by: Christian Couder <christian.couder@gmail.com>\n> Mentored-by: Usman Akinyemi <usmanakinyemi202@gmail.com>\n> Signed-off-by: Olamide Caleb Bello <belkid98@gmail.com>\n> ---\n>  builtin/index-pack.c | 3 ++-\n>  diff.c               | 3 ++-\n>  environment.c        | 6 +++---\n>  environment.h        | 2 +-\n>  http-push.c          | 3 ++-\n>  object-file.c        | 3 ++-\n>  6 files changed, 12 insertions(+), 8 deletions(-)\n>\n> diff --git a/builtin/index-pack.c b/builtin/index-pack.c\n> index b67fb0256c..dd82eed76f 100644\n> --- a/builtin/index-pack.c\n> +++ b/builtin/index-pack.c\n> @@ -1416,8 +1416,9 @@ static int write_compressed(struct hashfile *f, void *in, unsigned int size)\n>  \tgit_zstream stream;\n>  \tint status;\n>  \tunsigned char outbuf[4096];\n> +\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n>\n> -\tgit_deflate_init(&stream, zlib_compression_level);\n> +\tgit_deflate_init(&stream, cfg->zlib_compression_level);\n>  \tstream.next_in = in;\n>  \tstream.avail_in = size;\n>\n> diff --git a/diff.c b/diff.c\n> index 501648a5c4..4bc0297873 100644\n> --- a/diff.c\n> +++ b/diff.c\n> @@ -3365,8 +3365,9 @@ static unsigned char *deflate_it(char *data,\n>  \tint bound;\n>  \tunsigned char *deflated;\n>  \tgit_zstream stream;\n> +\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n>\n> -\tgit_deflate_init(&stream, zlib_compression_level);\n> +\tgit_deflate_init(&stream, cfg->zlib_compression_level);\n>  \tbound = git_deflate_bound(&stream, size);\n>  \tdeflated = xmalloc(bound);\n>  \tstream.next_out = deflated;\n> diff --git a/environment.c b/environment.c\n> index 8542ac3141..5b0e88b65c 100644\n> --- a/environment.c\n> +++ b/environment.c\n> @@ -52,7 +52,6 @@ char *git_commit_encoding;\n>  char *git_log_output_encoding;\n>  char *apply_default_whitespace;\n>  char *apply_default_ignorewhitespace;\n> -int zlib_compression_level = Z_BEST_SPEED;\n>  int pack_compression_level = Z_DEFAULT_COMPRESSION;\n>  int fsync_object_files = -1;\n>  int use_fsync = -1;\n> @@ -377,7 +376,7 @@ int git_default_core_config(const char *var, const char *value,\n>  \t\t\tlevel = Z_DEFAULT_COMPRESSION;\n>  \t\telse if (level < 0 || level > Z_BEST_COMPRESSION)\n>  \t\t\tdie(_(\"bad zlib compression level %d\"), level);\n> -\t\tzlib_compression_level = level;\n> +\t\tcfg->zlib_compression_level = level;\n>  \t\tzlib_compression_seen = 1;\n>  \t\treturn 0;\n>  \t}\n> @@ -389,7 +388,7 @@ int git_default_core_config(const char *var, const char *value,\n>  \t\telse if (level < 0 || level > Z_BEST_COMPRESSION)\n>  \t\t\tdie(_(\"bad zlib compression level %d\"), level);\n>  \t\tif (!zlib_compression_seen)\n> -\t\t\tzlib_compression_level = level;\n> +\t\t\tcfg->zlib_compression_level = level;\n>  \t\tif (!pack_compression_seen)\n>  \t\t\tpack_compression_level = level;\n>  \t\treturn 0;\n> @@ -721,4 +720,5 @@ void repo_config_values_init(struct repo_config_values *cfg)\n>  \tcfg->branch_track = BRANCH_TRACK_REMOTE;\n>  \tcfg->trust_ctime = 1;\n>  \tcfg->check_stat = 1;\n> +\tcfg->zlib_compression_level = Z_BEST_SPEED;\n>  }\n> diff --git a/environment.h b/environment.h\n> index 1d3e2e4f23..93201620af 100644\n> --- a/environment.h\n> +++ b/environment.h\n> @@ -93,6 +93,7 @@ struct repo_config_values {\n>  \tint apply_sparse_checkout;\n>  \tint trust_ctime;\n>  \tint check_stat;\n> +\tint zlib_compression_level;\n\nNit: applies to existing values too:\n1. Perhaps it would be nicer if these were sorted alphabetically, I\nassume we'll add a lot more fields here.\n2. Have a comment stating the purpose of the variable?\n\nThe patch looks good to me otherwise.\n"},{"id":"541536","messageId":"CAOLa=ZRE8O7UANkzr4p9__ReV1OX3KBBpqbKpfCJ+EvyziwtTA@mail.gmail.com","threadId":"65344","inReplyTo":"20260324123750.157143-6-belkid98@gmail.com","subject":"Re: [PATCH v2 5/8] environment: move \"precomposed_unicode\" into `struct repo_config_values`","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2026-04-14T09:07:01Z","receivedAt":"2026-04-14T09:07:03Z","isPatch":true,"body":"Olamide Caleb Bello <belkid98@gmail.com> writes:\n\n> The `core.precomposeunicode` configuration is currently stored in the\n> global variable `precomposed_unicode`, which makes it shared across\n> repository instances within a single process.\n>\n> Store it instead in `repo_config_values` so the value is associated\n> with the repository from which it was read. This preserves existing\n> behavior while avoiding cross-repository state leakage and is another\n> step toward eliminating repository-dependent global state.\n>\n> Update all references to use repo_config_values().\n>\n> Mentored-by: Christian Couder <christian.couder@gmail.com>\n> Mentored-by: Usman Akinyemi <usmanakinyemi202@gmail.com>\n> Signed-off-by: Olamide Caleb Bello <belkid98@gmail.com>\n> ---\n>  compat/precompose_utf8.c | 20 +++++++++++++-------\n>  environment.c            |  4 ++--\n>  environment.h            |  2 +-\n>  upload-pack.c            |  3 ++-\n>  4 files changed, 18 insertions(+), 11 deletions(-)\n>\n> diff --git a/compat/precompose_utf8.c b/compat/precompose_utf8.c\n> index 43b3be0114..0e94dbd862 100644\n> --- a/compat/precompose_utf8.c\n> +++ b/compat/precompose_utf8.c\n> @@ -48,16 +48,18 @@ void probe_utf8_pathname_composition(void)\n>  \tstatic const char *auml_nfc = \"\\xc3\\xa4\";\n>  \tstatic const char *auml_nfd = \"\\x61\\xcc\\x88\";\n>  \tint output_fd;\n> -\tif (precomposed_unicode != -1)\n> +\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n> +\n> +\tif (cfg->precomposed_unicode != -1)\n>  \t\treturn; /* We found it defined in the global config, respect it */\n>  \trepo_git_path_replace(the_repository, &path, \"%s\", auml_nfc);\n>  \toutput_fd = open(path.buf, O_CREAT|O_EXCL|O_RDWR, 0600);\n>  \tif (output_fd >= 0) {\n>  \t\tclose(output_fd);\n>  \t\trepo_git_path_replace(the_repository, &path, \"%s\", auml_nfd);\n> -\t\tprecomposed_unicode = access(path.buf, R_OK) ? 0 : 1;\n> +\t\tcfg->precomposed_unicode = access(path.buf, R_OK) ? 0 : 1;\n>  \t\trepo_config_set(the_repository, \"core.precomposeunicode\",\n> -\t\t\t\tprecomposed_unicode ? \"true\" : \"false\");\n> +\t\t\t\tcfg->precomposed_unicode ? \"true\" : \"false\");\n>  \t\trepo_git_path_replace(the_repository, &path, \"%s\", auml_nfc);\n>  \t\tif (unlink(path.buf))\n>  \t\t\tdie_errno(_(\"failed to unlink '%s'\"), path.buf);\n> @@ -69,14 +71,16 @@ const char *precompose_string_if_needed(const char *in)\n>  {\n>  \tsize_t inlen;\n>  \tsize_t outlen;\n> +\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n> +\n>  \tif (!in)\n>  \t\treturn NULL;\n>  \tif (has_non_ascii(in, (size_t)-1, &inlen)) {\n>  \t\ticonv_t ic_prec;\n>  \t\tchar *out;\n> -\t\tif (precomposed_unicode < 0)\n> -\t\t\trepo_config_get_bool(the_repository, \"core.precomposeunicode\", &precomposed_unicode);\n> -\t\tif (precomposed_unicode != 1)\n> +\t\tif (cfg->precomposed_unicode < 0)\n> +\t\t\trepo_config_get_bool(the_repository, \"core.precomposeunicode\", &cfg->precomposed_unicode);\n\nSo if the variable is unset, we parse the config again. My question is\nwhy doesn't this flow already have the config parsed, or in other words,\nis there a way we reach here without the repository being setup. Would\nbe nice to add this in the commit message.\n\n> +\t\tif (cfg->precomposed_unicode != 1)\n>  \t\t\treturn in;\n>  \t\tic_prec = iconv_open(repo_encoding, path_encoding);\n>  \t\tif (ic_prec == (iconv_t) -1)\n> @@ -130,7 +134,9 @@ PREC_DIR *precompose_utf8_opendir(const char *dirname)\n>\n>  struct dirent_prec_psx *precompose_utf8_readdir(PREC_DIR *prec_dir)\n>  {\n> +\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n>  \tstruct dirent *res;\n> +\n>  \tres = readdir(prec_dir->dirp);\n>  \tif (res) {\n>  \t\tsize_t namelenz = strlen(res->d_name) + 1; /* \\0 */\n> @@ -149,7 +155,7 @@ struct dirent_prec_psx *precompose_utf8_readdir(PREC_DIR *prec_dir)\n>  \t\tprec_dir->dirent_nfc->d_ino  = res->d_ino;\n>  \t\tprec_dir->dirent_nfc->d_type = res->d_type;\n>\n> -\t\tif ((precomposed_unicode == 1) && has_non_ascii(res->d_name, (size_t)-1, NULL)) {\n> +\t\tif ((cfg->precomposed_unicode == 1) && has_non_ascii(res->d_name, (size_t)-1, NULL)) {\n>  \t\t\tif (prec_dir->ic_precompose == (iconv_t)-1) {\n>  \t\t\t\tdie(\"iconv_open(%s,%s) failed, but needed:\\n\"\n>  \t\t\t\t\t\t\"    precomposed unicode is not supported.\\n\"\n> diff --git a/environment.c b/environment.c\n> index d0d3a4b7d2..739b647ebe 100644\n> --- a/environment.c\n> +++ b/environment.c\n> @@ -72,7 +72,6 @@ enum object_creation_mode object_creation_mode = OBJECT_CREATION_MODE;\n>  int grafts_keep_true_parents;\n>  int core_sparse_checkout_cone;\n>  int sparse_expect_files_outside_of_patterns;\n> -int precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */\n>  unsigned long pack_size_limit_cfg;\n>\n>  #ifndef PROTECT_HFS_DEFAULT\n> @@ -532,7 +531,7 @@ int git_default_core_config(const char *var, const char *value,\n>  \t}\n>\n>  \tif (!strcmp(var, \"core.precomposeunicode\")) {\n> -\t\tprecomposed_unicode = git_config_bool(var, value);\n> +\t\tcfg->precomposed_unicode = git_config_bool(var, value);\n\nWe parse a bool value, but....\n\n>  \t\treturn 0;\n>  \t}\n>\n> @@ -723,4 +722,5 @@ void repo_config_values_init(struct repo_config_values *cfg)\n>  \tcfg->check_stat = 1;\n>  \tcfg->zlib_compression_level = Z_BEST_SPEED;\n>  \tcfg->pack_compression_level = Z_DEFAULT_COMPRESSION;\n> +\tcfg->precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */\n>  }\n\nBut set -1 to showcase that this is not set. We should add that comment\nhere.\n\n> diff --git a/environment.h b/environment.h\n> index 514576b67a..508cb1afbc 100644\n> --- a/environment.h\n> +++ b/environment.h\n> @@ -95,6 +95,7 @@ struct repo_config_values {\n>  \tint check_stat;\n>  \tint zlib_compression_level;\n>  \tint pack_compression_level;\n> +\tint precomposed_unicode;\n>\n>  \t/* section \"branch\" config values */\n>  \tenum branch_track branch_track;\n> @@ -174,7 +175,6 @@ extern char *apply_default_whitespace;\n>  extern char *apply_default_ignorewhitespace;\n>  extern unsigned long pack_size_limit_cfg;\n>\n> -extern int precomposed_unicode;\n>  extern int protect_hfs;\n>  extern int protect_ntfs;\n"},{"id":"541537","messageId":"CAOLa=ZQDXn7181VfHpcWtNOSjTh9nzM3YnDTG_X1Vqh_v64bwg@mail.gmail.com","threadId":"65344","inReplyTo":"20260324123750.157143-1-belkid98@gmail.com","subject":"Re: [PATCH v2 0/8] repo_config_values: migrate more globals","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2026-04-14T09:10:14Z","receivedAt":"2026-04-14T09:10:16Z","isPatch":true,"body":"Olamide Caleb Bello <belkid98@gmail.com> writes:\n\n> Overview\n> ========\n> This series continues the effort to migrate repository-specific global\n> variables into struct repo_config_values, further reducing global\n> state and improving repository isolation.\n>\n> The previous series introduced the infrastructure for storing\n> repository-dependent configuration in repo_config_values. This series\n> extends that work by moving additional environment-related globals into\n> that struct and updating their call sites accordingly.\n>\n> This helps avoid cross-repository interference when multiple\n> repositories are used within the same process, and continues preparing\n> Git for improved library usage and better encapsulation of repository\n> state.\n>\n> Changes since v1:\n> - Dropped \"Base series\" section as the dependency has been merged.\n> - Fixed handling of pack_compression_level: removed use of a local copy and\n>   updated code to operate directly on cfg->pack_compression_level to avoid\n>   inconsistencies with option parsing.\n>\n\nI had a look at the series, the changes look good. I do think this is a\nnice opportunity to set some of the variables to be of type bool as\nneeded. Apart from that, I'd like to see some more comments about each\nof the variables and improved commit messages talking about why this\nchange is done this way.\n\nThanks,\nKarthik\n"},{"id":"541538","messageId":"53f43b85-b274-4352-938b-d40f942bfb2d@gmail.com","threadId":"65344","inReplyTo":"CAOLa=ZTD+qqgyB4Pn4bcOfP+Ks8Zch+AWZkzhrRRbk-eJvS-mg@mail.gmail.com","subject":"Re: [PATCH v2 1/8] environment: move \"trust_ctime\" into `struct repo_config_values`","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2026-04-14T09:35:50Z","receivedAt":"2026-04-14T09:35:55Z","isPatch":true,"body":"On 14/04/2026 09:52, Karthik Nayak wrote:\n> Olamide Caleb Bello <belkid98@gmail.com> writes:\n> \n>> The `core.trustctime` configuration is currently stored in the global\n>> variable `trust_ctime`, which makes it shared across repository\n>> instances in a single process.\n>>\n>> Store it instead in `repo_config_values`, so the value is tied to the\n>> repository from which it was read. This preserves existing behavior\n>> while avoiding cross-repository state leakage and continues the effort\n>> to reduce reliance on global configuration state.\n>>\n>> Update all references to use repo_config_values().\n>>\n> \n> Nit: I was hoping you'd also shed light on why this can go into\n> `repo_config_values()`. Does it need to be eagerly parsed? If so, why?\n\nIf trust_ctime was lazily parsed where it is used we'd end up dying in \nmatch_stat_data() which would be quite unexpected, make it very hard to \nreason about the code, and hamper the libification efforts. I'd much \nrather we put the onus on patch authors to justify any conversion from \neager parsing to lazy parsing rather than forcing them to justify \ncontinuing to parse settings eagerly.\n\nThanks\n\nPhillip\n\n>> Mentored-by: Christian Couder <christian.couder@gmail.com>\n>> Mentored-by: Usman Akinyemi <usmanakinyemi202@gmail.com>\n>> Signed-off-by: Olamide Caleb Bello <belkid98@gmail.com>\n>> ---\n>>   environment.c | 4 ++--\n>>   environment.h | 2 +-\n>>   statinfo.c    | 6 ++++--\n>>   3 files changed, 7 insertions(+), 5 deletions(-)\n>>\n>> diff --git a/environment.c b/environment.c\n>> index fc3ed8bb1c..0a9067729e 100644\n>> --- a/environment.c\n>> +++ b/environment.c\n>> @@ -42,7 +42,6 @@ static int pack_compression_seen;\n>>   static int zlib_compression_seen;\n>>\n>>   int trust_executable_bit = 1;\n>> -int trust_ctime = 1;\n>>   int check_stat = 1;\n>>   int has_symlinks = 1;\n>>   int minimum_abbrev = 4, default_abbrev = -1;\n>> @@ -309,7 +308,7 @@ int git_default_core_config(const char *var, const char *value,\n>>   \t\treturn 0;\n>>   \t}\n>>   \tif (!strcmp(var, \"core.trustctime\")) {\n>> -\t\ttrust_ctime = git_config_bool(var, value);\n>> +\t\tcfg->trust_ctime = git_config_bool(var, value);\n>>   \t\treturn 0;\n>>   \t}\n>>   \tif (!strcmp(var, \"core.checkstat\")) {\n>> @@ -721,4 +720,5 @@ void repo_config_values_init(struct repo_config_values *cfg)\n>>   \tcfg->attributes_file = NULL;\n>>   \tcfg->apply_sparse_checkout = 0;\n>>   \tcfg->branch_track = BRANCH_TRACK_REMOTE;\n>> +\tcfg->trust_ctime = 1;\n>>   }\n>> diff --git a/environment.h b/environment.h\n>> index 123a71cdc8..64d537686e 100644\n>> --- a/environment.h\n>> +++ b/environment.h\n>> @@ -91,6 +91,7 @@ struct repo_config_values {\n>>   \t/* section \"core\" config values */\n>>   \tchar *attributes_file;\n>>   \tint apply_sparse_checkout;\n>> +\tint trust_ctime;\n>>\n> \n> Since we parse it as a bool, perhaps we can make the variable to be of\n> type bool?\n> \n> [snip]\n\n"},{"id":"541563","messageId":"CAD=f0L8UM=6vZR24_7Lz9g+yMDDPbcizzcs+DcqQW05PsTOzDw@mail.gmail.com","threadId":"65344","inReplyTo":"CAOLa=ZQDXn7181VfHpcWtNOSjTh9nzM3YnDTG_X1Vqh_v64bwg@mail.gmail.com","subject":"Re: [PATCH v2 0/8] repo_config_values: migrate more globals","fromName":"Bello Olamide","fromEmail":"belkid98@gmail.com","sentAt":"2026-04-14T14:26:12Z","receivedAt":"2026-04-14T14:26:26Z","isPatch":true,"body":"On Tue, 14 Apr 2026 at 10:10, Karthik Nayak <karthik.188@gmail.com> wrote:\n>\n> Olamide Caleb Bello <belkid98@gmail.com> writes:\n>\n> > Overview\n> > ========\n> > This series continues the effort to migrate repository-specific global\n> > variables into struct repo_config_values, further reducing global\n> > state and improving repository isolation.\n> >\n> > The previous series introduced the infrastructure for storing\n> > repository-dependent configuration in repo_config_values. This series\n> > extends that work by moving additional environment-related globals into\n> > that struct and updating their call sites accordingly.\n> >\n> > This helps avoid cross-repository interference when multiple\n> > repositories are used within the same process, and continues preparing\n> > Git for improved library usage and better encapsulation of repository\n> > state.\n> >\n> > Changes since v1:\n> > - Dropped \"Base series\" section as the dependency has been merged.\n> > - Fixed handling of pack_compression_level: removed use of a local copy and\n> >   updated code to operate directly on cfg->pack_compression_level to avoid\n> >   inconsistencies with option parsing.\n> >\n>\n> I had a look at the series, the changes look good. I do think this is a\n> nice opportunity to set some of the variables to be of type bool as\n> needed. Apart from that, I'd like to see some more comments about each\n> of the variables and improved commit messages talking about why this\n> change is done this way.\n>\n> Thanks,\n> Karthik\n\nHi Karthik,\n\nThanks for taking a look.\n\nI’ll review the series and update variables to use bools where appropriate.\n\nI’ll also improve the commit messages to explain better why each variable is\nmoved into `repo_config_values`, and add comments describing their purpose\nand why they are safe to scope per-repository.\n\nI’ll send a v3 with these updates.\n\nThanks,\nOlamide\n"},{"id":"541564","messageId":"CAD=f0L-ckZUpcvjB02V=ebDgSQ2XeNG8pwHfUqOgeoJF67tLGA@mail.gmail.com","threadId":"65344","inReplyTo":"CAOLa=ZRexa+uYj=F2++=vijBb760MgjdTwq3REPpxcwk02caHg@mail.gmail.com","subject":"Re: [PATCH v2 3/8] environment: move `zlib_compression_level` into repo_config_values","fromName":"Bello Olamide","fromEmail":"belkid98@gmail.com","sentAt":"2026-04-14T14:32:43Z","receivedAt":"2026-04-14T14:32:55Z","isPatch":true,"body":"On Tue, 14 Apr 2026 at 09:58, Karthik Nayak <karthik.188@gmail.com> wrote:\n>\n> Olamide Caleb Bello <belkid98@gmail.com> writes:\n>\n> > The `zlib_compression_level` configuration is currently stored in the\n> > global variable `zlib_compression_level`, which makes it shared across\n> > repository instances within a single process.\n> >\n> > Store it instead in `repo_config_values` so the value is associated\n> > with the repository from which it was read. This preserves existing\n> > behavior while avoiding cross-repository state leakage and continues\n> > the effort to reduce reliance on global configuration state.\n> >\n> > Update all references to use repo_config_values().\n> >\n> > Mentored-by: Christian Couder <christian.couder@gmail.com>\n> > Mentored-by: Usman Akinyemi <usmanakinyemi202@gmail.com>\n> > Signed-off-by: Olamide Caleb Bello <belkid98@gmail.com>\n> > ---\n> >  builtin/index-pack.c | 3 ++-\n> >  diff.c               | 3 ++-\n> >  environment.c        | 6 +++---\n> >  environment.h        | 2 +-\n> >  http-push.c          | 3 ++-\n> >  object-file.c        | 3 ++-\n> >  6 files changed, 12 insertions(+), 8 deletions(-)\n> >\n> > diff --git a/builtin/index-pack.c b/builtin/index-pack.c\n> > index b67fb0256c..dd82eed76f 100644\n> > --- a/builtin/index-pack.c\n> > +++ b/builtin/index-pack.c\n> > @@ -1416,8 +1416,9 @@ static int write_compressed(struct hashfile *f, void *in, unsigned int size)\n> >       git_zstream stream;\n> >       int status;\n> >       unsigned char outbuf[4096];\n> > +     struct repo_config_values *cfg = repo_config_values(the_repository);\n> >\n> > -     git_deflate_init(&stream, zlib_compression_level);\n> > +     git_deflate_init(&stream, cfg->zlib_compression_level);\n> >       stream.next_in = in;\n> >       stream.avail_in = size;\n> >\n> > diff --git a/diff.c b/diff.c\n> > index 501648a5c4..4bc0297873 100644\n> > --- a/diff.c\n> > +++ b/diff.c\n> > @@ -3365,8 +3365,9 @@ static unsigned char *deflate_it(char *data,\n> >       int bound;\n> >       unsigned char *deflated;\n> >       git_zstream stream;\n> > +     struct repo_config_values *cfg = repo_config_values(the_repository);\n> >\n> > -     git_deflate_init(&stream, zlib_compression_level);\n> > +     git_deflate_init(&stream, cfg->zlib_compression_level);\n> >       bound = git_deflate_bound(&stream, size);\n> >       deflated = xmalloc(bound);\n> >       stream.next_out = deflated;\n> > diff --git a/environment.c b/environment.c\n> > index 8542ac3141..5b0e88b65c 100644\n> > --- a/environment.c\n> > +++ b/environment.c\n> > @@ -52,7 +52,6 @@ char *git_commit_encoding;\n> >  char *git_log_output_encoding;\n> >  char *apply_default_whitespace;\n> >  char *apply_default_ignorewhitespace;\n> > -int zlib_compression_level = Z_BEST_SPEED;\n> >  int pack_compression_level = Z_DEFAULT_COMPRESSION;\n> >  int fsync_object_files = -1;\n> >  int use_fsync = -1;\n> > @@ -377,7 +376,7 @@ int git_default_core_config(const char *var, const char *value,\n> >                       level = Z_DEFAULT_COMPRESSION;\n> >               else if (level < 0 || level > Z_BEST_COMPRESSION)\n> >                       die(_(\"bad zlib compression level %d\"), level);\n> > -             zlib_compression_level = level;\n> > +             cfg->zlib_compression_level = level;\n> >               zlib_compression_seen = 1;\n> >               return 0;\n> >       }\n> > @@ -389,7 +388,7 @@ int git_default_core_config(const char *var, const char *value,\n> >               else if (level < 0 || level > Z_BEST_COMPRESSION)\n> >                       die(_(\"bad zlib compression level %d\"), level);\n> >               if (!zlib_compression_seen)\n> > -                     zlib_compression_level = level;\n> > +                     cfg->zlib_compression_level = level;\n> >               if (!pack_compression_seen)\n> >                       pack_compression_level = level;\n> >               return 0;\n> > @@ -721,4 +720,5 @@ void repo_config_values_init(struct repo_config_values *cfg)\n> >       cfg->branch_track = BRANCH_TRACK_REMOTE;\n> >       cfg->trust_ctime = 1;\n> >       cfg->check_stat = 1;\n> > +     cfg->zlib_compression_level = Z_BEST_SPEED;\n> >  }\n> > diff --git a/environment.h b/environment.h\n> > index 1d3e2e4f23..93201620af 100644\n> > --- a/environment.h\n> > +++ b/environment.h\n> > @@ -93,6 +93,7 @@ struct repo_config_values {\n> >       int apply_sparse_checkout;\n> >       int trust_ctime;\n> >       int check_stat;\n> > +     int zlib_compression_level;\n>\n> Nit: applies to existing values too:\n> 1. Perhaps it would be nicer if these were sorted alphabetically, I\n> assume we'll add a lot more fields here.\nI’ll reorder the fields in `repo_config_values` alphabetically\nto keep things consistent as more entries are added.\n> 2. Have a comment stating the purpose of the variable?\nI’ll also add comments describing the purpose of each variable\n>\n> The patch looks good to me otherwise.\n\nThanks, Karthik, for the review.\n\nOlamide Bello\n"},{"id":"541572","messageId":"xmqqa4v5bgzn.fsf@gitster.g","threadId":"65344","inReplyTo":"53f43b85-b274-4352-938b-d40f942bfb2d@gmail.com","subject":"Re: [PATCH v2 1/8] environment: move \"trust_ctime\" into `struct repo_config_values`","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-04-14T17:15:40Z","receivedAt":"2026-04-14T17:15:42Z","isPatch":true,"body":"Phillip Wood <phillip.wood123@gmail.com> writes:\n\n> On 14/04/2026 09:52, Karthik Nayak wrote:\n> ...\n>> Nit: I was hoping you'd also shed light on why this can go into\n>> `repo_config_values()`. Does it need to be eagerly parsed? If so, why?\n>\n> If trust_ctime was lazily parsed where it is used we'd end up dying in \n> match_stat_data() which would be quite unexpected, make it very hard to \n> reason about the code, and hamper the libification efforts. I'd much \n> rather we put the onus on patch authors to justify any conversion from \n> eager parsing to lazy parsing rather than forcing them to justify \n> continuing to parse settings eagerly.\n>\n> Thanks\n>\n> Phillip\n\nI too often get confused while looking at these \"global static\nvariables holding parsed configuration values are bad, let's move it\nelsewhere\" patches between the on-demand and upfront parsing.\n\nI agree that what has traditionally been parsed upfront are mostly\nfundamental things (e.g., in core.* namespace) that is better parsed\nupfront, and what has been parsed on-demand are often very operation\nspecific thing whose misspelt values do not matter when we are not\nrunning that specific operation, so it is better parsed on-demand.\nThere may be exceptions and some variables that the current code\nparses upfront might be better parsed on-demand and vice versa, but\nthe default for these rewrite effort ought to be to keep the\nexisting semantics unless there is a good justification for changing\nit.\n\nThanks for injecting a dose of sanity so clearly.\n\n\n"},{"id":"541627","messageId":"CAOLa=ZT8H3xLXjact9it9jveviztL4Q72KNMk5nxW_ouq0T0=A@mail.gmail.com","threadId":"65344","inReplyTo":"53f43b85-b274-4352-938b-d40f942bfb2d@gmail.com","subject":"Re: [PATCH v2 1/8] environment: move \"trust_ctime\" into `struct repo_config_values`","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2026-04-15T11:16:23Z","receivedAt":"2026-04-15T11:16:25Z","isPatch":true,"body":"Phillip Wood <phillip.wood123@gmail.com> writes:\n\n> On 14/04/2026 09:52, Karthik Nayak wrote:\n>> Olamide Caleb Bello <belkid98@gmail.com> writes:\n>>\n>>> The `core.trustctime` configuration is currently stored in the global\n>>> variable `trust_ctime`, which makes it shared across repository\n>>> instances in a single process.\n>>>\n>>> Store it instead in `repo_config_values`, so the value is tied to the\n>>> repository from which it was read. This preserves existing behavior\n>>> while avoiding cross-repository state leakage and continues the effort\n>>> to reduce reliance on global configuration state.\n>>>\n>>> Update all references to use repo_config_values().\n>>>\n>>\n>> Nit: I was hoping you'd also shed light on why this can go into\n>> `repo_config_values()`. Does it need to be eagerly parsed? If so, why?\n>\n> If trust_ctime was lazily parsed where it is used we'd end up dying in\n> match_stat_data() which would be quite unexpected, make it very hard to\n> reason about the code, and hamper the libification efforts. I'd much\n> rather we put the onus on patch authors to justify any conversion from\n> eager parsing to lazy parsing rather than forcing them to justify\n> continuing to parse settings eagerly.\n>\n\nAgreed. A note in the commit message that this belongs in\n`repo_config_values()` because it's eagerly parsed would be enough.\n\n> Thanks\n>\n> Phillip\n>\n\n[snip]\n"},{"id":"541672","messageId":"xmqq5x5s8brc.fsf@gitster.g","threadId":"65344","inReplyTo":"CAOLa=ZT8H3xLXjact9it9jveviztL4Q72KNMk5nxW_ouq0T0=A@mail.gmail.com","subject":"Re: [PATCH v2 1/8] environment: move \"trust_ctime\" into `struct repo_config_values`","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-04-15T15:49:11Z","receivedAt":"2026-04-15T15:49:16Z","isPatch":true,"body":"Karthik Nayak <karthik.188@gmail.com> writes:\n\n>>>> Store it instead in `repo_config_values`, so the value is tied to the\n>>>> repository from which it was read. This preserves existing behavior\n>>>> while avoiding cross-repository state leakage and continues the effort\n>>>> to reduce reliance on global configuration state.\n>>>>\n>>>> Update all references to use repo_config_values().\n>>>>\n>>>\n>>> Nit: I was hoping you'd also shed light on why this can go into\n>>> `repo_config_values()`. Does it need to be eagerly parsed? If so, why?\n>>\n>> If trust_ctime was lazily parsed where it is used we'd end up dying in\n>> match_stat_data() which would be quite unexpected, make it very hard to\n>> reason about the code, and hamper the libification efforts. I'd much\n>> rather we put the onus on patch authors to justify any conversion from\n>> eager parsing to lazy parsing rather than forcing them to justify\n>> continuing to parse settings eagerly.\n>>\n>\n> Agreed. A note in the commit message that this belongs in\n> `repo_config_values()` because it's eagerly parsed would be enough.\n\nI see \"preserves existing behavior\" above.   Wouldn't it be enough?\n"},{"id":"541692","messageId":"CAOLa=ZS+br-gP=HqnMeib0yuFQr9=wVNFZC-vz1dT5ZVB6kJqQ@mail.gmail.com","threadId":"65344","inReplyTo":"xmqq5x5s8brc.fsf@gitster.g","subject":"Re: [PATCH v2 1/8] environment: move \"trust_ctime\" into `struct repo_config_values`","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2026-04-15T19:09:59Z","receivedAt":"2026-04-15T19:10:02Z","isPatch":true,"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Karthik Nayak <karthik.188@gmail.com> writes:\n>\n>>>>> Store it instead in `repo_config_values`, so the value is tied to the\n>>>>> repository from which it was read. This preserves existing behavior\n>>>>> while avoiding cross-repository state leakage and continues the effort\n>>>>> to reduce reliance on global configuration state.\n>>>>>\n>>>>> Update all references to use repo_config_values().\n>>>>>\n>>>>\n>>>> Nit: I was hoping you'd also shed light on why this can go into\n>>>> `repo_config_values()`. Does it need to be eagerly parsed? If so, why?\n>>>\n>>> If trust_ctime was lazily parsed where it is used we'd end up dying in\n>>> match_stat_data() which would be quite unexpected, make it very hard to\n>>> reason about the code, and hamper the libification efforts. I'd much\n>>> rather we put the onus on patch authors to justify any conversion from\n>>> eager parsing to lazy parsing rather than forcing them to justify\n>>> continuing to parse settings eagerly.\n>>>\n>>\n>> Agreed. A note in the commit message that this belongs in\n>> `repo_config_values()` because it's eagerly parsed would be enough.\n>\n> I see \"preserves existing behavior\" above.   Wouldn't it be enough?\n\nThough \"preserves existing behavior\" implicitly covers this, it would be\ncleaner to explicitly mention that eager parsing is the reason it\nbelongs in `repo_config_values()`. That said, I'm happy with it as is\ntoo.\n"},{"id":"542205","messageId":"20260423160832.114816-1-belkid98@gmail.com","threadId":"65344","inReplyTo":"CAOLa=ZQDXn7181VfHpcWtNOSjTh9nzM3YnDTG_X1Vqh_v64bwg@mail.gmail.com","subject":"[PATCH v3 0/8] repo_config_values: migrate more globals","fromName":"Olamide Caleb Bello","fromEmail":"belkid98@gmail.com","sentAt":"2026-04-23T16:08:24Z","receivedAt":"2026-04-23T16:09:25Z","isPatch":true,"body":"This series continues the effort to remove repository-dependent global\nconfiguration state by moving several core.* configuration variables\ninto struct `repo_config_values`.\n\nThis ensures configuration values are tied to the repository from which\nthey were read, avoiding cross-repository state leakage in processes\nhandling multiple repositories, while preserving existing behavior.\n\nAll affected configuration values are eagerly parsed. Storing them in\nrepo_config_values preserves current semantics and avoids introducing\nlazy parsing into runtime code paths.\n\nThis v3 addresses review feedback by explicitly clarifying the reason\nthese values belong in repo_config_values (eager parsing) and improving\ncommit message clarity.\n\nOlamide Caleb Bello (8):\n  environment: move \"trust_ctime\" into struct repo_config_values\n  environment: move \"check_stat\" into struct repo_config_values\n  environment: move \"zlib_compression_level\" into repo_config_values\n  environment: move \"pack_compression_level\" into struct repo_config_values\n  environment: move \"precomposed_unicode\" into struct repo_config_values\n  env: move \"core_sparse_checkout_cone\" into repo_config_values\n  env: put \"sparse_expect_files_outside_of_patterns\" in repo_config_values\n  env: move \"warn_on_object_refname_ambiguity\" into repo_config_values\n-- \n2.53.0.155.g9f36b15afa\n\n"},{"id":"542206","messageId":"20260423160832.114816-2-belkid98@gmail.com","threadId":"65344","inReplyTo":"20260423160832.114816-1-belkid98@gmail.com","subject":"[PATCH v3 1/8] Revert \"compat/posix: introduce writev(3p) wrapper\"","fromName":"Olamide Caleb Bello","fromEmail":"belkid98@gmail.com","sentAt":"2026-04-23T16:08:25Z","receivedAt":"2026-04-23T16:09:28Z","isPatch":true,"body":"From: Junio C Hamano <gitster@pobox.com>\n\nThis reverts commit 3b9b2c2a29a1d529ca9884fa0a6529f6e2496abe; let's\nnot use writev() for now.\n---\n Makefile         |  4 ----\n compat/posix.h   | 14 --------------\n compat/writev.c  | 44 --------------------------------------------\n config.mak.uname |  2 --\n meson.build      |  1 -\n 5 files changed, 65 deletions(-)\n delete mode 100644 compat/writev.c\n\ndiff --git a/Makefile b/Makefile\nindex 5d22394c2e..cedc234173 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -2029,10 +2029,6 @@ ifdef NO_PREAD\n \tCOMPAT_CFLAGS += -DNO_PREAD\n \tCOMPAT_OBJS += compat/pread.o\n endif\n-ifdef NO_WRITEV\n-\tCOMPAT_CFLAGS += -DNO_WRITEV\n-\tCOMPAT_OBJS += compat/writev.o\n-endif\n ifdef NO_FAST_WORKING_DIRECTORY\n \tBASIC_CFLAGS += -DNO_FAST_WORKING_DIRECTORY\n endif\ndiff --git a/compat/posix.h b/compat/posix.h\nindex 94699a03fa..faaae1b655 100644\n--- a/compat/posix.h\n+++ b/compat/posix.h\n@@ -137,9 +137,6 @@\n #include <sys/socket.h>\n #include <sys/ioctl.h>\n #include <sys/statvfs.h>\n-#ifndef NO_WRITEV\n-#include <sys/uio.h>\n-#endif\n #include <termios.h>\n #ifndef NO_SYS_SELECT_H\n #include <sys/select.h>\n@@ -326,17 +323,6 @@ int git_lstat(const char *, struct stat *);\n ssize_t git_pread(int fd, void *buf, size_t count, off_t offset);\n #endif\n \n-#ifdef NO_WRITEV\n-#define writev git_writev\n-#define iovec git_iovec\n-struct git_iovec {\n-\tvoid *iov_base;\n-\tsize_t iov_len;\n-};\n-\n-ssize_t git_writev(int fd, const struct iovec *iov, int iovcnt);\n-#endif\n-\n #ifdef NO_SETENV\n #define setenv gitsetenv\n int gitsetenv(const char *, const char *, int);\ndiff --git a/compat/writev.c b/compat/writev.c\ndeleted file mode 100644\nindex 3a94870a2f..0000000000\n--- a/compat/writev.c\n+++ /dev/null\n@@ -1,44 +0,0 @@\n-#include \"../git-compat-util.h\"\n-#include \"../wrapper.h\"\n-\n-ssize_t git_writev(int fd, const struct iovec *iov, int iovcnt)\n-{\n-\tsize_t total_written = 0;\n-\tsize_t sum = 0;\n-\n-\t/*\n-\t * According to writev(3p), the syscall shall error with EINVAL in case\n-\t * the sum of `iov_len` overflows `ssize_t`.\n-\t */\n-\t for (int i = 0; i < iovcnt; i++) {\n-\t\tif (iov[i].iov_len > maximum_signed_value_of_type(ssize_t) ||\n-\t\t    iov[i].iov_len + sum > maximum_signed_value_of_type(ssize_t)) {\n-\t\t\terrno = EINVAL;\n-\t\t\treturn -1;\n-\t\t}\n-\n-\t\tsum += iov[i].iov_len;\n-\t}\n-\n-\tfor (int i = 0; i < iovcnt; i++) {\n-\t\tconst char *bytes = iov[i].iov_base;\n-\t\tsize_t iovec_written = 0;\n-\n-\t\twhile (iovec_written < iov[i].iov_len) {\n-\t\t\tssize_t bytes_written = xwrite(fd, bytes + iovec_written,\n-\t\t\t\t\t\t       iov[i].iov_len - iovec_written);\n-\t\t\tif (bytes_written < 0) {\n-\t\t\t\tif (total_written)\n-\t\t\t\t\tgoto out;\n-\t\t\t\treturn bytes_written;\n-\t\t\t}\n-\t\t\tif (!bytes_written)\n-\t\t\t\tgoto out;\n-\t\t\tiovec_written += bytes_written;\n-\t\t\ttotal_written += bytes_written;\n-\t\t}\n-\t}\n-\n-out:\n-\treturn (ssize_t) total_written;\n-}\ndiff --git a/config.mak.uname b/config.mak.uname\nindex ccb3f71881..5feb582558 100644\n--- a/config.mak.uname\n+++ b/config.mak.uname\n@@ -459,7 +459,6 @@ ifeq ($(uname_S),Windows)\n \tSANE_TOOL_PATH ?= $(msvc_bin_dir_msys)\n \tHAVE_ALLOCA_H = YesPlease\n \tNO_PREAD = YesPlease\n-\tNO_WRITEV = YesPlease\n \tNEEDS_CRYPTO_WITH_SSL = YesPlease\n \tNO_LIBGEN_H = YesPlease\n \tNO_POLL = YesPlease\n@@ -675,7 +674,6 @@ ifeq ($(uname_S),MINGW)\n \tpathsep = ;\n \tHAVE_ALLOCA_H = YesPlease\n \tNO_PREAD = YesPlease\n-\tNO_WRITEV = YesPlease\n \tNEEDS_CRYPTO_WITH_SSL = YesPlease\n \tNO_LIBGEN_H = YesPlease\n \tNO_POLL = YesPlease\ndiff --git a/meson.build b/meson.build\nindex 8309942d18..11488623bf 100644\n--- a/meson.build\n+++ b/meson.build\n@@ -1429,7 +1429,6 @@ checkfuncs = {\n   'initgroups' : [],\n   'strtoumax' : ['strtoumax.c', 'strtoimax.c'],\n   'pread' : ['pread.c'],\n-  'writev' : ['writev.c'],\n }\n \n if host_machine.system() == 'windows'\n-- \n2.53.0.155.g9f36b15afa\n\n"},{"id":"542207","messageId":"20260423160832.114816-3-belkid98@gmail.com","threadId":"65344","inReplyTo":"20260423160832.114816-1-belkid98@gmail.com","subject":"[PATCH v3 2/8] rust: we are way beyond 2.53","fromName":"Olamide Caleb Bello","fromEmail":"belkid98@gmail.com","sentAt":"2026-04-23T16:08:26Z","receivedAt":"2026-04-23T16:09:31Z","isPatch":true,"body":"From: Junio C Hamano <gitster@pobox.com>\n\nEarlier we timelined that we'd tune our build procedures to build\nwith Rust by default in Git 2.53, but we are already in prerelease\nfreeze for 2.54 now.  Update the BreakingChanges document to delay\nit until Git 2.55 (slated for the end of June 2026).\n\nNoticed-by: brian m. carlson <sandals@crustytoothpaste.net>\nHelped-by: Derrick Stolee <stolee@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n Documentation/BreakingChanges.adoc | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/Documentation/BreakingChanges.adoc b/Documentation/BreakingChanges.adoc\nindex f814450d2f..af59c43f42 100644\n--- a/Documentation/BreakingChanges.adoc\n+++ b/Documentation/BreakingChanges.adoc\n@@ -190,7 +190,7 @@ milestones for the introduction of Rust:\n 1. Initially, with Git 2.52, support for Rust will be auto-detected by Meson and\n    disabled in our Makefile so that the project can sort out the initial\n    infrastructure.\n-2. In Git 2.53, both build systems will default-enable support for Rust.\n+2. In Git 2.55, both build systems will default-enable support for Rust.\n    Consequently, builds will break by default if Rust is not available on the\n    build host. The use of Rust can still be explicitly disabled via build\n    flags.\n-- \n2.53.0.155.g9f36b15afa\n\n"},{"id":"542208","messageId":"20260423160832.114816-4-belkid98@gmail.com","threadId":"65344","inReplyTo":"20260423160832.114816-1-belkid98@gmail.com","subject":"[PATCH v3 3/8] doc: am: revert Message-ID trailer claim","fromName":"Olamide Caleb Bello","fromEmail":"belkid98@gmail.com","sentAt":"2026-04-23T16:08:27Z","receivedAt":"2026-04-23T16:09:36Z","isPatch":true,"body":"From: Kristoffer Haugsbakk <code@khaugsbakk.name>\n\nI claimed in 3c18135b (doc: am: say that --message-id adds a trailer,\n2026-02-09) that `git am --message-id` adds a Git trailer. But that\nisn’t the case; for the case of a commit message with a subject, body,\nand no trailer block:\n\n    <subject>\n\n    <paragrah>\n\nIt just appends the line right after `paragraph`:\n\n    <subject>\n\n    <paragraph>\n    Message-ID: <message-id_trailer.323@msgid.xyz>\n\nIt does work for two other cases though, namely subject-only and with an\nexisting trailer block.\n\nThis is at best an inconsistency and arguably a bug, but we’re at the\ntrailing end of the release cycle now. So reverting the doc is safer\nthan making msg-id act as a trailer, for now.\n\nRevert this hunk from commit 3c18135b except the only useful\nchange (“Also use inline-verbatim for `Message-ID`”).\n\nSigned-off-by: Kristoffer Haugsbakk <code@khaugsbakk.name>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n Documentation/git-am.adoc | 9 ++++-----\n 1 file changed, 4 insertions(+), 5 deletions(-)\n\ndiff --git a/Documentation/git-am.adoc b/Documentation/git-am.adoc\nindex 403181baa9..14f83a8920 100644\n--- a/Documentation/git-am.adoc\n+++ b/Documentation/git-am.adoc\n@@ -84,11 +84,10 @@ OPTIONS\n \n -m::\n --message-id::\n-\tPass the `-m` flag to linkgit:git-mailinfo[1], so that the\n-\t`Message-ID` header is added as a trailer (see\n-\tlinkgit:git-interpret-trailers[1]).  The `am.messageid`\n-\tconfiguration variable can be used to specify the default\n-\tbehaviour.\n+\tPass the `-m` flag to linkgit:git-mailinfo[1],\n+\tso that the `Message-ID` header is added to the commit message.\n+\tThe `am.messageid` configuration variable can be used to specify\n+\tthe default behaviour.\n \n --no-message-id::\n \tDo not add the Message-ID header to the commit message.\n-- \n2.53.0.155.g9f36b15afa\n\n"},{"id":"542209","messageId":"20260423160832.114816-5-belkid98@gmail.com","threadId":"65344","inReplyTo":"20260423160832.114816-1-belkid98@gmail.com","subject":"[PATCH v3 4/8] doc: am: correct to full --no-message-id","fromName":"Olamide Caleb Bello","fromEmail":"belkid98@gmail.com","sentAt":"2026-04-23T16:08:28Z","receivedAt":"2026-04-23T16:09:39Z","isPatch":true,"body":"From: Kristoffer Haugsbakk <code@khaugsbakk.name>\n\nSigned-off-by: Kristoffer Haugsbakk <code@khaugsbakk.name>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n Documentation/git-am.adoc | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/Documentation/git-am.adoc b/Documentation/git-am.adoc\nindex 14f83a8920..ab71ab7490 100644\n--- a/Documentation/git-am.adoc\n+++ b/Documentation/git-am.adoc\n@@ -91,7 +91,7 @@ OPTIONS\n \n --no-message-id::\n \tDo not add the Message-ID header to the commit message.\n-\t`no-message-id` is useful to override `am.messageid`.\n+\t`--no-message-id` is useful to override `am.messageid`.\n \n -q::\n --quiet::\n-- \n2.53.0.155.g9f36b15afa\n\n"},{"id":"542210","messageId":"20260423160832.114816-6-belkid98@gmail.com","threadId":"65344","inReplyTo":"20260423160832.114816-1-belkid98@gmail.com","subject":"[PATCH v3 5/8] CI: bump actions/checkout from 4 to 5 for rust-analysis job","fromName":"Olamide Caleb Bello","fromEmail":"belkid98@gmail.com","sentAt":"2026-04-23T16:08:29Z","receivedAt":"2026-04-23T16:09:42Z","isPatch":true,"body":"From: Junio C Hamano <gitster@pobox.com>\n\nGitHub Actions started complaining about use of Node.js 20 and I was\nwondering why only one job uses actions/checkout@v4, while everybody\nelse already uses actions/checkout@v5.\n\nIt turns out that it is caused by a semantic mismerge between\ne75cd059 (ci: check formatting of our Rust code, 2025-10-15) that\nadded a new use of actions/checkout@v4 that happened very close to\nanother change 63541ed9 (build(deps): bump actions/checkout from 4\nto 5, 2025-10-16) that updated all uses of actions/checkout@v4 to\nuse vactions/checkout@v5.\n\nUpdate the leftover and the last use of actions/checkout@v4 to use\nactions/checkout@v5 to help ourselves to move away from Node.js 20.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n .github/workflows/main.yml | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/.github/workflows/main.yml b/.github/workflows/main.yml\nindex f2e93f5461..8ed268fc09 100644\n--- a/.github/workflows/main.yml\n+++ b/.github/workflows/main.yml\n@@ -480,7 +480,7 @@ jobs:\n       group: rust-analysis-${{ github.ref }}\n       cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }}\n     steps:\n-    - uses: actions/checkout@v4\n+    - uses: actions/checkout@v5\n     - run: ci/install-dependencies.sh\n     - run: ci/run-rust-checks.sh\n   sparse:\n-- \n2.53.0.155.g9f36b15afa\n\n"},{"id":"542211","messageId":"20260423160832.114816-7-belkid98@gmail.com","threadId":"65344","inReplyTo":"20260423160832.114816-1-belkid98@gmail.com","subject":"[PATCH v3 6/8] gitglossary: fix indentation of sub-lists","fromName":"Olamide Caleb Bello","fromEmail":"belkid98@gmail.com","sentAt":"2026-04-23T16:08:30Z","receivedAt":"2026-04-23T16:09:45Z","isPatch":true,"body":"From: Jeff King <peff@peff.net>\n\nThe glossary entry is a list of terms and their definitions, so\nmulti-paragraph definitions need \"+\" continuation lines to indicate\nthat they are part of a single entry.\n\nWhen an entry contains a sub-list (say, a bulleted list), the final \"+\"\nmay become ambiguous: is it connecting the next paragraph to the final\nentry of the sub-list, or to the original list of definition paragraphs?\n\nAsciidoc generally connects it to the former, even when we mean the\nlatter, and you end up with the next paragraph indented incorrectly,\nlike this:\n\n  glob\n    ...defines glob...\n\n    Two consecutive asterisks (\"**\") in patterns matched\n    against full pathname may have special meaning:\n\n    - ...some special meaning of **...\n\n    - ...another special meaning of **...\n\n    - Other consecutive asterisks are considered invalid.\n\n      Glob magic is incompatible with literal magic.\n\nThat final \"Glob magic is incompatible\" paragraph is in the wrong spot.\nIt should be at the same level as \"Two consecutive asterisks\", as it is\nnot part of the final \"Other consecutive asterisks\" bullet point.\n\nThe same problem appears in several other spots in the glossary.\n\nUsually we'd fix this by using \"--\" markers, which put the sub-list into\nits own block. But there's a catch: in some of these spots we are\nalready in an open block, and nesting open blocks is a problem. It seems\nto work for me using Asciidoc 10.2.1, but Asciidoctor 2.0.26 makes a\nmess of it (our intent to open a new block seems to close the old one).\n\nFortunately there's a work-around: when using a \"+\" list-continuation,\nthe number of empty lines above the continuation indicates which level\nof parent list to continue. So by adding an empty line after our\nunordered list (before the \"+\"), we should be able to continue the\ndefinition list item.\n\nBut asciidoc being asciidoc, of course that is not the end of the story.\nThat technique works fine for the \"glob\" and \"attr\" lists in this patch,\nbut under the \"refs\" item it works for only 1 of the 2 lists! I can't\nfigure out why, and this may be an asciidoctor bug. But we can work\naround it by using \"--\" open-block markers here, since we're not\nalready in an open block.\n\nSo using the extra blank line for the first two instances, and \"--\"\nmarkers for the second two, this patch produces identical output from\n\"doc-diff HEAD^ HEAD\" for both --asciidoctor and --asciidoc modes.\n\nSigned-off-by: Jeff King <peff@peff.net>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n Documentation/glossary-content.adoc | 6 ++++++\n 1 file changed, 6 insertions(+)\n\ndiff --git a/Documentation/glossary-content.adoc b/Documentation/glossary-content.adoc\nindex 20ba121314..8c4e9dd3be 100644\n--- a/Documentation/glossary-content.adoc\n+++ b/Documentation/glossary-content.adoc\n@@ -430,6 +430,7 @@ full pathname may have special meaning:\n    matches \"`a/b`\", \"`a/x/b`\", \"`a/x/y/b`\" and so on.\n \n  - Other consecutive asterisks are considered invalid.\n+\n +\n Glob magic is incompatible with literal magic.\n \n@@ -452,6 +453,7 @@ these forms:\n \n - \"`!ATTR`\" requires that the attribute `ATTR` be\n   unspecified.\n+\n +\n Note that when matching against a tree object, attributes are still\n obtained from working tree, not from the given tree object.\n@@ -560,14 +562,17 @@ The ref namespace is hierarchical.\n Ref names must either start with `refs/` or be located in the root of\n the hierarchy. For the latter, their name must follow these rules:\n +\n+--\n  - The name consists of only upper-case characters or underscores.\n \n  - The name ends with \"`_HEAD`\" or is equal to \"`HEAD`\".\n+--\n +\n There are some irregular refs in the root of the hierarchy that do not\n match these rules. The following list is exhaustive and shall not be\n extended in the future:\n +\n+--\n  - `AUTO_MERGE`\n \n  - `BISECT_EXPECTED_REV`\n@@ -577,6 +582,7 @@ extended in the future:\n  - `NOTES_MERGE_REF`\n \n  - `MERGE_AUTOSTASH`\n+--\n +\n Different subhierarchies are used for different purposes. For example,\n the `refs/heads/` hierarchy is used to represent local branches whereas\n-- \n2.53.0.155.g9f36b15afa\n\n"},{"id":"542212","messageId":"20260423160832.114816-8-belkid98@gmail.com","threadId":"65344","inReplyTo":"20260423160832.114816-1-belkid98@gmail.com","subject":"[PATCH v3 7/8] Hopefully the final tweak before -rc2","fromName":"Olamide Caleb Bello","fromEmail":"belkid98@gmail.com","sentAt":"2026-04-23T16:08:31Z","receivedAt":"2026-04-23T16:09:48Z","isPatch":true,"body":"From: Junio C Hamano <gitster@pobox.com>\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n Documentation/RelNotes/2.54.0.adoc | 6 ++++++\n 1 file changed, 6 insertions(+)\n\ndiff --git a/Documentation/RelNotes/2.54.0.adoc b/Documentation/RelNotes/2.54.0.adoc\nindex 3fa25e06f2..2ad73ff473 100644\n--- a/Documentation/RelNotes/2.54.0.adoc\n+++ b/Documentation/RelNotes/2.54.0.adoc\n@@ -526,6 +526,12 @@ Fixes since v2.53\n    conflicts.\n    (merge c0ce43376b ng/add-files-to-cache-wo-rename later to maint).\n \n+ * Doc mark-up update for entries in the glossary with bulleted lists.\n+   (merge a65cbd87ea jk/doc-markup-sub-list-indentation later to maint).\n+\n+ * CI dependency updates.\n+   (merge 4bdb17e3a8 jc/ci-github-actions-use-checkout-v5 later to maint).\n+\n  * Other code cleanup, docfix, build fix, etc.\n    (merge d79fff4a11 jk/remote-tracking-ref-leakfix later to maint).\n    (merge 7a747f972d dd/t5403-modernise later to maint).\n-- \n2.53.0.155.g9f36b15afa\n\n"},{"id":"542213","messageId":"20260423160832.114816-9-belkid98@gmail.com","threadId":"65344","inReplyTo":"20260423160832.114816-1-belkid98@gmail.com","subject":"[PATCH v3 8/8] Git 2.54-rc2","fromName":"Olamide Caleb Bello","fromEmail":"belkid98@gmail.com","sentAt":"2026-04-23T16:08:32Z","receivedAt":"2026-04-23T16:09:52Z","isPatch":true,"body":"From: Junio C Hamano <gitster@pobox.com>\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n GIT-VERSION-GEN | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN\nindex 9c55beb496..fb11bace12 100755\n--- a/GIT-VERSION-GEN\n+++ b/GIT-VERSION-GEN\n@@ -1,6 +1,6 @@\n #!/bin/sh\n \n-DEF_VER=v2.54.0-rc1\n+DEF_VER=v2.54.0-rc2\n \n LF='\n '\n-- \n2.53.0.155.g9f36b15afa\n\n"},{"id":"542214","messageId":"CAD=f0L8ZSCP-n6F055TmDNFfpB7gYrBEaKvvwMFkEMf2hQTe7g@mail.gmail.com","threadId":"65344","inReplyTo":"20260423160832.114816-1-belkid98@gmail.com","subject":"Re: [PATCH v3 0/8] repo_config_values: migrate more globals","fromName":"Bello Olamide","fromEmail":"belkid98@gmail.com","sentAt":"2026-04-23T16:37:54Z","receivedAt":"2026-04-23T16:38:07Z","isPatch":true,"body":"Hi all,\n\nApologies, this v3 series was generated with an incorrect commit range,\nand includes unrelated upstream commits. Please ignore this series.\n\nI will resend a corrected version shortly based only on the intended\nenvironment.* refactoring changes.\n\nThanks,\nOlamide Bello\n"},{"id":"542215","messageId":"20260423165432.143598-1-belkid98@gmail.com","threadId":"65344","inReplyTo":"CAOLa=ZQDXn7181VfHpcWtNOSjTh9nzM3YnDTG_X1Vqh_v64bwg@mail.gmail.com","subject":"[PATCH v3 0/8] environment: move core config globals into repo_config_values","fromName":"Olamide Caleb Bello","fromEmail":"belkid98@gmail.com","sentAt":"2026-04-23T16:54:24Z","receivedAt":"2026-04-23T16:55:36Z","isPatch":true,"body":"This series continues the effort to remove repository-dependent global\nconfiguration state by moving several core.* configuration variables\ninto struct repo_config_values.\n\nThis ensures configuration values are tied to the repository from which\nthey were read, avoiding cross-repository state leakage in processes\nhandling multiple repositories, while preserving existing behavior.\n\nAll affected configuration values are eagerly parsed. Storing them in\nrepo_config_values preserves current semantics and avoids introducing\nlazy parsing into runtime code paths.\n\nThis v3 addresses review feedback by explicitly clarifying the reason\nthese values belong in repo_config_values (eager parsing) and improving\ncommit message clarity.\n\nOlamide Caleb Bello (8):\n  environment: move \"trust_ctime\" into `struct repo_config_values`\n  environment: move \"check_stat\" into `struct repo_config_values`\n  environment: move `zlib_compression_level` into `struct\n    repo_config_values`\n  environment: move \"pack_compression_level\" into `struct\n    repo_config_values`\n  environment: move \"precomposed_unicode\" into `struct\n    repo_config_values`\n  env: move \"core_sparse_checkout_cone\" into `struct repo_config_values`\n  env: move \"sparse_expect_files_outside_of_patterns\" into\n    `repo_config_values`\n  env: move \"warn_on_object_refname_ambiguity\" into `struct\n    repo_config_values`\n\n builtin/cat-file.c        |  7 ++++---\n builtin/fast-import.c     |  8 +++++---\n builtin/index-pack.c      |  3 ++-\n builtin/mv.c              |  2 +-\n builtin/pack-objects.c    | 24 +++++++++++++----------\n builtin/sparse-checkout.c | 37 +++++++++++++++++++++---------------\n compat/precompose_utf8.c  | 20 +++++++++++++-------\n diff.c                    |  3 ++-\n dir.c                     |  3 ++-\n entry.c                   |  3 ++-\n environment.c             | 40 +++++++++++++++++++++------------------\n environment.h             | 19 ++++++++++---------\n http-push.c               |  3 ++-\n object-file.c             |  6 ++++--\n object-name.c             |  3 ++-\n revision.c                |  7 ++++---\n sparse-index.c            |  4 ++--\n statinfo.c                | 12 +++++++-----\n submodule.c               |  7 ++++---\n upload-pack.c             |  3 ++-\n 20 files changed, 126 insertions(+), 88 deletions(-)\n\n-- \n2.53.0.155.g9f36b15afa\n\n"},{"id":"542216","messageId":"20260423165432.143598-2-belkid98@gmail.com","threadId":"65344","inReplyTo":"20260423165432.143598-1-belkid98@gmail.com","subject":"[PATCH v3 1/8] environment: move \"trust_ctime\" into `struct repo_config_values`","fromName":"Olamide Caleb Bello","fromEmail":"belkid98@gmail.com","sentAt":"2026-04-23T16:54:25Z","receivedAt":"2026-04-23T16:55:39Z","isPatch":true,"body":"The `core.trustctime` configuration is currently stored in the global\nvariable `trust_ctime`, which makes it shared across repository\ninstances in a single process.\n\nStore it instead in `repo_config_values`, where eagerly‑parsed\nrepository configuration lives. `core.trustctime` is parsed eagerly\nbecause it is used in low‑level stat‑matching functions\n(`match_stat_data()`), where a lazy parse could cause unexpected\nfatal errors and complicate libification efforts. This preserves\nthat behavior while tying the value to the repository from which it\nwas read, avoiding cross‑repository state leakage and continuing the\neffort to reduce reliance on global configuration state.\n\nUpdate all references to use repo_config_values().\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Usman Akinyemi <usmanakinyemi202@gmail.com>\nSigned-off-by: Olamide Caleb Bello <belkid98@gmail.com>\n---\n environment.c | 4 ++--\n environment.h | 2 +-\n statinfo.c    | 6 ++++--\n 3 files changed, 7 insertions(+), 5 deletions(-)\n\ndiff --git a/environment.c b/environment.c\nindex fc3ed8bb1c..0a9067729e 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -42,7 +42,6 @@ static int pack_compression_seen;\n static int zlib_compression_seen;\n \n int trust_executable_bit = 1;\n-int trust_ctime = 1;\n int check_stat = 1;\n int has_symlinks = 1;\n int minimum_abbrev = 4, default_abbrev = -1;\n@@ -309,7 +308,7 @@ int git_default_core_config(const char *var, const char *value,\n \t\treturn 0;\n \t}\n \tif (!strcmp(var, \"core.trustctime\")) {\n-\t\ttrust_ctime = git_config_bool(var, value);\n+\t\tcfg->trust_ctime = git_config_bool(var, value);\n \t\treturn 0;\n \t}\n \tif (!strcmp(var, \"core.checkstat\")) {\n@@ -721,4 +720,5 @@ void repo_config_values_init(struct repo_config_values *cfg)\n \tcfg->attributes_file = NULL;\n \tcfg->apply_sparse_checkout = 0;\n \tcfg->branch_track = BRANCH_TRACK_REMOTE;\n+\tcfg->trust_ctime = 1;\n }\ndiff --git a/environment.h b/environment.h\nindex 123a71cdc8..64d537686e 100644\n--- a/environment.h\n+++ b/environment.h\n@@ -91,6 +91,7 @@ struct repo_config_values {\n \t/* section \"core\" config values */\n \tchar *attributes_file;\n \tint apply_sparse_checkout;\n+\tint trust_ctime;\n \n \t/* section \"branch\" config values */\n \tenum branch_track branch_track;\n@@ -161,7 +162,6 @@ extern char *git_work_tree_cfg;\n \n /* Environment bits from configuration mechanism */\n extern int trust_executable_bit;\n-extern int trust_ctime;\n extern int check_stat;\n extern int has_symlinks;\n extern int minimum_abbrev, default_abbrev;\ndiff --git a/statinfo.c b/statinfo.c\nindex 30a164b0e6..4fc12053f4 100644\n--- a/statinfo.c\n+++ b/statinfo.c\n@@ -3,6 +3,7 @@\n #include \"git-compat-util.h\"\n #include \"environment.h\"\n #include \"statinfo.h\"\n+#include \"repository.h\"\n \n /*\n  * Munge st_size into an unsigned int.\n@@ -63,17 +64,18 @@ void fake_lstat_data(const struct stat_data *sd, struct stat *st)\n int match_stat_data(const struct stat_data *sd, struct stat *st)\n {\n \tint changed = 0;\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n \tif (sd->sd_mtime.sec != (unsigned int)st->st_mtime)\n \t\tchanged |= MTIME_CHANGED;\n-\tif (trust_ctime && check_stat &&\n+\tif (cfg->trust_ctime && check_stat &&\n \t    sd->sd_ctime.sec != (unsigned int)st->st_ctime)\n \t\tchanged |= CTIME_CHANGED;\n \n #ifdef USE_NSEC\n \tif (check_stat && sd->sd_mtime.nsec != ST_MTIME_NSEC(*st))\n \t\tchanged |= MTIME_CHANGED;\n-\tif (trust_ctime && check_stat &&\n+\tif (cfg->trust_ctime && check_stat &&\n \t    sd->sd_ctime.nsec != ST_CTIME_NSEC(*st))\n \t\tchanged |= CTIME_CHANGED;\n #endif\n-- \n2.53.0.155.g9f36b15afa\n\n"},{"id":"542217","messageId":"20260423165432.143598-3-belkid98@gmail.com","threadId":"65344","inReplyTo":"20260423165432.143598-1-belkid98@gmail.com","subject":"[PATCH v3 2/8] environment: move \"check_stat\" into `struct repo_config_values`","fromName":"Olamide Caleb Bello","fromEmail":"belkid98@gmail.com","sentAt":"2026-04-23T16:54:26Z","receivedAt":"2026-04-23T16:55:41Z","isPatch":true,"body":"The `core.checkstat` configuration is currently stored in the global\nvariable `check_stat`, which makes it shared across repository\ninstances within a single process.\n\nStore it instead in `repo_config_values`, where eagerly‑parsed\nrepository configuration lives. `core.checkstat` is parsed eagerly\nbecause it controls how `match_stat_data()` and related functions\ndecide file freshness; a lazy parse could lead to unexpected\nbehavior or complicate libification. This preserves the existing\neager‑parsing behavior while tying the value to the repository it\nwas read from, avoiding cross‑repository state leakage, and\ncontinuing the effort to reduce reliance on global configuration\nstate.\n\nUpdate all references to use `repo_config_values()`.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Usman Akinyemi <usmanakinyemi202@gmail.com>\nSigned-off-by: Olamide Caleb Bello <belkid98@gmail.com>\n---\n entry.c       |  3 ++-\n environment.c |  6 +++---\n environment.h |  2 +-\n statinfo.c    | 10 +++++-----\n 4 files changed, 11 insertions(+), 10 deletions(-)\n\ndiff --git a/entry.c b/entry.c\nindex 7817aee362..c55e867d8a 100644\n--- a/entry.c\n+++ b/entry.c\n@@ -443,7 +443,8 @@ static int check_path(const char *path, int len, struct stat *st, int skiplen)\n static void mark_colliding_entries(const struct checkout *state,\n \t\t\t\t   struct cache_entry *ce, struct stat *st)\n {\n-\tint trust_ino = check_stat;\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n+\tint trust_ino = cfg->check_stat;\n \n #if defined(GIT_WINDOWS_NATIVE) || defined(__CYGWIN__)\n \ttrust_ino = 0;\ndiff --git a/environment.c b/environment.c\nindex 0a9067729e..8542ac3141 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -42,7 +42,6 @@ static int pack_compression_seen;\n static int zlib_compression_seen;\n \n int trust_executable_bit = 1;\n-int check_stat = 1;\n int has_symlinks = 1;\n int minimum_abbrev = 4, default_abbrev = -1;\n int ignore_case;\n@@ -315,9 +314,9 @@ int git_default_core_config(const char *var, const char *value,\n \t\tif (!value)\n \t\t\treturn config_error_nonbool(var);\n \t\tif (!strcasecmp(value, \"default\"))\n-\t\t\tcheck_stat = 1;\n+\t\t\tcfg->check_stat = 1;\n \t\telse if (!strcasecmp(value, \"minimal\"))\n-\t\t\tcheck_stat = 0;\n+\t\t\tcfg->check_stat = 0;\n \t\telse\n \t\t\treturn error(_(\"invalid value for '%s': '%s'\"),\n \t\t\t\t     var, value);\n@@ -721,4 +720,5 @@ void repo_config_values_init(struct repo_config_values *cfg)\n \tcfg->apply_sparse_checkout = 0;\n \tcfg->branch_track = BRANCH_TRACK_REMOTE;\n \tcfg->trust_ctime = 1;\n+\tcfg->check_stat = 1;\n }\ndiff --git a/environment.h b/environment.h\nindex 64d537686e..1d3e2e4f23 100644\n--- a/environment.h\n+++ b/environment.h\n@@ -92,6 +92,7 @@ struct repo_config_values {\n \tchar *attributes_file;\n \tint apply_sparse_checkout;\n \tint trust_ctime;\n+\tint check_stat;\n \n \t/* section \"branch\" config values */\n \tenum branch_track branch_track;\n@@ -162,7 +163,6 @@ extern char *git_work_tree_cfg;\n \n /* Environment bits from configuration mechanism */\n extern int trust_executable_bit;\n-extern int check_stat;\n extern int has_symlinks;\n extern int minimum_abbrev, default_abbrev;\n extern int ignore_case;\ndiff --git a/statinfo.c b/statinfo.c\nindex 4fc12053f4..5e00af127d 100644\n--- a/statinfo.c\n+++ b/statinfo.c\n@@ -68,19 +68,19 @@ int match_stat_data(const struct stat_data *sd, struct stat *st)\n \n \tif (sd->sd_mtime.sec != (unsigned int)st->st_mtime)\n \t\tchanged |= MTIME_CHANGED;\n-\tif (cfg->trust_ctime && check_stat &&\n+\tif (cfg->trust_ctime && cfg->check_stat &&\n \t    sd->sd_ctime.sec != (unsigned int)st->st_ctime)\n \t\tchanged |= CTIME_CHANGED;\n \n #ifdef USE_NSEC\n-\tif (check_stat && sd->sd_mtime.nsec != ST_MTIME_NSEC(*st))\n+\tif (cfg->check_stat && sd->sd_mtime.nsec != ST_MTIME_NSEC(*st))\n \t\tchanged |= MTIME_CHANGED;\n-\tif (cfg->trust_ctime && check_stat &&\n+\tif (cfg->trust_ctime && cfg->check_stat &&\n \t    sd->sd_ctime.nsec != ST_CTIME_NSEC(*st))\n \t\tchanged |= CTIME_CHANGED;\n #endif\n \n-\tif (check_stat) {\n+\tif (cfg->check_stat) {\n \t\tif (sd->sd_uid != (unsigned int) st->st_uid ||\n \t\t\tsd->sd_gid != (unsigned int) st->st_gid)\n \t\t\tchanged |= OWNER_CHANGED;\n@@ -94,7 +94,7 @@ int match_stat_data(const struct stat_data *sd, struct stat *st)\n \t * clients will have different views of what \"device\"\n \t * the filesystem is on\n \t */\n-\tif (check_stat && sd->sd_dev != (unsigned int) st->st_dev)\n+\tif (cfg->check_stat && sd->sd_dev != (unsigned int) st->st_dev)\n \t\t\tchanged |= INODE_CHANGED;\n #endif\n \n-- \n2.53.0.155.g9f36b15afa\n\n"},{"id":"542218","messageId":"20260423165432.143598-4-belkid98@gmail.com","threadId":"65344","inReplyTo":"20260423165432.143598-1-belkid98@gmail.com","subject":"[PATCH v3 3/8] environment: move `zlib_compression_level` into `struct repo_config_values`","fromName":"Olamide Caleb Bello","fromEmail":"belkid98@gmail.com","sentAt":"2026-04-23T16:54:27Z","receivedAt":"2026-04-23T16:55:44Z","isPatch":true,"body":"The `zlib_compression_level` configuration is currently stored in the\nglobal variable `zlib_compression_level`, which makes it shared across\nrepository instances within a single process.\n\nStore it instead in `repo_config_values`, where eagerly‑parsed\nrepository configuration lives. `zlib_compression_level` is parsed\neagerly because it determines compression behaviour for objects and\npacks – core operations where a lazy parse could lead to unpredictable\nresults and hinder libification. This preserves the existing\neager‑parsing behavior while tying the value to the repository it\nwas read from, avoiding cross‑repository state leakage and continuing\nthe effort to reduce reliance on global configuration state.\n\nUpdate all references to use `repo_config_values()`.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Usman Akinyemi <usmanakinyemi202@gmail.com>\nSigned-off-by: Olamide Caleb Bello <belkid98@gmail.com>\n---\n builtin/index-pack.c | 3 ++-\n diff.c               | 3 ++-\n environment.c        | 6 +++---\n environment.h        | 2 +-\n http-push.c          | 3 ++-\n object-file.c        | 3 ++-\n 6 files changed, 12 insertions(+), 8 deletions(-)\n\ndiff --git a/builtin/index-pack.c b/builtin/index-pack.c\nindex ca7784dc2c..3942d3e0d0 100644\n--- a/builtin/index-pack.c\n+++ b/builtin/index-pack.c\n@@ -1416,8 +1416,9 @@ static int write_compressed(struct hashfile *f, void *in, unsigned int size)\n \tgit_zstream stream;\n \tint status;\n \tunsigned char outbuf[4096];\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n-\tgit_deflate_init(&stream, zlib_compression_level);\n+\tgit_deflate_init(&stream, cfg->zlib_compression_level);\n \tstream.next_in = in;\n \tstream.avail_in = size;\n \ndiff --git a/diff.c b/diff.c\nindex 397e38b41c..7d17b0bf3f 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -3589,8 +3589,9 @@ static unsigned char *deflate_it(char *data,\n \tint bound;\n \tunsigned char *deflated;\n \tgit_zstream stream;\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n-\tgit_deflate_init(&stream, zlib_compression_level);\n+\tgit_deflate_init(&stream, cfg->zlib_compression_level);\n \tbound = git_deflate_bound(&stream, size);\n \tdeflated = xmalloc(bound);\n \tstream.next_out = deflated;\ndiff --git a/environment.c b/environment.c\nindex 8542ac3141..5b0e88b65c 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -52,7 +52,6 @@ char *git_commit_encoding;\n char *git_log_output_encoding;\n char *apply_default_whitespace;\n char *apply_default_ignorewhitespace;\n-int zlib_compression_level = Z_BEST_SPEED;\n int pack_compression_level = Z_DEFAULT_COMPRESSION;\n int fsync_object_files = -1;\n int use_fsync = -1;\n@@ -377,7 +376,7 @@ int git_default_core_config(const char *var, const char *value,\n \t\t\tlevel = Z_DEFAULT_COMPRESSION;\n \t\telse if (level < 0 || level > Z_BEST_COMPRESSION)\n \t\t\tdie(_(\"bad zlib compression level %d\"), level);\n-\t\tzlib_compression_level = level;\n+\t\tcfg->zlib_compression_level = level;\n \t\tzlib_compression_seen = 1;\n \t\treturn 0;\n \t}\n@@ -389,7 +388,7 @@ int git_default_core_config(const char *var, const char *value,\n \t\telse if (level < 0 || level > Z_BEST_COMPRESSION)\n \t\t\tdie(_(\"bad zlib compression level %d\"), level);\n \t\tif (!zlib_compression_seen)\n-\t\t\tzlib_compression_level = level;\n+\t\t\tcfg->zlib_compression_level = level;\n \t\tif (!pack_compression_seen)\n \t\t\tpack_compression_level = level;\n \t\treturn 0;\n@@ -721,4 +720,5 @@ void repo_config_values_init(struct repo_config_values *cfg)\n \tcfg->branch_track = BRANCH_TRACK_REMOTE;\n \tcfg->trust_ctime = 1;\n \tcfg->check_stat = 1;\n+\tcfg->zlib_compression_level = Z_BEST_SPEED;\n }\ndiff --git a/environment.h b/environment.h\nindex 1d3e2e4f23..93201620af 100644\n--- a/environment.h\n+++ b/environment.h\n@@ -93,6 +93,7 @@ struct repo_config_values {\n \tint apply_sparse_checkout;\n \tint trust_ctime;\n \tint check_stat;\n+\tint zlib_compression_level;\n \n \t/* section \"branch\" config values */\n \tenum branch_track branch_track;\n@@ -170,7 +171,6 @@ extern int assume_unchanged;\n extern int warn_on_object_refname_ambiguity;\n extern char *apply_default_whitespace;\n extern char *apply_default_ignorewhitespace;\n-extern int zlib_compression_level;\n extern int pack_compression_level;\n extern unsigned long pack_size_limit_cfg;\n \ndiff --git a/http-push.c b/http-push.c\nindex d143fe2845..8ac107a56e 100644\n--- a/http-push.c\n+++ b/http-push.c\n@@ -369,13 +369,14 @@ static void start_put(struct transfer_request *request)\n \tint hdrlen;\n \tssize_t size;\n \tgit_zstream stream;\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n \tunpacked = odb_read_object(the_repository->objects, &request->obj->oid,\n \t\t\t\t   &type, &len);\n \thdrlen = format_object_header(hdr, sizeof(hdr), type, len);\n \n \t/* Set it up */\n-\tgit_deflate_init(&stream, zlib_compression_level);\n+\tgit_deflate_init(&stream, cfg->zlib_compression_level);\n \tsize = git_deflate_bound(&stream, len + hdrlen);\n \tstrbuf_grow(&request->buffer.buf, size);\n \trequest->buffer.posn = 0;\ndiff --git a/object-file.c b/object-file.c\nindex 2acc9522df..7c122ac419 100644\n--- a/object-file.c\n+++ b/object-file.c\n@@ -906,6 +906,7 @@ static int start_loose_object_common(struct odb_source *source,\n \tconst struct git_hash_algo *algo = source->odb->repo->hash_algo;\n \tconst struct git_hash_algo *compat = source->odb->repo->compat_hash_algo;\n \tint fd;\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n \tfd = create_tmpfile(source->odb->repo, tmp_file, filename);\n \tif (fd < 0) {\n@@ -921,7 +922,7 @@ static int start_loose_object_common(struct odb_source *source,\n \t}\n \n \t/*  Setup zlib stream for compression */\n-\tgit_deflate_init(stream, zlib_compression_level);\n+\tgit_deflate_init(stream, cfg->zlib_compression_level);\n \tstream->next_out = buf;\n \tstream->avail_out = buflen;\n \talgo->init_fn(c);\n-- \n2.53.0.155.g9f36b15afa\n\n"},{"id":"542219","messageId":"20260423165432.143598-5-belkid98@gmail.com","threadId":"65344","inReplyTo":"20260423165432.143598-1-belkid98@gmail.com","subject":"[PATCH v3 4/8] environment: move \"pack_compression_level\" into `struct repo_config_values`","fromName":"Olamide Caleb Bello","fromEmail":"belkid98@gmail.com","sentAt":"2026-04-23T16:54:28Z","receivedAt":"2026-04-23T16:55:47Z","isPatch":true,"body":"The `pack_compression_level` configuration is currently stored in the\nglobal variable `pack_compression_level`, which makes it shared across\nrepository instances within a single process.\n\nStore it instead in `repo_config_values`, where eagerly‑parsed\nrepository configuration lives. `pack_compression_level` is parsed\neagerly because it influences packfile compression, a core operation\nwhere a lazy parse could cause inconsistent behavior and hamper\nlibification. This preserves the existing eager‑parsing behavior while\ntying the value to the repository from which it was read, avoiding\ncross‑repository state leakage and continuing the effort to reduce\nreliance on global configuration state.\n\nThe type remains `int` as it represents a numeric compression level,\nnot a boolean toggle.\n\nUpdate all references to use `repo_config_values()`.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Usman Akinyemi <usmanakinyemi202@gmail.com>\nSigned-off-by: Olamide Caleb Bello <belkid98@gmail.com>\n---\n builtin/fast-import.c  |  8 +++++---\n builtin/pack-objects.c | 17 ++++++++++-------\n environment.c          |  8 +++++---\n environment.h          |  2 +-\n object-file.c          |  3 ++-\n 5 files changed, 23 insertions(+), 15 deletions(-)\n\ndiff --git a/builtin/fast-import.c b/builtin/fast-import.c\nindex 82bc6dcc00..070a5af3e4 100644\n--- a/builtin/fast-import.c\n+++ b/builtin/fast-import.c\n@@ -965,6 +965,7 @@ static int store_object(\n \tunsigned long hdrlen, deltalen;\n \tstruct git_hash_ctx c;\n \tgit_zstream s;\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n \thdrlen = format_object_header((char *)hdr, sizeof(hdr), type,\n \t\t\t\t      dat->len);\n@@ -1005,7 +1006,7 @@ static int store_object(\n \t} else\n \t\tdelta = NULL;\n \n-\tgit_deflate_init(&s, pack_compression_level);\n+\tgit_deflate_init(&s, cfg->pack_compression_level);\n \tif (delta) {\n \t\ts.next_in = delta;\n \t\ts.avail_in = deltalen;\n@@ -1032,7 +1033,7 @@ static int store_object(\n \t\tif (delta) {\n \t\t\tFREE_AND_NULL(delta);\n \n-\t\t\tgit_deflate_init(&s, pack_compression_level);\n+\t\t\tgit_deflate_init(&s, cfg->pack_compression_level);\n \t\t\ts.next_in = (void *)dat->buf;\n \t\t\ts.avail_in = dat->len;\n \t\t\ts.avail_out = git_deflate_bound(&s, s.avail_in);\n@@ -1115,6 +1116,7 @@ static void stream_blob(uintmax_t len, struct object_id *oidout, uintmax_t mark)\n \tstruct git_hash_ctx c;\n \tgit_zstream s;\n \tstruct hashfile_checkpoint checkpoint;\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \tint status = Z_OK;\n \n \t/* Determine if we should auto-checkpoint. */\n@@ -1134,7 +1136,7 @@ static void stream_blob(uintmax_t len, struct object_id *oidout, uintmax_t mark)\n \n \tcrc32_begin(pack_file);\n \n-\tgit_deflate_init(&s, pack_compression_level);\n+\tgit_deflate_init(&s, cfg->pack_compression_level);\n \n \thdrlen = encode_in_pack_object_header(out_buf, out_sz, OBJ_BLOB, len);\n \ndiff --git a/builtin/pack-objects.c b/builtin/pack-objects.c\nindex dd2480a73d..8ccbe7e178 100644\n--- a/builtin/pack-objects.c\n+++ b/builtin/pack-objects.c\n@@ -386,8 +386,9 @@ static unsigned long do_compress(void **pptr, unsigned long size)\n \tgit_zstream stream;\n \tvoid *in, *out;\n \tunsigned long maxsize;\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n-\tgit_deflate_init(&stream, pack_compression_level);\n+\tgit_deflate_init(&stream, cfg->pack_compression_level);\n \tmaxsize = git_deflate_bound(&stream, size);\n \n \tin = *pptr;\n@@ -413,8 +414,9 @@ static unsigned long write_large_blob_data(struct odb_read_stream *st, struct ha\n \tunsigned char ibuf[1024 * 16];\n \tunsigned char obuf[1024 * 16];\n \tunsigned long olen = 0;\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n-\tgit_deflate_init(&stream, pack_compression_level);\n+\tgit_deflate_init(&stream, cfg->pack_compression_level);\n \n \tfor (;;) {\n \t\tssize_t readlen;\n@@ -5003,6 +5005,7 @@ int cmd_pack_objects(int argc,\n \tstruct string_list keep_pack_list = STRING_LIST_INIT_NODUP;\n \tstruct list_objects_filter_options filter_options =\n \t\tLIST_OBJECTS_FILTER_INIT;\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n \tstruct option pack_objects_options[] = {\n \t\tOPT_CALLBACK_F('q', \"quiet\", &progress, NULL,\n@@ -5084,7 +5087,7 @@ int cmd_pack_objects(int argc,\n \t\t\t N_(\"ignore packs that have companion .keep file\")),\n \t\tOPT_STRING_LIST(0, \"keep-pack\", &keep_pack_list, N_(\"name\"),\n \t\t\t\tN_(\"ignore this pack\")),\n-\t\tOPT_INTEGER(0, \"compression\", &pack_compression_level,\n+\t\tOPT_INTEGER(0, \"compression\", &cfg->pack_compression_level,\n \t\t\t    N_(\"pack compression level\")),\n \t\tOPT_BOOL(0, \"keep-true-parents\", &grafts_keep_true_parents,\n \t\t\t N_(\"do not hide commits by grafts\")),\n@@ -5243,10 +5246,10 @@ int cmd_pack_objects(int argc,\n \n \tif (!reuse_object)\n \t\treuse_delta = 0;\n-\tif (pack_compression_level == -1)\n-\t\tpack_compression_level = Z_DEFAULT_COMPRESSION;\n-\telse if (pack_compression_level < 0 || pack_compression_level > Z_BEST_COMPRESSION)\n-\t\tdie(_(\"bad pack compression level %d\"), pack_compression_level);\n+\tif (cfg->pack_compression_level == -1)\n+\t\tcfg->pack_compression_level = Z_DEFAULT_COMPRESSION;\n+\telse if (cfg->pack_compression_level < 0 || cfg->pack_compression_level > Z_BEST_COMPRESSION)\n+\t\tdie(_(\"bad pack compression level %d\"), cfg->pack_compression_level);\n \n \tif (!delta_search_threads)\t/* --threads=0 means autodetect */\n \t\tdelta_search_threads = online_cpus();\ndiff --git a/environment.c b/environment.c\nindex 5b0e88b65c..d0d3a4b7d2 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -52,7 +52,6 @@ char *git_commit_encoding;\n char *git_log_output_encoding;\n char *apply_default_whitespace;\n char *apply_default_ignorewhitespace;\n-int pack_compression_level = Z_DEFAULT_COMPRESSION;\n int fsync_object_files = -1;\n int use_fsync = -1;\n enum fsync_method fsync_method = FSYNC_METHOD_DEFAULT;\n@@ -390,7 +389,7 @@ int git_default_core_config(const char *var, const char *value,\n \t\tif (!zlib_compression_seen)\n \t\t\tcfg->zlib_compression_level = level;\n \t\tif (!pack_compression_seen)\n-\t\t\tpack_compression_level = level;\n+\t\t\tcfg->pack_compression_level = level;\n \t\treturn 0;\n \t}\n \n@@ -662,6 +661,8 @@ static int git_default_attr_config(const char *var, const char *value)\n int git_default_config(const char *var, const char *value,\n \t\t       const struct config_context *ctx, void *cb)\n {\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n+\n \tif (starts_with(var, \"core.\"))\n \t\treturn git_default_core_config(var, value, ctx, cb);\n \n@@ -701,7 +702,7 @@ int git_default_config(const char *var, const char *value,\n \t\t\tlevel = Z_DEFAULT_COMPRESSION;\n \t\telse if (level < 0 || level > Z_BEST_COMPRESSION)\n \t\t\tdie(_(\"bad pack compression level %d\"), level);\n-\t\tpack_compression_level = level;\n+\t\tcfg->pack_compression_level = level;\n \t\tpack_compression_seen = 1;\n \t\treturn 0;\n \t}\n@@ -721,4 +722,5 @@ void repo_config_values_init(struct repo_config_values *cfg)\n \tcfg->trust_ctime = 1;\n \tcfg->check_stat = 1;\n \tcfg->zlib_compression_level = Z_BEST_SPEED;\n+\tcfg->pack_compression_level = Z_DEFAULT_COMPRESSION;\n }\ndiff --git a/environment.h b/environment.h\nindex 93201620af..514576b67a 100644\n--- a/environment.h\n+++ b/environment.h\n@@ -94,6 +94,7 @@ struct repo_config_values {\n \tint trust_ctime;\n \tint check_stat;\n \tint zlib_compression_level;\n+\tint pack_compression_level;\n \n \t/* section \"branch\" config values */\n \tenum branch_track branch_track;\n@@ -171,7 +172,6 @@ extern int assume_unchanged;\n extern int warn_on_object_refname_ambiguity;\n extern char *apply_default_whitespace;\n extern char *apply_default_ignorewhitespace;\n-extern int pack_compression_level;\n extern unsigned long pack_size_limit_cfg;\n \n extern int precomposed_unicode;\ndiff --git a/object-file.c b/object-file.c\nindex 7c122ac419..37def5cc59 100644\n--- a/object-file.c\n+++ b/object-file.c\n@@ -1437,8 +1437,9 @@ static int stream_blob_to_pack(struct transaction_packfile *state,\n \tint status = Z_OK;\n \tint write_object = (flags & INDEX_WRITE_OBJECT);\n \toff_t offset = 0;\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n-\tgit_deflate_init(&s, pack_compression_level);\n+\tgit_deflate_init(&s, cfg->pack_compression_level);\n \n \thdrlen = encode_in_pack_object_header(obuf, sizeof(obuf), OBJ_BLOB, size);\n \ts.next_out = obuf + hdrlen;\n-- \n2.53.0.155.g9f36b15afa\n\n"},{"id":"542220","messageId":"20260423165432.143598-6-belkid98@gmail.com","threadId":"65344","inReplyTo":"20260423165432.143598-1-belkid98@gmail.com","subject":"[PATCH v3 5/8] environment: move \"precomposed_unicode\" into `struct repo_config_values`","fromName":"Olamide Caleb Bello","fromEmail":"belkid98@gmail.com","sentAt":"2026-04-23T16:54:29Z","receivedAt":"2026-04-23T16:55:49Z","isPatch":true,"body":"The `core.precomposeunicode` configuration is currently stored in the\nglobal variable `precomposed_unicode`, which makes it shared across\nrepository instances within a single process.\n\nStore it instead in `repo_config_values`, where eagerly‑parsed\nrepository configuration lives. `core.precomposeunicode` is parsed\neagerly because it controls Unicode path normalization on macOS,\na fundamental filesystem‑level behavior that many operations depend\non; a lazy parse could lead to inconsistent results and hamper\nlibification. This preserves the existing behavior while tying the\nvalue to the repository from which it was read, avoiding cross‑\nrepository state leakage and continuing the effort to reduce reliance\non global configuration state.\n\nChange the type of the field from `int` to `bool` since it is parsed\nas a boolean value.\n\nUpdate all references to use `repo_config_values()`.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Usman Akinyemi <usmanakinyemi202@gmail.com>\nSigned-off-by: Olamide Caleb Bello <belkid98@gmail.com>\n---\n compat/precompose_utf8.c | 20 +++++++++++++-------\n environment.c            |  4 ++--\n environment.h            |  2 +-\n upload-pack.c            |  3 ++-\n 4 files changed, 18 insertions(+), 11 deletions(-)\n\ndiff --git a/compat/precompose_utf8.c b/compat/precompose_utf8.c\nindex 43b3be0114..0e94dbd862 100644\n--- a/compat/precompose_utf8.c\n+++ b/compat/precompose_utf8.c\n@@ -48,16 +48,18 @@ void probe_utf8_pathname_composition(void)\n \tstatic const char *auml_nfc = \"\\xc3\\xa4\";\n \tstatic const char *auml_nfd = \"\\x61\\xcc\\x88\";\n \tint output_fd;\n-\tif (precomposed_unicode != -1)\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n+\n+\tif (cfg->precomposed_unicode != -1)\n \t\treturn; /* We found it defined in the global config, respect it */\n \trepo_git_path_replace(the_repository, &path, \"%s\", auml_nfc);\n \toutput_fd = open(path.buf, O_CREAT|O_EXCL|O_RDWR, 0600);\n \tif (output_fd >= 0) {\n \t\tclose(output_fd);\n \t\trepo_git_path_replace(the_repository, &path, \"%s\", auml_nfd);\n-\t\tprecomposed_unicode = access(path.buf, R_OK) ? 0 : 1;\n+\t\tcfg->precomposed_unicode = access(path.buf, R_OK) ? 0 : 1;\n \t\trepo_config_set(the_repository, \"core.precomposeunicode\",\n-\t\t\t\tprecomposed_unicode ? \"true\" : \"false\");\n+\t\t\t\tcfg->precomposed_unicode ? \"true\" : \"false\");\n \t\trepo_git_path_replace(the_repository, &path, \"%s\", auml_nfc);\n \t\tif (unlink(path.buf))\n \t\t\tdie_errno(_(\"failed to unlink '%s'\"), path.buf);\n@@ -69,14 +71,16 @@ const char *precompose_string_if_needed(const char *in)\n {\n \tsize_t inlen;\n \tsize_t outlen;\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n+\n \tif (!in)\n \t\treturn NULL;\n \tif (has_non_ascii(in, (size_t)-1, &inlen)) {\n \t\ticonv_t ic_prec;\n \t\tchar *out;\n-\t\tif (precomposed_unicode < 0)\n-\t\t\trepo_config_get_bool(the_repository, \"core.precomposeunicode\", &precomposed_unicode);\n-\t\tif (precomposed_unicode != 1)\n+\t\tif (cfg->precomposed_unicode < 0)\n+\t\t\trepo_config_get_bool(the_repository, \"core.precomposeunicode\", &cfg->precomposed_unicode);\n+\t\tif (cfg->precomposed_unicode != 1)\n \t\t\treturn in;\n \t\tic_prec = iconv_open(repo_encoding, path_encoding);\n \t\tif (ic_prec == (iconv_t) -1)\n@@ -130,7 +134,9 @@ PREC_DIR *precompose_utf8_opendir(const char *dirname)\n \n struct dirent_prec_psx *precompose_utf8_readdir(PREC_DIR *prec_dir)\n {\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \tstruct dirent *res;\n+\n \tres = readdir(prec_dir->dirp);\n \tif (res) {\n \t\tsize_t namelenz = strlen(res->d_name) + 1; /* \\0 */\n@@ -149,7 +155,7 @@ struct dirent_prec_psx *precompose_utf8_readdir(PREC_DIR *prec_dir)\n \t\tprec_dir->dirent_nfc->d_ino  = res->d_ino;\n \t\tprec_dir->dirent_nfc->d_type = res->d_type;\n \n-\t\tif ((precomposed_unicode == 1) && has_non_ascii(res->d_name, (size_t)-1, NULL)) {\n+\t\tif ((cfg->precomposed_unicode == 1) && has_non_ascii(res->d_name, (size_t)-1, NULL)) {\n \t\t\tif (prec_dir->ic_precompose == (iconv_t)-1) {\n \t\t\t\tdie(\"iconv_open(%s,%s) failed, but needed:\\n\"\n \t\t\t\t\t\t\"    precomposed unicode is not supported.\\n\"\ndiff --git a/environment.c b/environment.c\nindex d0d3a4b7d2..739b647ebe 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -72,7 +72,6 @@ enum object_creation_mode object_creation_mode = OBJECT_CREATION_MODE;\n int grafts_keep_true_parents;\n int core_sparse_checkout_cone;\n int sparse_expect_files_outside_of_patterns;\n-int precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */\n unsigned long pack_size_limit_cfg;\n \n #ifndef PROTECT_HFS_DEFAULT\n@@ -532,7 +531,7 @@ int git_default_core_config(const char *var, const char *value,\n \t}\n \n \tif (!strcmp(var, \"core.precomposeunicode\")) {\n-\t\tprecomposed_unicode = git_config_bool(var, value);\n+\t\tcfg->precomposed_unicode = git_config_bool(var, value);\n \t\treturn 0;\n \t}\n \n@@ -723,4 +722,5 @@ void repo_config_values_init(struct repo_config_values *cfg)\n \tcfg->check_stat = 1;\n \tcfg->zlib_compression_level = Z_BEST_SPEED;\n \tcfg->pack_compression_level = Z_DEFAULT_COMPRESSION;\n+\tcfg->precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */\n }\ndiff --git a/environment.h b/environment.h\nindex 514576b67a..508cb1afbc 100644\n--- a/environment.h\n+++ b/environment.h\n@@ -95,6 +95,7 @@ struct repo_config_values {\n \tint check_stat;\n \tint zlib_compression_level;\n \tint pack_compression_level;\n+\tint precomposed_unicode;\n \n \t/* section \"branch\" config values */\n \tenum branch_track branch_track;\n@@ -174,7 +175,6 @@ extern char *apply_default_whitespace;\n extern char *apply_default_ignorewhitespace;\n extern unsigned long pack_size_limit_cfg;\n \n-extern int precomposed_unicode;\n extern int protect_hfs;\n extern int protect_ntfs;\n \ndiff --git a/upload-pack.c b/upload-pack.c\nindex 9f6d6fe48c..3a52237134 100644\n--- a/upload-pack.c\n+++ b/upload-pack.c\n@@ -1336,6 +1336,7 @@ static int upload_pack_config(const char *var, const char *value,\n \t\t\t      void *cb_data)\n {\n \tstruct upload_pack_data *data = cb_data;\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n \tif (!strcmp(\"uploadpack.allowtipsha1inwant\", var)) {\n \t\tif (git_config_bool(var, value))\n@@ -1366,7 +1367,7 @@ static int upload_pack_config(const char *var, const char *value,\n \t\tif (value)\n \t\t\tdata->allow_packfile_uris = 1;\n \t} else if (!strcmp(\"core.precomposeunicode\", var)) {\n-\t\tprecomposed_unicode = git_config_bool(var, value);\n+\t\tcfg->precomposed_unicode = git_config_bool(var, value);\n \t} else if (!strcmp(\"transfer.advertisesid\", var)) {\n \t\tdata->advertise_sid = git_config_bool(var, value);\n \t}\n-- \n2.53.0.155.g9f36b15afa\n\n"},{"id":"542221","messageId":"20260423165432.143598-7-belkid98@gmail.com","threadId":"65344","inReplyTo":"20260423165432.143598-1-belkid98@gmail.com","subject":"[PATCH v3 6/8] env: move \"core_sparse_checkout_cone\" into `struct repo_config_values`","fromName":"Olamide Caleb Bello","fromEmail":"belkid98@gmail.com","sentAt":"2026-04-23T16:54:30Z","receivedAt":"2026-04-23T16:55:52Z","isPatch":true,"body":"The `core.sparseCheckoutCone` configuration was previously stored in an\nuninitialized global `int` variable, risking cross‑repository state\nleakage.\n\nMove it into `repo_config_values`, where eagerly‑parsed repository\nconfiguration lives. `core.sparseCheckoutCone` is parsed eagerly\nbecause it determines the fundamental sparse‑checkout mode and is\nconsulted very early during repository setup; a lazy parse could\nleave the sparse‑checkout state undefined and complicate\nlibification. This preserves the existing behavior while tying the\nvalue to the repository from which it was read, avoiding cross‑\nrepository state leakage and continuing the effort to reduce reliance\non global configuration state.\n\nUpdate all references to use `repo_config_values()`.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Usman Akinyemi <usmanakinyemi202@gmail.com>\nSigned-off-by: Olamide Caleb Bello <belkid98@gmail.com>\n---\n builtin/mv.c              |  2 +-\n builtin/sparse-checkout.c | 37 ++++++++++++++++++++++---------------\n dir.c                     |  3 ++-\n environment.c             |  4 ++--\n environment.h             |  2 +-\n sparse-index.c            |  2 +-\n 6 files changed, 29 insertions(+), 21 deletions(-)\n\ndiff --git a/builtin/mv.c b/builtin/mv.c\nindex 2215d34e31..ef3a326c90 100644\n--- a/builtin/mv.c\n+++ b/builtin/mv.c\n@@ -574,7 +574,7 @@ int cmd_mv(int argc,\n \n \t\tif (ignore_sparse &&\n \t\t    cfg->apply_sparse_checkout &&\n-\t\t    core_sparse_checkout_cone) {\n+\t\t    cfg->core_sparse_checkout_cone) {\n \t\t\t/*\n \t\t\t * NEEDSWORK: we are *not* paying attention to\n \t\t\t * \"out-to-out\" move (<source> is out-of-cone and\ndiff --git a/builtin/sparse-checkout.c b/builtin/sparse-checkout.c\nindex f4aa405da9..92d017b81f 100644\n--- a/builtin/sparse-checkout.c\n+++ b/builtin/sparse-checkout.c\n@@ -73,7 +73,7 @@ static int sparse_checkout_list(int argc, const char **argv, const char *prefix,\n \n \tmemset(&pl, 0, sizeof(pl));\n \n-\tpl.use_cone_patterns = core_sparse_checkout_cone;\n+\tpl.use_cone_patterns = cfg->core_sparse_checkout_cone;\n \n \tsparse_filename = get_sparse_checkout_filename();\n \tres = add_patterns_from_file_to_list(sparse_filename, \"\", 0, &pl, NULL, 0);\n@@ -334,6 +334,7 @@ static int write_patterns_and_update(struct repository *repo,\n \tFILE *fp;\n \tstruct lock_file lk = LOCK_INIT;\n \tint result;\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n \tsparse_filename = get_sparse_checkout_filename();\n \n@@ -353,7 +354,7 @@ static int write_patterns_and_update(struct repository *repo,\n \tif (!fp)\n \t\tdie_errno(_(\"unable to fdopen %s\"), get_lock_file_path(&lk));\n \n-\tif (core_sparse_checkout_cone)\n+\tif (cfg->core_sparse_checkout_cone)\n \t\twrite_cone_to_file(fp, pl);\n \telse\n \t\twrite_patterns_to_file(fp, pl);\n@@ -402,15 +403,15 @@ static enum sparse_checkout_mode update_cone_mode(int *cone_mode) {\n \n \t/* If not specified, use previous definition of cone mode */\n \tif (*cone_mode == -1 && cfg->apply_sparse_checkout)\n-\t\t*cone_mode = core_sparse_checkout_cone;\n+\t\t*cone_mode = cfg->core_sparse_checkout_cone;\n \n \t/* Set cone/non-cone mode appropriately */\n \tcfg->apply_sparse_checkout = 1;\n \tif (*cone_mode == 1 || *cone_mode == -1) {\n-\t\tcore_sparse_checkout_cone = 1;\n+\t\tcfg->core_sparse_checkout_cone = 1;\n \t\treturn MODE_CONE_PATTERNS;\n \t}\n-\tcore_sparse_checkout_cone = 0;\n+\tcfg->core_sparse_checkout_cone = 0;\n \treturn MODE_ALL_PATTERNS;\n }\n \n@@ -577,7 +578,9 @@ static void add_patterns_from_input(struct pattern_list *pl,\n \t\t\t\t    FILE *file)\n {\n \tint i;\n-\tif (core_sparse_checkout_cone) {\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n+\n+\tif (cfg->core_sparse_checkout_cone) {\n \t\tstruct strbuf line = STRBUF_INIT;\n \n \t\thashmap_init(&pl->recursive_hashmap, pl_hashmap_cmp, NULL, 0);\n@@ -636,13 +639,14 @@ static void add_patterns_cone_mode(int argc, const char **argv,\n \tstruct pattern_entry *pe;\n \tstruct hashmap_iter iter;\n \tstruct pattern_list existing;\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \tchar *sparse_filename = get_sparse_checkout_filename();\n \n \tadd_patterns_from_input(pl, argc, argv,\n \t\t\t\tuse_stdin ? stdin : NULL);\n \n \tmemset(&existing, 0, sizeof(existing));\n-\texisting.use_cone_patterns = core_sparse_checkout_cone;\n+\texisting.use_cone_patterns = cfg->core_sparse_checkout_cone;\n \n \tif (add_patterns_from_file_to_list(sparse_filename, \"\", 0,\n \t\t\t\t\t   &existing, NULL, 0))\n@@ -690,7 +694,7 @@ static int modify_pattern_list(struct repository *repo,\n \n \tswitch (m) {\n \tcase ADD:\n-\t\tif (core_sparse_checkout_cone)\n+\t\tif (cfg->core_sparse_checkout_cone)\n \t\t\tadd_patterns_cone_mode(args->nr, args->v, pl, use_stdin);\n \t\telse\n \t\t\tadd_patterns_literal(args->nr, args->v, pl, use_stdin);\n@@ -723,11 +727,12 @@ static void sanitize_paths(struct repository *repo,\n \t\t\t   const char *prefix, int skip_checks)\n {\n \tint i;\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n \tif (!args->nr)\n \t\treturn;\n \n-\tif (prefix && *prefix && core_sparse_checkout_cone) {\n+\tif (prefix && *prefix && cfg->core_sparse_checkout_cone) {\n \t\t/*\n \t\t * The args are not pathspecs, so unfortunately we\n \t\t * cannot imitate how cmd_add() uses parse_pathspec().\n@@ -744,10 +749,10 @@ static void sanitize_paths(struct repository *repo,\n \tif (skip_checks)\n \t\treturn;\n \n-\tif (prefix && *prefix && !core_sparse_checkout_cone)\n+\tif (prefix && *prefix && !cfg->core_sparse_checkout_cone)\n \t\tdie(_(\"please run from the toplevel directory in non-cone mode\"));\n \n-\tif (core_sparse_checkout_cone) {\n+\tif (cfg->core_sparse_checkout_cone) {\n \t\tfor (i = 0; i < args->nr; i++) {\n \t\t\tif (args->v[i][0] == '/')\n \t\t\t\tdie(_(\"specify directories rather than patterns (no leading slash)\"));\n@@ -769,7 +774,7 @@ static void sanitize_paths(struct repository *repo,\n \t\tif (S_ISSPARSEDIR(ce->ce_mode))\n \t\t\tcontinue;\n \n-\t\tif (core_sparse_checkout_cone)\n+\t\tif (cfg->core_sparse_checkout_cone)\n \t\t\tdie(_(\"'%s' is not a directory; to treat it as a directory anyway, rerun with --skip-checks\"), args->v[i]);\n \t\telse\n \t\t\twarning(_(\"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]);\n@@ -836,6 +841,7 @@ static struct sparse_checkout_set_opts {\n static int sparse_checkout_set(int argc, const char **argv, const char *prefix,\n \t\t\t       struct repository *repo)\n {\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \tint default_patterns_nr = 2;\n \tconst char *default_patterns[] = {\"/*\", \"!/*/\", NULL};\n \n@@ -873,7 +879,7 @@ static int sparse_checkout_set(int argc, const char **argv, const char *prefix,\n \t * non-cone mode, if nothing is specified, manually select just the\n \t * top-level directory (much as 'init' would do).\n \t */\n-\tif (!core_sparse_checkout_cone && !set_opts.use_stdin && argc == 0) {\n+\tif (!cfg->core_sparse_checkout_cone && !set_opts.use_stdin && argc == 0) {\n \t\tfor (int i = 0; i < default_patterns_nr; i++)\n \t\t\tstrvec_push(&patterns, default_patterns[i]);\n \t} else {\n@@ -977,7 +983,7 @@ static int sparse_checkout_clean(int argc, const char **argv,\n \tsetup_work_tree();\n \tif (!cfg->apply_sparse_checkout)\n \t\tdie(_(\"must be in a sparse-checkout to clean directories\"));\n-\tif (!core_sparse_checkout_cone)\n+\tif (!cfg->core_sparse_checkout_cone)\n \t\tdie(_(\"must be in a cone-mode sparse-checkout to clean directories\"));\n \n \targc = parse_options(argc, argv, prefix,\n@@ -1141,6 +1147,7 @@ static int sparse_checkout_check_rules(int argc, const char **argv, const char *\n \tFILE *fp;\n \tint ret;\n \tstruct pattern_list pl = {0};\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \tchar *sparse_filename;\n \tcheck_rules_opts.cone_mode = -1;\n \n@@ -1152,7 +1159,7 @@ static int sparse_checkout_check_rules(int argc, const char **argv, const char *\n \t\tcheck_rules_opts.cone_mode = 1;\n \n \tupdate_cone_mode(&check_rules_opts.cone_mode);\n-\tpl.use_cone_patterns = core_sparse_checkout_cone;\n+\tpl.use_cone_patterns = cfg->core_sparse_checkout_cone;\n \tif (check_rules_opts.rules_file) {\n \t\tfp = xfopen(check_rules_opts.rules_file, \"r\");\n \t\tadd_patterns_from_input(&pl, argc, argv, fp);\ndiff --git a/dir.c b/dir.c\nindex fcb8f6dd2a..4f493b64c6 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -3508,8 +3508,9 @@ int get_sparse_checkout_patterns(struct pattern_list *pl)\n {\n \tint res;\n \tchar *sparse_filename = get_sparse_checkout_filename();\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n-\tpl->use_cone_patterns = core_sparse_checkout_cone;\n+\tpl->use_cone_patterns = cfg->core_sparse_checkout_cone;\n \tres = add_patterns_from_file_to_list(sparse_filename, \"\", 0, pl, NULL, 0);\n \n \tfree(sparse_filename);\ndiff --git a/environment.c b/environment.c\nindex 739b647ebe..b0e873e9f5 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -70,7 +70,6 @@ enum push_default_type push_default = PUSH_DEFAULT_UNSPECIFIED;\n #endif\n enum object_creation_mode object_creation_mode = OBJECT_CREATION_MODE;\n int grafts_keep_true_parents;\n-int core_sparse_checkout_cone;\n int sparse_expect_files_outside_of_patterns;\n unsigned long pack_size_limit_cfg;\n \n@@ -526,7 +525,7 @@ int git_default_core_config(const char *var, const char *value,\n \t}\n \n \tif (!strcmp(var, \"core.sparsecheckoutcone\")) {\n-\t\tcore_sparse_checkout_cone = git_config_bool(var, value);\n+\t\tcfg->core_sparse_checkout_cone = git_config_bool(var, value);\n \t\treturn 0;\n \t}\n \n@@ -723,4 +722,5 @@ void repo_config_values_init(struct repo_config_values *cfg)\n \tcfg->zlib_compression_level = Z_BEST_SPEED;\n \tcfg->pack_compression_level = Z_DEFAULT_COMPRESSION;\n \tcfg->precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */\n+\tcfg->core_sparse_checkout_cone = 0;\n }\ndiff --git a/environment.h b/environment.h\nindex 508cb1afbc..befad9a388 100644\n--- a/environment.h\n+++ b/environment.h\n@@ -96,6 +96,7 @@ struct repo_config_values {\n \tint zlib_compression_level;\n \tint pack_compression_level;\n \tint precomposed_unicode;\n+\tint core_sparse_checkout_cone;\n \n \t/* section \"branch\" config values */\n \tenum branch_track branch_track;\n@@ -178,7 +179,6 @@ extern unsigned long pack_size_limit_cfg;\n extern int protect_hfs;\n extern int protect_ntfs;\n \n-extern int core_sparse_checkout_cone;\n extern int sparse_expect_files_outside_of_patterns;\n \n enum rebase_setup_type {\ndiff --git a/sparse-index.c b/sparse-index.c\nindex 13629c075d..53cb8d64fc 100644\n--- a/sparse-index.c\n+++ b/sparse-index.c\n@@ -154,7 +154,7 @@ int is_sparse_index_allowed(struct index_state *istate, int flags)\n {\n \tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n-\tif (!cfg->apply_sparse_checkout || !core_sparse_checkout_cone)\n+\tif (!cfg->apply_sparse_checkout || !cfg->core_sparse_checkout_cone)\n \t\treturn 0;\n \n \tif (!(flags & SPARSE_INDEX_MEMORY_ONLY)) {\n-- \n2.53.0.155.g9f36b15afa\n\n"},{"id":"542222","messageId":"20260423165432.143598-8-belkid98@gmail.com","threadId":"65344","inReplyTo":"20260423165432.143598-1-belkid98@gmail.com","subject":"[PATCH v3 7/8] env: move \"sparse_expect_files_outside_of_patterns\" into `repo_config_values`","fromName":"Olamide Caleb Bello","fromEmail":"belkid98@gmail.com","sentAt":"2026-04-23T16:54:31Z","receivedAt":"2026-04-23T16:55:54Z","isPatch":true,"body":"The `core.sparseCheckoutExpectFilesOutsideOfPatterns` configuration was\npreviously stored in a global `int` variable, making it shared across\nrepository instances and risking cross‑repository state leakage.\n\nStore it instead in `repo_config_values`, where eagerly‑parsed\nrepository configuration lives. This option is parsed eagerly because\nit controls how sparse‑checkout paths are interpreted – a fundamental\nbehavior that many commands rely on; a lazy parse could cause\ninconsistent sparse‑checkout handling and complicate libification.\nThis preserves the existing behavior while tying the value to the\nrepository from which it was read, avoiding cross‑repository state\nleakage and continuing the effort to reduce reliance on global\nconfiguration state.\n\nUpdate all references to use `repo_config_values()`.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Usman Akinyemi <usmanakinyemi202@gmail.com>\nSigned-off-by: Olamide Caleb Bello <belkid98@gmail.com>\n---\n environment.c  | 6 ++++--\n environment.h  | 5 +++--\n sparse-index.c | 2 +-\n 3 files changed, 8 insertions(+), 5 deletions(-)\n\ndiff --git a/environment.c b/environment.c\nindex b0e873e9f5..57587ede56 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -70,7 +70,6 @@ enum push_default_type push_default = PUSH_DEFAULT_UNSPECIFIED;\n #endif\n enum object_creation_mode object_creation_mode = OBJECT_CREATION_MODE;\n int grafts_keep_true_parents;\n-int sparse_expect_files_outside_of_patterns;\n unsigned long pack_size_limit_cfg;\n \n #ifndef PROTECT_HFS_DEFAULT\n@@ -550,8 +549,10 @@ int git_default_core_config(const char *var, const char *value,\n \n static int git_default_sparse_config(const char *var, const char *value)\n {\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n+\n \tif (!strcmp(var, \"sparse.expectfilesoutsideofpatterns\")) {\n-\t\tsparse_expect_files_outside_of_patterns = git_config_bool(var, value);\n+\t\tcfg->sparse_expect_files_outside_of_patterns = git_config_bool(var, value);\n \t\treturn 0;\n \t}\n \n@@ -723,4 +724,5 @@ void repo_config_values_init(struct repo_config_values *cfg)\n \tcfg->pack_compression_level = Z_DEFAULT_COMPRESSION;\n \tcfg->precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */\n \tcfg->core_sparse_checkout_cone = 0;\n+\tcfg->sparse_expect_files_outside_of_patterns = 0;\n }\ndiff --git a/environment.h b/environment.h\nindex befad9a388..609cdaa07f 100644\n--- a/environment.h\n+++ b/environment.h\n@@ -98,6 +98,9 @@ struct repo_config_values {\n \tint precomposed_unicode;\n \tint core_sparse_checkout_cone;\n \n+\t/* section \"sparse\" config values */\n+\tint sparse_expect_files_outside_of_patterns;\n+\n \t/* section \"branch\" config values */\n \tenum branch_track branch_track;\n };\n@@ -179,8 +182,6 @@ extern unsigned long pack_size_limit_cfg;\n extern int protect_hfs;\n extern int protect_ntfs;\n \n-extern int sparse_expect_files_outside_of_patterns;\n-\n enum rebase_setup_type {\n \tAUTOREBASE_NEVER = 0,\n \tAUTOREBASE_LOCAL,\ndiff --git a/sparse-index.c b/sparse-index.c\nindex 53cb8d64fc..1ed769b78d 100644\n--- a/sparse-index.c\n+++ b/sparse-index.c\n@@ -675,7 +675,7 @@ void clear_skip_worktree_from_present_files(struct index_state *istate)\n \tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n \tif (!cfg->apply_sparse_checkout ||\n-\t    sparse_expect_files_outside_of_patterns)\n+\t    cfg->sparse_expect_files_outside_of_patterns)\n \t\treturn;\n \n \tif (clear_skip_worktree_from_present_files_sparse(istate)) {\n-- \n2.53.0.155.g9f36b15afa\n\n"},{"id":"542223","messageId":"20260423165432.143598-9-belkid98@gmail.com","threadId":"65344","inReplyTo":"20260423165432.143598-1-belkid98@gmail.com","subject":"[PATCH v3 8/8] env: move \"warn_on_object_refname_ambiguity\" into `struct repo_config_values`","fromName":"Olamide Caleb Bello","fromEmail":"belkid98@gmail.com","sentAt":"2026-04-23T16:54:32Z","receivedAt":"2026-04-23T16:55:57Z","isPatch":true,"body":"The `core.warnAmbiguousRefs` configuration was previously stored in a\nglobal `int` variable, making it shared across repository instances\nand risking cross‑repository state leakage.\n\nStore it instead in `repo_config_values`, where eagerly‑parsed\nrepository configuration lives. This option is parsed eagerly because\nambiguity warnings influence how users interpret object references in\nmany commands; a lazy parse could cause these warnings to behave\ninconsistently or to appear for the wrong repository, confusing users\nand hindering libification. This preserves the existing behavior while\ntying the value to the repository from which it was read, avoiding\ncross‑repository state leakage and continuing the effort to reduce\nreliance on global configuration state.\n\nUpdate all references to use `repo_config_values()`.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Usman Akinyemi <usmanakinyemi202@gmail.com>\nSigned-off-by: Olamide Caleb Bello <belkid98@gmail.com>\n---\n builtin/cat-file.c     | 7 ++++---\n builtin/pack-objects.c | 7 ++++---\n environment.c          | 2 +-\n environment.h          | 2 +-\n object-name.c          | 3 ++-\n revision.c             | 7 ++++---\n submodule.c            | 7 ++++---\n 7 files changed, 20 insertions(+), 15 deletions(-)\n\ndiff --git a/builtin/cat-file.c b/builtin/cat-file.c\nindex d9fbad5358..cfc5430186 100644\n--- a/builtin/cat-file.c\n+++ b/builtin/cat-file.c\n@@ -901,6 +901,7 @@ static int batch_objects(struct batch_options *opt)\n \tstruct strbuf input = STRBUF_INIT;\n \tstruct strbuf output = STRBUF_INIT;\n \tstruct expand_data data = EXPAND_DATA_INIT;\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \tint save_warning;\n \tint retval = 0;\n \n@@ -973,8 +974,8 @@ static int batch_objects(struct batch_options *opt)\n \t * warn) ends up dwarfing the actual cost of the object lookups\n \t * themselves. We can work around it by just turning off the warning.\n \t */\n-\tsave_warning = warn_on_object_refname_ambiguity;\n-\twarn_on_object_refname_ambiguity = 0;\n+\tsave_warning = cfg->warn_on_object_refname_ambiguity;\n+\tcfg->warn_on_object_refname_ambiguity = 0;\n \n \tif (opt->batch_mode == BATCH_MODE_QUEUE_AND_DISPATCH) {\n \t\tbatch_objects_command(opt, &output, &data);\n@@ -1002,7 +1003,7 @@ static int batch_objects(struct batch_options *opt)\n  cleanup:\n \tstrbuf_release(&input);\n \tstrbuf_release(&output);\n-\twarn_on_object_refname_ambiguity = save_warning;\n+\tcfg->warn_on_object_refname_ambiguity = save_warning;\n \treturn retval;\n }\n \ndiff --git a/builtin/pack-objects.c b/builtin/pack-objects.c\nindex 8ccbe7e178..7df75fe91e 100644\n--- a/builtin/pack-objects.c\n+++ b/builtin/pack-objects.c\n@@ -4788,6 +4788,7 @@ static void get_object_list(struct rev_info *revs, struct strvec *argv)\n \tstruct setup_revision_opt s_r_opt = {\n \t\t.allow_exclude_promisor_objects = 1,\n \t};\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \tchar line[1000];\n \tint flags = 0;\n \tint save_warning;\n@@ -4798,8 +4799,8 @@ static void get_object_list(struct rev_info *revs, struct strvec *argv)\n \t/* make sure shallows are read */\n \tis_repository_shallow(the_repository);\n \n-\tsave_warning = warn_on_object_refname_ambiguity;\n-\twarn_on_object_refname_ambiguity = 0;\n+\tsave_warning = cfg->warn_on_object_refname_ambiguity;\n+\tcfg->warn_on_object_refname_ambiguity = 0;\n \n \twhile (fgets(line, sizeof(line), stdin) != NULL) {\n \t\tint len = strlen(line);\n@@ -4827,7 +4828,7 @@ static void get_object_list(struct rev_info *revs, struct strvec *argv)\n \t\t\tdie(_(\"bad revision '%s'\"), line);\n \t}\n \n-\twarn_on_object_refname_ambiguity = save_warning;\n+\tcfg->warn_on_object_refname_ambiguity = save_warning;\n \n \tif (use_bitmap_index && !get_object_list_from_bitmap(revs))\n \t\treturn;\ndiff --git a/environment.c b/environment.c\nindex 57587ede56..ba2c60103f 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -47,7 +47,6 @@ int minimum_abbrev = 4, default_abbrev = -1;\n int ignore_case;\n int assume_unchanged;\n int is_bare_repository_cfg = -1; /* unspecified */\n-int warn_on_object_refname_ambiguity = 1;\n char *git_commit_encoding;\n char *git_log_output_encoding;\n char *apply_default_whitespace;\n@@ -725,4 +724,5 @@ void repo_config_values_init(struct repo_config_values *cfg)\n \tcfg->precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */\n \tcfg->core_sparse_checkout_cone = 0;\n \tcfg->sparse_expect_files_outside_of_patterns = 0;\n+\tcfg->warn_on_object_refname_ambiguity = 1;\n }\ndiff --git a/environment.h b/environment.h\nindex 609cdaa07f..1ff0a7ba8b 100644\n--- a/environment.h\n+++ b/environment.h\n@@ -97,6 +97,7 @@ struct repo_config_values {\n \tint pack_compression_level;\n \tint precomposed_unicode;\n \tint core_sparse_checkout_cone;\n+\tint warn_on_object_refname_ambiguity;\n \n \t/* section \"sparse\" config values */\n \tint sparse_expect_files_outside_of_patterns;\n@@ -174,7 +175,6 @@ extern int has_symlinks;\n extern int minimum_abbrev, default_abbrev;\n extern int ignore_case;\n extern int assume_unchanged;\n-extern int warn_on_object_refname_ambiguity;\n extern char *apply_default_whitespace;\n extern char *apply_default_ignorewhitespace;\n extern unsigned long pack_size_limit_cfg;\ndiff --git a/object-name.c b/object-name.c\nindex 21dcdc4a0e..319d3db01d 100644\n--- a/object-name.c\n+++ b/object-name.c\n@@ -684,11 +684,12 @@ static int get_oid_basic(struct repository *r, const char *str, int len,\n \tint refs_found = 0;\n \tint at, reflog_len, nth_prior = 0;\n \tint fatal = !(flags & GET_OID_QUIETLY);\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n \tif (len == r->hash_algo->hexsz && !get_oid_hex(str, oid)) {\n \t\tif (!(flags & GET_OID_SKIP_AMBIGUITY_CHECK) &&\n \t\t    repo_settings_get_warn_ambiguous_refs(r) &&\n-\t\t    warn_on_object_refname_ambiguity) {\n+\t\t    cfg->warn_on_object_refname_ambiguity) {\n \t\t\trefs_found = repo_dwim_ref(r, str, len, &tmp_oid, &real_ref, 0);\n \t\t\tif (refs_found > 0) {\n \t\t\t\twarning(warn_msg, len, str);\ndiff --git a/revision.c b/revision.c\nindex 599b3a66c3..4e7faa7eb1 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -2922,9 +2922,10 @@ static void read_revisions_from_stdin(struct rev_info *revs,\n \tint seen_end_of_options = 0;\n \tint save_warning;\n \tint flags = 0;\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n-\tsave_warning = warn_on_object_refname_ambiguity;\n-\twarn_on_object_refname_ambiguity = 0;\n+\tsave_warning = cfg->warn_on_object_refname_ambiguity;\n+\tcfg->warn_on_object_refname_ambiguity = 0;\n \n \tstrbuf_init(&sb, 1000);\n \twhile (strbuf_getline(&sb, stdin) != EOF) {\n@@ -2958,7 +2959,7 @@ static void read_revisions_from_stdin(struct rev_info *revs,\n \t\tread_pathspec_from_stdin(&sb, prune);\n \n \tstrbuf_release(&sb);\n-\twarn_on_object_refname_ambiguity = save_warning;\n+\tcfg->warn_on_object_refname_ambiguity = save_warning;\n }\n \n static void NORETURN diagnose_missing_default(const char *def)\ndiff --git a/submodule.c b/submodule.c\nindex b1a0363f9d..f26235bbb7 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -898,12 +898,13 @@ static void collect_changed_submodules(struct repository *r,\n \tstruct setup_revision_opt s_r_opt = {\n \t\t.assume_dashdash = 1,\n \t};\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n-\tsave_warning = warn_on_object_refname_ambiguity;\n-\twarn_on_object_refname_ambiguity = 0;\n+\tsave_warning = cfg->warn_on_object_refname_ambiguity;\n+\tcfg->warn_on_object_refname_ambiguity = 0;\n \trepo_init_revisions(r, &rev, NULL);\n \tsetup_revisions_from_strvec(argv, &rev, &s_r_opt);\n-\twarn_on_object_refname_ambiguity = save_warning;\n+\tcfg->warn_on_object_refname_ambiguity = save_warning;\n \tif (prepare_revision_walk(&rev))\n \t\tdie(_(\"revision walk setup failed\"));\n \n-- \n2.53.0.155.g9f36b15afa\n\n"},{"id":"542312","messageId":"xmqqqzo27fnu.fsf@gitster.g","threadId":"65344","inReplyTo":"20260423165432.143598-1-belkid98@gmail.com","subject":"Re: [PATCH v3 0/8] environment: move core config globals into repo_config_values","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-04-26T00:01:57Z","receivedAt":"2026-04-26T00:02:00Z","isPatch":true,"body":"Olamide Caleb Bello <belkid98@gmail.com> writes:\n\n> Olamide Caleb Bello (8):\n>   environment: move \"trust_ctime\" into `struct repo_config_values`\n>   environment: move \"check_stat\" into `struct repo_config_values`\n>   environment: move `zlib_compression_level` into `struct\n>     repo_config_values`\n>   environment: move \"pack_compression_level\" into `struct\n>     repo_config_values`\n>   environment: move \"precomposed_unicode\" into `struct\n>     repo_config_values`\n>   env: move \"core_sparse_checkout_cone\" into `struct repo_config_values`\n>   env: move \"sparse_expect_files_outside_of_patterns\" into\n>     `repo_config_values`\n>   env: move \"warn_on_object_refname_ambiguity\" into `struct\n>     repo_config_values`\n\nAre there differences between the ones that start with \"environment:\"\nvs the ones with \"env:\"?\n\n>\n>  builtin/cat-file.c        |  7 ++++---\n>  builtin/fast-import.c     |  8 +++++---\n>  builtin/index-pack.c      |  3 ++-\n>  builtin/mv.c              |  2 +-\n>  builtin/pack-objects.c    | 24 +++++++++++++----------\n>  builtin/sparse-checkout.c | 37 +++++++++++++++++++++---------------\n>  compat/precompose_utf8.c  | 20 +++++++++++++-------\n>  diff.c                    |  3 ++-\n>  dir.c                     |  3 ++-\n>  entry.c                   |  3 ++-\n>  environment.c             | 40 +++++++++++++++++++++------------------\n>  environment.h             | 19 ++++++++++---------\n>  http-push.c               |  3 ++-\n>  object-file.c             |  6 ++++--\n>  object-name.c             |  3 ++-\n>  revision.c                |  7 ++++---\n>  sparse-index.c            |  4 ++--\n>  statinfo.c                | 12 +++++++-----\n>  submodule.c               |  7 ++++---\n>  upload-pack.c             |  3 ++-\n>  20 files changed, 126 insertions(+), 88 deletions(-)\n"},{"id":"542313","messageId":"CAD=f0L8-_3sDGGkCzF4WA0xmUtaY_qiz__3zq5AemLgwTsqvsg@mail.gmail.com","threadId":"65344","inReplyTo":"xmqqqzo27fnu.fsf@gitster.g","subject":"Re: [PATCH v3 0/8] environment: move core config globals into repo_config_values","fromName":"Bello Olamide","fromEmail":"belkid98@gmail.com","sentAt":"2026-04-26T00:31:17Z","receivedAt":"2026-04-26T00:31:30Z","isPatch":true,"body":"On Sun, 26 Apr 2026 at 01:02, Junio C Hamano <gitster@pobox.com> wrote:\n>\n> Olamide Caleb Bello <belkid98@gmail.com> writes:\n>\n> > Olamide Caleb Bello (8):\n> >   environment: move \"trust_ctime\" into `struct repo_config_values`\n> >   environment: move \"check_stat\" into `struct repo_config_values`\n> >   environment: move `zlib_compression_level` into `struct\n> >     repo_config_values`\n> >   environment: move \"pack_compression_level\" into `struct\n> >     repo_config_values`\n> >   environment: move \"precomposed_unicode\" into `struct\n> >     repo_config_values`\n> >   env: move \"core_sparse_checkout_cone\" into `struct repo_config_values`\n> >   env: move \"sparse_expect_files_outside_of_patterns\" into\n> >     `repo_config_values`\n> >   env: move \"warn_on_object_refname_ambiguity\" into `struct\n> >     repo_config_values`\n>\n> Are there differences between the ones that start with \"environment:\"\n> vs the ones with \"env:\"?\n>\nHi Junio,\n\nThere isn’t any semantic difference intended between\nthe \"environment:\" and \"env:\" prefixes\n\nI shortened some of them to stay within the recommended subject length,\nbut on a second thought I agree that consistency is more important here.\n\nI’ll standardize them in the next revision.\nThanks.\n> >\n> >  builtin/cat-file.c        |  7 ++++---\n> >  builtin/fast-import.c     |  8 +++++---\n> >  builtin/index-pack.c      |  3 ++-\n> >  builtin/mv.c              |  2 +-\n> >  builtin/pack-objects.c    | 24 +++++++++++++----------\n> >  builtin/sparse-checkout.c | 37 +++++++++++++++++++++---------------\n> >  compat/precompose_utf8.c  | 20 +++++++++++++-------\n> >  diff.c                    |  3 ++-\n> >  dir.c                     |  3 ++-\n> >  entry.c                   |  3 ++-\n> >  environment.c             | 40 +++++++++++++++++++++------------------\n> >  environment.h             | 19 ++++++++++---------\n> >  http-push.c               |  3 ++-\n> >  object-file.c             |  6 ++++--\n> >  object-name.c             |  3 ++-\n> >  revision.c                |  7 ++++---\n> >  sparse-index.c            |  4 ++--\n> >  statinfo.c                | 12 +++++++-----\n> >  submodule.c               |  7 ++++---\n> >  upload-pack.c             |  3 ++-\n> >  20 files changed, 126 insertions(+), 88 deletions(-)\n"},{"id":"543004","messageId":"xmqqlddqu013.fsf@gitster.g","threadId":"65344","inReplyTo":"CAD=f0L8-_3sDGGkCzF4WA0xmUtaY_qiz__3zq5AemLgwTsqvsg@mail.gmail.com","subject":"Re: [PATCH v3 0/8] environment: move core config globals into repo_config_values","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-05-11T02:56:24Z","receivedAt":"2026-05-11T02:56:26Z","isPatch":true,"body":"Bello Olamide <belkid98@gmail.com> writes:\n\n> On Sun, 26 Apr 2026 at 01:02, Junio C Hamano <gitster@pobox.com> wrote:\n>>\n>> Olamide Caleb Bello <belkid98@gmail.com> writes:\n>>\n>> > Olamide Caleb Bello (8):\n>> >   environment: move \"trust_ctime\" into `struct repo_config_values`\n>> >   environment: move \"check_stat\" into `struct repo_config_values`\n>> >   environment: move `zlib_compression_level` into `struct\n>> >     repo_config_values`\n>> >   environment: move \"pack_compression_level\" into `struct\n>> >     repo_config_values`\n>> >   environment: move \"precomposed_unicode\" into `struct\n>> >     repo_config_values`\n>> >   env: move \"core_sparse_checkout_cone\" into `struct repo_config_values`\n>> >   env: move \"sparse_expect_files_outside_of_patterns\" into\n>> >     `repo_config_values`\n>> >   env: move \"warn_on_object_refname_ambiguity\" into `struct\n>> >     repo_config_values`\n>>\n>> Are there differences between the ones that start with \"environment:\"\n>> vs the ones with \"env:\"?\n>>\n> Hi Junio,\n>\n> There isn’t any semantic difference intended between\n> the \"environment:\" and \"env:\" prefixes\n>\n> I shortened some of them to stay within the recommended subject length,\n> but on a second thought I agree that consistency is more important here.\n>\n> I’ll standardize them in the next revision.\n\nDoes anybody listed on the CC: in the original submission have any\ncomments on this round?  It seems that v2 iteration was commented on\nquite a bit, but has anybody checked the latest iteration since it\nwas posted?\n\nThanks.\n"},{"id":"543420","messageId":"f4aa8cac-232a-440e-ae12-5e76c799a110@malon.dev","threadId":"65344","inReplyTo":"20260423165432.143598-6-belkid98@gmail.com","subject":"Re: [PATCH v3 5/8] environment: move \"precomposed_unicode\" into `struct repo_config_values`","fromName":"Tian Yuchen","fromEmail":"cat@malon.dev","sentAt":"2026-05-15T17:15:28Z","receivedAt":"2026-05-15T17:15:41Z","isPatch":true,"body":"On 4/24/26 00:54, Olamide Caleb Bello wrote:\n>   struct dirent_prec_psx *precompose_utf8_readdir(PREC_DIR *prec_dir)\n>   {\n> +\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n>   \tstruct dirent *res;\n> +\n>   \tres = readdir(prec_dir->dirp);\n>   \tif (res) {\n>   \t\tsize_t namelenz = strlen(res->d_name) + 1; /* \\0 */\nThis 'precompose_utf8_readdir()' appears to be a wrapper for \n'readdir()', so that Git thinks it is calling a standard POSIX function. \nLooking at it this way, I feel the architectural design here is a bit \nambiguous. I think the role of 'readdir()' (or its wrapper) should be: \n\"You give me a directory handle, and I give you a file entry\". \nConceptually, it shouldn’t even be related to Git: you can take a look \nat the rest of code of this wrapper.\n\nSince there is a wrapper for 'readdir()', there must also be one for \n'opendir()'. To me, initializing a flag like 'perform_precompose' when \nthe PREC_DIR handle is created in 'opendir()' , and pass it down through \nthe handle looks a bit more optimal. In other words, If one of them has \nto handle the repo pointer, I think it would be better to leave that to \n'opendir()' ;)\n\nGood night, yuchen\n"},{"id":"543840","messageId":"08efcc49-0db8-49f6-8971-633aa55eb66c@malon.dev","threadId":"65344","inReplyTo":"20260423165432.143598-2-belkid98@gmail.com","subject":"Re: [PATCH v3 1/8] environment: move \"trust_ctime\" into `struct repo_config_values`","fromName":"Tian Yuchen","fromEmail":"cat@malon.dev","sentAt":"2026-05-21T16:37:29Z","receivedAt":"2026-05-21T16:37:43Z","isPatch":true,"body":"Hi Bello!\n\nOn 4/24/26 00:54, Olamide Caleb Bello wrote:\n\nThe code itself looks great to me, but I have some reservations about \nthe description here (in terms of why trust_ctime is eagerly parsed):\n\n > `core.trustctime` is parsed eagerly\n > because it is used in low‑level stat‑matching functions\n > (`match_stat_data()`), where a lazy parse could cause unexpected\n > fatal errors and complicate libification efforts.\n\nIt's true that if we use repo_config_get_bool() to parse trust_ctime, \nfollowing the call stack downwards, there is a die() call. The terminate \ncondition is that the configuration does not exist or contains invalid \ncharacters.\n\nBut I think there is another factor: match_stat_data() is called on a \nhot path. The following code is implemented in read-cache.c, \nrefresh_index() function:\n\n\tfor (i = 0; i < istate->cache_nr; i++) {\n\t\t...\n\t\tnew_entry = refresh_cache_ent(istate, ce, options,\n\t\t\t\t\t      &cache_errno, &changed,\n\t\t\t\t\t      &t2_did_lstat, &t2_did_scan);\n\t\tt2_sum_lstat += t2_did_lstat;\n\t\tt2_sum_scan += t2_did_scan;\n\t\tif (new_entry == ce)\n\t\t...\n\nThe call chain: refresh_index() -> refresh_cache_ent() -> \nie_match_stat() -> ce_match_stat_basic() -> *match_stat_data()*\n\nTherefore, if the variable is lazily parsed, this means there will be a \nperformance regression whenever the index status needs to be checked, \ne.g. 'git status'.\n\nSo, I guess it would be better to extend a bit:\n\n'...where a lazy parse could cause unexpected fatal, and result in a \nperformance regression...'\n\nThanks, yuchen\n"},{"id":"544391","messageId":"CAD=f0L_zoZebG039APOcgYysjXnJF0TXCMJXT9YE2XT5LwBwTA@mail.gmail.com","threadId":"65344","inReplyTo":"08efcc49-0db8-49f6-8971-633aa55eb66c@malon.dev","subject":"Re: [PATCH v3 1/8] environment: move \"trust_ctime\" into `struct repo_config_values`","fromName":"Bello Olamide","fromEmail":"belkid98@gmail.com","sentAt":"2026-06-01T14:01:35Z","receivedAt":"2026-06-01T14:01:49Z","isPatch":true,"body":"On Thu, May 21, 2026, 5:37 PM Tian Yuchen <cat@malon.dev> wrote:\n>\n> Hi Bello!\n>\n> On 4/24/26 00:54, Olamide Caleb Bello wrote:\n>\n> The code itself looks great to me, but I have some reservations about\n> the description here (in terms of why trust_ctime is eagerly parsed):\n>\n>  > `core.trustctime` is parsed eagerly\n>  > because it is used in low‑level stat‑matching functions\n>  > (`match_stat_data()`), where a lazy parse could cause unexpected\n>  > fatal errors and complicate libification efforts.\n>\n> It's true that if we use repo_config_get_bool() to parse trust_ctime,\n> following the call stack downwards, there is a die() call. The terminate\n> condition is that the configuration does not exist or contains invalid\n> characters.\n>\n> But I think there is another factor: match_stat_data() is called on a\n> hot path. The following code is implemented in read-cache.c,\n> refresh_index() function:\n>\n>         for (i = 0; i < istate->cache_nr; i++) {\n>                 ...\n>                 new_entry = refresh_cache_ent(istate, ce, options,\n>                                               &cache_errno, &changed,\n>                                               &t2_did_lstat, &t2_did_scan);\n>                 t2_sum_lstat += t2_did_lstat;\n>                 t2_sum_scan += t2_did_scan;\n>                 if (new_entry == ce)\n>                 ...\n>\n> The call chain: refresh_index() -> refresh_cache_ent() ->\n> ie_match_stat() -> ce_match_stat_basic() -> *match_stat_data()*\n>\n> Therefore, if the variable is lazily parsed, this means there will be a\n> performance regression whenever the index status needs to be checked,\n> e.g. 'git status'.\n>\n> So, I guess it would be better to extend a bit:\n>\n> '...where a lazy parse could cause unexpected fatal, and result in a\n> performance regression...'\nnoted...\n>\n> Thanks, yuchen\n\nThank you, Yuchen.\n"},{"id":"544403","messageId":"20260601154211.82370-1-belkid98@gmail.com","threadId":"65344","inReplyTo":"20260423160832.114816-1-belkid98@gmail.com","subject":"[PATCH v4 0/8] repo_config_values: migrate more globals","fromName":"Olamide Caleb Bello","fromEmail":"belkid98@gmail.com","sentAt":"2026-06-01T15:42:03Z","receivedAt":"2026-06-01T15:43:48Z","isPatch":true,"body":"Changes since version 3:\n- Reword commit subjects for consistency (changed `env` to `environment`)\n- Updated commit message in (move \"trust_ctime\" into `struct repo_config_values`)\n\nOlamide Caleb Bello (8):\n  environment: move \"trust_ctime\" into `struct repo_config_values`\n  environment: move \"check_stat\" into `struct repo_config_values`\n  environment: move `zlib_compression_level` into `struct\n    repo_config_values`\n  environment: move \"pack_compression_level\" into `struct\n    repo_config_values`\n  environment: move \"precomposed_unicode\" into `struct\n    repo_config_values`\n  environment: move \"core_sparse_checkout_cone\" into `struct\n    repo_config_values`\n  environment: move \"sparse_expect_files_outside_of_patterns\" into\n    `repo_config_values`\n  environment: move \"warn_on_object_refname_ambiguity\" into `struct\n    repo_config_values`\n\n builtin/cat-file.c        |  7 ++++---\n builtin/fast-import.c     |  8 +++++---\n builtin/index-pack.c      |  3 ++-\n builtin/mv.c              |  2 +-\n builtin/pack-objects.c    | 24 +++++++++++++----------\n builtin/sparse-checkout.c | 37 +++++++++++++++++++++---------------\n compat/precompose_utf8.c  | 20 +++++++++++++-------\n diff.c                    |  3 ++-\n dir.c                     |  3 ++-\n entry.c                   |  3 ++-\n environment.c             | 40 +++++++++++++++++++++------------------\n environment.h             | 19 ++++++++++---------\n http-push.c               |  3 ++-\n object-file.c             |  6 ++++--\n object-name.c             |  3 ++-\n revision.c                |  7 ++++---\n sparse-index.c            |  4 ++--\n statinfo.c                | 12 +++++++-----\n submodule.c               |  7 ++++---\n upload-pack.c             |  3 ++-\n 20 files changed, 126 insertions(+), 88 deletions(-)\n\n-- \n2.53.0.155.g9f36b15afa\n\n"},{"id":"544404","messageId":"20260601154211.82370-2-belkid98@gmail.com","threadId":"65344","inReplyTo":"20260601154211.82370-1-belkid98@gmail.com","subject":"[PATCH v4 1/8] environment: move \"trust_ctime\" into `struct repo_config_values`","fromName":"Olamide Caleb Bello","fromEmail":"belkid98@gmail.com","sentAt":"2026-06-01T15:42:04Z","receivedAt":"2026-06-01T15:43:50Z","isPatch":true,"body":"The `core.trustctime` configuration is currently stored in the global\nvariable `trust_ctime`, which makes it shared across repository\ninstances in a single process.\n\nStore it instead in `repo_config_values`, where eagerly‑parsed\nrepository configuration lives. `core.trustctime` is parsed eagerly\nbecause it is used in low‑level stat‑matching functions\n(`match_stat_data()`), where a lazy parse could cause unexpected\nfatal errors, result in a performance regression and complicate\nlibification efforts. This preserves that behavior while tying the\nvalue to the repository from which it was read, avoiding cross‑repository\nstate leakage and continuing the effort to reduce reliance on global\nconfiguration state.\n\nUpdate all references to use repo_config_values().\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nSigned-off-by: Olamide Caleb Bello <belkid98@gmail.com>\n---\n environment.c | 4 ++--\n environment.h | 2 +-\n statinfo.c    | 6 ++++--\n 3 files changed, 7 insertions(+), 5 deletions(-)\n\ndiff --git a/environment.c b/environment.c\nindex fc3ed8bb1c..0a9067729e 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -42,7 +42,6 @@ static int pack_compression_seen;\n static int zlib_compression_seen;\n \n int trust_executable_bit = 1;\n-int trust_ctime = 1;\n int check_stat = 1;\n int has_symlinks = 1;\n int minimum_abbrev = 4, default_abbrev = -1;\n@@ -309,7 +308,7 @@ int git_default_core_config(const char *var, const char *value,\n \t\treturn 0;\n \t}\n \tif (!strcmp(var, \"core.trustctime\")) {\n-\t\ttrust_ctime = git_config_bool(var, value);\n+\t\tcfg->trust_ctime = git_config_bool(var, value);\n \t\treturn 0;\n \t}\n \tif (!strcmp(var, \"core.checkstat\")) {\n@@ -721,4 +720,5 @@ void repo_config_values_init(struct repo_config_values *cfg)\n \tcfg->attributes_file = NULL;\n \tcfg->apply_sparse_checkout = 0;\n \tcfg->branch_track = BRANCH_TRACK_REMOTE;\n+\tcfg->trust_ctime = 1;\n }\ndiff --git a/environment.h b/environment.h\nindex 123a71cdc8..64d537686e 100644\n--- a/environment.h\n+++ b/environment.h\n@@ -91,6 +91,7 @@ struct repo_config_values {\n \t/* section \"core\" config values */\n \tchar *attributes_file;\n \tint apply_sparse_checkout;\n+\tint trust_ctime;\n \n \t/* section \"branch\" config values */\n \tenum branch_track branch_track;\n@@ -161,7 +162,6 @@ extern char *git_work_tree_cfg;\n \n /* Environment bits from configuration mechanism */\n extern int trust_executable_bit;\n-extern int trust_ctime;\n extern int check_stat;\n extern int has_symlinks;\n extern int minimum_abbrev, default_abbrev;\ndiff --git a/statinfo.c b/statinfo.c\nindex 30a164b0e6..4fc12053f4 100644\n--- a/statinfo.c\n+++ b/statinfo.c\n@@ -3,6 +3,7 @@\n #include \"git-compat-util.h\"\n #include \"environment.h\"\n #include \"statinfo.h\"\n+#include \"repository.h\"\n \n /*\n  * Munge st_size into an unsigned int.\n@@ -63,17 +64,18 @@ void fake_lstat_data(const struct stat_data *sd, struct stat *st)\n int match_stat_data(const struct stat_data *sd, struct stat *st)\n {\n \tint changed = 0;\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n \tif (sd->sd_mtime.sec != (unsigned int)st->st_mtime)\n \t\tchanged |= MTIME_CHANGED;\n-\tif (trust_ctime && check_stat &&\n+\tif (cfg->trust_ctime && check_stat &&\n \t    sd->sd_ctime.sec != (unsigned int)st->st_ctime)\n \t\tchanged |= CTIME_CHANGED;\n \n #ifdef USE_NSEC\n \tif (check_stat && sd->sd_mtime.nsec != ST_MTIME_NSEC(*st))\n \t\tchanged |= MTIME_CHANGED;\n-\tif (trust_ctime && check_stat &&\n+\tif (cfg->trust_ctime && check_stat &&\n \t    sd->sd_ctime.nsec != ST_CTIME_NSEC(*st))\n \t\tchanged |= CTIME_CHANGED;\n #endif\n-- \n2.53.0.155.g9f36b15afa\n\n"},{"id":"544405","messageId":"20260601154211.82370-3-belkid98@gmail.com","threadId":"65344","inReplyTo":"20260601154211.82370-1-belkid98@gmail.com","subject":"[PATCH v4 2/8] environment: move \"check_stat\" into `struct repo_config_values`","fromName":"Olamide Caleb Bello","fromEmail":"belkid98@gmail.com","sentAt":"2026-06-01T15:42:05Z","receivedAt":"2026-06-01T15:43:52Z","isPatch":true,"body":"The `core.checkstat` configuration is currently stored in the global\nvariable `check_stat`, which makes it shared across repository\ninstances within a single process.\n\nStore it instead in `repo_config_values`, where eagerly‑parsed\nrepository configuration lives. `core.checkstat` is parsed eagerly\nbecause it controls how `match_stat_data()` and related functions\ndecide file freshness; a lazy parse could lead to unexpected\nbehavior or complicate libification. This preserves the existing\neager‑parsing behavior while tying the value to the repository it\nwas read from, avoiding cross‑repository state leakage, and\ncontinuing the effort to reduce reliance on global configuration\nstate.\n\nUpdate all references to use `repo_config_values()`.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Usman Akinyemi <usmanakinyemi202@gmail.com>\nSigned-off-by: Olamide Caleb Bello <belkid98@gmail.com>\n---\n entry.c       |  3 ++-\n environment.c |  6 +++---\n environment.h |  2 +-\n statinfo.c    | 10 +++++-----\n 4 files changed, 11 insertions(+), 10 deletions(-)\n\ndiff --git a/entry.c b/entry.c\nindex 7817aee362..c55e867d8a 100644\n--- a/entry.c\n+++ b/entry.c\n@@ -443,7 +443,8 @@ static int check_path(const char *path, int len, struct stat *st, int skiplen)\n static void mark_colliding_entries(const struct checkout *state,\n \t\t\t\t   struct cache_entry *ce, struct stat *st)\n {\n-\tint trust_ino = check_stat;\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n+\tint trust_ino = cfg->check_stat;\n \n #if defined(GIT_WINDOWS_NATIVE) || defined(__CYGWIN__)\n \ttrust_ino = 0;\ndiff --git a/environment.c b/environment.c\nindex 0a9067729e..8542ac3141 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -42,7 +42,6 @@ static int pack_compression_seen;\n static int zlib_compression_seen;\n \n int trust_executable_bit = 1;\n-int check_stat = 1;\n int has_symlinks = 1;\n int minimum_abbrev = 4, default_abbrev = -1;\n int ignore_case;\n@@ -315,9 +314,9 @@ int git_default_core_config(const char *var, const char *value,\n \t\tif (!value)\n \t\t\treturn config_error_nonbool(var);\n \t\tif (!strcasecmp(value, \"default\"))\n-\t\t\tcheck_stat = 1;\n+\t\t\tcfg->check_stat = 1;\n \t\telse if (!strcasecmp(value, \"minimal\"))\n-\t\t\tcheck_stat = 0;\n+\t\t\tcfg->check_stat = 0;\n \t\telse\n \t\t\treturn error(_(\"invalid value for '%s': '%s'\"),\n \t\t\t\t     var, value);\n@@ -721,4 +720,5 @@ void repo_config_values_init(struct repo_config_values *cfg)\n \tcfg->apply_sparse_checkout = 0;\n \tcfg->branch_track = BRANCH_TRACK_REMOTE;\n \tcfg->trust_ctime = 1;\n+\tcfg->check_stat = 1;\n }\ndiff --git a/environment.h b/environment.h\nindex 64d537686e..1d3e2e4f23 100644\n--- a/environment.h\n+++ b/environment.h\n@@ -92,6 +92,7 @@ struct repo_config_values {\n \tchar *attributes_file;\n \tint apply_sparse_checkout;\n \tint trust_ctime;\n+\tint check_stat;\n \n \t/* section \"branch\" config values */\n \tenum branch_track branch_track;\n@@ -162,7 +163,6 @@ extern char *git_work_tree_cfg;\n \n /* Environment bits from configuration mechanism */\n extern int trust_executable_bit;\n-extern int check_stat;\n extern int has_symlinks;\n extern int minimum_abbrev, default_abbrev;\n extern int ignore_case;\ndiff --git a/statinfo.c b/statinfo.c\nindex 4fc12053f4..5e00af127d 100644\n--- a/statinfo.c\n+++ b/statinfo.c\n@@ -68,19 +68,19 @@ int match_stat_data(const struct stat_data *sd, struct stat *st)\n \n \tif (sd->sd_mtime.sec != (unsigned int)st->st_mtime)\n \t\tchanged |= MTIME_CHANGED;\n-\tif (cfg->trust_ctime && check_stat &&\n+\tif (cfg->trust_ctime && cfg->check_stat &&\n \t    sd->sd_ctime.sec != (unsigned int)st->st_ctime)\n \t\tchanged |= CTIME_CHANGED;\n \n #ifdef USE_NSEC\n-\tif (check_stat && sd->sd_mtime.nsec != ST_MTIME_NSEC(*st))\n+\tif (cfg->check_stat && sd->sd_mtime.nsec != ST_MTIME_NSEC(*st))\n \t\tchanged |= MTIME_CHANGED;\n-\tif (cfg->trust_ctime && check_stat &&\n+\tif (cfg->trust_ctime && cfg->check_stat &&\n \t    sd->sd_ctime.nsec != ST_CTIME_NSEC(*st))\n \t\tchanged |= CTIME_CHANGED;\n #endif\n \n-\tif (check_stat) {\n+\tif (cfg->check_stat) {\n \t\tif (sd->sd_uid != (unsigned int) st->st_uid ||\n \t\t\tsd->sd_gid != (unsigned int) st->st_gid)\n \t\t\tchanged |= OWNER_CHANGED;\n@@ -94,7 +94,7 @@ int match_stat_data(const struct stat_data *sd, struct stat *st)\n \t * clients will have different views of what \"device\"\n \t * the filesystem is on\n \t */\n-\tif (check_stat && sd->sd_dev != (unsigned int) st->st_dev)\n+\tif (cfg->check_stat && sd->sd_dev != (unsigned int) st->st_dev)\n \t\t\tchanged |= INODE_CHANGED;\n #endif\n \n-- \n2.53.0.155.g9f36b15afa\n\n"},{"id":"544406","messageId":"20260601154211.82370-4-belkid98@gmail.com","threadId":"65344","inReplyTo":"20260601154211.82370-1-belkid98@gmail.com","subject":"[PATCH v4 3/8] environment: move `zlib_compression_level` into `struct repo_config_values`","fromName":"Olamide Caleb Bello","fromEmail":"belkid98@gmail.com","sentAt":"2026-06-01T15:42:06Z","receivedAt":"2026-06-01T15:43:55Z","isPatch":true,"body":"The `zlib_compression_level` configuration is currently stored in the\nglobal variable `zlib_compression_level`, which makes it shared across\nrepository instances within a single process.\n\nStore it instead in `repo_config_values`, where eagerly‑parsed\nrepository configuration lives. `zlib_compression_level` is parsed\neagerly because it determines compression behaviour for objects and\npacks – core operations where a lazy parse could lead to unpredictable\nresults and hinder libification. This preserves the existing\neager‑parsing behavior while tying the value to the repository it\nwas read from, avoiding cross‑repository state leakage and continuing\nthe effort to reduce reliance on global configuration state.\n\nUpdate all references to use `repo_config_values()`.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Usman Akinyemi <usmanakinyemi202@gmail.com>\nSigned-off-by: Olamide Caleb Bello <belkid98@gmail.com>\n---\n builtin/index-pack.c | 3 ++-\n diff.c               | 3 ++-\n environment.c        | 6 +++---\n environment.h        | 2 +-\n http-push.c          | 3 ++-\n object-file.c        | 3 ++-\n 6 files changed, 12 insertions(+), 8 deletions(-)\n\ndiff --git a/builtin/index-pack.c b/builtin/index-pack.c\nindex ca7784dc2c..3942d3e0d0 100644\n--- a/builtin/index-pack.c\n+++ b/builtin/index-pack.c\n@@ -1416,8 +1416,9 @@ static int write_compressed(struct hashfile *f, void *in, unsigned int size)\n \tgit_zstream stream;\n \tint status;\n \tunsigned char outbuf[4096];\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n-\tgit_deflate_init(&stream, zlib_compression_level);\n+\tgit_deflate_init(&stream, cfg->zlib_compression_level);\n \tstream.next_in = in;\n \tstream.avail_in = size;\n \ndiff --git a/diff.c b/diff.c\nindex 397e38b41c..7d17b0bf3f 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -3589,8 +3589,9 @@ static unsigned char *deflate_it(char *data,\n \tint bound;\n \tunsigned char *deflated;\n \tgit_zstream stream;\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n-\tgit_deflate_init(&stream, zlib_compression_level);\n+\tgit_deflate_init(&stream, cfg->zlib_compression_level);\n \tbound = git_deflate_bound(&stream, size);\n \tdeflated = xmalloc(bound);\n \tstream.next_out = deflated;\ndiff --git a/environment.c b/environment.c\nindex 8542ac3141..5b0e88b65c 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -52,7 +52,6 @@ char *git_commit_encoding;\n char *git_log_output_encoding;\n char *apply_default_whitespace;\n char *apply_default_ignorewhitespace;\n-int zlib_compression_level = Z_BEST_SPEED;\n int pack_compression_level = Z_DEFAULT_COMPRESSION;\n int fsync_object_files = -1;\n int use_fsync = -1;\n@@ -377,7 +376,7 @@ int git_default_core_config(const char *var, const char *value,\n \t\t\tlevel = Z_DEFAULT_COMPRESSION;\n \t\telse if (level < 0 || level > Z_BEST_COMPRESSION)\n \t\t\tdie(_(\"bad zlib compression level %d\"), level);\n-\t\tzlib_compression_level = level;\n+\t\tcfg->zlib_compression_level = level;\n \t\tzlib_compression_seen = 1;\n \t\treturn 0;\n \t}\n@@ -389,7 +388,7 @@ int git_default_core_config(const char *var, const char *value,\n \t\telse if (level < 0 || level > Z_BEST_COMPRESSION)\n \t\t\tdie(_(\"bad zlib compression level %d\"), level);\n \t\tif (!zlib_compression_seen)\n-\t\t\tzlib_compression_level = level;\n+\t\t\tcfg->zlib_compression_level = level;\n \t\tif (!pack_compression_seen)\n \t\t\tpack_compression_level = level;\n \t\treturn 0;\n@@ -721,4 +720,5 @@ void repo_config_values_init(struct repo_config_values *cfg)\n \tcfg->branch_track = BRANCH_TRACK_REMOTE;\n \tcfg->trust_ctime = 1;\n \tcfg->check_stat = 1;\n+\tcfg->zlib_compression_level = Z_BEST_SPEED;\n }\ndiff --git a/environment.h b/environment.h\nindex 1d3e2e4f23..93201620af 100644\n--- a/environment.h\n+++ b/environment.h\n@@ -93,6 +93,7 @@ struct repo_config_values {\n \tint apply_sparse_checkout;\n \tint trust_ctime;\n \tint check_stat;\n+\tint zlib_compression_level;\n \n \t/* section \"branch\" config values */\n \tenum branch_track branch_track;\n@@ -170,7 +171,6 @@ extern int assume_unchanged;\n extern int warn_on_object_refname_ambiguity;\n extern char *apply_default_whitespace;\n extern char *apply_default_ignorewhitespace;\n-extern int zlib_compression_level;\n extern int pack_compression_level;\n extern unsigned long pack_size_limit_cfg;\n \ndiff --git a/http-push.c b/http-push.c\nindex d143fe2845..8ac107a56e 100644\n--- a/http-push.c\n+++ b/http-push.c\n@@ -369,13 +369,14 @@ static void start_put(struct transfer_request *request)\n \tint hdrlen;\n \tssize_t size;\n \tgit_zstream stream;\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n \tunpacked = odb_read_object(the_repository->objects, &request->obj->oid,\n \t\t\t\t   &type, &len);\n \thdrlen = format_object_header(hdr, sizeof(hdr), type, len);\n \n \t/* Set it up */\n-\tgit_deflate_init(&stream, zlib_compression_level);\n+\tgit_deflate_init(&stream, cfg->zlib_compression_level);\n \tsize = git_deflate_bound(&stream, len + hdrlen);\n \tstrbuf_grow(&request->buffer.buf, size);\n \trequest->buffer.posn = 0;\ndiff --git a/object-file.c b/object-file.c\nindex 2acc9522df..7c122ac419 100644\n--- a/object-file.c\n+++ b/object-file.c\n@@ -906,6 +906,7 @@ static int start_loose_object_common(struct odb_source *source,\n \tconst struct git_hash_algo *algo = source->odb->repo->hash_algo;\n \tconst struct git_hash_algo *compat = source->odb->repo->compat_hash_algo;\n \tint fd;\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n \tfd = create_tmpfile(source->odb->repo, tmp_file, filename);\n \tif (fd < 0) {\n@@ -921,7 +922,7 @@ static int start_loose_object_common(struct odb_source *source,\n \t}\n \n \t/*  Setup zlib stream for compression */\n-\tgit_deflate_init(stream, zlib_compression_level);\n+\tgit_deflate_init(stream, cfg->zlib_compression_level);\n \tstream->next_out = buf;\n \tstream->avail_out = buflen;\n \talgo->init_fn(c);\n-- \n2.53.0.155.g9f36b15afa\n\n"},{"id":"544407","messageId":"20260601154211.82370-5-belkid98@gmail.com","threadId":"65344","inReplyTo":"20260601154211.82370-1-belkid98@gmail.com","subject":"[PATCH v4 4/8] environment: move \"pack_compression_level\" into `struct repo_config_values`","fromName":"Olamide Caleb Bello","fromEmail":"belkid98@gmail.com","sentAt":"2026-06-01T15:42:07Z","receivedAt":"2026-06-01T15:43:57Z","isPatch":true,"body":"The `pack_compression_level` configuration is currently stored in the\nglobal variable `pack_compression_level`, which makes it shared across\nrepository instances within a single process.\n\nStore it instead in `repo_config_values`, where eagerly‑parsed\nrepository configuration lives. `pack_compression_level` is parsed\neagerly because it influences packfile compression, a core operation\nwhere a lazy parse could cause inconsistent behavior and hamper\nlibification. This preserves the existing eager‑parsing behavior while\ntying the value to the repository from which it was read, avoiding\ncross‑repository state leakage and continuing the effort to reduce\nreliance on global configuration state.\n\nThe type remains `int` as it represents a numeric compression level,\nnot a boolean toggle.\n\nUpdate all references to use `repo_config_values()`.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Usman Akinyemi <usmanakinyemi202@gmail.com>\nSigned-off-by: Olamide Caleb Bello <belkid98@gmail.com>\n---\n builtin/fast-import.c  |  8 +++++---\n builtin/pack-objects.c | 17 ++++++++++-------\n environment.c          |  8 +++++---\n environment.h          |  2 +-\n object-file.c          |  3 ++-\n 5 files changed, 23 insertions(+), 15 deletions(-)\n\ndiff --git a/builtin/fast-import.c b/builtin/fast-import.c\nindex 82bc6dcc00..070a5af3e4 100644\n--- a/builtin/fast-import.c\n+++ b/builtin/fast-import.c\n@@ -965,6 +965,7 @@ static int store_object(\n \tunsigned long hdrlen, deltalen;\n \tstruct git_hash_ctx c;\n \tgit_zstream s;\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n \thdrlen = format_object_header((char *)hdr, sizeof(hdr), type,\n \t\t\t\t      dat->len);\n@@ -1005,7 +1006,7 @@ static int store_object(\n \t} else\n \t\tdelta = NULL;\n \n-\tgit_deflate_init(&s, pack_compression_level);\n+\tgit_deflate_init(&s, cfg->pack_compression_level);\n \tif (delta) {\n \t\ts.next_in = delta;\n \t\ts.avail_in = deltalen;\n@@ -1032,7 +1033,7 @@ static int store_object(\n \t\tif (delta) {\n \t\t\tFREE_AND_NULL(delta);\n \n-\t\t\tgit_deflate_init(&s, pack_compression_level);\n+\t\t\tgit_deflate_init(&s, cfg->pack_compression_level);\n \t\t\ts.next_in = (void *)dat->buf;\n \t\t\ts.avail_in = dat->len;\n \t\t\ts.avail_out = git_deflate_bound(&s, s.avail_in);\n@@ -1115,6 +1116,7 @@ static void stream_blob(uintmax_t len, struct object_id *oidout, uintmax_t mark)\n \tstruct git_hash_ctx c;\n \tgit_zstream s;\n \tstruct hashfile_checkpoint checkpoint;\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \tint status = Z_OK;\n \n \t/* Determine if we should auto-checkpoint. */\n@@ -1134,7 +1136,7 @@ static void stream_blob(uintmax_t len, struct object_id *oidout, uintmax_t mark)\n \n \tcrc32_begin(pack_file);\n \n-\tgit_deflate_init(&s, pack_compression_level);\n+\tgit_deflate_init(&s, cfg->pack_compression_level);\n \n \thdrlen = encode_in_pack_object_header(out_buf, out_sz, OBJ_BLOB, len);\n \ndiff --git a/builtin/pack-objects.c b/builtin/pack-objects.c\nindex dd2480a73d..8ccbe7e178 100644\n--- a/builtin/pack-objects.c\n+++ b/builtin/pack-objects.c\n@@ -386,8 +386,9 @@ static unsigned long do_compress(void **pptr, unsigned long size)\n \tgit_zstream stream;\n \tvoid *in, *out;\n \tunsigned long maxsize;\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n-\tgit_deflate_init(&stream, pack_compression_level);\n+\tgit_deflate_init(&stream, cfg->pack_compression_level);\n \tmaxsize = git_deflate_bound(&stream, size);\n \n \tin = *pptr;\n@@ -413,8 +414,9 @@ static unsigned long write_large_blob_data(struct odb_read_stream *st, struct ha\n \tunsigned char ibuf[1024 * 16];\n \tunsigned char obuf[1024 * 16];\n \tunsigned long olen = 0;\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n-\tgit_deflate_init(&stream, pack_compression_level);\n+\tgit_deflate_init(&stream, cfg->pack_compression_level);\n \n \tfor (;;) {\n \t\tssize_t readlen;\n@@ -5003,6 +5005,7 @@ int cmd_pack_objects(int argc,\n \tstruct string_list keep_pack_list = STRING_LIST_INIT_NODUP;\n \tstruct list_objects_filter_options filter_options =\n \t\tLIST_OBJECTS_FILTER_INIT;\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n \tstruct option pack_objects_options[] = {\n \t\tOPT_CALLBACK_F('q', \"quiet\", &progress, NULL,\n@@ -5084,7 +5087,7 @@ int cmd_pack_objects(int argc,\n \t\t\t N_(\"ignore packs that have companion .keep file\")),\n \t\tOPT_STRING_LIST(0, \"keep-pack\", &keep_pack_list, N_(\"name\"),\n \t\t\t\tN_(\"ignore this pack\")),\n-\t\tOPT_INTEGER(0, \"compression\", &pack_compression_level,\n+\t\tOPT_INTEGER(0, \"compression\", &cfg->pack_compression_level,\n \t\t\t    N_(\"pack compression level\")),\n \t\tOPT_BOOL(0, \"keep-true-parents\", &grafts_keep_true_parents,\n \t\t\t N_(\"do not hide commits by grafts\")),\n@@ -5243,10 +5246,10 @@ int cmd_pack_objects(int argc,\n \n \tif (!reuse_object)\n \t\treuse_delta = 0;\n-\tif (pack_compression_level == -1)\n-\t\tpack_compression_level = Z_DEFAULT_COMPRESSION;\n-\telse if (pack_compression_level < 0 || pack_compression_level > Z_BEST_COMPRESSION)\n-\t\tdie(_(\"bad pack compression level %d\"), pack_compression_level);\n+\tif (cfg->pack_compression_level == -1)\n+\t\tcfg->pack_compression_level = Z_DEFAULT_COMPRESSION;\n+\telse if (cfg->pack_compression_level < 0 || cfg->pack_compression_level > Z_BEST_COMPRESSION)\n+\t\tdie(_(\"bad pack compression level %d\"), cfg->pack_compression_level);\n \n \tif (!delta_search_threads)\t/* --threads=0 means autodetect */\n \t\tdelta_search_threads = online_cpus();\ndiff --git a/environment.c b/environment.c\nindex 5b0e88b65c..d0d3a4b7d2 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -52,7 +52,6 @@ char *git_commit_encoding;\n char *git_log_output_encoding;\n char *apply_default_whitespace;\n char *apply_default_ignorewhitespace;\n-int pack_compression_level = Z_DEFAULT_COMPRESSION;\n int fsync_object_files = -1;\n int use_fsync = -1;\n enum fsync_method fsync_method = FSYNC_METHOD_DEFAULT;\n@@ -390,7 +389,7 @@ int git_default_core_config(const char *var, const char *value,\n \t\tif (!zlib_compression_seen)\n \t\t\tcfg->zlib_compression_level = level;\n \t\tif (!pack_compression_seen)\n-\t\t\tpack_compression_level = level;\n+\t\t\tcfg->pack_compression_level = level;\n \t\treturn 0;\n \t}\n \n@@ -662,6 +661,8 @@ static int git_default_attr_config(const char *var, const char *value)\n int git_default_config(const char *var, const char *value,\n \t\t       const struct config_context *ctx, void *cb)\n {\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n+\n \tif (starts_with(var, \"core.\"))\n \t\treturn git_default_core_config(var, value, ctx, cb);\n \n@@ -701,7 +702,7 @@ int git_default_config(const char *var, const char *value,\n \t\t\tlevel = Z_DEFAULT_COMPRESSION;\n \t\telse if (level < 0 || level > Z_BEST_COMPRESSION)\n \t\t\tdie(_(\"bad pack compression level %d\"), level);\n-\t\tpack_compression_level = level;\n+\t\tcfg->pack_compression_level = level;\n \t\tpack_compression_seen = 1;\n \t\treturn 0;\n \t}\n@@ -721,4 +722,5 @@ void repo_config_values_init(struct repo_config_values *cfg)\n \tcfg->trust_ctime = 1;\n \tcfg->check_stat = 1;\n \tcfg->zlib_compression_level = Z_BEST_SPEED;\n+\tcfg->pack_compression_level = Z_DEFAULT_COMPRESSION;\n }\ndiff --git a/environment.h b/environment.h\nindex 93201620af..514576b67a 100644\n--- a/environment.h\n+++ b/environment.h\n@@ -94,6 +94,7 @@ struct repo_config_values {\n \tint trust_ctime;\n \tint check_stat;\n \tint zlib_compression_level;\n+\tint pack_compression_level;\n \n \t/* section \"branch\" config values */\n \tenum branch_track branch_track;\n@@ -171,7 +172,6 @@ extern int assume_unchanged;\n extern int warn_on_object_refname_ambiguity;\n extern char *apply_default_whitespace;\n extern char *apply_default_ignorewhitespace;\n-extern int pack_compression_level;\n extern unsigned long pack_size_limit_cfg;\n \n extern int precomposed_unicode;\ndiff --git a/object-file.c b/object-file.c\nindex 7c122ac419..37def5cc59 100644\n--- a/object-file.c\n+++ b/object-file.c\n@@ -1437,8 +1437,9 @@ static int stream_blob_to_pack(struct transaction_packfile *state,\n \tint status = Z_OK;\n \tint write_object = (flags & INDEX_WRITE_OBJECT);\n \toff_t offset = 0;\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n-\tgit_deflate_init(&s, pack_compression_level);\n+\tgit_deflate_init(&s, cfg->pack_compression_level);\n \n \thdrlen = encode_in_pack_object_header(obuf, sizeof(obuf), OBJ_BLOB, size);\n \ts.next_out = obuf + hdrlen;\n-- \n2.53.0.155.g9f36b15afa\n\n"},{"id":"544408","messageId":"20260601154211.82370-6-belkid98@gmail.com","threadId":"65344","inReplyTo":"20260601154211.82370-1-belkid98@gmail.com","subject":"[PATCH v4 5/8] environment: move \"precomposed_unicode\" into `struct repo_config_values`","fromName":"Olamide Caleb Bello","fromEmail":"belkid98@gmail.com","sentAt":"2026-06-01T15:42:08Z","receivedAt":"2026-06-01T15:43:59Z","isPatch":true,"body":"The `core.precomposeunicode` configuration is currently stored in the\nglobal variable `precomposed_unicode`, which makes it shared across\nrepository instances within a single process.\n\nStore it instead in `repo_config_values`, where eagerly‑parsed\nrepository configuration lives. `core.precomposeunicode` is parsed\neagerly because it controls Unicode path normalization on macOS,\na fundamental filesystem‑level behavior that many operations depend\non; a lazy parse could lead to inconsistent results and hamper\nlibification. This preserves the existing behavior while tying the\nvalue to the repository from which it was read, avoiding cross‑\nrepository state leakage and continuing the effort to reduce reliance\non global configuration state.\n\nChange the type of the field from `int` to `bool` since it is parsed\nas a boolean value.\n\nUpdate all references to use `repo_config_values()`.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Usman Akinyemi <usmanakinyemi202@gmail.com>\nSigned-off-by: Olamide Caleb Bello <belkid98@gmail.com>\n---\n compat/precompose_utf8.c | 20 +++++++++++++-------\n environment.c            |  4 ++--\n environment.h            |  2 +-\n upload-pack.c            |  3 ++-\n 4 files changed, 18 insertions(+), 11 deletions(-)\n\ndiff --git a/compat/precompose_utf8.c b/compat/precompose_utf8.c\nindex 43b3be0114..0e94dbd862 100644\n--- a/compat/precompose_utf8.c\n+++ b/compat/precompose_utf8.c\n@@ -48,16 +48,18 @@ void probe_utf8_pathname_composition(void)\n \tstatic const char *auml_nfc = \"\\xc3\\xa4\";\n \tstatic const char *auml_nfd = \"\\x61\\xcc\\x88\";\n \tint output_fd;\n-\tif (precomposed_unicode != -1)\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n+\n+\tif (cfg->precomposed_unicode != -1)\n \t\treturn; /* We found it defined in the global config, respect it */\n \trepo_git_path_replace(the_repository, &path, \"%s\", auml_nfc);\n \toutput_fd = open(path.buf, O_CREAT|O_EXCL|O_RDWR, 0600);\n \tif (output_fd >= 0) {\n \t\tclose(output_fd);\n \t\trepo_git_path_replace(the_repository, &path, \"%s\", auml_nfd);\n-\t\tprecomposed_unicode = access(path.buf, R_OK) ? 0 : 1;\n+\t\tcfg->precomposed_unicode = access(path.buf, R_OK) ? 0 : 1;\n \t\trepo_config_set(the_repository, \"core.precomposeunicode\",\n-\t\t\t\tprecomposed_unicode ? \"true\" : \"false\");\n+\t\t\t\tcfg->precomposed_unicode ? \"true\" : \"false\");\n \t\trepo_git_path_replace(the_repository, &path, \"%s\", auml_nfc);\n \t\tif (unlink(path.buf))\n \t\t\tdie_errno(_(\"failed to unlink '%s'\"), path.buf);\n@@ -69,14 +71,16 @@ const char *precompose_string_if_needed(const char *in)\n {\n \tsize_t inlen;\n \tsize_t outlen;\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n+\n \tif (!in)\n \t\treturn NULL;\n \tif (has_non_ascii(in, (size_t)-1, &inlen)) {\n \t\ticonv_t ic_prec;\n \t\tchar *out;\n-\t\tif (precomposed_unicode < 0)\n-\t\t\trepo_config_get_bool(the_repository, \"core.precomposeunicode\", &precomposed_unicode);\n-\t\tif (precomposed_unicode != 1)\n+\t\tif (cfg->precomposed_unicode < 0)\n+\t\t\trepo_config_get_bool(the_repository, \"core.precomposeunicode\", &cfg->precomposed_unicode);\n+\t\tif (cfg->precomposed_unicode != 1)\n \t\t\treturn in;\n \t\tic_prec = iconv_open(repo_encoding, path_encoding);\n \t\tif (ic_prec == (iconv_t) -1)\n@@ -130,7 +134,9 @@ PREC_DIR *precompose_utf8_opendir(const char *dirname)\n \n struct dirent_prec_psx *precompose_utf8_readdir(PREC_DIR *prec_dir)\n {\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \tstruct dirent *res;\n+\n \tres = readdir(prec_dir->dirp);\n \tif (res) {\n \t\tsize_t namelenz = strlen(res->d_name) + 1; /* \\0 */\n@@ -149,7 +155,7 @@ struct dirent_prec_psx *precompose_utf8_readdir(PREC_DIR *prec_dir)\n \t\tprec_dir->dirent_nfc->d_ino  = res->d_ino;\n \t\tprec_dir->dirent_nfc->d_type = res->d_type;\n \n-\t\tif ((precomposed_unicode == 1) && has_non_ascii(res->d_name, (size_t)-1, NULL)) {\n+\t\tif ((cfg->precomposed_unicode == 1) && has_non_ascii(res->d_name, (size_t)-1, NULL)) {\n \t\t\tif (prec_dir->ic_precompose == (iconv_t)-1) {\n \t\t\t\tdie(\"iconv_open(%s,%s) failed, but needed:\\n\"\n \t\t\t\t\t\t\"    precomposed unicode is not supported.\\n\"\ndiff --git a/environment.c b/environment.c\nindex d0d3a4b7d2..739b647ebe 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -72,7 +72,6 @@ enum object_creation_mode object_creation_mode = OBJECT_CREATION_MODE;\n int grafts_keep_true_parents;\n int core_sparse_checkout_cone;\n int sparse_expect_files_outside_of_patterns;\n-int precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */\n unsigned long pack_size_limit_cfg;\n \n #ifndef PROTECT_HFS_DEFAULT\n@@ -532,7 +531,7 @@ int git_default_core_config(const char *var, const char *value,\n \t}\n \n \tif (!strcmp(var, \"core.precomposeunicode\")) {\n-\t\tprecomposed_unicode = git_config_bool(var, value);\n+\t\tcfg->precomposed_unicode = git_config_bool(var, value);\n \t\treturn 0;\n \t}\n \n@@ -723,4 +722,5 @@ void repo_config_values_init(struct repo_config_values *cfg)\n \tcfg->check_stat = 1;\n \tcfg->zlib_compression_level = Z_BEST_SPEED;\n \tcfg->pack_compression_level = Z_DEFAULT_COMPRESSION;\n+\tcfg->precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */\n }\ndiff --git a/environment.h b/environment.h\nindex 514576b67a..508cb1afbc 100644\n--- a/environment.h\n+++ b/environment.h\n@@ -95,6 +95,7 @@ struct repo_config_values {\n \tint check_stat;\n \tint zlib_compression_level;\n \tint pack_compression_level;\n+\tint precomposed_unicode;\n \n \t/* section \"branch\" config values */\n \tenum branch_track branch_track;\n@@ -174,7 +175,6 @@ extern char *apply_default_whitespace;\n extern char *apply_default_ignorewhitespace;\n extern unsigned long pack_size_limit_cfg;\n \n-extern int precomposed_unicode;\n extern int protect_hfs;\n extern int protect_ntfs;\n \ndiff --git a/upload-pack.c b/upload-pack.c\nindex 9f6d6fe48c..3a52237134 100644\n--- a/upload-pack.c\n+++ b/upload-pack.c\n@@ -1336,6 +1336,7 @@ static int upload_pack_config(const char *var, const char *value,\n \t\t\t      void *cb_data)\n {\n \tstruct upload_pack_data *data = cb_data;\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n \tif (!strcmp(\"uploadpack.allowtipsha1inwant\", var)) {\n \t\tif (git_config_bool(var, value))\n@@ -1366,7 +1367,7 @@ static int upload_pack_config(const char *var, const char *value,\n \t\tif (value)\n \t\t\tdata->allow_packfile_uris = 1;\n \t} else if (!strcmp(\"core.precomposeunicode\", var)) {\n-\t\tprecomposed_unicode = git_config_bool(var, value);\n+\t\tcfg->precomposed_unicode = git_config_bool(var, value);\n \t} else if (!strcmp(\"transfer.advertisesid\", var)) {\n \t\tdata->advertise_sid = git_config_bool(var, value);\n \t}\n-- \n2.53.0.155.g9f36b15afa\n\n"},{"id":"544409","messageId":"20260601154211.82370-7-belkid98@gmail.com","threadId":"65344","inReplyTo":"20260601154211.82370-1-belkid98@gmail.com","subject":"[PATCH v4 6/8] environment: move \"core_sparse_checkout_cone\" into `struct repo_config_values`","fromName":"Olamide Caleb Bello","fromEmail":"belkid98@gmail.com","sentAt":"2026-06-01T15:42:09Z","receivedAt":"2026-06-01T15:44:02Z","isPatch":true,"body":"The `core.sparseCheckoutCone` configuration was previously stored in an\nuninitialized global `int` variable, risking cross‑repository state\nleakage.\n\nMove it into `repo_config_values`, where eagerly‑parsed repository\nconfiguration lives. `core.sparseCheckoutCone` is parsed eagerly\nbecause it determines the fundamental sparse‑checkout mode and is\nconsulted very early during repository setup; a lazy parse could\nleave the sparse‑checkout state undefined and complicate\nlibification. This preserves the existing behavior while tying the\nvalue to the repository from which it was read, avoiding cross‑\nrepository state leakage and continuing the effort to reduce reliance\non global configuration state.\n\nUpdate all references to use `repo_config_values()`.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Usman Akinyemi <usmanakinyemi202@gmail.com>\nSigned-off-by: Olamide Caleb Bello <belkid98@gmail.com>\n---\n builtin/mv.c              |  2 +-\n builtin/sparse-checkout.c | 37 ++++++++++++++++++++++---------------\n dir.c                     |  3 ++-\n environment.c             |  4 ++--\n environment.h             |  2 +-\n sparse-index.c            |  2 +-\n 6 files changed, 29 insertions(+), 21 deletions(-)\n\ndiff --git a/builtin/mv.c b/builtin/mv.c\nindex 2215d34e31..ef3a326c90 100644\n--- a/builtin/mv.c\n+++ b/builtin/mv.c\n@@ -574,7 +574,7 @@ int cmd_mv(int argc,\n \n \t\tif (ignore_sparse &&\n \t\t    cfg->apply_sparse_checkout &&\n-\t\t    core_sparse_checkout_cone) {\n+\t\t    cfg->core_sparse_checkout_cone) {\n \t\t\t/*\n \t\t\t * NEEDSWORK: we are *not* paying attention to\n \t\t\t * \"out-to-out\" move (<source> is out-of-cone and\ndiff --git a/builtin/sparse-checkout.c b/builtin/sparse-checkout.c\nindex f4aa405da9..92d017b81f 100644\n--- a/builtin/sparse-checkout.c\n+++ b/builtin/sparse-checkout.c\n@@ -73,7 +73,7 @@ static int sparse_checkout_list(int argc, const char **argv, const char *prefix,\n \n \tmemset(&pl, 0, sizeof(pl));\n \n-\tpl.use_cone_patterns = core_sparse_checkout_cone;\n+\tpl.use_cone_patterns = cfg->core_sparse_checkout_cone;\n \n \tsparse_filename = get_sparse_checkout_filename();\n \tres = add_patterns_from_file_to_list(sparse_filename, \"\", 0, &pl, NULL, 0);\n@@ -334,6 +334,7 @@ static int write_patterns_and_update(struct repository *repo,\n \tFILE *fp;\n \tstruct lock_file lk = LOCK_INIT;\n \tint result;\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n \tsparse_filename = get_sparse_checkout_filename();\n \n@@ -353,7 +354,7 @@ static int write_patterns_and_update(struct repository *repo,\n \tif (!fp)\n \t\tdie_errno(_(\"unable to fdopen %s\"), get_lock_file_path(&lk));\n \n-\tif (core_sparse_checkout_cone)\n+\tif (cfg->core_sparse_checkout_cone)\n \t\twrite_cone_to_file(fp, pl);\n \telse\n \t\twrite_patterns_to_file(fp, pl);\n@@ -402,15 +403,15 @@ static enum sparse_checkout_mode update_cone_mode(int *cone_mode) {\n \n \t/* If not specified, use previous definition of cone mode */\n \tif (*cone_mode == -1 && cfg->apply_sparse_checkout)\n-\t\t*cone_mode = core_sparse_checkout_cone;\n+\t\t*cone_mode = cfg->core_sparse_checkout_cone;\n \n \t/* Set cone/non-cone mode appropriately */\n \tcfg->apply_sparse_checkout = 1;\n \tif (*cone_mode == 1 || *cone_mode == -1) {\n-\t\tcore_sparse_checkout_cone = 1;\n+\t\tcfg->core_sparse_checkout_cone = 1;\n \t\treturn MODE_CONE_PATTERNS;\n \t}\n-\tcore_sparse_checkout_cone = 0;\n+\tcfg->core_sparse_checkout_cone = 0;\n \treturn MODE_ALL_PATTERNS;\n }\n \n@@ -577,7 +578,9 @@ static void add_patterns_from_input(struct pattern_list *pl,\n \t\t\t\t    FILE *file)\n {\n \tint i;\n-\tif (core_sparse_checkout_cone) {\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n+\n+\tif (cfg->core_sparse_checkout_cone) {\n \t\tstruct strbuf line = STRBUF_INIT;\n \n \t\thashmap_init(&pl->recursive_hashmap, pl_hashmap_cmp, NULL, 0);\n@@ -636,13 +639,14 @@ static void add_patterns_cone_mode(int argc, const char **argv,\n \tstruct pattern_entry *pe;\n \tstruct hashmap_iter iter;\n \tstruct pattern_list existing;\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \tchar *sparse_filename = get_sparse_checkout_filename();\n \n \tadd_patterns_from_input(pl, argc, argv,\n \t\t\t\tuse_stdin ? stdin : NULL);\n \n \tmemset(&existing, 0, sizeof(existing));\n-\texisting.use_cone_patterns = core_sparse_checkout_cone;\n+\texisting.use_cone_patterns = cfg->core_sparse_checkout_cone;\n \n \tif (add_patterns_from_file_to_list(sparse_filename, \"\", 0,\n \t\t\t\t\t   &existing, NULL, 0))\n@@ -690,7 +694,7 @@ static int modify_pattern_list(struct repository *repo,\n \n \tswitch (m) {\n \tcase ADD:\n-\t\tif (core_sparse_checkout_cone)\n+\t\tif (cfg->core_sparse_checkout_cone)\n \t\t\tadd_patterns_cone_mode(args->nr, args->v, pl, use_stdin);\n \t\telse\n \t\t\tadd_patterns_literal(args->nr, args->v, pl, use_stdin);\n@@ -723,11 +727,12 @@ static void sanitize_paths(struct repository *repo,\n \t\t\t   const char *prefix, int skip_checks)\n {\n \tint i;\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n \tif (!args->nr)\n \t\treturn;\n \n-\tif (prefix && *prefix && core_sparse_checkout_cone) {\n+\tif (prefix && *prefix && cfg->core_sparse_checkout_cone) {\n \t\t/*\n \t\t * The args are not pathspecs, so unfortunately we\n \t\t * cannot imitate how cmd_add() uses parse_pathspec().\n@@ -744,10 +749,10 @@ static void sanitize_paths(struct repository *repo,\n \tif (skip_checks)\n \t\treturn;\n \n-\tif (prefix && *prefix && !core_sparse_checkout_cone)\n+\tif (prefix && *prefix && !cfg->core_sparse_checkout_cone)\n \t\tdie(_(\"please run from the toplevel directory in non-cone mode\"));\n \n-\tif (core_sparse_checkout_cone) {\n+\tif (cfg->core_sparse_checkout_cone) {\n \t\tfor (i = 0; i < args->nr; i++) {\n \t\t\tif (args->v[i][0] == '/')\n \t\t\t\tdie(_(\"specify directories rather than patterns (no leading slash)\"));\n@@ -769,7 +774,7 @@ static void sanitize_paths(struct repository *repo,\n \t\tif (S_ISSPARSEDIR(ce->ce_mode))\n \t\t\tcontinue;\n \n-\t\tif (core_sparse_checkout_cone)\n+\t\tif (cfg->core_sparse_checkout_cone)\n \t\t\tdie(_(\"'%s' is not a directory; to treat it as a directory anyway, rerun with --skip-checks\"), args->v[i]);\n \t\telse\n \t\t\twarning(_(\"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]);\n@@ -836,6 +841,7 @@ static struct sparse_checkout_set_opts {\n static int sparse_checkout_set(int argc, const char **argv, const char *prefix,\n \t\t\t       struct repository *repo)\n {\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \tint default_patterns_nr = 2;\n \tconst char *default_patterns[] = {\"/*\", \"!/*/\", NULL};\n \n@@ -873,7 +879,7 @@ static int sparse_checkout_set(int argc, const char **argv, const char *prefix,\n \t * non-cone mode, if nothing is specified, manually select just the\n \t * top-level directory (much as 'init' would do).\n \t */\n-\tif (!core_sparse_checkout_cone && !set_opts.use_stdin && argc == 0) {\n+\tif (!cfg->core_sparse_checkout_cone && !set_opts.use_stdin && argc == 0) {\n \t\tfor (int i = 0; i < default_patterns_nr; i++)\n \t\t\tstrvec_push(&patterns, default_patterns[i]);\n \t} else {\n@@ -977,7 +983,7 @@ static int sparse_checkout_clean(int argc, const char **argv,\n \tsetup_work_tree();\n \tif (!cfg->apply_sparse_checkout)\n \t\tdie(_(\"must be in a sparse-checkout to clean directories\"));\n-\tif (!core_sparse_checkout_cone)\n+\tif (!cfg->core_sparse_checkout_cone)\n \t\tdie(_(\"must be in a cone-mode sparse-checkout to clean directories\"));\n \n \targc = parse_options(argc, argv, prefix,\n@@ -1141,6 +1147,7 @@ static int sparse_checkout_check_rules(int argc, const char **argv, const char *\n \tFILE *fp;\n \tint ret;\n \tstruct pattern_list pl = {0};\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \tchar *sparse_filename;\n \tcheck_rules_opts.cone_mode = -1;\n \n@@ -1152,7 +1159,7 @@ static int sparse_checkout_check_rules(int argc, const char **argv, const char *\n \t\tcheck_rules_opts.cone_mode = 1;\n \n \tupdate_cone_mode(&check_rules_opts.cone_mode);\n-\tpl.use_cone_patterns = core_sparse_checkout_cone;\n+\tpl.use_cone_patterns = cfg->core_sparse_checkout_cone;\n \tif (check_rules_opts.rules_file) {\n \t\tfp = xfopen(check_rules_opts.rules_file, \"r\");\n \t\tadd_patterns_from_input(&pl, argc, argv, fp);\ndiff --git a/dir.c b/dir.c\nindex fcb8f6dd2a..4f493b64c6 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -3508,8 +3508,9 @@ int get_sparse_checkout_patterns(struct pattern_list *pl)\n {\n \tint res;\n \tchar *sparse_filename = get_sparse_checkout_filename();\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n-\tpl->use_cone_patterns = core_sparse_checkout_cone;\n+\tpl->use_cone_patterns = cfg->core_sparse_checkout_cone;\n \tres = add_patterns_from_file_to_list(sparse_filename, \"\", 0, pl, NULL, 0);\n \n \tfree(sparse_filename);\ndiff --git a/environment.c b/environment.c\nindex 739b647ebe..b0e873e9f5 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -70,7 +70,6 @@ enum push_default_type push_default = PUSH_DEFAULT_UNSPECIFIED;\n #endif\n enum object_creation_mode object_creation_mode = OBJECT_CREATION_MODE;\n int grafts_keep_true_parents;\n-int core_sparse_checkout_cone;\n int sparse_expect_files_outside_of_patterns;\n unsigned long pack_size_limit_cfg;\n \n@@ -526,7 +525,7 @@ int git_default_core_config(const char *var, const char *value,\n \t}\n \n \tif (!strcmp(var, \"core.sparsecheckoutcone\")) {\n-\t\tcore_sparse_checkout_cone = git_config_bool(var, value);\n+\t\tcfg->core_sparse_checkout_cone = git_config_bool(var, value);\n \t\treturn 0;\n \t}\n \n@@ -723,4 +722,5 @@ void repo_config_values_init(struct repo_config_values *cfg)\n \tcfg->zlib_compression_level = Z_BEST_SPEED;\n \tcfg->pack_compression_level = Z_DEFAULT_COMPRESSION;\n \tcfg->precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */\n+\tcfg->core_sparse_checkout_cone = 0;\n }\ndiff --git a/environment.h b/environment.h\nindex 508cb1afbc..befad9a388 100644\n--- a/environment.h\n+++ b/environment.h\n@@ -96,6 +96,7 @@ struct repo_config_values {\n \tint zlib_compression_level;\n \tint pack_compression_level;\n \tint precomposed_unicode;\n+\tint core_sparse_checkout_cone;\n \n \t/* section \"branch\" config values */\n \tenum branch_track branch_track;\n@@ -178,7 +179,6 @@ extern unsigned long pack_size_limit_cfg;\n extern int protect_hfs;\n extern int protect_ntfs;\n \n-extern int core_sparse_checkout_cone;\n extern int sparse_expect_files_outside_of_patterns;\n \n enum rebase_setup_type {\ndiff --git a/sparse-index.c b/sparse-index.c\nindex 13629c075d..53cb8d64fc 100644\n--- a/sparse-index.c\n+++ b/sparse-index.c\n@@ -154,7 +154,7 @@ int is_sparse_index_allowed(struct index_state *istate, int flags)\n {\n \tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n-\tif (!cfg->apply_sparse_checkout || !core_sparse_checkout_cone)\n+\tif (!cfg->apply_sparse_checkout || !cfg->core_sparse_checkout_cone)\n \t\treturn 0;\n \n \tif (!(flags & SPARSE_INDEX_MEMORY_ONLY)) {\n-- \n2.53.0.155.g9f36b15afa\n\n"},{"id":"544410","messageId":"20260601154211.82370-8-belkid98@gmail.com","threadId":"65344","inReplyTo":"20260601154211.82370-1-belkid98@gmail.com","subject":"[PATCH v4 7/8] environment: move \"sparse_expect_files_outside_of_patterns\" into `repo_config_values`","fromName":"Olamide Caleb Bello","fromEmail":"belkid98@gmail.com","sentAt":"2026-06-01T15:42:10Z","receivedAt":"2026-06-01T15:44:04Z","isPatch":true,"body":"The `core.sparseCheckoutExpectFilesOutsideOfPatterns` configuration was\npreviously stored in a global `int` variable, making it shared across\nrepository instances and risking cross‑repository state leakage.\n\nStore it instead in `repo_config_values`, where eagerly‑parsed\nrepository configuration lives. This option is parsed eagerly because\nit controls how sparse‑checkout paths are interpreted – a fundamental\nbehavior that many commands rely on; a lazy parse could cause\ninconsistent sparse‑checkout handling and complicate libification.\nThis preserves the existing behavior while tying the value to the\nrepository from which it was read, avoiding cross‑repository state\nleakage and continuing the effort to reduce reliance on global\nconfiguration state.\n\nUpdate all references to use `repo_config_values()`.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Usman Akinyemi <usmanakinyemi202@gmail.com>\nSigned-off-by: Olamide Caleb Bello <belkid98@gmail.com>\n---\n environment.c  | 6 ++++--\n environment.h  | 5 +++--\n sparse-index.c | 2 +-\n 3 files changed, 8 insertions(+), 5 deletions(-)\n\ndiff --git a/environment.c b/environment.c\nindex b0e873e9f5..57587ede56 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -70,7 +70,6 @@ enum push_default_type push_default = PUSH_DEFAULT_UNSPECIFIED;\n #endif\n enum object_creation_mode object_creation_mode = OBJECT_CREATION_MODE;\n int grafts_keep_true_parents;\n-int sparse_expect_files_outside_of_patterns;\n unsigned long pack_size_limit_cfg;\n \n #ifndef PROTECT_HFS_DEFAULT\n@@ -550,8 +549,10 @@ int git_default_core_config(const char *var, const char *value,\n \n static int git_default_sparse_config(const char *var, const char *value)\n {\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n+\n \tif (!strcmp(var, \"sparse.expectfilesoutsideofpatterns\")) {\n-\t\tsparse_expect_files_outside_of_patterns = git_config_bool(var, value);\n+\t\tcfg->sparse_expect_files_outside_of_patterns = git_config_bool(var, value);\n \t\treturn 0;\n \t}\n \n@@ -723,4 +724,5 @@ void repo_config_values_init(struct repo_config_values *cfg)\n \tcfg->pack_compression_level = Z_DEFAULT_COMPRESSION;\n \tcfg->precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */\n \tcfg->core_sparse_checkout_cone = 0;\n+\tcfg->sparse_expect_files_outside_of_patterns = 0;\n }\ndiff --git a/environment.h b/environment.h\nindex befad9a388..609cdaa07f 100644\n--- a/environment.h\n+++ b/environment.h\n@@ -98,6 +98,9 @@ struct repo_config_values {\n \tint precomposed_unicode;\n \tint core_sparse_checkout_cone;\n \n+\t/* section \"sparse\" config values */\n+\tint sparse_expect_files_outside_of_patterns;\n+\n \t/* section \"branch\" config values */\n \tenum branch_track branch_track;\n };\n@@ -179,8 +182,6 @@ extern unsigned long pack_size_limit_cfg;\n extern int protect_hfs;\n extern int protect_ntfs;\n \n-extern int sparse_expect_files_outside_of_patterns;\n-\n enum rebase_setup_type {\n \tAUTOREBASE_NEVER = 0,\n \tAUTOREBASE_LOCAL,\ndiff --git a/sparse-index.c b/sparse-index.c\nindex 53cb8d64fc..1ed769b78d 100644\n--- a/sparse-index.c\n+++ b/sparse-index.c\n@@ -675,7 +675,7 @@ void clear_skip_worktree_from_present_files(struct index_state *istate)\n \tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n \tif (!cfg->apply_sparse_checkout ||\n-\t    sparse_expect_files_outside_of_patterns)\n+\t    cfg->sparse_expect_files_outside_of_patterns)\n \t\treturn;\n \n \tif (clear_skip_worktree_from_present_files_sparse(istate)) {\n-- \n2.53.0.155.g9f36b15afa\n\n"},{"id":"544411","messageId":"20260601154211.82370-9-belkid98@gmail.com","threadId":"65344","inReplyTo":"20260601154211.82370-1-belkid98@gmail.com","subject":"[PATCH v4 8/8] environment: move \"warn_on_object_refname_ambiguity\" into `struct repo_config_values`","fromName":"Olamide Caleb Bello","fromEmail":"belkid98@gmail.com","sentAt":"2026-06-01T15:42:11Z","receivedAt":"2026-06-01T15:44:06Z","isPatch":true,"body":"The `core.warnAmbiguousRefs` configuration was previously stored in a\nglobal `int` variable, making it shared across repository instances\nand risking cross‑repository state leakage.\n\nStore it instead in `repo_config_values`, where eagerly‑parsed\nrepository configuration lives. This option is parsed eagerly because\nambiguity warnings influence how users interpret object references in\nmany commands; a lazy parse could cause these warnings to behave\ninconsistently or to appear for the wrong repository, confusing users\nand hindering libification. This preserves the existing behavior while\ntying the value to the repository from which it was read, avoiding\ncross‑repository state leakage and continuing the effort to reduce\nreliance on global configuration state.\n\nUpdate all references to use `repo_config_values()`.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Usman Akinyemi <usmanakinyemi202@gmail.com>\nSigned-off-by: Olamide Caleb Bello <belkid98@gmail.com>\n---\n builtin/cat-file.c     | 7 ++++---\n builtin/pack-objects.c | 7 ++++---\n environment.c          | 2 +-\n environment.h          | 2 +-\n object-name.c          | 3 ++-\n revision.c             | 7 ++++---\n submodule.c            | 7 ++++---\n 7 files changed, 20 insertions(+), 15 deletions(-)\n\ndiff --git a/builtin/cat-file.c b/builtin/cat-file.c\nindex d9fbad5358..cfc5430186 100644\n--- a/builtin/cat-file.c\n+++ b/builtin/cat-file.c\n@@ -901,6 +901,7 @@ static int batch_objects(struct batch_options *opt)\n \tstruct strbuf input = STRBUF_INIT;\n \tstruct strbuf output = STRBUF_INIT;\n \tstruct expand_data data = EXPAND_DATA_INIT;\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \tint save_warning;\n \tint retval = 0;\n \n@@ -973,8 +974,8 @@ static int batch_objects(struct batch_options *opt)\n \t * warn) ends up dwarfing the actual cost of the object lookups\n \t * themselves. We can work around it by just turning off the warning.\n \t */\n-\tsave_warning = warn_on_object_refname_ambiguity;\n-\twarn_on_object_refname_ambiguity = 0;\n+\tsave_warning = cfg->warn_on_object_refname_ambiguity;\n+\tcfg->warn_on_object_refname_ambiguity = 0;\n \n \tif (opt->batch_mode == BATCH_MODE_QUEUE_AND_DISPATCH) {\n \t\tbatch_objects_command(opt, &output, &data);\n@@ -1002,7 +1003,7 @@ static int batch_objects(struct batch_options *opt)\n  cleanup:\n \tstrbuf_release(&input);\n \tstrbuf_release(&output);\n-\twarn_on_object_refname_ambiguity = save_warning;\n+\tcfg->warn_on_object_refname_ambiguity = save_warning;\n \treturn retval;\n }\n \ndiff --git a/builtin/pack-objects.c b/builtin/pack-objects.c\nindex 8ccbe7e178..7df75fe91e 100644\n--- a/builtin/pack-objects.c\n+++ b/builtin/pack-objects.c\n@@ -4788,6 +4788,7 @@ static void get_object_list(struct rev_info *revs, struct strvec *argv)\n \tstruct setup_revision_opt s_r_opt = {\n \t\t.allow_exclude_promisor_objects = 1,\n \t};\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \tchar line[1000];\n \tint flags = 0;\n \tint save_warning;\n@@ -4798,8 +4799,8 @@ static void get_object_list(struct rev_info *revs, struct strvec *argv)\n \t/* make sure shallows are read */\n \tis_repository_shallow(the_repository);\n \n-\tsave_warning = warn_on_object_refname_ambiguity;\n-\twarn_on_object_refname_ambiguity = 0;\n+\tsave_warning = cfg->warn_on_object_refname_ambiguity;\n+\tcfg->warn_on_object_refname_ambiguity = 0;\n \n \twhile (fgets(line, sizeof(line), stdin) != NULL) {\n \t\tint len = strlen(line);\n@@ -4827,7 +4828,7 @@ static void get_object_list(struct rev_info *revs, struct strvec *argv)\n \t\t\tdie(_(\"bad revision '%s'\"), line);\n \t}\n \n-\twarn_on_object_refname_ambiguity = save_warning;\n+\tcfg->warn_on_object_refname_ambiguity = save_warning;\n \n \tif (use_bitmap_index && !get_object_list_from_bitmap(revs))\n \t\treturn;\ndiff --git a/environment.c b/environment.c\nindex 57587ede56..ba2c60103f 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -47,7 +47,6 @@ int minimum_abbrev = 4, default_abbrev = -1;\n int ignore_case;\n int assume_unchanged;\n int is_bare_repository_cfg = -1; /* unspecified */\n-int warn_on_object_refname_ambiguity = 1;\n char *git_commit_encoding;\n char *git_log_output_encoding;\n char *apply_default_whitespace;\n@@ -725,4 +724,5 @@ void repo_config_values_init(struct repo_config_values *cfg)\n \tcfg->precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */\n \tcfg->core_sparse_checkout_cone = 0;\n \tcfg->sparse_expect_files_outside_of_patterns = 0;\n+\tcfg->warn_on_object_refname_ambiguity = 1;\n }\ndiff --git a/environment.h b/environment.h\nindex 609cdaa07f..1ff0a7ba8b 100644\n--- a/environment.h\n+++ b/environment.h\n@@ -97,6 +97,7 @@ struct repo_config_values {\n \tint pack_compression_level;\n \tint precomposed_unicode;\n \tint core_sparse_checkout_cone;\n+\tint warn_on_object_refname_ambiguity;\n \n \t/* section \"sparse\" config values */\n \tint sparse_expect_files_outside_of_patterns;\n@@ -174,7 +175,6 @@ extern int has_symlinks;\n extern int minimum_abbrev, default_abbrev;\n extern int ignore_case;\n extern int assume_unchanged;\n-extern int warn_on_object_refname_ambiguity;\n extern char *apply_default_whitespace;\n extern char *apply_default_ignorewhitespace;\n extern unsigned long pack_size_limit_cfg;\ndiff --git a/object-name.c b/object-name.c\nindex 21dcdc4a0e..319d3db01d 100644\n--- a/object-name.c\n+++ b/object-name.c\n@@ -684,11 +684,12 @@ static int get_oid_basic(struct repository *r, const char *str, int len,\n \tint refs_found = 0;\n \tint at, reflog_len, nth_prior = 0;\n \tint fatal = !(flags & GET_OID_QUIETLY);\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n \tif (len == r->hash_algo->hexsz && !get_oid_hex(str, oid)) {\n \t\tif (!(flags & GET_OID_SKIP_AMBIGUITY_CHECK) &&\n \t\t    repo_settings_get_warn_ambiguous_refs(r) &&\n-\t\t    warn_on_object_refname_ambiguity) {\n+\t\t    cfg->warn_on_object_refname_ambiguity) {\n \t\t\trefs_found = repo_dwim_ref(r, str, len, &tmp_oid, &real_ref, 0);\n \t\t\tif (refs_found > 0) {\n \t\t\t\twarning(warn_msg, len, str);\ndiff --git a/revision.c b/revision.c\nindex 599b3a66c3..4e7faa7eb1 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -2922,9 +2922,10 @@ static void read_revisions_from_stdin(struct rev_info *revs,\n \tint seen_end_of_options = 0;\n \tint save_warning;\n \tint flags = 0;\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n-\tsave_warning = warn_on_object_refname_ambiguity;\n-\twarn_on_object_refname_ambiguity = 0;\n+\tsave_warning = cfg->warn_on_object_refname_ambiguity;\n+\tcfg->warn_on_object_refname_ambiguity = 0;\n \n \tstrbuf_init(&sb, 1000);\n \twhile (strbuf_getline(&sb, stdin) != EOF) {\n@@ -2958,7 +2959,7 @@ static void read_revisions_from_stdin(struct rev_info *revs,\n \t\tread_pathspec_from_stdin(&sb, prune);\n \n \tstrbuf_release(&sb);\n-\twarn_on_object_refname_ambiguity = save_warning;\n+\tcfg->warn_on_object_refname_ambiguity = save_warning;\n }\n \n static void NORETURN diagnose_missing_default(const char *def)\ndiff --git a/submodule.c b/submodule.c\nindex b1a0363f9d..f26235bbb7 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -898,12 +898,13 @@ static void collect_changed_submodules(struct repository *r,\n \tstruct setup_revision_opt s_r_opt = {\n \t\t.assume_dashdash = 1,\n \t};\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n-\tsave_warning = warn_on_object_refname_ambiguity;\n-\twarn_on_object_refname_ambiguity = 0;\n+\tsave_warning = cfg->warn_on_object_refname_ambiguity;\n+\tcfg->warn_on_object_refname_ambiguity = 0;\n \trepo_init_revisions(r, &rev, NULL);\n \tsetup_revisions_from_strvec(argv, &rev, &s_r_opt);\n-\twarn_on_object_refname_ambiguity = save_warning;\n+\tcfg->warn_on_object_refname_ambiguity = save_warning;\n \tif (prepare_revision_walk(&rev))\n \t\tdie(_(\"revision walk setup failed\"));\n \n-- \n2.53.0.155.g9f36b15afa\n\n"},{"id":"544426","messageId":"xmqq8q8y3pjl.fsf@gitster.g","threadId":"65344","inReplyTo":"xmqqlddqu013.fsf@gitster.g","subject":"Re: [PATCH v3 0/8] environment: move core config globals into repo_config_values","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-06-01T21:43:10Z","receivedAt":"2026-06-01T21:43:13Z","isPatch":true,"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Bello Olamide <belkid98@gmail.com> writes:\n>\n>> There isn’t any semantic difference intended between\n>> the \"environment:\" and \"env:\" prefixes\n>>\n>> I shortened some of them to stay within the recommended subject length,\n>> but on a second thought I agree that consistency is more important here.\n>>\n>> I’ll standardize them in the next revision.\n>\n> Does anybody listed on the CC: in the original submission have any\n> comments on this round?  It seems that v2 iteration was commented on\n> quite a bit, but has anybody checked the latest iteration since it\n> was posted?\n\nYour mention of \"the next revision\" were made on Apr 26th and it has\nbeen a month without any updates since then.  Tian Yuchen seems to\nhave made a few review comments, so perhaps it is a good time to\nupdate the series to stir the pot, hopefully reigniting interests in\nthe topic?\n\nhttps://lore.kernel.org/git/08efcc49-0db8-49f6-8971-633aa55eb66c@malon.dev/\n"},{"id":"544437","messageId":"xmqq4ijl3nn3.fsf@gitster.g","threadId":"65344","inReplyTo":"xmqq8q8y3pjl.fsf@gitster.g","subject":"Re: [PATCH v3 0/8] environment: move core config globals into repo_config_values","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-06-01T22:24:16Z","receivedAt":"2026-06-01T22:24:18Z","isPatch":true,"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Your mention of \"the next revision\" were made on Apr 26th and it has\n> been a month without any updates since then.  Tian Yuchen seems to\n> have made a few review comments, so perhaps it is a good time to\n> update the series to stir the pot, hopefully reigniting interests in\n> the topic?\n\nAh, I see you now have an updated version.  Let's see what people\nsay on these patches.  Thanks.\n"},{"id":"544448","messageId":"xmqq1pep24wn.fsf@gitster.g","threadId":"65344","inReplyTo":"20260601154211.82370-6-belkid98@gmail.com","subject":"Re: [PATCH v4 5/8] environment: move \"precomposed_unicode\" into `struct repo_config_values`","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-06-01T23:54:16Z","receivedAt":"2026-06-01T23:54:18Z","isPatch":true,"body":"Olamide Caleb Bello <belkid98@gmail.com> writes:\n\n> The `core.precomposeunicode` configuration is currently stored in the\n> global variable `precomposed_unicode`, which makes it shared across\n> repository instances within a single process.\n> ...\n> Change the type of the field from `int` to `bool` since it is parsed\n> as a boolean value.\n\nIs it really?  The variable (or the structure member in the new\ncode) needs to be initialized to -1, so in that sense it is tristate\n(unspecified -1, false 0, or true 1).\n\n> diff --git a/environment.h b/environment.h\n> index 514576b67a..508cb1afbc 100644\n> --- a/environment.h\n> +++ b/environment.h\n> @@ -95,6 +95,7 @@ struct repo_config_values {\n>  \tint check_stat;\n>  \tint zlib_compression_level;\n>  \tint pack_compression_level;\n> +\tint precomposed_unicode;\n\nAnd the code does not make such a type change.  Leaving it \"int\" is\nalso the right thing to do for this topic, as its stated goal is to\nturn the process-wide global into a per-repository setting.\n"},{"id":"544449","messageId":"xmqqtsrlztzu.fsf@gitster.g","threadId":"65344","inReplyTo":"20260601154211.82370-9-belkid98@gmail.com","subject":"Re: [PATCH v4 8/8] environment: move \"warn_on_object_refname_ambiguity\" into `struct repo_config_values`","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-06-02T00:05:57Z","receivedAt":"2026-06-02T00:05:59Z","isPatch":true,"body":"Olamide Caleb Bello <belkid98@gmail.com> writes:\n\n> @@ -684,11 +684,12 @@ static int get_oid_basic(struct repository *r, const char *str, int len,\n>  \tint refs_found = 0;\n>  \tint at, reflog_len, nth_prior = 0;\n>  \tint fatal = !(flags & GET_OID_QUIETLY);\n> +\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n\nThe theme of this topic, however, is to turn the process-wide global\ninto per-repository setting, so it may appear to be a bit unrelated\nchange, but the function already takes a repository instance, which\nmay be different from the_repository.  In the longer run, we\ndefinitely want to see this call pass 'r' instead of\n'the_repository', after making sure that repo-config-values for\nrepository 'r' has already been properly initialized in the program\nflow that leads here.\n\nIf we want to be conservative, keep the call passing the_repository,\nbut leave an in-code comment \n\n\t/*\n\t * NEEDSWORK: pass 'r' instead of the_repository after\n\t * making sure that repo_config_values for 'r' does have\n\t * the right value for the repository.\n\t */\n\nor something like that nearby.\n\n> diff --git a/submodule.c b/submodule.c\n> index b1a0363f9d..f26235bbb7 100644\n> --- a/submodule.c\n> +++ b/submodule.c\n> @@ -898,12 +898,13 @@ static void collect_changed_submodules(struct repository *r,\n>  \tstruct setup_revision_opt s_r_opt = {\n>  \t\t.assume_dashdash = 1,\n>  \t};\n> +\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n\nLikewise.\n\nThere may be other places with the same issue I may have missed.\n\n\n"},{"id":"544450","messageId":"xmqqpl29ztx7.fsf@gitster.g","threadId":"65344","inReplyTo":"20260601154211.82370-4-belkid98@gmail.com","subject":"Re: [PATCH v4 3/8] environment: move `zlib_compression_level` into `struct repo_config_values`","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-06-02T00:07:32Z","receivedAt":"2026-06-02T00:07:34Z","isPatch":true,"body":"Olamide Caleb Bello <belkid98@gmail.com> writes:\n\n> @@ -906,6 +906,7 @@ static int start_loose_object_common(struct odb_source *source,\n>  \tconst struct git_hash_algo *algo = source->odb->repo->hash_algo;\n>  \tconst struct git_hash_algo *compat = source->odb->repo->compat_hash_algo;\n>  \tint fd;\n> +\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n\nWould source->odb->repo have properly initialized repo_config_values\nstructure at this point?  Shouldn't we be using it for this call,\ninstead of the_repository?\n\n>  \tfd = create_tmpfile(source->odb->repo, tmp_file, filename);\n>  \tif (fd < 0) {\n> @@ -921,7 +922,7 @@ static int start_loose_object_common(struct odb_source *source,\n>  \t}\n>  \n>  \t/*  Setup zlib stream for compression */\n> -\tgit_deflate_init(stream, zlib_compression_level);\n> +\tgit_deflate_init(stream, cfg->zlib_compression_level);\n>  \tstream->next_out = buf;\n>  \tstream->avail_out = buflen;\n>  \talgo->init_fn(c);\n"},{"id":"544467","messageId":"ah6QgwfK_TykIiBp@pks.im","threadId":"65344","inReplyTo":"xmqqpl29ztx7.fsf@gitster.g","subject":"Re: [PATCH v4 3/8] environment: move `zlib_compression_level` into `struct repo_config_values`","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-06-02T08:12:51Z","receivedAt":"2026-06-02T08:13:00Z","isPatch":true,"body":"On Tue, Jun 02, 2026 at 09:07:32AM +0900, Junio C Hamano wrote:\n> Olamide Caleb Bello <belkid98@gmail.com> writes:\n> \n> > @@ -906,6 +906,7 @@ static int start_loose_object_common(struct odb_source *source,\n> >  \tconst struct git_hash_algo *algo = source->odb->repo->hash_algo;\n> >  \tconst struct git_hash_algo *compat = source->odb->repo->compat_hash_algo;\n> >  \tint fd;\n> > +\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n> \n> Would source->odb->repo have properly initialized repo_config_values\n> structure at this point?  Shouldn't we be using it for this call,\n> instead of the_repository?\n\nI think as an intermediate step it's okay-ish to use `the_repository`,\nas it doesn't make the status quo any worse. But ideally, we'd have a\nfollow-up patch series that converts \"object-file.c\" to drop the\ndependency on `the_repository` completely, which will be easier after\nthis patch series here has landed as there will only be a handful more\nconfig options to migrate:\n\n  - `pack_compression_level` and `zlib_compression_level` get migrated\n    in this series.\n\n  - `object_creation_mode` still needs migration.\n\n  - `pack_size_limit_cfg` still needs migration.\n\nOther than that we really only need to use the correct repo in a small\nset of functions.\n\nOverall, I think it's sensible to always use `the_repository` at the\ncallsites in a patch series like this so that it's obvious that there is\nno change in behaviour. So every patch series that gets rid of global\nstate in a subsystem X will basically bubble up the global state into\nthe next-higher level, and it's then the duty of the next patch series\nto address that next-higher level.\n\nThe only exception of course is subsystems that already got rid of\n`the_repository` -- we really shouldn't reintroduce the use there.\n\nPatrick\n"},{"id":"544486","messageId":"CAP8UFD2J_482vT3J3hYpSeqG+of_ZDjO3a-paGocRyRgn0=FDQ@mail.gmail.com","threadId":"65344","inReplyTo":"ah6QgwfK_TykIiBp@pks.im","subject":"Re: [PATCH v4 3/8] environment: move `zlib_compression_level` into `struct repo_config_values`","fromName":"Christian Couder","fromEmail":"christian.couder@gmail.com","sentAt":"2026-06-02T10:08:44Z","receivedAt":"2026-06-02T10:08:57Z","isPatch":true,"body":"On Tue, Jun 2, 2026 at 10:13 AM Patrick Steinhardt <ps@pks.im> wrote:\n\n> Overall, I think it's sensible to always use `the_repository` at the\n> callsites in a patch series like this so that it's obvious that there is\n> no change in behaviour. So every patch series that gets rid of global\n> state in a subsystem X will basically bubble up the global state into\n> the next-higher level, and it's then the duty of the next patch series\n> to address that next-higher level.\n>\n> The only exception of course is subsystems that already got rid of\n> `the_repository` -- we really shouldn't reintroduce the use there.\n\nI agree that it should be fine to proceed like this. It limits the\ncomplexity of the patches when we separate getting rid of\n`the_repository` from getting rid of other global state.\n"},{"id":"544488","messageId":"xmqq33z5xmp8.fsf@gitster.g","threadId":"65344","inReplyTo":"CAP8UFD2J_482vT3J3hYpSeqG+of_ZDjO3a-paGocRyRgn0=FDQ@mail.gmail.com","subject":"Re: [PATCH v4 3/8] environment: move `zlib_compression_level` into `struct repo_config_values`","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-06-02T10:26:27Z","receivedAt":"2026-06-02T10:26:29Z","isPatch":true,"body":"Christian Couder <christian.couder@gmail.com> writes:\n\n> On Tue, Jun 2, 2026 at 10:13 AM Patrick Steinhardt <ps@pks.im> wrote:\n>\n>> Overall, I think it's sensible to always use `the_repository` at the\n>> callsites in a patch series like this so that it's obvious that there is\n>> no change in behaviour. So every patch series that gets rid of global\n>> state in a subsystem X will basically bubble up the global state into\n>> the next-higher level, and it's then the duty of the next patch series\n>> to address that next-higher level.\n>>\n>> The only exception of course is subsystems that already got rid of\n>> `the_repository` -- we really shouldn't reintroduce the use there.\n>\n> I agree that it should be fine to proceed like this. It limits the\n> complexity of the patches when we separate getting rid of\n> `the_repository` from getting rid of other global state.\n\nI guess we are all in agreement that what was posted stops at a good\npoint, leaving some for later updates.  Unless there are any other\noutstanding issues, it may be a good time to declare victory.  The\n\"bool\" in the log message for [5/8] must be corrected, though, so\nperhaps this topic is expecting a (hopefully small and final)\nreroll?\n\nThanks.\n"},{"id":"544537","messageId":"20260602170921.35869-1-belkid98@gmail.com","threadId":"65344","inReplyTo":"20260601154211.82370-1-belkid98@gmail.com","subject":"[PATCH v5 0/8] repo_config_values: migrate more globals variables","fromName":"Olamide Caleb Bello","fromEmail":"belkid98@gmail.com","sentAt":"2026-06-02T17:09:13Z","receivedAt":"2026-06-02T17:10:46Z","isPatch":true,"body":"Changes since v4:\n\n- environment: move \"precomposed_unicode\" into `struct repo_config_values`:\n  remove incorrect mention of changing `int` to `bool`\n\n\n\nOlamide Caleb Bello (8):\n  environment: move \"trust_ctime\" into `struct repo_config_values`\n  environment: move \"check_stat\" into `struct repo_config_values`\n  environment: move `zlib_compression_level` into `struct\n    repo_config_values`\n  environment: move \"pack_compression_level\" into `struct\n    repo_config_values`\n  environment: move \"precomposed_unicode\" into `struct\n    repo_config_values`\n  environment: move \"core_sparse_checkout_cone\" into `struct\n    repo_config_values`\n  environment: move \"sparse_expect_files_outside_of_patterns\" into\n    `struct repo_config_values`\n  environment: move \"warn_on_object_refname_ambiguity\" into `struct\n    repo_config_values`\n\n builtin/cat-file.c        |  7 ++++---\n builtin/fast-import.c     |  8 +++++---\n builtin/index-pack.c      |  3 ++-\n builtin/mv.c              |  2 +-\n builtin/pack-objects.c    | 24 +++++++++++++----------\n builtin/sparse-checkout.c | 37 +++++++++++++++++++++---------------\n compat/precompose_utf8.c  | 20 +++++++++++++-------\n diff.c                    |  3 ++-\n dir.c                     |  3 ++-\n entry.c                   |  3 ++-\n environment.c             | 40 +++++++++++++++++++++------------------\n environment.h             | 19 ++++++++++---------\n http-push.c               |  3 ++-\n object-file.c             |  6 ++++--\n object-name.c             |  3 ++-\n revision.c                |  7 ++++---\n sparse-index.c            |  4 ++--\n statinfo.c                | 12 +++++++-----\n submodule.c               |  7 ++++---\n upload-pack.c             |  3 ++-\n 20 files changed, 126 insertions(+), 88 deletions(-)\n\n-- \n2.53.0.155.g9f36b15afa\n\n"},{"id":"544538","messageId":"20260602170921.35869-2-belkid98@gmail.com","threadId":"65344","inReplyTo":"20260602170921.35869-1-belkid98@gmail.com","subject":"[PATCH v5 1/8] environment: move \"trust_ctime\" into `struct repo_config_values`","fromName":"Olamide Caleb Bello","fromEmail":"belkid98@gmail.com","sentAt":"2026-06-02T17:09:14Z","receivedAt":"2026-06-02T17:10:48Z","isPatch":true,"body":"The `core.trustctime` configuration is currently stored in the global\nvariable `trust_ctime`, which makes it shared across repository\ninstances in a single process.\n\nStore it instead in `repo_config_values`, where eagerly‑parsed\nrepository configuration lives. `core.trustctime` is parsed eagerly\nbecause it is used in low‑level stat‑matching functions\n(`match_stat_data()`), where a lazy parse could cause unexpected\nfatal errors, result in a performance regression and complicate\nlibification efforts. This preserves that behavior while tying the\nvalue to the repository from which it was read, avoiding cross‑repository\nstate leakage and continuing the effort to reduce reliance on global\nconfiguration state.\n\nUpdate all references to use repo_config_values().\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nSigned-off-by: Olamide Caleb Bello <belkid98@gmail.com>\n---\n environment.c | 4 ++--\n environment.h | 2 +-\n statinfo.c    | 6 ++++--\n 3 files changed, 7 insertions(+), 5 deletions(-)\n\ndiff --git a/environment.c b/environment.c\nindex fc3ed8bb1c..0a9067729e 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -42,7 +42,6 @@ static int pack_compression_seen;\n static int zlib_compression_seen;\n \n int trust_executable_bit = 1;\n-int trust_ctime = 1;\n int check_stat = 1;\n int has_symlinks = 1;\n int minimum_abbrev = 4, default_abbrev = -1;\n@@ -309,7 +308,7 @@ int git_default_core_config(const char *var, const char *value,\n \t\treturn 0;\n \t}\n \tif (!strcmp(var, \"core.trustctime\")) {\n-\t\ttrust_ctime = git_config_bool(var, value);\n+\t\tcfg->trust_ctime = git_config_bool(var, value);\n \t\treturn 0;\n \t}\n \tif (!strcmp(var, \"core.checkstat\")) {\n@@ -721,4 +720,5 @@ void repo_config_values_init(struct repo_config_values *cfg)\n \tcfg->attributes_file = NULL;\n \tcfg->apply_sparse_checkout = 0;\n \tcfg->branch_track = BRANCH_TRACK_REMOTE;\n+\tcfg->trust_ctime = 1;\n }\ndiff --git a/environment.h b/environment.h\nindex 123a71cdc8..64d537686e 100644\n--- a/environment.h\n+++ b/environment.h\n@@ -91,6 +91,7 @@ struct repo_config_values {\n \t/* section \"core\" config values */\n \tchar *attributes_file;\n \tint apply_sparse_checkout;\n+\tint trust_ctime;\n \n \t/* section \"branch\" config values */\n \tenum branch_track branch_track;\n@@ -161,7 +162,6 @@ extern char *git_work_tree_cfg;\n \n /* Environment bits from configuration mechanism */\n extern int trust_executable_bit;\n-extern int trust_ctime;\n extern int check_stat;\n extern int has_symlinks;\n extern int minimum_abbrev, default_abbrev;\ndiff --git a/statinfo.c b/statinfo.c\nindex 30a164b0e6..4fc12053f4 100644\n--- a/statinfo.c\n+++ b/statinfo.c\n@@ -3,6 +3,7 @@\n #include \"git-compat-util.h\"\n #include \"environment.h\"\n #include \"statinfo.h\"\n+#include \"repository.h\"\n \n /*\n  * Munge st_size into an unsigned int.\n@@ -63,17 +64,18 @@ void fake_lstat_data(const struct stat_data *sd, struct stat *st)\n int match_stat_data(const struct stat_data *sd, struct stat *st)\n {\n \tint changed = 0;\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n \tif (sd->sd_mtime.sec != (unsigned int)st->st_mtime)\n \t\tchanged |= MTIME_CHANGED;\n-\tif (trust_ctime && check_stat &&\n+\tif (cfg->trust_ctime && check_stat &&\n \t    sd->sd_ctime.sec != (unsigned int)st->st_ctime)\n \t\tchanged |= CTIME_CHANGED;\n \n #ifdef USE_NSEC\n \tif (check_stat && sd->sd_mtime.nsec != ST_MTIME_NSEC(*st))\n \t\tchanged |= MTIME_CHANGED;\n-\tif (trust_ctime && check_stat &&\n+\tif (cfg->trust_ctime && check_stat &&\n \t    sd->sd_ctime.nsec != ST_CTIME_NSEC(*st))\n \t\tchanged |= CTIME_CHANGED;\n #endif\n-- \n2.53.0.155.g9f36b15afa\n\n"},{"id":"544539","messageId":"20260602170921.35869-3-belkid98@gmail.com","threadId":"65344","inReplyTo":"20260602170921.35869-1-belkid98@gmail.com","subject":"[PATCH v5 2/8] environment: move \"check_stat\" into `struct repo_config_values`","fromName":"Olamide Caleb Bello","fromEmail":"belkid98@gmail.com","sentAt":"2026-06-02T17:09:15Z","receivedAt":"2026-06-02T17:10:51Z","isPatch":true,"body":"The `core.checkstat` configuration is currently stored in the global\nvariable `check_stat`, which makes it shared across repository\ninstances within a single process.\n\nStore it instead in `repo_config_values`, where eagerly‑parsed\nrepository configuration lives. `core.checkstat` is parsed eagerly\nbecause it controls how `match_stat_data()` and related functions\ndecide file freshness; a lazy parse could lead to unexpected\nbehavior or complicate libification. This preserves the existing\neager‑parsing behavior while tying the value to the repository it\nwas read from, avoiding cross‑repository state leakage, and\ncontinuing the effort to reduce reliance on global configuration\nstate.\n\nUpdate all references to use `repo_config_values()`.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Usman Akinyemi <usmanakinyemi202@gmail.com>\nSigned-off-by: Olamide Caleb Bello <belkid98@gmail.com>\n---\n entry.c       |  3 ++-\n environment.c |  6 +++---\n environment.h |  2 +-\n statinfo.c    | 10 +++++-----\n 4 files changed, 11 insertions(+), 10 deletions(-)\n\ndiff --git a/entry.c b/entry.c\nindex 7817aee362..c55e867d8a 100644\n--- a/entry.c\n+++ b/entry.c\n@@ -443,7 +443,8 @@ static int check_path(const char *path, int len, struct stat *st, int skiplen)\n static void mark_colliding_entries(const struct checkout *state,\n \t\t\t\t   struct cache_entry *ce, struct stat *st)\n {\n-\tint trust_ino = check_stat;\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n+\tint trust_ino = cfg->check_stat;\n \n #if defined(GIT_WINDOWS_NATIVE) || defined(__CYGWIN__)\n \ttrust_ino = 0;\ndiff --git a/environment.c b/environment.c\nindex 0a9067729e..8542ac3141 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -42,7 +42,6 @@ static int pack_compression_seen;\n static int zlib_compression_seen;\n \n int trust_executable_bit = 1;\n-int check_stat = 1;\n int has_symlinks = 1;\n int minimum_abbrev = 4, default_abbrev = -1;\n int ignore_case;\n@@ -315,9 +314,9 @@ int git_default_core_config(const char *var, const char *value,\n \t\tif (!value)\n \t\t\treturn config_error_nonbool(var);\n \t\tif (!strcasecmp(value, \"default\"))\n-\t\t\tcheck_stat = 1;\n+\t\t\tcfg->check_stat = 1;\n \t\telse if (!strcasecmp(value, \"minimal\"))\n-\t\t\tcheck_stat = 0;\n+\t\t\tcfg->check_stat = 0;\n \t\telse\n \t\t\treturn error(_(\"invalid value for '%s': '%s'\"),\n \t\t\t\t     var, value);\n@@ -721,4 +720,5 @@ void repo_config_values_init(struct repo_config_values *cfg)\n \tcfg->apply_sparse_checkout = 0;\n \tcfg->branch_track = BRANCH_TRACK_REMOTE;\n \tcfg->trust_ctime = 1;\n+\tcfg->check_stat = 1;\n }\ndiff --git a/environment.h b/environment.h\nindex 64d537686e..1d3e2e4f23 100644\n--- a/environment.h\n+++ b/environment.h\n@@ -92,6 +92,7 @@ struct repo_config_values {\n \tchar *attributes_file;\n \tint apply_sparse_checkout;\n \tint trust_ctime;\n+\tint check_stat;\n \n \t/* section \"branch\" config values */\n \tenum branch_track branch_track;\n@@ -162,7 +163,6 @@ extern char *git_work_tree_cfg;\n \n /* Environment bits from configuration mechanism */\n extern int trust_executable_bit;\n-extern int check_stat;\n extern int has_symlinks;\n extern int minimum_abbrev, default_abbrev;\n extern int ignore_case;\ndiff --git a/statinfo.c b/statinfo.c\nindex 4fc12053f4..5e00af127d 100644\n--- a/statinfo.c\n+++ b/statinfo.c\n@@ -68,19 +68,19 @@ int match_stat_data(const struct stat_data *sd, struct stat *st)\n \n \tif (sd->sd_mtime.sec != (unsigned int)st->st_mtime)\n \t\tchanged |= MTIME_CHANGED;\n-\tif (cfg->trust_ctime && check_stat &&\n+\tif (cfg->trust_ctime && cfg->check_stat &&\n \t    sd->sd_ctime.sec != (unsigned int)st->st_ctime)\n \t\tchanged |= CTIME_CHANGED;\n \n #ifdef USE_NSEC\n-\tif (check_stat && sd->sd_mtime.nsec != ST_MTIME_NSEC(*st))\n+\tif (cfg->check_stat && sd->sd_mtime.nsec != ST_MTIME_NSEC(*st))\n \t\tchanged |= MTIME_CHANGED;\n-\tif (cfg->trust_ctime && check_stat &&\n+\tif (cfg->trust_ctime && cfg->check_stat &&\n \t    sd->sd_ctime.nsec != ST_CTIME_NSEC(*st))\n \t\tchanged |= CTIME_CHANGED;\n #endif\n \n-\tif (check_stat) {\n+\tif (cfg->check_stat) {\n \t\tif (sd->sd_uid != (unsigned int) st->st_uid ||\n \t\t\tsd->sd_gid != (unsigned int) st->st_gid)\n \t\t\tchanged |= OWNER_CHANGED;\n@@ -94,7 +94,7 @@ int match_stat_data(const struct stat_data *sd, struct stat *st)\n \t * clients will have different views of what \"device\"\n \t * the filesystem is on\n \t */\n-\tif (check_stat && sd->sd_dev != (unsigned int) st->st_dev)\n+\tif (cfg->check_stat && sd->sd_dev != (unsigned int) st->st_dev)\n \t\t\tchanged |= INODE_CHANGED;\n #endif\n \n-- \n2.53.0.155.g9f36b15afa\n\n"},{"id":"544540","messageId":"20260602170921.35869-4-belkid98@gmail.com","threadId":"65344","inReplyTo":"20260602170921.35869-1-belkid98@gmail.com","subject":"[PATCH v5 3/8] environment: move `zlib_compression_level` into `struct repo_config_values`","fromName":"Olamide Caleb Bello","fromEmail":"belkid98@gmail.com","sentAt":"2026-06-02T17:09:16Z","receivedAt":"2026-06-02T17:10:53Z","isPatch":true,"body":"The `zlib_compression_level` configuration is currently stored in the\nglobal variable `zlib_compression_level`, which makes it shared across\nrepository instances within a single process.\n\nStore it instead in `repo_config_values`, where eagerly‑parsed\nrepository configuration lives. `zlib_compression_level` is parsed\neagerly because it determines compression behaviour for objects and\npacks – core operations where a lazy parse could lead to unpredictable\nresults and hinder libification. This preserves the existing\neager‑parsing behavior while tying the value to the repository it\nwas read from, avoiding cross‑repository state leakage and continuing\nthe effort to reduce reliance on global configuration state.\n\nUpdate all references to use `repo_config_values()`.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Usman Akinyemi <usmanakinyemi202@gmail.com>\nSigned-off-by: Olamide Caleb Bello <belkid98@gmail.com>\n---\n builtin/index-pack.c | 3 ++-\n diff.c               | 3 ++-\n environment.c        | 6 +++---\n environment.h        | 2 +-\n http-push.c          | 3 ++-\n object-file.c        | 3 ++-\n 6 files changed, 12 insertions(+), 8 deletions(-)\n\ndiff --git a/builtin/index-pack.c b/builtin/index-pack.c\nindex ca7784dc2c..3942d3e0d0 100644\n--- a/builtin/index-pack.c\n+++ b/builtin/index-pack.c\n@@ -1416,8 +1416,9 @@ static int write_compressed(struct hashfile *f, void *in, unsigned int size)\n \tgit_zstream stream;\n \tint status;\n \tunsigned char outbuf[4096];\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n-\tgit_deflate_init(&stream, zlib_compression_level);\n+\tgit_deflate_init(&stream, cfg->zlib_compression_level);\n \tstream.next_in = in;\n \tstream.avail_in = size;\n \ndiff --git a/diff.c b/diff.c\nindex 397e38b41c..7d17b0bf3f 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -3589,8 +3589,9 @@ static unsigned char *deflate_it(char *data,\n \tint bound;\n \tunsigned char *deflated;\n \tgit_zstream stream;\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n-\tgit_deflate_init(&stream, zlib_compression_level);\n+\tgit_deflate_init(&stream, cfg->zlib_compression_level);\n \tbound = git_deflate_bound(&stream, size);\n \tdeflated = xmalloc(bound);\n \tstream.next_out = deflated;\ndiff --git a/environment.c b/environment.c\nindex 8542ac3141..5b0e88b65c 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -52,7 +52,6 @@ char *git_commit_encoding;\n char *git_log_output_encoding;\n char *apply_default_whitespace;\n char *apply_default_ignorewhitespace;\n-int zlib_compression_level = Z_BEST_SPEED;\n int pack_compression_level = Z_DEFAULT_COMPRESSION;\n int fsync_object_files = -1;\n int use_fsync = -1;\n@@ -377,7 +376,7 @@ int git_default_core_config(const char *var, const char *value,\n \t\t\tlevel = Z_DEFAULT_COMPRESSION;\n \t\telse if (level < 0 || level > Z_BEST_COMPRESSION)\n \t\t\tdie(_(\"bad zlib compression level %d\"), level);\n-\t\tzlib_compression_level = level;\n+\t\tcfg->zlib_compression_level = level;\n \t\tzlib_compression_seen = 1;\n \t\treturn 0;\n \t}\n@@ -389,7 +388,7 @@ int git_default_core_config(const char *var, const char *value,\n \t\telse if (level < 0 || level > Z_BEST_COMPRESSION)\n \t\t\tdie(_(\"bad zlib compression level %d\"), level);\n \t\tif (!zlib_compression_seen)\n-\t\t\tzlib_compression_level = level;\n+\t\t\tcfg->zlib_compression_level = level;\n \t\tif (!pack_compression_seen)\n \t\t\tpack_compression_level = level;\n \t\treturn 0;\n@@ -721,4 +720,5 @@ void repo_config_values_init(struct repo_config_values *cfg)\n \tcfg->branch_track = BRANCH_TRACK_REMOTE;\n \tcfg->trust_ctime = 1;\n \tcfg->check_stat = 1;\n+\tcfg->zlib_compression_level = Z_BEST_SPEED;\n }\ndiff --git a/environment.h b/environment.h\nindex 1d3e2e4f23..93201620af 100644\n--- a/environment.h\n+++ b/environment.h\n@@ -93,6 +93,7 @@ struct repo_config_values {\n \tint apply_sparse_checkout;\n \tint trust_ctime;\n \tint check_stat;\n+\tint zlib_compression_level;\n \n \t/* section \"branch\" config values */\n \tenum branch_track branch_track;\n@@ -170,7 +171,6 @@ extern int assume_unchanged;\n extern int warn_on_object_refname_ambiguity;\n extern char *apply_default_whitespace;\n extern char *apply_default_ignorewhitespace;\n-extern int zlib_compression_level;\n extern int pack_compression_level;\n extern unsigned long pack_size_limit_cfg;\n \ndiff --git a/http-push.c b/http-push.c\nindex d143fe2845..8ac107a56e 100644\n--- a/http-push.c\n+++ b/http-push.c\n@@ -369,13 +369,14 @@ static void start_put(struct transfer_request *request)\n \tint hdrlen;\n \tssize_t size;\n \tgit_zstream stream;\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n \tunpacked = odb_read_object(the_repository->objects, &request->obj->oid,\n \t\t\t\t   &type, &len);\n \thdrlen = format_object_header(hdr, sizeof(hdr), type, len);\n \n \t/* Set it up */\n-\tgit_deflate_init(&stream, zlib_compression_level);\n+\tgit_deflate_init(&stream, cfg->zlib_compression_level);\n \tsize = git_deflate_bound(&stream, len + hdrlen);\n \tstrbuf_grow(&request->buffer.buf, size);\n \trequest->buffer.posn = 0;\ndiff --git a/object-file.c b/object-file.c\nindex 2acc9522df..7c122ac419 100644\n--- a/object-file.c\n+++ b/object-file.c\n@@ -906,6 +906,7 @@ static int start_loose_object_common(struct odb_source *source,\n \tconst struct git_hash_algo *algo = source->odb->repo->hash_algo;\n \tconst struct git_hash_algo *compat = source->odb->repo->compat_hash_algo;\n \tint fd;\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n \tfd = create_tmpfile(source->odb->repo, tmp_file, filename);\n \tif (fd < 0) {\n@@ -921,7 +922,7 @@ static int start_loose_object_common(struct odb_source *source,\n \t}\n \n \t/*  Setup zlib stream for compression */\n-\tgit_deflate_init(stream, zlib_compression_level);\n+\tgit_deflate_init(stream, cfg->zlib_compression_level);\n \tstream->next_out = buf;\n \tstream->avail_out = buflen;\n \talgo->init_fn(c);\n-- \n2.53.0.155.g9f36b15afa\n\n"},{"id":"544541","messageId":"20260602170921.35869-5-belkid98@gmail.com","threadId":"65344","inReplyTo":"20260602170921.35869-1-belkid98@gmail.com","subject":"[PATCH v5 4/8] environment: move \"pack_compression_level\" into `struct repo_config_values`","fromName":"Olamide Caleb Bello","fromEmail":"belkid98@gmail.com","sentAt":"2026-06-02T17:09:17Z","receivedAt":"2026-06-02T17:10:57Z","isPatch":true,"body":"The `pack_compression_level` configuration is currently stored in the\nglobal variable `pack_compression_level`, which makes it shared across\nrepository instances within a single process.\n\nStore it instead in `repo_config_values`, where eagerly‑parsed\nrepository configuration lives. `pack_compression_level` is parsed\neagerly because it influences packfile compression, a core operation\nwhere a lazy parse could cause inconsistent behavior and hamper\nlibification. This preserves the existing eager‑parsing behavior while\ntying the value to the repository from which it was read, avoiding\ncross‑repository state leakage and continuing the effort to reduce\nreliance on global configuration state.\n\nUpdate all references to use `repo_config_values()`.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Usman Akinyemi <usmanakinyemi202@gmail.com>\nSigned-off-by: Olamide Caleb Bello <belkid98@gmail.com>\n---\n builtin/fast-import.c  |  8 +++++---\n builtin/pack-objects.c | 17 ++++++++++-------\n environment.c          |  8 +++++---\n environment.h          |  2 +-\n object-file.c          |  3 ++-\n 5 files changed, 23 insertions(+), 15 deletions(-)\n\ndiff --git a/builtin/fast-import.c b/builtin/fast-import.c\nindex 82bc6dcc00..070a5af3e4 100644\n--- a/builtin/fast-import.c\n+++ b/builtin/fast-import.c\n@@ -965,6 +965,7 @@ static int store_object(\n \tunsigned long hdrlen, deltalen;\n \tstruct git_hash_ctx c;\n \tgit_zstream s;\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n \thdrlen = format_object_header((char *)hdr, sizeof(hdr), type,\n \t\t\t\t      dat->len);\n@@ -1005,7 +1006,7 @@ static int store_object(\n \t} else\n \t\tdelta = NULL;\n \n-\tgit_deflate_init(&s, pack_compression_level);\n+\tgit_deflate_init(&s, cfg->pack_compression_level);\n \tif (delta) {\n \t\ts.next_in = delta;\n \t\ts.avail_in = deltalen;\n@@ -1032,7 +1033,7 @@ static int store_object(\n \t\tif (delta) {\n \t\t\tFREE_AND_NULL(delta);\n \n-\t\t\tgit_deflate_init(&s, pack_compression_level);\n+\t\t\tgit_deflate_init(&s, cfg->pack_compression_level);\n \t\t\ts.next_in = (void *)dat->buf;\n \t\t\ts.avail_in = dat->len;\n \t\t\ts.avail_out = git_deflate_bound(&s, s.avail_in);\n@@ -1115,6 +1116,7 @@ static void stream_blob(uintmax_t len, struct object_id *oidout, uintmax_t mark)\n \tstruct git_hash_ctx c;\n \tgit_zstream s;\n \tstruct hashfile_checkpoint checkpoint;\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \tint status = Z_OK;\n \n \t/* Determine if we should auto-checkpoint. */\n@@ -1134,7 +1136,7 @@ static void stream_blob(uintmax_t len, struct object_id *oidout, uintmax_t mark)\n \n \tcrc32_begin(pack_file);\n \n-\tgit_deflate_init(&s, pack_compression_level);\n+\tgit_deflate_init(&s, cfg->pack_compression_level);\n \n \thdrlen = encode_in_pack_object_header(out_buf, out_sz, OBJ_BLOB, len);\n \ndiff --git a/builtin/pack-objects.c b/builtin/pack-objects.c\nindex dd2480a73d..8ccbe7e178 100644\n--- a/builtin/pack-objects.c\n+++ b/builtin/pack-objects.c\n@@ -386,8 +386,9 @@ static unsigned long do_compress(void **pptr, unsigned long size)\n \tgit_zstream stream;\n \tvoid *in, *out;\n \tunsigned long maxsize;\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n-\tgit_deflate_init(&stream, pack_compression_level);\n+\tgit_deflate_init(&stream, cfg->pack_compression_level);\n \tmaxsize = git_deflate_bound(&stream, size);\n \n \tin = *pptr;\n@@ -413,8 +414,9 @@ static unsigned long write_large_blob_data(struct odb_read_stream *st, struct ha\n \tunsigned char ibuf[1024 * 16];\n \tunsigned char obuf[1024 * 16];\n \tunsigned long olen = 0;\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n-\tgit_deflate_init(&stream, pack_compression_level);\n+\tgit_deflate_init(&stream, cfg->pack_compression_level);\n \n \tfor (;;) {\n \t\tssize_t readlen;\n@@ -5003,6 +5005,7 @@ int cmd_pack_objects(int argc,\n \tstruct string_list keep_pack_list = STRING_LIST_INIT_NODUP;\n \tstruct list_objects_filter_options filter_options =\n \t\tLIST_OBJECTS_FILTER_INIT;\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n \tstruct option pack_objects_options[] = {\n \t\tOPT_CALLBACK_F('q', \"quiet\", &progress, NULL,\n@@ -5084,7 +5087,7 @@ int cmd_pack_objects(int argc,\n \t\t\t N_(\"ignore packs that have companion .keep file\")),\n \t\tOPT_STRING_LIST(0, \"keep-pack\", &keep_pack_list, N_(\"name\"),\n \t\t\t\tN_(\"ignore this pack\")),\n-\t\tOPT_INTEGER(0, \"compression\", &pack_compression_level,\n+\t\tOPT_INTEGER(0, \"compression\", &cfg->pack_compression_level,\n \t\t\t    N_(\"pack compression level\")),\n \t\tOPT_BOOL(0, \"keep-true-parents\", &grafts_keep_true_parents,\n \t\t\t N_(\"do not hide commits by grafts\")),\n@@ -5243,10 +5246,10 @@ int cmd_pack_objects(int argc,\n \n \tif (!reuse_object)\n \t\treuse_delta = 0;\n-\tif (pack_compression_level == -1)\n-\t\tpack_compression_level = Z_DEFAULT_COMPRESSION;\n-\telse if (pack_compression_level < 0 || pack_compression_level > Z_BEST_COMPRESSION)\n-\t\tdie(_(\"bad pack compression level %d\"), pack_compression_level);\n+\tif (cfg->pack_compression_level == -1)\n+\t\tcfg->pack_compression_level = Z_DEFAULT_COMPRESSION;\n+\telse if (cfg->pack_compression_level < 0 || cfg->pack_compression_level > Z_BEST_COMPRESSION)\n+\t\tdie(_(\"bad pack compression level %d\"), cfg->pack_compression_level);\n \n \tif (!delta_search_threads)\t/* --threads=0 means autodetect */\n \t\tdelta_search_threads = online_cpus();\ndiff --git a/environment.c b/environment.c\nindex 5b0e88b65c..d0d3a4b7d2 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -52,7 +52,6 @@ char *git_commit_encoding;\n char *git_log_output_encoding;\n char *apply_default_whitespace;\n char *apply_default_ignorewhitespace;\n-int pack_compression_level = Z_DEFAULT_COMPRESSION;\n int fsync_object_files = -1;\n int use_fsync = -1;\n enum fsync_method fsync_method = FSYNC_METHOD_DEFAULT;\n@@ -390,7 +389,7 @@ int git_default_core_config(const char *var, const char *value,\n \t\tif (!zlib_compression_seen)\n \t\t\tcfg->zlib_compression_level = level;\n \t\tif (!pack_compression_seen)\n-\t\t\tpack_compression_level = level;\n+\t\t\tcfg->pack_compression_level = level;\n \t\treturn 0;\n \t}\n \n@@ -662,6 +661,8 @@ static int git_default_attr_config(const char *var, const char *value)\n int git_default_config(const char *var, const char *value,\n \t\t       const struct config_context *ctx, void *cb)\n {\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n+\n \tif (starts_with(var, \"core.\"))\n \t\treturn git_default_core_config(var, value, ctx, cb);\n \n@@ -701,7 +702,7 @@ int git_default_config(const char *var, const char *value,\n \t\t\tlevel = Z_DEFAULT_COMPRESSION;\n \t\telse if (level < 0 || level > Z_BEST_COMPRESSION)\n \t\t\tdie(_(\"bad pack compression level %d\"), level);\n-\t\tpack_compression_level = level;\n+\t\tcfg->pack_compression_level = level;\n \t\tpack_compression_seen = 1;\n \t\treturn 0;\n \t}\n@@ -721,4 +722,5 @@ void repo_config_values_init(struct repo_config_values *cfg)\n \tcfg->trust_ctime = 1;\n \tcfg->check_stat = 1;\n \tcfg->zlib_compression_level = Z_BEST_SPEED;\n+\tcfg->pack_compression_level = Z_DEFAULT_COMPRESSION;\n }\ndiff --git a/environment.h b/environment.h\nindex 93201620af..514576b67a 100644\n--- a/environment.h\n+++ b/environment.h\n@@ -94,6 +94,7 @@ struct repo_config_values {\n \tint trust_ctime;\n \tint check_stat;\n \tint zlib_compression_level;\n+\tint pack_compression_level;\n \n \t/* section \"branch\" config values */\n \tenum branch_track branch_track;\n@@ -171,7 +172,6 @@ extern int assume_unchanged;\n extern int warn_on_object_refname_ambiguity;\n extern char *apply_default_whitespace;\n extern char *apply_default_ignorewhitespace;\n-extern int pack_compression_level;\n extern unsigned long pack_size_limit_cfg;\n \n extern int precomposed_unicode;\ndiff --git a/object-file.c b/object-file.c\nindex 7c122ac419..37def5cc59 100644\n--- a/object-file.c\n+++ b/object-file.c\n@@ -1437,8 +1437,9 @@ static int stream_blob_to_pack(struct transaction_packfile *state,\n \tint status = Z_OK;\n \tint write_object = (flags & INDEX_WRITE_OBJECT);\n \toff_t offset = 0;\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n-\tgit_deflate_init(&s, pack_compression_level);\n+\tgit_deflate_init(&s, cfg->pack_compression_level);\n \n \thdrlen = encode_in_pack_object_header(obuf, sizeof(obuf), OBJ_BLOB, size);\n \ts.next_out = obuf + hdrlen;\n-- \n2.53.0.155.g9f36b15afa\n\n"},{"id":"544542","messageId":"20260602170921.35869-6-belkid98@gmail.com","threadId":"65344","inReplyTo":"20260602170921.35869-1-belkid98@gmail.com","subject":"[PATCH v5 5/8] environment: move \"precomposed_unicode\" into `struct repo_config_values`","fromName":"Olamide Caleb Bello","fromEmail":"belkid98@gmail.com","sentAt":"2026-06-02T17:09:18Z","receivedAt":"2026-06-02T17:10:59Z","isPatch":true,"body":"The `core.precomposeunicode` configuration is currently stored in the\nglobal variable `precomposed_unicode`, which makes it shared across\nrepository instances within a single process.\n\nStore it instead in `repo_config_values`, where eagerly‑parsed\nrepository configuration lives. `core.precomposeunicode` is parsed\neagerly because it controls Unicode path normalization on macOS,\na fundamental filesystem‑level behavior that many operations depend\non; a lazy parse could lead to inconsistent results and hamper\nlibification. This preserves the existing behavior while tying the\nvalue to the repository from which it was read, avoiding cross‑\nrepository state leakage and continuing the effort to reduce reliance\non global configuration state.\n\nUpdate all references to use `repo_config_values()`.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Usman Akinyemi <usmanakinyemi202@gmail.com>\nSigned-off-by: Olamide Caleb Bello <belkid98@gmail.com>\n---\n compat/precompose_utf8.c | 20 +++++++++++++-------\n environment.c            |  4 ++--\n environment.h            |  2 +-\n upload-pack.c            |  3 ++-\n 4 files changed, 18 insertions(+), 11 deletions(-)\n\ndiff --git a/compat/precompose_utf8.c b/compat/precompose_utf8.c\nindex 43b3be0114..0e94dbd862 100644\n--- a/compat/precompose_utf8.c\n+++ b/compat/precompose_utf8.c\n@@ -48,16 +48,18 @@ void probe_utf8_pathname_composition(void)\n \tstatic const char *auml_nfc = \"\\xc3\\xa4\";\n \tstatic const char *auml_nfd = \"\\x61\\xcc\\x88\";\n \tint output_fd;\n-\tif (precomposed_unicode != -1)\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n+\n+\tif (cfg->precomposed_unicode != -1)\n \t\treturn; /* We found it defined in the global config, respect it */\n \trepo_git_path_replace(the_repository, &path, \"%s\", auml_nfc);\n \toutput_fd = open(path.buf, O_CREAT|O_EXCL|O_RDWR, 0600);\n \tif (output_fd >= 0) {\n \t\tclose(output_fd);\n \t\trepo_git_path_replace(the_repository, &path, \"%s\", auml_nfd);\n-\t\tprecomposed_unicode = access(path.buf, R_OK) ? 0 : 1;\n+\t\tcfg->precomposed_unicode = access(path.buf, R_OK) ? 0 : 1;\n \t\trepo_config_set(the_repository, \"core.precomposeunicode\",\n-\t\t\t\tprecomposed_unicode ? \"true\" : \"false\");\n+\t\t\t\tcfg->precomposed_unicode ? \"true\" : \"false\");\n \t\trepo_git_path_replace(the_repository, &path, \"%s\", auml_nfc);\n \t\tif (unlink(path.buf))\n \t\t\tdie_errno(_(\"failed to unlink '%s'\"), path.buf);\n@@ -69,14 +71,16 @@ const char *precompose_string_if_needed(const char *in)\n {\n \tsize_t inlen;\n \tsize_t outlen;\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n+\n \tif (!in)\n \t\treturn NULL;\n \tif (has_non_ascii(in, (size_t)-1, &inlen)) {\n \t\ticonv_t ic_prec;\n \t\tchar *out;\n-\t\tif (precomposed_unicode < 0)\n-\t\t\trepo_config_get_bool(the_repository, \"core.precomposeunicode\", &precomposed_unicode);\n-\t\tif (precomposed_unicode != 1)\n+\t\tif (cfg->precomposed_unicode < 0)\n+\t\t\trepo_config_get_bool(the_repository, \"core.precomposeunicode\", &cfg->precomposed_unicode);\n+\t\tif (cfg->precomposed_unicode != 1)\n \t\t\treturn in;\n \t\tic_prec = iconv_open(repo_encoding, path_encoding);\n \t\tif (ic_prec == (iconv_t) -1)\n@@ -130,7 +134,9 @@ PREC_DIR *precompose_utf8_opendir(const char *dirname)\n \n struct dirent_prec_psx *precompose_utf8_readdir(PREC_DIR *prec_dir)\n {\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \tstruct dirent *res;\n+\n \tres = readdir(prec_dir->dirp);\n \tif (res) {\n \t\tsize_t namelenz = strlen(res->d_name) + 1; /* \\0 */\n@@ -149,7 +155,7 @@ struct dirent_prec_psx *precompose_utf8_readdir(PREC_DIR *prec_dir)\n \t\tprec_dir->dirent_nfc->d_ino  = res->d_ino;\n \t\tprec_dir->dirent_nfc->d_type = res->d_type;\n \n-\t\tif ((precomposed_unicode == 1) && has_non_ascii(res->d_name, (size_t)-1, NULL)) {\n+\t\tif ((cfg->precomposed_unicode == 1) && has_non_ascii(res->d_name, (size_t)-1, NULL)) {\n \t\t\tif (prec_dir->ic_precompose == (iconv_t)-1) {\n \t\t\t\tdie(\"iconv_open(%s,%s) failed, but needed:\\n\"\n \t\t\t\t\t\t\"    precomposed unicode is not supported.\\n\"\ndiff --git a/environment.c b/environment.c\nindex d0d3a4b7d2..739b647ebe 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -72,7 +72,6 @@ enum object_creation_mode object_creation_mode = OBJECT_CREATION_MODE;\n int grafts_keep_true_parents;\n int core_sparse_checkout_cone;\n int sparse_expect_files_outside_of_patterns;\n-int precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */\n unsigned long pack_size_limit_cfg;\n \n #ifndef PROTECT_HFS_DEFAULT\n@@ -532,7 +531,7 @@ int git_default_core_config(const char *var, const char *value,\n \t}\n \n \tif (!strcmp(var, \"core.precomposeunicode\")) {\n-\t\tprecomposed_unicode = git_config_bool(var, value);\n+\t\tcfg->precomposed_unicode = git_config_bool(var, value);\n \t\treturn 0;\n \t}\n \n@@ -723,4 +722,5 @@ void repo_config_values_init(struct repo_config_values *cfg)\n \tcfg->check_stat = 1;\n \tcfg->zlib_compression_level = Z_BEST_SPEED;\n \tcfg->pack_compression_level = Z_DEFAULT_COMPRESSION;\n+\tcfg->precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */\n }\ndiff --git a/environment.h b/environment.h\nindex 514576b67a..508cb1afbc 100644\n--- a/environment.h\n+++ b/environment.h\n@@ -95,6 +95,7 @@ struct repo_config_values {\n \tint check_stat;\n \tint zlib_compression_level;\n \tint pack_compression_level;\n+\tint precomposed_unicode;\n \n \t/* section \"branch\" config values */\n \tenum branch_track branch_track;\n@@ -174,7 +175,6 @@ extern char *apply_default_whitespace;\n extern char *apply_default_ignorewhitespace;\n extern unsigned long pack_size_limit_cfg;\n \n-extern int precomposed_unicode;\n extern int protect_hfs;\n extern int protect_ntfs;\n \ndiff --git a/upload-pack.c b/upload-pack.c\nindex 9f6d6fe48c..3a52237134 100644\n--- a/upload-pack.c\n+++ b/upload-pack.c\n@@ -1336,6 +1336,7 @@ static int upload_pack_config(const char *var, const char *value,\n \t\t\t      void *cb_data)\n {\n \tstruct upload_pack_data *data = cb_data;\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n \tif (!strcmp(\"uploadpack.allowtipsha1inwant\", var)) {\n \t\tif (git_config_bool(var, value))\n@@ -1366,7 +1367,7 @@ static int upload_pack_config(const char *var, const char *value,\n \t\tif (value)\n \t\t\tdata->allow_packfile_uris = 1;\n \t} else if (!strcmp(\"core.precomposeunicode\", var)) {\n-\t\tprecomposed_unicode = git_config_bool(var, value);\n+\t\tcfg->precomposed_unicode = git_config_bool(var, value);\n \t} else if (!strcmp(\"transfer.advertisesid\", var)) {\n \t\tdata->advertise_sid = git_config_bool(var, value);\n \t}\n-- \n2.53.0.155.g9f36b15afa\n\n"},{"id":"544543","messageId":"20260602170921.35869-7-belkid98@gmail.com","threadId":"65344","inReplyTo":"20260602170921.35869-1-belkid98@gmail.com","subject":"[PATCH v5 6/8] environment: move \"core_sparse_checkout_cone\" into `struct repo_config_values`","fromName":"Olamide Caleb Bello","fromEmail":"belkid98@gmail.com","sentAt":"2026-06-02T17:09:19Z","receivedAt":"2026-06-02T17:11:02Z","isPatch":true,"body":"The `core.sparseCheckoutCone` configuration was previously stored in an\nuninitialized global `int` variable, risking cross‑repository state\nleakage.\n\nMove it into `repo_config_values`, where eagerly‑parsed repository\nconfiguration lives. `core.sparseCheckoutCone` is parsed eagerly\nbecause it determines the fundamental sparse‑checkout mode and is\nconsulted very early during repository setup; a lazy parse could\nleave the sparse‑checkout state undefined and complicate\nlibification. This preserves the existing behavior while tying the\nvalue to the repository from which it was read, avoiding cross‑\nrepository state leakage and continuing the effort to reduce reliance\non global configuration state.\n\nUpdate all references to use `repo_config_values()`.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Usman Akinyemi <usmanakinyemi202@gmail.com>\nSigned-off-by: Olamide Caleb Bello <belkid98@gmail.com>\n---\n builtin/mv.c              |  2 +-\n builtin/sparse-checkout.c | 37 ++++++++++++++++++++++---------------\n dir.c                     |  3 ++-\n environment.c             |  4 ++--\n environment.h             |  2 +-\n sparse-index.c            |  2 +-\n 6 files changed, 29 insertions(+), 21 deletions(-)\n\ndiff --git a/builtin/mv.c b/builtin/mv.c\nindex 2215d34e31..ef3a326c90 100644\n--- a/builtin/mv.c\n+++ b/builtin/mv.c\n@@ -574,7 +574,7 @@ int cmd_mv(int argc,\n \n \t\tif (ignore_sparse &&\n \t\t    cfg->apply_sparse_checkout &&\n-\t\t    core_sparse_checkout_cone) {\n+\t\t    cfg->core_sparse_checkout_cone) {\n \t\t\t/*\n \t\t\t * NEEDSWORK: we are *not* paying attention to\n \t\t\t * \"out-to-out\" move (<source> is out-of-cone and\ndiff --git a/builtin/sparse-checkout.c b/builtin/sparse-checkout.c\nindex f4aa405da9..92d017b81f 100644\n--- a/builtin/sparse-checkout.c\n+++ b/builtin/sparse-checkout.c\n@@ -73,7 +73,7 @@ static int sparse_checkout_list(int argc, const char **argv, const char *prefix,\n \n \tmemset(&pl, 0, sizeof(pl));\n \n-\tpl.use_cone_patterns = core_sparse_checkout_cone;\n+\tpl.use_cone_patterns = cfg->core_sparse_checkout_cone;\n \n \tsparse_filename = get_sparse_checkout_filename();\n \tres = add_patterns_from_file_to_list(sparse_filename, \"\", 0, &pl, NULL, 0);\n@@ -334,6 +334,7 @@ static int write_patterns_and_update(struct repository *repo,\n \tFILE *fp;\n \tstruct lock_file lk = LOCK_INIT;\n \tint result;\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n \tsparse_filename = get_sparse_checkout_filename();\n \n@@ -353,7 +354,7 @@ static int write_patterns_and_update(struct repository *repo,\n \tif (!fp)\n \t\tdie_errno(_(\"unable to fdopen %s\"), get_lock_file_path(&lk));\n \n-\tif (core_sparse_checkout_cone)\n+\tif (cfg->core_sparse_checkout_cone)\n \t\twrite_cone_to_file(fp, pl);\n \telse\n \t\twrite_patterns_to_file(fp, pl);\n@@ -402,15 +403,15 @@ static enum sparse_checkout_mode update_cone_mode(int *cone_mode) {\n \n \t/* If not specified, use previous definition of cone mode */\n \tif (*cone_mode == -1 && cfg->apply_sparse_checkout)\n-\t\t*cone_mode = core_sparse_checkout_cone;\n+\t\t*cone_mode = cfg->core_sparse_checkout_cone;\n \n \t/* Set cone/non-cone mode appropriately */\n \tcfg->apply_sparse_checkout = 1;\n \tif (*cone_mode == 1 || *cone_mode == -1) {\n-\t\tcore_sparse_checkout_cone = 1;\n+\t\tcfg->core_sparse_checkout_cone = 1;\n \t\treturn MODE_CONE_PATTERNS;\n \t}\n-\tcore_sparse_checkout_cone = 0;\n+\tcfg->core_sparse_checkout_cone = 0;\n \treturn MODE_ALL_PATTERNS;\n }\n \n@@ -577,7 +578,9 @@ static void add_patterns_from_input(struct pattern_list *pl,\n \t\t\t\t    FILE *file)\n {\n \tint i;\n-\tif (core_sparse_checkout_cone) {\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n+\n+\tif (cfg->core_sparse_checkout_cone) {\n \t\tstruct strbuf line = STRBUF_INIT;\n \n \t\thashmap_init(&pl->recursive_hashmap, pl_hashmap_cmp, NULL, 0);\n@@ -636,13 +639,14 @@ static void add_patterns_cone_mode(int argc, const char **argv,\n \tstruct pattern_entry *pe;\n \tstruct hashmap_iter iter;\n \tstruct pattern_list existing;\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \tchar *sparse_filename = get_sparse_checkout_filename();\n \n \tadd_patterns_from_input(pl, argc, argv,\n \t\t\t\tuse_stdin ? stdin : NULL);\n \n \tmemset(&existing, 0, sizeof(existing));\n-\texisting.use_cone_patterns = core_sparse_checkout_cone;\n+\texisting.use_cone_patterns = cfg->core_sparse_checkout_cone;\n \n \tif (add_patterns_from_file_to_list(sparse_filename, \"\", 0,\n \t\t\t\t\t   &existing, NULL, 0))\n@@ -690,7 +694,7 @@ static int modify_pattern_list(struct repository *repo,\n \n \tswitch (m) {\n \tcase ADD:\n-\t\tif (core_sparse_checkout_cone)\n+\t\tif (cfg->core_sparse_checkout_cone)\n \t\t\tadd_patterns_cone_mode(args->nr, args->v, pl, use_stdin);\n \t\telse\n \t\t\tadd_patterns_literal(args->nr, args->v, pl, use_stdin);\n@@ -723,11 +727,12 @@ static void sanitize_paths(struct repository *repo,\n \t\t\t   const char *prefix, int skip_checks)\n {\n \tint i;\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n \tif (!args->nr)\n \t\treturn;\n \n-\tif (prefix && *prefix && core_sparse_checkout_cone) {\n+\tif (prefix && *prefix && cfg->core_sparse_checkout_cone) {\n \t\t/*\n \t\t * The args are not pathspecs, so unfortunately we\n \t\t * cannot imitate how cmd_add() uses parse_pathspec().\n@@ -744,10 +749,10 @@ static void sanitize_paths(struct repository *repo,\n \tif (skip_checks)\n \t\treturn;\n \n-\tif (prefix && *prefix && !core_sparse_checkout_cone)\n+\tif (prefix && *prefix && !cfg->core_sparse_checkout_cone)\n \t\tdie(_(\"please run from the toplevel directory in non-cone mode\"));\n \n-\tif (core_sparse_checkout_cone) {\n+\tif (cfg->core_sparse_checkout_cone) {\n \t\tfor (i = 0; i < args->nr; i++) {\n \t\t\tif (args->v[i][0] == '/')\n \t\t\t\tdie(_(\"specify directories rather than patterns (no leading slash)\"));\n@@ -769,7 +774,7 @@ static void sanitize_paths(struct repository *repo,\n \t\tif (S_ISSPARSEDIR(ce->ce_mode))\n \t\t\tcontinue;\n \n-\t\tif (core_sparse_checkout_cone)\n+\t\tif (cfg->core_sparse_checkout_cone)\n \t\t\tdie(_(\"'%s' is not a directory; to treat it as a directory anyway, rerun with --skip-checks\"), args->v[i]);\n \t\telse\n \t\t\twarning(_(\"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]);\n@@ -836,6 +841,7 @@ static struct sparse_checkout_set_opts {\n static int sparse_checkout_set(int argc, const char **argv, const char *prefix,\n \t\t\t       struct repository *repo)\n {\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \tint default_patterns_nr = 2;\n \tconst char *default_patterns[] = {\"/*\", \"!/*/\", NULL};\n \n@@ -873,7 +879,7 @@ static int sparse_checkout_set(int argc, const char **argv, const char *prefix,\n \t * non-cone mode, if nothing is specified, manually select just the\n \t * top-level directory (much as 'init' would do).\n \t */\n-\tif (!core_sparse_checkout_cone && !set_opts.use_stdin && argc == 0) {\n+\tif (!cfg->core_sparse_checkout_cone && !set_opts.use_stdin && argc == 0) {\n \t\tfor (int i = 0; i < default_patterns_nr; i++)\n \t\t\tstrvec_push(&patterns, default_patterns[i]);\n \t} else {\n@@ -977,7 +983,7 @@ static int sparse_checkout_clean(int argc, const char **argv,\n \tsetup_work_tree();\n \tif (!cfg->apply_sparse_checkout)\n \t\tdie(_(\"must be in a sparse-checkout to clean directories\"));\n-\tif (!core_sparse_checkout_cone)\n+\tif (!cfg->core_sparse_checkout_cone)\n \t\tdie(_(\"must be in a cone-mode sparse-checkout to clean directories\"));\n \n \targc = parse_options(argc, argv, prefix,\n@@ -1141,6 +1147,7 @@ static int sparse_checkout_check_rules(int argc, const char **argv, const char *\n \tFILE *fp;\n \tint ret;\n \tstruct pattern_list pl = {0};\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \tchar *sparse_filename;\n \tcheck_rules_opts.cone_mode = -1;\n \n@@ -1152,7 +1159,7 @@ static int sparse_checkout_check_rules(int argc, const char **argv, const char *\n \t\tcheck_rules_opts.cone_mode = 1;\n \n \tupdate_cone_mode(&check_rules_opts.cone_mode);\n-\tpl.use_cone_patterns = core_sparse_checkout_cone;\n+\tpl.use_cone_patterns = cfg->core_sparse_checkout_cone;\n \tif (check_rules_opts.rules_file) {\n \t\tfp = xfopen(check_rules_opts.rules_file, \"r\");\n \t\tadd_patterns_from_input(&pl, argc, argv, fp);\ndiff --git a/dir.c b/dir.c\nindex fcb8f6dd2a..4f493b64c6 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -3508,8 +3508,9 @@ int get_sparse_checkout_patterns(struct pattern_list *pl)\n {\n \tint res;\n \tchar *sparse_filename = get_sparse_checkout_filename();\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n-\tpl->use_cone_patterns = core_sparse_checkout_cone;\n+\tpl->use_cone_patterns = cfg->core_sparse_checkout_cone;\n \tres = add_patterns_from_file_to_list(sparse_filename, \"\", 0, pl, NULL, 0);\n \n \tfree(sparse_filename);\ndiff --git a/environment.c b/environment.c\nindex 739b647ebe..b0e873e9f5 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -70,7 +70,6 @@ enum push_default_type push_default = PUSH_DEFAULT_UNSPECIFIED;\n #endif\n enum object_creation_mode object_creation_mode = OBJECT_CREATION_MODE;\n int grafts_keep_true_parents;\n-int core_sparse_checkout_cone;\n int sparse_expect_files_outside_of_patterns;\n unsigned long pack_size_limit_cfg;\n \n@@ -526,7 +525,7 @@ int git_default_core_config(const char *var, const char *value,\n \t}\n \n \tif (!strcmp(var, \"core.sparsecheckoutcone\")) {\n-\t\tcore_sparse_checkout_cone = git_config_bool(var, value);\n+\t\tcfg->core_sparse_checkout_cone = git_config_bool(var, value);\n \t\treturn 0;\n \t}\n \n@@ -723,4 +722,5 @@ void repo_config_values_init(struct repo_config_values *cfg)\n \tcfg->zlib_compression_level = Z_BEST_SPEED;\n \tcfg->pack_compression_level = Z_DEFAULT_COMPRESSION;\n \tcfg->precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */\n+\tcfg->core_sparse_checkout_cone = 0;\n }\ndiff --git a/environment.h b/environment.h\nindex 508cb1afbc..befad9a388 100644\n--- a/environment.h\n+++ b/environment.h\n@@ -96,6 +96,7 @@ struct repo_config_values {\n \tint zlib_compression_level;\n \tint pack_compression_level;\n \tint precomposed_unicode;\n+\tint core_sparse_checkout_cone;\n \n \t/* section \"branch\" config values */\n \tenum branch_track branch_track;\n@@ -178,7 +179,6 @@ extern unsigned long pack_size_limit_cfg;\n extern int protect_hfs;\n extern int protect_ntfs;\n \n-extern int core_sparse_checkout_cone;\n extern int sparse_expect_files_outside_of_patterns;\n \n enum rebase_setup_type {\ndiff --git a/sparse-index.c b/sparse-index.c\nindex 13629c075d..53cb8d64fc 100644\n--- a/sparse-index.c\n+++ b/sparse-index.c\n@@ -154,7 +154,7 @@ int is_sparse_index_allowed(struct index_state *istate, int flags)\n {\n \tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n-\tif (!cfg->apply_sparse_checkout || !core_sparse_checkout_cone)\n+\tif (!cfg->apply_sparse_checkout || !cfg->core_sparse_checkout_cone)\n \t\treturn 0;\n \n \tif (!(flags & SPARSE_INDEX_MEMORY_ONLY)) {\n-- \n2.53.0.155.g9f36b15afa\n\n"},{"id":"544544","messageId":"20260602170921.35869-8-belkid98@gmail.com","threadId":"65344","inReplyTo":"20260602170921.35869-1-belkid98@gmail.com","subject":"[PATCH v5 7/8] environment: move \"sparse_expect_files_outside_of_patterns\" into `struct repo_config_values`","fromName":"Olamide Caleb Bello","fromEmail":"belkid98@gmail.com","sentAt":"2026-06-02T17:09:20Z","receivedAt":"2026-06-02T17:11:04Z","isPatch":true,"body":"The `core.sparseCheckoutExpectFilesOutsideOfPatterns` configuration was\npreviously stored in a global `int` variable, making it shared across\nrepository instances and risking cross‑repository state leakage.\n\nStore it instead in `repo_config_values`, where eagerly‑parsed\nrepository configuration lives. This option is parsed eagerly because\nit controls how sparse‑checkout paths are interpreted – a fundamental\nbehavior that many commands rely on; a lazy parse could cause\ninconsistent sparse‑checkout handling and complicate libification.\nThis preserves the existing behavior while tying the value to the\nrepository from which it was read, avoiding cross‑repository state\nleakage and continuing the effort to reduce reliance on global\nconfiguration state.\n\nUpdate all references to use `repo_config_values()`.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Usman Akinyemi <usmanakinyemi202@gmail.com>\nSigned-off-by: Olamide Caleb Bello <belkid98@gmail.com>\n---\n environment.c  | 6 ++++--\n environment.h  | 5 +++--\n sparse-index.c | 2 +-\n 3 files changed, 8 insertions(+), 5 deletions(-)\n\ndiff --git a/environment.c b/environment.c\nindex b0e873e9f5..57587ede56 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -70,7 +70,6 @@ enum push_default_type push_default = PUSH_DEFAULT_UNSPECIFIED;\n #endif\n enum object_creation_mode object_creation_mode = OBJECT_CREATION_MODE;\n int grafts_keep_true_parents;\n-int sparse_expect_files_outside_of_patterns;\n unsigned long pack_size_limit_cfg;\n \n #ifndef PROTECT_HFS_DEFAULT\n@@ -550,8 +549,10 @@ int git_default_core_config(const char *var, const char *value,\n \n static int git_default_sparse_config(const char *var, const char *value)\n {\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n+\n \tif (!strcmp(var, \"sparse.expectfilesoutsideofpatterns\")) {\n-\t\tsparse_expect_files_outside_of_patterns = git_config_bool(var, value);\n+\t\tcfg->sparse_expect_files_outside_of_patterns = git_config_bool(var, value);\n \t\treturn 0;\n \t}\n \n@@ -723,4 +724,5 @@ void repo_config_values_init(struct repo_config_values *cfg)\n \tcfg->pack_compression_level = Z_DEFAULT_COMPRESSION;\n \tcfg->precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */\n \tcfg->core_sparse_checkout_cone = 0;\n+\tcfg->sparse_expect_files_outside_of_patterns = 0;\n }\ndiff --git a/environment.h b/environment.h\nindex befad9a388..609cdaa07f 100644\n--- a/environment.h\n+++ b/environment.h\n@@ -98,6 +98,9 @@ struct repo_config_values {\n \tint precomposed_unicode;\n \tint core_sparse_checkout_cone;\n \n+\t/* section \"sparse\" config values */\n+\tint sparse_expect_files_outside_of_patterns;\n+\n \t/* section \"branch\" config values */\n \tenum branch_track branch_track;\n };\n@@ -179,8 +182,6 @@ extern unsigned long pack_size_limit_cfg;\n extern int protect_hfs;\n extern int protect_ntfs;\n \n-extern int sparse_expect_files_outside_of_patterns;\n-\n enum rebase_setup_type {\n \tAUTOREBASE_NEVER = 0,\n \tAUTOREBASE_LOCAL,\ndiff --git a/sparse-index.c b/sparse-index.c\nindex 53cb8d64fc..1ed769b78d 100644\n--- a/sparse-index.c\n+++ b/sparse-index.c\n@@ -675,7 +675,7 @@ void clear_skip_worktree_from_present_files(struct index_state *istate)\n \tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n \tif (!cfg->apply_sparse_checkout ||\n-\t    sparse_expect_files_outside_of_patterns)\n+\t    cfg->sparse_expect_files_outside_of_patterns)\n \t\treturn;\n \n \tif (clear_skip_worktree_from_present_files_sparse(istate)) {\n-- \n2.53.0.155.g9f36b15afa\n\n"},{"id":"544545","messageId":"20260602170921.35869-9-belkid98@gmail.com","threadId":"65344","inReplyTo":"20260602170921.35869-1-belkid98@gmail.com","subject":"[PATCH v5 8/8] environment: move \"warn_on_object_refname_ambiguity\" into `struct repo_config_values`","fromName":"Olamide Caleb Bello","fromEmail":"belkid98@gmail.com","sentAt":"2026-06-02T17:09:21Z","receivedAt":"2026-06-02T17:11:07Z","isPatch":true,"body":"The `core.warnAmbiguousRefs` configuration was previously stored in a\nglobal `int` variable, making it shared across repository instances\nand risking cross‑repository state leakage.\n\nStore it instead in `repo_config_values`, where eagerly‑parsed\nrepository configuration lives. This option is parsed eagerly because\nambiguity warnings influence how users interpret object references in\nmany commands; a lazy parse could cause these warnings to behave\ninconsistently or to appear for the wrong repository, confusing users\nand hindering libification. This preserves the existing behavior while\ntying the value to the repository from which it was read, avoiding\ncross‑repository state leakage and continuing the effort to reduce\nreliance on global configuration state.\n\nUpdate all references to use `repo_config_values()`.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Usman Akinyemi <usmanakinyemi202@gmail.com>\nSigned-off-by: Olamide Caleb Bello <belkid98@gmail.com>\n---\n builtin/cat-file.c     | 7 ++++---\n builtin/pack-objects.c | 7 ++++---\n environment.c          | 2 +-\n environment.h          | 2 +-\n object-name.c          | 3 ++-\n revision.c             | 7 ++++---\n submodule.c            | 7 ++++---\n 7 files changed, 20 insertions(+), 15 deletions(-)\n\ndiff --git a/builtin/cat-file.c b/builtin/cat-file.c\nindex d9fbad5358..cfc5430186 100644\n--- a/builtin/cat-file.c\n+++ b/builtin/cat-file.c\n@@ -901,6 +901,7 @@ static int batch_objects(struct batch_options *opt)\n \tstruct strbuf input = STRBUF_INIT;\n \tstruct strbuf output = STRBUF_INIT;\n \tstruct expand_data data = EXPAND_DATA_INIT;\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \tint save_warning;\n \tint retval = 0;\n \n@@ -973,8 +974,8 @@ static int batch_objects(struct batch_options *opt)\n \t * warn) ends up dwarfing the actual cost of the object lookups\n \t * themselves. We can work around it by just turning off the warning.\n \t */\n-\tsave_warning = warn_on_object_refname_ambiguity;\n-\twarn_on_object_refname_ambiguity = 0;\n+\tsave_warning = cfg->warn_on_object_refname_ambiguity;\n+\tcfg->warn_on_object_refname_ambiguity = 0;\n \n \tif (opt->batch_mode == BATCH_MODE_QUEUE_AND_DISPATCH) {\n \t\tbatch_objects_command(opt, &output, &data);\n@@ -1002,7 +1003,7 @@ static int batch_objects(struct batch_options *opt)\n  cleanup:\n \tstrbuf_release(&input);\n \tstrbuf_release(&output);\n-\twarn_on_object_refname_ambiguity = save_warning;\n+\tcfg->warn_on_object_refname_ambiguity = save_warning;\n \treturn retval;\n }\n \ndiff --git a/builtin/pack-objects.c b/builtin/pack-objects.c\nindex 8ccbe7e178..7df75fe91e 100644\n--- a/builtin/pack-objects.c\n+++ b/builtin/pack-objects.c\n@@ -4788,6 +4788,7 @@ static void get_object_list(struct rev_info *revs, struct strvec *argv)\n \tstruct setup_revision_opt s_r_opt = {\n \t\t.allow_exclude_promisor_objects = 1,\n \t};\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \tchar line[1000];\n \tint flags = 0;\n \tint save_warning;\n@@ -4798,8 +4799,8 @@ static void get_object_list(struct rev_info *revs, struct strvec *argv)\n \t/* make sure shallows are read */\n \tis_repository_shallow(the_repository);\n \n-\tsave_warning = warn_on_object_refname_ambiguity;\n-\twarn_on_object_refname_ambiguity = 0;\n+\tsave_warning = cfg->warn_on_object_refname_ambiguity;\n+\tcfg->warn_on_object_refname_ambiguity = 0;\n \n \twhile (fgets(line, sizeof(line), stdin) != NULL) {\n \t\tint len = strlen(line);\n@@ -4827,7 +4828,7 @@ static void get_object_list(struct rev_info *revs, struct strvec *argv)\n \t\t\tdie(_(\"bad revision '%s'\"), line);\n \t}\n \n-\twarn_on_object_refname_ambiguity = save_warning;\n+\tcfg->warn_on_object_refname_ambiguity = save_warning;\n \n \tif (use_bitmap_index && !get_object_list_from_bitmap(revs))\n \t\treturn;\ndiff --git a/environment.c b/environment.c\nindex 57587ede56..ba2c60103f 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -47,7 +47,6 @@ int minimum_abbrev = 4, default_abbrev = -1;\n int ignore_case;\n int assume_unchanged;\n int is_bare_repository_cfg = -1; /* unspecified */\n-int warn_on_object_refname_ambiguity = 1;\n char *git_commit_encoding;\n char *git_log_output_encoding;\n char *apply_default_whitespace;\n@@ -725,4 +724,5 @@ void repo_config_values_init(struct repo_config_values *cfg)\n \tcfg->precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */\n \tcfg->core_sparse_checkout_cone = 0;\n \tcfg->sparse_expect_files_outside_of_patterns = 0;\n+\tcfg->warn_on_object_refname_ambiguity = 1;\n }\ndiff --git a/environment.h b/environment.h\nindex 609cdaa07f..1ff0a7ba8b 100644\n--- a/environment.h\n+++ b/environment.h\n@@ -97,6 +97,7 @@ struct repo_config_values {\n \tint pack_compression_level;\n \tint precomposed_unicode;\n \tint core_sparse_checkout_cone;\n+\tint warn_on_object_refname_ambiguity;\n \n \t/* section \"sparse\" config values */\n \tint sparse_expect_files_outside_of_patterns;\n@@ -174,7 +175,6 @@ extern int has_symlinks;\n extern int minimum_abbrev, default_abbrev;\n extern int ignore_case;\n extern int assume_unchanged;\n-extern int warn_on_object_refname_ambiguity;\n extern char *apply_default_whitespace;\n extern char *apply_default_ignorewhitespace;\n extern unsigned long pack_size_limit_cfg;\ndiff --git a/object-name.c b/object-name.c\nindex 21dcdc4a0e..319d3db01d 100644\n--- a/object-name.c\n+++ b/object-name.c\n@@ -684,11 +684,12 @@ static int get_oid_basic(struct repository *r, const char *str, int len,\n \tint refs_found = 0;\n \tint at, reflog_len, nth_prior = 0;\n \tint fatal = !(flags & GET_OID_QUIETLY);\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n \tif (len == r->hash_algo->hexsz && !get_oid_hex(str, oid)) {\n \t\tif (!(flags & GET_OID_SKIP_AMBIGUITY_CHECK) &&\n \t\t    repo_settings_get_warn_ambiguous_refs(r) &&\n-\t\t    warn_on_object_refname_ambiguity) {\n+\t\t    cfg->warn_on_object_refname_ambiguity) {\n \t\t\trefs_found = repo_dwim_ref(r, str, len, &tmp_oid, &real_ref, 0);\n \t\t\tif (refs_found > 0) {\n \t\t\t\twarning(warn_msg, len, str);\ndiff --git a/revision.c b/revision.c\nindex 599b3a66c3..4e7faa7eb1 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -2922,9 +2922,10 @@ static void read_revisions_from_stdin(struct rev_info *revs,\n \tint seen_end_of_options = 0;\n \tint save_warning;\n \tint flags = 0;\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n-\tsave_warning = warn_on_object_refname_ambiguity;\n-\twarn_on_object_refname_ambiguity = 0;\n+\tsave_warning = cfg->warn_on_object_refname_ambiguity;\n+\tcfg->warn_on_object_refname_ambiguity = 0;\n \n \tstrbuf_init(&sb, 1000);\n \twhile (strbuf_getline(&sb, stdin) != EOF) {\n@@ -2958,7 +2959,7 @@ static void read_revisions_from_stdin(struct rev_info *revs,\n \t\tread_pathspec_from_stdin(&sb, prune);\n \n \tstrbuf_release(&sb);\n-\twarn_on_object_refname_ambiguity = save_warning;\n+\tcfg->warn_on_object_refname_ambiguity = save_warning;\n }\n \n static void NORETURN diagnose_missing_default(const char *def)\ndiff --git a/submodule.c b/submodule.c\nindex b1a0363f9d..f26235bbb7 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -898,12 +898,13 @@ static void collect_changed_submodules(struct repository *r,\n \tstruct setup_revision_opt s_r_opt = {\n \t\t.assume_dashdash = 1,\n \t};\n+\tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n-\tsave_warning = warn_on_object_refname_ambiguity;\n-\twarn_on_object_refname_ambiguity = 0;\n+\tsave_warning = cfg->warn_on_object_refname_ambiguity;\n+\tcfg->warn_on_object_refname_ambiguity = 0;\n \trepo_init_revisions(r, &rev, NULL);\n \tsetup_revisions_from_strvec(argv, &rev, &s_r_opt);\n-\twarn_on_object_refname_ambiguity = save_warning;\n+\tcfg->warn_on_object_refname_ambiguity = save_warning;\n \tif (prepare_revision_walk(&rev))\n \t\tdie(_(\"revision walk setup failed\"));\n \n-- \n2.53.0.155.g9f36b15afa\n\n"}]}