environment: move "precomposed_unicode" into `struct repo_config_values`

The `core.precomposeunicode` configuration is currently stored in the global variable `precomposed_unicode`, which makes it shared across repository instances within a single process. Store it instead in `repo_config_values`, where eagerly‑parsed repository configuration lives. `core.precomposeunicode` is parsed eagerly because it controls Unicode path normalization on macOS, a fundamental filesystem‑level behavior that many operations depend on; a lazy parse could lead to inconsistent results and hamper libification. This preserves the existing behavior while tying the value to the repository from which it was read, avoiding cross‑ repository state leakage and continuing the effort to reduce reliance on global configuration state. Update all references to use `repo_config_values()`. Mentored-by: Christian Couder <christian.couder@gmail.com> Mentored-by: Usman Akinyemi <usmanakinyemi202@gmail.com> Signed-off-by: Olamide Caleb Bello <belkid98@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Olamide Caleb Bello committed Jun 2, 2026 at 18:09 UTC 6f00fc0499851d33ef6eae3f8633cb67808834aa
4 files changed +18 -11
compat/precompose_utf8.c
+13 -7
@@ -48,16 +48,18 @@ void probe_utf8_pathname_composition(void)
48 static const char *auml_nfc = "\xc3\xa4";
49 static const char *auml_nfd = "\x61\xcc\x88";
50 int output_fd;
51 - if (precomposed_unicode != -1)
51 + struct repo_config_values *cfg = repo_config_values(the_repository);
52 +
53 + if (cfg->precomposed_unicode != -1)
54 return; /* We found it defined in the global config, respect it */
55 repo_git_path_replace(the_repository, &path, "%s", auml_nfc);
56 output_fd = open(path.buf, O_CREAT|O_EXCL|O_RDWR, 0600);
57 if (output_fd >= 0) {
58 close(output_fd);
59 repo_git_path_replace(the_repository, &path, "%s", auml_nfd);
58 - precomposed_unicode = access(path.buf, R_OK) ? 0 : 1;
60 + cfg->precomposed_unicode = access(path.buf, R_OK) ? 0 : 1;
61 repo_config_set(the_repository, "core.precomposeunicode",
60 - precomposed_unicode ? "true" : "false");
62 + cfg->precomposed_unicode ? "true" : "false");
63 repo_git_path_replace(the_repository, &path, "%s", auml_nfc);
64 if (unlink(path.buf))
65 die_errno(_("failed to unlink '%s'"), path.buf);
@@ -69,14 +71,16 @@ const char *precompose_string_if_needed(const char *in)
71 {
72 size_t inlen;
73 size_t outlen;
74 + struct repo_config_values *cfg = repo_config_values(the_repository);
75 +
76 if (!in)
77 return NULL;
78 if (has_non_ascii(in, (size_t)-1, &inlen)) {
79 iconv_t ic_prec;
80 char *out;
77 - if (precomposed_unicode < 0)
78 - repo_config_get_bool(the_repository, "core.precomposeunicode", &precomposed_unicode);
79 - if (precomposed_unicode != 1)
81 + if (cfg->precomposed_unicode < 0)
82 + repo_config_get_bool(the_repository, "core.precomposeunicode", &cfg->precomposed_unicode);
83 + if (cfg->precomposed_unicode != 1)
84 return in;
85 ic_prec = iconv_open(repo_encoding, path_encoding);
86 if (ic_prec == (iconv_t) -1)
@@ -130,7 +134,9 @@ PREC_DIR *precompose_utf8_opendir(const char *dirname)
134
135 struct dirent_prec_psx *precompose_utf8_readdir(PREC_DIR *prec_dir)
136 {
137 + struct repo_config_values *cfg = repo_config_values(the_repository);
138 struct dirent *res;
139 +
140 res = readdir(prec_dir->dirp);
141 if (res) {
142 size_t namelenz = strlen(res->d_name) + 1; /* \0 */
@@ -149,7 +155,7 @@ struct dirent_prec_psx *precompose_utf8_readdir(PREC_DIR *prec_dir)
155 prec_dir->dirent_nfc->d_ino = res->d_ino;
156 prec_dir->dirent_nfc->d_type = res->d_type;
157
152 - if ((precomposed_unicode == 1) && has_non_ascii(res->d_name, (size_t)-1, NULL)) {
158 + if ((cfg->precomposed_unicode == 1) && has_non_ascii(res->d_name, (size_t)-1, NULL)) {
159 if (prec_dir->ic_precompose == (iconv_t)-1) {
160 die("iconv_open(%s,%s) failed, but needed:\n"
161 " precomposed unicode is not supported.\n"
environment.c
+2 -2
@@ -72,7 +72,6 @@ enum object_creation_mode object_creation_mode = OBJECT_CREATION_MODE;
72 int grafts_keep_true_parents;
73 int core_sparse_checkout_cone;
74 int sparse_expect_files_outside_of_patterns;
75 -int precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */
75 unsigned long pack_size_limit_cfg;
76
77 #ifndef PROTECT_HFS_DEFAULT
@@ -532,7 +531,7 @@ int git_default_core_config(const char *var, const char *value,
531 }
532
533 if (!strcmp(var, "core.precomposeunicode")) {
535 - precomposed_unicode = git_config_bool(var, value);
534 + cfg->precomposed_unicode = git_config_bool(var, value);
535 return 0;
536 }
537
@@ -723,4 +722,5 @@ void repo_config_values_init(struct repo_config_values *cfg)
722 cfg->check_stat = 1;
723 cfg->zlib_compression_level = Z_BEST_SPEED;
724 cfg->pack_compression_level = Z_DEFAULT_COMPRESSION;
725 + cfg->precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */
726 }
environment.h
+1 -1
@@ -95,6 +95,7 @@ struct repo_config_values {
95 int check_stat;
96 int zlib_compression_level;
97 int pack_compression_level;
98 + int precomposed_unicode;
99
100 /* section "branch" config values */
101 enum branch_track branch_track;
@@ -174,7 +175,6 @@ extern char *apply_default_whitespace;
175 extern char *apply_default_ignorewhitespace;
176 extern unsigned long pack_size_limit_cfg;
177
177 -extern int precomposed_unicode;
178 extern int protect_hfs;
179 extern int protect_ntfs;
180
upload-pack.c
+2 -1
@@ -1336,6 +1336,7 @@ static int upload_pack_config(const char *var, const char *value,
1336 void *cb_data)
1337 {
1338 struct upload_pack_data *data = cb_data;
1339 + struct repo_config_values *cfg = repo_config_values(the_repository);
1340
1341 if (!strcmp("uploadpack.allowtipsha1inwant", var)) {
1342 if (git_config_bool(var, value))
@@ -1366,7 +1367,7 @@ static int upload_pack_config(const char *var, const char *value,
1367 if (value)
1368 data->allow_packfile_uris = 1;
1369 } else if (!strcmp("core.precomposeunicode", var)) {
1369 - precomposed_unicode = git_config_bool(var, value);
1370 + cfg->precomposed_unicode = git_config_bool(var, value);
1371 } else if (!strcmp("transfer.advertisesid", var)) {
1372 data->advertise_sid = git_config_bool(var, value);
1373 }