{"thread":{"id":"44586","subject":"[PATCHv3 1/5] submodule: use absolute path for computing relative path connecting","startedAt":"2016-12-01T20:26:15Z","lastAt":"2016-12-01T20:26:33Z","messageCount":6,"participants":["Stefan Beller"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"306737","messageId":"20161201202554.19944-2-sbeller@google.com","threadId":"44586","inReplyTo":"20161201202554.19944-1-sbeller@google.com","subject":"[PATCHv3 1/5] submodule: use absolute path for computing relative path connecting","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2016-12-01T20:25:50Z","receivedAt":"2016-12-01T20:26:15Z","isPatch":false,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"The current caller of connect_work_tree_and_git_dir passes\nan absolute path for the `git_dir` parameter. In the future patch\nwe will also pass in relative path for `git_dir`. Extend the functionality\nof connect_work_tree_and_git_dir to take relative paths for parameters.\n\nWe could work around this in the future patch by computing the absolute\npath for the git_dir in the calling site, however accepting relative\npaths for either parameter makes the API for this function much harder\nto misuse.\n\nSigned-off-by: Stefan Beller <sbeller@google.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n submodule.c | 12 +++++++-----\n 1 file changed, 7 insertions(+), 5 deletions(-)\n\ndiff --git a/submodule.c b/submodule.c\nindex 6f7d883de9..66c5ce5a24 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -1227,23 +1227,25 @@ void connect_work_tree_and_git_dir(const char *work_tree, const char *git_dir)\n {\n \tstruct strbuf file_name = STRBUF_INIT;\n \tstruct strbuf rel_path = STRBUF_INIT;\n-\tconst char *real_work_tree = xstrdup(real_path(work_tree));\n+\tchar *real_git_dir = xstrdup(real_path(git_dir));\n+\tchar *real_work_tree = xstrdup(real_path(work_tree));\n \n \t/* Update gitfile */\n \tstrbuf_addf(&file_name, \"%s/.git\", work_tree);\n \twrite_file(file_name.buf, \"gitdir: %s\",\n-\t\t   relative_path(git_dir, real_work_tree, &rel_path));\n+\t\t   relative_path(real_git_dir, real_work_tree, &rel_path));\n \n \t/* Update core.worktree setting */\n \tstrbuf_reset(&file_name);\n-\tstrbuf_addf(&file_name, \"%s/config\", git_dir);\n+\tstrbuf_addf(&file_name, \"%s/config\", real_git_dir);\n \tgit_config_set_in_file(file_name.buf, \"core.worktree\",\n-\t\t\t       relative_path(real_work_tree, git_dir,\n+\t\t\t       relative_path(real_work_tree, real_git_dir,\n \t\t\t\t\t     &rel_path));\n \n \tstrbuf_release(&file_name);\n \tstrbuf_release(&rel_path);\n-\tfree((void *)real_work_tree);\n+\tfree(real_work_tree);\n+\tfree(real_git_dir);\n }\n \n int parallel_submodules(void)\n-- \n2.10.2.613.g22f2156\n\n"},{"id":"306738","messageId":"20161201202554.19944-3-sbeller@google.com","threadId":"44586","inReplyTo":"20161201202554.19944-1-sbeller@google.com","subject":"[PATCHv3 2/5] submodule helper: support super prefix","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2016-12-01T20:25:51Z","receivedAt":"2016-12-01T20:26:19Z","isPatch":false,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"Just like main commands in Git, the submodule helper needs\naccess to the superproject prefix. Enable this in the git.c\nbut have its own fuse in the helper code by having a flag to\nturn on the super prefix.\n\nSigned-off-by: Stefan Beller <sbeller@google.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/submodule--helper.c | 31 ++++++++++++++++++++-----------\n git.c                       |  2 +-\n 2 files changed, 21 insertions(+), 12 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 4beeda5f9f..806e29ce4e 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -1076,21 +1076,24 @@ static int resolve_remote_submodule_branch(int argc, const char **argv,\n \treturn 0;\n }\n \n+#define SUPPORT_SUPER_PREFIX (1<<0)\n+\n struct cmd_struct {\n \tconst char *cmd;\n \tint (*fn)(int, const char **, const char *);\n+\tint option;\n };\n \n static struct cmd_struct commands[] = {\n-\t{\"list\", module_list},\n-\t{\"name\", module_name},\n-\t{\"clone\", module_clone},\n-\t{\"update-clone\", update_clone},\n-\t{\"relative-path\", resolve_relative_path},\n-\t{\"resolve-relative-url\", resolve_relative_url},\n-\t{\"resolve-relative-url-test\", resolve_relative_url_test},\n-\t{\"init\", module_init},\n-\t{\"remote-branch\", resolve_remote_submodule_branch}\n+\t{\"list\", module_list, 0},\n+\t{\"name\", module_name, 0},\n+\t{\"clone\", module_clone, 0},\n+\t{\"update-clone\", update_clone, 0},\n+\t{\"relative-path\", resolve_relative_path, 0},\n+\t{\"resolve-relative-url\", resolve_relative_url, 0},\n+\t{\"resolve-relative-url-test\", resolve_relative_url_test, 0},\n+\t{\"init\", module_init, 0},\n+\t{\"remote-branch\", resolve_remote_submodule_branch, 0}\n };\n \n int cmd_submodule__helper(int argc, const char **argv, const char *prefix)\n@@ -1100,9 +1103,15 @@ int cmd_submodule__helper(int argc, const char **argv, const char *prefix)\n \t\tdie(_(\"submodule--helper subcommand must be \"\n \t\t      \"called with a subcommand\"));\n \n-\tfor (i = 0; i < ARRAY_SIZE(commands); i++)\n-\t\tif (!strcmp(argv[1], commands[i].cmd))\n+\tfor (i = 0; i < ARRAY_SIZE(commands); i++) {\n+\t\tif (!strcmp(argv[1], commands[i].cmd)) {\n+\t\t\tif (get_super_prefix() &&\n+\t\t\t    !(commands[i].option & SUPPORT_SUPER_PREFIX))\n+\t\t\t\tdie(\"%s doesn't support --super-prefix\",\n+\t\t\t\t    commands[i].cmd);\n \t\t\treturn commands[i].fn(argc - 1, argv + 1, prefix);\n+\t\t}\n+\t}\n \n \tdie(_(\"'%s' is not a valid submodule--helper \"\n \t      \"subcommand\"), argv[1]);\ndiff --git a/git.c b/git.c\nindex efa1059fe0..98dcf6c518 100644\n--- a/git.c\n+++ b/git.c\n@@ -493,7 +493,7 @@ static struct cmd_struct commands[] = {\n \t{ \"stage\", cmd_add, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"status\", cmd_status, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"stripspace\", cmd_stripspace },\n-\t{ \"submodule--helper\", cmd_submodule__helper, RUN_SETUP },\n+\t{ \"submodule--helper\", cmd_submodule__helper, RUN_SETUP | SUPPORT_SUPER_PREFIX},\n \t{ \"symbolic-ref\", cmd_symbolic_ref, RUN_SETUP },\n \t{ \"tag\", cmd_tag, RUN_SETUP },\n \t{ \"unpack-file\", cmd_unpack_file, RUN_SETUP },\n-- \n2.10.2.613.g22f2156\n\n"},{"id":"306739","messageId":"20161201202554.19944-4-sbeller@google.com","threadId":"44586","inReplyTo":"20161201202554.19944-1-sbeller@google.com","subject":"[PATCHv3 3/5] test-lib-functions.sh: teach test_commit -C <dir>","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2016-12-01T20:25:52Z","receivedAt":"2016-12-01T20:26:22Z","isPatch":false,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"Specifically when setting up submodule tests, it comes in handy if\nwe can create commits in repositories that are not at the root of\nthe tested trash dir. Add \"-C <dir>\" similar to gits -C parameter\nthat will perform the operation in the given directory.\n\nSigned-off-by: Stefan Beller <sbeller@google.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n t/test-lib-functions.sh | 20 +++++++++++++++-----\n 1 file changed, 15 insertions(+), 5 deletions(-)\n\ndiff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh\nindex fdaeb3a96b..579e812506 100644\n--- a/t/test-lib-functions.sh\n+++ b/t/test-lib-functions.sh\n@@ -157,16 +157,21 @@ debug () {\n \t GIT_TEST_GDB=1 \"$@\"\n }\n \n-# Call test_commit with the arguments \"<message> [<file> [<contents> [<tag>]]]\"\n+# Call test_commit with the arguments\n+# [-C <directory>] <message> [<file> [<contents> [<tag>]]]\"\n #\n # This will commit a file with the given contents and the given commit\n # message, and tag the resulting commit with the given tag name.\n #\n # <file>, <contents>, and <tag> all default to <message>.\n+#\n+# If the first argument is \"-C\", the second argument is used as a path for\n+# the git invocations.\n \n test_commit () {\n \tnotick= &&\n \tsignoff= &&\n+\tindir= &&\n \twhile test $# != 0\n \tdo\n \t\tcase \"$1\" in\n@@ -176,21 +181,26 @@ test_commit () {\n \t\t--signoff)\n \t\t\tsignoff=\"$1\"\n \t\t\t;;\n+\t\t-C)\n+\t\t\tindir=\"$2\"\n+\t\t\tshift\n+\t\t\t;;\n \t\t*)\n \t\t\tbreak\n \t\t\t;;\n \t\tesac\n \t\tshift\n \tdone &&\n+\tindir=${indir:+\"$indir\"/} &&\n \tfile=${2:-\"$1.t\"} &&\n-\techo \"${3-$1}\" > \"$file\" &&\n-\tgit add \"$file\" &&\n+\techo \"${3-$1}\" > \"$indir$file\" &&\n+\tgit ${indir:+ -C \"$indir\"} add \"$file\" &&\n \tif test -z \"$notick\"\n \tthen\n \t\ttest_tick\n \tfi &&\n-\tgit commit $signoff -m \"$1\" &&\n-\tgit tag \"${4:-$1}\"\n+\tgit ${indir:+ -C \"$indir\"} commit $signoff -m \"$1\" &&\n+\tgit ${indir:+ -C \"$indir\"} tag \"${4:-$1}\"\n }\n \n # Call test_merge with the arguments \"<message> <commit>\", where <commit>\n-- \n2.10.2.613.g22f2156\n\n"},{"id":"306740","messageId":"20161201202554.19944-1-sbeller@google.com","threadId":"44586","inReplyTo":null,"subject":"[PATCHv3 0/5] submodule embedgitdirs","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2016-12-01T20:25:49Z","receivedAt":"2016-12-01T20:26:29Z","isPatch":false,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"v3:\n* have a slightly more generic function \"relocate_gitdir\".\n  The recursion is strictly related to submodules, though.\n* bail out if a submodule is using worktrees.\n  This also lays the groundwork for later doing the proper thing,\n  as worktree.h offers a function `get_submodule_worktrees(path)`\n* nit by duy: use git_path instead of git_common_dir\n\n* diff to v2 (as queued by Junio) below.\n\nStefan Beller (5):\n  submodule: use absolute path for computing relative path connecting\n  submodule helper: support super prefix\n  test-lib-functions.sh: teach test_commit -C <dir>\n  worktree: get worktrees from submodules\n  submodule: add embed-git-dir function\n\n Documentation/git-submodule.txt   | 14 ++++++\n builtin/submodule--helper.c       | 68 ++++++++++++++++++++++++-----\n dir.c                             | 78 +++++++++++++++++++++++++++++++++\n dir.h                             |  4 ++\n git-submodule.sh                  |  7 ++-\n git.c                             |  2 +-\n submodule.c                       | 12 ++---\n submodule.h                       |  1 -\n t/t7412-submodule-embedgitdirs.sh | 92 +++++++++++++++++++++++++++++++++++++++\n t/test-lib-functions.sh           | 20 ++++++---\n worktree.c                        | 40 ++++++++++++-----\n worktree.h                        |  5 +++\n 12 files changed, 309 insertions(+), 34 deletions(-)\n create mode 100755 t/t7412-submodule-embedgitdirs.sh\n\nv2:\n* fixed commit message for patch:\n \"submodule: use absolute path for computing relative path connecting\"\n* a new patch \"submodule helper: support super prefix\"\n* redid the final patch with more tests and fixing bugs along the way\n* \"test-lib-functions.sh: teach test_commit -C <dir>\" unchanged\n\nv1:\nThe discussion of the submodule checkout series revealed to me that a command\nis needed to move the git directory from the submodules working tree to be\nembedded into the superprojects git directory.\n\nSo I wrote the code to intern the submodules git dir into the superproject,\nbut whilst writing the code I realized this could be valueable for our use\nin testing too. So I exposed it via the submodule--helper. But as the\nsubmodule helper ought to be just an internal API, we could also\noffer it via the proper submodule command.\n\nThe command as it is has little value to the end user for now, but\nbreaking it out of the submodule checkout series hopefully makes review easier.\n\nThanks,\nStefan\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 75cdbf45b8..f2df166d15 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -1081,11 +1081,14 @@ static int embed_git_dir(int argc, const char **argv, const char *prefix)\n \tint i;\n \tstruct pathspec pathspec;\n \tstruct module_list list = MODULE_LIST_INIT;\n+\tunsigned flags = RELOCATE_GITDIR_RECURSE_SUBMODULES;\n \n \tstruct option embed_gitdir_options[] = {\n \t\tOPT_STRING(0, \"prefix\", &prefix,\n \t\t\t   N_(\"path\"),\n \t\t\t   N_(\"path into the working tree\")),\n+\t\tOPT_BIT(0, \"--recursive\", &flags, N_(\"recurse into submodules\"),\n+\t\t\tRELOCATE_GITDIR_RECURSE_SUBMODULES),\n \t\tOPT_END()\n \t};\n \n@@ -1104,7 +1107,7 @@ static int embed_git_dir(int argc, const char **argv, const char *prefix)\n \t\treturn 1;\n \n \tfor (i = 0; i < list.nr; i++)\n-\t\tmigrate_submodule_gitdir(prefix, list.entries[i]->name, 1);\n+\t\trelocate_gitdir(prefix, list.entries[i]->name, flags);\n \n \treturn 0;\n }\ndiff --git a/dir.c b/dir.c\nindex bfa8c8a9a5..7b3abc1340 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -15,6 +15,9 @@\n #include \"utf8.h\"\n #include \"varint.h\"\n #include \"ewah/ewok.h\"\n+#include \"submodule-config.h\"\n+#include \"run-command.h\"\n+#include \"worktree.h\"\n \n struct path_simplify {\n \tint len;\n@@ -2748,3 +2751,78 @@ void untracked_cache_add_to_index(struct index_state *istate,\n {\n \tuntracked_cache_invalidate_path(istate, path);\n }\n+\n+/*\n+ * Migrate the given submodule (and all its submodules recursively) from\n+ * having its git directory within the working tree to the git dir nested\n+ * in its superprojects git dir under modules/.\n+ */\n+void relocate_gitdir(const char *prefix, const char *path, unsigned flags)\n+{\n+\tchar *old_git_dir;\n+\tconst char *new_git_dir;\n+\tconst struct submodule *sub;\n+\tstruct worktree **worktrees;\n+\tint i;\n+\n+\tworktrees = get_submodule_worktrees(path);\n+\tfor (i = 0; worktrees[i]; i++)\n+\t\t;\n+\tif (i > 1)\n+\t\tdie(_(\"relocate_gitdir for submodule with more than one worktree not supported\"));\n+\n+\told_git_dir = xstrfmt(\"%s/.git\", path);\n+\tif (read_gitfile(old_git_dir))\n+\t\t/* If it is an actual gitfile, it doesn't need migration. */\n+\t\tgoto out;\n+\n+\tsub = submodule_from_path(null_sha1, path);\n+\tif (!sub)\n+\t\tdie(_(\"Could not lookup name for submodule '%s'\"),\n+\t\t      path);\n+\n+\tnew_git_dir = git_path(\"modules/%s\", sub->name);\n+\tif (safe_create_leading_directories_const(new_git_dir) < 0)\n+\t\tdie(_(\"could not create directory '%s'\"), new_git_dir);\n+\n+\tif (!prefix)\n+\t\tprefix = get_super_prefix();\n+\tprintf(\"Migrating git directory of %s%s from\\n'%s' to\\n'%s'\\n\",\n+\t\tprefix ? prefix : \"\", path,\n+\t\treal_path(old_git_dir), new_git_dir);\n+\n+\tif (rename(old_git_dir, new_git_dir) < 0)\n+\t\tdie_errno(_(\"Could not migrate git directory from '%s' to '%s'\"),\n+\t\t\told_git_dir, new_git_dir);\n+\n+\tconnect_work_tree_and_git_dir(path, new_git_dir);\n+\n+out:\n+\tif (flags & RELOCATE_GITDIR_RECURSE_SUBMODULES) {\n+\t\tstruct child_process cp = CHILD_PROCESS_INIT;\n+\t\tstruct strbuf sb = STRBUF_INIT;\n+\n+\t\tif (flags & ~RELOCATE_GITDIR_RECURSE_SUBMODULES)\n+\t\t\tdie(\"BUG: we don't know how to pass the flags down?\");\n+\n+\t\tif (get_super_prefix())\n+\t\t\tstrbuf_addstr(&sb, get_super_prefix());\n+\t\tstrbuf_addstr(&sb, path);\n+\t\tstrbuf_addch(&sb, '/');\n+\n+\t\tcp.dir = path;\n+\t\tcp.git_cmd = 1;\n+\t\tcp.no_stdin = 1;\n+\t\targv_array_pushl(&cp.args, \"--super-prefix\", sb.buf,\n+\t\t\t\t\t    \"submodule--helper\",\n+\t\t\t\t\t   \"embed-git-dirs\", NULL);\n+\t\tprepare_submodule_repo_env(&cp.env_array);\n+\t\tif (run_command(&cp))\n+\t\t\tdie(_(\"Could not migrate git directory in submodule '%s'\"),\n+\t\t\t    path);\n+\n+\t\tstrbuf_release(&sb);\n+\t}\n+\n+\tfree(old_git_dir);\n+}\ndiff --git a/dir.h b/dir.h\nindex 97c83bb383..0b5e99b21d 100644\n--- a/dir.h\n+++ b/dir.h\n@@ -335,4 +335,8 @@ struct untracked_cache *read_untracked_extension(const void *data, unsigned long\n void write_untracked_extension(struct strbuf *out, struct untracked_cache *untracked);\n void add_untracked_cache(struct index_state *istate);\n void remove_untracked_cache(struct index_state *istate);\n+\n+#define RELOCATE_GITDIR_RECURSE_SUBMODULES (1<<0)\n+extern void relocate_gitdir(const char *prefix, const char *path, unsigned flags);\n+\n #endif\ndiff --git a/submodule.c b/submodule.c\nindex d330b567a3..66c5ce5a24 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -1263,68 +1263,3 @@ void prepare_submodule_repo_env(struct argv_array *out)\n \t}\n \targv_array_push(out, \"GIT_DIR=.git\");\n }\n-\n-/*\n- * Migrate the given submodule (and all its submodules recursively) from\n- * having its git directory within the working tree to the git dir nested\n- * in its superprojects git dir under modules/.\n- */\n-void migrate_submodule_gitdir(const char *prefix, const char *path,\n-\t\t\t      int recursive)\n-{\n-\tchar *old_git_dir;\n-\tconst char *new_git_dir;\n-\tconst struct submodule *sub;\n-\n-\told_git_dir = xstrfmt(\"%s/.git\", path);\n-\tif (read_gitfile(old_git_dir))\n-\t\t/* If it is an actual gitfile, it doesn't need migration. */\n-\t\tgoto out;\n-\n-\tsub = submodule_from_path(null_sha1, path);\n-\tif (!sub)\n-\t\tdie(_(\"Could not lookup name for submodule '%s'\"),\n-\t\t      path);\n-\n-\tnew_git_dir = git_common_path(\"modules/%s\", sub->name);\n-\tif (safe_create_leading_directories_const(new_git_dir) < 0)\n-\t\tdie(_(\"could not create directory '%s'\"), new_git_dir);\n-\n-\tif (!prefix)\n-\t\tprefix = get_super_prefix();\n-\tprintf(\"Migrating git directory of %s%s from\\n'%s' to\\n'%s'\\n\",\n-\t\tprefix ? prefix : \"\", path,\n-\t\treal_path(old_git_dir), new_git_dir);\n-\n-\tif (rename(old_git_dir, new_git_dir) < 0)\n-\t\tdie_errno(_(\"Could not migrate git directory from '%s' to '%s'\"),\n-\t\t\told_git_dir, new_git_dir);\n-\n-\tconnect_work_tree_and_git_dir(path, new_git_dir);\n-\n-out:\n-\tif (recursive) {\n-\t\tstruct child_process cp = CHILD_PROCESS_INIT;\n-\t\tstruct strbuf sb = STRBUF_INIT;\n-\n-\t\tif (get_super_prefix())\n-\t\t\tstrbuf_addstr(&sb, get_super_prefix());\n-\t\tstrbuf_addstr(&sb, path);\n-\t\tstrbuf_addch(&sb, '/');\n-\n-\t\tcp.dir = path;\n-\t\tcp.git_cmd = 1;\n-\t\tcp.no_stdin = 1;\n-\t\targv_array_pushl(&cp.args, \"--super-prefix\", sb.buf,\n-\t\t\t\t\t    \"submodule--helper\",\n-\t\t\t\t\t   \"embed-git-dirs\", NULL);\n-\t\tprepare_submodule_repo_env(&cp.env_array);\n-\t\tif (run_command(&cp))\n-\t\t\tdie(_(\"Could not migrate git directory in submodule '%s'\"),\n-\t\t\t    path);\n-\n-\t\tstrbuf_release(&sb);\n-\t}\n-\n-\tfree(old_git_dir);\n-}\ndiff --git a/submodule.h b/submodule.h\nindex e5975d1f3d..1e42222cff 100644\n--- a/submodule.h\n+++ b/submodule.h\n@@ -74,7 +74,4 @@ int parallel_submodules(void);\n  * retaining any config in the environment.\n  */\n void prepare_submodule_repo_env(struct argv_array *out);\n-\n-extern void migrate_submodule_gitdir(const char *prefix,\n-\t\t\t\t     const char *path, int recursive);\n #endif\ndiff --git a/t/t7412-submodule-embedgitdirs.sh b/t/t7412-submodule-embedgitdirs.sh\nindex 1cf5d4b4af..e3443b88cd 100755\n--- a/t/t7412-submodule-embedgitdirs.sh\n+++ b/t/t7412-submodule-embedgitdirs.sh\n@@ -74,4 +74,19 @@ test_expect_success 'embedding the git dir fails for incomplete submodules' '\n \ttest_cmp expect.2 actual.2\n '\n \n+test_expect_success 'setup a submodule with multiple worktrees' '\n+\t# first create another unembedded git dir in a new submodule\n+\tgit init sub3 &&\n+\ttest_commit -C sub3 first &&\n+\tgit submodule add ./sub3 &&\n+\ttest_tick &&\n+\tgit commit -m \"add another submodule\" &&\n+\tgit -C sub3 worktree add ../sub3_second_work_tree\n+'\n+\n+test_expect_success 'embed a submodule with multiple worktrees' '\n+\ttest_must_fail git submodule embedgitdirs sub3 2>error &&\n+\ttest_i18ngrep \"not supported\" error\n+'\n+\n test_done\ndiff --git a/worktree.c b/worktree.c\nindex f7869f8d60..fb1f72bbf3 100644\n--- a/worktree.c\n+++ b/worktree.c\n@@ -72,7 +72,7 @@ static void add_head_info(struct strbuf *head_ref, struct worktree *worktree)\n /**\n  * get the main worktree\n  */\n-static struct worktree *get_main_worktree(void)\n+static struct worktree *get_main_worktree(const char *git_common_dir)\n {\n \tstruct worktree *worktree = NULL;\n \tstruct strbuf path = STRBUF_INIT;\n@@ -81,12 +81,12 @@ static struct worktree *get_main_worktree(void)\n \tint is_bare = 0;\n \tint is_detached = 0;\n \n-\tstrbuf_add_absolute_path(&worktree_path, get_git_common_dir());\n+\tstrbuf_add_absolute_path(&worktree_path, git_common_dir);\n \tis_bare = !strbuf_strip_suffix(&worktree_path, \"/.git\");\n \tif (is_bare)\n \t\tstrbuf_strip_suffix(&worktree_path, \"/.\");\n \n-\tstrbuf_addf(&path, \"%s/HEAD\", get_git_common_dir());\n+\tstrbuf_addf(&path, \"%s/HEAD\", git_common_dir);\n \n \tif (parse_ref(path.buf, &head_ref, &is_detached) < 0)\n \t\tgoto done;\n@@ -109,7 +109,8 @@ static struct worktree *get_main_worktree(void)\n \treturn worktree;\n }\n \n-static struct worktree *get_linked_worktree(const char *id)\n+static struct worktree *get_linked_worktree(const char *git_common_dir,\n+\t\t\t\t\t    const char *id)\n {\n \tstruct worktree *worktree = NULL;\n \tstruct strbuf path = STRBUF_INIT;\n@@ -120,7 +121,7 @@ static struct worktree *get_linked_worktree(const char *id)\n \tif (!id)\n \t\tdie(\"Missing linked worktree name\");\n \n-\tstrbuf_git_common_path(&path, \"worktrees/%s/gitdir\", id);\n+\tstrbuf_addf(&path, \"%s/worktrees/%s/gitdir\", git_common_dir, id);\n \tif (strbuf_read_file(&worktree_path, path.buf, 0) <= 0)\n \t\t/* invalid gitdir file */\n \t\tgoto done;\n@@ -133,7 +134,7 @@ static struct worktree *get_linked_worktree(const char *id)\n \t}\n \n \tstrbuf_reset(&path);\n-\tstrbuf_addf(&path, \"%s/worktrees/%s/HEAD\", get_git_common_dir(), id);\n+\tstrbuf_addf(&path, \"%s/worktrees/%s/HEAD\", git_common_dir, id);\n \n \tif (parse_ref(path.buf, &head_ref, &is_detached) < 0)\n \t\tgoto done;\n@@ -173,7 +174,7 @@ static void mark_current_worktree(struct worktree **worktrees)\n \tfree(git_dir);\n }\n \n-struct worktree **get_worktrees(void)\n+struct worktree **get_worktrees_internal(const char *git_common_dir)\n {\n \tstruct worktree **list = NULL;\n \tstruct strbuf path = STRBUF_INIT;\n@@ -183,10 +184,10 @@ struct worktree **get_worktrees(void)\n \n \tlist = xmalloc(alloc * sizeof(struct worktree *));\n \n-\tif ((list[counter] = get_main_worktree()))\n+\tif ((list[counter] = get_main_worktree(git_common_dir)))\n \t\tcounter++;\n \n-\tstrbuf_addf(&path, \"%s/worktrees\", get_git_common_dir());\n+\tstrbuf_addf(&path, \"%s/worktrees\", git_common_dir);\n \tdir = opendir(path.buf);\n \tstrbuf_release(&path);\n \tif (dir) {\n@@ -195,7 +196,7 @@ struct worktree **get_worktrees(void)\n \t\t\tif (is_dot_or_dotdot(d->d_name))\n \t\t\t\tcontinue;\n \n-\t\t\tif ((linked = get_linked_worktree(d->d_name))) {\n+\t\t\tif ((linked = get_linked_worktree(git_common_dir, d->d_name))) {\n \t\t\t\tALLOC_GROW(list, counter + 1, alloc);\n \t\t\t\tlist[counter++] = linked;\n \t\t\t}\n@@ -209,6 +210,25 @@ struct worktree **get_worktrees(void)\n \treturn list;\n }\n \n+struct worktree **get_worktrees(void)\n+{\n+\treturn get_worktrees_internal(get_git_common_dir());\n+}\n+\n+struct worktree **get_submodule_worktrees(const char *path)\n+{\n+\tconst char *submodule_common_dir;\n+\tstruct strbuf sb = STRBUF_INIT;\n+\tstruct worktree **ret;\n+\tstrbuf_addf(&sb, \"%s/.git\", path);\n+\tsubmodule_common_dir = resolve_gitdir(sb.buf);\n+\n+\tret = get_worktrees_internal(submodule_common_dir);\n+\n+\tstrbuf_release(&sb);\n+\treturn ret;\n+}\n+\n const char *get_worktree_git_dir(const struct worktree *wt)\n {\n \tif (!wt)\ndiff --git a/worktree.h b/worktree.h\nindex 90e1311fa7..c93845516c 100644\n--- a/worktree.h\n+++ b/worktree.h\n@@ -25,6 +25,11 @@ struct worktree {\n  */\n extern struct worktree **get_worktrees(void);\n \n+/*\n+ * Get the worktrees of a submodule named by `path`.\n+ */\n+extern struct worktree **get_submodule_worktrees(const char *path);\n+\n /*\n  * Return git dir of the worktree. Note that the path may be relative.\n  * If wt is NULL, git dir of current worktree is returned.\n\n\n-- \n2.10.2.613.g22f2156\n\n"},{"id":"306741","messageId":"20161201202554.19944-5-sbeller@google.com","threadId":"44586","inReplyTo":"20161201202554.19944-1-sbeller@google.com","subject":"[PATCHv3 4/5] worktree: get worktrees from submodules","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2016-12-01T20:25:53Z","receivedAt":"2016-12-01T20:26:32Z","isPatch":false,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"In a later patch we want to move around the the git directory of\na submodule. Both submodules as well as worktrees are involved in\nplacing git directories at unusual places, so their functionality\nmay collide. To react appropriately to situations where worktrees\nin submodules are in use, offer a new function to query the\nworktrees for submodules.\n\nSigned-off-by: Stefan Beller <sbeller@google.com>\n---\n worktree.c | 40 ++++++++++++++++++++++++++++++----------\n worktree.h |  5 +++++\n 2 files changed, 35 insertions(+), 10 deletions(-)\n\ndiff --git a/worktree.c b/worktree.c\nindex f7869f8d60..fb1f72bbf3 100644\n--- a/worktree.c\n+++ b/worktree.c\n@@ -72,7 +72,7 @@ static void add_head_info(struct strbuf *head_ref, struct worktree *worktree)\n /**\n  * get the main worktree\n  */\n-static struct worktree *get_main_worktree(void)\n+static struct worktree *get_main_worktree(const char *git_common_dir)\n {\n \tstruct worktree *worktree = NULL;\n \tstruct strbuf path = STRBUF_INIT;\n@@ -81,12 +81,12 @@ static struct worktree *get_main_worktree(void)\n \tint is_bare = 0;\n \tint is_detached = 0;\n \n-\tstrbuf_add_absolute_path(&worktree_path, get_git_common_dir());\n+\tstrbuf_add_absolute_path(&worktree_path, git_common_dir);\n \tis_bare = !strbuf_strip_suffix(&worktree_path, \"/.git\");\n \tif (is_bare)\n \t\tstrbuf_strip_suffix(&worktree_path, \"/.\");\n \n-\tstrbuf_addf(&path, \"%s/HEAD\", get_git_common_dir());\n+\tstrbuf_addf(&path, \"%s/HEAD\", git_common_dir);\n \n \tif (parse_ref(path.buf, &head_ref, &is_detached) < 0)\n \t\tgoto done;\n@@ -109,7 +109,8 @@ static struct worktree *get_main_worktree(void)\n \treturn worktree;\n }\n \n-static struct worktree *get_linked_worktree(const char *id)\n+static struct worktree *get_linked_worktree(const char *git_common_dir,\n+\t\t\t\t\t    const char *id)\n {\n \tstruct worktree *worktree = NULL;\n \tstruct strbuf path = STRBUF_INIT;\n@@ -120,7 +121,7 @@ static struct worktree *get_linked_worktree(const char *id)\n \tif (!id)\n \t\tdie(\"Missing linked worktree name\");\n \n-\tstrbuf_git_common_path(&path, \"worktrees/%s/gitdir\", id);\n+\tstrbuf_addf(&path, \"%s/worktrees/%s/gitdir\", git_common_dir, id);\n \tif (strbuf_read_file(&worktree_path, path.buf, 0) <= 0)\n \t\t/* invalid gitdir file */\n \t\tgoto done;\n@@ -133,7 +134,7 @@ static struct worktree *get_linked_worktree(const char *id)\n \t}\n \n \tstrbuf_reset(&path);\n-\tstrbuf_addf(&path, \"%s/worktrees/%s/HEAD\", get_git_common_dir(), id);\n+\tstrbuf_addf(&path, \"%s/worktrees/%s/HEAD\", git_common_dir, id);\n \n \tif (parse_ref(path.buf, &head_ref, &is_detached) < 0)\n \t\tgoto done;\n@@ -173,7 +174,7 @@ static void mark_current_worktree(struct worktree **worktrees)\n \tfree(git_dir);\n }\n \n-struct worktree **get_worktrees(void)\n+struct worktree **get_worktrees_internal(const char *git_common_dir)\n {\n \tstruct worktree **list = NULL;\n \tstruct strbuf path = STRBUF_INIT;\n@@ -183,10 +184,10 @@ struct worktree **get_worktrees(void)\n \n \tlist = xmalloc(alloc * sizeof(struct worktree *));\n \n-\tif ((list[counter] = get_main_worktree()))\n+\tif ((list[counter] = get_main_worktree(git_common_dir)))\n \t\tcounter++;\n \n-\tstrbuf_addf(&path, \"%s/worktrees\", get_git_common_dir());\n+\tstrbuf_addf(&path, \"%s/worktrees\", git_common_dir);\n \tdir = opendir(path.buf);\n \tstrbuf_release(&path);\n \tif (dir) {\n@@ -195,7 +196,7 @@ struct worktree **get_worktrees(void)\n \t\t\tif (is_dot_or_dotdot(d->d_name))\n \t\t\t\tcontinue;\n \n-\t\t\tif ((linked = get_linked_worktree(d->d_name))) {\n+\t\t\tif ((linked = get_linked_worktree(git_common_dir, d->d_name))) {\n \t\t\t\tALLOC_GROW(list, counter + 1, alloc);\n \t\t\t\tlist[counter++] = linked;\n \t\t\t}\n@@ -209,6 +210,25 @@ struct worktree **get_worktrees(void)\n \treturn list;\n }\n \n+struct worktree **get_worktrees(void)\n+{\n+\treturn get_worktrees_internal(get_git_common_dir());\n+}\n+\n+struct worktree **get_submodule_worktrees(const char *path)\n+{\n+\tconst char *submodule_common_dir;\n+\tstruct strbuf sb = STRBUF_INIT;\n+\tstruct worktree **ret;\n+\tstrbuf_addf(&sb, \"%s/.git\", path);\n+\tsubmodule_common_dir = resolve_gitdir(sb.buf);\n+\n+\tret = get_worktrees_internal(submodule_common_dir);\n+\n+\tstrbuf_release(&sb);\n+\treturn ret;\n+}\n+\n const char *get_worktree_git_dir(const struct worktree *wt)\n {\n \tif (!wt)\ndiff --git a/worktree.h b/worktree.h\nindex 90e1311fa7..c93845516c 100644\n--- a/worktree.h\n+++ b/worktree.h\n@@ -25,6 +25,11 @@ struct worktree {\n  */\n extern struct worktree **get_worktrees(void);\n \n+/*\n+ * Get the worktrees of a submodule named by `path`.\n+ */\n+extern struct worktree **get_submodule_worktrees(const char *path);\n+\n /*\n  * Return git dir of the worktree. Note that the path may be relative.\n  * If wt is NULL, git dir of current worktree is returned.\n-- \n2.10.2.613.g22f2156\n\n"},{"id":"306742","messageId":"20161201202554.19944-6-sbeller@google.com","threadId":"44586","inReplyTo":"20161201202554.19944-1-sbeller@google.com","subject":"[PATCHv3 5/5] submodule: add embed-git-dir function","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2016-12-01T20:25:54Z","receivedAt":"2016-12-01T20:26:33Z","isPatch":false,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"When a submodule has its git dir inside the working dir, the submodule\nsupport for checkout that we plan to add in a later patch will fail.\n\nAdd functionality to migrate the git directory to be embedded\ninto the superprojects git directory.\n\nSigned-off-by: Stefan Beller <sbeller@google.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n Documentation/git-submodule.txt   | 14 ++++++\n builtin/submodule--helper.c       | 39 ++++++++++++++++-\n dir.c                             | 78 +++++++++++++++++++++++++++++++++\n dir.h                             |  4 ++\n git-submodule.sh                  |  7 ++-\n submodule.h                       |  1 -\n t/t7412-submodule-embedgitdirs.sh | 92 +++++++++++++++++++++++++++++++++++++++\n 7 files changed, 232 insertions(+), 3 deletions(-)\n create mode 100755 t/t7412-submodule-embedgitdirs.sh\n\ndiff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt\nindex d841573475..34791cfc65 100644\n--- a/Documentation/git-submodule.txt\n+++ b/Documentation/git-submodule.txt\n@@ -22,6 +22,7 @@ SYNOPSIS\n \t      [commit] [--] [<path>...]\n 'git submodule' [--quiet] foreach [--recursive] <command>\n 'git submodule' [--quiet] sync [--recursive] [--] [<path>...]\n+'git submodule' [--quiet] embedgitdirs [--] [<path>...]\n \n \n DESCRIPTION\n@@ -245,6 +246,19 @@ sync::\n If `--recursive` is specified, this command will recurse into the\n registered submodules, and sync any nested submodules within.\n \n+embedgitdirs::\n+\tMove the git directory of submodules into its superprojects\n+\t`$GIT_DIR/modules` path and then connect the git directory and\n+\tits working directory by setting the `core.worktree` and adding\n+\ta .git file pointing to the git directory interned into the\n+\tsuperproject.\n++\n+A repository that was cloned independently and later added as a submodule or\n+old setups have the submodules git directory inside the submodule instead of\n+embedded into the superprojects git directory.\n++\n+This command is recursive by default.\n+\n OPTIONS\n -------\n -q::\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 806e29ce4e..f2df166d15 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -1076,6 +1076,42 @@ static int resolve_remote_submodule_branch(int argc, const char **argv,\n \treturn 0;\n }\n \n+static int embed_git_dir(int argc, const char **argv, const char *prefix)\n+{\n+\tint i;\n+\tstruct pathspec pathspec;\n+\tstruct module_list list = MODULE_LIST_INIT;\n+\tunsigned flags = RELOCATE_GITDIR_RECURSE_SUBMODULES;\n+\n+\tstruct option embed_gitdir_options[] = {\n+\t\tOPT_STRING(0, \"prefix\", &prefix,\n+\t\t\t   N_(\"path\"),\n+\t\t\t   N_(\"path into the working tree\")),\n+\t\tOPT_BIT(0, \"--recursive\", &flags, N_(\"recurse into submodules\"),\n+\t\t\tRELOCATE_GITDIR_RECURSE_SUBMODULES),\n+\t\tOPT_END()\n+\t};\n+\n+\tconst char *const git_submodule_helper_usage[] = {\n+\t\tN_(\"git submodule--helper embed-git-dir [<path>...]\"),\n+\t\tNULL\n+\t};\n+\n+\targc = parse_options(argc, argv, prefix, embed_gitdir_options,\n+\t\t\t     git_submodule_helper_usage, 0);\n+\n+\tgitmodules_config();\n+\tgit_config(submodule_config, NULL);\n+\n+\tif (module_list_compute(argc, argv, prefix, &pathspec, &list) < 0)\n+\t\treturn 1;\n+\n+\tfor (i = 0; i < list.nr; i++)\n+\t\trelocate_gitdir(prefix, list.entries[i]->name, flags);\n+\n+\treturn 0;\n+}\n+\n #define SUPPORT_SUPER_PREFIX (1<<0)\n \n struct cmd_struct {\n@@ -1093,7 +1129,8 @@ static struct cmd_struct commands[] = {\n \t{\"resolve-relative-url\", resolve_relative_url, 0},\n \t{\"resolve-relative-url-test\", resolve_relative_url_test, 0},\n \t{\"init\", module_init, 0},\n-\t{\"remote-branch\", resolve_remote_submodule_branch, 0}\n+\t{\"remote-branch\", resolve_remote_submodule_branch, 0},\n+\t{\"embed-git-dirs\", embed_git_dir, SUPPORT_SUPER_PREFIX}\n };\n \n int cmd_submodule__helper(int argc, const char **argv, const char *prefix)\ndiff --git a/dir.c b/dir.c\nindex bfa8c8a9a5..7b3abc1340 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -15,6 +15,9 @@\n #include \"utf8.h\"\n #include \"varint.h\"\n #include \"ewah/ewok.h\"\n+#include \"submodule-config.h\"\n+#include \"run-command.h\"\n+#include \"worktree.h\"\n \n struct path_simplify {\n \tint len;\n@@ -2748,3 +2751,78 @@ void untracked_cache_add_to_index(struct index_state *istate,\n {\n \tuntracked_cache_invalidate_path(istate, path);\n }\n+\n+/*\n+ * Migrate the given submodule (and all its submodules recursively) from\n+ * having its git directory within the working tree to the git dir nested\n+ * in its superprojects git dir under modules/.\n+ */\n+void relocate_gitdir(const char *prefix, const char *path, unsigned flags)\n+{\n+\tchar *old_git_dir;\n+\tconst char *new_git_dir;\n+\tconst struct submodule *sub;\n+\tstruct worktree **worktrees;\n+\tint i;\n+\n+\tworktrees = get_submodule_worktrees(path);\n+\tfor (i = 0; worktrees[i]; i++)\n+\t\t;\n+\tif (i > 1)\n+\t\tdie(_(\"relocate_gitdir for submodule with more than one worktree not supported\"));\n+\n+\told_git_dir = xstrfmt(\"%s/.git\", path);\n+\tif (read_gitfile(old_git_dir))\n+\t\t/* If it is an actual gitfile, it doesn't need migration. */\n+\t\tgoto out;\n+\n+\tsub = submodule_from_path(null_sha1, path);\n+\tif (!sub)\n+\t\tdie(_(\"Could not lookup name for submodule '%s'\"),\n+\t\t      path);\n+\n+\tnew_git_dir = git_path(\"modules/%s\", sub->name);\n+\tif (safe_create_leading_directories_const(new_git_dir) < 0)\n+\t\tdie(_(\"could not create directory '%s'\"), new_git_dir);\n+\n+\tif (!prefix)\n+\t\tprefix = get_super_prefix();\n+\tprintf(\"Migrating git directory of %s%s from\\n'%s' to\\n'%s'\\n\",\n+\t\tprefix ? prefix : \"\", path,\n+\t\treal_path(old_git_dir), new_git_dir);\n+\n+\tif (rename(old_git_dir, new_git_dir) < 0)\n+\t\tdie_errno(_(\"Could not migrate git directory from '%s' to '%s'\"),\n+\t\t\told_git_dir, new_git_dir);\n+\n+\tconnect_work_tree_and_git_dir(path, new_git_dir);\n+\n+out:\n+\tif (flags & RELOCATE_GITDIR_RECURSE_SUBMODULES) {\n+\t\tstruct child_process cp = CHILD_PROCESS_INIT;\n+\t\tstruct strbuf sb = STRBUF_INIT;\n+\n+\t\tif (flags & ~RELOCATE_GITDIR_RECURSE_SUBMODULES)\n+\t\t\tdie(\"BUG: we don't know how to pass the flags down?\");\n+\n+\t\tif (get_super_prefix())\n+\t\t\tstrbuf_addstr(&sb, get_super_prefix());\n+\t\tstrbuf_addstr(&sb, path);\n+\t\tstrbuf_addch(&sb, '/');\n+\n+\t\tcp.dir = path;\n+\t\tcp.git_cmd = 1;\n+\t\tcp.no_stdin = 1;\n+\t\targv_array_pushl(&cp.args, \"--super-prefix\", sb.buf,\n+\t\t\t\t\t    \"submodule--helper\",\n+\t\t\t\t\t   \"embed-git-dirs\", NULL);\n+\t\tprepare_submodule_repo_env(&cp.env_array);\n+\t\tif (run_command(&cp))\n+\t\t\tdie(_(\"Could not migrate git directory in submodule '%s'\"),\n+\t\t\t    path);\n+\n+\t\tstrbuf_release(&sb);\n+\t}\n+\n+\tfree(old_git_dir);\n+}\ndiff --git a/dir.h b/dir.h\nindex 97c83bb383..0b5e99b21d 100644\n--- a/dir.h\n+++ b/dir.h\n@@ -335,4 +335,8 @@ struct untracked_cache *read_untracked_extension(const void *data, unsigned long\n void write_untracked_extension(struct strbuf *out, struct untracked_cache *untracked);\n void add_untracked_cache(struct index_state *istate);\n void remove_untracked_cache(struct index_state *istate);\n+\n+#define RELOCATE_GITDIR_RECURSE_SUBMODULES (1<<0)\n+extern void relocate_gitdir(const char *prefix, const char *path, unsigned flags);\n+\n #endif\ndiff --git a/git-submodule.sh b/git-submodule.sh\nindex a024a135d6..b7e124f340 100755\n--- a/git-submodule.sh\n+++ b/git-submodule.sh\n@@ -1131,6 +1131,11 @@ cmd_sync()\n \tdone\n }\n \n+cmd_embedgitdirs()\n+{\n+\tgit submodule--helper embed-git-dirs --prefix \"$wt_prefix\" \"$@\"\n+}\n+\n # This loop parses the command line arguments to find the\n # subcommand name to dispatch.  Parsing of the subcommand specific\n # options are primarily done by the subcommand implementations.\n@@ -1140,7 +1145,7 @@ cmd_sync()\n while test $# != 0 && test -z \"$command\"\n do\n \tcase \"$1\" in\n-\tadd | foreach | init | deinit | update | status | summary | sync)\n+\tadd | foreach | init | deinit | update | status | summary | sync | embedgitdirs)\n \t\tcommand=$1\n \t\t;;\n \t-q|--quiet)\ndiff --git a/submodule.h b/submodule.h\nindex d9e197a948..1e42222cff 100644\n--- a/submodule.h\n+++ b/submodule.h\n@@ -74,5 +74,4 @@ int parallel_submodules(void);\n  * retaining any config in the environment.\n  */\n void prepare_submodule_repo_env(struct argv_array *out);\n-\n #endif\ndiff --git a/t/t7412-submodule-embedgitdirs.sh b/t/t7412-submodule-embedgitdirs.sh\nnew file mode 100755\nindex 0000000000..e3443b88cd\n--- /dev/null\n+++ b/t/t7412-submodule-embedgitdirs.sh\n@@ -0,0 +1,92 @@\n+#!/bin/sh\n+\n+test_description='Test submodule embedgitdirs\n+\n+This test verifies that `git submodue embedgitdirs` moves a submodules git\n+directory into the superproject.\n+'\n+\n+. ./test-lib.sh\n+\n+test_expect_success 'setup a real submodule' '\n+\tgit init sub1 &&\n+\ttest_commit -C sub1 first &&\n+\tgit submodule add ./sub1 &&\n+\ttest_tick &&\n+\tgit commit -m superproject\n+'\n+\n+test_expect_success 'embed the git dir' '\n+\t>expect.1 &&\n+\t>expect.2 &&\n+\t>actual.1 &&\n+\t>actual.2 &&\n+\tgit status >expect.1 &&\n+\tgit -C sub1 rev-parse HEAD >expect.2 &&\n+\tgit submodule embedgitdirs &&\n+\tgit fsck &&\n+\ttest -f sub1/.git &&\n+\ttest -d .git/modules/sub1 &&\n+\tgit status >actual.1 &&\n+\tgit -C sub1 rev-parse HEAD >actual.2 &&\n+\ttest_cmp expect.1 actual.1 &&\n+\ttest_cmp expect.2 actual.2\n+'\n+\n+test_expect_success 'setup nested submodule' '\n+\tgit init sub1/nested &&\n+\ttest_commit -C sub1/nested first_nested &&\n+\tgit -C sub1 submodule add ./nested &&\n+\ttest_tick &&\n+\tgit -C sub1 commit -m \"add nested\" &&\n+\tgit add sub1 &&\n+\tgit commit -m \"sub1 to include nested submodule\"\n+'\n+\n+test_expect_success 'embed the git dir in a nested submodule' '\n+\tgit status >expect.1 &&\n+\tgit -C sub1/nested rev-parse HEAD >expect.2 &&\n+\tgit submodule embedgitdirs &&\n+\ttest -f sub1/nested/.git &&\n+\ttest -d .git/modules/sub1/modules/nested &&\n+\tgit status >actual.1 &&\n+\tgit -C sub1/nested rev-parse HEAD >actual.2 &&\n+\ttest_cmp expect.1 actual.1 &&\n+\ttest_cmp expect.2 actual.2\n+'\n+\n+test_expect_success 'setup a gitlink with missing .gitmodules entry' '\n+\tgit init sub2 &&\n+\ttest_commit -C sub2 first &&\n+\tgit add sub2 &&\n+\tgit commit -m superproject\n+'\n+\n+test_expect_success 'embedding the git dir fails for incomplete submodules' '\n+\tgit status >expect.1 &&\n+\tgit -C sub2 rev-parse HEAD >expect.2 &&\n+\ttest_must_fail git submodule embedgitdirs &&\n+\tgit -C sub2 fsck &&\n+\ttest -d sub2/.git &&\n+\tgit status >actual &&\n+\tgit -C sub2 rev-parse HEAD >actual.2 &&\n+\ttest_cmp expect.1 actual.1 &&\n+\ttest_cmp expect.2 actual.2\n+'\n+\n+test_expect_success 'setup a submodule with multiple worktrees' '\n+\t# first create another unembedded git dir in a new submodule\n+\tgit init sub3 &&\n+\ttest_commit -C sub3 first &&\n+\tgit submodule add ./sub3 &&\n+\ttest_tick &&\n+\tgit commit -m \"add another submodule\" &&\n+\tgit -C sub3 worktree add ../sub3_second_work_tree\n+'\n+\n+test_expect_success 'embed a submodule with multiple worktrees' '\n+\ttest_must_fail git submodule embedgitdirs sub3 2>error &&\n+\ttest_i18ngrep \"not supported\" error\n+'\n+\n+test_done\n-- \n2.10.2.613.g22f2156\n\n"}]}