{"thread":{"id":"38079","subject":"[PATCH/RFC v2] Squashed changes for multiple worktrees vs. submodules","startedAt":"2014-11-30T23:27:56Z","lastAt":"2014-12-08T21:49:56Z","messageCount":14,"participants":["Max Kirillov","Duy Nguyen","Jens Lehmann"],"isPatch":true,"patchVersion":2,"patchTotal":null},"messages":[{"id":"252752","messageId":"1417390076-2953-1-git-send-email-max@max630.net","threadId":"38079","inReplyTo":null,"subject":"[PATCH/RFC v2] Squashed changes for multiple worktrees vs. submodules","fromName":"Max Kirillov","fromEmail":"max@max630.net","sentAt":"2014-11-30T23:27:56Z","receivedAt":"2014-11-30T23:27:56Z","isPatch":true,"sender":{"key":"max@max630.net","avatar":"https://avatars.githubusercontent.com/u/381560?v=4"},"body":"builtin/checkout.c: use absolute path instead of given argument for\n picking worktree name, it happens to be needed because for submodule\n checkout the new worktree is always \".\"\nenvironment.c: add GIT_COMMON_DIR to local_repo_env\ngit-submodule.sh: implement automatic cloning of main repository\n and checkout to new worktree at \"submodule update --init\"\npath.c, setup.c, submodule.c: fix \"diff --submodule\" when\n submodule is a linked worktree\nt/t7410-submodule-checkout-to.sh: tests for all the above\n\nSigned-off-by: Max Kirillov <max@max630.net>\n---\nHi.\n\nThanks for including my 2 patches.\n\nBut, while hacking the submodule init I became more convinced that the\nmodules directory should be common and submodules in checkout should be\na checkouts of the submodule. Because this is looks like concept of\nsubmodules, that they are unique for the lifetime of repository, even if\nthey do not exist in all revisions. And if anybody want to use fully\nindependent checkout they can be always checked out manually. Actually,\nafter a submodule is initialized and have a proper gitlink, it can be\nupdated and inquired regardless of where it points to.\n\nSo that one I think is not needed. I have instead some changes to\ngit-submodule, but have not prepared them yet as an exportable history.\n\nI am submitting here squashed changes which I have so far, to give an\nidea where it goes. I'll try to prepare a proper patch series as soon as\nI can.\n\nThey contain change $gmane/258173, which I think is important,\nespecially because it is required not only for initialization but for\nregular work also, and changes for initialization of submodules.\n\nThey are rebased on top of you patches excluding the 34/34 patch.\n\n builtin/checkout.c               |  25 ++---\n cache.h                          |   1 +\n environment.c                    |   1 +\n git-submodule.sh                 |  94 ++++++++++++++----\n path.c                           |  24 ++++-\n setup.c                          |  17 +++-\n submodule.c                      |  28 ++----\n t/t7410-submodule-checkout-to.sh | 201 +++++++++++++++++++++++++++++++++++++++\n 8 files changed, 332 insertions(+), 59 deletions(-)\n create mode 100755 t/t7410-submodule-checkout-to.sh\n\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex 953b763..78154ae 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -858,27 +858,29 @@ static int prepare_linked_checkout(const struct checkout_opts *opts,\n {\n \tstruct strbuf sb_git = STRBUF_INIT, sb_repo = STRBUF_INIT;\n \tstruct strbuf sb = STRBUF_INIT;\n-\tconst char *path = opts->new_worktree, *name;\n+\tstruct strbuf sb_path = STRBUF_INIT;\n+\tconst char *name;\n \tstruct stat st;\n \tstruct child_process cp;\n \tint counter = 0, len, ret;\n \n \tif (!new->commit)\n \t\tdie(_(\"no branch specified\"));\n-\tif (file_exists(path) && !is_empty_dir(path))\n-\t\tdie(_(\"'%s' already exists\"), path);\n+\tstrbuf_add_absolute_path(&sb_path, opts->new_worktree);\n+\tif (file_exists(sb_path.buf) && !is_empty_dir(sb_path.buf))\n+\t\tdie(_(\"'%s' already exists\"), sb_path.buf);\n \n-\tlen = strlen(path);\n-\twhile (len && is_dir_sep(path[len - 1]))\n+\tlen = sb_path.len;\n+\twhile (len && is_dir_sep(sb_path.buf[len - 1]))\n \t\tlen--;\n \n-\tfor (name = path + len - 1; name > path; name--)\n+\tfor (name = sb_path.buf + len - 1; name > sb_path.buf; name--)\n \t\tif (is_dir_sep(*name)) {\n \t\t\tname++;\n \t\t\tbreak;\n \t\t}\n \tstrbuf_addstr(&sb_repo,\n-\t\t      git_path(\"worktrees/%.*s\", (int)(path + len - name), name));\n+\t\t      git_path(\"worktrees/%.*s\", (int)(sb_path.buf + len - name), name));\n \tlen = sb_repo.len;\n \tif (safe_create_leading_directories_const(sb_repo.buf))\n \t\tdie_errno(_(\"could not create leading directories of '%s'\"),\n@@ -906,11 +908,11 @@ static int prepare_linked_checkout(const struct checkout_opts *opts,\n \tstrbuf_addf(&sb, \"%s/locked\", sb_repo.buf);\n \twrite_file(sb.buf, 1, \"initializing\\n\");\n \n-\tstrbuf_addf(&sb_git, \"%s/.git\", path);\n+\tstrbuf_addf(&sb_git, \"%s/.git\", sb_path.buf);\n \tif (safe_create_leading_directories_const(sb_git.buf))\n \t\tdie_errno(_(\"could not create leading directories of '%s'\"),\n \t\t\t  sb_git.buf);\n-\tjunk_work_tree = xstrdup(path);\n+\tjunk_work_tree = xstrdup(sb_path.buf);\n \n \tstrbuf_reset(&sb);\n \tstrbuf_addf(&sb, \"%s/gitdir\", sb_repo.buf);\n@@ -931,11 +933,11 @@ static int prepare_linked_checkout(const struct checkout_opts *opts,\n \twrite_file(sb.buf, 1, \"../..\\n\");\n \n \tif (!opts->quiet)\n-\t\tfprintf_ln(stderr, _(\"Enter %s (identifier %s)\"), path, name);\n+\t\tfprintf_ln(stderr, _(\"Enter %s (identifier %s)\"), sb_path.buf, name);\n \n \tsetenv(\"GIT_CHECKOUT_NEW_WORKTREE\", \"1\", 1);\n \tsetenv(GIT_DIR_ENVIRONMENT, sb_git.buf, 1);\n-\tsetenv(GIT_WORK_TREE_ENVIRONMENT, path, 1);\n+\tsetenv(GIT_WORK_TREE_ENVIRONMENT, sb_path.buf, 1);\n \tmemset(&cp, 0, sizeof(cp));\n \tcp.git_cmd = 1;\n \tcp.argv = opts->saved_argv;\n@@ -950,6 +952,7 @@ static int prepare_linked_checkout(const struct checkout_opts *opts,\n \tstrbuf_reset(&sb);\n \tstrbuf_addf(&sb, \"%s/locked\", sb_repo.buf);\n \tunlink_or_warn(sb.buf);\n+\tstrbuf_release(&sb_path);\n \tstrbuf_release(&sb);\n \tstrbuf_release(&sb_repo);\n \tstrbuf_release(&sb_git);\ndiff --git a/cache.h b/cache.h\nindex 3f60a11..e8f465a 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -437,6 +437,7 @@ extern char *get_object_directory(void);\n extern char *get_index_file(void);\n extern char *get_graft_file(void);\n extern int set_git_dir(const char *path);\n+extern int get_common_dir_noenv(struct strbuf *sb, const char *gitdir);\n extern int get_common_dir(struct strbuf *sb, const char *gitdir);\n extern const char *get_git_namespace(void);\n extern const char *strip_namespace(const char *namespaced_ref);\ndiff --git a/environment.c b/environment.c\nindex 8351007..85ce3c4 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -94,6 +94,7 @@ const char * const local_repo_env[] = {\n \tCONFIG_DATA_ENVIRONMENT,\n \tDB_ENVIRONMENT,\n \tGIT_DIR_ENVIRONMENT,\n+\tGIT_COMMON_DIR_ENVIRONMENT,\n \tGIT_WORK_TREE_ENVIRONMENT,\n \tGIT_IMPLICIT_WORK_TREE_ENVIRONMENT,\n \tGRAFT_ENVIRONMENT,\ndiff --git a/git-submodule.sh b/git-submodule.sh\nindex 9245abf..1b1dbf9 100755\n--- a/git-submodule.sh\n+++ b/git-submodule.sh\n@@ -254,6 +254,7 @@ module_name()\n #\n module_clone()\n {\n+\tlocal sm_path\n \tsm_path=$1\n \tname=$2\n \turl=$3\n@@ -269,9 +270,8 @@ module_clone()\n \tgitdir_base=\n \tbase_name=$(dirname \"$name\")\n \n-\tgitdir=$(git rev-parse --git-dir)\n-\tgitdir_base=\"$gitdir/modules/$base_name\"\n-\tgitdir=\"$gitdir/modules/$name\"\n+\tgitdir_base=$(git rev-parse --git-path \"modules/$base_name\")\n+\tgitdir=$(git rev-parse --git-path \"modules/$name\")\n \n \tif test -d \"$gitdir\"\n \tthen\n@@ -458,12 +458,13 @@ Use -f if you really want to add it.\" >&2\n \t\tfi\n \n \telse\n-\t\tif test -d \".git/modules/$sm_name\"\n+\t\tmodule_gitdir=$(git rev-parse --git-path \"modules/$sm_name\")\n+\t\tif test -d \"$module_gitdir\"\n \t\tthen\n \t\t\tif test -z \"$force\"\n \t\t\tthen\n \t\t\t\techo >&2 \"$(eval_gettext \"A git directory for '\\$sm_name' is found locally with remote(s):\")\"\n-\t\t\t\tGIT_DIR=\".git/modules/$sm_name\" GIT_WORK_TREE=. git remote -v | grep '(fetch)' | sed -e s,^,\"  \", -e s,' (fetch)',, >&2\n+\t\t\t\tGIT_DIR=\"$module_gitdir\" GIT_WORK_TREE=. git remote -v | grep '(fetch)' | sed -e s,^,\"  \", -e s,' (fetch)',, >&2\n \t\t\t\techo >&2 \"$(eval_gettext \"If you want to reuse this local git directory instead of cloning again from\")\"\n \t\t\t\techo >&2 \"  $realrepo\"\n \t\t\t\techo >&2 \"$(eval_gettext \"use the '--force' option. If the local git directory is not the correct repo\")\"\n@@ -472,16 +473,44 @@ Use -f if you really want to add it.\" >&2\n \t\t\t\techo \"$(eval_gettext \"Reactivating local git directory for submodule '\\$sm_name'.\")\"\n \t\t\tfi\n \t\tfi\n-\t\tmodule_clone \"$sm_path\" \"$sm_name\" \"$realrepo\" \"$reference\" \"$depth\" || exit\n-\t\t(\n-\t\t\tclear_local_git_env\n-\t\t\tcd \"$sm_path\" &&\n-\t\t\t# ash fails to wordsplit ${branch:+-b \"$branch\"...}\n-\t\t\tcase \"$branch\" in\n-\t\t\t'') git checkout -f -q ;;\n-\t\t\t?*) git checkout -f -q -B \"$branch\" \"origin/$branch\" ;;\n-\t\t\tesac\n-\t\t) || die \"$(eval_gettext \"Unable to checkout submodule '\\$sm_path'\")\"\n+\t\tcheckout_to_common_gitdir=\n+\t\tcommon_dir=$(git rev-parse --git-common-dir)\n+\t\tprivate_dir=$(git rev-parse --git-dir)\n+\t\tif test \"$common_dir\" != \"$private_dir\"\n+\t\tthen\n+\t\t\tcheckout_to_common_gitdir=\"$module_gitdir\"\n+\t\t\ttmp_worktree=$(mktemp -d)\n+\t\t\tls -a \"$tmp_worktree\"\n+\t\t\ttest -n \"$tmp_worktree\" || die \"mktemp failed\"\n+\t\t\tmodule_clone \"$tmp_worktree\" \"$sm_name\" \"$realrepo\" \"$reference\" \"$depth\" &&\n+\t\t\t(\n+\t\t\t\tclear_local_git_env\n+\t\t\t\tcd \"$tmp_worktree\" &&\n+\t\t\t\tgit update-ref --no-deref HEAD HEAD'^0' &&\n+\t\t\t\tgit config --unset core.worktree\n+\t\t\t) || exit\n+\t\t\trm -rf \"$tmp_worktree\"\n+\t\t\trm -f \"$checkout_to_common_gitdir/index\"\n+\t\t\t(\n+\t\t\t\tclear_local_git_env\n+\t\t\t\t# ash fails to wordsplit ${branch:+-b \"$branch\"...}\n+\t\t\t\tcase \"$branch\" in\n+\t\t\t\t'') git --git-dir=\"$checkout_to_common_gitdir\" checkout -f -q --to \"$sm_path\" origin/HEAD ;;\n+\t\t\t\t?*) git --git-dir=\"$checkout_to_common_gitdir\" checkout -f -q -B \"$branch\" --to \"$sm_path\" \"origin/$branch\" ;;\n+\t\t\t\tesac\n+\t\t\t) || die \"$(eval_gettext \"Unable to checkout submodule '\\$sm_path'\")\"\n+\t\telse\n+\t\t\tmodule_clone \"$sm_path\" \"$sm_name\" \"$realrepo\" \"$reference\" \"$depth\" || exit\n+\t\t\t(\n+\t\t\t\tclear_local_git_env\n+\t\t\t\tcd \"$sm_path\" &&\n+\t\t\t\t# ash fails to wordsplit ${branch:+-b \"$branch\"...}\n+\t\t\t\tcase \"$branch\" in\n+\t\t\t\t'') git checkout -f -q ;;\n+\t\t\t\t?*) git checkout -f -q -B \"$branch\" \"origin/$branch\" ;;\n+\t\t\t\tesac\n+\t\t\t) || die \"$(eval_gettext \"Unable to checkout submodule '\\$sm_path'\")\"\n+\t\tfi\n \tfi\n \tgit config submodule.\"$sm_name\".url \"$realrepo\"\n \n@@ -832,9 +861,27 @@ Maybe you want to use 'update --init'?\")\"\n \t\t\tcontinue\n \t\tfi\n \n+\t\tcheckout_to_common_gitdir=\n \t\tif ! test -d \"$sm_path\"/.git && ! test -f \"$sm_path\"/.git\n \t\tthen\n-\t\t\tmodule_clone \"$sm_path\" \"$name\" \"$url\" \"$reference\" \"$depth\" || exit\n+\t\t\tcommon_dir=$(git rev-parse --git-common-dir)\n+\t\t\tprivate_dir=$(git rev-parse --git-dir)\n+\t\t\tif test \"$common_dir\" != \"$private_dir\"\n+\t\t\tthen\n+\t\t\t\tcheckout_to_common_gitdir=$(git rev-parse --git-path \"modules/$name\")\n+\t\t\t\tif ! test -d \"$checkout_to_common_gitdir\"\n+\t\t\t\tthen\n+\t\t\t\t\ttmp_worktree=$(mktemp -d)\n+\t\t\t\t\tls -a \"$tmp_worktree\"\n+\t\t\t\t\ttest -n \"$tmp_worktree\" || die \"mktemp failed\"\n+\t\t\t\t\tmodule_clone \"$tmp_worktree\" \"$name\" \"$url\" \"$reference\" \"$depth\" || exit\n+\t\t\t\t\tgit --git-dir=\"$checkout_to_common_gitdir\" config --unset core.worktree\n+\t\t\t\t\trm -rf \"$tmp_worktree\"\n+\t\t\t\t\trm -f \"$checkout_to_common_gitdir/index\"\n+\t\t\t\tfi\n+\t\t\telse\n+\t\t\t\tmodule_clone \"$sm_path\" \"$name\" \"$url\" \"$reference\" \"$depth\" || exit\n+\t\t\tfi\n \t\t\tcloned_modules=\"$cloned_modules;$name\"\n \t\t\tsubsha1=\n \t\telse\n@@ -886,24 +933,29 @@ Maybe you want to use 'update --init'?\")\"\n \t\t\tmust_die_on_failure=\n \t\t\tcase \"$update_module\" in\n \t\t\tcheckout)\n-\t\t\t\tcommand=\"git checkout $subforce -q\"\n+\t\t\t\tif test -n \"$checkout_to_common_gitdir\"\n+\t\t\t\tthen\n+\t\t\t\t\tsubmodule_command() { git --git-dir=\"$checkout_to_common_gitdir\" checkout --to . $subforce -q \"$@\"; }\n+\t\t\t\telse\n+\t\t\t\t\tsubmodule_command() { git checkout $subforce -q \"$@\"; }\n+\t\t\t\tfi\n \t\t\t\tdie_msg=\"$(eval_gettext \"Unable to checkout '\\$sha1' in submodule path '\\$displaypath'\")\"\n \t\t\t\tsay_msg=\"$(eval_gettext \"Submodule path '\\$displaypath': checked out '\\$sha1'\")\"\n \t\t\t\t;;\n \t\t\trebase)\n-\t\t\t\tcommand=\"git rebase\"\n+\t\t\t\tsubmodule_command() { git rebase \"$@\"; }\n \t\t\t\tdie_msg=\"$(eval_gettext \"Unable to rebase '\\$sha1' in submodule path '\\$displaypath'\")\"\n \t\t\t\tsay_msg=\"$(eval_gettext \"Submodule path '\\$displaypath': rebased into '\\$sha1'\")\"\n \t\t\t\tmust_die_on_failure=yes\n \t\t\t\t;;\n \t\t\tmerge)\n-\t\t\t\tcommand=\"git merge\"\n+\t\t\t\tsubmodule_command() { git merge \"$@\"; }\n \t\t\t\tdie_msg=\"$(eval_gettext \"Unable to merge '\\$sha1' in submodule path '\\$displaypath'\")\"\n \t\t\t\tsay_msg=\"$(eval_gettext \"Submodule path '\\$displaypath': merged in '\\$sha1'\")\"\n \t\t\t\tmust_die_on_failure=yes\n \t\t\t\t;;\n \t\t\t!*)\n-\t\t\t\tcommand=\"${update_module#!}\"\n+\t\t\t\tsubmodule_command() { ${update_module#!} \"$@\"; }\n \t\t\t\tdie_msg=\"$(eval_gettext \"Execution of '\\$command \\$sha1' failed in submodule  path '\\$prefix\\$sm_path'\")\"\n \t\t\t\tsay_msg=\"$(eval_gettext \"Submodule path '\\$prefix\\$sm_path': '\\$command \\$sha1'\")\"\n \t\t\t\tmust_die_on_failure=yes\n@@ -912,7 +964,7 @@ Maybe you want to use 'update --init'?\")\"\n \t\t\t\tdie \"$(eval_gettext \"Invalid update mode '$update_module' for submodule '$name'\")\"\n \t\t\tesac\n \n-\t\t\tif (clear_local_git_env; cd \"$sm_path\" && $command \"$sha1\")\n+\t\t\tif (clear_local_git_env; cd \"$sm_path\" && submodule_command \"$sha1\")\n \t\t\tthen\n \t\t\t\tsay \"$say_msg\"\n \t\t\telif test -n \"$must_die_on_failure\"\ndiff --git a/path.c b/path.c\nindex 35d498e..fadc1ea 100644\n--- a/path.c\n+++ b/path.c\n@@ -98,7 +98,7 @@ static const char *common_list[] = {\n \tNULL\n };\n \n-static void update_common_dir(struct strbuf *buf, int git_dir_len)\n+static void update_common_dir(struct strbuf *buf, int git_dir_len, const char* common_dir)\n {\n \tchar *base = buf->buf + git_dir_len;\n \tconst char **p;\n@@ -115,12 +115,17 @@ static void update_common_dir(struct strbuf *buf, int git_dir_len)\n \t\t\tpath++;\n \t\t\tis_dir = 1;\n \t\t}\n+\n+\t\tif (!common_dir) {\n+\t\t\tcommon_dir = get_git_common_dir();\n+\t\t}\n+\n \t\tif (is_dir && dir_prefix(base, path)) {\n-\t\t\treplace_dir(buf, git_dir_len, get_git_common_dir());\n+\t\t\treplace_dir(buf, git_dir_len, common_dir);\n \t\t\treturn;\n \t\t}\n \t\tif (!is_dir && !strcmp(base, path)) {\n-\t\t\treplace_dir(buf, git_dir_len, get_git_common_dir());\n+\t\t\treplace_dir(buf, git_dir_len, common_dir);\n \t\t\treturn;\n \t\t}\n \t}\n@@ -160,7 +165,7 @@ static void adjust_git_path(struct strbuf *buf, int git_dir_len)\n \telse if (git_db_env && dir_prefix(base, \"objects\"))\n \t\treplace_dir(buf, git_dir_len + 7, get_object_directory());\n \telse if (git_common_dir_env)\n-\t\tupdate_common_dir(buf, git_dir_len);\n+\t\tupdate_common_dir(buf, git_dir_len, NULL);\n }\n \n static void do_git_path(struct strbuf *buf, const char *fmt, va_list args)\n@@ -256,6 +261,8 @@ const char *git_path_submodule(const char *path, const char *fmt, ...)\n {\n \tstruct strbuf *buf = get_pathname();\n \tconst char *git_dir;\n+\tstruct strbuf git_submodule_common_dir = STRBUF_INIT;\n+\tstruct strbuf git_submodule_dir = STRBUF_INIT;\n \tva_list args;\n \n \tstrbuf_addstr(buf, path);\n@@ -269,11 +276,20 @@ const char *git_path_submodule(const char *path, const char *fmt, ...)\n \t\tstrbuf_addstr(buf, git_dir);\n \t}\n \tstrbuf_addch(buf, '/');\n+\tstrbuf_addstr(&git_submodule_dir, buf->buf);\n \n \tva_start(args, fmt);\n \tstrbuf_vaddf(buf, fmt, args);\n \tva_end(args);\n+\n+\tif (get_common_dir_noenv(&git_submodule_common_dir, git_submodule_dir.buf)) {\n+\t\tupdate_common_dir(buf, git_submodule_dir.len, git_submodule_common_dir.buf);\n+\t}\n+\n \tstrbuf_cleanup_path(buf);\n+\n+\tstrbuf_release(&git_submodule_dir);\n+\tstrbuf_release(&git_submodule_common_dir);\n \treturn buf->buf;\n }\n \ndiff --git a/setup.c b/setup.c\nindex fb61860..ffda622 100644\n--- a/setup.c\n+++ b/setup.c\n@@ -226,14 +226,21 @@ void verify_non_filename(const char *prefix, const char *arg)\n \n int get_common_dir(struct strbuf *sb, const char *gitdir)\n {\n+\tconst char *git_env_common_dir = getenv(GIT_COMMON_DIR_ENVIRONMENT);\n+\tif (git_env_common_dir) {\n+\t\tstrbuf_addstr(sb, git_env_common_dir);\n+\t\treturn 1;\n+\t} else {\n+\t\treturn get_common_dir_noenv(sb, gitdir);\n+\t}\n+}\n+\n+int get_common_dir_noenv(struct strbuf *sb, const char *gitdir)\n+{\n \tstruct strbuf data = STRBUF_INIT;\n \tstruct strbuf path = STRBUF_INIT;\n-\tconst char *git_common_dir = getenv(GIT_COMMON_DIR_ENVIRONMENT);\n \tint ret = 0;\n-\tif (git_common_dir) {\n-\t\tstrbuf_addstr(sb, git_common_dir);\n-\t\treturn 1;\n-\t}\n+\n \tstrbuf_addf(&path, \"%s/commondir\", gitdir);\n \tif (file_exists(path.buf)) {\n \t\tif (strbuf_read_file(&data, path.buf, 0) <= 0)\ndiff --git a/submodule.c b/submodule.c\nindex 34094f5..4aad3d4 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -122,43 +122,35 @@ void stage_updated_gitmodules(void)\n \n static int add_submodule_odb(const char *path)\n {\n-\tstruct strbuf objects_directory = STRBUF_INIT;\n \tstruct alternate_object_database *alt_odb;\n+\tconst char* objects_directory;\n \tint ret = 0;\n-\tconst char *git_dir;\n \n-\tstrbuf_addf(&objects_directory, \"%s/.git\", path);\n-\tgit_dir = read_gitfile(objects_directory.buf);\n-\tif (git_dir) {\n-\t\tstrbuf_reset(&objects_directory);\n-\t\tstrbuf_addstr(&objects_directory, git_dir);\n-\t}\n-\tstrbuf_addstr(&objects_directory, \"/objects/\");\n-\tif (!is_directory(objects_directory.buf)) {\n+\tobjects_directory = git_path_submodule(path, \"objects/\");\n+\tif (!is_directory(objects_directory)) {\n \t\tret = -1;\n \t\tgoto done;\n \t}\n+\n \t/* avoid adding it twice */\n \tfor (alt_odb = alt_odb_list; alt_odb; alt_odb = alt_odb->next)\n-\t\tif (alt_odb->name - alt_odb->base == objects_directory.len &&\n-\t\t\t\t!strncmp(alt_odb->base, objects_directory.buf,\n-\t\t\t\t\tobjects_directory.len))\n+\t\tif (alt_odb->name - alt_odb->base == strlen(objects_directory) &&\n+\t\t\t\t!strcmp(alt_odb->base, objects_directory))\n \t\t\tgoto done;\n \n-\talt_odb = xmalloc(objects_directory.len + 42 + sizeof(*alt_odb));\n+\talt_odb = xmalloc(strlen(objects_directory) + 42 + sizeof(*alt_odb));\n \talt_odb->next = alt_odb_list;\n-\tstrcpy(alt_odb->base, objects_directory.buf);\n-\talt_odb->name = alt_odb->base + objects_directory.len;\n+\tstrcpy(alt_odb->base, objects_directory);\n+\talt_odb->name = alt_odb->base + strlen(objects_directory);\n \talt_odb->name[2] = '/';\n \talt_odb->name[40] = '\\0';\n \talt_odb->name[41] = '\\0';\n \talt_odb_list = alt_odb;\n \n \t/* add possible alternates from the submodule */\n-\tread_info_alternates(objects_directory.buf, 0);\n+\tread_info_alternates(objects_directory, 0);\n \tprepare_alt_odb();\n done:\n-\tstrbuf_release(&objects_directory);\n \treturn ret;\n }\n \ndiff --git a/t/t7410-submodule-checkout-to.sh b/t/t7410-submodule-checkout-to.sh\nnew file mode 100755\nindex 0000000..cbbcecb\n--- /dev/null\n+++ b/t/t7410-submodule-checkout-to.sh\n@@ -0,0 +1,201 @@\n+#!/bin/sh\n+\n+test_description='Combination of submodules and multiple workdirs'\n+\n+. ./test-lib.sh\n+\n+base_path=$(pwd -P)\n+\n+test_expect_success 'setup: make origin' \\\n+    'mkdir -p origin/sub && ( cd origin/sub && git init &&\n+\techo file1 >file1 &&\n+\tgit add file1 &&\n+\tgit commit -m file1 ) &&\n+    mkdir -p origin/main && ( cd origin/main && git init &&\n+\tgit submodule add ../sub &&\n+\tgit commit -m \"add sub\" ) &&\n+    ( cd origin/sub &&\n+\techo file1updated >file1 &&\n+\tgit add file1 &&\n+\tgit commit -m \"file1 updated\" ) &&\n+    ( cd origin/main/sub && git pull ) &&\n+    ( cd origin/main &&\n+\tgit add sub &&\n+\tgit commit -m \"sub updated\" )'\n+\n+test_expect_success 'setup: clone' \\\n+    'mkdir clone && ( cd clone &&\n+\tgit clone --recursive \"$base_path/origin/main\")'\n+\n+rev1_hash_main=$(git --git-dir=origin/main/.git show --pretty=format:%h -q \"HEAD~1\")\n+rev1_hash_sub=$(git --git-dir=origin/sub/.git show --pretty=format:%h -q \"HEAD~1\")\n+\n+test_expect_success 'checkout main' \\\n+    'mkdir default_checkout &&\n+    (cd clone/main &&\n+\tgit checkout --to \"$base_path/default_checkout/main\" \"$rev1_hash_main\")'\n+\n+# TODO: this must never work without --recursive\n+test_expect_failure 'can see submodule diffs just after checkout' \\\n+    '(cd default_checkout/main && git diff --submodule master\"^!\" | grep \"file1 updated\")'\n+\n+test_expect_success 'checkout main and initialize independed clones' \\\n+    'mkdir fully_cloned_submodule &&\n+    (cd clone/main &&\n+\tgit checkout --to \"$base_path/fully_cloned_submodule/main\" \"$rev1_hash_main\") &&\n+    (cd fully_cloned_submodule/main && git submodule update)'\n+\n+# TODO: thus must require update --init\n+test_expect_success 'can see submodule diffs after independed cloning' \\\n+    '(cd fully_cloned_submodule/main && git diff --submodule master\"^!\" | grep \"file1 updated\")'\n+\n+# TODO: this is not needed to do now regularly, rather being a special case\n+# 1. manual checkout should point to somewhere else at all\n+# 2. no need to make that gitlink\n+test_expect_success 'checkout sub manually' \\\n+    'mkdir linked_submodule &&\n+    (cd clone/main &&\n+\tgit checkout --to \"$base_path/linked_submodule/main\" \"$rev1_hash_main\") &&\n+    (cd clone/main/sub &&\n+\tgit checkout --to \"$base_path/linked_submodule/main/sub\" \"$rev1_hash_sub\") &&\n+    mkdir clone/main/.git/worktrees/main/modules &&\n+\techo \"gitdir: ../../modules/sub/worktrees/sub\" > clone/main/.git/worktrees/main/modules/sub'\n+\n+test_expect_success 'can see submodule diffs after manual checkout of linked submodule' \\\n+    '(cd linked_submodule/main && git diff --submodule master\"^!\" | grep \"file1 updated\")'\n+\n+test_expect_success 'clone non-recursively and update to linked superpproject' \\\n+    'mkdir clone_norec && ( cd clone_norec &&\n+\tgit clone \"$base_path/origin/main\" &&\n+\tcd main &&\n+\tgit checkout --to \"$base_path/worktree_with_submodule/main\" \"$rev1_hash_main\") &&\n+    (cd worktree_with_submodule/main &&\n+\tgit submodule update --init)'\n+\n+test_expect_success 'can see submodule diffs in worktree with independently updated submodule' \\\n+    '(cd worktree_with_submodule/main && git diff --submodule master\"^!\" | grep \"file1 updated\")'\n+\n+test_expect_success 'init submodule in main repository back' \\\n+    '( cd clone_norec/main && git submodule update --init)'\n+\n+test_expect_success 'can see submodule diffs in main repository which initalized after linked' \\\n+    '(cd clone_norec/main && git diff --submodule master\"^!\" | grep \"file1 updated\")'\n+\n+test_expect_success 'linked worktree is uptodate after chanages in main' \\\n+    '(cd clone_norec/main && git checkout --detach master~1 && git submodule update) &&\n+    (cd worktree_with_submodule/main &&\n+\tgit status --porcelain >../../actual &&\n+\t: >../../expected &&\n+\ttest_cmp ../../expected ../../actual)'\n+\n+test_expect_success 'init another repository to test adding' \\\n+    'mkdir -p add_area/repo &&\n+    (cd add_area/repo &&\n+\tgit init &&\n+\tgit commit --allow-empty -m main_commit &&\n+\tgit branch b2 &&\n+\tgit checkout --to ../worktree b2)'\n+\n+test_expect_success 'add sub&history' \\\n+    '(cd add_area/worktree &&\n+\tgit submodule add ../../origin/sub sub &&\n+\t(cd sub && git checkout --detach \"$rev1_hash_sub\") &&\n+\tgit add sub &&\n+\tgit commit -m sub_added &&\n+\t(cd sub && git checkout --detach origin/master) &&\n+\tgit add sub &&\n+\tgit commit -m sub_changed)'\n+\n+test_expect_success 'inquire history after adding' \\\n+    '(cd add_area/worktree &&\n+\tgit diff --submodule b2\"^!\" | grep \"file1 updated\")'\n+\n+test_expect_success 'init submodule in main' \\\n+    '(cd add_area/repo &&\n+\tgit reset --hard b2~1 &&\n+\tgit submodule update --init)'\n+\n+test_expect_success 'linked worktree is uptodate after changes in original after adding' \\\n+    '(cd add_area/worktree &&\n+\tgit status --porcelain >../../actual &&\n+\t: >../../expected &&\n+\ttest_cmp ../../expected ../../actual)'\n+\n+deinit_start()\n+{\n+    rm -rf deinit_area && \\\n+    mkdir deinit_area && \\\n+    ( cd deinit_area && \\\n+\tgit clone \"$base_path/origin/main\" && \\\n+\tcd main && \\\n+\tgit checkout --to ../worktree --detach HEAD )\n+}\n+\n+deinit_init()\n+{\n+    (cd \"deinit_area/$1\" && git submodule update --init)\n+}\n+\n+deinit_deinit()\n+{\n+    (cd \"deinit_area/$1\" && git submodule deinit sub)\n+}\n+\n+deinit_not_checked_out()\n+{\n+    (cd \"deinit_area/$1\" && git diff --submodule master\"^!\" >actual && grep -q \"not checked out\" actual)\n+}\n+\n+deinit_checked_out()\n+{\n+    (cd \"deinit_area/$1\" && git diff --submodule master\"^!\" >actual && grep -q \"file1 updated\" actual)\n+}\n+\n+# TODO:\n+# 1. check that directories are cleaned and index is removed for main (?)\n+# 2. .git/config should be removed only after last owrktree is. Is it visible at all?\n+test_expect_success 'deinit main only - create' \\\n+    'deinit_start && deinit_init main && deinit_deinit main'\n+\n+test_expect_success 'deinit main only - not checked out' \\\n+    'deinit_not_checked_out main'\n+\n+test_expect_success 'deinit worktree only - create' \\\n+    'deinit_init && deinit_init worktree && deinit_deinit worktree'\n+\n+test_expect_success 'deinit worktree only - not checked out' \\\n+    'deinit_not_checked_out worktree'\n+\n+test_expect_success 'deinit from both, worktree then main - create' \\\n+    'deinit_init && deinit_init main && deinit_init worktree && deinit_deinit worktree'\n+\n+test_expect_success 'deinit from both, worktree then main - update' \\\n+    '(cd deinit_area/main && git submodule update) &&\n+    (cd deinit_area/worktree && git submodule update)'\n+\n+test_expect_success 'deinit from both, worktree then main - check#1' \\\n+    'deinit_not_checked_out worktree && deinit_checked_out main'\n+\n+test_expect_success 'deinit from both, worktree then main - deinit main' \\\n+    'deinit_deinit main'\n+\n+test_expect_success 'deinit from both, worktree then main - check#2' \\\n+    'deinit_not_checked_out worktree && deinit_not_checked_out main'\n+\n+test_expect_success 'deinit from both, main then worktree - create' \\\n+    'deinit_init && deinit_init main && deinit_init worktree && deinit_deinit main'\n+\n+test_expect_success 'deinit from both, worktree then main - update' \\\n+    '(cd deinit_area/main && git submodule update) &&\n+    (cd deinit_area/worktree && git submodule update)'\n+\n+test_expect_success 'deinit from both, main then worktree - check#1' \\\n+    'deinit_not_checked_out main && deinit_checked_out worktree'\n+\n+test_expect_success 'deinit from both, main then worktree - deinit worktree' \\\n+    'deinit_deinit worktree'\n+\n+test_expect_success 'deinit from both, main then worktree - check#2' \\\n+    'deinit_not_checked_out worktree && deinit_not_checked_out main'\n+\n+test_done\n-- \n2.1.1.391.g7a54a76\n"},{"id":"252775","messageId":"CACsJy8C1968-NJAxvxnwXAOZTofedpAe+Rmg4OYJA4E3t9Ao+g@mail.gmail.com","threadId":"38079","inReplyTo":"1417390076-2953-1-git-send-email-max@max630.net","subject":"Re: [PATCH/RFC v2] Squashed changes for multiple worktrees vs. submodules","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2014-12-01T10:43:16Z","receivedAt":"2014-12-01T10:43:16Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Mon, Dec 1, 2014 at 6:27 AM, Max Kirillov <max@max630.net> wrote:\n> But, while hacking the submodule init I became more convinced that the\n> modules directory should be common and submodules in checkout should be\n> a checkouts of the submodule. Because this is looks like concept of\n> submodules, that they are unique for the lifetime of repository, even if\n> they do not exist in all revisions. And if anybody want to use fully\n> independent checkout they can be always checked out manually. Actually,\n> after a submodule is initialized and have a proper gitlink, it can be\n> updated and inquired regardless of where it points to.\n\nJust throw something in for discussion. What about keeping\n$GIT_DIR/modules like it is now (i.e. not shared) and add\n$GIT_DIR/shared-modules, which is the same for all checkouts? That\nwould keep current submodule code happy (no name collision or\nanything). New submodule code can start using $GIT_DIR/shared-modules\nwhile still keeping an eye on $GIT_DIR/modules for old setups.\n-- \nDuy\n"},{"id":"252781","messageId":"20141201144731.GA9128@wheezy.local","threadId":"38079","inReplyTo":"CACsJy8C1968-NJAxvxnwXAOZTofedpAe+Rmg4OYJA4E3t9Ao+g@mail.gmail.com","subject":"Re: [PATCH/RFC v2] Squashed changes for multiple worktrees vs. submodules","fromName":"Max Kirillov","fromEmail":"max@max630.net","sentAt":"2014-12-01T14:47:31Z","receivedAt":"2014-12-01T14:47:31Z","isPatch":true,"sender":{"key":"max@max630.net","avatar":"https://avatars.githubusercontent.com/u/381560?v=4"},"body":"On Mon, Dec 01, 2014 at 05:43:16PM +0700, Duy Nguyen wrote:\n> On Mon, Dec 1, 2014 at 6:27 AM, Max Kirillov <max@max630.net> wrote:\n>> But, while hacking the submodule init I became more\n>> convinced that the modules directory should be common and\n>> submodules in checkout should be a checkouts of the\n>> submodule. Because this is looks like concept of\n>> submodules, that they are unique for the lifetime of\n>> repository, even if they do not exist in all revisions.\n>> And if anybody want to use fully independent checkout\n>> they can be always checked out manually. Actually, after\n>> a submodule is initialized and have a proper gitlink, it\n>> can be updated and inquired regardless of where it points\n>> to.\n> \n> Just throw something in for discussion. What about keeping\n> $GIT_DIR/modules like it is now (i.e. not shared) and add\n> $GIT_DIR/shared-modules, which is the same for all\n> checkouts? That would keep current submodule code happy\n> (no name collision or anything). New submodule code can\n> start using $GIT_DIR/shared-modules while still keeping an\n> eye on $GIT_DIR/modules for old setups.\n\nI think it would be too complicated. To make fancy think\nuser can always manually initialize a repository or a\ncheckout. And all sumbodule functionality except\nadding/removing/(de)initialization should work with any\nrepository or gitlink, regardless of where it points to.\n"},{"id":"252889","messageId":"547E24E4.7050100@web.de","threadId":"38079","inReplyTo":"1417390076-2953-1-git-send-email-max@max630.net","subject":"Re: [PATCH/RFC v2] Squashed changes for multiple worktrees vs. submodules","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2014-12-02T20:45:24Z","receivedAt":"2014-12-02T20:45:24Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"Am 01.12.2014 um 00:27 schrieb Max Kirillov:\n> builtin/checkout.c: use absolute path instead of given argument for\n>   picking worktree name, it happens to be needed because for submodule\n>   checkout the new worktree is always \".\"\n> environment.c: add GIT_COMMON_DIR to local_repo_env\n> git-submodule.sh: implement automatic cloning of main repository\n>   and checkout to new worktree at \"submodule update --init\"\n> path.c, setup.c, submodule.c: fix \"diff --submodule\" when\n>   submodule is a linked worktree\n> t/t7410-submodule-checkout-to.sh: tests for all the above\n>\n> Signed-off-by: Max Kirillov <max@max630.net>\n> ---\n> Hi.\n>\n> Thanks for including my 2 patches.\n>\n> But, while hacking the submodule init I became more convinced that the\n> modules directory should be common and submodules in checkout should be\n> a checkouts of the submodule. Because this is looks like concept of\n> submodules, that they are unique for the lifetime of repository, even if\n> they do not exist in all revisions. And if anybody want to use fully\n> independent checkout they can be always checked out manually. Actually,\n> after a submodule is initialized and have a proper gitlink, it can be\n> updated and inquired regardless of where it points to.\n\nIf I understand you correctly you want to put the submodule's common\ngit dir under the superproject's common git dir. I agree that that\nmakes most sense as the default, but having the possibility to use a\ncommon git dir for submodule's of different superprojects would be\nnice to have for some setups, e.g. CI-servers. But that can be added\nlater.\n\n> So that one I think is not needed. I have instead some changes to\n> git-submodule, but have not prepared them yet as an exportable history.\n>\n> I am submitting here squashed changes which I have so far, to give an\n> idea where it goes. I'll try to prepare a proper patch series as soon as\n> I can.\n\nThanks. I just didn't quite understand why you had to do so many\nchanges to git-submodule.sh. Wouldn't it be sufficient to just\nupdate module_clone()?\n\nIf the superproject uses a common git dir I'd expect module_clone()\nto set up the local superproject's worktree .git/modules/<name>\nreferencing the /modules/<name> directory of the superproject's\ncommon git dir as the submodule's common git dir. So instead of a\nclone of the submodule's upstream it would put a multiple worktree\nversion of the submodule under .git/modules/<name>. Then there\nshould be no further difference between a submodule that borrows\nfrom the common git dir an one that doesn't.\n\nAm I missing something about how the common dir thingy works? Or\nmaybe that .git/modules/<name> is bare is a problem here?\n\n> They contain change $gmane/258173, which I think is important,\n> especially because it is required not only for initialization but for\n> regular work also, and changes for initialization of submodules.\n>\n> They are rebased on top of you patches excluding the 34/34 patch.\n>\n>   builtin/checkout.c               |  25 ++---\n>   cache.h                          |   1 +\n>   environment.c                    |   1 +\n>   git-submodule.sh                 |  94 ++++++++++++++----\n>   path.c                           |  24 ++++-\n>   setup.c                          |  17 +++-\n>   submodule.c                      |  28 ++----\n>   t/t7410-submodule-checkout-to.sh | 201 +++++++++++++++++++++++++++++++++++++++\n>   8 files changed, 332 insertions(+), 59 deletions(-)\n>   create mode 100755 t/t7410-submodule-checkout-to.sh\n>\n> diff --git a/builtin/checkout.c b/builtin/checkout.c\n> index 953b763..78154ae 100644\n> --- a/builtin/checkout.c\n> +++ b/builtin/checkout.c\n> @@ -858,27 +858,29 @@ static int prepare_linked_checkout(const struct checkout_opts *opts,\n>   {\n>   \tstruct strbuf sb_git = STRBUF_INIT, sb_repo = STRBUF_INIT;\n>   \tstruct strbuf sb = STRBUF_INIT;\n> -\tconst char *path = opts->new_worktree, *name;\n> +\tstruct strbuf sb_path = STRBUF_INIT;\n> +\tconst char *name;\n>   \tstruct stat st;\n>   \tstruct child_process cp;\n>   \tint counter = 0, len, ret;\n>\n>   \tif (!new->commit)\n>   \t\tdie(_(\"no branch specified\"));\n> -\tif (file_exists(path) && !is_empty_dir(path))\n> -\t\tdie(_(\"'%s' already exists\"), path);\n> +\tstrbuf_add_absolute_path(&sb_path, opts->new_worktree);\n> +\tif (file_exists(sb_path.buf) && !is_empty_dir(sb_path.buf))\n> +\t\tdie(_(\"'%s' already exists\"), sb_path.buf);\n>\n> -\tlen = strlen(path);\n> -\twhile (len && is_dir_sep(path[len - 1]))\n> +\tlen = sb_path.len;\n> +\twhile (len && is_dir_sep(sb_path.buf[len - 1]))\n>   \t\tlen--;\n>\n> -\tfor (name = path + len - 1; name > path; name--)\n> +\tfor (name = sb_path.buf + len - 1; name > sb_path.buf; name--)\n>   \t\tif (is_dir_sep(*name)) {\n>   \t\t\tname++;\n>   \t\t\tbreak;\n>   \t\t}\n>   \tstrbuf_addstr(&sb_repo,\n> -\t\t      git_path(\"worktrees/%.*s\", (int)(path + len - name), name));\n> +\t\t      git_path(\"worktrees/%.*s\", (int)(sb_path.buf + len - name), name));\n>   \tlen = sb_repo.len;\n>   \tif (safe_create_leading_directories_const(sb_repo.buf))\n>   \t\tdie_errno(_(\"could not create leading directories of '%s'\"),\n> @@ -906,11 +908,11 @@ static int prepare_linked_checkout(const struct checkout_opts *opts,\n>   \tstrbuf_addf(&sb, \"%s/locked\", sb_repo.buf);\n>   \twrite_file(sb.buf, 1, \"initializing\\n\");\n>\n> -\tstrbuf_addf(&sb_git, \"%s/.git\", path);\n> +\tstrbuf_addf(&sb_git, \"%s/.git\", sb_path.buf);\n>   \tif (safe_create_leading_directories_const(sb_git.buf))\n>   \t\tdie_errno(_(\"could not create leading directories of '%s'\"),\n>   \t\t\t  sb_git.buf);\n> -\tjunk_work_tree = xstrdup(path);\n> +\tjunk_work_tree = xstrdup(sb_path.buf);\n>\n>   \tstrbuf_reset(&sb);\n>   \tstrbuf_addf(&sb, \"%s/gitdir\", sb_repo.buf);\n> @@ -931,11 +933,11 @@ static int prepare_linked_checkout(const struct checkout_opts *opts,\n>   \twrite_file(sb.buf, 1, \"../..\\n\");\n>\n>   \tif (!opts->quiet)\n> -\t\tfprintf_ln(stderr, _(\"Enter %s (identifier %s)\"), path, name);\n> +\t\tfprintf_ln(stderr, _(\"Enter %s (identifier %s)\"), sb_path.buf, name);\n>\n>   \tsetenv(\"GIT_CHECKOUT_NEW_WORKTREE\", \"1\", 1);\n>   \tsetenv(GIT_DIR_ENVIRONMENT, sb_git.buf, 1);\n> -\tsetenv(GIT_WORK_TREE_ENVIRONMENT, path, 1);\n> +\tsetenv(GIT_WORK_TREE_ENVIRONMENT, sb_path.buf, 1);\n>   \tmemset(&cp, 0, sizeof(cp));\n>   \tcp.git_cmd = 1;\n>   \tcp.argv = opts->saved_argv;\n> @@ -950,6 +952,7 @@ static int prepare_linked_checkout(const struct checkout_opts *opts,\n>   \tstrbuf_reset(&sb);\n>   \tstrbuf_addf(&sb, \"%s/locked\", sb_repo.buf);\n>   \tunlink_or_warn(sb.buf);\n> +\tstrbuf_release(&sb_path);\n>   \tstrbuf_release(&sb);\n>   \tstrbuf_release(&sb_repo);\n>   \tstrbuf_release(&sb_git);\n> diff --git a/cache.h b/cache.h\n> index 3f60a11..e8f465a 100644\n> --- a/cache.h\n> +++ b/cache.h\n> @@ -437,6 +437,7 @@ extern char *get_object_directory(void);\n>   extern char *get_index_file(void);\n>   extern char *get_graft_file(void);\n>   extern int set_git_dir(const char *path);\n> +extern int get_common_dir_noenv(struct strbuf *sb, const char *gitdir);\n>   extern int get_common_dir(struct strbuf *sb, const char *gitdir);\n>   extern const char *get_git_namespace(void);\n>   extern const char *strip_namespace(const char *namespaced_ref);\n> diff --git a/environment.c b/environment.c\n> index 8351007..85ce3c4 100644\n> --- a/environment.c\n> +++ b/environment.c\n> @@ -94,6 +94,7 @@ const char * const local_repo_env[] = {\n>   \tCONFIG_DATA_ENVIRONMENT,\n>   \tDB_ENVIRONMENT,\n>   \tGIT_DIR_ENVIRONMENT,\n> +\tGIT_COMMON_DIR_ENVIRONMENT,\n>   \tGIT_WORK_TREE_ENVIRONMENT,\n>   \tGIT_IMPLICIT_WORK_TREE_ENVIRONMENT,\n>   \tGRAFT_ENVIRONMENT,\n> diff --git a/git-submodule.sh b/git-submodule.sh\n> index 9245abf..1b1dbf9 100755\n> --- a/git-submodule.sh\n> +++ b/git-submodule.sh\n> @@ -254,6 +254,7 @@ module_name()\n>   #\n>   module_clone()\n>   {\n> +\tlocal sm_path\n>   \tsm_path=$1\n>   \tname=$2\n>   \turl=$3\n> @@ -269,9 +270,8 @@ module_clone()\n>   \tgitdir_base=\n>   \tbase_name=$(dirname \"$name\")\n>\n> -\tgitdir=$(git rev-parse --git-dir)\n> -\tgitdir_base=\"$gitdir/modules/$base_name\"\n> -\tgitdir=\"$gitdir/modules/$name\"\n> +\tgitdir_base=$(git rev-parse --git-path \"modules/$base_name\")\n> +\tgitdir=$(git rev-parse --git-path \"modules/$name\")\n>\n>   \tif test -d \"$gitdir\"\n>   \tthen\n> @@ -458,12 +458,13 @@ Use -f if you really want to add it.\" >&2\n>   \t\tfi\n>\n>   \telse\n> -\t\tif test -d \".git/modules/$sm_name\"\n> +\t\tmodule_gitdir=$(git rev-parse --git-path \"modules/$sm_name\")\n> +\t\tif test -d \"$module_gitdir\"\n>   \t\tthen\n>   \t\t\tif test -z \"$force\"\n>   \t\t\tthen\n>   \t\t\t\techo >&2 \"$(eval_gettext \"A git directory for '\\$sm_name' is found locally with remote(s):\")\"\n> -\t\t\t\tGIT_DIR=\".git/modules/$sm_name\" GIT_WORK_TREE=. git remote -v | grep '(fetch)' | sed -e s,^,\"  \", -e s,' (fetch)',, >&2\n> +\t\t\t\tGIT_DIR=\"$module_gitdir\" GIT_WORK_TREE=. git remote -v | grep '(fetch)' | sed -e s,^,\"  \", -e s,' (fetch)',, >&2\n>   \t\t\t\techo >&2 \"$(eval_gettext \"If you want to reuse this local git directory instead of cloning again from\")\"\n>   \t\t\t\techo >&2 \"  $realrepo\"\n>   \t\t\t\techo >&2 \"$(eval_gettext \"use the '--force' option. If the local git directory is not the correct repo\")\"\n> @@ -472,16 +473,44 @@ Use -f if you really want to add it.\" >&2\n>   \t\t\t\techo \"$(eval_gettext \"Reactivating local git directory for submodule '\\$sm_name'.\")\"\n>   \t\t\tfi\n>   \t\tfi\n> -\t\tmodule_clone \"$sm_path\" \"$sm_name\" \"$realrepo\" \"$reference\" \"$depth\" || exit\n> -\t\t(\n> -\t\t\tclear_local_git_env\n> -\t\t\tcd \"$sm_path\" &&\n> -\t\t\t# ash fails to wordsplit ${branch:+-b \"$branch\"...}\n> -\t\t\tcase \"$branch\" in\n> -\t\t\t'') git checkout -f -q ;;\n> -\t\t\t?*) git checkout -f -q -B \"$branch\" \"origin/$branch\" ;;\n> -\t\t\tesac\n> -\t\t) || die \"$(eval_gettext \"Unable to checkout submodule '\\$sm_path'\")\"\n> +\t\tcheckout_to_common_gitdir=\n> +\t\tcommon_dir=$(git rev-parse --git-common-dir)\n> +\t\tprivate_dir=$(git rev-parse --git-dir)\n> +\t\tif test \"$common_dir\" != \"$private_dir\"\n> +\t\tthen\n> +\t\t\tcheckout_to_common_gitdir=\"$module_gitdir\"\n> +\t\t\ttmp_worktree=$(mktemp -d)\n> +\t\t\tls -a \"$tmp_worktree\"\n> +\t\t\ttest -n \"$tmp_worktree\" || die \"mktemp failed\"\n> +\t\t\tmodule_clone \"$tmp_worktree\" \"$sm_name\" \"$realrepo\" \"$reference\" \"$depth\" &&\n> +\t\t\t(\n> +\t\t\t\tclear_local_git_env\n> +\t\t\t\tcd \"$tmp_worktree\" &&\n> +\t\t\t\tgit update-ref --no-deref HEAD HEAD'^0' &&\n> +\t\t\t\tgit config --unset core.worktree\n> +\t\t\t) || exit\n> +\t\t\trm -rf \"$tmp_worktree\"\n> +\t\t\trm -f \"$checkout_to_common_gitdir/index\"\n> +\t\t\t(\n> +\t\t\t\tclear_local_git_env\n> +\t\t\t\t# ash fails to wordsplit ${branch:+-b \"$branch\"...}\n> +\t\t\t\tcase \"$branch\" in\n> +\t\t\t\t'') git --git-dir=\"$checkout_to_common_gitdir\" checkout -f -q --to \"$sm_path\" origin/HEAD ;;\n> +\t\t\t\t?*) git --git-dir=\"$checkout_to_common_gitdir\" checkout -f -q -B \"$branch\" --to \"$sm_path\" \"origin/$branch\" ;;\n> +\t\t\t\tesac\n> +\t\t\t) || die \"$(eval_gettext \"Unable to checkout submodule '\\$sm_path'\")\"\n> +\t\telse\n> +\t\t\tmodule_clone \"$sm_path\" \"$sm_name\" \"$realrepo\" \"$reference\" \"$depth\" || exit\n> +\t\t\t(\n> +\t\t\t\tclear_local_git_env\n> +\t\t\t\tcd \"$sm_path\" &&\n> +\t\t\t\t# ash fails to wordsplit ${branch:+-b \"$branch\"...}\n> +\t\t\t\tcase \"$branch\" in\n> +\t\t\t\t'') git checkout -f -q ;;\n> +\t\t\t\t?*) git checkout -f -q -B \"$branch\" \"origin/$branch\" ;;\n> +\t\t\t\tesac\n> +\t\t\t) || die \"$(eval_gettext \"Unable to checkout submodule '\\$sm_path'\")\"\n> +\t\tfi\n>   \tfi\n>   \tgit config submodule.\"$sm_name\".url \"$realrepo\"\n>\n> @@ -832,9 +861,27 @@ Maybe you want to use 'update --init'?\")\"\n>   \t\t\tcontinue\n>   \t\tfi\n>\n> +\t\tcheckout_to_common_gitdir=\n>   \t\tif ! test -d \"$sm_path\"/.git && ! test -f \"$sm_path\"/.git\n>   \t\tthen\n> -\t\t\tmodule_clone \"$sm_path\" \"$name\" \"$url\" \"$reference\" \"$depth\" || exit\n> +\t\t\tcommon_dir=$(git rev-parse --git-common-dir)\n> +\t\t\tprivate_dir=$(git rev-parse --git-dir)\n> +\t\t\tif test \"$common_dir\" != \"$private_dir\"\n> +\t\t\tthen\n> +\t\t\t\tcheckout_to_common_gitdir=$(git rev-parse --git-path \"modules/$name\")\n> +\t\t\t\tif ! test -d \"$checkout_to_common_gitdir\"\n> +\t\t\t\tthen\n> +\t\t\t\t\ttmp_worktree=$(mktemp -d)\n> +\t\t\t\t\tls -a \"$tmp_worktree\"\n> +\t\t\t\t\ttest -n \"$tmp_worktree\" || die \"mktemp failed\"\n> +\t\t\t\t\tmodule_clone \"$tmp_worktree\" \"$name\" \"$url\" \"$reference\" \"$depth\" || exit\n> +\t\t\t\t\tgit --git-dir=\"$checkout_to_common_gitdir\" config --unset core.worktree\n> +\t\t\t\t\trm -rf \"$tmp_worktree\"\n> +\t\t\t\t\trm -f \"$checkout_to_common_gitdir/index\"\n> +\t\t\t\tfi\n> +\t\t\telse\n> +\t\t\t\tmodule_clone \"$sm_path\" \"$name\" \"$url\" \"$reference\" \"$depth\" || exit\n> +\t\t\tfi\n>   \t\t\tcloned_modules=\"$cloned_modules;$name\"\n>   \t\t\tsubsha1=\n>   \t\telse\n> @@ -886,24 +933,29 @@ Maybe you want to use 'update --init'?\")\"\n>   \t\t\tmust_die_on_failure=\n>   \t\t\tcase \"$update_module\" in\n>   \t\t\tcheckout)\n> -\t\t\t\tcommand=\"git checkout $subforce -q\"\n> +\t\t\t\tif test -n \"$checkout_to_common_gitdir\"\n> +\t\t\t\tthen\n> +\t\t\t\t\tsubmodule_command() { git --git-dir=\"$checkout_to_common_gitdir\" checkout --to . $subforce -q \"$@\"; }\n> +\t\t\t\telse\n> +\t\t\t\t\tsubmodule_command() { git checkout $subforce -q \"$@\"; }\n> +\t\t\t\tfi\n>   \t\t\t\tdie_msg=\"$(eval_gettext \"Unable to checkout '\\$sha1' in submodule path '\\$displaypath'\")\"\n>   \t\t\t\tsay_msg=\"$(eval_gettext \"Submodule path '\\$displaypath': checked out '\\$sha1'\")\"\n>   \t\t\t\t;;\n>   \t\t\trebase)\n> -\t\t\t\tcommand=\"git rebase\"\n> +\t\t\t\tsubmodule_command() { git rebase \"$@\"; }\n>   \t\t\t\tdie_msg=\"$(eval_gettext \"Unable to rebase '\\$sha1' in submodule path '\\$displaypath'\")\"\n>   \t\t\t\tsay_msg=\"$(eval_gettext \"Submodule path '\\$displaypath': rebased into '\\$sha1'\")\"\n>   \t\t\t\tmust_die_on_failure=yes\n>   \t\t\t\t;;\n>   \t\t\tmerge)\n> -\t\t\t\tcommand=\"git merge\"\n> +\t\t\t\tsubmodule_command() { git merge \"$@\"; }\n>   \t\t\t\tdie_msg=\"$(eval_gettext \"Unable to merge '\\$sha1' in submodule path '\\$displaypath'\")\"\n>   \t\t\t\tsay_msg=\"$(eval_gettext \"Submodule path '\\$displaypath': merged in '\\$sha1'\")\"\n>   \t\t\t\tmust_die_on_failure=yes\n>   \t\t\t\t;;\n>   \t\t\t!*)\n> -\t\t\t\tcommand=\"${update_module#!}\"\n> +\t\t\t\tsubmodule_command() { ${update_module#!} \"$@\"; }\n>   \t\t\t\tdie_msg=\"$(eval_gettext \"Execution of '\\$command \\$sha1' failed in submodule  path '\\$prefix\\$sm_path'\")\"\n>   \t\t\t\tsay_msg=\"$(eval_gettext \"Submodule path '\\$prefix\\$sm_path': '\\$command \\$sha1'\")\"\n>   \t\t\t\tmust_die_on_failure=yes\n> @@ -912,7 +964,7 @@ Maybe you want to use 'update --init'?\")\"\n>   \t\t\t\tdie \"$(eval_gettext \"Invalid update mode '$update_module' for submodule '$name'\")\"\n>   \t\t\tesac\n>\n> -\t\t\tif (clear_local_git_env; cd \"$sm_path\" && $command \"$sha1\")\n> +\t\t\tif (clear_local_git_env; cd \"$sm_path\" && submodule_command \"$sha1\")\n>   \t\t\tthen\n>   \t\t\t\tsay \"$say_msg\"\n>   \t\t\telif test -n \"$must_die_on_failure\"\n> diff --git a/path.c b/path.c\n> index 35d498e..fadc1ea 100644\n> --- a/path.c\n> +++ b/path.c\n> @@ -98,7 +98,7 @@ static const char *common_list[] = {\n>   \tNULL\n>   };\n>\n> -static void update_common_dir(struct strbuf *buf, int git_dir_len)\n> +static void update_common_dir(struct strbuf *buf, int git_dir_len, const char* common_dir)\n>   {\n>   \tchar *base = buf->buf + git_dir_len;\n>   \tconst char **p;\n> @@ -115,12 +115,17 @@ static void update_common_dir(struct strbuf *buf, int git_dir_len)\n>   \t\t\tpath++;\n>   \t\t\tis_dir = 1;\n>   \t\t}\n> +\n> +\t\tif (!common_dir) {\n> +\t\t\tcommon_dir = get_git_common_dir();\n> +\t\t}\n> +\n>   \t\tif (is_dir && dir_prefix(base, path)) {\n> -\t\t\treplace_dir(buf, git_dir_len, get_git_common_dir());\n> +\t\t\treplace_dir(buf, git_dir_len, common_dir);\n>   \t\t\treturn;\n>   \t\t}\n>   \t\tif (!is_dir && !strcmp(base, path)) {\n> -\t\t\treplace_dir(buf, git_dir_len, get_git_common_dir());\n> +\t\t\treplace_dir(buf, git_dir_len, common_dir);\n>   \t\t\treturn;\n>   \t\t}\n>   \t}\n> @@ -160,7 +165,7 @@ static void adjust_git_path(struct strbuf *buf, int git_dir_len)\n>   \telse if (git_db_env && dir_prefix(base, \"objects\"))\n>   \t\treplace_dir(buf, git_dir_len + 7, get_object_directory());\n>   \telse if (git_common_dir_env)\n> -\t\tupdate_common_dir(buf, git_dir_len);\n> +\t\tupdate_common_dir(buf, git_dir_len, NULL);\n>   }\n>\n>   static void do_git_path(struct strbuf *buf, const char *fmt, va_list args)\n> @@ -256,6 +261,8 @@ const char *git_path_submodule(const char *path, const char *fmt, ...)\n>   {\n>   \tstruct strbuf *buf = get_pathname();\n>   \tconst char *git_dir;\n> +\tstruct strbuf git_submodule_common_dir = STRBUF_INIT;\n> +\tstruct strbuf git_submodule_dir = STRBUF_INIT;\n>   \tva_list args;\n>\n>   \tstrbuf_addstr(buf, path);\n> @@ -269,11 +276,20 @@ const char *git_path_submodule(const char *path, const char *fmt, ...)\n>   \t\tstrbuf_addstr(buf, git_dir);\n>   \t}\n>   \tstrbuf_addch(buf, '/');\n> +\tstrbuf_addstr(&git_submodule_dir, buf->buf);\n>\n>   \tva_start(args, fmt);\n>   \tstrbuf_vaddf(buf, fmt, args);\n>   \tva_end(args);\n> +\n> +\tif (get_common_dir_noenv(&git_submodule_common_dir, git_submodule_dir.buf)) {\n> +\t\tupdate_common_dir(buf, git_submodule_dir.len, git_submodule_common_dir.buf);\n> +\t}\n> +\n>   \tstrbuf_cleanup_path(buf);\n> +\n> +\tstrbuf_release(&git_submodule_dir);\n> +\tstrbuf_release(&git_submodule_common_dir);\n>   \treturn buf->buf;\n>   }\n>\n> diff --git a/setup.c b/setup.c\n> index fb61860..ffda622 100644\n> --- a/setup.c\n> +++ b/setup.c\n> @@ -226,14 +226,21 @@ void verify_non_filename(const char *prefix, const char *arg)\n>\n>   int get_common_dir(struct strbuf *sb, const char *gitdir)\n>   {\n> +\tconst char *git_env_common_dir = getenv(GIT_COMMON_DIR_ENVIRONMENT);\n> +\tif (git_env_common_dir) {\n> +\t\tstrbuf_addstr(sb, git_env_common_dir);\n> +\t\treturn 1;\n> +\t} else {\n> +\t\treturn get_common_dir_noenv(sb, gitdir);\n> +\t}\n> +}\n> +\n> +int get_common_dir_noenv(struct strbuf *sb, const char *gitdir)\n> +{\n>   \tstruct strbuf data = STRBUF_INIT;\n>   \tstruct strbuf path = STRBUF_INIT;\n> -\tconst char *git_common_dir = getenv(GIT_COMMON_DIR_ENVIRONMENT);\n>   \tint ret = 0;\n> -\tif (git_common_dir) {\n> -\t\tstrbuf_addstr(sb, git_common_dir);\n> -\t\treturn 1;\n> -\t}\n> +\n>   \tstrbuf_addf(&path, \"%s/commondir\", gitdir);\n>   \tif (file_exists(path.buf)) {\n>   \t\tif (strbuf_read_file(&data, path.buf, 0) <= 0)\n> diff --git a/submodule.c b/submodule.c\n> index 34094f5..4aad3d4 100644\n> --- a/submodule.c\n> +++ b/submodule.c\n> @@ -122,43 +122,35 @@ void stage_updated_gitmodules(void)\n>\n>   static int add_submodule_odb(const char *path)\n>   {\n> -\tstruct strbuf objects_directory = STRBUF_INIT;\n>   \tstruct alternate_object_database *alt_odb;\n> +\tconst char* objects_directory;\n>   \tint ret = 0;\n> -\tconst char *git_dir;\n>\n> -\tstrbuf_addf(&objects_directory, \"%s/.git\", path);\n> -\tgit_dir = read_gitfile(objects_directory.buf);\n> -\tif (git_dir) {\n> -\t\tstrbuf_reset(&objects_directory);\n> -\t\tstrbuf_addstr(&objects_directory, git_dir);\n> -\t}\n> -\tstrbuf_addstr(&objects_directory, \"/objects/\");\n> -\tif (!is_directory(objects_directory.buf)) {\n> +\tobjects_directory = git_path_submodule(path, \"objects/\");\n> +\tif (!is_directory(objects_directory)) {\n>   \t\tret = -1;\n>   \t\tgoto done;\n>   \t}\n> +\n>   \t/* avoid adding it twice */\n>   \tfor (alt_odb = alt_odb_list; alt_odb; alt_odb = alt_odb->next)\n> -\t\tif (alt_odb->name - alt_odb->base == objects_directory.len &&\n> -\t\t\t\t!strncmp(alt_odb->base, objects_directory.buf,\n> -\t\t\t\t\tobjects_directory.len))\n> +\t\tif (alt_odb->name - alt_odb->base == strlen(objects_directory) &&\n> +\t\t\t\t!strcmp(alt_odb->base, objects_directory))\n>   \t\t\tgoto done;\n>\n> -\talt_odb = xmalloc(objects_directory.len + 42 + sizeof(*alt_odb));\n> +\talt_odb = xmalloc(strlen(objects_directory) + 42 + sizeof(*alt_odb));\n>   \talt_odb->next = alt_odb_list;\n> -\tstrcpy(alt_odb->base, objects_directory.buf);\n> -\talt_odb->name = alt_odb->base + objects_directory.len;\n> +\tstrcpy(alt_odb->base, objects_directory);\n> +\talt_odb->name = alt_odb->base + strlen(objects_directory);\n>   \talt_odb->name[2] = '/';\n>   \talt_odb->name[40] = '\\0';\n>   \talt_odb->name[41] = '\\0';\n>   \talt_odb_list = alt_odb;\n>\n>   \t/* add possible alternates from the submodule */\n> -\tread_info_alternates(objects_directory.buf, 0);\n> +\tread_info_alternates(objects_directory, 0);\n>   \tprepare_alt_odb();\n>   done:\n> -\tstrbuf_release(&objects_directory);\n>   \treturn ret;\n>   }\n>\n> diff --git a/t/t7410-submodule-checkout-to.sh b/t/t7410-submodule-checkout-to.sh\n> new file mode 100755\n> index 0000000..cbbcecb\n> --- /dev/null\n> +++ b/t/t7410-submodule-checkout-to.sh\n> @@ -0,0 +1,201 @@\n> +#!/bin/sh\n> +\n> +test_description='Combination of submodules and multiple workdirs'\n> +\n> +. ./test-lib.sh\n> +\n> +base_path=$(pwd -P)\n> +\n> +test_expect_success 'setup: make origin' \\\n> +    'mkdir -p origin/sub && ( cd origin/sub && git init &&\n> +\techo file1 >file1 &&\n> +\tgit add file1 &&\n> +\tgit commit -m file1 ) &&\n> +    mkdir -p origin/main && ( cd origin/main && git init &&\n> +\tgit submodule add ../sub &&\n> +\tgit commit -m \"add sub\" ) &&\n> +    ( cd origin/sub &&\n> +\techo file1updated >file1 &&\n> +\tgit add file1 &&\n> +\tgit commit -m \"file1 updated\" ) &&\n> +    ( cd origin/main/sub && git pull ) &&\n> +    ( cd origin/main &&\n> +\tgit add sub &&\n> +\tgit commit -m \"sub updated\" )'\n> +\n> +test_expect_success 'setup: clone' \\\n> +    'mkdir clone && ( cd clone &&\n> +\tgit clone --recursive \"$base_path/origin/main\")'\n> +\n> +rev1_hash_main=$(git --git-dir=origin/main/.git show --pretty=format:%h -q \"HEAD~1\")\n> +rev1_hash_sub=$(git --git-dir=origin/sub/.git show --pretty=format:%h -q \"HEAD~1\")\n> +\n> +test_expect_success 'checkout main' \\\n> +    'mkdir default_checkout &&\n> +    (cd clone/main &&\n> +\tgit checkout --to \"$base_path/default_checkout/main\" \"$rev1_hash_main\")'\n> +\n> +# TODO: this must never work without --recursive\n> +test_expect_failure 'can see submodule diffs just after checkout' \\\n> +    '(cd default_checkout/main && git diff --submodule master\"^!\" | grep \"file1 updated\")'\n> +\n> +test_expect_success 'checkout main and initialize independed clones' \\\n> +    'mkdir fully_cloned_submodule &&\n> +    (cd clone/main &&\n> +\tgit checkout --to \"$base_path/fully_cloned_submodule/main\" \"$rev1_hash_main\") &&\n> +    (cd fully_cloned_submodule/main && git submodule update)'\n> +\n> +# TODO: thus must require update --init\n> +test_expect_success 'can see submodule diffs after independed cloning' \\\n> +    '(cd fully_cloned_submodule/main && git diff --submodule master\"^!\" | grep \"file1 updated\")'\n> +\n> +# TODO: this is not needed to do now regularly, rather being a special case\n> +# 1. manual checkout should point to somewhere else at all\n> +# 2. no need to make that gitlink\n> +test_expect_success 'checkout sub manually' \\\n> +    'mkdir linked_submodule &&\n> +    (cd clone/main &&\n> +\tgit checkout --to \"$base_path/linked_submodule/main\" \"$rev1_hash_main\") &&\n> +    (cd clone/main/sub &&\n> +\tgit checkout --to \"$base_path/linked_submodule/main/sub\" \"$rev1_hash_sub\") &&\n> +    mkdir clone/main/.git/worktrees/main/modules &&\n> +\techo \"gitdir: ../../modules/sub/worktrees/sub\" > clone/main/.git/worktrees/main/modules/sub'\n> +\n> +test_expect_success 'can see submodule diffs after manual checkout of linked submodule' \\\n> +    '(cd linked_submodule/main && git diff --submodule master\"^!\" | grep \"file1 updated\")'\n> +\n> +test_expect_success 'clone non-recursively and update to linked superpproject' \\\n> +    'mkdir clone_norec && ( cd clone_norec &&\n> +\tgit clone \"$base_path/origin/main\" &&\n> +\tcd main &&\n> +\tgit checkout --to \"$base_path/worktree_with_submodule/main\" \"$rev1_hash_main\") &&\n> +    (cd worktree_with_submodule/main &&\n> +\tgit submodule update --init)'\n> +\n> +test_expect_success 'can see submodule diffs in worktree with independently updated submodule' \\\n> +    '(cd worktree_with_submodule/main && git diff --submodule master\"^!\" | grep \"file1 updated\")'\n> +\n> +test_expect_success 'init submodule in main repository back' \\\n> +    '( cd clone_norec/main && git submodule update --init)'\n> +\n> +test_expect_success 'can see submodule diffs in main repository which initalized after linked' \\\n> +    '(cd clone_norec/main && git diff --submodule master\"^!\" | grep \"file1 updated\")'\n> +\n> +test_expect_success 'linked worktree is uptodate after chanages in main' \\\n> +    '(cd clone_norec/main && git checkout --detach master~1 && git submodule update) &&\n> +    (cd worktree_with_submodule/main &&\n> +\tgit status --porcelain >../../actual &&\n> +\t: >../../expected &&\n> +\ttest_cmp ../../expected ../../actual)'\n> +\n> +test_expect_success 'init another repository to test adding' \\\n> +    'mkdir -p add_area/repo &&\n> +    (cd add_area/repo &&\n> +\tgit init &&\n> +\tgit commit --allow-empty -m main_commit &&\n> +\tgit branch b2 &&\n> +\tgit checkout --to ../worktree b2)'\n> +\n> +test_expect_success 'add sub&history' \\\n> +    '(cd add_area/worktree &&\n> +\tgit submodule add ../../origin/sub sub &&\n> +\t(cd sub && git checkout --detach \"$rev1_hash_sub\") &&\n> +\tgit add sub &&\n> +\tgit commit -m sub_added &&\n> +\t(cd sub && git checkout --detach origin/master) &&\n> +\tgit add sub &&\n> +\tgit commit -m sub_changed)'\n> +\n> +test_expect_success 'inquire history after adding' \\\n> +    '(cd add_area/worktree &&\n> +\tgit diff --submodule b2\"^!\" | grep \"file1 updated\")'\n> +\n> +test_expect_success 'init submodule in main' \\\n> +    '(cd add_area/repo &&\n> +\tgit reset --hard b2~1 &&\n> +\tgit submodule update --init)'\n> +\n> +test_expect_success 'linked worktree is uptodate after changes in original after adding' \\\n> +    '(cd add_area/worktree &&\n> +\tgit status --porcelain >../../actual &&\n> +\t: >../../expected &&\n> +\ttest_cmp ../../expected ../../actual)'\n> +\n> +deinit_start()\n> +{\n> +    rm -rf deinit_area && \\\n> +    mkdir deinit_area && \\\n> +    ( cd deinit_area && \\\n> +\tgit clone \"$base_path/origin/main\" && \\\n> +\tcd main && \\\n> +\tgit checkout --to ../worktree --detach HEAD )\n> +}\n> +\n> +deinit_init()\n> +{\n> +    (cd \"deinit_area/$1\" && git submodule update --init)\n> +}\n> +\n> +deinit_deinit()\n> +{\n> +    (cd \"deinit_area/$1\" && git submodule deinit sub)\n> +}\n> +\n> +deinit_not_checked_out()\n> +{\n> +    (cd \"deinit_area/$1\" && git diff --submodule master\"^!\" >actual && grep -q \"not checked out\" actual)\n> +}\n> +\n> +deinit_checked_out()\n> +{\n> +    (cd \"deinit_area/$1\" && git diff --submodule master\"^!\" >actual && grep -q \"file1 updated\" actual)\n> +}\n> +\n> +# TODO:\n> +# 1. check that directories are cleaned and index is removed for main (?)\n> +# 2. .git/config should be removed only after last owrktree is. Is it visible at all?\n> +test_expect_success 'deinit main only - create' \\\n> +    'deinit_start && deinit_init main && deinit_deinit main'\n> +\n> +test_expect_success 'deinit main only - not checked out' \\\n> +    'deinit_not_checked_out main'\n> +\n> +test_expect_success 'deinit worktree only - create' \\\n> +    'deinit_init && deinit_init worktree && deinit_deinit worktree'\n> +\n> +test_expect_success 'deinit worktree only - not checked out' \\\n> +    'deinit_not_checked_out worktree'\n> +\n> +test_expect_success 'deinit from both, worktree then main - create' \\\n> +    'deinit_init && deinit_init main && deinit_init worktree && deinit_deinit worktree'\n> +\n> +test_expect_success 'deinit from both, worktree then main - update' \\\n> +    '(cd deinit_area/main && git submodule update) &&\n> +    (cd deinit_area/worktree && git submodule update)'\n> +\n> +test_expect_success 'deinit from both, worktree then main - check#1' \\\n> +    'deinit_not_checked_out worktree && deinit_checked_out main'\n> +\n> +test_expect_success 'deinit from both, worktree then main - deinit main' \\\n> +    'deinit_deinit main'\n> +\n> +test_expect_success 'deinit from both, worktree then main - check#2' \\\n> +    'deinit_not_checked_out worktree && deinit_not_checked_out main'\n> +\n> +test_expect_success 'deinit from both, main then worktree - create' \\\n> +    'deinit_init && deinit_init main && deinit_init worktree && deinit_deinit main'\n> +\n> +test_expect_success 'deinit from both, worktree then main - update' \\\n> +    '(cd deinit_area/main && git submodule update) &&\n> +    (cd deinit_area/worktree && git submodule update)'\n> +\n> +test_expect_success 'deinit from both, main then worktree - check#1' \\\n> +    'deinit_not_checked_out main && deinit_checked_out worktree'\n> +\n> +test_expect_success 'deinit from both, main then worktree - deinit worktree' \\\n> +    'deinit_deinit worktree'\n> +\n> +test_expect_success 'deinit from both, main then worktree - check#2' \\\n> +    'deinit_not_checked_out worktree && deinit_not_checked_out main'\n> +\n> +test_done\n>\n"},{"id":"252895","messageId":"20141202221611.GB9128@wheezy.local","threadId":"38079","inReplyTo":"547E24E4.7050100@web.de","subject":"Re: [PATCH/RFC v2] Squashed changes for multiple worktrees vs. submodules","fromName":"Max Kirillov","fromEmail":"max@max630.net","sentAt":"2014-12-02T22:16:11Z","receivedAt":"2014-12-02T22:16:11Z","isPatch":true,"sender":{"key":"max@max630.net","avatar":"https://avatars.githubusercontent.com/u/381560?v=4"},"body":"On Tue, Dec 02, 2014 at 09:45:24PM +0100, Jens Lehmann wrote:\n>> But, while hacking the submodule init I became more\n>> convinced that the modules directory should be common and\n>> submodules in checkout should be a checkouts of the\n>> submodule. Because this is looks like concept of\n>> submodules, that they are unique for the lifetime of\n>> repository, even if they do not exist in all revisions.\n>> And if anybody want to use fully independent checkout\n>> they can be always checked out manually. Actually, after\n>> a submodule is initialized and have a proper gitlink, it\n>> can be updated and inquired regardless of where it points\n>> to.\n> \n> If I understand you correctly you want to put the\n> submodule's common git dir under the superproject's common\n> git dir. I agree that that makes most sense as the\n> default, but having the possibility to use a common git\n> dir for submodule's of different superprojects would be\n> nice to have for some setups, e.g. CI-servers. But that\n> can be added later.\n\nSo far there is no separation of .git/config for different\nworktrees. As submodules rely on the config their separation\ncannot be done fully without changing that. So this should\nbe really left for some later improvements.\n\nAs a user I am currently perfectly satisfied with manually\nchecking out or even cloning submodules inplace, I don't do\nit often.\n\n> Thanks. I just didn't quite understand why you had to do so many\n> changes to git-submodule.sh. Wouldn't it be sufficient to just\n> update module_clone()?\n\nThanks, I should try it.\n\nProbably I had the opposite idea in mind - keep module_clone\nas untouched as possible. Maybe I should see how it's going\nto look if I move all worktrees logic there.\n\n-- \nMax\n"},{"id":"253087","messageId":"5480BEB9.8070109@web.de","threadId":"38079","inReplyTo":"20141202221611.GB9128@wheezy.local","subject":"Re: [PATCH/RFC v2] Squashed changes for multiple worktrees vs. submodules","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2014-12-04T20:06:17Z","receivedAt":"2014-12-04T20:06:17Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"Am 02.12.2014 um 23:16 schrieb Max Kirillov:\n> On Tue, Dec 02, 2014 at 09:45:24PM +0100, Jens Lehmann wrote:\n>>> But, while hacking the submodule init I became more\n>>> convinced that the modules directory should be common and\n>>> submodules in checkout should be a checkouts of the\n>>> submodule. Because this is looks like concept of\n>>> submodules, that they are unique for the lifetime of\n>>> repository, even if they do not exist in all revisions.\n>>> And if anybody want to use fully independent checkout\n>>> they can be always checked out manually. Actually, after\n>>> a submodule is initialized and have a proper gitlink, it\n>>> can be updated and inquired regardless of where it points\n>>> to.\n>>\n>> If I understand you correctly you want to put the\n>> submodule's common git dir under the superproject's common\n>> git dir. I agree that that makes most sense as the\n>> default, but having the possibility to use a common git\n>> dir for submodule's of different superprojects would be\n>> nice to have for some setups, e.g. CI-servers. But that\n>> can be added later.\n>\n> So far there is no separation of .git/config for different\n> worktrees. As submodules rely on the config their separation\n> cannot be done fully without changing that. So this should\n> be really left for some later improvements.\n\nWow, so the .git/config is shared between all worktrees? I\nsuspect you have very good reasons for that, but I believe\nthat'll make multiple work trees surprise the user from time\nto time when used with submodules. Because initializing a\nsubmodule in one worktree initializes it in all other\nworktrees too (I suspect other users regard \"git submodule\ninit\" being a worktree local command too). And setting\n\"submodule.<name>.update\" to \"none\" will also affect all\nother worktrees. But I'd need to have separate settings for\nour CI server, e.g. to checkout the sources without the\nlargish documentation submodule in one test job (=worktree)\nwhile checking out the whole documentation for another job\nbuilding the setup in another worktree.\n\nAnd if I understand the \"checkout: reject if the branch is\nalready checked out elsewhere\" thread correctly, I won't be\nable to build \"master\" in two jobs at the same time?\n\nSo two reasons against using multiple worktrees on our CI\nserver to save quite some disk space :-(\n\n>> Thanks. I just didn't quite understand why you had to do so many\n>> changes to git-submodule.sh. Wouldn't it be sufficient to just\n>> update module_clone()?\n>\n> Thanks, I should try it.\n>\n> Probably I had the opposite idea in mind - keep module_clone\n> as untouched as possible. Maybe I should see how it's going\n> to look if I move all worktrees logic there.\n\nThanks. But I changed my mind about the details (now that I\nknow about .git/config and multiple worktrees). I think you'd\nhave to connect a .git directory in the submodule to the\ncommon git dir directly, as you cannot use the core.worktree\nsetting (which could be different between commits due to\nrenames) when putting it into <worktree>/.git/modules. And\nthen you couldn't remove or rename a submodule anymore,\nbecause that fails when it contains a .git directory.\n\nSeems like we should put a \"Warning: may do unexpected things\nwhen used with submodules\" (with some examples about what might\nhappen) in the multiple worktrees documentation. And I don't\nbelieve anymore that teaching submodules to use the common git\ndir makes that much sense after I know about the restrictions\nit imposes.\n\nOr am I misunderstanding anything?\n"},{"id":"253146","messageId":"CACsJy8BWv8U6+sujEj8HgMGmgFJR_YgCroYHcG1jsoGtbVCD7Q@mail.gmail.com","threadId":"38079","inReplyTo":"5480BEB9.8070109@web.de","subject":"Re: [PATCH/RFC v2] Squashed changes for multiple worktrees vs. submodules","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2014-12-05T01:33:55Z","receivedAt":"2014-12-05T01:33:55Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Fri, Dec 5, 2014 at 3:06 AM, Jens Lehmann <Jens.Lehmann@web.de> wrote:\n> Wow, so the .git/config is shared between all worktrees? I\n> suspect you have very good reasons for that,\n\nmost of config vars are at repo-level, not worktree-level, except\nmaybe submodule.* and something else. Technically we could use\n\"include.path\" to point to a non-shared file, where we store\nworktree-specific config.\n\n> but I believe\n> that'll make multiple work trees surprise the user from time\n> to time when used with submodules. Because initializing a\n> submodule in one worktree initializes it in all other\n> worktrees too (I suspect other users regard \"git submodule\n> init\" being a worktree local command too). And setting\n> \"submodule.<name>.update\" to \"none\" will also affect all\n> other worktrees. But I'd need to have separate settings for\n> our CI server, e.g. to checkout the sources without the\n> largish documentation submodule in one test job (=worktree)\n> while checking out the whole documentation for another job\n> building the setup in another worktree.\n>\n> And if I understand the \"checkout: reject if the branch is\n> already checked out elsewhere\" thread correctly, I won't be\n> able to build \"master\" in two jobs at the same time?\n\nIf you do \"git checkout --to ... master^{}\", it should run fine. I'm\nstill considering doing something better with the read-only refs, but\nhaven't found time to really think it through yet.\n\n> Thanks. But I changed my mind about the details (now that I\n> know about .git/config and multiple worktrees). I think you'd\n> have to connect a .git directory in the submodule to the\n> common git dir directly, as you cannot use the core.worktree\n> setting (which could be different between commits due to\n> renames) when putting it into <worktree>/.git/modules. And\n> then you couldn't remove or rename a submodule anymore,\n> because that fails when it contains a .git directory.\n>\n> Seems like we should put a \"Warning: may do unexpected things\n> when used with submodules\" (with some examples about what might\n> happen) in the multiple worktrees documentation. And I don't\n> believe anymore that teaching submodules to use the common git\n> dir makes that much sense after I know about the restrictions\n> it imposes.\n\nI'm ok with such a warning fwiw.\n-- \nDuy\n"},{"id":"253153","messageId":"CAF7_NFQzPDF+7NS2VwopK8Oei=9NzWEAGM5fko-St5KvvmLa9A@mail.gmail.com","threadId":"38079","inReplyTo":"5480BEB9.8070109@web.de","subject":"Re: [PATCH/RFC v2] Squashed changes for multiple worktrees vs. submodules","fromName":"Max Kirillov","fromEmail":"max@max630.net","sentAt":"2014-12-05T06:32:00Z","receivedAt":"2014-12-05T06:32:00Z","isPatch":true,"sender":{"key":"max@max630.net","avatar":"https://avatars.githubusercontent.com/u/381560?v=4"},"body":"On Thu, Dec 4, 2014 at 10:06 PM, Jens Lehmann <Jens.Lehmann@web.de> wrote:\n> But I'd need to have separate settings for\n> our CI server, e.g. to checkout the sources without the\n> largish documentation submodule in one test job (=worktree)\n> while checking out the whole documentation for another job\n> building the setup in another worktree.\n\nCurrently I'm estimating approach when submodules which have .git\nfile or directory inside are updated, and those which do not have it are not.\nI have added a config variable submodule.updateIgnoringConfigUrl (because\nusually the submodule.<name>.url is what turns on the update). It looks working,\nmaybe I even add setting the variable when chackout --to is used.\n\n> And if I understand the \"checkout: reject if the branch is\n> already checked out elsewhere\" thread correctly, I won't be\n> able to build \"master\" in two jobs at the same time?\n\nYou are alerady second person complaining about it, but I don't really see\nhow this can be a problem. Make a branch 'master2', it's another 40 bytes.\n\n> So two reasons against using multiple worktrees on our CI\n> server to save quite some disk space :-(\n\nMy use is not to save space (working tree files often takes more than\nthe repository\nitself), but for development, I have like 3-5 checkouts usually, which\nused to be local\nclones, but not having to keep synching them is really life changing.\n\n> Thanks. But I changed my mind about the details (now that I\n> know about .git/config and multiple worktrees). I think you'd\n> have to connect a .git directory in the submodule to the\n> common git dir directly, as you cannot use the core.worktree\n> setting (which could be different between commits due to\n> renames) when putting it into <worktree>/.git/modules. And\n> then you couldn't remove or rename a submodule anymore,\n> because that fails when it contains a .git directory.\n\nI need to think more about it.\n\n> Seems like we should put a \"Warning: may do unexpected things\n> when used with submodules\" (with some examples about what might\n> happen) in the multiple worktrees documentation. And I don't\n> believe anymore that teaching submodules to use the common git\n> dir makes that much sense after I know about the restrictions\n> it imposes.\n\nbtw, I thought even about making it an error to add/remove/(de)initialize\nsubmodule not in the main working tree. But I'm afraid it would not be\nconsidered appropriate for merging.\n\n-- \nMax\n"},{"id":"253242","messageId":"5482FA35.40600@web.de","threadId":"38079","inReplyTo":"CACsJy8BWv8U6+sujEj8HgMGmgFJR_YgCroYHcG1jsoGtbVCD7Q@mail.gmail.com","subject":"Re: [PATCH/RFC v2] Squashed changes for multiple worktrees vs. submodules","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2014-12-06T12:44:37Z","receivedAt":"2014-12-06T12:44:37Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"Am 05.12.2014 um 02:33 schrieb Duy Nguyen:\n> On Fri, Dec 5, 2014 at 3:06 AM, Jens Lehmann <Jens.Lehmann@web.de> wrote:\n>> Wow, so the .git/config is shared between all worktrees? I\n>> suspect you have very good reasons for that,\n>\n> most of config vars are at repo-level, not worktree-level, except\n> maybe submodule.* and something else.\n\nYeah, that would have been my first guess too.\n\n > Technically we could use\n> \"include.path\" to point to a non-shared file, where we store\n> worktree-specific config.\n\nI like that, but am not sure how hard that would be to\nimplement.\n\n>> but I believe\n>> that'll make multiple work trees surprise the user from time\n>> to time when used with submodules. Because initializing a\n>> submodule in one worktree initializes it in all other\n>> worktrees too (I suspect other users regard \"git submodule\n>> init\" being a worktree local command too). And setting\n>> \"submodule.<name>.update\" to \"none\" will also affect all\n>> other worktrees. But I'd need to have separate settings for\n>> our CI server, e.g. to checkout the sources without the\n>> largish documentation submodule in one test job (=worktree)\n>> while checking out the whole documentation for another job\n>> building the setup in another worktree.\n>>\n>> And if I understand the \"checkout: reject if the branch is\n>> already checked out elsewhere\" thread correctly, I won't be\n>> able to build \"master\" in two jobs at the same time?\n>\n> If you do \"git checkout --to ... master^{}\", it should run fine.\n\nSo I'd have to teach our CI-server that incantation ... and\nmust hope nothing else breaks because of the detached HEAD.\n\n > I'm\n> still considering doing something better with the read-only refs, but\n> haven't found time to really think it through yet.\n\nHmm, what about different namespaces for the refs in the repo\nborrowed from? Maybe only when it is bare? Dunno ...\n\n>> Thanks. But I changed my mind about the details (now that I\n>> know about .git/config and multiple worktrees). I think you'd\n>> have to connect a .git directory in the submodule to the\n>> common git dir directly, as you cannot use the core.worktree\n>> setting (which could be different between commits due to\n>> renames) when putting it into <worktree>/.git/modules. And\n>> then you couldn't remove or rename a submodule anymore,\n>> because that fails when it contains a .git directory.\n>>\n>> Seems like we should put a \"Warning: may do unexpected things\n>> when used with submodules\" (with some examples about what might\n>> happen) in the multiple worktrees documentation. And I don't\n>> believe anymore that teaching submodules to use the common git\n>> dir makes that much sense after I know about the restrictions\n>> it imposes.\n>\n> I'm ok with such a warning fwiw.\n\nI believe you'd need to prominently advertise that changing\nsettings in .git/config affects all worktrees anyway to avoid\nsurprising users (at least I didn't expect it ;-), so adding\na word or to that this also impacts submodules should suffice.\n"},{"id":"253243","messageId":"5482FF40.3040204@web.de","threadId":"38079","inReplyTo":"CAF7_NFQzPDF+7NS2VwopK8Oei=9NzWEAGM5fko-St5KvvmLa9A@mail.gmail.com","subject":"Re: [PATCH/RFC v2] Squashed changes for multiple worktrees vs. submodules","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2014-12-06T13:06:08Z","receivedAt":"2014-12-06T13:06:08Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"Am 05.12.2014 um 07:32 schrieb Max Kirillov:\n> On Thu, Dec 4, 2014 at 10:06 PM, Jens Lehmann <Jens.Lehmann@web.de> wrote:\n>> But I'd need to have separate settings for\n>> our CI server, e.g. to checkout the sources without the\n>> largish documentation submodule in one test job (=worktree)\n>> while checking out the whole documentation for another job\n>> building the setup in another worktree.\n>\n> Currently I'm estimating approach when submodules which have .git\n> file or directory inside are updated, and those which do not have it are not.\n> I have added a config variable submodule.updateIgnoringConfigUrl (because\n> usually the submodule.<name>.url is what turns on the update). It looks working,\n> maybe I even add setting the variable when chackout --to is used.\n\nBut it's not only submodule.<name>.url, the list goes on with\nupdate, fetch & ignore and then there are the global options\nlike diff.submodule, diff.ignoreSubmodules and some more.\n\n>> And if I understand the \"checkout: reject if the branch is\n>> already checked out elsewhere\" thread correctly, I won't be\n>> able to build \"master\" in two jobs at the same time?\n>\n> You are alerady second person complaining about it, but I don't really see\n> how this can be a problem. Make a branch 'master2', it's another 40 bytes.\n\nI didn't mean to complain, I'm just explaining. And I cannot\neasily make it master2, I'd have to teach Jenkins that (and\nmaybe that's easy and I just don't know how to do it).\n\n>> So two reasons against using multiple worktrees on our CI\n>> server to save quite some disk space :-(\n>\n> My use is not to save space (working tree files often takes more than\n> the repository\n> itself), but for development, I have like 3-5 checkouts usually, which\n> used to be local\n> clones, but not having to keep synching them is really life changing.\n\nThanks, that explains my confusion. You want those repos to be\ntightly coupled while I'm looking for completely separate repos\nwhich just share their shared objects to reduce disk footprint.\n\n>> Seems like we should put a \"Warning: may do unexpected things\n>> when used with submodules\" (with some examples about what might\n>> happen) in the multiple worktrees documentation. And I don't\n>> believe anymore that teaching submodules to use the common git\n>> dir makes that much sense after I know about the restrictions\n>> it imposes.\n>\n> btw, I thought even about making it an error to add/remove/(de)initialize\n> submodule not in the main working tree. But I'm afraid it would not be\n> considered appropriate for merging.\n\nI think an error is too harsh here. If you know what you are\ndoing (and what you cannot do) I see no reason not to use\nsubmodules together with multiple worktrees. And if you're\nsharing branches it might be rather obvious that you share\nsubmodule and other worktree settings too in the superproject.\n\n\nThanks to you and Duy for discussing this with me! I'd sum it\nup like this:\n\n*) Multiple worktrees are meant to couple separate worktrees\n    with a single repository to avoid having to push and fetch\n    each time to sync refs and also to not having to sync\n    settings manually (with the benefit of some disk space\n    savings). That's a cool feature and explains why a branch\n    should be protected against being modified in different\n    worktrees.\n\n    The first level submodule settings are shared between the\n    multiple worktrees; submodule objects, settings and refs\n    aren't (because the .git/modules directory isn't shared).\n\n    Looks like that would work with just what we have now, no?\n\n    Having submodules share repos would need at least a\n    per-worktree core.git setting (which could be achieved via\n    worktree-specific .git/config includes).\n\n*) I'd love to see a solution for sharing the object database\n    between otherwise unrelated clones of the same project (so\n    that fetching in one clone updates the objects in the common\n    dir and gc cannot throw anything away used by one of the\n    clones). But I'd expect a bare repository as the common one\n    where we put the worktrees refs into their own namespaces.\n\n    That's another beast (which nonetheless might be based on\n    what you guys are doing here). And the worktree specific\n    configuration needed here could help to share submodule\n    repos for the multiple worktrees case.\n\nDoes that make sense?\n"},{"id":"253264","messageId":"20141207064230.GA9782@wheezy.local","threadId":"38079","inReplyTo":"5482FF40.3040204@web.de","subject":"Re: [PATCH/RFC v2] Squashed changes for multiple worktrees vs. submodules","fromName":"Max Kirillov","fromEmail":"max@max630.net","sentAt":"2014-12-07T06:42:30Z","receivedAt":"2014-12-07T06:42:30Z","isPatch":true,"sender":{"key":"max@max630.net","avatar":"https://avatars.githubusercontent.com/u/381560?v=4"},"body":"On Sat, Dec 06, 2014 at 02:06:08PM +0100, Jens Lehmann wrote:\n> Am 05.12.2014 um 07:32 schrieb Max Kirillov:\n>> Currently I'm estimating approach when submodules which have .git\n>> file or directory inside are updated, and those which do not have it are not.\n>> I have added a config variable submodule.updateIgnoringConfigUrl (because\n>> usually the submodule.<name>.url is what turns on the update). It looks working,\n>> maybe I even add setting the variable when chackout --to is used.\n\n> But it's not only submodule.<name>.url, the list goes on with\n> update, fetch & ignore and then there are the global options\n> like diff.submodule, diff.ignoreSubmodules and some more.\n\nI believe that parameters are important for some use, but I\nknow several tesns of git users who have no idea bout them,\nand I myself only learned about them while working on this.\n\nTo have some a submodule not initialized in some sorktree is\nwhat I really need. I was sure before it is managed by\nhaving the submodule checked out. Probably I just did not\nrun `submodule update` in the worktree where did not use\nsubmodules, but I cannot rely on it.  I see now from\n211b7f19c7 that adding parameter for all updates will break\nthe initalization. Maybe it would be better to have a\nruntime argument: `git submodule update --ignore-config-url`\n\n> Thanks to you and Duy for discussing this with me! I'd sum it\n> up like this:\n> \n> *) Multiple worktrees are meant to couple separate worktrees\n>    with a single repository to avoid having to push and fetch\n>    each time to sync refs and also to not having to sync\n>    settings manually (with the benefit of some disk space\n>    savings). That's a cool feature and explains why a branch\n>    should be protected against being modified in different\n>    worktrees.\n\nI should notify that I am not the author of the feature,\nmaybe Duy have some other vision.\n\n>    The first level submodule settings are shared between the\n>    multiple worktrees; submodule objects, settings and refs\n>    aren't (because the .git/modules directory isn't shared).\n> \n>    Looks like that would work with just what we have now, no?\n\nYes, very much like what I proposed in $gmane/258173, but I\nneed to have something about preventing checkout. And I\nshould review what I've done since that, maybe there are\nmore things to fix.\n\n> *) I'd love to see a solution for sharing the object database\n>    between otherwise unrelated clones of the same project (so\n>    that fetching in one clone updates the objects in the common\n>    dir and gc cannot throw anything away used by one of the\n>    clones). But I'd expect a bare repository as the common one\n>    where we put the worktrees refs into their own namespaces.\n\nThere is a GIT_NAMESPACE already, maybe it should be just\nextended to work with all commands?\n\nbtw, have you tried alternates? It does reduce the number of\nobjects you need to keep very strongly. You can put in the\nalternate store only released branches which are guaranteed\nto be not force-updated, to avoid issues with missing\nobjects, and it still helps. For example, the full git\nrepository takes about 70mb, and if I put master to\nalternate store, the rest takes 7mb, and even if I clone all\noriginal repository, debian repository and msysgit\nrepository, thay all take 15mb. It's without worktree, which\ntakes 27mb :)\n\n-- \nMax\n"},{"id":"253268","messageId":"20141207091503.GC9128@wheezy.local","threadId":"38079","inReplyTo":"20141207064230.GA9782@wheezy.local","subject":"Re: [PATCH/RFC v2] Squashed changes for multiple worktrees vs. submodules","fromName":"Max Kirillov","fromEmail":"max@max630.net","sentAt":"2014-12-07T09:15:03Z","receivedAt":"2014-12-07T09:15:03Z","isPatch":true,"sender":{"key":"max@max630.net","avatar":"https://avatars.githubusercontent.com/u/381560?v=4"},"body":"On Sun, Dec 07, 2014 at 08:42:30AM +0200, Max Kirillov wrote:\n>> *) I'd love to see a solution for sharing the object database\n>>    between otherwise unrelated clones of the same project (so\n>>    that fetching in one clone updates the objects in the common\n>>    dir and gc cannot throw anything away used by one of the\n>>    clones). But I'd expect a bare repository as the common one\n>>    where we put the worktrees refs into their own namespaces.\n\n> There is a GIT_NAMESPACE already, maybe it should be just\n> extended to work with all commands?\n\nNo, this will not work for submodules, has same issues with\nthe same config.\n"},{"id":"253373","messageId":"54860CDB.9090904@web.de","threadId":"38079","inReplyTo":"20141207064230.GA9782@wheezy.local","subject":"Re: [PATCH/RFC v2] Squashed changes for multiple worktrees vs. submodules","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2014-12-08T20:40:59Z","receivedAt":"2014-12-08T20:40:59Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"Am 07.12.2014 um 07:42 schrieb Max Kirillov:\n> On Sat, Dec 06, 2014 at 02:06:08PM +0100, Jens Lehmann wrote:\n>> Am 05.12.2014 um 07:32 schrieb Max Kirillov:\n>>> Currently I'm estimating approach when submodules which have .git\n>>> file or directory inside are updated, and those which do not have it are not.\n>>> I have added a config variable submodule.updateIgnoringConfigUrl (because\n>>> usually the submodule.<name>.url is what turns on the update). It looks working,\n>>> maybe I even add setting the variable when chackout --to is used.\n>\n>> But it's not only submodule.<name>.url, the list goes on with\n>> update, fetch & ignore and then there are the global options\n>> like diff.submodule, diff.ignoreSubmodules and some more.\n>\n> I believe that parameters are important for some use, but I\n> know several tesns of git users who have no idea bout them,\n> and I myself only learned about them while working on this.\n\nBut we still want to support them all properly, no?\n\n> To have some a submodule not initialized in some sorktree is\n> what I really need. I was sure before it is managed by\n> having the submodule checked out. Probably I just did not\n> run `submodule update` in the worktree where did not use\n> submodules, but I cannot rely on it.  I see now from\n> 211b7f19c7 that adding parameter for all updates will break\n> the initalization. Maybe it would be better to have a\n> runtime argument: `git submodule update --ignore-config-url`\n\nHuh? I think we already have that: If you ignore the url\nconfig it's as if the submodule was never initialized, so\nyou can just *not* run the \"git submodule update\" command\nat all to get that effect. No new option needed ;-)\n\n>> Thanks to you and Duy for discussing this with me! I'd sum it\n>> up like this:\n>>\n>> *) Multiple worktrees are meant to couple separate worktrees\n>>     with a single repository to avoid having to push and fetch\n>>     each time to sync refs and also to not having to sync\n>>     settings manually (with the benefit of some disk space\n>>     savings). That's a cool feature and explains why a branch\n>>     should be protected against being modified in different\n>>     worktrees.\n>\n> I should notify that I am not the author of the feature,\n> maybe Duy have some other vision.\n>\n>>     The first level submodule settings are shared between the\n>>     multiple worktrees; submodule objects, settings and refs\n>>     aren't (because the .git/modules directory isn't shared).\n>>\n>>     Looks like that would work with just what we have now, no?\n>\n> Yes, very much like what I proposed in $gmane/258173, but I\n> need to have something about preventing checkout. And I\n> should review what I've done since that, maybe there are\n> more things to fix.\n\nHmm, I do not get the \"preventing checkout\" part. If you ran\n\"git submodule init <path>\" in just one of the multiple work\ntrees a later \"git submodule update\" in any of the multiple\nwork trees will checkout the submodule there. The only way I\ncan imagine to change that is to implement separate worktree\nconfigurations for each of the multiple worktrees.\n\n>> *) I'd love to see a solution for sharing the object database\n>>     between otherwise unrelated clones of the same project (so\n>>     that fetching in one clone updates the objects in the common\n>>     dir and gc cannot throw anything away used by one of the\n>>     clones). But I'd expect a bare repository as the common one\n>>     where we put the worktrees refs into their own namespaces.\n>\n> There is a GIT_NAMESPACE already, maybe it should be just\n> extended to work with all commands?\n\nAs you already noticed, it isn't a solution for my problem.\n\n> btw, have you tried alternates? It does reduce the number of\n> objects you need to keep very strongly. You can put in the\n> alternate store only released branches which are guaranteed\n> to be not force-updated, to avoid issues with missing\n> objects, and it still helps.\n\nWhich is exactly what we do *not* want to do on a CI server,\nits purpose is to endlessly build development branches that\nare force-updated on a regular basis.\n"},{"id":"253375","messageId":"20141208214956.GD9128@wheezy.local","threadId":"38079","inReplyTo":"54860CDB.9090904@web.de","subject":"Re: [PATCH/RFC v2] Squashed changes for multiple worktrees vs. submodules","fromName":"Max Kirillov","fromEmail":"max@max630.net","sentAt":"2014-12-08T21:49:56Z","receivedAt":"2014-12-08T21:49:56Z","isPatch":true,"sender":{"key":"max@max630.net","avatar":"https://avatars.githubusercontent.com/u/381560?v=4"},"body":"On Mon, Dec 08, 2014 at 09:40:59PM +0100, Jens Lehmann wrote:\n> Huh? I think we already have that: If you ignore the url\n> config it's as if the submodule was never initialized, so\n> you can just *not* run the \"git submodule update\" command\n> at all to get that effect. No new option needed ;-)\n\nYou are right. I was thinking about minimal change to\nsubmodules which would allow user selectively checkout them\nbut the most minimal one is just selectively run `submodule\nupdate`. I think in scope of this feature no changes to\ngit-submodule is required.\n\n>> btw, have you tried alternates? It does reduce the number of\n>> objects you need to keep very strongly. You can put in the\n>> alternate store only released branches which are guaranteed\n>> to be not force-updated, to avoid issues with missing\n>> objects, and it still helps.\n\n> Which is exactly what we do *not* want to do on a CI server,\n> its purpose is to endlessly build development branches that\n> are force-updated on a regular basis.\n\nYes, but they still are only somewhat ahead of some stable\nbranch. And not very much, if you count space: _All_ git\ndevelopment, with whatever unstable branches, takes 5-10\ntimes less space than its carved in stone history under\n`master`.\n\n-- \nMax\n"}]}