{"thread":{"id":"44690","subject":"[PATCH 0/6] git-rm absorbs submodule git directory before deletion","startedAt":"2016-12-13T01:41:12Z","lastAt":"2016-12-13T20:23:07Z","messageCount":21,"participants":["Stefan Beller","brian m. carlson","Junio C Hamano","David Turner"],"isPatch":true,"patchVersion":1,"patchTotal":6},"messages":[{"id":"307564","messageId":"20161213014055.14268-1-sbeller@google.com","threadId":"44690","inReplyTo":null,"subject":"[PATCH 0/6] git-rm absorbs submodule git directory before deletion","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2016-12-13T01:40:49Z","receivedAt":"2016-12-13T01:41:12Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"The \"checkout --recurse-submodules\" series got too large to comfortably send\nit out for review, so I had to break it up into smaller series'; this is the\nfirst subseries, but it makes sense on its own.\n\nThis series teaches git-rm to absorb the git directory of a submodule instead\nof failing and complaining about the git directory preventing deletion.\n \nIt applies on origin/sb/submodule-embed-gitdir.\n\nAny feedback welcome!\n\nThanks,\nStefan\n\nStefan Beller (6):\n  submodule.h: add extern keyword to functions\n  submodule: modernize ok_to_remove_submodule to use argv_array\n  submodule: add flags to ok_to_remove_submodule\n  ok_to_remove_submodule: absorb the submodule git dir\n  t3600: slightly modernize style\n  rm: add absorb a submodules git dir before deletion\n\n builtin/rm.c  |  21 +++-----\n cache.h       |   2 +\n entry.c       |   5 ++\n submodule.c   |  77 +++++++++++++++++++++++-----\n submodule.h   |  64 ++++++++++++++---------\n t/t3600-rm.sh | 159 +++++++++++++++++++++++----------------------------------\n 6 files changed, 182 insertions(+), 146 deletions(-)\n\n-- \n2.11.0.rc2.35.g7af3268\n\n"},{"id":"307565","messageId":"20161213014055.14268-3-sbeller@google.com","threadId":"44690","inReplyTo":"20161213014055.14268-1-sbeller@google.com","subject":"[PATCH 2/6] submodule: modernize ok_to_remove_submodule to use argv_array","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2016-12-13T01:40:51Z","receivedAt":"2016-12-13T01:41:15Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"Instead of constructing the NULL terminated array ourselves, we\nshould make use of the argv_array infrastructure.\n\nWhile at it, adapt the error messages to reflect the actual invocation.\n\nSigned-off-by: Stefan Beller <sbeller@google.com>\n---\n submodule.c | 14 ++++----------\n 1 file changed, 4 insertions(+), 10 deletions(-)\n\ndiff --git a/submodule.c b/submodule.c\nindex 45ccfb7ab4..9f0b544ebe 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -1023,13 +1023,6 @@ int ok_to_remove_submodule(const char *path)\n {\n \tssize_t len;\n \tstruct child_process cp = CHILD_PROCESS_INIT;\n-\tconst char *argv[] = {\n-\t\t\"status\",\n-\t\t\"--porcelain\",\n-\t\t\"-u\",\n-\t\t\"--ignore-submodules=none\",\n-\t\tNULL,\n-\t};\n \tstruct strbuf buf = STRBUF_INIT;\n \tint ok_to_remove = 1;\n \n@@ -1039,14 +1032,15 @@ int ok_to_remove_submodule(const char *path)\n \tif (!submodule_uses_gitfile(path))\n \t\treturn 0;\n \n-\tcp.argv = argv;\n+\targv_array_pushl(&cp.args, \"status\", \"--porcelain\", \"-u\",\n+\t\t\t\t   \"--ignore-submodules=none\", NULL);\n \tprepare_submodule_repo_env(&cp.env_array);\n \tcp.git_cmd = 1;\n \tcp.no_stdin = 1;\n \tcp.out = -1;\n \tcp.dir = path;\n \tif (start_command(&cp))\n-\t\tdie(\"Could not run 'git status --porcelain -uall --ignore-submodules=none' in submodule %s\", path);\n+\t\tdie(_(\"could not run 'git status --porcelain -u --ignore-submodules=none' in submodule %s\"), path);\n \n \tlen = strbuf_read(&buf, cp.out, 1024);\n \tif (len > 2)\n@@ -1054,7 +1048,7 @@ int ok_to_remove_submodule(const char *path)\n \tclose(cp.out);\n \n \tif (finish_command(&cp))\n-\t\tdie(\"'git status --porcelain -uall --ignore-submodules=none' failed in submodule %s\", path);\n+\t\tdie(_(\"'git status --porcelain -u --ignore-submodules=none' failed in submodule %s\"), path);\n \n \tstrbuf_release(&buf);\n \treturn ok_to_remove;\n-- \n2.11.0.rc2.35.g7af3268\n\n"},{"id":"307566","messageId":"20161213014055.14268-5-sbeller@google.com","threadId":"44690","inReplyTo":"20161213014055.14268-1-sbeller@google.com","subject":"[PATCH 4/6] ok_to_remove_submodule: absorb the submodule git dir","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2016-12-13T01:40:53Z","receivedAt":"2016-12-13T01:41:16Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"When deciding if a submodule can be deleted a major\nreason to say no is the git directory of the submodule\nbeing contained in the submodules working directory.\n\nInstead of failing migrate the git directory into the\nsuperproject and proceed with the other checks.\n\nSigned-off-by: Stefan Beller <sbeller@google.com>\n---\n submodule.c | 15 +++++++++++++--\n 1 file changed, 13 insertions(+), 2 deletions(-)\n\ndiff --git a/submodule.c b/submodule.c\nindex 2d13744b06..e42efa2337 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -1026,11 +1026,22 @@ int ok_to_remove_submodule(const char *path, unsigned flags)\n \tstruct strbuf buf = STRBUF_INIT;\n \tint ok_to_remove = 1;\n \n+\t/* Is it there? */\n \tif (!file_exists(path) || is_empty_dir(path))\n \t\treturn 1;\n \n-\tif (!submodule_uses_gitfile(path))\n-\t\treturn 0;\n+\t/* Does it have a .git directory? */\n+\tif (!submodule_uses_gitfile(path)) {\n+\t\tabsorb_git_dir_into_superproject(\"\", path,\n+\t\t\tABSORB_GITDIR_RECURSE_SUBMODULES);\n+\n+\t\t/*\n+\t\t * We should be using a gitfile by now. Let's double\n+\t\t * check as losing the git dir would be fatal.\n+\t\t */\n+\t\tif (!submodule_uses_gitfile(path))\n+\t\t\treturn 0;\n+\t}\n \n \targv_array_pushl(&cp.args, \"status\", \"--porcelain\",\n \t\t\t\t   \"--ignore-submodules=none\", NULL);\n-- \n2.11.0.rc2.35.g7af3268\n\n"},{"id":"307567","messageId":"20161213014055.14268-2-sbeller@google.com","threadId":"44690","inReplyTo":"20161213014055.14268-1-sbeller@google.com","subject":"[PATCH 1/6] submodule.h: add extern keyword to functions","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2016-12-13T01:40:50Z","receivedAt":"2016-12-13T01:41:26Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"As the upcoming series will add a lot of functions to the submodule\nheader, let's first make the header consistent to the rest of the project\nby adding the extern keyword to functions.\n\nAs per the CodingGuidelines we try to stay below 80 characters per line,\nso adapt all those functions to stay below 80 characters that are already\nusing more than one line.  Those function using just one line are better\nkept in one line than breaking them up into multiple lines just for the\ngoal of staying below the character limit as it makes grepping\nfor functions easier if they are one liners.\n\nSigned-off-by: Stefan Beller <sbeller@google.com>\n---\n submodule.h | 55 ++++++++++++++++++++++++++++++-------------------------\n 1 file changed, 30 insertions(+), 25 deletions(-)\n\ndiff --git a/submodule.h b/submodule.h\nindex 6229054b99..61fb610749 100644\n--- a/submodule.h\n+++ b/submodule.h\n@@ -29,50 +29,55 @@ struct submodule_update_strategy {\n };\n #define SUBMODULE_UPDATE_STRATEGY_INIT {SM_UPDATE_UNSPECIFIED, NULL}\n \n-int is_staging_gitmodules_ok(void);\n-int update_path_in_gitmodules(const char *oldpath, const char *newpath);\n-int remove_path_from_gitmodules(const char *path);\n-void stage_updated_gitmodules(void);\n-void set_diffopt_flags_from_submodule_config(struct diff_options *diffopt,\n+extern int is_staging_gitmodules_ok(void);\n+extern int update_path_in_gitmodules(const char *oldpath, const char *newpath);\n+extern int remove_path_from_gitmodules(const char *path);\n+extern void stage_updated_gitmodules(void);\n+extern void set_diffopt_flags_from_submodule_config(struct diff_options *,\n \t\tconst char *path);\n-int submodule_config(const char *var, const char *value, void *cb);\n-void gitmodules_config(void);\n-int parse_submodule_update_strategy(const char *value,\n+extern int submodule_config(const char *var, const char *value, void *cb);\n+extern void gitmodules_config(void);\n+extern int parse_submodule_update_strategy(const char *value,\n \t\tstruct submodule_update_strategy *dst);\n-const char *submodule_strategy_to_string(const struct submodule_update_strategy *s);\n-void handle_ignore_submodules_arg(struct diff_options *diffopt, const char *);\n-void show_submodule_summary(FILE *f, const char *path,\n+extern const char *submodule_strategy_to_string(const struct submodule_update_strategy *s);\n+extern void handle_ignore_submodules_arg(struct diff_options *, const char *);\n+extern void show_submodule_summary(FILE *f, const char *path,\n \t\tconst char *line_prefix,\n \t\tstruct object_id *one, struct object_id *two,\n \t\tunsigned dirty_submodule, const char *meta,\n \t\tconst char *del, const char *add, const char *reset);\n-void show_submodule_inline_diff(FILE *f, const char *path,\n+extern void show_submodule_inline_diff(FILE *f, const char *path,\n \t\tconst char *line_prefix,\n \t\tstruct object_id *one, struct object_id *two,\n \t\tunsigned dirty_submodule, const char *meta,\n \t\tconst char *del, const char *add, const char *reset,\n \t\tconst struct diff_options *opt);\n-void set_config_fetch_recurse_submodules(int value);\n-void check_for_new_submodule_commits(unsigned char new_sha1[20]);\n-int fetch_populated_submodules(const struct argv_array *options,\n+extern void set_config_fetch_recurse_submodules(int value);\n+extern void check_for_new_submodule_commits(unsigned char new_sha1[20]);\n+extern int fetch_populated_submodules(const struct argv_array *options,\n \t\t\t       const char *prefix, int command_line_option,\n \t\t\t       int quiet, int max_parallel_jobs);\n-unsigned is_submodule_modified(const char *path, int ignore_untracked);\n-int submodule_uses_gitfile(const char *path);\n-int ok_to_remove_submodule(const char *path);\n-int merge_submodule(unsigned char result[20], const char *path, const unsigned char base[20],\n-\t\t    const unsigned char a[20], const unsigned char b[20], int search);\n-int find_unpushed_submodules(unsigned char new_sha1[20], const char *remotes_name,\n-\t\tstruct string_list *needs_pushing);\n-int push_unpushed_submodules(unsigned char new_sha1[20], const char *remotes_name);\n-int parallel_submodules(void);\n+extern unsigned is_submodule_modified(const char *path, int ignore_untracked);\n+extern int submodule_uses_gitfile(const char *path);\n+extern int ok_to_remove_submodule(const char *path);\n+extern int merge_submodule(unsigned char result[20], const char *path,\n+\t\t\t   const unsigned char base[20],\n+\t\t\t   const unsigned char a[20],\n+\t\t\t   const unsigned char b[20], int search);\n+extern int find_unpushed_submodules(unsigned char new_sha1[20],\n+\t\t\t\t    const char *remotes_name,\n+\t\t\t\t    struct string_list *needs_pushing);\n+extern int push_unpushed_submodules(unsigned char new_sha1[20],\n+\t\t\t\t    const char *remotes_name);\n+extern void connect_work_tree_and_git_dir(const char *work_tree, const char *git_dir);\n+extern int parallel_submodules(void);\n \n /*\n  * Prepare the \"env_array\" parameter of a \"struct child_process\" for executing\n  * a submodule by clearing any repo-specific envirionment variables, but\n  * retaining any config in the environment.\n  */\n-void prepare_submodule_repo_env(struct argv_array *out);\n+extern void prepare_submodule_repo_env(struct argv_array *out);\n \n #define ABSORB_GITDIR_RECURSE_SUBMODULES (1<<0)\n extern void absorb_git_dir_into_superproject(const char *prefix,\n-- \n2.11.0.rc2.35.g7af3268\n\n"},{"id":"307568","messageId":"20161213014055.14268-4-sbeller@google.com","threadId":"44690","inReplyTo":"20161213014055.14268-1-sbeller@google.com","subject":"[PATCH 3/6] submodule: add flags to ok_to_remove_submodule","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2016-12-13T01:40:52Z","receivedAt":"2016-12-13T01:41:29Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"In different contexts the question whether deleting a submodule is ok\nto remove may be answered differently.\n\nIn 293ab15eea (submodule: teach rm to remove submodules unless they\ncontain a git directory, 2012-09-26) a case was made that we can safely\nignore ignored untracked files for removal as we explicitely ask for the\nremoval of the submodule.\n\nIn a later patch we want to remove submodules even when the user doesn't\nexplicitly ask for it (e.g. checking out a tree-ish in which the submodule\ndoesn't exist).  In that case we want to be more careful when it comes\nto deletion of untracked files. As of this patch it is unclear how this\nwill be implemented exactly, so we'll offer flags in which the caller\ncan specify how the different untracked files ought to be handled.\n\nSigned-off-by: Stefan Beller <sbeller@google.com>\n---\n builtin/rm.c |  3 ++-\n submodule.c  | 23 +++++++++++++++++++----\n submodule.h  |  5 ++++-\n 3 files changed, 25 insertions(+), 6 deletions(-)\n\ndiff --git a/builtin/rm.c b/builtin/rm.c\nindex 3f3e24eb36..fdd7183f61 100644\n--- a/builtin/rm.c\n+++ b/builtin/rm.c\n@@ -187,7 +187,8 @@ static int check_local_mod(struct object_id *head, int index_only)\n \t\t */\n \t\tif (ce_match_stat(ce, &st, 0) ||\n \t\t    (S_ISGITLINK(ce->ce_mode) &&\n-\t\t     !ok_to_remove_submodule(ce->name)))\n+\t\t     !ok_to_remove_submodule(ce->name,\n+\t\t\t\tSUBMODULE_REMOVAL_IGNORE_IGNORED_UNTRACKED)))\n \t\t\tlocal_changes = 1;\n \n \t\t/*\ndiff --git a/submodule.c b/submodule.c\nindex 9f0b544ebe..2d13744b06 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -1019,7 +1019,7 @@ int submodule_uses_gitfile(const char *path)\n \treturn 1;\n }\n \n-int ok_to_remove_submodule(const char *path)\n+int ok_to_remove_submodule(const char *path, unsigned flags)\n {\n \tssize_t len;\n \tstruct child_process cp = CHILD_PROCESS_INIT;\n@@ -1032,15 +1032,27 @@ int ok_to_remove_submodule(const char *path)\n \tif (!submodule_uses_gitfile(path))\n \t\treturn 0;\n \n-\targv_array_pushl(&cp.args, \"status\", \"--porcelain\", \"-u\",\n+\targv_array_pushl(&cp.args, \"status\", \"--porcelain\",\n \t\t\t\t   \"--ignore-submodules=none\", NULL);\n+\n+\tif (flags & SUBMODULE_REMOVAL_IGNORE_UNTRACKED)\n+\t\targv_array_push(&cp.args, \"-uno\");\n+\telse\n+\t\targv_array_push(&cp.args, \"-uall\");\n+\n+\tif (!(flags & SUBMODULE_REMOVAL_IGNORE_IGNORED_UNTRACKED))\n+\t\targv_array_push(&cp.args, \"--ignored\");\n+\n \tprepare_submodule_repo_env(&cp.env_array);\n \tcp.git_cmd = 1;\n \tcp.no_stdin = 1;\n \tcp.out = -1;\n \tcp.dir = path;\n \tif (start_command(&cp))\n-\t\tdie(_(\"could not run 'git status --porcelain -u --ignore-submodules=none' in submodule %s\"), path);\n+\t\tdie(_(\"could not run 'git status --porcelain --ignore-submodules=none %s %s' in submodule '%s'\"),\n+\t\t\t(flags & SUBMODULE_REMOVAL_IGNORE_UNTRACKED) ? \"-uno\" : \"-uall\",\n+\t\t\t(!(flags & SUBMODULE_REMOVAL_IGNORE_IGNORED_UNTRACKED)) ? \"--ignored\" : \"\",\n+\t\t\tpath);\n \n \tlen = strbuf_read(&buf, cp.out, 1024);\n \tif (len > 2)\n@@ -1048,7 +1060,10 @@ int ok_to_remove_submodule(const char *path)\n \tclose(cp.out);\n \n \tif (finish_command(&cp))\n-\t\tdie(_(\"'git status --porcelain -u --ignore-submodules=none' failed in submodule %s\"), path);\n+\t\tdie(_(\"'git status --porcelain --ignore-submodules=none %s %s' failed in submodule '%s'\"),\n+\t\t\t(flags & SUBMODULE_REMOVAL_IGNORE_UNTRACKED) ? \"-uno\" : \"-uall\",\n+\t\t\t(!(flags & SUBMODULE_REMOVAL_IGNORE_IGNORED_UNTRACKED)) ? \"--ignored\" : \"\",\n+\t\t\tpath);\n \n \tstrbuf_release(&buf);\n \treturn ok_to_remove;\ndiff --git a/submodule.h b/submodule.h\nindex 61fb610749..3ed3aa479a 100644\n--- a/submodule.h\n+++ b/submodule.h\n@@ -59,7 +59,10 @@ extern int fetch_populated_submodules(const struct argv_array *options,\n \t\t\t       int quiet, int max_parallel_jobs);\n extern unsigned is_submodule_modified(const char *path, int ignore_untracked);\n extern int submodule_uses_gitfile(const char *path);\n-extern int ok_to_remove_submodule(const char *path);\n+\n+#define SUBMODULE_REMOVAL_IGNORE_UNTRACKED (1<<0)\n+#define SUBMODULE_REMOVAL_IGNORE_IGNORED_UNTRACKED (1<<1)\n+extern int ok_to_remove_submodule(const char *path, unsigned flags);\n extern int merge_submodule(unsigned char result[20], const char *path,\n \t\t\t   const unsigned char base[20],\n \t\t\t   const unsigned char a[20],\n-- \n2.11.0.rc2.35.g7af3268\n\n"},{"id":"307569","messageId":"20161213014055.14268-7-sbeller@google.com","threadId":"44690","inReplyTo":"20161213014055.14268-1-sbeller@google.com","subject":"[PATCH 6/6] rm: add absorb a submodules git dir before deletion","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2016-12-13T01:40:55Z","receivedAt":"2016-12-13T01:41:30Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"When deleting a submodule we need to keep the actual git directory around,\nsuch that we do not lose local changes in there and at a later checkout\nof the submodule we don't need to clone it again.\n\nImplement `depopulate_submodule`, that migrates the git directory before\ndeletion of a submodule and afterwards the equivalent of \"rm -rf\", which\nis already found in entry.c, so expose that and for clarity add a suffix\n\"_or_dir\" to it.\n\nSigned-off-by: Stefan Beller <sbeller@google.com>\n---\n builtin/rm.c  | 18 ++++++------------\n cache.h       |  2 ++\n entry.c       |  5 +++++\n submodule.c   | 31 +++++++++++++++++++++++++++++++\n submodule.h   |  6 ++++++\n t/t3600-rm.sh | 41 ++++++++++++++++-------------------------\n 6 files changed, 66 insertions(+), 37 deletions(-)\n\ndiff --git a/builtin/rm.c b/builtin/rm.c\nindex fdd7183f61..f8c5e9b6c6 100644\n--- a/builtin/rm.c\n+++ b/builtin/rm.c\n@@ -400,18 +400,12 @@ int cmd_rm(int argc, const char **argv, const char *prefix)\n \t\t\t\t\t\tcontinue;\n \t\t\t\t\t}\n \t\t\t\t} else {\n-\t\t\t\t\tstrbuf_reset(&buf);\n-\t\t\t\t\tstrbuf_addstr(&buf, path);\n-\t\t\t\t\tif (!remove_dir_recursively(&buf, 0)) {\n-\t\t\t\t\t\tremoved = 1;\n-\t\t\t\t\t\tif (!remove_path_from_gitmodules(path))\n-\t\t\t\t\t\t\tgitmodules_modified = 1;\n-\t\t\t\t\t\tstrbuf_release(&buf);\n-\t\t\t\t\t\tcontinue;\n-\t\t\t\t\t} else if (!file_exists(path))\n-\t\t\t\t\t\t/* Submodule was removed by user */\n-\t\t\t\t\t\tif (!remove_path_from_gitmodules(path))\n-\t\t\t\t\t\t\tgitmodules_modified = 1;\n+\t\t\t\t\tif (file_exists(path))\n+\t\t\t\t\t\tdepopulate_submodule(path);\n+\t\t\t\t\tremoved = 1;\n+\t\t\t\t\tif (!remove_path_from_gitmodules(path))\n+\t\t\t\t\t\tgitmodules_modified = 1;\n+\t\t\t\t\tcontinue;\n \t\t\t\t\t/* Fallthrough and let remove_path() fail. */\n \t\t\t\t}\n \t\t\t}\ndiff --git a/cache.h b/cache.h\nindex a50a61a197..b645ca2f9a 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -2018,4 +2018,6 @@ void sleep_millisec(int millisec);\n  */\n void safe_create_dir(const char *dir, int share);\n \n+extern void remove_directory_or_die(struct strbuf *path);\n+\n #endif /* CACHE_H */\ndiff --git a/entry.c b/entry.c\nindex c6eea240b6..02c4ac9f22 100644\n--- a/entry.c\n+++ b/entry.c\n@@ -73,6 +73,11 @@ static void remove_subtree(struct strbuf *path)\n \t\tdie_errno(\"cannot rmdir '%s'\", path->buf);\n }\n \n+void remove_directory_or_die(struct strbuf *path)\n+{\n+\tremove_subtree(path);\n+}\n+\n static int create_file(const char *path, unsigned int mode)\n {\n \tmode = (mode & 0100) ? 0777 : 0666;\ndiff --git a/submodule.c b/submodule.c\nindex e42efa2337..3770ecb7b9 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -308,6 +308,37 @@ static void print_submodule_summary(struct rev_info *rev, FILE *f,\n \tstrbuf_release(&sb);\n }\n \n+void depopulate_submodule(const char *path)\n+{\n+\tstruct strbuf pathbuf = STRBUF_INIT;\n+\tchar *dot_git = xstrfmt(\"%s/.git\", path);\n+\n+\t/* Is it populated? */\n+\tif (!resolve_gitdir(dot_git))\n+\t\tgoto out;\n+\n+\t/* Does it have a .git directory? */\n+\tif (!submodule_uses_gitfile(path)) {\n+\t\tabsorb_git_dir_into_superproject(\"\", path,\n+\t\t\tABSORB_GITDIR_RECURSE_SUBMODULES);\n+\n+\t\tif (!submodule_uses_gitfile(path)) {\n+\t\t\t/*\n+\t\t\t * We should be using a gitfile by now. Let's double\n+\t\t\t * check as losing the git dir would be fatal.\n+\t\t\t */\n+\t\t\tdie(\"BUG: could not absorb git directory for '%s'\", path);\n+\t\t}\n+\t}\n+\n+\tstrbuf_addstr(&pathbuf, path);\n+\tremove_directory_or_die(&pathbuf);\n+\n+out:\n+\tstrbuf_release(&pathbuf);\n+\tfree(dot_git);\n+}\n+\n /* Helper function to display the submodule header line prior to the full\n  * summary output. If it can locate the submodule objects directory it will\n  * attempt to lookup both the left and right commits and put them into the\ndiff --git a/submodule.h b/submodule.h\nindex 3ed3aa479a..516e377a12 100644\n--- a/submodule.h\n+++ b/submodule.h\n@@ -53,6 +53,12 @@ extern void show_submodule_inline_diff(FILE *f, const char *path,\n \t\tconst char *del, const char *add, const char *reset,\n \t\tconst struct diff_options *opt);\n extern void set_config_fetch_recurse_submodules(int value);\n+\n+/*\n+ * Removes a submodule from a given path. When the submodule contains its\n+ * git directory instead of a gitlink, migrate that first into the superproject.\n+ */\n+extern void depopulate_submodule(const char *path);\n extern void check_for_new_submodule_commits(unsigned char new_sha1[20]);\n extern int fetch_populated_submodules(const struct argv_array *options,\n \t\t\t       const char *prefix, int command_line_option,\ndiff --git a/t/t3600-rm.sh b/t/t3600-rm.sh\nindex 5e5a16c863..5aa6db584c 100755\n--- a/t/t3600-rm.sh\n+++ b/t/t3600-rm.sh\n@@ -569,26 +569,22 @@ test_expect_success 'rm of a conflicted unpopulated submodule succeeds' '\n \ttest_cmp expect actual\n '\n \n-test_expect_success 'rm of a populated submodule with a .git directory fails even when forced' '\n+test_expect_success 'rm of a populated submodule with a .git directory migrates git dir' '\n \tgit checkout -f master &&\n \tgit reset --hard &&\n \tgit submodule update &&\n \t(cd submod &&\n \t\trm .git &&\n \t\tcp -R ../.git/modules/sub .git &&\n-\t\tGIT_WORK_TREE=. git config --unset core.worktree\n+\t\tGIT_WORK_TREE=. git config --unset core.worktree &&\n+\t\trm -r ../.git/modules/sub\n \t) &&\n-\ttest_must_fail git rm submod &&\n-\ttest -d submod &&\n-\ttest -d submod/.git &&\n-\tgit status -s -uno --ignore-submodules=none >actual &&\n-\t! test -s actual &&\n-\ttest_must_fail git rm -f submod &&\n-\ttest -d submod &&\n-\ttest -d submod/.git &&\n+\tgit rm submod 2>output.err &&\n+\t! test -d submod &&\n+\t! test -d submod/.git &&\n \tgit status -s -uno --ignore-submodules=none >actual &&\n-\t! test -s actual &&\n-\trm -rf submod\n+\ttest -s actual &&\n+\ttest_i18ngrep Migrating output.err\n '\n \n cat >expect.deepmodified <<EOF\n@@ -667,27 +663,22 @@ test_expect_success 'rm of a populated nested submodule with a nested .git direc\n \tgit submodule update --recursive &&\n \t(cd submod/subsubmod &&\n \t\trm .git &&\n-\t\tcp -R ../../.git/modules/sub/modules/sub .git &&\n+\t\tmv ../../.git/modules/sub/modules/sub .git &&\n \t\tGIT_WORK_TREE=. git config --unset core.worktree\n \t) &&\n-\ttest_must_fail git rm submod &&\n-\ttest -d submod &&\n-\ttest -d submod/subsubmod/.git &&\n-\tgit status -s -uno --ignore-submodules=none >actual &&\n-\t! test -s actual &&\n-\ttest_must_fail git rm -f submod &&\n-\ttest -d submod &&\n-\ttest -d submod/subsubmod/.git &&\n+\tgit rm submod 2>output.err &&\n+\t! test -d submod &&\n+\t! test -d submod/subsubmod/.git &&\n \tgit status -s -uno --ignore-submodules=none >actual &&\n-\t! test -s actual &&\n-\trm -rf submod\n+\ttest -s actual &&\n+\ttest_i18ngrep Migrating output.err\n '\n \n test_expect_success 'checking out a commit after submodule removal needs manual updates' '\n-\tgit commit -m \"submodule removal\" submod &&\n+\tgit commit -m \"submodule removal\" submod .gitmodules &&\n \tgit checkout HEAD^ &&\n \tgit submodule update &&\n-\tgit checkout -q HEAD^ 2>actual &&\n+\tgit checkout -q HEAD^ &&\n \tgit checkout -q master 2>actual &&\n \ttest_i18ngrep \"^warning: unable to rmdir submod:\" actual &&\n \tgit status -s submod >actual &&\n-- \n2.11.0.rc2.35.g7af3268\n\n"},{"id":"307570","messageId":"20161213014055.14268-6-sbeller@google.com","threadId":"44690","inReplyTo":"20161213014055.14268-1-sbeller@google.com","subject":"[PATCH 5/6] t3600: slightly modernize style","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2016-12-13T01:40:54Z","receivedAt":"2016-12-13T01:41:32Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"Remove the space between redirection and file name.\nAlso remove unnecessary invocations of subshells, such as\n\n\t(cd submod &&\n\t\techo X >untracked\n\t) &&\n\nas there is no point of having the shell for functional purposes.\nIn case of a single Git command use the `-C` option to let Git cd into\nthe directory.\n\nSigned-off-by: Stefan Beller <sbeller@google.com>\n---\n t/t3600-rm.sh | 122 ++++++++++++++++++++++++----------------------------------\n 1 file changed, 50 insertions(+), 72 deletions(-)\n\ndiff --git a/t/t3600-rm.sh b/t/t3600-rm.sh\nindex 14f0edca2b..5e5a16c863 100755\n--- a/t/t3600-rm.sh\n+++ b/t/t3600-rm.sh\n@@ -111,21 +111,21 @@ test_expect_success 'Remove nonexistent file with --ignore-unmatch' '\n '\n \n test_expect_success '\"rm\" command printed' '\n-\techo frotz > test-file &&\n+\techo frotz >test-file &&\n \tgit add test-file &&\n \tgit commit -m \"add file for rm test\" &&\n-\tgit rm test-file > rm-output &&\n+\tgit rm test-file >rm-output &&\n \ttest $(grep \"^rm \" rm-output | wc -l) = 1 &&\n \trm -f test-file rm-output &&\n \tgit commit -m \"remove file from rm test\"\n '\n \n test_expect_success '\"rm\" command suppressed with --quiet' '\n-\techo frotz > test-file &&\n+\techo frotz >test-file &&\n \tgit add test-file &&\n \tgit commit -m \"add file for rm --quiet test\" &&\n-\tgit rm --quiet test-file > rm-output &&\n-\ttest $(wc -l < rm-output) = 0 &&\n+\tgit rm --quiet test-file >rm-output &&\n+\ttest_must_be_empty rm-output &&\n \trm -f test-file rm-output &&\n \tgit commit -m \"remove file from rm --quiet test\"\n '\n@@ -221,7 +221,7 @@ test_expect_success 'Call \"rm\" from outside the work tree' '\n \tmkdir repo &&\n \t(cd repo &&\n \t git init &&\n-\t echo something > somefile &&\n+\t echo something >somefile &&\n \t git add somefile &&\n \t git commit -m \"add a file\" &&\n \t (cd .. &&\n@@ -287,7 +287,7 @@ test_expect_success 'rm removes empty submodules from work tree' '\n \tgit commit -m \"add submodule\" &&\n \tgit rm submod &&\n \ttest ! -e submod &&\n-\tgit status -s -uno --ignore-submodules=none > actual &&\n+\tgit status -s -uno --ignore-submodules=none >actual &&\n \ttest_cmp expect actual &&\n \ttest_must_fail git config -f .gitmodules submodule.sub.url &&\n \ttest_must_fail git config -f .gitmodules submodule.sub.path\n@@ -298,7 +298,7 @@ test_expect_success 'rm removes removed submodule from index and .gitmodules' '\n \tgit submodule update &&\n \trm -rf submod &&\n \tgit rm submod &&\n-\tgit status -s -uno --ignore-submodules=none > actual &&\n+\tgit status -s -uno --ignore-submodules=none >actual &&\n \ttest_cmp expect actual &&\n \ttest_must_fail git config -f .gitmodules submodule.sub.url &&\n \ttest_must_fail git config -f .gitmodules submodule.sub.path\n@@ -309,7 +309,7 @@ test_expect_success 'rm removes work tree of unmodified submodules' '\n \tgit submodule update &&\n \tgit rm submod &&\n \ttest ! -d submod &&\n-\tgit status -s -uno --ignore-submodules=none > actual &&\n+\tgit status -s -uno --ignore-submodules=none >actual &&\n \ttest_cmp expect actual &&\n \ttest_must_fail git config -f .gitmodules submodule.sub.url &&\n \ttest_must_fail git config -f .gitmodules submodule.sub.path\n@@ -320,7 +320,7 @@ test_expect_success 'rm removes a submodule with a trailing /' '\n \tgit submodule update &&\n \tgit rm submod/ &&\n \ttest ! -d submod &&\n-\tgit status -s -uno --ignore-submodules=none > actual &&\n+\tgit status -s -uno --ignore-submodules=none >actual &&\n \ttest_cmp expect actual\n '\n \n@@ -335,17 +335,15 @@ test_expect_success 'rm succeeds when given a directory with a trailing /' '\n test_expect_success 'rm of a populated submodule with different HEAD fails unless forced' '\n \tgit reset --hard &&\n \tgit submodule update &&\n-\t(cd submod &&\n-\t\tgit checkout HEAD^\n-\t) &&\n+\tgit -C submod checkout HEAD^ &&\n \ttest_must_fail git rm submod &&\n \ttest -d submod &&\n \ttest -f submod/.git &&\n-\tgit status -s -uno --ignore-submodules=none > actual &&\n+\tgit status -s -uno --ignore-submodules=none >actual &&\n \ttest_cmp expect.modified actual &&\n \tgit rm -f submod &&\n \ttest ! -d submod &&\n-\tgit status -s -uno --ignore-submodules=none > actual &&\n+\tgit status -s -uno --ignore-submodules=none >actual &&\n \ttest_cmp expect actual &&\n \ttest_must_fail git config -f .gitmodules submodule.sub.url &&\n \ttest_must_fail git config -f .gitmodules submodule.sub.path\n@@ -418,34 +416,30 @@ test_expect_success 'rm issues a warning when section is not found in .gitmodule\n test_expect_success 'rm of a populated submodule with modifications fails unless forced' '\n \tgit reset --hard &&\n \tgit submodule update &&\n-\t(cd submod &&\n-\t\techo X >empty\n-\t) &&\n+\techo X >submod/empty &&\n \ttest_must_fail git rm submod &&\n \ttest -d submod &&\n \ttest -f submod/.git &&\n-\tgit status -s -uno --ignore-submodules=none > actual &&\n+\tgit status -s -uno --ignore-submodules=none >actual &&\n \ttest_cmp expect.modified actual &&\n \tgit rm -f submod &&\n \ttest ! -d submod &&\n-\tgit status -s -uno --ignore-submodules=none > actual &&\n+\tgit status -s -uno --ignore-submodules=none >actual &&\n \ttest_cmp expect actual\n '\n \n test_expect_success 'rm of a populated submodule with untracked files fails unless forced' '\n \tgit reset --hard &&\n \tgit submodule update &&\n-\t(cd submod &&\n-\t\techo X >untracked\n-\t) &&\n+\techo X >submod/untracked &&\n \ttest_must_fail git rm submod &&\n \ttest -d submod &&\n \ttest -f submod/.git &&\n-\tgit status -s -uno --ignore-submodules=none > actual &&\n+\tgit status -s -uno --ignore-submodules=none >actual &&\n \ttest_cmp expect.modified actual &&\n \tgit rm -f submod &&\n \ttest ! -d submod &&\n-\tgit status -s -uno --ignore-submodules=none > actual &&\n+\tgit status -s -uno --ignore-submodules=none >actual &&\n \ttest_cmp expect actual\n '\n \n@@ -461,16 +455,12 @@ test_expect_success 'setup submodule conflict' '\n \tgit add nitfol &&\n \tgit commit -m \"added nitfol 2\" &&\n \tgit checkout -b conflict1 master &&\n-\t(cd submod &&\n-\t\tgit fetch &&\n-\t\tgit checkout branch1\n-\t) &&\n+\tgit -C submod fetch &&\n+\tgit -C submod checkout branch1 &&\n \tgit add submod &&\n \tgit commit -m \"submod 1\" &&\n \tgit checkout -b conflict2 master &&\n-\t(cd submod &&\n-\t\tgit checkout branch2\n-\t) &&\n+\tgit -C submod checkout branch2 &&\n \tgit add submod &&\n \tgit commit -m \"submod 2\"\n '\n@@ -486,7 +476,7 @@ test_expect_success 'rm removes work tree of unmodified conflicted submodule' '\n \ttest_must_fail git merge conflict2 &&\n \tgit rm submod &&\n \ttest ! -d submod &&\n-\tgit status -s -uno --ignore-submodules=none > actual &&\n+\tgit status -s -uno --ignore-submodules=none >actual &&\n \ttest_cmp expect actual\n '\n \n@@ -494,18 +484,16 @@ test_expect_success 'rm of a conflicted populated submodule with different HEAD\n \tgit checkout conflict1 &&\n \tgit reset --hard &&\n \tgit submodule update &&\n-\t(cd submod &&\n-\t\tgit checkout HEAD^\n-\t) &&\n+\tgit -C submod checkout HEAD^ &&\n \ttest_must_fail git merge conflict2 &&\n \ttest_must_fail git rm submod &&\n \ttest -d submod &&\n \ttest -f submod/.git &&\n-\tgit status -s -uno --ignore-submodules=none > actual &&\n+\tgit status -s -uno --ignore-submodules=none >actual &&\n \ttest_cmp expect.conflict actual &&\n \tgit rm -f submod &&\n \ttest ! -d submod &&\n-\tgit status -s -uno --ignore-submodules=none > actual &&\n+\tgit status -s -uno --ignore-submodules=none >actual &&\n \ttest_cmp expect actual &&\n \ttest_must_fail git config -f .gitmodules submodule.sub.url &&\n \ttest_must_fail git config -f .gitmodules submodule.sub.path\n@@ -515,18 +503,16 @@ test_expect_success 'rm of a conflicted populated submodule with modifications f\n \tgit checkout conflict1 &&\n \tgit reset --hard &&\n \tgit submodule update &&\n-\t(cd submod &&\n-\t\techo X >empty\n-\t) &&\n+\techo X >submod/empty &&\n \ttest_must_fail git merge conflict2 &&\n \ttest_must_fail git rm submod &&\n \ttest -d submod &&\n \ttest -f submod/.git &&\n-\tgit status -s -uno --ignore-submodules=none > actual &&\n+\tgit status -s -uno --ignore-submodules=none >actual &&\n \ttest_cmp expect.conflict actual &&\n \tgit rm -f submod &&\n \ttest ! -d submod &&\n-\tgit status -s -uno --ignore-submodules=none > actual &&\n+\tgit status -s -uno --ignore-submodules=none >actual &&\n \ttest_cmp expect actual &&\n \ttest_must_fail git config -f .gitmodules submodule.sub.url &&\n \ttest_must_fail git config -f .gitmodules submodule.sub.path\n@@ -536,18 +522,16 @@ test_expect_success 'rm of a conflicted populated submodule with untracked files\n \tgit checkout conflict1 &&\n \tgit reset --hard &&\n \tgit submodule update &&\n-\t(cd submod &&\n-\t\techo X >untracked\n-\t) &&\n+\techo X >submod/untracked &&\n \ttest_must_fail git merge conflict2 &&\n \ttest_must_fail git rm submod &&\n \ttest -d submod &&\n \ttest -f submod/.git &&\n-\tgit status -s -uno --ignore-submodules=none > actual &&\n+\tgit status -s -uno --ignore-submodules=none >actual &&\n \ttest_cmp expect.conflict actual &&\n \tgit rm -f submod &&\n \ttest ! -d submod &&\n-\tgit status -s -uno --ignore-submodules=none > actual &&\n+\tgit status -s -uno --ignore-submodules=none >actual &&\n \ttest_cmp expect actual\n '\n \n@@ -564,12 +548,12 @@ test_expect_success 'rm of a conflicted populated submodule with a .git director\n \ttest_must_fail git rm submod &&\n \ttest -d submod &&\n \ttest -d submod/.git &&\n-\tgit status -s -uno --ignore-submodules=none > actual &&\n+\tgit status -s -uno --ignore-submodules=none >actual &&\n \ttest_cmp expect.conflict actual &&\n \ttest_must_fail git rm -f submod &&\n \ttest -d submod &&\n \ttest -d submod/.git &&\n-\tgit status -s -uno --ignore-submodules=none > actual &&\n+\tgit status -s -uno --ignore-submodules=none >actual &&\n \ttest_cmp expect.conflict actual &&\n \tgit merge --abort &&\n \trm -rf submod\n@@ -581,7 +565,7 @@ test_expect_success 'rm of a conflicted unpopulated submodule succeeds' '\n \ttest_must_fail git merge conflict2 &&\n \tgit rm submod &&\n \ttest ! -d submod &&\n-\tgit status -s -uno --ignore-submodules=none > actual &&\n+\tgit status -s -uno --ignore-submodules=none >actual &&\n \ttest_cmp expect actual\n '\n \n@@ -597,12 +581,12 @@ test_expect_success 'rm of a populated submodule with a .git directory fails eve\n \ttest_must_fail git rm submod &&\n \ttest -d submod &&\n \ttest -d submod/.git &&\n-\tgit status -s -uno --ignore-submodules=none > actual &&\n+\tgit status -s -uno --ignore-submodules=none >actual &&\n \t! test -s actual &&\n \ttest_must_fail git rm -f submod &&\n \ttest -d submod &&\n \ttest -d submod/.git &&\n-\tgit status -s -uno --ignore-submodules=none > actual &&\n+\tgit status -s -uno --ignore-submodules=none >actual &&\n \t! test -s actual &&\n \trm -rf submod\n '\n@@ -629,58 +613,52 @@ test_expect_success 'setup subsubmodule' '\n test_expect_success 'rm recursively removes work tree of unmodified submodules' '\n \tgit rm submod &&\n \ttest ! -d submod &&\n-\tgit status -s -uno --ignore-submodules=none > actual &&\n+\tgit status -s -uno --ignore-submodules=none >actual &&\n \ttest_cmp expect actual\n '\n \n test_expect_success 'rm of a populated nested submodule with different nested HEAD fails unless forced' '\n \tgit reset --hard &&\n \tgit submodule update --recursive &&\n-\t(cd submod/subsubmod &&\n-\t\tgit checkout HEAD^\n-\t) &&\n+\tgit -C submod/subsubmod checkout HEAD^ &&\n \ttest_must_fail git rm submod &&\n \ttest -d submod &&\n \ttest -f submod/.git &&\n-\tgit status -s -uno --ignore-submodules=none > actual &&\n+\tgit status -s -uno --ignore-submodules=none >actual &&\n \ttest_cmp expect.modified actual &&\n \tgit rm -f submod &&\n \ttest ! -d submod &&\n-\tgit status -s -uno --ignore-submodules=none > actual &&\n+\tgit status -s -uno --ignore-submodules=none >actual &&\n \ttest_cmp expect actual\n '\n \n test_expect_success 'rm of a populated nested submodule with nested modifications fails unless forced' '\n \tgit reset --hard &&\n \tgit submodule update --recursive &&\n-\t(cd submod/subsubmod &&\n-\t\techo X >empty\n-\t) &&\n+\techo X >submod/subsubmod/empty &&\n \ttest_must_fail git rm submod &&\n \ttest -d submod &&\n \ttest -f submod/.git &&\n-\tgit status -s -uno --ignore-submodules=none > actual &&\n+\tgit status -s -uno --ignore-submodules=none >actual &&\n \ttest_cmp expect.modified actual &&\n \tgit rm -f submod &&\n \ttest ! -d submod &&\n-\tgit status -s -uno --ignore-submodules=none > actual &&\n+\tgit status -s -uno --ignore-submodules=none >actual &&\n \ttest_cmp expect actual\n '\n \n test_expect_success 'rm of a populated nested submodule with nested untracked files fails unless forced' '\n \tgit reset --hard &&\n \tgit submodule update --recursive &&\n-\t(cd submod/subsubmod &&\n-\t\techo X >untracked\n-\t) &&\n+\techo X >submod/subsubmod/untracked &&\n \ttest_must_fail git rm submod &&\n \ttest -d submod &&\n \ttest -f submod/.git &&\n-\tgit status -s -uno --ignore-submodules=none > actual &&\n+\tgit status -s -uno --ignore-submodules=none >actual &&\n \ttest_cmp expect.modified actual &&\n \tgit rm -f submod &&\n \ttest ! -d submod &&\n-\tgit status -s -uno --ignore-submodules=none > actual &&\n+\tgit status -s -uno --ignore-submodules=none >actual &&\n \ttest_cmp expect actual\n '\n \n@@ -695,12 +673,12 @@ test_expect_success 'rm of a populated nested submodule with a nested .git direc\n \ttest_must_fail git rm submod &&\n \ttest -d submod &&\n \ttest -d submod/subsubmod/.git &&\n-\tgit status -s -uno --ignore-submodules=none > actual &&\n+\tgit status -s -uno --ignore-submodules=none >actual &&\n \t! test -s actual &&\n \ttest_must_fail git rm -f submod &&\n \ttest -d submod &&\n \ttest -d submod/subsubmod/.git &&\n-\tgit status -s -uno --ignore-submodules=none > actual &&\n+\tgit status -s -uno --ignore-submodules=none >actual &&\n \t! test -s actual &&\n \trm -rf submod\n '\n@@ -716,7 +694,7 @@ test_expect_success 'checking out a commit after submodule removal needs manual\n \techo \"?? submod/\" >expected &&\n \ttest_cmp expected actual &&\n \trm -rf submod &&\n-\tgit status -s -uno --ignore-submodules=none > actual &&\n+\tgit status -s -uno --ignore-submodules=none >actual &&\n \t! test -s actual\n '\n \n-- \n2.11.0.rc2.35.g7af3268\n\n"},{"id":"307571","messageId":"20161213032848.4ps42jinix6fdgdc@genre.crustytoothpaste.net","threadId":"44690","inReplyTo":"20161213014055.14268-7-sbeller@google.com","subject":"Re: [PATCH 6/6] rm: add absorb a submodules git dir before deletion","fromName":"brian m. carlson","fromEmail":"sandals@crustytoothpaste.net","sentAt":"2016-12-13T03:28:49Z","receivedAt":"2016-12-13T03:29:01Z","isPatch":true,"sender":{"key":"sandals@crustytoothpaste.net","avatar":"https://avatars.githubusercontent.com/u/497054?v=4"},"body":"On Mon, Dec 12, 2016 at 05:40:55PM -0800, Stefan Beller wrote:\n> When deleting a submodule we need to keep the actual git directory around,\n> such that we do not lose local changes in there and at a later checkout\n> of the submodule we don't need to clone it again.\n> \n> Implement `depopulate_submodule`, that migrates the git directory before\n> deletion of a submodule and afterwards the equivalent of \"rm -rf\", which\n> is already found in entry.c, so expose that and for clarity add a suffix\n> \"_or_dir\" to it.\n\nI think you might have meant \"_or_die\" here.\n\nOther than that, I didn't see anything that stuck out to me in this\nseries as obviously wrong or broken, but this isn't an area of the code\nI'm super familiar with.\n-- \nbrian m. carlson / brian with sandals: Houston, Texas, US\n+1 832 623 2791 | https://www.crustytoothpaste.net/~bmc | My opinion only\nOpenPGP: https://keybase.io/bk2204\n"},{"id":"307577","messageId":"xmqqr35c5luq.fsf@gitster.mtv.corp.google.com","threadId":"44690","inReplyTo":"20161213014055.14268-1-sbeller@google.com","subject":"Re: [PATCH 0/6] git-rm absorbs submodule git directory before deletion","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-12-13T07:28:29Z","receivedAt":"2016-12-13T07:28:37Z","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 \"checkout --recurse-submodules\" series got too large to comfortably send\n> it out for review, so I had to break it up into smaller series'; this is the\n> first subseries, but it makes sense on its own.\n>\n> This series teaches git-rm to absorb the git directory of a submodule instead\n> of failing and complaining about the git directory preventing deletion.\n>  \n> It applies on origin/sb/submodule-embed-gitdir.\n\nThanks.  I probably should rename the topic again with s/embed/absorb/;\n\n> Any feedback welcome!\n>\n> Thanks,\n> Stefan\n>\n> Stefan Beller (6):\n>   submodule.h: add extern keyword to functions\n>   submodule: modernize ok_to_remove_submodule to use argv_array\n>   submodule: add flags to ok_to_remove_submodule\n>   ok_to_remove_submodule: absorb the submodule git dir\n>   t3600: slightly modernize style\n>   rm: add absorb a submodules git dir before deletion\n>\n>  builtin/rm.c  |  21 +++-----\n>  cache.h       |   2 +\n>  entry.c       |   5 ++\n>  submodule.c   |  77 +++++++++++++++++++++++-----\n>  submodule.h   |  64 ++++++++++++++---------\n>  t/t3600-rm.sh | 159 +++++++++++++++++++++++----------------------------------\n>  6 files changed, 182 insertions(+), 146 deletions(-)\n"},{"id":"307640","messageId":"CAGZ79kYg0kdRt1K_m+ocMeeJz=-18+jZFktt5ic+7T_55Gfh3w@mail.gmail.com","threadId":"44690","inReplyTo":"20161213032848.4ps42jinix6fdgdc@genre.crustytoothpaste.net","subject":"Re: [PATCH 6/6] rm: add absorb a submodules git dir before deletion","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2016-12-13T17:51:11Z","receivedAt":"2016-12-13T17:51:59Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Mon, Dec 12, 2016 at 7:28 PM, brian m. carlson\n<sandals@crustytoothpaste.net> wrote:\n> On Mon, Dec 12, 2016 at 05:40:55PM -0800, Stefan Beller wrote:\n>> When deleting a submodule we need to keep the actual git directory around,\n>> such that we do not lose local changes in there and at a later checkout\n>> of the submodule we don't need to clone it again.\n>>\n>> Implement `depopulate_submodule`, that migrates the git directory before\n>> deletion of a submodule and afterwards the equivalent of \"rm -rf\", which\n>> is already found in entry.c, so expose that and for clarity add a suffix\n>> \"_or_dir\" to it.\n>\n> I think you might have meant \"_or_die\" here.\n\nindeed, will fix in a reroll. Thanks for the review!\n"},{"id":"307641","messageId":"CAGZ79kbmtYzFmEKrxHKx-_WY=0NDJM=QZYJziim-eh-w4WzDKw@mail.gmail.com","threadId":"44690","inReplyTo":"xmqqr35c5luq.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH 0/6] git-rm absorbs submodule git directory before deletion","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2016-12-13T17:55:37Z","receivedAt":"2016-12-13T17:55:47Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Mon, Dec 12, 2016 at 11:28 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> Stefan Beller <sbeller@google.com> writes:\n>\n>> The \"checkout --recurse-submodules\" series got too large to comfortably send\n>> it out for review, so I had to break it up into smaller series'; this is the\n>> first subseries, but it makes sense on its own.\n>>\n>> This series teaches git-rm to absorb the git directory of a submodule instead\n>> of failing and complaining about the git directory preventing deletion.\n>>\n>> It applies on origin/sb/submodule-embed-gitdir.\n>\n> Thanks.  I probably should rename the topic again with s/embed/absorb/;\n\nI mostly renamed it in the hope to settle our dispute what embedding means. ;)\nSo in case we want to further discuss on the name of the function, we should\ndo that before doing actual work such as renaming.\n\nNote that sb/t3600-cleanup is part of this series now,\n(The first commit of that series is in patch 6/6 of this series, and patch 5 is\nthe modernization effort.)\n\nThanks,\nStefan\n"},{"id":"307643","messageId":"15196def9a7f4458b053b2d1e182541c@exmbdft7.ad.twosigma.com","threadId":"44690","inReplyTo":"20161213014055.14268-7-sbeller@google.com","subject":"RE: [PATCH 6/6] rm: add absorb a submodules git dir before deletion","fromName":"David Turner","fromEmail":"david.turner@twosigma.com","sentAt":"2016-12-13T18:06:12Z","receivedAt":"2016-12-13T18:06:22Z","isPatch":true,"sender":{"key":"david.turner@twosigma.com","avatar":null},"body":"> -----Original Message-----\n> From: Stefan Beller [mailto:sbeller@google.com]\n> Sent: Monday, December 12, 2016 8:41 PM\n> To: gitster@pobox.com\n> Cc: git@vger.kernel.org; David Turner; bmwill@google.com; Stefan Beller\n> Subject: [PATCH 6/6] rm: add absorb a submodules git dir before deletion\n> \n> When deleting a submodule we need to keep the actual git directory around,\n\nNit: comma after submodule.\n\n> -\t\t\t\t\tstrbuf_reset(&buf);\n> -\t\t\t\t\tstrbuf_addstr(&buf, path);\n> -\t\t\t\t\tif (!remove_dir_recursively(&buf, 0)) {\n> -\t\t\t\t\t\tremoved = 1;\n> -\t\t\t\t\t\tif\n> (!remove_path_from_gitmodules(path))\n> -\t\t\t\t\t\t\tgitmodules_modified = 1;\n> -\t\t\t\t\t\tstrbuf_release(&buf);\n> -\t\t\t\t\t\tcontinue;\n> -\t\t\t\t\t} else if (!file_exists(path))\n> -\t\t\t\t\t\t/* Submodule was removed by user */\n> -\t\t\t\t\t\tif\n> (!remove_path_from_gitmodules(path))\n> -\t\t\t\t\t\t\tgitmodules_modified = 1;\n> +\t\t\t\t\tif (file_exists(path))\n> +\t\t\t\t\t\tdepopulate_submodule(path);\n> +\t\t\t\t\tremoved = 1;\n> +\t\t\t\t\tif (!remove_path_from_gitmodules(path))\n> +\t\t\t\t\t\tgitmodules_modified = 1;\n> +\t\t\t\t\tcontinue;\n>  \t\t\t\t\t/* Fallthrough and let remove_path() fail.\n> */\n\nIt seems odd to have a continue right before a comment that says \"Fallthrough\".  \n\n"},{"id":"307654","messageId":"xmqq37hr4q5t.fsf@gitster.mtv.corp.google.com","threadId":"44690","inReplyTo":"CAGZ79kbmtYzFmEKrxHKx-_WY=0NDJM=QZYJziim-eh-w4WzDKw@mail.gmail.com","subject":"Re: [PATCH 0/6] git-rm absorbs submodule git directory before deletion","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-12-13T18:53:02Z","receivedAt":"2016-12-13T18:53:11Z","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> On Mon, Dec 12, 2016 at 11:28 PM, Junio C Hamano <gitster@pobox.com> wrote:\n>> Stefan Beller <sbeller@google.com> writes:\n>>\n>>> The \"checkout --recurse-submodules\" series got too large to comfortably send\n>>> it out for review, so I had to break it up into smaller series'; this is the\n>>> first subseries, but it makes sense on its own.\n>>>\n>>> This series teaches git-rm to absorb the git directory of a submodule instead\n>>> of failing and complaining about the git directory preventing deletion.\n>>>\n>>> It applies on origin/sb/submodule-embed-gitdir.\n>>\n>> Thanks.  I probably should rename the topic again with s/embed/absorb/;\n>\n> I mostly renamed it in the hope to settle our dispute what embedding means. ;)\n\nI do not think there is no dispute about what embedding means.  A\nsubmodule whose .git is inside its working tree has its repository\nembedded.\n\nWhat we had trouble settling on was what to call the operation to\nundo the embedding, unentangling its repository out of the working\ntree.  I'd still vote for unembed if you want a name to be nominated.\n\n> Note that sb/t3600-cleanup is part of this series now,\n> (The first commit of that series is in patch 6/6 of this series, and patch 5 is\n> the modernization effort.)\n\nWell, \"t3600: remove useless redirect\" has been in 'next' already;\ndo you mean that you want me to queue this series on top of that\ntopic?\n\n\n"},{"id":"307657","messageId":"CAGZ79kY_E8xnOpCAFQo_91FeQCs9X3fkassFYunG=adx81AcBg@mail.gmail.com","threadId":"44690","inReplyTo":"xmqq37hr4q5t.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH 0/6] git-rm absorbs submodule git directory before deletion","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2016-12-13T19:07:32Z","receivedAt":"2016-12-13T19:08:44Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Tue, Dec 13, 2016 at 10:53 AM, Junio C Hamano <gitster@pobox.com> wrote:\n> Stefan Beller <sbeller@google.com> writes:\n>\n>> On Mon, Dec 12, 2016 at 11:28 PM, Junio C Hamano <gitster@pobox.com> wrote:\n>>> Stefan Beller <sbeller@google.com> writes:\n>>>\n>>>> The \"checkout --recurse-submodules\" series got too large to comfortably send\n>>>> it out for review, so I had to break it up into smaller series'; this is the\n>>>> first subseries, but it makes sense on its own.\n>>>>\n>>>> This series teaches git-rm to absorb the git directory of a submodule instead\n>>>> of failing and complaining about the git directory preventing deletion.\n>>>>\n>>>> It applies on origin/sb/submodule-embed-gitdir.\n>>>\n>>> Thanks.  I probably should rename the topic again with s/embed/absorb/;\n>>\n>> I mostly renamed it in the hope to settle our dispute what embedding means. ;)\n>\n> I do not think there is no dispute about what embedding means.\n\ndouble negative: You think we have a slight dispute here.\n\n>  A\n> submodule whose .git is inside its working tree has its repository\n> embedded.\n>\n> What we had trouble settling on was what to call the operation to\n> undo the embedding, unentangling its repository out of the working\n> tree.  I'd still vote for unembed if you want a name to be nominated.\n\nSo I can redo the series with two commands \"git submodule [un]embed\".\n\nFor me \"unembed\" == \"absorb\", such that we could also go with\nabsorb into superproject <-> embed into worktree\n\n\n>\n>> Note that sb/t3600-cleanup is part of this series now,\n>> (The first commit of that series is in patch 6/6 of this series, and patch 5 is\n>> the modernization effort.)\n>\n> Well, \"t3600: remove useless redirect\" has been in 'next' already;\n> do you mean that you want me to queue this series on top of that\n> topic?\n>\n\nI need to reroll this series any way; the reroll will be on top of that.\n\nThanks,\nStefan\n"},{"id":"307660","messageId":"xmqqtwa73ara.fsf@gitster.mtv.corp.google.com","threadId":"44690","inReplyTo":"CAGZ79kY_E8xnOpCAFQo_91FeQCs9X3fkassFYunG=adx81AcBg@mail.gmail.com","subject":"Re: [PATCH 0/6] git-rm absorbs submodule git directory before deletion","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-12-13T19:11:05Z","receivedAt":"2016-12-13T19:11:14Z","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>> I do not think there is no dispute about what embedding means.\n>\n> double negative: You think we have a slight dispute here.\n\nSorry, I do not think there is any dispute on that.\n\n>>  A\n>> submodule whose .git is inside its working tree has its repository\n>> embedded.\n>>\n>> What we had trouble settling on was what to call the operation to\n>> undo the embedding, unentangling its repository out of the working\n>> tree.  I'd still vote for unembed if you want a name to be nominated.\n>\n> So I can redo the series with two commands \"git submodule [un]embed\".\n>\n> For me \"unembed\" == \"absorb\", such that we could also go with\n> absorb into superproject <-> embed into worktree\n\nWith us agreeing that \"embed\" is about something is _IN_ submodule\nworking tree, unembed would naturally be something becomes OUTSIDE\nthe same thing (i.e. \"submodule working tree\").  However, if you\nintroduce \"absorb\", we suddenly need to talk about a different\nthing, i.e. \"superproject's .git/modules\", that is doing the\nabsorption.  That is why I suggest \"unembed\" over \"absorb\".\n"},{"id":"307667","messageId":"CAGZ79kYsfybEBnWzv4OjCCLe70fNS=roZdKDbN_DSb4PDVJj7g@mail.gmail.com","threadId":"44690","inReplyTo":"CAGZ79kZCza=cwtzQ7raU3ch_Z_5TDqt0AGN2fPHiRSTDu66Fag@mail.gmail.com","subject":"Re: [PATCH 0/6] git-rm absorbs submodule git directory before deletion","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2016-12-13T19:38:57Z","receivedAt":"2016-12-13T19:40:53Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Tue, Dec 13, 2016 at 11:13 AM, Stefan Beller <sbeller@google.com> wrote:\n> On Tue, Dec 13, 2016 at 11:11 AM, Junio C Hamano <gitster@pobox.com> wrote:\n>> Stefan Beller <sbeller@google.com> writes:\n>>\n>>>> I do not think there is no dispute about what embedding means.\n>>>\n>>> double negative: You think we have a slight dispute here.\n>>\n>> Sorry, I do not think there is any dispute on that.\n>>\n>>>>  A\n>>>> submodule whose .git is inside its working tree has its repository\n>>>> embedded.\n>>>>\n>>>> What we had trouble settling on was what to call the operation to\n>>>> undo the embedding, unentangling its repository out of the working\n>>>> tree.  I'd still vote for unembed if you want a name to be nominated.\n>>>\n>>> So I can redo the series with two commands \"git submodule [un]embed\".\n>>>\n>>> For me \"unembed\" == \"absorb\", such that we could also go with\n>>> absorb into superproject <-> embed into worktree\n>>\n>> With us agreeing that \"embed\" is about something is _IN_ submodule\n>> working tree, unembed would naturally be something becomes OUTSIDE\n>> the same thing (i.e. \"submodule working tree\").\n\nI do not agree, yet.\nSo I thought about this for a while.\n\nThe standard in Git is to have the .git directory inside the working tree,\nwhich is why you are convinced that embedded means the .git is in the\nworking tree, because you approach this discussion as the Git maintainer,\nspending only little time on submodule related stuff.\n\nThe desired standard for submodules is to have the git dir inside the\nsuperprojects git dir (since  501770e, Aug 2011, Move git-dir for\nsubmodules), which is why I think an \"embedded submodule git dir\"\nis inside the superproject already.\n\nI think both views are legit, and we would want to choose the one that\nusers find most intuitive (and I think there will be users that find either\nviewpoint intuitive).\n\nSo when you have typed \"git submodule \", I wonder if a user would\nassume a submodule-centric mindset of how submodules ought to\nwork or if they still look at a submodule as its own git repo\nthat just happens to be embedded into the superproject.\n\nI guess the latter is the case, so embedding is actually inside the working\ntree and un-embedding is the relocation to the superproject.\n"},{"id":"307669","messageId":"CAGZ79kZCza=cwtzQ7raU3ch_Z_5TDqt0AGN2fPHiRSTDu66Fag@mail.gmail.com","threadId":"44690","inReplyTo":"xmqqtwa73ara.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH 0/6] git-rm absorbs submodule git directory before deletion","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2016-12-13T19:13:36Z","receivedAt":"2016-12-13T19:44:13Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Tue, Dec 13, 2016 at 11:11 AM, Junio C Hamano <gitster@pobox.com> wrote:\n> Stefan Beller <sbeller@google.com> writes:\n>\n>>> I do not think there is no dispute about what embedding means.\n>>\n>> double negative: You think we have a slight dispute here.\n>\n> Sorry, I do not think there is any dispute on that.\n>\n>>>  A\n>>> submodule whose .git is inside its working tree has its repository\n>>> embedded.\n>>>\n>>> What we had trouble settling on was what to call the operation to\n>>> undo the embedding, unentangling its repository out of the working\n>>> tree.  I'd still vote for unembed if you want a name to be nominated.\n>>\n>> So I can redo the series with two commands \"git submodule [un]embed\".\n>>\n>> For me \"unembed\" == \"absorb\", such that we could also go with\n>> absorb into superproject <-> embed into worktree\n>\n> With us agreeing that \"embed\" is about something is _IN_ submodule\n> working tree, unembed would naturally be something becomes OUTSIDE\n> the same thing (i.e. \"submodule working tree\").  However, if you\n> introduce \"absorb\", we suddenly need to talk about a different\n> thing, i.e. \"superproject's .git/modules\", that is doing the\n> absorption.  That is why I suggest \"unembed\" over \"absorb\".\n\nok, I will take unembed then.  We could also go with more command line options\nsuch as \"embed --reverse\" or such, but that is not as nice I'd think.\n"},{"id":"307670","messageId":"xmqq60mn3937.fsf@gitster.mtv.corp.google.com","threadId":"44690","inReplyTo":"CAGZ79kYsfybEBnWzv4OjCCLe70fNS=roZdKDbN_DSb4PDVJj7g@mail.gmail.com","subject":"Re: [PATCH 0/6] git-rm absorbs submodule git directory before deletion","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-12-13T19:47:08Z","receivedAt":"2016-12-13T19:48:30Z","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 desired standard for submodules is to have the git dir inside the\n> superprojects git dir (since  501770e, Aug 2011, Move git-dir for\n> submodules), which is why I think an \"embedded submodule git dir\"\n> is inside the superproject already.\n\nThink how you start a new submodule.  What are the steps you take\nbefore you say \"git submodule add\"?  And where does .git for the\nsubmodule live at that point?\n\nWith the current system, you as the submodule originator need to do\nsomething different to make your working tree of the superproject\nmatch what the others who clone from your public repository.\n\nAnd comparing the two layout, the one originally held by the\nsubmodule originator has .git embedded in the working tree, no?\n\nAll of the above is coming from \"submodule\" centric mindset.  It\njust is not centric to those who follow what others originated.\n"},{"id":"307672","messageId":"xmqq1sxb38qn.fsf@gitster.mtv.corp.google.com","threadId":"44690","inReplyTo":"CAGZ79kYsfybEBnWzv4OjCCLe70fNS=roZdKDbN_DSb4PDVJj7g@mail.gmail.com","subject":"Re: [PATCH 0/6] git-rm absorbs submodule git directory before deletion","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-12-13T19:54:40Z","receivedAt":"2016-12-13T19:55:01Z","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> I guess the latter is the case, so embedding is actually inside\n> the working tree and un-embedding is the relocation to the\n> superproject.\n\nAnother reason why I personally see a .git in each submodule working\ntree is \"embedded\" has nothing to do with Git.  It is an analogy I\nfeel (perhaps it is just me) with the word \"embedded reporters in\nwarzone\".  These people are spread around, assigned to units to\nreport from places closer to the front line and being closer to the\nleaf of the hierarchy, as opposed to be assigned to a more central\nplace like HQ to do their reporting.\n"},{"id":"307676","messageId":"CAGZ79kYM_3NWyRfk42=EshMYVZ=DSWRtn4RU4jkUE7v1EN6ngg@mail.gmail.com","threadId":"44690","inReplyTo":"xmqq60mn3937.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH 0/6] git-rm absorbs submodule git directory before deletion","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2016-12-13T20:09:15Z","receivedAt":"2016-12-13T20:12:40Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Tue, Dec 13, 2016 at 11:47 AM, Junio C Hamano <gitster@pobox.com> wrote:\n> Stefan Beller <sbeller@google.com> writes:\n>\n>> The desired standard for submodules is to have the git dir inside the\n>> superprojects git dir (since  501770e, Aug 2011, Move git-dir for\n>> submodules), which is why I think an \"embedded submodule git dir\"\n>> is inside the superproject already.\n>\n> Think how you start a new submodule.  What are the steps you take\n> before you say \"git submodule add\"?  And where does .git for the\n> submodule live at that point?\n\nWell there is no way to directly start a submodule\n(e.g. \"git submodule create\"), such that there has to be one repo\nthat actually has the git dir inside the working tree.\n\nIf the submodule exists already somewhere, there are 2 ways to do it\n(\"git submodule add <URL>\"  or \"git clone && git submodule add\")\nwhich lead to different outcomes, where the .git resides.\n\n> With the current system, you as the submodule originator need to do\n> something different to make your working tree of the superproject\n> match what the others who clone from your public repository.\n>\n> And comparing the two layout, the one originally held by the\n> submodule originator has .git embedded in the working tree, no?\n\nWhen starting a new submodule repo, yes, the git dir is inside\nthe working tree.\n\n> All of the above is coming from \"submodule\" centric mindset.  It\n> just is not centric to those who follow what others originated.\n\nok.\n\n> Another reason why I personally see a .git in each submodule working\n> tree is \"embedded\" has nothing to do with Git.  It is an analogy I\n> feel (perhaps it is just me) with the word \"embedded reporters in\n> warzone\".  These people are spread around, assigned to units to\n> report from places closer to the front line and being closer to the\n> leaf of the hierarchy, as opposed to be assigned to a more central\n> place like HQ to do their reporting.\n\nI talked to people in the office and got a heavy rejection on the\nthe work \"embedded\" here for another reason:\n\n    \"Does it put the submodule on an embedded device?\n    What does embedded even mean?\n    The end user is super confused\"\n\nSo I think we should not use embed or un-embed one way or the other.\nInstead we need to have another name.\n\nI think absorb is ok-ish, as \"git submodule absorb\" hints that the\nsuperproject absorbs something from the submodule.\n\nSo I will reroll it with \"absorb\" fixing some nits pointed out by David?\n"},{"id":"307677","messageId":"CAGZ79kb=-hUi+NqSa5v9qqKRfVW-Qsf_8Wsbi+hcYTQR5zyzBQ@mail.gmail.com","threadId":"44690","inReplyTo":"CAGZ79kYM_3NWyRfk42=EshMYVZ=DSWRtn4RU4jkUE7v1EN6ngg@mail.gmail.com","subject":"Re: [PATCH 0/6] git-rm absorbs submodule git directory before deletion","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2016-12-13T20:22:52Z","receivedAt":"2016-12-13T20:23:07Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Tue, Dec 13, 2016 at 12:09 PM, Stefan Beller <sbeller@google.com> wrote:\n>\n> So I will reroll it with \"absorb\" fixing some nits pointed out by David?\n\nI got confused there, Davids nits are for this series, the absorb series itself\ndoesn't seem to have nits.\n\nSo I'll just reroll this series on top of the currently\nsb/submodule-embed-gitdir (which you originally noted to be better renamed to\nsubmodule-absorb-gitdir) merged with t3600-cleanup.\n\nThanks,\nStefan\n"}]}