environment: move excludes_file into repo_config_values

The global variable 'excludes_file' is used to track the path to the global ignore file. If this variable is NULL, 'setup_standard_excludes()' in 'dir.c' forcefully evaluates and assigns the XDG default path to it. Continue the libification effort by encapsulating this lazy-loading fallback logic into a proper getter and moving the variable into 'struct repo_config_values'. Since 'excludes_file' is a dynamically allocated string, it requires proper heap memory management. It is safely freed using the newly introduced 'repo_config_values_clear()' function when the repository is torn down. 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>

Tian Yuchen committed Jul 14, 2026 at 11:25 UTC 7488b9d1fd505ce1194b98893508fa5b194cf0cd
3 files changed +19 -6
dir.c
+2 -2
@@ -3481,11 +3481,11 @@ static GIT_PATH_FUNC(git_path_info_exclude, "info/exclude")
3481
3482 void setup_standard_excludes(struct dir_struct *dir)
3483 {
3484 + const char *excludes_file = repo_excludes_file(the_repository);
3485 +
3486 dir->exclude_per_dir = ".gitignore";
3487
3488 /* core.excludesfile defaulting to $XDG_CONFIG_HOME/git/ignore */
3487 - if (!excludes_file)
3488 - excludes_file = xdg_config_home("ignore");
3489 if (excludes_file && !access_or_warn(excludes_file, R_OK, 0))
3490 add_patterns_from_file_1(dir, excludes_file,
3491 dir->untracked ? &dir->internal.ss_excludes_file : NULL);
environment.c
+14 -3
@@ -57,7 +57,6 @@ enum fsync_method fsync_method = FSYNC_METHOD_DEFAULT;
57 enum fsync_component fsync_components = FSYNC_COMPONENTS_DEFAULT;
58 char *editor_program;
59 char *askpass_program;
60 -char *excludes_file;
60 enum auto_crlf auto_crlf = AUTO_CRLF_FALSE;
61 enum eol core_eol = EOL_UNSET;
62 int global_conv_flags_eol = CONV_EOL_RNDTRP_WARN;
@@ -134,6 +133,16 @@ int is_bare_repository(void)
133 return is_bare_repository_cfg && !repo_get_work_tree(the_repository);
134 }
135
136 +const char *repo_excludes_file(struct repository *repo)
137 +{
138 + struct repo_config_values *cfg = repo_config_values(repo);
139 +
140 + if (!cfg->excludes_file)
141 + cfg->excludes_file = xdg_config_home("ignore");
142 +
143 + return cfg->excludes_file;
144 +}
145 +
146 int have_git_dir(void)
147 {
148 return startup_info->have_repository
@@ -461,8 +470,8 @@ int git_default_core_config(const char *var, const char *value,
470 }
471
472 if (!strcmp(var, "core.excludesfile")) {
464 - FREE_AND_NULL(excludes_file);
465 - return git_config_pathname(&excludes_file, var, value);
473 + FREE_AND_NULL(cfg->excludes_file);
474 + return git_config_pathname(&cfg->excludes_file, var, value);
475 }
476
477 if (!strcmp(var, "core.whitespace")) {
@@ -715,6 +724,7 @@ int git_default_config(const char *var, const char *value,
724 void repo_config_values_init(struct repo_config_values *cfg)
725 {
726 cfg->attributes_file = NULL;
727 + cfg->excludes_file = NULL;
728 cfg->apply_sparse_checkout = 0;
729 cfg->branch_track = BRANCH_TRACK_REMOTE;
730 cfg->trust_ctime = 1;
@@ -730,4 +740,5 @@ void repo_config_values_init(struct repo_config_values *cfg)
740 void repo_config_values_clear(struct repo_config_values *cfg)
741 {
742 FREE_AND_NULL(cfg->attributes_file);
743 + FREE_AND_NULL(cfg->excludes_file);
744 }
environment.h
+3 -1
@@ -90,6 +90,7 @@ struct repository;
90 struct repo_config_values {
91 /* section "core" config values */
92 char *attributes_file;
93 + char *excludes_file;
94 int apply_sparse_checkout;
95 int trust_ctime;
96 int check_stat;
@@ -133,6 +134,8 @@ int git_default_config(const char *, const char *,
134 int git_default_core_config(const char *var, const char *value,
135 const struct config_context *ctx, void *cb);
136
137 +const char *repo_excludes_file(struct repository *repo);
138 +
139 void repo_config_values_init(struct repo_config_values *cfg);
140
141 /*
@@ -217,7 +220,6 @@ extern char *git_log_output_encoding;
220
221 extern char *editor_program;
222 extern char *askpass_program;
220 -extern char *excludes_file;
223
224 /*
225 * The character that begins a commented line in user-editable file