From: Tian Yuchen Date: Wed, 15 Jul 2026 03:55:01 GMT Subject: [PATCH v5 4/4] environment: move has_symlinks into repo_config_values Message-ID: <20260715035501.48271-5-cat@malon.dev> In-Reply-To: <20260715035501.48271-1-cat@malon.dev> Move the global 'has_symlinks' configuration into the repository-specific 'repo_config_values' struct. To ensure code readability, the getter function 'repo_has_symlinks()' has been introduced. Callers access this configuration by passing in 'repo' when possible, and explicitly fall back to 'the_repository' the rest of the time. Note: To support early platform-specific (MinGW) overrides before repository initialization, a global variable 'default_has_symlinks' fallback is introduced as a fallback in environment.h. The *writer* in compat/mingw.c can only access this variable. Mentored-by: Christian Couder Mentored-by: Ayush Chandekar Mentored-by: Olamide Caleb Bello Signed-off-by: Tian Yuchen --- apply.c | 2 +- combine-diff.c | 2 +- compat/mingw.c | 7 ++++--- entry.c | 2 +- environment.c | 17 +++++++++++++++-- environment.h | 5 ++++- read-cache.c | 9 +++++---- 7 files changed, 31 insertions(+), 13 deletions(-) diff --git a/apply.c b/apply.c index 47b6ae5904..4ce4160b48 100644 --- a/apply.c +++ b/apply.c @@ -4511,7 +4511,7 @@ static int try_create_file(struct apply_state *state, const char *path, return !!mkdir(path, 0777); } - if (has_symlinks && S_ISLNK(mode)) + if (repo_has_symlinks(state->repo) && S_ISLNK(mode)) /* Although buf:size is counted string, it also is NUL * terminated. */ diff --git a/combine-diff.c b/combine-diff.c index b799862068..80e5c46e9b 100644 --- a/combine-diff.c +++ b/combine-diff.c @@ -1078,7 +1078,7 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent, /* if symlinks don't work, assume symlink if all parents * are symlinks */ - is_file = has_symlinks; + is_file = repo_has_symlinks(rev->repo); for (i = 0; !is_file && i < num_parent; i++) is_file = !S_ISLNK(elem->parent[i].mode); if (!is_file) diff --git a/compat/mingw.c b/compat/mingw.c index aa7525f419..b38cd9a1ec 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -7,6 +7,7 @@ #include "config.h" #include "dir.h" #include "environment.h" +#include "repository.h" #include "gettext.h" #include "run-command.h" #include "strbuf.h" @@ -1043,7 +1044,7 @@ int mingw_chdir(const char *dirname) if (xutftowcs_path(wdirname, dirname) < 0) return -1; - if (has_symlinks) { + if (repo_has_symlinks(the_repository)) { HANDLE hnd = CreateFileW(wdirname, 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); @@ -2903,7 +2904,7 @@ int symlink(const char *target, const char *link) int len; /* fail if symlinks are disabled or API is not supported (WinXP) */ - if (!has_symlinks) { + if (!repo_has_symlinks(the_repository)) { errno = ENOSYS; return -1; } @@ -3181,7 +3182,7 @@ static void setup_windows_environment(void) * symlink support. */ if (!(tmp = getenv("MSYS")) || !strstr(tmp, "winsymlinks:nativestrict")) - has_symlinks = 0; + default_has_symlinks = 0; } static void get_current_user_sid(PSID *sid, HANDLE *linked_token) diff --git a/entry.c b/entry.c index 7817aee362..f2854b4cd8 100644 --- a/entry.c +++ b/entry.c @@ -321,7 +321,7 @@ static int write_entry(struct cache_entry *ce, char *path, struct conv_attrs *ca * We can't make a real symlink; write out a regular file entry * with the symlink destination as its contents. */ - if (!has_symlinks || to_tempfile) + if (!repo_has_symlinks(state->istate ? state->istate->repo : NULL) || to_tempfile) goto write_file_entry; ret = symlink(new_blob, path); diff --git a/environment.c b/environment.c index 75069a884d..c7cebe18fd 100644 --- a/environment.c +++ b/environment.c @@ -43,7 +43,7 @@ static int zlib_compression_seen; int trust_ctime = 1; int check_stat = 1; -int has_symlinks = 1; +int default_has_symlinks = 1; int minimum_abbrev = 4, default_abbrev = -1; int ignore_case; int assume_unchanged; @@ -148,6 +148,17 @@ int repo_trust_executable_bit(struct repository *repo) 1; } +int repo_has_symlinks(struct repository *repo) +{ + if (!repo) + repo = the_repository; + + if (!repo->gitdir) + return default_has_symlinks; + + return repo_config_values(repo)->has_symlinks; +} + int have_git_dir(void) { return startup_info->have_repository @@ -336,7 +347,8 @@ int git_default_core_config(const char *var, const char *value, } if (!strcmp(var, "core.symlinks")) { - has_symlinks = git_config_bool(var, value); + struct repo_config_values *cfg = repo_config_values(the_repository); + cfg->has_symlinks = git_config_bool(var, value); return 0; } @@ -727,5 +739,6 @@ void repo_config_values_init(struct repo_config_values *cfg) cfg->attributes_file = NULL; cfg->apply_sparse_checkout = 0; cfg->trust_executable_bit = 1; + cfg->has_symlinks = default_has_symlinks; cfg->branch_track = BRANCH_TRACK_REMOTE; } diff --git a/environment.h b/environment.h index 72b59fd89c..e590225c86 100644 --- a/environment.h +++ b/environment.h @@ -92,6 +92,7 @@ struct repo_config_values { char *attributes_file; int apply_sparse_checkout; int trust_executable_bit; + int has_symlinks; /* section "branch" config values */ enum branch_track branch_track; @@ -126,6 +127,8 @@ int git_default_core_config(const char *var, const char *value, int repo_trust_executable_bit(struct repository *repo); +int repo_has_symlinks(struct repository *repo); + void repo_config_values_init(struct repo_config_values *cfg); /* @@ -165,7 +168,7 @@ extern char *git_work_tree_cfg; /* Environment bits from configuration mechanism */ extern int trust_ctime; extern int check_stat; -extern int has_symlinks; +extern int default_has_symlinks; extern int minimum_abbrev, default_abbrev; extern int ignore_case; extern int assume_unchanged; diff --git a/read-cache.c b/read-cache.c index a9c11a3346..5a40ffa061 100644 --- a/read-cache.c +++ b/read-cache.c @@ -211,7 +211,7 @@ void fill_stat_cache_info(struct index_state *istate, struct cache_entry *ce, st */ unsigned int ce_mode_from_stat(const struct cache_entry *ce, unsigned int mode) { - if (!has_symlinks && S_ISREG(mode) && + if (!repo_has_symlinks(the_repository) && S_ISREG(mode) && ce && S_ISLNK(ce->ce_mode)) return ce->ce_mode; if (!repo_trust_executable_bit(the_repository) && S_ISREG(mode)) { @@ -226,7 +226,7 @@ static unsigned int st_mode_from_ce(const struct cache_entry *ce) { switch (ce->ce_mode & S_IFMT) { case S_IFLNK: - return has_symlinks ? S_IFLNK : (S_IFREG | 0644); + return repo_has_symlinks(the_repository) ? S_IFLNK : (S_IFREG | 0644); case S_IFREG: return (ce->ce_mode & (repo_trust_executable_bit(the_repository) ? 0755 : 0644)) | S_IFREG; case S_IFGITLINK: @@ -344,7 +344,7 @@ static int ce_match_stat_basic(const struct cache_entry *ce, struct stat *st) break; case S_IFLNK: if (!S_ISLNK(st->st_mode) && - (has_symlinks || !S_ISREG(st->st_mode))) + (repo_has_symlinks(the_repository) || !S_ISREG(st->st_mode))) changed |= TYPE_CHANGED; break; case S_IFGITLINK: @@ -759,7 +759,8 @@ int add_to_index(struct index_state *istate, const char *path, struct stat *st, ce->ce_flags |= CE_INTENT_TO_ADD; - if (repo_trust_executable_bit(istate->repo) && has_symlinks) { + if (repo_trust_executable_bit(istate->repo) && + repo_has_symlinks(istate->repo)) { ce->ce_mode = create_ce_mode(st_mode); } else { /* If there is an existing entry, pick the mode bits and type -- 2.43.0