{"thread":{"id":"48702","subject":"[RFC PATCH 0/3] submodules with no working tree shall unset core.worktree","startedAt":"2018-06-12T23:58:34Z","lastAt":"2018-06-19T00:06:30Z","messageCount":11,"participants":["Stefan Beller","Junio C Hamano","SZEDER Gábor"],"isPatch":true,"patchVersion":1,"patchTotal":3},"messages":[{"id":"350033","messageId":"20180612235825.12271-1-sbeller@google.com","threadId":"48702","inReplyTo":null,"subject":"[RFC PATCH 0/3] submodules with no working tree shall unset core.worktree","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2018-06-12T23:58:22Z","receivedAt":"2018-06-12T23:58:34Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"The first patch teaches checkout/reset (with --recurse-submodules) to unset\nthe core.worktree config when the new state of the superprojects working tree\ndoesn't contain the submodules working tree.\n\nThe last patch is teaching \"git submodule deinit\" to unset the core.worktree\nsetting as well. It turned out this one is tricky, as for that we also\nhave to set it in the counter part, such as \"submodule update\".\n\nThanks,\nStefan\n\nStefan Beller (3):\n  submodule: unset core.worktree if no working tree is present\n  submodule: ensure core.worktree is set after update\n  submodule deinit: unset core.worktree\n\n builtin/submodule--helper.c | 26 ++++++++++++++++++++++++++\n git-submodule.sh            |  5 +++++\n submodule.c                 | 14 ++++++++++++++\n submodule.h                 |  2 ++\n t/lib-submodule-update.sh   |  5 +++--\n t/t7400-submodule-basic.sh  |  5 +++++\n 6 files changed, 55 insertions(+), 2 deletions(-)\n\n-- \n2.18.0.rc1.244.gcf134e6275-goog\n\n"},{"id":"350034","messageId":"20180612235825.12271-2-sbeller@google.com","threadId":"48702","inReplyTo":"20180612235825.12271-1-sbeller@google.com","subject":"[PATCH 1/3] submodule: unset core.worktree if no working tree is present","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2018-06-12T23:58:23Z","receivedAt":"2018-06-12T23:58:40Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"When a submodules work tree is removed, we should unset its core.worktree\nsetting as the worktree is no longer present. This is not just in line\nwith the conceptual view of submodules, but it fixes an inconvenience\nfor looking at submodules that are not checked out:\n\n    git clone --recurse-submodules git://github.com/git/git && cd git &&\n    git checkout --recurse-submodules v2.13.0\n    git -C .git/modules/sha1collisiondetection log\n    fatal: cannot chdir to '../../../sha1collisiondetection': \\\n        No such file or directory\n\nWith this patch applied, the final call to git log works instead of dying\nin its setup, as the checkout will unset the core.worktree setting such\nthat following log will be run in a bare repository.\n\nThis patch covers all commands that are in the unpack machinery, i.e.\ncheckout, read-tree, reset. A follow up patch will address\n\"git submodule deinit\", which will also make use of the new function\nsubmodule_unset_core_worktree(), which is why we expose it in this patch.\n\nSigned-off-by: Stefan Beller <sbeller@google.com>\n---\n submodule.c               | 14 ++++++++++++++\n submodule.h               |  2 ++\n t/lib-submodule-update.sh |  3 ++-\n 3 files changed, 18 insertions(+), 1 deletion(-)\n\ndiff --git a/submodule.c b/submodule.c\nindex 939d6870ecd..e127c074b04 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -1532,6 +1532,18 @@ int bad_to_remove_submodule(const char *path, unsigned flags)\n \treturn ret;\n }\n \n+void submodule_unset_core_worktree(const struct submodule *sub)\n+{\n+\tchar *config_path = xstrfmt(\"%s/modules/%s/config\",\n+\t\t\t\t    get_git_common_dir(), sub->name);\n+\n+\tif (git_config_set_in_file_gently(config_path, \"core.worktree\", NULL))\n+\t\twarning(_(\"Could not unset core.worktree setting in submodule '%s'\"),\n+\t\t\t  sub->path);\n+\n+\tfree(config_path);\n+}\n+\n static const char *get_super_prefix_or_empty(void)\n {\n \tconst char *s = get_super_prefix();\n@@ -1697,6 +1709,8 @@ int submodule_move_head(const char *path,\n \n \t\t\tif (is_empty_dir(path))\n \t\t\t\trmdir_or_warn(path);\n+\n+\t\t\tsubmodule_unset_core_worktree(sub);\n \t\t}\n \t}\n out:\ndiff --git a/submodule.h b/submodule.h\nindex 7856b8a0b3d..4644683e6cb 100644\n--- a/submodule.h\n+++ b/submodule.h\n@@ -121,6 +121,8 @@ extern int submodule_move_head(const char *path,\n \t\t\t       const char *new_head,\n \t\t\t       unsigned flags);\n \n+void submodule_unset_core_worktree(const struct submodule *sub);\n+\n /*\n  * Prepare the \"env_array\" parameter of a \"struct child_process\" for executing\n  * a submodule by clearing any repo-specific environment variables, but\ndiff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh\nindex 1f38a85371a..12cd4e9233e 100755\n--- a/t/lib-submodule-update.sh\n+++ b/t/lib-submodule-update.sh\n@@ -709,7 +709,8 @@ test_submodule_recursing_with_args_common() {\n \t\t\tgit branch -t remove_sub1 origin/remove_sub1 &&\n \t\t\t$command remove_sub1 &&\n \t\t\ttest_superproject_content origin/remove_sub1 &&\n-\t\t\t! test -e sub1\n+\t\t\t! test -e sub1 &&\n+\t\t\ttest_must_fail git config -f .git/modules/sub1/config core.worktree\n \t\t)\n \t'\n \t# ... absorbing a .git directory along the way.\n-- \n2.18.0.rc1.244.gcf134e6275-goog\n\n"},{"id":"350035","messageId":"20180612235825.12271-3-sbeller@google.com","threadId":"48702","inReplyTo":"20180612235825.12271-1-sbeller@google.com","subject":"[PATCH 2/3] submodule: ensure core.worktree is set after update","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2018-06-12T23:58:24Z","receivedAt":"2018-06-12T23:58:42Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"Signed-off-by: Stefan Beller <sbeller@google.com>\n---\n builtin/submodule--helper.c | 24 ++++++++++++++++++++++++\n git-submodule.sh            |  5 +++++\n 2 files changed, 29 insertions(+)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex bd250ca2164..dffc55ed8ee 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -1860,6 +1860,29 @@ static int check_name(int argc, const char **argv, const char *prefix)\n \treturn 0;\n }\n \n+static int connect_gitdir_workingtree(int argc, const char **argv, const char *prefix)\n+{\n+\tstruct strbuf sb = STRBUF_INIT;\n+\tconst char *name, *path;\n+\tchar *sm_gitdir;\n+\n+\tif (argc != 3)\n+\t\tBUG(\"submodule--helper connect-gitdir-workingtree <name> <path>\");\n+\n+\tname = argv[1];\n+\tpath = argv[2];\n+\n+\tstrbuf_addf(&sb, \"%s/modules/%s\", get_git_dir(), name);\n+\tsm_gitdir = absolute_pathdup(sb.buf);\n+\n+\tconnect_work_tree_and_git_dir(path, sm_gitdir, 0);\n+\n+\tstrbuf_release(&sb);\n+\tfree(sm_gitdir);\n+\n+\treturn 0;\n+}\n+\n #define SUPPORT_SUPER_PREFIX (1<<0)\n \n struct cmd_struct {\n@@ -1873,6 +1896,7 @@ static struct cmd_struct commands[] = {\n \t{\"name\", module_name, 0},\n \t{\"clone\", module_clone, 0},\n \t{\"update-clone\", update_clone, 0},\n+\t{\"connect-gitdir-workingtree\", connect_gitdir_workingtree, 0},\n \t{\"relative-path\", resolve_relative_path, 0},\n \t{\"resolve-relative-url\", resolve_relative_url, 0},\n \t{\"resolve-relative-url-test\", resolve_relative_url_test, 0},\ndiff --git a/git-submodule.sh b/git-submodule.sh\nindex 78073cd87d1..6596a77c5ef 100755\n--- a/git-submodule.sh\n+++ b/git-submodule.sh\n@@ -615,6 +615,11 @@ cmd_update()\n \t\t\tdie \"$(eval_gettext \"Unable to find current \\${remote_name}/\\${branch} revision in submodule path '\\$sm_path'\")\"\n \t\tfi\n \n+\t\tif ! $(git config -f \"$(git rev-parse --git-common-dir)/modules/$name/config\" core.worktree) 2>/dev/null\n+\t\tthen\n+\t\t\tgit submodule--helper connect-gitdir-workingtree $name $sm_path\n+\t\tfi\n+\n \t\tif test \"$subsha1\" != \"$sha1\" || test -n \"$force\"\n \t\tthen\n \t\t\tsubforce=$force\n-- \n2.18.0.rc1.244.gcf134e6275-goog\n\n"},{"id":"350036","messageId":"20180612235825.12271-4-sbeller@google.com","threadId":"48702","inReplyTo":"20180612235825.12271-1-sbeller@google.com","subject":"[PATCH 3/3] submodule deinit: unset core.worktree","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2018-06-12T23:58:25Z","receivedAt":"2018-06-12T23:58:45Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"When a submodule is deinit'd, the working tree is gone, so the setting of\ncore.worktree is bogus. Unset it.\n\nSigned-off-by: Stefan Beller <sbeller@google.com>\n---\n builtin/submodule--helper.c | 2 ++\n t/lib-submodule-update.sh   | 2 +-\n t/t7400-submodule-basic.sh  | 5 +++++\n 3 files changed, 8 insertions(+), 1 deletion(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex dffc55ed8ee..19480902681 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -980,6 +980,8 @@ static void deinit_submodule(const char *path, const char *prefix,\n \t\tif (!(flags & OPT_QUIET))\n \t\t\tprintf(format, displaypath);\n \n+\t\tsubmodule_unset_core_worktree(sub);\n+\n \t\tstrbuf_release(&sb_rm);\n \t}\n \ndiff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh\nindex 12cd4e9233e..aa5ac03325a 100755\n--- a/t/lib-submodule-update.sh\n+++ b/t/lib-submodule-update.sh\n@@ -235,7 +235,7 @@ reset_work_tree_to_interested () {\n \tthen\n \t\tmkdir -p submodule_update/.git/modules/sub1/modules &&\n \t\tcp -r submodule_update_repo/.git/modules/sub1/modules/sub2 submodule_update/.git/modules/sub1/modules/sub2\n-\t\tGIT_WORK_TREE=. git -C submodule_update/.git/modules/sub1/modules/sub2 config --unset core.worktree\n+\t\t# core.worktree is unset for sub2 as it is not checked out\n \tfi &&\n \t# indicate we are interested in the submodule:\n \tgit -C submodule_update config submodule.sub1.url \"bogus\" &&\ndiff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh\nindex be946fb1fd1..c6e1f749639 100755\n--- a/t/t7400-submodule-basic.sh\n+++ b/t/t7400-submodule-basic.sh\n@@ -993,6 +993,11 @@ test_expect_success 'submodule deinit should remove the whole submodule section\n \trmdir init\n '\n \n+test_expect_success 'submodule deinit should unset core.worktree' '\n+\ttest_path_is_file .git/modules/example/config &&\n+\ttest_must_fail git config -f .git/modules/example/config core.worktree\n+'\n+\n test_expect_success 'submodule deinit from subdirectory' '\n \tgit submodule update --init &&\n \tgit config submodule.example.foo bar &&\n-- \n2.18.0.rc1.244.gcf134e6275-goog\n\n"},{"id":"350073","messageId":"xmqq7en27ej0.fsf@gitster-ct.c.googlers.com","threadId":"48702","inReplyTo":"20180612235825.12271-1-sbeller@google.com","subject":"Re: [RFC PATCH 0/3] submodules with no working tree shall unset core.worktree","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-06-13T18:00:19Z","receivedAt":"2018-06-13T18:00:25Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Stefan Beller <sbeller@google.com> writes:\n\n> The first patch teaches checkout/reset (with --recurse-submodules) to unset\n> the core.worktree config when the new state of the superprojects working tree\n> doesn't contain the submodules working tree.\n\nAre there two cases of \"doesn't contain working tree of a submodule\"?\n\nThe superproject's commit may not have a gitlink to a specific\nsubmodule in its tree (i.e. there is no way to even \"submodule init\"\nwith such a commit in the superproject's history).  Or there may be\na gitlink but the user chose not to check it out in the working\ntree.\n\nDo they need to be treated differently, or can they be treated the\nsame way?\n\nAlso, is the \"submodule\" feature supposed to play well with multiple\nworktree feature?  Let's imagine that you have two worktrees for a\nsingle superproject, and the branches of the superproject these two\nworktrees check out are different ones (which is the more sensible\nset-up than checking out the same branch twice).  Further imagine\nthat the superproject started using a single submodule sometime in\nthe past and keeps using it throughout its life since then.\n\n 1. if both of these two branches have the submodule, and two\n    worktrees both are interested in having the submodule checked\n    out via \"submodule init/update\", where does core.worktree point\n    at?  Do we have two copies of the variable?\n\n 2. what if one branch predates the use of the submodule in the\n    superproject while the other branch is newer and uses the\n    submodule?  Where does core.worktree point at?\n\nThanks.\n\n> The last patch is teaching \"git submodule deinit\" to unset the core.worktree\n> setting as well. It turned out this one is tricky, as for that we also\n> have to set it in the counter part, such as \"submodule update\".\n>\n> Thanks,\n> Stefan\n>\n> Stefan Beller (3):\n>   submodule: unset core.worktree if no working tree is present\n>   submodule: ensure core.worktree is set after update\n>   submodule deinit: unset core.worktree\n>\n>  builtin/submodule--helper.c | 26 ++++++++++++++++++++++++++\n>  git-submodule.sh            |  5 +++++\n>  submodule.c                 | 14 ++++++++++++++\n>  submodule.h                 |  2 ++\n>  t/lib-submodule-update.sh   |  5 +++--\n>  t/t7400-submodule-basic.sh  |  5 +++++\n>  6 files changed, 55 insertions(+), 2 deletions(-)\n"},{"id":"350079","messageId":"CAGZ79kbTuu9kXXag0aYvDr90D8LXYo2kWhshx=kr5QHk7Lv3AQ@mail.gmail.com","threadId":"48702","inReplyTo":"xmqq7en27ej0.fsf@gitster-ct.c.googlers.com","subject":"Re: [RFC PATCH 0/3] submodules with no working tree shall unset core.worktree","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2018-06-13T18:52:17Z","receivedAt":"2018-06-13T18:52:32Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Wed, Jun 13, 2018 at 11:00 AM Junio C Hamano <gitster@pobox.com> wrote:\n>\n> Stefan Beller <sbeller@google.com> writes:\n>\n> > The first patch teaches checkout/reset (with --recurse-submodules) to unset\n> > the core.worktree config when the new state of the superprojects working tree\n> > doesn't contain the submodules working tree.\n>\n> Are there two cases of \"doesn't contain working tree of a submodule\"?\n>\n> The superproject's commit may not have a gitlink to a specific\n> submodule in its tree (i.e. there is no way to even \"submodule init\"\n> with such a commit in the superproject's history).\n\n... for example git.git before 2.13 did not have a gitlink for its\nsha1collision submodule ...\n\n>   Or there may be\n> a gitlink but the user chose not to check it out in the working\n> tree.\n\nThis is when the submodule is not active or de-initialized or not initialized\nto begin with. However there is an empty directory as a place holder.\nAs long as the empty place holder is there, we do not run into trouble.\n\n> Do they need to be treated differently, or can they be treated the\n> same way?\n\nI would think they are the same, as both cases do not have a working tree\nfor the submodule.\n\n> Also, is the \"submodule\" feature supposed to play well with multiple\n> worktree feature?\n\nIt is a long term goal to get this working.\n\n>  Let's imagine that you have two worktrees for a\n> single superproject, and the branches of the superproject these two\n> worktrees check out are different ones (which is the more sensible\n> set-up than checking out the same branch twice).\n\n(git-worktree even prevents you to checkout the same branch),\nsounds all very sensible up to here.\n\n\n> Further imagine\n> that the superproject started using a single submodule sometime in\n> the past and keeps using it throughout its life since then.\n>\n>  1. if both of these two branches have the submodule, and two\n>     worktrees both are interested in having the submodule checked\n>     out via \"submodule init/update\", where does core.worktree point\n>     at?  Do we have two copies of the variable?\n\nCurrently in the real world (aka in origin/master), the submodules are\ncompletely duplicated, and do not know about the worktree feature\nthemselves:\n\n    $ cd .git && find . |grep config |grep sha1co\n    ./modules/sha1collisiondetection/config\n    ./worktrees/git/modules/sha1collisiondetection/config\n\n(Yes I do have a worktree called \"git\".)\n\nSo for the sake of this patch series this should be okay, as there\nis only ever one working tree for a submodule currently.\n\nThe current state of affairs is really bad as the submodule is\nthere twice with all objects and the rest.\n\n>  2. what if one branch predates the use of the submodule in the\n>     superproject while the other branch is newer and uses the\n>     submodule?  Where does core.worktree point at?\n\nAs we have two copies of the repository, one of them points at the\ncorrect place, and the other would be unset.\n\n---\n\nIn an ideal world we would want the submodules to use the worktree\nfeature along-side the superproject, e.g. if the superproject has the\ntwo worktrees as above, the submodule would also get these.\n\nHowever I have not thought about this future too deeply, as there\nare a couple bumps along the road:\n\nSupposedly the submodules main (common) git dir would stay in the\ncommon git dir of the superproject at /modules/<name>.\nHowever where would we put the submodules non-main worktree\ngit dirs? There are two places, as seen from the superprojects:\n\n  .git/modules/<submodule-name>/worktrees/<worktree-name>\n  .git/worktrees/<worktree-name>/modules/<submodule-name>\n\nAs worktrees can be removed pretty easily (\"git worktree prune\"),\nI would not put the main parts of a submodule into a worktree part\nof the superproject (The user could be in a non-main worktree\nwhen they first ask for the submodule -- we have to make sure\nthe main git dir goes into the superprojects main git dir under\nmodules/).\n\nAn advantage for\n   .git/worktrees/<worktree-name>/modules/<submodule-name>\nwould be that the worktree of the submodule is coupled to the\nworktree of the superproject, i.e. if the user wipes the superprojects\nworktree, the submodules accompanying worktree is gone automatically.\n\nAn advantage for\n  .git/modules/<submodule-name>/worktrees/<worktree-name>\nis to have any submodule related things in one place in\n  .git/modules/<submodule-name>\n\nCleanup of the worktrees would be a bit harder as we'd have to\nremember to prune the worktrees for all submodules as well\nwhen the superproject removes one of its worktrees.\n\nIt is relatively rare to delete the submodule git directory compared to\nremoving a worktree, such that\n  .git/modules/<submodule-name>/worktrees/<worktree-name>\nsounds a bit more promising to me.\n\nHowever the worktree command needs to figure out the worktrees:\n    /path/to/super/worktree/submodule $ git worktree list\n\nThis would look at its git dir, which is\n\n .git/modules/<submodule-name>/worktrees/<specific-worktree>\n\ndiscover the common dir at\n\n .git/modules/<submodule-name>\n\nand then proceed in listing worktrees by exploring worktrees/.\nIf we had put it in the other form of\n   .git/worktrees/<worktree-name>/modules/<submodule-name>\nwe'd discover the common git dir at\n  .git/modules/<submodule-name>\nand list it from there.\n\nHowever currently we use the existence of directories (both for\nsubmodules as well as worktrees) to infer some knowledge about\nthe existence of submodules and worktrees, so we cannot just declare\none version or the other to be the future, but we'd have to add some\nform of linking, I would think.\n\nStefan\n"},{"id":"350333","messageId":"20180616202628.9208-1-szeder.dev@gmail.com","threadId":"48702","inReplyTo":"20180612235825.12271-3-sbeller@google.com","subject":"Re: [PATCH 2/3] submodule: ensure core.worktree is set after update","fromName":"SZEDER Gábor","fromEmail":"szeder.dev@gmail.com","sentAt":"2018-06-16T20:26:28Z","receivedAt":"2018-06-16T20:26:42Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"> +static int connect_gitdir_workingtree(int argc, const char **argv, const char *prefix)\n> +{\n> +\tstruct strbuf sb = STRBUF_INIT;\n> +\tconst char *name, *path;\n> +\tchar *sm_gitdir;\n> +\n> +\tif (argc != 3)\n> +\t\tBUG(\"submodule--helper connect-gitdir-workingtree <name> <path>\");\n\nSo this aborts when it's invoked with the wrong number of cmdline\narguments.\n\n> +\n> +\tname = argv[1];\n> +\tpath = argv[2];\n> +\n> +\tstrbuf_addf(&sb, \"%s/modules/%s\", get_git_dir(), name);\n> +\tsm_gitdir = absolute_pathdup(sb.buf);\n> +\n> +\tconnect_work_tree_and_git_dir(path, sm_gitdir, 0);\n> +\n> +\tstrbuf_release(&sb);\n> +\tfree(sm_gitdir);\n> +\n> +\treturn 0;\n> +}\n> +\n>  #define SUPPORT_SUPER_PREFIX (1<<0)\n>  \n>  struct cmd_struct {\n\n> diff --git a/git-submodule.sh b/git-submodule.sh\n> index 78073cd87d1..6596a77c5ef 100755\n> --- a/git-submodule.sh\n> +++ b/git-submodule.sh\n> @@ -615,6 +615,11 @@ cmd_update()\n>  \t\t\tdie \"$(eval_gettext \"Unable to find current \\${remote_name}/\\${branch} revision in submodule path '\\$sm_path'\")\"\n>  \t\tfi\n>  \n> +\t\tif ! $(git config -f \"$(git rev-parse --git-common-dir)/modules/$name/config\" core.worktree) 2>/dev/null\n> +\t\tthen\n> +\t\t\tgit submodule--helper connect-gitdir-workingtree $name $sm_path\n\nThe path to the submodule, $sm_path, may contain spaces, so it must\nbe quoted.\n\nI'm sure you would have noticed this already, had you checked this\n'submodule--helper's exit code :)  In t7406 the test 'submodule update\nproperly revives a moved submodule' does update a submodule with a\nspace in its name, and thus executes 'submodule--helper' with one more\nargument than expected, causing it to abort, but since there is no\nerror checking, 'git submodule update' continues anyway, and in the\nend the test tends to pass[1].\n\nI think it would be prudent to check the exit code of all\n'submodule--helper' executions.\n\n\n[1] I wrote \"tends to\", because e.g. on Travis CI the aborting\n    'submodule--helper' often dumps its core, and the extra 'core'\n    file shows up in the output of 'git status' and 'test_cmp' notices\n    it.\n\n\n> +\t\tfi\n> +\n>  \t\tif test \"$subsha1\" != \"$sha1\" || test -n \"$force\"\n>  \t\tthen\n>  \t\t\tsubforce=$force\n> -- \n> 2.18.0.rc1.244.gcf134e6275-goog\n> \n> \n"},{"id":"350445","messageId":"20180619000608.147422-1-sbeller@google.com","threadId":"48702","inReplyTo":"20180612235825.12271-1-sbeller@google.com","subject":"[PATCH 0/3] submodules with no working tree shall unset core.worktree","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2018-06-19T00:06:05Z","receivedAt":"2018-06-19T00:06:20Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"v2:\n* fixed quoting issues for white space'd names/paths\n\nv1:\nThe first patch teaches checkout/reset (with --recurse-submodules) to unset\nthe core.worktree config when the new state of the superprojects working tree\ndoesn't contain the submodules working tree.\n\nThe last patch is teaching \"git submodule deinit\" to unset the core.worktree\nsetting as well. It turned out this one is tricky, as for that we also\nhave to set it in the counter part, such as \"submodule update\".\n\nThanks,\nStefan\n\nStefan Beller (3):\n  submodule: unset core.worktree if no working tree is present\n  submodule: ensure core.worktree is set after update\n  submodule deinit: unset core.worktree\n\n builtin/submodule--helper.c | 26 ++++++++++++++++++++++++++\n git-submodule.sh            |  5 +++++\n submodule.c                 | 14 ++++++++++++++\n submodule.h                 |  2 ++\n t/lib-submodule-update.sh   |  5 +++--\n t/t7400-submodule-basic.sh  |  5 +++++\n 6 files changed, 55 insertions(+), 2 deletions(-)\n\n-- \n2.18.0.rc1.244.gcf134e6275-goog\n\n"},{"id":"350446","messageId":"20180619000608.147422-2-sbeller@google.com","threadId":"48702","inReplyTo":"20180619000608.147422-1-sbeller@google.com","subject":"[PATCH 1/3] submodule: unset core.worktree if no working tree is present","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2018-06-19T00:06:06Z","receivedAt":"2018-06-19T00:06:25Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"When a submodules work tree is removed, we should unset its core.worktree\nsetting as the worktree is no longer present. This is not just in line\nwith the conceptual view of submodules, but it fixes an inconvenience\nfor looking at submodules that are not checked out:\n\n    git clone --recurse-submodules git://github.com/git/git && cd git &&\n    git checkout --recurse-submodules v2.13.0\n    git -C .git/modules/sha1collisiondetection log\n    fatal: cannot chdir to '../../../sha1collisiondetection': \\\n        No such file or directory\n\nWith this patch applied, the final call to git log works instead of dying\nin its setup, as the checkout will unset the core.worktree setting such\nthat following log will be run in a bare repository.\n\nThis patch covers all commands that are in the unpack machinery, i.e.\ncheckout, read-tree, reset. A follow up patch will address\n\"git submodule deinit\", which will also make use of the new function\nsubmodule_unset_core_worktree(), which is why we expose it in this patch.\n\nSigned-off-by: Stefan Beller <sbeller@google.com>\n---\n submodule.c               | 14 ++++++++++++++\n submodule.h               |  2 ++\n t/lib-submodule-update.sh |  3 ++-\n 3 files changed, 18 insertions(+), 1 deletion(-)\n\ndiff --git a/submodule.c b/submodule.c\nindex 939d6870ecd..e127c074b04 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -1532,6 +1532,18 @@ int bad_to_remove_submodule(const char *path, unsigned flags)\n \treturn ret;\n }\n \n+void submodule_unset_core_worktree(const struct submodule *sub)\n+{\n+\tchar *config_path = xstrfmt(\"%s/modules/%s/config\",\n+\t\t\t\t    get_git_common_dir(), sub->name);\n+\n+\tif (git_config_set_in_file_gently(config_path, \"core.worktree\", NULL))\n+\t\twarning(_(\"Could not unset core.worktree setting in submodule '%s'\"),\n+\t\t\t  sub->path);\n+\n+\tfree(config_path);\n+}\n+\n static const char *get_super_prefix_or_empty(void)\n {\n \tconst char *s = get_super_prefix();\n@@ -1697,6 +1709,8 @@ int submodule_move_head(const char *path,\n \n \t\t\tif (is_empty_dir(path))\n \t\t\t\trmdir_or_warn(path);\n+\n+\t\t\tsubmodule_unset_core_worktree(sub);\n \t\t}\n \t}\n out:\ndiff --git a/submodule.h b/submodule.h\nindex 7856b8a0b3d..4644683e6cb 100644\n--- a/submodule.h\n+++ b/submodule.h\n@@ -121,6 +121,8 @@ extern int submodule_move_head(const char *path,\n \t\t\t       const char *new_head,\n \t\t\t       unsigned flags);\n \n+void submodule_unset_core_worktree(const struct submodule *sub);\n+\n /*\n  * Prepare the \"env_array\" parameter of a \"struct child_process\" for executing\n  * a submodule by clearing any repo-specific environment variables, but\ndiff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh\nindex 1f38a85371a..12cd4e9233e 100755\n--- a/t/lib-submodule-update.sh\n+++ b/t/lib-submodule-update.sh\n@@ -709,7 +709,8 @@ test_submodule_recursing_with_args_common() {\n \t\t\tgit branch -t remove_sub1 origin/remove_sub1 &&\n \t\t\t$command remove_sub1 &&\n \t\t\ttest_superproject_content origin/remove_sub1 &&\n-\t\t\t! test -e sub1\n+\t\t\t! test -e sub1 &&\n+\t\t\ttest_must_fail git config -f .git/modules/sub1/config core.worktree\n \t\t)\n \t'\n \t# ... absorbing a .git directory along the way.\n-- \n2.18.0.rc1.244.gcf134e6275-goog\n\n"},{"id":"350447","messageId":"20180619000608.147422-3-sbeller@google.com","threadId":"48702","inReplyTo":"20180619000608.147422-1-sbeller@google.com","subject":"[PATCH 2/3] submodule: ensure core.worktree is set after update","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2018-06-19T00:06:07Z","receivedAt":"2018-06-19T00:06:26Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"Signed-off-by: Stefan Beller <sbeller@google.com>\n---\n builtin/submodule--helper.c | 24 ++++++++++++++++++++++++\n git-submodule.sh            |  5 +++++\n 2 files changed, 29 insertions(+)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex bd250ca2164..dffc55ed8ee 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -1860,6 +1860,29 @@ static int check_name(int argc, const char **argv, const char *prefix)\n \treturn 0;\n }\n \n+static int connect_gitdir_workingtree(int argc, const char **argv, const char *prefix)\n+{\n+\tstruct strbuf sb = STRBUF_INIT;\n+\tconst char *name, *path;\n+\tchar *sm_gitdir;\n+\n+\tif (argc != 3)\n+\t\tBUG(\"submodule--helper connect-gitdir-workingtree <name> <path>\");\n+\n+\tname = argv[1];\n+\tpath = argv[2];\n+\n+\tstrbuf_addf(&sb, \"%s/modules/%s\", get_git_dir(), name);\n+\tsm_gitdir = absolute_pathdup(sb.buf);\n+\n+\tconnect_work_tree_and_git_dir(path, sm_gitdir, 0);\n+\n+\tstrbuf_release(&sb);\n+\tfree(sm_gitdir);\n+\n+\treturn 0;\n+}\n+\n #define SUPPORT_SUPER_PREFIX (1<<0)\n \n struct cmd_struct {\n@@ -1873,6 +1896,7 @@ static struct cmd_struct commands[] = {\n \t{\"name\", module_name, 0},\n \t{\"clone\", module_clone, 0},\n \t{\"update-clone\", update_clone, 0},\n+\t{\"connect-gitdir-workingtree\", connect_gitdir_workingtree, 0},\n \t{\"relative-path\", resolve_relative_path, 0},\n \t{\"resolve-relative-url\", resolve_relative_url, 0},\n \t{\"resolve-relative-url-test\", resolve_relative_url_test, 0},\ndiff --git a/git-submodule.sh b/git-submodule.sh\nindex 78073cd87d1..6bd0db02b33 100755\n--- a/git-submodule.sh\n+++ b/git-submodule.sh\n@@ -615,6 +615,11 @@ cmd_update()\n \t\t\tdie \"$(eval_gettext \"Unable to find current \\${remote_name}/\\${branch} revision in submodule path '\\$sm_path'\")\"\n \t\tfi\n \n+\t\tif ! $(git config -f \"$(git rev-parse --git-common-dir)/modules/$name/config\" core.worktree) 2>/dev/null\n+\t\tthen\n+\t\t\tgit submodule--helper connect-gitdir-workingtree \"$name\" \"$sm_path\"\n+\t\tfi\n+\n \t\tif test \"$subsha1\" != \"$sha1\" || test -n \"$force\"\n \t\tthen\n \t\t\tsubforce=$force\n-- \n2.18.0.rc1.244.gcf134e6275-goog\n\n"},{"id":"350448","messageId":"20180619000608.147422-4-sbeller@google.com","threadId":"48702","inReplyTo":"20180619000608.147422-1-sbeller@google.com","subject":"[PATCH 3/3] submodule deinit: unset core.worktree","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2018-06-19T00:06:08Z","receivedAt":"2018-06-19T00:06:30Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"When a submodule is deinit'd, the working tree is gone, so the setting of\ncore.worktree is bogus. Unset it.\n\nSigned-off-by: Stefan Beller <sbeller@google.com>\n---\n builtin/submodule--helper.c | 2 ++\n t/lib-submodule-update.sh   | 2 +-\n t/t7400-submodule-basic.sh  | 5 +++++\n 3 files changed, 8 insertions(+), 1 deletion(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex dffc55ed8ee..19480902681 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -980,6 +980,8 @@ static void deinit_submodule(const char *path, const char *prefix,\n \t\tif (!(flags & OPT_QUIET))\n \t\t\tprintf(format, displaypath);\n \n+\t\tsubmodule_unset_core_worktree(sub);\n+\n \t\tstrbuf_release(&sb_rm);\n \t}\n \ndiff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh\nindex 12cd4e9233e..aa5ac03325a 100755\n--- a/t/lib-submodule-update.sh\n+++ b/t/lib-submodule-update.sh\n@@ -235,7 +235,7 @@ reset_work_tree_to_interested () {\n \tthen\n \t\tmkdir -p submodule_update/.git/modules/sub1/modules &&\n \t\tcp -r submodule_update_repo/.git/modules/sub1/modules/sub2 submodule_update/.git/modules/sub1/modules/sub2\n-\t\tGIT_WORK_TREE=. git -C submodule_update/.git/modules/sub1/modules/sub2 config --unset core.worktree\n+\t\t# core.worktree is unset for sub2 as it is not checked out\n \tfi &&\n \t# indicate we are interested in the submodule:\n \tgit -C submodule_update config submodule.sub1.url \"bogus\" &&\ndiff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh\nindex 812db137b8d..48fd14fae6e 100755\n--- a/t/t7400-submodule-basic.sh\n+++ b/t/t7400-submodule-basic.sh\n@@ -993,6 +993,11 @@ test_expect_success 'submodule deinit should remove the whole submodule section\n \trmdir init\n '\n \n+test_expect_success 'submodule deinit should unset core.worktree' '\n+\ttest_path_is_file .git/modules/example/config &&\n+\ttest_must_fail git config -f .git/modules/example/config core.worktree\n+'\n+\n test_expect_success 'submodule deinit from subdirectory' '\n \tgit submodule update --init &&\n \tgit config submodule.example.foo bar &&\n-- \n2.18.0.rc1.244.gcf134e6275-goog\n\n"}]}