Skip to content

Commit cf82364

Browse files
jayatheerthkulkarnigitster
authored andcommitted
submodule: prevent overwriting .gitmodules entry on path reuse
Adding a submodule at a path that previously hosted another submodule (e.g., 'child') reuses the submodule name derived from the path. If the original submodule was only moved (e.g., to 'child_old') and not renamed, this silently overwrites its configuration in .gitmodules. This behavior loses user configuration and causes confusion when the original submodule is expected to remain intact. It assumes that the path-derived name is always safe to reuse, even though the name might still be in use elsewhere in the repository. Teach `module_add()` to check if the computed submodule name already exists in the repository's submodule config, and if so, refuse the operation unless the user explicitly renames or uses force to auto increment. Signed-off-by: K Jayatheerth <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent cb96e16 commit cf82364

File tree

2 files changed

+51
-0
lines changed

2 files changed

+51
-0
lines changed

builtin/submodule--helper.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3444,6 +3444,10 @@ static int module_add(int argc, const char **argv, const char *prefix,
34443444
struct add_data add_data = ADD_DATA_INIT;
34453445
const char *ref_storage_format = NULL;
34463446
char *to_free = NULL;
3447+
const struct submodule *existing;
3448+
struct strbuf buf = STRBUF_INIT;
3449+
int i;
3450+
char *sm_name_to_free = NULL;
34473451
struct option options[] = {
34483452
OPT_STRING('b', "branch", &add_data.branch, N_("branch"),
34493453
N_("branch of repository to add as submodule")),
@@ -3546,6 +3550,29 @@ static int module_add(int argc, const char **argv, const char *prefix,
35463550
if(!add_data.sm_name)
35473551
add_data.sm_name = add_data.sm_path;
35483552

3553+
existing = submodule_from_name(the_repository,
3554+
null_oid(the_hash_algo),
3555+
add_data.sm_name);
3556+
3557+
if (existing && strcmp(existing->path, add_data.sm_path)) {
3558+
if (!force) {
3559+
die(_("submodule name '%s' already used for path '%s'"),
3560+
add_data.sm_name, existing->path);
3561+
}
3562+
3563+
/* --force: build <name><n> until unique */
3564+
for (i = 1; ; i++) {
3565+
strbuf_reset(&buf);
3566+
strbuf_addf(&buf, "%s%d", add_data.sm_name, i);
3567+
if (!submodule_from_name(the_repository,
3568+
null_oid(the_hash_algo),
3569+
buf.buf)) {
3570+
break;
3571+
}
3572+
}
3573+
3574+
add_data.sm_name = sm_name_to_free = strbuf_detach(&buf, NULL);
3575+
}
35493576
if (check_submodule_name(add_data.sm_name))
35503577
die(_("'%s' is not a valid submodule name"), add_data.sm_name);
35513578

@@ -3561,6 +3588,7 @@ static int module_add(int argc, const char **argv, const char *prefix,
35613588

35623589
ret = 0;
35633590
cleanup:
3591+
free(sm_name_to_free);
35643592
free(add_data.sm_path);
35653593
free(to_free);
35663594
strbuf_release(&sb);

t/t7400-submodule-basic.sh

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1482,4 +1482,27 @@ test_expect_success '`submodule init` and `init.templateDir`' '
14821482
)
14831483
'
14841484

1485+
test_expect_success 'submodule add fails when name is reused' '
1486+
git init test-submodule &&
1487+
(
1488+
cd test-submodule &&
1489+
git commit --allow-empty -m init &&
1490+
1491+
git init ../child-origin &&
1492+
git -C ../child-origin commit --allow-empty -m init &&
1493+
1494+
git submodule add ../child-origin child &&
1495+
git commit -m "Add submodule child" &&
1496+
1497+
git mv child child_old &&
1498+
git commit -m "Move child to child_old" &&
1499+
1500+
# Now adding a *new* repo at the old name must fail
1501+
git init ../child2-origin &&
1502+
git -C ../child2-origin commit --allow-empty -m init &&
1503+
test_must_fail git submodule add ../child2-origin child
1504+
)
1505+
'
1506+
1507+
14851508
test_done

0 commit comments

Comments
 (0)