Skip to content

Commit ce125d4

Browse files
jonathantanmygitster
authored andcommitted
submodule: extract path to submodule gitdir func
We currently store each submodule gitdir in ".git/modules/<name>", but this has problems with some submodule naming schemes, as described in a comment in submodule_name_to_gitdir() in this patch. Extract the determination of the location of a submodule's gitdir into its own function submodule_name_to_gitdir(). For now, the problem remains unsolved, but this puts us in a better position for finding a solution. This was motivated, at $DAYJOB, by a part of Android's repo hierarchy [1]. In particular, there is a repo "build", and several repos of the form "build/<name>". This is based on earlier work by Brandon Williams [2]. [1] https://android.googlesource.com/platform/ [2] https://lore.kernel.org/git/[email protected]/ Signed-off-by: Jonathan Tan <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 8b7c11b commit ce125d4

File tree

5 files changed

+72
-27
lines changed

5 files changed

+72
-27
lines changed

builtin/submodule--helper.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1704,18 +1704,24 @@ static int add_possible_reference_from_superproject(
17041704
* standard layout with .git/(modules/<name>)+/objects
17051705
*/
17061706
if (strip_suffix(odb->path, "/objects", &len)) {
1707+
struct repository alternate;
17071708
char *sm_alternate;
17081709
struct strbuf sb = STRBUF_INIT;
17091710
struct strbuf err = STRBUF_INIT;
17101711
strbuf_add(&sb, odb->path, len);
17111712

1713+
repo_init(&alternate, sb.buf, NULL);
1714+
17121715
/*
17131716
* We need to end the new path with '/' to mark it as a dir,
17141717
* otherwise a submodule name containing '/' will be broken
17151718
* as the last part of a missing submodule reference would
17161719
* be taken as a file name.
17171720
*/
1718-
strbuf_addf(&sb, "/modules/%s/", sas->submodule_name);
1721+
strbuf_reset(&sb);
1722+
submodule_name_to_gitdir(&sb, &alternate, sas->submodule_name);
1723+
strbuf_addch(&sb, '/');
1724+
repo_clear(&alternate);
17191725

17201726
sm_alternate = compute_alternate_path(sb.buf, &err);
17211727
if (sm_alternate) {
@@ -1785,7 +1791,7 @@ static int clone_submodule(struct module_clone_data *clone_data)
17851791
struct strbuf sb = STRBUF_INIT;
17861792
struct child_process cp = CHILD_PROCESS_INIT;
17871793

1788-
strbuf_addf(&sb, "%s/modules/%s", get_git_dir(), clone_data->name);
1794+
submodule_name_to_gitdir(&sb, the_repository, clone_data->name);
17891795
sm_gitdir = absolute_pathdup(sb.buf);
17901796
strbuf_reset(&sb);
17911797

dir.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3633,7 +3633,7 @@ static void connect_wt_gitdir_in_nested(const char *sub_worktree,
36333633
strbuf_reset(&sub_wt);
36343634
strbuf_reset(&sub_gd);
36353635
strbuf_addf(&sub_wt, "%s/%s", sub_worktree, sub->path);
3636-
strbuf_addf(&sub_gd, "%s/modules/%s", sub_gitdir, sub->name);
3636+
submodule_name_to_gitdir(&sub_gd, &subrepo, sub->name);
36373637

36383638
connect_work_tree_and_git_dir(sub_wt.buf, sub_gd.buf, 1);
36393639
}

repository.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -213,8 +213,7 @@ int repo_submodule_init(struct repository *subrepo,
213213
* submodule would not have a worktree.
214214
*/
215215
strbuf_reset(&gitdir);
216-
strbuf_repo_git_path(&gitdir, superproject,
217-
"modules/%s", sub->name);
216+
submodule_name_to_gitdir(&gitdir, superproject, sub->name);
218217

219218
if (repo_init(subrepo, gitdir.buf, NULL)) {
220219
ret = -1;

submodule.c

Lines changed: 55 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1819,14 +1819,16 @@ int bad_to_remove_submodule(const char *path, unsigned flags)
18191819

18201820
void submodule_unset_core_worktree(const struct submodule *sub)
18211821
{
1822-
char *config_path = xstrfmt("%s/modules/%s/config",
1823-
get_git_dir(), sub->name);
1822+
struct strbuf config_path = STRBUF_INIT;
18241823

1825-
if (git_config_set_in_file_gently(config_path, "core.worktree", NULL))
1824+
submodule_name_to_gitdir(&config_path, the_repository, sub->name);
1825+
strbuf_addstr(&config_path, "/config");
1826+
1827+
if (git_config_set_in_file_gently(config_path.buf, "core.worktree", NULL))
18261828
warning(_("Could not unset core.worktree setting in submodule '%s'"),
18271829
sub->path);
18281830

1829-
free(config_path);
1831+
strbuf_release(&config_path);
18301832
}
18311833

18321834
static const char *get_super_prefix_or_empty(void)
@@ -1922,20 +1924,22 @@ int submodule_move_head(const char *path,
19221924
absorb_git_dir_into_superproject(path,
19231925
ABSORB_GITDIR_RECURSE_SUBMODULES);
19241926
} else {
1925-
char *gitdir = xstrfmt("%s/modules/%s",
1926-
get_git_dir(), sub->name);
1927-
connect_work_tree_and_git_dir(path, gitdir, 0);
1928-
free(gitdir);
1927+
struct strbuf gitdir = STRBUF_INIT;
1928+
submodule_name_to_gitdir(&gitdir, the_repository,
1929+
sub->name);
1930+
connect_work_tree_and_git_dir(path, gitdir.buf, 0);
1931+
strbuf_release(&gitdir);
19291932

19301933
/* make sure the index is clean as well */
19311934
submodule_reset_index(path);
19321935
}
19331936

19341937
if (old_head && (flags & SUBMODULE_MOVE_HEAD_FORCE)) {
1935-
char *gitdir = xstrfmt("%s/modules/%s",
1936-
get_git_dir(), sub->name);
1937-
connect_work_tree_and_git_dir(path, gitdir, 1);
1938-
free(gitdir);
1938+
struct strbuf gitdir = STRBUF_INIT;
1939+
submodule_name_to_gitdir(&gitdir, the_repository,
1940+
sub->name);
1941+
connect_work_tree_and_git_dir(path, gitdir.buf, 1);
1942+
strbuf_release(&gitdir);
19391943
}
19401944
}
19411945

@@ -2050,7 +2054,7 @@ int validate_submodule_git_dir(char *git_dir, const char *submodule_name)
20502054
static void relocate_single_git_dir_into_superproject(const char *path)
20512055
{
20522056
char *old_git_dir = NULL, *real_old_git_dir = NULL, *real_new_git_dir = NULL;
2053-
char *new_git_dir;
2057+
struct strbuf new_gitdir = STRBUF_INIT;
20542058
const struct submodule *sub;
20552059

20562060
if (submodule_uses_worktrees(path))
@@ -2068,14 +2072,13 @@ static void relocate_single_git_dir_into_superproject(const char *path)
20682072
if (!sub)
20692073
die(_("could not lookup name for submodule '%s'"), path);
20702074

2071-
new_git_dir = git_pathdup("modules/%s", sub->name);
2072-
if (validate_submodule_git_dir(new_git_dir, sub->name) < 0)
2075+
submodule_name_to_gitdir(&new_gitdir, the_repository, sub->name);
2076+
if (validate_submodule_git_dir(new_gitdir.buf, sub->name) < 0)
20732077
die(_("refusing to move '%s' into an existing git dir"),
20742078
real_old_git_dir);
2075-
if (safe_create_leading_directories_const(new_git_dir) < 0)
2076-
die(_("could not create directory '%s'"), new_git_dir);
2077-
real_new_git_dir = real_pathdup(new_git_dir, 1);
2078-
free(new_git_dir);
2079+
if (safe_create_leading_directories_const(new_gitdir.buf) < 0)
2080+
die(_("could not create directory '%s'"), new_gitdir.buf);
2081+
real_new_git_dir = real_pathdup(new_gitdir.buf, 1);
20792082

20802083
fprintf(stderr, _("Migrating git directory of '%s%s' from\n'%s' to\n'%s'\n"),
20812084
get_super_prefix_or_empty(), path,
@@ -2086,6 +2089,7 @@ static void relocate_single_git_dir_into_superproject(const char *path)
20862089
free(old_git_dir);
20872090
free(real_old_git_dir);
20882091
free(real_new_git_dir);
2092+
strbuf_release(&new_gitdir);
20892093
}
20902094

20912095
/*
@@ -2105,6 +2109,7 @@ void absorb_git_dir_into_superproject(const char *path,
21052109
/* Not populated? */
21062110
if (!sub_git_dir) {
21072111
const struct submodule *sub;
2112+
struct strbuf sub_gitdir = STRBUF_INIT;
21082113

21092114
if (err_code == READ_GITFILE_ERR_STAT_FAILED) {
21102115
/* unpopulated as expected */
@@ -2126,8 +2131,9 @@ void absorb_git_dir_into_superproject(const char *path,
21262131
sub = submodule_from_path(the_repository, null_oid(), path);
21272132
if (!sub)
21282133
die(_("could not lookup name for submodule '%s'"), path);
2129-
connect_work_tree_and_git_dir(path,
2130-
git_path("modules/%s", sub->name), 0);
2134+
submodule_name_to_gitdir(&sub_gitdir, the_repository, sub->name);
2135+
connect_work_tree_and_git_dir(path, sub_gitdir.buf, 0);
2136+
strbuf_release(&sub_gitdir);
21312137
} else {
21322138
/* Is it already absorbed into the superprojects git dir? */
21332139
char *real_sub_git_dir = real_pathdup(sub_git_dir, 1);
@@ -2278,9 +2284,36 @@ int submodule_to_gitdir(struct strbuf *buf, const char *submodule)
22782284
goto cleanup;
22792285
}
22802286
strbuf_reset(buf);
2281-
strbuf_git_path(buf, "%s/%s", "modules", sub->name);
2287+
submodule_name_to_gitdir(buf, the_repository, sub->name);
22822288
}
22832289

22842290
cleanup:
22852291
return ret;
22862292
}
2293+
2294+
void submodule_name_to_gitdir(struct strbuf *buf, struct repository *r,
2295+
const char *submodule_name)
2296+
{
2297+
/*
2298+
* NEEDSWORK: The current way of mapping a submodule's name to
2299+
* its location in .git/modules/ has problems with some naming
2300+
* schemes. For example, if a submodule is named "foo" and
2301+
* another is named "foo/bar" (whether present in the same
2302+
* superproject commit or not - the problem will arise if both
2303+
* superproject commits have been checked out at any point in
2304+
* time), or if two submodule names only have different cases in
2305+
* a case-insensitive filesystem.
2306+
*
2307+
* There are several solutions, including encoding the path in
2308+
* some way, introducing a submodule.<name>.gitdir config in
2309+
* .git/config (not .gitmodules) that allows overriding what the
2310+
* gitdir of a submodule would be (and teach Git, upon noticing
2311+
* a clash, to automatically determine a non-clashing name and
2312+
* to write such a config), or introducing a
2313+
* submodule.<name>.gitdir config in .gitmodules that repo
2314+
* administrators can explicitly set. Nothing has been decided,
2315+
* so for now, just append the name at the end of the path.
2316+
*/
2317+
strbuf_repo_git_path(buf, r, "modules/");
2318+
strbuf_addstr(buf, submodule_name);
2319+
}

submodule.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,13 @@ int push_unpushed_submodules(struct repository *r,
124124
*/
125125
int submodule_to_gitdir(struct strbuf *buf, const char *submodule);
126126

127+
/*
128+
* Given a submodule name, create a path to where the submodule's gitdir lives
129+
* inside of the provided repository's 'modules' directory.
130+
*/
131+
void submodule_name_to_gitdir(struct strbuf *buf, struct repository *r,
132+
const char *submodule_name);
133+
127134
/*
128135
* Make sure that no submodule's git dir is nested in a sibling submodule's.
129136
*/

0 commit comments

Comments
 (0)