setup: split up concerns of `setup_git_env_internal()`

The function `setup_git_env_internal()` does two completely unrelated things: - It configures the repository's gitdir and propagates environment variables into it. - It configures a couple of global parameters via environment variables. The function is called when we initialize the repository's path, but it's also called via `chdir_notify_register()` whenever we change the current working directory. While we indeed have to reconfigure the gitdir in case it's a relative path, it doesn't make sense to reapply the global environment variables. Split up concerns of this function along the above delineation. Handling of the global environment variables is moved into `init_git()`, as they can be considered part of our setup procedure. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Patrick Steinhardt committed Jul 7, 2026 at 09:21 UTC cf1687a41c9fc7dc9c640201303c626be54464cc
2 files changed +48 -45
common-init.c
+20
@@ -5,7 +5,10 @@
5 #include "exec-cmd.h"
6 #include "gettext.h"
7 #include "attr.h"
8 +#include "odb.h"
9 +#include "parse.h"
10 #include "repository.h"
11 +#include "replace-object.h"
12 #include "setup.h"
13 #include "strbuf.h"
14 #include "trace2.h"
@@ -31,6 +34,22 @@ static void restore_sigpipe_to_default(void)
34 signal(SIGPIPE, SIG_DFL);
35 }
36
37 +static void setup_environment(void)
38 +{
39 + char *git_replace_ref_base;
40 + const char *replace_ref_base;
41 +
42 + if (getenv(NO_REPLACE_OBJECTS_ENVIRONMENT))
43 + disable_replace_refs();
44 + replace_ref_base = getenv(GIT_REPLACE_REF_BASE_ENVIRONMENT);
45 + git_replace_ref_base = xstrdup(replace_ref_base ? replace_ref_base
46 + : "refs/replace/");
47 + update_ref_namespace(NAMESPACE_REPLACE, git_replace_ref_base);
48 +
49 + if (git_env_bool(NO_LAZY_FETCH_ENVIRONMENT, 0))
50 + fetch_if_missing = 0;
51 +}
52 +
53 void init_git(const char **argv)
54 {
55 struct strbuf tmp = STRBUF_INIT;
@@ -51,6 +70,7 @@ void init_git(const char **argv)
70 git_setup_gettext();
71
72 initialize_repository(the_repository);
73 + setup_environment();
74
75 attr_start();
76
setup.c
+28 -45
@@ -10,7 +10,6 @@
10 #include "object-file.h"
11 #include "object-name.h"
12 #include "refs.h"
13 -#include "replace-object.h"
13 #include "repository.h"
14 #include "config.h"
15 #include "dir.h"
@@ -1042,38 +1041,19 @@ cleanup_return:
1041 return error_code ? NULL : path;
1042 }
1043
1045 -static void setup_git_env_internal(struct repository *repo,
1046 - const char *git_dir)
1044 +static void apply_gitdir_and_environment(struct repository *repo, const char *path)
1045 {
1048 - char *git_replace_ref_base;
1049 - const char *replace_ref_base;
1050 - struct set_gitdir_args args = { NULL };
1046 struct strvec to_free = STRVEC_INIT;
1047 + struct set_gitdir_args args = {
1048 + .commondir = getenv_safe(&to_free, GIT_COMMON_DIR_ENVIRONMENT),
1049 + .graft_file = getenv_safe(&to_free, GRAFT_ENVIRONMENT),
1050 + .index_file = getenv_safe(&to_free, INDEX_ENVIRONMENT),
1051 + .disable_ref_updates = !!getenv(GIT_QUARANTINE_ENVIRONMENT),
1052 + };
1053
1053 - args.commondir = getenv_safe(&to_free, GIT_COMMON_DIR_ENVIRONMENT);
1054 - args.graft_file = getenv_safe(&to_free, GRAFT_ENVIRONMENT);
1055 - args.index_file = getenv_safe(&to_free, INDEX_ENVIRONMENT);
1056 - if (getenv(GIT_QUARANTINE_ENVIRONMENT))
1057 - args.disable_ref_updates = true;
1054 + repo_set_gitdir(repo, path, &args);
1055
1059 - repo_set_gitdir(repo, git_dir, &args);
1056 strvec_clear(&to_free);
1061 -
1062 - if (getenv(NO_REPLACE_OBJECTS_ENVIRONMENT))
1063 - disable_replace_refs();
1064 - replace_ref_base = getenv(GIT_REPLACE_REF_BASE_ENVIRONMENT);
1065 - git_replace_ref_base = xstrdup(replace_ref_base ? replace_ref_base
1066 - : "refs/replace/");
1067 - update_ref_namespace(NAMESPACE_REPLACE, git_replace_ref_base);
1068 -
1069 - if (git_env_bool(NO_LAZY_FETCH_ENVIRONMENT, 0))
1070 - fetch_if_missing = 0;
1071 -}
1072 -
1073 -static void set_git_dir_1(struct repository *repo, const char *path)
1074 -{
1075 - xsetenv(GIT_DIR_ENVIRONMENT, path, 1);
1076 - setup_git_env_internal(repo, path);
1057 }
1058
1059 static void update_relative_gitdir(const char *name UNUSED,
@@ -1087,11 +1067,12 @@ static void update_relative_gitdir(const char *name UNUSED,
1067 trace_printf_key(&trace_setup_key,
1068 "setup: move $GIT_DIR to '%s'",
1069 path);
1090 - set_git_dir_1(repo, path);
1070 + apply_gitdir_and_environment(repo, path);
1071 + xsetenv(GIT_DIR_ENVIRONMENT, path, 1);
1072 free(path);
1073 }
1074
1094 -static void set_git_dir(struct repository *repo, const char *path, int make_realpath)
1075 +static void apply_and_export_relative_gitdir(struct repository *repo, const char *path, int make_realpath)
1076 {
1077 struct strbuf realpath = STRBUF_INIT;
1078
@@ -1100,7 +1081,9 @@ static void set_git_dir(struct repository *repo, const char *path, int make_real
1081 path = realpath.buf;
1082 }
1083
1103 - set_git_dir_1(repo, path);
1084 + apply_gitdir_and_environment(repo, path);
1085 + xsetenv(GIT_DIR_ENVIRONMENT, path, 1);
1086 +
1087 if (!is_absolute_path(path))
1088 chdir_notify_register(NULL, update_relative_gitdir, repo);
1089
@@ -1153,7 +1136,7 @@ static const char *setup_explicit_git_dir(struct repository *repo,
1136 set_git_work_tree(repo, work_tree_env);
1137 } else if (repo_fmt->is_bare > 0) {
1138 /* #18, #26 */
1156 - set_git_dir(repo, gitdirenv, 0);
1139 + apply_and_export_relative_gitdir(repo, gitdirenv, 0);
1140 free(gitfile);
1141 return NULL;
1142 } else if (repo_fmt->work_tree) { /* #6, #14 */
@@ -1173,7 +1156,7 @@ static const char *setup_explicit_git_dir(struct repository *repo,
1156 }
1157 } else if (!git_env_bool(GIT_IMPLICIT_WORK_TREE_ENVIRONMENT, 1)) {
1158 /* #16d */
1176 - set_git_dir(repo, gitdirenv, 0);
1159 + apply_and_export_relative_gitdir(repo, gitdirenv, 0);
1160 free(gitfile);
1161 return NULL;
1162 } else { /* #2, #10 */
@@ -1185,14 +1168,14 @@ static const char *setup_explicit_git_dir(struct repository *repo,
1168
1169 /* both repo_get_work_tree() and cwd are already normalized */
1170 if (!strcmp(cwd->buf, worktree)) { /* cwd == worktree */
1188 - set_git_dir(repo, gitdirenv, 0);
1171 + apply_and_export_relative_gitdir(repo, gitdirenv, 0);
1172 free(gitfile);
1173 return NULL;
1174 }
1175
1176 offset = dir_inside_of(cwd->buf, worktree);
1177 if (offset >= 0) { /* cwd inside worktree? */
1195 - set_git_dir(repo, gitdirenv, 1);
1178 + apply_and_export_relative_gitdir(repo, gitdirenv, 1);
1179 if (chdir(worktree))
1180 die_errno(_("cannot chdir to '%s'"), worktree);
1181 strbuf_addch(cwd, '/');
@@ -1201,7 +1184,7 @@ static const char *setup_explicit_git_dir(struct repository *repo,
1184 }
1185
1186 /* cwd outside worktree */
1204 - set_git_dir(repo, gitdirenv, 0);
1187 + apply_and_export_relative_gitdir(repo, gitdirenv, 0);
1188 free(gitfile);
1189 return NULL;
1190 }
@@ -1231,7 +1214,7 @@ static const char *setup_discovered_git_dir(struct repository *repo,
1214
1215 /* #16.2, #17.2, #20.2, #21.2, #24, #25, #28, #29 (see t1510) */
1216 if (repo_fmt->is_bare > 0) {
1234 - set_git_dir(repo, gitdir, (offset != cwd->len));
1217 + apply_and_export_relative_gitdir(repo, gitdir, (offset != cwd->len));
1218 if (chdir(cwd->buf))
1219 die_errno(_("cannot come back to cwd"));
1220 return NULL;
@@ -1240,7 +1223,7 @@ static const char *setup_discovered_git_dir(struct repository *repo,
1223 /* #0, #1, #5, #8, #9, #12, #13 */
1224 set_git_work_tree(repo, ".");
1225 if (strcmp(gitdir, DEFAULT_GIT_DIR_ENVIRONMENT))
1243 - set_git_dir(repo, gitdir, 0);
1226 + apply_and_export_relative_gitdir(repo, gitdir, 0);
1227 if (offset >= cwd->len)
1228 return NULL;
1229
@@ -1280,10 +1263,10 @@ static const char *setup_bare_git_dir(struct repository *repo,
1263 die_errno(_("cannot come back to cwd"));
1264 root_len = offset_1st_component(cwd->buf);
1265 strbuf_setlen(cwd, offset > root_len ? offset : root_len);
1283 - set_git_dir(repo, cwd->buf, 0);
1266 + apply_and_export_relative_gitdir(repo, cwd->buf, 0);
1267 }
1268 else
1286 - set_git_dir(repo, ".", 0);
1269 + apply_and_export_relative_gitdir(repo, ".", 0);
1270 return NULL;
1271 }
1272
@@ -1878,7 +1861,7 @@ const char *enter_repo(struct repository *repo, const char *path, unsigned flags
1861 struct repository_format fmt = REPOSITORY_FORMAT_INIT;
1862 struct strbuf err = STRBUF_INIT;
1863
1881 - set_git_dir(repo, ".", 0);
1864 + apply_and_export_relative_gitdir(repo, ".", 0);
1865 read_and_verify_repository_format(&fmt, ".", NULL);
1866 if (apply_repository_format(repo, &fmt, APPLY_REPOSITORY_FORMAT_HONOR_ENV, &err) < 0)
1867 die("%s", err.buf);
@@ -2022,7 +2005,7 @@ const char *setup_git_directory_gently(struct repository *repo, int *nongit_ok)
2005 startup_info->have_repository = 1;
2006
2007 /*
2025 - * Not all paths through the setup code will call 'set_git_dir()' (which
2008 + * Not all paths through the setup code will call 'apply_and_export_relative_gitdir()' (which
2009 * directly sets up the environment) so in order to guarantee that the
2010 * environment is in a consistent state after setup, explicitly setup
2011 * the environment if we have a repository.
@@ -2040,7 +2023,7 @@ const char *setup_git_directory_gently(struct repository *repo, int *nongit_ok)
2023 const char *gitdir = getenv(GIT_DIR_ENVIRONMENT);
2024 if (!gitdir)
2025 gitdir = DEFAULT_GIT_DIR_ENVIRONMENT;
2043 - setup_git_env_internal(repo, gitdir);
2026 + apply_gitdir_and_environment(repo, gitdir);
2027 }
2028
2029 if (startup_info->have_repository) {
@@ -2825,12 +2808,12 @@ int init_db(struct repository *repo,
2808 if (!exist_ok && !stat(real_git_dir, &st))
2809 die(_("%s already exists"), real_git_dir);
2810
2828 - set_git_dir(repo, real_git_dir, 1);
2811 + apply_and_export_relative_gitdir(repo, real_git_dir, 1);
2812 git_dir = repo_get_git_dir(repo);
2813 separate_git_dir(git_dir, original_git_dir);
2814 }
2815 else {
2833 - set_git_dir(repo, git_dir, 1);
2816 + apply_and_export_relative_gitdir(repo, git_dir, 1);
2817 git_dir = repo_get_git_dir(repo);
2818 }
2819 startup_info->have_repository = 1;