git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH v5 4/4] environment: move has_symlinks into repo_config_values

From
Tian Yuchen <cat@malon.dev>
Date
Jul 15, 2026, 03:55 UTC
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 <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>
---
 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
Previous: Tian YuchenNext: Christian Couder
Message 36 of 62 in “environment.c: migrate 'trust_executable_bit' into 'repo_config_values'”
  1. 0/4 environment.c: migrate 'trust_executable_bit' into 'repo_config_values'Tian Yuchen, May 30, 2026
  2. 2/4 read-cache: move 'ce_mode_from_stat()' to 'read-cache.c'Tian Yuchen, May 30, 2026
  3. Patrick SteinhardtJun 4, 2026
  4. Tian YuchenJun 10, 2026
  5. 3/4 environment: move 'trust_executable_bit' into repo_config_valuesTian Yuchen, May 30, 2026
  6. Christian CouderMay 30, 2026
  7. Junio C HamanoMay 30, 2026
  8. Tian YuchenJun 1, 2026
  9. Tian YuchenJun 1, 2026
  10. Junio C HamanoJun 9, 2026
  11. 4/4 read-cache: pass 'istate' to stat/mode helper functionsTian Yuchen, May 30, 2026
  12. Christian CouderMay 30, 2026
  13. 1/4 read-cache: remove redundant extern declarationsTian Yuchen, May 30, 2026
  14. 0/3 environment: migrate 'trust_executable_bit' into 'repo_config_values'Tian Yuchen, Jun 10, 2026
  15. 1/3 read-cache: remove redundant extern declarationsTian Yuchen, Jun 10, 2026
  16. 2/3 read-cache: move 'ce_mode_from_stat()' to 'read-cache.c'Tian Yuchen, Jun 10, 2026
  17. Christian CouderJun 12, 2026
  18. 3/3 environment: move trust_executable_bit into repo_config_valuesTian Yuchen, Jun 10, 2026
  19. Tian YuchenJun 11, 2026
  20. Christian CouderJun 12, 2026
  21. Junio C HamanoJun 12, 2026
  22. 0/3 environment: migrate 'trust_executable_bit' into 'repo_config_values'Tian Yuchen, Jun 12, 2026
  23. 2/3 read-cache: move 'ce_mode_from_stat()' to 'read-cache.c'Tian Yuchen, Jun 12, 2026
  24. 1/3 read-cache: remove redundant extern declarationsTian Yuchen, Jun 12, 2026
  25. 3/3 environment: move trust_executable_bit into repo_config_valuesTian Yuchen, Jun 12, 2026
  26. 0/3 environment: migrate 'trust_executable_bit' into 'repo_config_values'Tian Yuchen, Jun 19, 2026
  27. 1/3 read-cache: remove redundant extern declarationsTian Yuchen, Jun 19, 2026
  28. 2/3 read-cache: move 'ce_mode_from_stat()' to 'read-cache.c'Tian Yuchen, Jun 19, 2026
  29. 3/3 environment: move trust_executable_bit into repo_config_valuesTian Yuchen, Jun 19, 2026
  30. Junio C HamanoJun 29, 2026
  31. Tian YuchenJul 15, 2026
  32. 0/4 environment: migrate 'trust_executable_bit' and 'has_symlinks' into 'repo_config_values'Tian Yuchen, Jul 15, 2026
  33. 1/4 read-cache: remove redundant extern declarationsTian Yuchen, Jul 15, 2026
  34. 2/4 read-cache: move 'ce_mode_from_stat()' to 'read-cache.c'Tian Yuchen, Jul 15, 2026
  35. 3/4 environment: move trust_executable_bit into repo_config_valuesTian Yuchen, Jul 15, 2026
  36. 4/4 environment: move has_symlinks into repo_config_valuesTian Yuchen, Jul 15, 2026
  37. Christian CouderJul 15, 2026
  38. Junio C HamanoJul 15, 2026
  39. Junio C HamanoJul 15, 2026
  40. 0/4 environment: migrate 'trust_executable_bit' and 'has_symlinks' into 'repo_config_values'Tian Yuchen, Jul 16, 2026
  41. 1/4 read-cache: remove redundant extern declarationsTian Yuchen, Jul 16, 2026
  42. 2/4 read-cache: move 'ce_mode_from_stat()' to 'read-cache.c'Tian Yuchen, Jul 16, 2026
  43. Junio C HamanoJul 16, 2026
  44. 3/4 environment: move trust_executable_bit into repo_config_valuesTian Yuchen, Jul 16, 2026
  45. 4/4 environment: move has_symlinks into repo_config_valuesTian Yuchen, Jul 16, 2026
  46. Junio C HamanoJul 16, 2026
  47. 0/4 environment: migrate 'trust_executable_bit' and 'has_symlinks' into 'repo_config_values'Tian Yuchen, Jul 17, 2026
  48. 2/4 read-cache: pass 'repo' to 'ce_mode_from_stat()'Tian Yuchen, Jul 17, 2026
  49. SZEDER GáborJul 18, 2026
  50. Tian YuchenJul 20, 2026
  51. SZEDER GáborJul 20, 2026
  52. Tian YuchenJul 20, 2026
  53. 1/4 read-cache: remove redundant extern declarationsTian Yuchen, Jul 17, 2026
  54. 3/4 environment: move trust_executable_bit into repo_config_valuesTian Yuchen, Jul 17, 2026
  55. Junio C HamanoJul 17, 2026
  56. Tian YuchenJul 20, 2026
  57. 4/4 environment: move has_symlinks into repo_config_valuesTian Yuchen, Jul 17, 2026
  58. 0/4 environment: migrate 'trust_executable_bit' and 'has_symlinks' into 'repo_config_values'Tian Yuchen, Jul 20, 2026
  59. 1/4 read-cache: remove redundant extern declarationsTian Yuchen, Jul 20, 2026
  60. 2/4 read-cache: pass 'repo' to 'ce_mode_from_stat()'Tian Yuchen, Jul 20, 2026
  61. 3/4 environment: move trust_executable_bit into repo_config_valuesTian Yuchen, Jul 20, 2026
  62. 4/4 environment: move has_symlinks into repo_config_valuesTian Yuchen, Jul 20, 2026

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.