{"thread":{"id":"65179","subject":"[PATCH 1/3] Refactor 'trust_executable_bit' to repository-scoped setting","startedAt":"2026-03-09T16:57:07Z","lastAt":"2026-03-09T16:57:07Z","messageCount":1,"participants":["drona"],"isPatch":true,"patchVersion":1,"patchTotal":3},"messages":[{"id":"538298","messageId":"20260309165052.13002-1-dronarajgyawali@gmail.com","threadId":"65179","inReplyTo":null,"subject":"[PATCH 1/3] Refactor 'trust_executable_bit' to repository-scoped setting","fromName":"drona","fromEmail":"dronarajgyawali@gmail.com","sentAt":"2026-03-09T16:50:49Z","receivedAt":"2026-03-09T16:57:07Z","isPatch":true,"sender":{"key":"dronarajgyawali@gmail.com","avatar":null},"body":"From: Dorna Raj Gyawali <dronarajgyawali@gmail.com>\n\nCurrently, 'trust_executable_bit' is a global variable in environment.c,\nwhich controls how executable bits are interpreted when creating/updating\ncache entries.\n\nThis patch moves 'trust_executable_bit' into 'struct repo_settings', making\nit a repository-scoped configuration. All references in files have been updated to use\n'the_repository->settings.trust_executable_bit'.\n\nWhy this is a good candidate:\n- It's a self-contained global variable that only affects file mode logic.\n- Low risk: changes only impact mode calculations and related apply/update\n  operations.\n- Makes Git codebase more maintainable and prepares for future multi-repo\n  support.\n\n- Manual sanity check with a test repo confirms executable bits behave correctly.\n\nSigned-off-by: Dorna Raj Gyawali <dronarajgyawali@gmail.com>\n---\n apply.c                |  4 ++--\n builtin/update-index.c |  2 +-\n diff-lib.c             | 10 +++++-----\n environment.c          |  3 +--\n environment.h          |  1 -\n read-cache.c           | 10 +++++-----\n read-cache.h           | 11 +++++++----\n repo-settings.h        |  6 +++++-\n 8 files changed, 26 insertions(+), 21 deletions(-)\n\ndiff --git a/apply.c b/apply.c\nindex d044c95d50..2bcb22a4bc 100644\n--- a/apply.c\n+++ b/apply.c\n@@ -3838,8 +3838,8 @@ static int check_preimage(struct apply_state *state,\n \t\tif (*ce && !(*ce)->ce_mode)\n \t\t\tBUG(\"ce_mode == 0 for path '%s'\", old_name);\n \n-\t\tif (trust_executable_bit || !S_ISREG(st->st_mode))\n-\t\t\tst_mode = ce_mode_from_stat(*ce, st->st_mode);\n+\t\tif (the_repository->settings.trust_executable_bit  || !S_ISREG(st->st_mode))\n+\t\t\tst_mode = ce_mode_from_stat(the_repository, *ce, st->st_mode);\n \t\telse if (*ce)\n \t\t\tst_mode = (*ce)->ce_mode;\n \t\telse\ndiff --git a/builtin/update-index.c b/builtin/update-index.c\nindex 8a5907767b..7917bd286f 100644\n--- a/builtin/update-index.c\n+++ b/builtin/update-index.c\n@@ -293,7 +293,7 @@ static int add_one_path(const struct cache_entry *old, const char *path, int len\n \tce->ce_flags = create_ce_flags(0);\n \tce->ce_namelen = len;\n \tfill_stat_cache_info(the_repository->index, ce, st);\n-\tce->ce_mode = ce_mode_from_stat(old, st->st_mode);\n+\tce->ce_mode = ce_mode_from_stat(the_repository, old, st->st_mode);\n \n \tif (index_path(the_repository->index, &ce->oid, path, st,\n \t\t       info_only ? 0 : INDEX_WRITE_OBJECT)) {\ndiff --git a/diff-lib.c b/diff-lib.c\nindex ae91027a02..894358c8b0 100644\n--- a/diff-lib.c\n+++ b/diff-lib.c\n@@ -160,7 +160,7 @@ void run_diff_files(struct rev_info *revs, unsigned int option)\n \n \t\t\tchanged = check_removed(ce, &st);\n \t\t\tif (!changed)\n-\t\t\t\twt_mode = ce_mode_from_stat(ce, st.st_mode);\n+\t\t\t\twt_mode = ce_mode_from_stat(the_repository, ce, st.st_mode);\n \t\t\telse {\n \t\t\t\tif (changed < 0) {\n \t\t\t\t\tperror(ce->name);\n@@ -193,7 +193,7 @@ void run_diff_files(struct rev_info *revs, unsigned int option)\n \t\t\t\t\tnum_compare_stages++;\n \t\t\t\t\toidcpy(&dpath->parent[stage - 2].oid,\n \t\t\t\t\t       &nce->oid);\n-\t\t\t\t\tdpath->parent[stage-2].mode = ce_mode_from_stat(nce, mode);\n+\t\t\t\t\tdpath->parent[stage-2].mode = ce_mode_from_stat(the_repository,nce, mode);\n \t\t\t\t\tdpath->parent[stage-2].status =\n \t\t\t\t\t\tDIFF_STATUS_MODIFIED;\n \t\t\t\t}\n@@ -262,7 +262,7 @@ void run_diff_files(struct rev_info *revs, unsigned int option)\n \t\t\t\tcontinue;\n \t\t\t} else if (revs->diffopt.ita_invisible_in_index &&\n \t\t\t\t   ce_intent_to_add(ce)) {\n-\t\t\t\tnewmode = ce_mode_from_stat(ce, st.st_mode);\n+\t\t\t\tnewmode = ce_mode_from_stat(the_repository, ce, st.st_mode);\n \t\t\t\tdiff_addremove(&revs->diffopt, '+', newmode,\n \t\t\t\t\t       null_oid(the_hash_algo), 0, ce->name, 0);\n \t\t\t\tcontinue;\n@@ -270,7 +270,7 @@ void run_diff_files(struct rev_info *revs, unsigned int option)\n \n \t\t\tchanged = match_stat_with_submodule(&revs->diffopt, ce, &st,\n \t\t\t\t\t\t\t    ce_option, &dirty_submodule);\n-\t\t\tnewmode = ce_mode_from_stat(ce, st.st_mode);\n+\t\t\tnewmode = ce_mode_from_stat(the_repository, ce, st.st_mode);\n \t\t}\n \n \t\tif (!changed && !dirty_submodule) {\n@@ -338,7 +338,7 @@ static int get_stat_data(const struct cache_entry *ce,\n \t\tchanged = match_stat_with_submodule(diffopt, ce, &st,\n \t\t\t\t\t\t    0, dirty_submodule);\n \t\tif (changed) {\n-\t\t\tmode = ce_mode_from_stat(ce, st.st_mode);\n+\t\t\tmode = ce_mode_from_stat(the_repository, ce, st.st_mode);\n \t\t\toid = null_oid(the_hash_algo);\n \t\t}\n \t}\ndiff --git a/environment.c b/environment.c\nindex 0026eb2274..861ef084dc 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -41,7 +41,6 @@\n 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@@ -306,7 +305,7 @@ int git_default_core_config(const char *var, const char *value,\n {\n \t/* This needs a better name */\n \tif (!strcmp(var, \"core.filemode\")) {\n-\t\ttrust_executable_bit = git_config_bool(var, value);\n+\t\tthe_repository->settings.trust_executable_bit = git_config_bool(var, value);\n \t\treturn 0;\n \t}\n \tif (!strcmp(var, \"core.trustctime\")) {\ndiff --git a/environment.h b/environment.h\nindex 27f657af04..7f3437f369 100644\n--- a/environment.h\n+++ b/environment.h\n@@ -144,7 +144,6 @@ int is_bare_repository(void);\n 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;\ndiff --git a/read-cache.c b/read-cache.c\nindex 0c07c3aef7..b1fcb9e1a0 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -201,13 +201,13 @@ void fill_stat_cache_info(struct index_state *istate, struct cache_entry *ce, st\n \n static unsigned int st_mode_from_ce(const struct cache_entry *ce)\n {\n-\textern int trust_executable_bit, has_symlinks;\n+\textern int has_symlinks;\n \n \tswitch (ce->ce_mode & S_IFMT) {\n \tcase S_IFLNK:\n \t\treturn has_symlinks ? S_IFLNK : (S_IFREG | 0644);\n \tcase S_IFREG:\n-\t\treturn (ce->ce_mode & (trust_executable_bit ? 0755 : 0644)) | S_IFREG;\n+\t\treturn (ce->ce_mode & (the_repository->settings.trust_executable_bit ? 0755 : 0644)) | S_IFREG;\n \tcase S_IFGITLINK:\n \t\treturn S_IFDIR | 0755;\n \tcase S_IFDIR:\n@@ -317,7 +317,7 @@ static int ce_match_stat_basic(const struct cache_entry *ce, struct stat *st)\n \t\t/* We consider only the owner x bit to be relevant for\n \t\t * \"mode changes\"\n \t\t */\n-\t\tif (trust_executable_bit &&\n+\t\tif (the_repository->settings.trust_executable_bit &&\n \t\t    (0100 & (ce->ce_mode ^ st->st_mode)))\n \t\t\tchanged |= MODE_CHANGED;\n \t\tbreak;\n@@ -738,7 +738,7 @@ int add_to_index(struct index_state *istate, const char *path, struct stat *st,\n \t\tce->ce_flags |= CE_INTENT_TO_ADD;\n \n \n-\tif (trust_executable_bit && has_symlinks) {\n+\tif (the_repository->settings.trust_executable_bit && has_symlinks) {\n \t\tce->ce_mode = create_ce_mode(st_mode);\n \t} else {\n \t\t/* If there is an existing entry, pick the mode bits and type\n@@ -748,7 +748,7 @@ int add_to_index(struct index_state *istate, const char *path, struct stat *st,\n \t\tint pos = index_name_pos_also_unmerged(istate, path, namelen);\n \n \t\tent = (0 <= pos) ? istate->cache[pos] : NULL;\n-\t\tce->ce_mode = ce_mode_from_stat(ent, st_mode);\n+\t\tce->ce_mode = ce_mode_from_stat(the_repository, ent, st_mode);\n \t}\n \n \t/* When core.ignorecase=true, determine if a directory of the same name but differing\ndiff --git a/read-cache.h b/read-cache.h\nindex 043da1f1aa..4e88d476aa 100644\n--- a/read-cache.h\n+++ b/read-cache.h\n@@ -4,15 +4,18 @@\n #include \"read-cache-ll.h\"\n #include \"object.h\"\n #include \"pathspec.h\"\n+#include \"repository.h\"\n \n-static inline unsigned int ce_mode_from_stat(const struct cache_entry *ce,\n-\t\t\t\t\t     unsigned int mode)\n+static inline unsigned int ce_mode_from_stat(\n+\t\t\t\t\t\tstruct repository *repo,\n+\t\t\t\t\t\tconst struct cache_entry *ce,\n+\t\t\t\t\t    unsigned int mode)\n {\n-\textern int trust_executable_bit, has_symlinks;\n+\textern int has_symlinks;\n \tif (!has_symlinks && S_ISREG(mode) &&\n \t    ce && S_ISLNK(ce->ce_mode))\n \t\treturn ce->ce_mode;\n-\tif (!trust_executable_bit && S_ISREG(mode)) {\n+\tif (!repo->settings.trust_executable_bit && S_ISREG(mode)) {\n \t\tif (ce && S_ISREG(ce->ce_mode))\n \t\t\treturn ce->ce_mode;\n \t\treturn create_ce_mode(0666);\ndiff --git a/repo-settings.h b/repo-settings.h\nindex cad9c3f0cc..a12e763f4f 100644\n--- a/repo-settings.h\n+++ b/repo-settings.h\n@@ -48,7 +48,10 @@ struct repo_settings {\n \t * replace_refs_enabled() for more details.\n \t */\n \tint read_replace_refs;\n-\n+\t\n+\t/* Whether to trust executable bit on filesystem (core.filemode) */\n+\tint trust_executable_bit;\n+\t\n \tstruct fsmonitor_settings *fsmonitor; /* lazily loaded */\n \n \tint index_version;\n@@ -74,6 +77,7 @@ struct repo_settings {\n #define REPO_SETTINGS_INIT { \\\n \t.shared_repository = -1, \\\n \t.index_version = -1, \\\n+\t.trust_executable_bit = 1, \\\n \t.core_untracked_cache = UNTRACKED_CACHE_KEEP, \\\n \t.fetch_negotiation_algorithm = FETCH_NEGOTIATION_CONSECUTIVE, \\\n \t.warn_ambiguous_refs = -1, \\\n-- \n2.43.0\n\n"}]}