git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
* [PATCH] submodule absorbing: fix worktree/gitdir pointers recursively for non-moves
@ 2017-01-24 21:03 Stefan Beller
  2017-01-24 21:58 ` Brandon Williams
  0 siblings, 1 reply; 13+ messages in thread
From: Stefan Beller @ 2017-01-24 21:03 UTC (permalink / raw)
  To: gitster; +Cc: git, bmwill, peff, Stefan Beller

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 <sbeller@google.com>
---

  cc Jeff and Brandon, who worked on the setup code recently,
  and the alternative design mentioned was messing around a lot in setup.c.
  
  Thanks,
  Stefan

 submodule.c                        | 41 +++++++++++++++++++-------------------
 t/t7412-submodule-absorbgitdirs.sh | 27 +++++++++++++++++++++++++
 2 files changed, 48 insertions(+), 20 deletions(-)

diff --git a/submodule.c b/submodule.c
index 4c4f033e8a..7deb0fca6a 100644
--- a/submodule.c
+++ b/submodule.c
@@ -1393,16 +1393,9 @@ static void relocate_single_git_dir_into_superproject(const char *prefix,
 	char *old_git_dir = NULL, *real_old_git_dir = NULL, *real_new_git_dir = NULL;
 	const char *new_git_dir;
 	const struct submodule *sub;
-
-	if (submodule_uses_worktrees(path))
-		die(_("relocate_gitdir for submodule '%s' with "
-		      "more than one worktree not supported"), path);
+	int err_code;
 
 	old_git_dir = xstrfmt("%s/.git", path);
-	if (read_gitfile(old_git_dir))
-		/* If it is an actual gitfile, it doesn't need migration. */
-		return;
-
 	real_old_git_dir = real_pathdup(old_git_dir);
 
 	sub = submodule_from_path(null_sha1, path);
@@ -1414,6 +1407,24 @@ static void relocate_single_git_dir_into_superproject(const char *prefix,
 		die(_("could not create directory '%s'"), new_git_dir);
 	real_new_git_dir = real_pathdup(new_git_dir);
 
+	if (read_gitfile_gently(old_git_dir, &err_code) ||
+	    err_code == READ_GITFILE_ERR_NOT_A_REPO) {
+		/*
+		 * If it is an actual gitfile, it doesn't need migration,
+		 * however in case of a recursively nested submodule, the
+		 * gitfile content may be stale, as its superproject
+		 * (which may be a submodule of another superproject)
+		 * may have been moved. So expect a bogus pointer to be read,
+		 * which materializes as error READ_GITFILE_ERR_NOT_A_REPO.
+		 */
+		connect_work_tree_and_git_dir(path, real_new_git_dir);
+		return;
+	}
+
+	if (submodule_uses_worktrees(path))
+		die(_("relocate_gitdir for submodule '%s' with "
+		      "more than one worktree not supported"), path);
+
 	if (!prefix)
 		prefix = get_super_prefix();
 
@@ -1437,22 +1448,14 @@ 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;
 	struct strbuf gitdir = STRBUF_INIT;
-
 	strbuf_addf(&gitdir, "%s/.git", path);
-	sub_git_dir = resolve_gitdir(gitdir.buf);
 
 	/* Not populated? */
-	if (!sub_git_dir)
+	if (!file_exists(gitdir.buf))
 		goto out;
 
-	/* 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);
+	relocate_single_git_dir_into_superproject(prefix, path);
 
 	if (flags & ABSORB_GITDIR_RECURSE_SUBMODULES) {
 		struct child_process cp = CHILD_PROCESS_INIT;
@@ -1481,6 +1484,4 @@ void absorb_git_dir_into_superproject(const char *prefix,
 
 out:
 	strbuf_release(&gitdir);
-	free(real_sub_git_dir);
-	free(real_common_git_dir);
 }
diff --git a/t/t7412-submodule-absorbgitdirs.sh b/t/t7412-submodule-absorbgitdirs.sh
index 1c47780e2b..e2bbb449b6 100755
--- a/t/t7412-submodule-absorbgitdirs.sh
+++ b/t/t7412-submodule-absorbgitdirs.sh
@@ -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 &&
-- 
2.11.0.486.g67830dbe1c


^ permalink raw reply related	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2017-01-25 23:40 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-01-24 21:03 [PATCH] submodule absorbing: fix worktree/gitdir pointers recursively for non-moves Stefan Beller
2017-01-24 21:58 ` Brandon Williams
2017-01-24 22:13   ` Stefan Beller
2017-01-24 22:19     ` Brandon Williams
2017-01-24 23:56       ` [PATCHv2 0/3] fix recursive submodule absorbing Stefan Beller
2017-01-24 23:56         ` [PATCHv2 1/3] Add gentle version of resolve_git_dir Stefan Beller
2017-01-24 23:56         ` [PATCHv2 2/3] cache.h: expose the dying procedure for reading gitlinks Stefan Beller
2017-01-24 23:56         ` [PATCHv2 3/3] submodule absorbing: fix worktree/gitdir pointers recursively for non-moves Stefan Beller
2017-01-25  0:46           ` Brandon Williams
2017-01-25 23:04             ` Stefan Beller
2017-01-25 22:54           ` Junio C Hamano
2017-01-25 23:04             ` [PATCHv3 " Stefan Beller
2017-01-25 23:39               ` Brandon Williams

Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).