]> git.ipfire.org Git - thirdparty/git.git/commitdiff
environment: move has_symlinks into repo_config_values
authorTian Yuchen <cat@malon.dev>
Mon, 20 Jul 2026 10:53:35 +0000 (18:53 +0800)
committerJunio C Hamano <gitster@pobox.com>
Mon, 20 Jul 2026 14:37:05 +0000 (07:37 -0700)
Move the global 'has_symlinks' configuration into the
repository-specific 'repo_config_values' struct.

Introduce 'repo_has_symlinks()' getter for readability.
Callers access this configuration by passing in 'repo'
when possible, and explicitly fall back to
'the_repository' the rest of the time.

Introduce 'platform_has_symlinks()' macro to allow
platform specific-customization, primarily to help MinGW.
Platforms can override this in their respective headers.

Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Ayush Chandekar <ayu.chandekar@gmail.com>
Mentored-by: Olamide Caleb Bello <belkid98@gmail.com>
Signed-off-by: Tian Yuchen <cat@malon.dev>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
apply.c
combine-diff.c
compat/mingw.c
compat/mingw.h
entry.c
environment.c
environment.h
git-compat-util.h
read-cache.c
read-cache.h

diff --git a/apply.c b/apply.c
index edb1502414e4be33d176e2a2c5e6e9a6c6cfb373..b748192ee2c1f674524f1c944f67903f3a753988 100644 (file)
--- 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.
                 */
index b7998620687ed796306c306029e6f29f2eec44c0..80e5c46e9b26ffca60a8e585b855d54824488628 100644 (file)
@@ -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)
index aa7525f419cb642d5b3a28f93c55d09517af8e2c..47819119292d8e4795e755a2847de96cb1eda8d3 100644 (file)
@@ -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;
        }
@@ -3173,15 +3174,23 @@ static void setup_windows_environment(void)
                if (!tmp && (tmp = getenv("USERPROFILE")))
                        setenv("HOME", tmp, 1);
        }
+}
 
+int mingw_platform_has_symlinks(void)
+{
+       static int has_symlinks = -1;
        /*
         * Change 'core.symlinks' default to false, unless native symlinks are
         * enabled in MSys2 (via 'MSYS=winsymlinks:nativestrict'). Thus we can
         * run the test suite (which doesn't obey config files) with or without
         * symlink support.
         */
-       if (!(tmp = getenv("MSYS")) || !strstr(tmp, "winsymlinks:nativestrict"))
-               has_symlinks = 0;
+       if (has_symlinks < 0) {
+               const char *tmp = getenv("MSYS");
+               has_symlinks = (tmp && strstr(tmp, "winsymlinks:nativestrict")) ? 1 : 0;
+       }
+
+       return has_symlinks;
 }
 
 static void get_current_user_sid(PSID *sid, HANDLE *linked_token)
index 444daedfa524692e3b0b19ef7e988eb280069834..df02aeb632d8c30de88ba4a2638addd294dbe79c 100644 (file)
@@ -208,6 +208,9 @@ void open_in_gdb(void);
  */
 int err_win_to_posix(DWORD winerr);
 
+int mingw_platform_has_symlinks(void);
+#define platform_has_symlinks() mingw_platform_has_symlinks()
+
 #ifndef NO_UNIX_SOCKETS
 int mingw_have_unix_sockets(void);
 #undef have_unix_sockets
diff --git a/entry.c b/entry.c
index 7817aee362ed9e7e14e3a2b92c9cc0ab5f013673..5913a8b51f1895fc7dc1bb2a991403109912922f 100644 (file)
--- a/entry.c
+++ b/entry.c
@@ -321,7 +321,8 @@ 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 ?
+                                      state->istate->repo : the_repository) || to_tempfile)
                        goto write_file_entry;
 
                ret = symlink(new_blob, path);
index 32b110c40505bee6a4bdd0723a7113e906ede566..e351043446001d2ba6045427b02e930fef585614 100644 (file)
@@ -43,7 +43,6 @@ static int zlib_compression_seen;
 
 int trust_ctime = 1;
 int check_stat = 1;
-int has_symlinks = 1;
 int minimum_abbrev = 4, default_abbrev = -1;
 int ignore_case;
 int assume_unchanged;
@@ -148,6 +147,13 @@ int repo_trust_executable_bit(struct repository *repo)
                : 1;
 }
 
+int repo_has_symlinks(struct repository *repo)
+{
+       return repo->initialized
+               ? repo_config_values(repo)->has_symlinks
+               : platform_has_symlinks();
+}
+
 int have_git_dir(void)
 {
        return startup_info->have_repository
@@ -336,7 +342,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 +734,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 = platform_has_symlinks();
        cfg->branch_track = BRANCH_TRACK_REMOTE;
 }
index c15456fc0d0b39f49b5a26ba8f1b88181f37c881..8f54c481e92a06d1f4076b67047a8b8da130cb1e 100644 (file)
@@ -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);
 
 /*
@@ -163,7 +166,6 @@ 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 minimum_abbrev, default_abbrev;
 extern int ignore_case;
 extern int assume_unchanged;
index 88097764078538aeb04d8b9a3dc4326a1203a3ad..a0f901ce793ed62633a65842d22d8f829db7fb00 100644 (file)
@@ -245,6 +245,10 @@ static inline int git_is_dir_sep(int c)
 #define is_dir_sep git_is_dir_sep
 #endif
 
+#ifndef platform_has_symlinks
+#define platform_has_symlinks() 1
+#endif
+
 #ifndef offset_1st_component
 static inline int git_offset_1st_component(const char *path)
 {
index 90789ff049edd0499dd7fc1a23a7f74291273604..046b1e649e75522c718479713e29e11a46e4ae92 100644 (file)
@@ -207,7 +207,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:
@@ -325,7 +325,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:
@@ -740,7 +740,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
index 4b54cfc57c8de0c751491db83862aec2a37736ed..ab9d40aa81f95e791304ceaed81400ff73c861e8 100644 (file)
@@ -17,8 +17,7 @@ static inline unsigned int ce_mode_from_stat(struct repository *repo,
                                             const struct cache_entry *ce,
                                             unsigned int mode)
 {
-       extern int has_symlinks;
-       if (S_ISREG(mode) && !has_symlinks &&
+       if (S_ISREG(mode) && !repo_has_symlinks(repo) &&
            ce && S_ISLNK(ce->ce_mode))
                return ce->ce_mode;
        if (S_ISREG(mode) && !repo_trust_executable_bit(repo)) {