mirror of
https://github.com/git/git.git
synced 2024-11-24 18:33:43 +08:00
Merge branch 'sb/submodule-recursive-absorb'
When a submodule "A", which has another submodule "B" nested within it, is "absorbed" into the top-level superproject, the inner submodule "B" used to be left in a strange state. The logic to adjust the .git pointers in these submodules has been corrected. * sb/submodule-recursive-absorb: submodule absorbing: fix worktree/gitdir pointers recursively for non-moves cache.h: expose the dying procedure for reading gitlinks setup: add gentle version of resolve_git_dir
This commit is contained in:
commit
5348021c67
5
cache.h
5
cache.h
@ -507,9 +507,12 @@ extern int is_nonbare_repository_dir(struct strbuf *path);
|
||||
#define READ_GITFILE_ERR_NO_PATH 6
|
||||
#define READ_GITFILE_ERR_NOT_A_REPO 7
|
||||
#define READ_GITFILE_ERR_TOO_LARGE 8
|
||||
extern void read_gitfile_error_die(int error_code, const char *path, const char *dir);
|
||||
extern const char *read_gitfile_gently(const char *path, int *return_error_code);
|
||||
#define read_gitfile(path) read_gitfile_gently((path), NULL)
|
||||
extern const char *resolve_gitdir(const char *suspect);
|
||||
extern const char *resolve_gitdir_gently(const char *suspect, int *return_error_code);
|
||||
#define resolve_gitdir(path) resolve_gitdir_gently((path), NULL)
|
||||
|
||||
extern void set_git_work_tree(const char *tree);
|
||||
|
||||
#define ALTERNATE_DB_ENVIRONMENT "GIT_ALTERNATE_OBJECT_DIRECTORIES"
|
||||
|
52
setup.c
52
setup.c
@ -486,6 +486,30 @@ int verify_repository_format(const struct repository_format *format,
|
||||
return 0;
|
||||
}
|
||||
|
||||
void read_gitfile_error_die(int error_code, const char *path, const char *dir)
|
||||
{
|
||||
switch (error_code) {
|
||||
case READ_GITFILE_ERR_STAT_FAILED:
|
||||
case READ_GITFILE_ERR_NOT_A_FILE:
|
||||
/* non-fatal; follow return path */
|
||||
break;
|
||||
case READ_GITFILE_ERR_OPEN_FAILED:
|
||||
die_errno("Error opening '%s'", path);
|
||||
case READ_GITFILE_ERR_TOO_LARGE:
|
||||
die("Too large to be a .git file: '%s'", path);
|
||||
case READ_GITFILE_ERR_READ_FAILED:
|
||||
die("Error reading %s", path);
|
||||
case READ_GITFILE_ERR_INVALID_FORMAT:
|
||||
die("Invalid gitfile format: %s", path);
|
||||
case READ_GITFILE_ERR_NO_PATH:
|
||||
die("No path in gitfile: %s", path);
|
||||
case READ_GITFILE_ERR_NOT_A_REPO:
|
||||
die("Not a git repository: %s", dir);
|
||||
default:
|
||||
die("BUG: unknown error code");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to read the location of the git directory from the .git file,
|
||||
* return path to git directory if found.
|
||||
@ -559,28 +583,8 @@ const char *read_gitfile_gently(const char *path, int *return_error_code)
|
||||
cleanup_return:
|
||||
if (return_error_code)
|
||||
*return_error_code = error_code;
|
||||
else if (error_code) {
|
||||
switch (error_code) {
|
||||
case READ_GITFILE_ERR_STAT_FAILED:
|
||||
case READ_GITFILE_ERR_NOT_A_FILE:
|
||||
/* non-fatal; follow return path */
|
||||
break;
|
||||
case READ_GITFILE_ERR_OPEN_FAILED:
|
||||
die_errno("Error opening '%s'", path);
|
||||
case READ_GITFILE_ERR_TOO_LARGE:
|
||||
die("Too large to be a .git file: '%s'", path);
|
||||
case READ_GITFILE_ERR_READ_FAILED:
|
||||
die("Error reading %s", path);
|
||||
case READ_GITFILE_ERR_INVALID_FORMAT:
|
||||
die("Invalid gitfile format: %s", path);
|
||||
case READ_GITFILE_ERR_NO_PATH:
|
||||
die("No path in gitfile: %s", path);
|
||||
case READ_GITFILE_ERR_NOT_A_REPO:
|
||||
die("Not a git repository: %s", dir);
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
else if (error_code)
|
||||
read_gitfile_error_die(error_code, path, dir);
|
||||
|
||||
free(buf);
|
||||
return error_code ? NULL : path;
|
||||
@ -1017,11 +1021,11 @@ const char *setup_git_directory(void)
|
||||
return setup_git_directory_gently(NULL);
|
||||
}
|
||||
|
||||
const char *resolve_gitdir(const char *suspect)
|
||||
const char *resolve_gitdir_gently(const char *suspect, int *return_error_code)
|
||||
{
|
||||
if (is_git_directory(suspect))
|
||||
return suspect;
|
||||
return read_gitfile(suspect);
|
||||
return read_gitfile_gently(suspect, return_error_code);
|
||||
}
|
||||
|
||||
/* if any standard file descriptor is missing open it to /dev/null */
|
||||
|
62
submodule.c
62
submodule.c
@ -1437,22 +1437,57 @@ void absorb_git_dir_into_superproject(const char *prefix,
|
||||
const char *path,
|
||||
unsigned flags)
|
||||
{
|
||||
const char *sub_git_dir, *v;
|
||||
char *real_sub_git_dir = NULL, *real_common_git_dir = NULL;
|
||||
int err_code;
|
||||
const char *sub_git_dir;
|
||||
struct strbuf gitdir = STRBUF_INIT;
|
||||
|
||||
strbuf_addf(&gitdir, "%s/.git", path);
|
||||
sub_git_dir = resolve_gitdir(gitdir.buf);
|
||||
sub_git_dir = resolve_gitdir_gently(gitdir.buf, &err_code);
|
||||
|
||||
/* Not populated? */
|
||||
if (!sub_git_dir)
|
||||
goto out;
|
||||
if (!sub_git_dir) {
|
||||
char *real_new_git_dir;
|
||||
const char *new_git_dir;
|
||||
const struct submodule *sub;
|
||||
|
||||
/* Is it already absorbed into the superprojects git dir? */
|
||||
real_sub_git_dir = real_pathdup(sub_git_dir);
|
||||
real_common_git_dir = real_pathdup(get_git_common_dir());
|
||||
if (!skip_prefix(real_sub_git_dir, real_common_git_dir, &v))
|
||||
relocate_single_git_dir_into_superproject(prefix, path);
|
||||
if (err_code == READ_GITFILE_ERR_STAT_FAILED) {
|
||||
/* unpopulated as expected */
|
||||
strbuf_release(&gitdir);
|
||||
return;
|
||||
}
|
||||
|
||||
if (err_code != READ_GITFILE_ERR_NOT_A_REPO)
|
||||
/* We don't know what broke here. */
|
||||
read_gitfile_error_die(err_code, path, NULL);
|
||||
|
||||
/*
|
||||
* Maybe populated, but no git directory was found?
|
||||
* This can happen if the superproject is a submodule
|
||||
* itself and was just absorbed. The absorption of the
|
||||
* superproject did not rewrite the git file links yet,
|
||||
* fix it now.
|
||||
*/
|
||||
sub = submodule_from_path(null_sha1, path);
|
||||
if (!sub)
|
||||
die(_("could not lookup name for submodule '%s'"), path);
|
||||
new_git_dir = git_path("modules/%s", sub->name);
|
||||
if (safe_create_leading_directories_const(new_git_dir) < 0)
|
||||
die(_("could not create directory '%s'"), new_git_dir);
|
||||
real_new_git_dir = real_pathdup(new_git_dir);
|
||||
connect_work_tree_and_git_dir(path, real_new_git_dir);
|
||||
|
||||
free(real_new_git_dir);
|
||||
} else {
|
||||
/* Is it already absorbed into the superprojects git dir? */
|
||||
char *real_sub_git_dir = real_pathdup(sub_git_dir);
|
||||
char *real_common_git_dir = real_pathdup(get_git_common_dir());
|
||||
|
||||
if (!starts_with(real_sub_git_dir, real_common_git_dir))
|
||||
relocate_single_git_dir_into_superproject(prefix, path);
|
||||
|
||||
free(real_sub_git_dir);
|
||||
free(real_common_git_dir);
|
||||
}
|
||||
strbuf_release(&gitdir);
|
||||
|
||||
if (flags & ABSORB_GITDIR_RECURSE_SUBMODULES) {
|
||||
struct child_process cp = CHILD_PROCESS_INIT;
|
||||
@ -1478,9 +1513,4 @@ void absorb_git_dir_into_superproject(const char *prefix,
|
||||
|
||||
strbuf_release(&sb);
|
||||
}
|
||||
|
||||
out:
|
||||
strbuf_release(&gitdir);
|
||||
free(real_sub_git_dir);
|
||||
free(real_common_git_dir);
|
||||
}
|
||||
|
@ -64,6 +64,33 @@ test_expect_success 'absorb the git dir in a nested submodule' '
|
||||
test_cmp expect.2 actual.2
|
||||
'
|
||||
|
||||
test_expect_success 're-setup nested submodule' '
|
||||
# un-absorb the direct submodule, to test if the nested submodule
|
||||
# is still correct (needs a rewrite of the gitfile only)
|
||||
rm -rf sub1/.git &&
|
||||
mv .git/modules/sub1 sub1/.git &&
|
||||
GIT_WORK_TREE=. git -C sub1 config --unset core.worktree &&
|
||||
# fixup the nested submodule
|
||||
echo "gitdir: ../.git/modules/nested" >sub1/nested/.git &&
|
||||
GIT_WORK_TREE=../../../nested git -C sub1/.git/modules/nested config \
|
||||
core.worktree "../../../nested" &&
|
||||
# make sure this re-setup is correct
|
||||
git status --ignore-submodules=none
|
||||
'
|
||||
|
||||
test_expect_success 'absorb the git dir in a nested submodule' '
|
||||
git status >expect.1 &&
|
||||
git -C sub1/nested rev-parse HEAD >expect.2 &&
|
||||
git submodule absorbgitdirs &&
|
||||
test -f sub1/.git &&
|
||||
test -f sub1/nested/.git &&
|
||||
test -d .git/modules/sub1/modules/nested &&
|
||||
git status >actual.1 &&
|
||||
git -C sub1/nested rev-parse HEAD >actual.2 &&
|
||||
test_cmp expect.1 actual.1 &&
|
||||
test_cmp expect.2 actual.2
|
||||
'
|
||||
|
||||
test_expect_success 'setup a gitlink with missing .gitmodules entry' '
|
||||
git init sub2 &&
|
||||
test_commit -C sub2 first &&
|
||||
|
Loading…
Reference in New Issue
Block a user