{"thread":{"id":"65877","subject":"[PATCH v3 0/1] move excludes_file into repo_config_values","startedAt":"2026-06-27T15:45:27Z","lastAt":"2026-06-27T15:52:40Z","messageCount":3,"participants":["Tian Yuchen"],"isPatch":true,"patchVersion":3,"patchTotal":1},"messages":[{"id":"546540","messageId":"20260627154514.1073154-1-cat@malon.dev","threadId":"65877","inReplyTo":null,"subject":"[PATCH v3 0/1] move excludes_file into repo_config_values","fromName":"Tian Yuchen","fromEmail":"cat@malon.dev","sentAt":"2026-06-27T15:45:13Z","receivedAt":"2026-06-27T15:45:27Z","isPatch":true,"body":"This patch continues the libification effort by migrating the global\nstring variable 'excludes_file' into 'struct repo_config_values'. Since\nthis is a dynamically allocated variable, the migration requires proper\nheap memory management.\n\nThis patch mainly does three things:\n\n - Abstract the XDG fallback lazy-loading logic out of dir.c into a proper\n getter.\n\n - Move the variables into the struct repo_config_values.\n\n - Introduce the memory destructor 'repo_config_values_clear()'.\n\n\nChanges since V2:\n\n - Squash together the previous two commits into one.\n\n - The 'repo->initialized' check is used in both the getter and destructor.\n This eliminates redundant checks and follows the fail-fast principle. This\n is consistent with the previous global variable removal patches [1][2][3].\n\nThanks!\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Ayush Chandekar <ayu.chandekar@gmail.com>\nMentored-by: Olamide Caleb Bello <belkid98@gmail.com>\nSigned-off-by: Tian Yuchen <cat@malon.dev>\n\n[1] https://lore.kernel.org/git/20260610093635.139719-1-cat@malon.dev/T/#m856253610936d052a798259bfc06d598561e53c4\n[2] https://lore.kernel.org/git/20260606143412.15443-1-cat@malon.dev/\n[3] https://lore.kernel.org/git/20260617154929.564498-2-cat@malon.dev/T/#m8843984a6175a1a4c7e00877085c77b0c72f5803\n\nTian Yuchen (1):\n  environment: move excludes_file into repo_config_values\n\n dir.c         |  4 ++--\n environment.c | 30 +++++++++++++++++++++++++++---\n environment.h | 13 ++++++++++++-\n repository.c  |  1 +\n 4 files changed, 42 insertions(+), 6 deletions(-)\n\n-- \n2.43.0\n\n"},{"id":"546541","messageId":"20260627154514.1073154-2-cat@malon.dev","threadId":"65877","inReplyTo":"20260627154514.1073154-1-cat@malon.dev","subject":"[PATCH v3 1/1] environment: move excludes_file into repo_config_values","fromName":"Tian Yuchen","fromEmail":"cat@malon.dev","sentAt":"2026-06-27T15:45:14Z","receivedAt":"2026-06-27T15:45:33Z","isPatch":true,"body":"The global variable 'excludes_file' is used to track the path to the\nglobal ignore file. If this variable is NULL, setup_standard_excludes()\nin dir.c forcefully evaluates and assigns the XDG default path to it.\n\nContinue the libification effort by encapsulating this lazy-loading\nfallback logic into a proper getter and moving the variable into\n'struct repo_config_values'.\n\nSince 'excludes_file' is a dynamically allocated string, it requires\nproper heap memory management. Introduce repo_config_values_clear()\nand wire it up in repo_clear() to safely free this memory when a\nrepository instance is destroyed. Also clean up the heap-allocated\n'attributes_file' in this new destructor while we are at it.\n\nNote: 'if (!repo->initialized)' is added in both the getter and the\ndestructor. This ensures we safely return or bypass cleaning up\nuninitialized repositories without hardcoding a dependency on\n'the_repository'.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Ayush Chandekar <ayu.chandekar@gmail.com>\nMentored-by: Olamide Caleb Bello <belkid98@gmail.com>\nSigned-off-by: Tian Yuchen <cat@malon.dev>\n---\n dir.c         |  4 ++--\n environment.c | 30 +++++++++++++++++++++++++++---\n environment.h | 13 ++++++++++++-\n repository.c  |  1 +\n 4 files changed, 42 insertions(+), 6 deletions(-)\n\ndiff --git a/dir.c b/dir.c\nindex 7a73690fbc..4f87a52b3c 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -3481,11 +3481,11 @@ static GIT_PATH_FUNC(git_path_info_exclude, \"info/exclude\")\n \n void setup_standard_excludes(struct dir_struct *dir)\n {\n+\tconst char *excludes_file = repo_excludes_file(the_repository);\n+\n \tdir->exclude_per_dir = \".gitignore\";\n \n \t/* core.excludesfile defaulting to $XDG_CONFIG_HOME/git/ignore */\n-\tif (!excludes_file)\n-\t\texcludes_file = xdg_config_home(\"ignore\");\n \tif (excludes_file && !access_or_warn(excludes_file, R_OK, 0))\n \t\tadd_patterns_from_file_1(dir, excludes_file,\n \t\t\t\t\t dir->untracked ? &dir->internal.ss_excludes_file : NULL);\ndiff --git a/environment.c b/environment.c\nindex ba2c60103f..2519c60918 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -57,7 +57,6 @@ enum fsync_method fsync_method = FSYNC_METHOD_DEFAULT;\n enum fsync_component fsync_components = FSYNC_COMPONENTS_DEFAULT;\n char *editor_program;\n char *askpass_program;\n-char *excludes_file;\n enum auto_crlf auto_crlf = AUTO_CRLF_FALSE;\n enum eol core_eol = EOL_UNSET;\n int global_conv_flags_eol = CONV_EOL_RNDTRP_WARN;\n@@ -134,6 +133,17 @@ int is_bare_repository(void)\n \treturn is_bare_repository_cfg && !repo_get_work_tree(the_repository);\n }\n \n+const char *repo_excludes_file(struct repository *repo)\n+{\n+\tif (!repo || !repo->initialized)\n+\t\treturn NULL;\n+\n+\tif (!repo_config_values(repo)->excludes_file)\n+\t\trepo_config_values(repo)->excludes_file = xdg_config_home(\"ignore\");\n+\n+\treturn repo_config_values(repo)->excludes_file;\n+}\n+\n int have_git_dir(void)\n {\n \treturn startup_info->have_repository\n@@ -461,8 +471,8 @@ int git_default_core_config(const char *var, const char *value,\n \t}\n \n \tif (!strcmp(var, \"core.excludesfile\")) {\n-\t\tFREE_AND_NULL(excludes_file);\n-\t\treturn git_config_pathname(&excludes_file, var, value);\n+\t\tFREE_AND_NULL(cfg->excludes_file);\n+\t\treturn git_config_pathname(&cfg->excludes_file, var, value);\n \t}\n \n \tif (!strcmp(var, \"core.whitespace\")) {\n@@ -715,6 +725,7 @@ int git_default_config(const char *var, const char *value,\n void repo_config_values_init(struct repo_config_values *cfg)\n {\n \tcfg->attributes_file = NULL;\n+\tcfg->excludes_file = NULL;\n \tcfg->apply_sparse_checkout = 0;\n \tcfg->branch_track = BRANCH_TRACK_REMOTE;\n \tcfg->trust_ctime = 1;\n@@ -726,3 +737,16 @@ void repo_config_values_init(struct repo_config_values *cfg)\n \tcfg->sparse_expect_files_outside_of_patterns = 0;\n \tcfg->warn_on_object_refname_ambiguity = 1;\n }\n+\n+void repo_config_values_clear(struct repository *repo)\n+{\n+\tstruct repo_config_values *cfg;\n+\n+\tif (repo->initialized)\n+\t\treturn;\n+\n+\tcfg = repo_config_values(repo);\n+\n+\tFREE_AND_NULL(cfg->attributes_file);\n+\tFREE_AND_NULL(cfg->excludes_file);\n+}\ndiff --git a/environment.h b/environment.h\nindex 6f18286955..2e8352de7f 100644\n--- a/environment.h\n+++ b/environment.h\n@@ -90,6 +90,7 @@ struct repository;\n struct repo_config_values {\n \t/* section \"core\" config values */\n \tchar *attributes_file;\n+\tchar *excludes_file;\n \tint apply_sparse_checkout;\n \tint trust_ctime;\n \tint check_stat;\n@@ -133,8 +134,19 @@ int git_default_config(const char *, const char *,\n int git_default_core_config(const char *var, const char *value,\n \t\t\t    const struct config_context *ctx, void *cb);\n \n+const char *repo_excludes_file(struct repository *repo);\n+\n void repo_config_values_init(struct repo_config_values *cfg);\n \n+/*\n+ * Frees memory allocated for dynamically loaded configuration values\n+ * inside `repo_config_values`.\n+ *\n+ * As dynamically allocated variables are migrated into this struct,\n+ * their FREE_AND_NULL() calls should be appended here.\n+ */\n+void repo_config_values_clear(struct repository *repo);\n+\n /*\n  * TODO: All the below state either explicitly or implicitly relies on\n  * `the_repository`. We should eventually get rid of these and make the\n@@ -208,7 +220,6 @@ extern char *git_log_output_encoding;\n \n extern char *editor_program;\n extern char *askpass_program;\n-extern char *excludes_file;\n \n /*\n  * The character that begins a commented line in user-editable file\ndiff --git a/repository.c b/repository.c\nindex 187dd471c4..b31f1b7852 100644\n--- a/repository.c\n+++ b/repository.c\n@@ -388,6 +388,7 @@ void repo_clear(struct repository *repo)\n \tFREE_AND_NULL(repo->parsed_objects);\n \n \trepo_settings_clear(repo);\n+\trepo_config_values_clear(repo);\n \n \tif (repo->config) {\n \t\tgit_configset_clear(repo->config);\n-- \n2.43.0\n\n"},{"id":"546543","messageId":"832fee0a-f61d-413a-9562-78eccf8b5eb0@malon.dev","threadId":"65877","inReplyTo":"20260627154514.1073154-1-cat@malon.dev","subject":"Re: [PATCH v3 0/1] move excludes_file into repo_config_values","fromName":"Tian Yuchen","fromEmail":"cat@malon.dev","sentAt":"2026-06-27T15:52:30Z","receivedAt":"2026-06-27T15:52:40Z","isPatch":true,"body":"On 6/27/26 23:45, Tian Yuchen wrote:\n> This patch continues the libification effort by migrating the global\n> string variable 'excludes_file' into 'struct repo_config_values'. Since\n> this is a dynamically allocated variable, the migration requires proper\n> heap memory management.\n> \n> This patch mainly does three things:\n> \n>   - Abstract the XDG fallback lazy-loading logic out of dir.c into a proper\n>   getter.\n> \n>   - Move the variables into the struct repo_config_values.\n> \n>   - Introduce the memory destructor 'repo_config_values_clear()'.\n> \n> \n> Changes since V2:\n> \n>   - Squash together the previous two commits into one.\n> \n>   - The 'repo->initialized' check is used in both the getter and destructor.\n>   This eliminates redundant checks and follows the fail-fast principle. This\n>   is consistent with the previous global variable removal patches [1][2][3].\n> \n> Thanks!\n> \n> Mentored-by: Christian Couder <christian.couder@gmail.com>\n> Mentored-by: Ayush Chandekar <ayu.chandekar@gmail.com>\n> Mentored-by: Olamide Caleb Bello <belkid98@gmail.com>\n> Signed-off-by: Tian Yuchen <cat@malon.dev>\n> \n> [1] https://lore.kernel.org/git/20260610093635.139719-1-cat@malon.dev/T/#m856253610936d052a798259bfc06d598561e53c4\n> [2] https://lore.kernel.org/git/20260606143412.15443-1-cat@malon.dev/\n> [3] https://lore.kernel.org/git/20260617154929.564498-2-cat@malon.dev/T/#m8843984a6175a1a4c7e00877085c77b0c72f5803\n> \n> Tian Yuchen (1):\n>    environment: move excludes_file into repo_config_values\n> \n>   dir.c         |  4 ++--\n>   environment.c | 30 +++++++++++++++++++++++++++---\n>   environment.h | 13 ++++++++++++-\n>   repository.c  |  1 +\n>   4 files changed, 42 insertions(+), 6 deletions(-)\n> \n\nWhat happened...? I used in-reply-to this time, but I probably typed too \nfast and didn't notice where I made a mistake. Anyway...\n\nhttps://lore.kernel.org/git/20260626075037.532164-1-cat@malon.dev/#t\n\nThis is the link to the previous patch. Hopefully it will be helpful...\n\nApology, yuchen\n"}]}