setup: propagate prefix via repository discovery
In the preceding commits we have started to propagate all information required for the configuration of the repository via a new `struct repo_discovery`. The only exception is the repository's prefix, which we still return via the return parameter. This is conceptually fine, but somewhat inconsistent. Refactor this to instead propagate the prefix via the repository discovery, too. While at it, drop a static variable in `repo_discover_bare_gitdir()`. We apply its value to the repository discovery anyway, so we don't have to keep it around afterwards anymore. 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
0bf8e1464331c7d611a79e7355a3826969c00405
1 file changed
+45
-56
setup.c
+45
-56
@@ -1094,6 +1094,7 @@ struct repo_discovery {
1094
struct repository_format format;
1095
char *gitdir;
1096
char *worktree;
1097
+ char *prefix;
1098
};
1099
1100
#define REPO_DISCOVERY_INIT { \
@@ -1105,6 +1106,7 @@ static void repo_discovery_release(struct repo_discovery *r)
1106
clear_repository_format(&r->format);
1107
free(r->gitdir);
1108
free(r->worktree);
1109
+ free(r->prefix);
1110
}
1111
1112
static void repo_discovery_set_gitdir(struct repo_discovery *r,
@@ -1128,10 +1130,10 @@ static void repo_discovery_set_worktree(struct repo_discovery *r,
1130
r->worktree = real_pathdup(worktree, 1);
1131
}
1132
1131
-static const char *repo_discover_explicit_gitdir(struct repo_discovery *discovery,
1132
- const char *gitdirenv,
1133
- struct strbuf *cwd,
1134
- int *nongit_ok)
1133
+static void repo_discover_explicit_gitdir(struct repo_discovery *discovery,
1134
+ const char *gitdirenv,
1135
+ struct strbuf *cwd,
1136
+ int *nongit_ok)
1137
{
1138
const char *work_tree_env = getenv(GIT_WORK_TREE_ENVIRONMENT);
1139
char *gitfile;
@@ -1149,16 +1151,13 @@ static const char *repo_discover_explicit_gitdir(struct repo_discovery *discover
1151
if (!is_git_directory(gitdirenv)) {
1152
if (nongit_ok) {
1153
*nongit_ok = 1;
1152
- free(gitfile);
1153
- return NULL;
1154
+ goto out;
1155
}
1156
die(_("not a git repository: '%s'"), gitdirenv);
1157
}
1158
1158
- if (read_and_verify_repository_format(&discovery->format, gitdirenv, nongit_ok)) {
1159
- free(gitfile);
1160
- return NULL;
1161
- }
1159
+ if (read_and_verify_repository_format(&discovery->format, gitdirenv, nongit_ok))
1160
+ goto out;
1161
1162
/* #3, #7, #11, #15, #19, #23, #27, #31 (see t1510) */
1163
if (work_tree_env) {
@@ -1173,8 +1172,7 @@ static const char *repo_discover_explicit_gitdir(struct repo_discovery *discover
1172
} else if (discovery->format.is_bare > 0) {
1173
/* #18, #26 */
1174
repo_discovery_set_gitdir(discovery, gitdirenv, 0);
1176
- free(gitfile);
1177
- return NULL;
1175
+ goto out;
1176
} else if (discovery->format.work_tree) { /* #6, #14 */
1177
if (is_absolute_path(discovery->format.work_tree)) {
1178
repo_discovery_set_worktree(discovery, discovery->format.work_tree);
@@ -1193,8 +1191,7 @@ static const char *repo_discover_explicit_gitdir(struct repo_discovery *discover
1191
} else if (!git_env_bool(GIT_IMPLICIT_WORK_TREE_ENVIRONMENT, 1)) {
1192
/* #16d */
1193
repo_discovery_set_gitdir(discovery, gitdirenv, 0);
1196
- free(gitfile);
1197
- return NULL;
1194
+ goto out;
1195
} else { /* #2, #10 */
1196
repo_discovery_set_worktree(discovery, ".");
1197
}
@@ -1202,8 +1199,7 @@ static const char *repo_discover_explicit_gitdir(struct repo_discovery *discover
1199
/* both the worktree and cwd are already normalized */
1200
if (!strcmp(cwd->buf, discovery->worktree)) { /* cwd == worktree */
1201
repo_discovery_set_gitdir(discovery, gitdirenv, 0);
1205
- free(gitfile);
1206
- return NULL;
1202
+ goto out;
1203
}
1204
1205
offset = dir_inside_of(cwd->buf, discovery->worktree);
@@ -1211,38 +1207,37 @@ static const char *repo_discover_explicit_gitdir(struct repo_discovery *discover
1207
repo_discovery_set_gitdir(discovery, gitdirenv, 1);
1208
if (chdir(discovery->worktree))
1209
die_errno(_("cannot chdir to '%s'"), discovery->worktree);
1214
- strbuf_addch(cwd, '/');
1215
- free(gitfile);
1216
- return cwd->buf + offset;
1210
+ discovery->prefix = xstrfmt("%s/", cwd->buf + offset);
1211
+ goto out;
1212
}
1213
1214
/* cwd outside worktree */
1215
repo_discovery_set_gitdir(discovery, gitdirenv, 0);
1216
+
1217
+out:
1218
free(gitfile);
1222
- return NULL;
1219
}
1220
1225
-static const char *repo_discover_implicit_gitdir(struct repo_discovery *discovery,
1226
- const char *gitdir,
1227
- struct strbuf *cwd, int offset,
1228
- int *nongit_ok)
1221
+static void repo_discover_implicit_gitdir(struct repo_discovery *discovery,
1222
+ const char *gitdir,
1223
+ struct strbuf *cwd, int offset,
1224
+ int *nongit_ok)
1225
{
1226
if (read_and_verify_repository_format(&discovery->format, gitdir, nongit_ok))
1231
- return NULL;
1227
+ return;
1228
1229
/* --work-tree is set without --git-dir; use discovered one */
1230
if (getenv(GIT_WORK_TREE_ENVIRONMENT) || discovery->format.work_tree) {
1231
char *to_free = NULL;
1236
- const char *ret;
1232
1233
if (offset != cwd->len && !is_absolute_path(gitdir))
1234
gitdir = to_free = real_pathdup(gitdir, 1);
1235
if (chdir(cwd->buf))
1236
die_errno(_("cannot come back to cwd"));
1242
- ret = repo_discover_explicit_gitdir(discovery, gitdir, cwd,
1243
- nongit_ok);
1237
+ repo_discover_explicit_gitdir(discovery, gitdir, cwd,
1238
+ nongit_ok);
1239
free(to_free);
1245
- return ret;
1240
+ return;
1241
}
1242
1243
/* #16.2, #17.2, #20.2, #21.2, #24, #25, #28, #29 (see t1510) */
@@ -1250,7 +1245,7 @@ static const char *repo_discover_implicit_gitdir(struct repo_discovery *discover
1245
repo_discovery_set_gitdir(discovery, gitdir, (offset != cwd->len));
1246
if (chdir(cwd->buf))
1247
die_errno(_("cannot come back to cwd"));
1253
- return NULL;
1248
+ return;
1249
}
1250
1251
/* #0, #1, #5, #8, #9, #12, #13 */
@@ -1258,37 +1253,34 @@ static const char *repo_discover_implicit_gitdir(struct repo_discovery *discover
1253
if (strcmp(gitdir, DEFAULT_GIT_DIR_ENVIRONMENT))
1254
repo_discovery_set_gitdir(discovery, gitdir, 0);
1255
if (offset >= cwd->len)
1261
- return NULL;
1256
+ return;
1257
1258
/* Make "offset" point past the '/' (already the case for root dirs) */
1259
if (offset != offset_1st_component(cwd->buf))
1260
offset++;
1266
- /* Add a '/' at the end */
1267
- strbuf_addch(cwd, '/');
1268
- return cwd->buf + offset;
1261
+ discovery->prefix = xstrfmt("%s/", cwd->buf + offset);
1262
}
1263
1264
/* #16.1, #17.1, #20.1, #21.1, #22.1 (see t1510) */
1272
-static const char *repo_discover_bare_gitdir(struct repo_discovery *discovery,
1273
- struct strbuf *cwd, int offset,
1274
- int *nongit_ok)
1265
+static void repo_discover_bare_gitdir(struct repo_discovery *discovery,
1266
+ struct strbuf *cwd, int offset,
1267
+ int *nongit_ok)
1268
{
1269
int root_len;
1270
1271
if (read_and_verify_repository_format(&discovery->format, ".", nongit_ok))
1279
- return NULL;
1272
+ return;
1273
1274
setenv(GIT_IMPLICIT_WORK_TREE_ENVIRONMENT, "0", 1);
1275
1276
/* --work-tree is set without --git-dir; use discovered one */
1277
if (getenv(GIT_WORK_TREE_ENVIRONMENT) || discovery->format.work_tree) {
1285
- static const char *gitdir;
1286
-
1287
- gitdir = offset == cwd->len ? "." : xmemdupz(cwd->buf, offset);
1278
+ char *gitdir = offset == cwd->len ? xstrdup(".") : xmemdupz(cwd->buf, offset);
1279
if (chdir(cwd->buf))
1280
die_errno(_("cannot come back to cwd"));
1290
- return repo_discover_explicit_gitdir(discovery, gitdir, cwd,
1291
- nongit_ok);
1281
+ repo_discover_explicit_gitdir(discovery, gitdir, cwd, nongit_ok);
1282
+ free(gitdir);
1283
+ return;
1284
}
1285
1286
if (offset != cwd->len) {
@@ -1297,10 +1289,9 @@ static const char *repo_discover_bare_gitdir(struct repo_discovery *discovery,
1289
root_len = offset_1st_component(cwd->buf);
1290
strbuf_setlen(cwd, offset > root_len ? offset : root_len);
1291
repo_discovery_set_gitdir(discovery, cwd->buf, 0);
1300
- }
1301
- else
1292
+ } else {
1293
repo_discovery_set_gitdir(discovery, ".", 0);
1303
- return NULL;
1294
+ }
1295
}
1296
1297
static dev_t get_device_or_die(const char *path, const char *prefix, int prefix_len)
@@ -1936,7 +1927,6 @@ const char *setup_git_directory_gently(struct repository *repo, int *nongit_ok)
1927
struct strbuf cwd = STRBUF_INIT;
1928
struct strbuf dir = STRBUF_INIT, gitdir = STRBUF_INIT, report = STRBUF_INIT;
1929
struct repo_discovery discovery = REPO_DISCOVERY_INIT;
1939
- const char *prefix = NULL;
1930
1931
/*
1932
* We may have read an incomplete configuration before
@@ -1961,20 +1951,19 @@ const char *setup_git_directory_gently(struct repository *repo, int *nongit_ok)
1951
1952
switch (repo_discovery_find_dir(&dir, &gitdir, &report, 1)) {
1953
case GIT_DIR_EXPLICIT:
1964
- prefix = repo_discover_explicit_gitdir(&discovery, gitdir.buf, &cwd,
1965
- nongit_ok);
1954
+ repo_discover_explicit_gitdir(&discovery, gitdir.buf, &cwd,
1955
+ nongit_ok);
1956
break;
1957
case GIT_DIR_DISCOVERED:
1958
if (dir.len < cwd.len && chdir(dir.buf))
1959
die(_("cannot change to '%s'"), dir.buf);
1970
- prefix = repo_discover_implicit_gitdir(&discovery, gitdir.buf, &cwd, dir.len,
1971
- nongit_ok);
1960
+ repo_discover_implicit_gitdir(&discovery, gitdir.buf, &cwd, dir.len,
1961
+ nongit_ok);
1962
break;
1963
case GIT_DIR_BARE:
1964
if (dir.len < cwd.len && chdir(dir.buf))
1965
die(_("cannot change to '%s'"), dir.buf);
1976
- prefix = repo_discover_bare_gitdir(&discovery, &cwd, dir.len,
1977
- nongit_ok);
1966
+ repo_discover_bare_gitdir(&discovery, &cwd, dir.len, nongit_ok);
1967
break;
1968
case GIT_DIR_HIT_CEILING:
1969
if (!nongit_ok)
@@ -2103,10 +2092,10 @@ const char *setup_git_directory_gently(struct repository *repo, int *nongit_ok)
2092
* out where the repository is, i.e. a preparation
2093
* for calling repo_config_get_bool().
2094
*/
2106
- if (prefix) {
2107
- prefix = precompose_string_if_needed(prefix);
2095
+ if (discovery.prefix) {
2096
+ const char *prefix = precompose_string_if_needed(discovery.prefix);
2097
repo->prefix = xstrdup(prefix);
2109
- setenv(GIT_PREFIX_ENVIRONMENT, prefix, 1);
2098
+ setenv(GIT_PREFIX_ENVIRONMENT, repo->prefix, 1);
2099
} else {
2100
FREE_AND_NULL(repo->prefix);
2101
setenv(GIT_PREFIX_ENVIRONMENT, "", 1);