提交 5348021c 编写于 作者: J Junio C Hamano

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
...@@ -507,9 +507,12 @@ extern int is_nonbare_repository_dir(struct strbuf *path); ...@@ -507,9 +507,12 @@ extern int is_nonbare_repository_dir(struct strbuf *path);
#define READ_GITFILE_ERR_NO_PATH 6 #define READ_GITFILE_ERR_NO_PATH 6
#define READ_GITFILE_ERR_NOT_A_REPO 7 #define READ_GITFILE_ERR_NOT_A_REPO 7
#define READ_GITFILE_ERR_TOO_LARGE 8 #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); extern const char *read_gitfile_gently(const char *path, int *return_error_code);
#define read_gitfile(path) read_gitfile_gently((path), NULL) #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); extern void set_git_work_tree(const char *tree);
#define ALTERNATE_DB_ENVIRONMENT "GIT_ALTERNATE_OBJECT_DIRECTORIES" #define ALTERNATE_DB_ENVIRONMENT "GIT_ALTERNATE_OBJECT_DIRECTORIES"
......
...@@ -486,6 +486,30 @@ int verify_repository_format(const struct repository_format *format, ...@@ -486,6 +486,30 @@ int verify_repository_format(const struct repository_format *format,
return 0; 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, * Try to read the location of the git directory from the .git file,
* return path to git directory if found. * return path to git directory if found.
...@@ -559,28 +583,8 @@ const char *read_gitfile_gently(const char *path, int *return_error_code) ...@@ -559,28 +583,8 @@ const char *read_gitfile_gently(const char *path, int *return_error_code)
cleanup_return: cleanup_return:
if (return_error_code) if (return_error_code)
*return_error_code = error_code; *return_error_code = error_code;
else if (error_code) { else if (error_code)
switch (error_code) { read_gitfile_error_die(error_code, path, dir);
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);
}
}
free(buf); free(buf);
return error_code ? NULL : path; return error_code ? NULL : path;
...@@ -1017,11 +1021,11 @@ const char *setup_git_directory(void) ...@@ -1017,11 +1021,11 @@ const char *setup_git_directory(void)
return setup_git_directory_gently(NULL); 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)) if (is_git_directory(suspect))
return 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 */ /* if any standard file descriptor is missing open it to /dev/null */
......
...@@ -1437,22 +1437,57 @@ void absorb_git_dir_into_superproject(const char *prefix, ...@@ -1437,22 +1437,57 @@ void absorb_git_dir_into_superproject(const char *prefix,
const char *path, const char *path,
unsigned flags) unsigned flags)
{ {
const char *sub_git_dir, *v; int err_code;
char *real_sub_git_dir = NULL, *real_common_git_dir = NULL; const char *sub_git_dir;
struct strbuf gitdir = STRBUF_INIT; struct strbuf gitdir = STRBUF_INIT;
strbuf_addf(&gitdir, "%s/.git", path); 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? */ /* Not populated? */
if (!sub_git_dir) if (!sub_git_dir) {
goto out; char *real_new_git_dir;
const char *new_git_dir;
const struct submodule *sub;
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());
/* Is it already absorbed into the superprojects git dir? */ if (!starts_with(real_sub_git_dir, real_common_git_dir))
real_sub_git_dir = real_pathdup(sub_git_dir); relocate_single_git_dir_into_superproject(prefix, path);
real_common_git_dir = real_pathdup(get_git_common_dir());
if (!skip_prefix(real_sub_git_dir, real_common_git_dir, &v)) free(real_sub_git_dir);
relocate_single_git_dir_into_superproject(prefix, path); free(real_common_git_dir);
}
strbuf_release(&gitdir);
if (flags & ABSORB_GITDIR_RECURSE_SUBMODULES) { if (flags & ABSORB_GITDIR_RECURSE_SUBMODULES) {
struct child_process cp = CHILD_PROCESS_INIT; struct child_process cp = CHILD_PROCESS_INIT;
...@@ -1478,9 +1513,4 @@ void absorb_git_dir_into_superproject(const char *prefix, ...@@ -1478,9 +1513,4 @@ void absorb_git_dir_into_superproject(const char *prefix,
strbuf_release(&sb); 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' ' ...@@ -64,6 +64,33 @@ test_expect_success 'absorb the git dir in a nested submodule' '
test_cmp expect.2 actual.2 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' ' test_expect_success 'setup a gitlink with missing .gitmodules entry' '
git init sub2 && git init sub2 &&
test_commit -C sub2 first && test_commit -C sub2 first &&
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册