Skip to content

Commit ec9629b

Browse files
stefanbellergitster
authored andcommitted
submodule absorbing: fix worktree/gitdir pointers recursively for non-moves
Consider having a submodule 'sub' and a nested submodule at 'sub/nested'. When nested is already absorbed into sub, but sub is not absorbed into its superproject, then we need to fixup the gitfile and core.worktree setting for 'nested' when absorbing 'sub', but we do not need to move its git dir around. Previously 'nested's gitfile contained "gitdir: ../.git/modules/nested"; it has to be corrected to "gitdir: ../../.git/modules/sub1/modules/nested". An alternative I considered to do this work lazily, i.e. when resolving "../.git/modules/nested", we would notice the ".git" being a gitfile linking to another path. That seemed to be robuster by design, but harder to get the implementation right. Maybe we have to do that anyway once we try to have submodules and worktrees working nicely together, but for now just produce 'correct' (i.e. direct) pointers. Signed-off-by: Stefan Beller <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 5f29433 commit ec9629b

File tree

2 files changed

+73
-16
lines changed

2 files changed

+73
-16
lines changed

submodule.c

Lines changed: 46 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1437,22 +1437,57 @@ void absorb_git_dir_into_superproject(const char *prefix,
14371437
const char *path,
14381438
unsigned flags)
14391439
{
1440-
const char *sub_git_dir, *v;
1441-
char *real_sub_git_dir = NULL, *real_common_git_dir = NULL;
1440+
int err_code;
1441+
const char *sub_git_dir;
14421442
struct strbuf gitdir = STRBUF_INIT;
1443-
14441443
strbuf_addf(&gitdir, "%s/.git", path);
1445-
sub_git_dir = resolve_gitdir(gitdir.buf);
1444+
sub_git_dir = resolve_gitdir_gently(gitdir.buf, &err_code);
14461445

14471446
/* Not populated? */
1448-
if (!sub_git_dir)
1449-
goto out;
1447+
if (!sub_git_dir) {
1448+
char *real_new_git_dir;
1449+
const char *new_git_dir;
1450+
const struct submodule *sub;
1451+
1452+
if (err_code == READ_GITFILE_ERR_STAT_FAILED) {
1453+
/* unpopulated as expected */
1454+
strbuf_release(&gitdir);
1455+
return;
1456+
}
1457+
1458+
if (err_code != READ_GITFILE_ERR_NOT_A_REPO)
1459+
/* We don't know what broke here. */
1460+
read_gitfile_error_die(err_code, path, NULL);
1461+
1462+
/*
1463+
* Maybe populated, but no git directory was found?
1464+
* This can happen if the superproject is a submodule
1465+
* itself and was just absorbed. The absorption of the
1466+
* superproject did not rewrite the git file links yet,
1467+
* fix it now.
1468+
*/
1469+
sub = submodule_from_path(null_sha1, path);
1470+
if (!sub)
1471+
die(_("could not lookup name for submodule '%s'"), path);
1472+
new_git_dir = git_path("modules/%s", sub->name);
1473+
if (safe_create_leading_directories_const(new_git_dir) < 0)
1474+
die(_("could not create directory '%s'"), new_git_dir);
1475+
real_new_git_dir = real_pathdup(new_git_dir);
1476+
connect_work_tree_and_git_dir(path, real_new_git_dir);
1477+
1478+
free(real_new_git_dir);
1479+
} else {
1480+
/* Is it already absorbed into the superprojects git dir? */
1481+
char *real_sub_git_dir = real_pathdup(sub_git_dir);
1482+
char *real_common_git_dir = real_pathdup(get_git_common_dir());
14501483

1451-
/* Is it already absorbed into the superprojects git dir? */
1452-
real_sub_git_dir = real_pathdup(sub_git_dir);
1453-
real_common_git_dir = real_pathdup(get_git_common_dir());
1454-
if (!skip_prefix(real_sub_git_dir, real_common_git_dir, &v))
1455-
relocate_single_git_dir_into_superproject(prefix, path);
1484+
if (!starts_with(real_sub_git_dir, real_common_git_dir))
1485+
relocate_single_git_dir_into_superproject(prefix, path);
1486+
1487+
free(real_sub_git_dir);
1488+
free(real_common_git_dir);
1489+
}
1490+
strbuf_release(&gitdir);
14561491

14571492
if (flags & ABSORB_GITDIR_RECURSE_SUBMODULES) {
14581493
struct child_process cp = CHILD_PROCESS_INIT;
@@ -1478,9 +1513,4 @@ void absorb_git_dir_into_superproject(const char *prefix,
14781513

14791514
strbuf_release(&sb);
14801515
}
1481-
1482-
out:
1483-
strbuf_release(&gitdir);
1484-
free(real_sub_git_dir);
1485-
free(real_common_git_dir);
14861516
}

t/t7412-submodule-absorbgitdirs.sh

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,33 @@ test_expect_success 'absorb the git dir in a nested submodule' '
6464
test_cmp expect.2 actual.2
6565
'
6666

67+
test_expect_success 're-setup nested submodule' '
68+
# un-absorb the direct submodule, to test if the nested submodule
69+
# is still correct (needs a rewrite of the gitfile only)
70+
rm -rf sub1/.git &&
71+
mv .git/modules/sub1 sub1/.git &&
72+
GIT_WORK_TREE=. git -C sub1 config --unset core.worktree &&
73+
# fixup the nested submodule
74+
echo "gitdir: ../.git/modules/nested" >sub1/nested/.git &&
75+
GIT_WORK_TREE=../../../nested git -C sub1/.git/modules/nested config \
76+
core.worktree "../../../nested" &&
77+
# make sure this re-setup is correct
78+
git status --ignore-submodules=none
79+
'
80+
81+
test_expect_success 'absorb the git dir in a nested submodule' '
82+
git status >expect.1 &&
83+
git -C sub1/nested rev-parse HEAD >expect.2 &&
84+
git submodule absorbgitdirs &&
85+
test -f sub1/.git &&
86+
test -f sub1/nested/.git &&
87+
test -d .git/modules/sub1/modules/nested &&
88+
git status >actual.1 &&
89+
git -C sub1/nested rev-parse HEAD >actual.2 &&
90+
test_cmp expect.1 actual.1 &&
91+
test_cmp expect.2 actual.2
92+
'
93+
6794
test_expect_success 'setup a gitlink with missing .gitmodules entry' '
6895
git init sub2 &&
6996
test_commit -C sub2 first &&

0 commit comments

Comments
 (0)