{"thread":{"id":"42151","subject":"[PATCH 00/15] submodule groups (once again)","startedAt":"2016-04-26T20:50:18Z","lastAt":"2016-05-06T18:59:47Z","messageCount":48,"participants":["Stefan Beller","Junio C Hamano","Jacob Keller"],"isPatch":true,"patchVersion":1,"patchTotal":15},"messages":[{"id":"284589","messageId":"1461703833-10350-1-git-send-email-sbeller@google.com","threadId":"42151","inReplyTo":null,"subject":"[PATCH 00/15] submodule groups (once again)","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2016-04-26T20:50:18Z","receivedAt":"2016-04-26T20:50:18Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"New in this series: git status, git diff and all remaining git submodule subcommands.\n\nOne pain point I am still aware of:\n`git diff` and `git status` completely ignore submodules which are not in the\ndefault group. I am not sure if that is a reasonable default.\n\nA poor analogy could be the .gitignore file configuration:\nIf an entry exists in .gitignore, the corresponding file is ignored if\n(and only if) the file is not part of the repository, i.e changes to \na tracked (but ignored) file are still shown. Another way of saying it:\nThe ignore mechanism doesn't influence the diff machinery.\n\ngit diff is supposed to view the differences between \"what would I\nget after checkout\" (i.e. what is in the index run through smudge filters)\ncompared to the actual worktree.\nWith the submodule default group set, we would expect to not see some\nsubmodules checked out. But if such a submodule is in the worktree,\nwe may want to show a message instead:\n\n    $ git status\n    ... # normal git status stuff\n        More than 2 submodules (123 actually) including \n            'path/foo'\n            'lib/baz'\n            # have a reasonable maximum for the number of submodules shown\n        are checked out, but not part of the default group.\n        You can add these submodules via\n            git config --add submodule.defaultGroup ./path/foo\n            git config --add submodule.defaultGroup ./lib/baz\n\nOnce we have such a message, we would need to train `git checkout` to checkout\nand drop the right submodules for switching branches.\n\nIt has been a while since last posting this series and it is substantially\ndifferent in scope (and I have rewritten most of the patches), so I'll not\nprovide an intra-diff or a version number for this series.\n\nWhat is this series about?\n==========================\n\nIf you have lots of submodules, you probably don't need all of them at once, \nbut you have functional units. Some submodules are absolutely required, \nsome are optional and only for very specific purposes. \n\nThis patch series adds labels to submodules in the .gitmodules file. \n\nSo you could have a .gitmodules file such as: \n\n[submodule \"gcc\"] \n        path = gcc \n        url = git://... \n        label = default\n        label = devel \n[submodule \"linux\"] \n        path = linux \n        url = git://... \n        label = default \n[submodule \"nethack\"] \n        path = nethack \n        url = git://... \n        label = optional\n        label = games \n\nand by this series you can work on an arbitrary group of these submodules\ncomposed by the labels, names or paths of the submodules.\n\n    git clone --recurse-submodules --init-submodule=label --init-submodule=label2   git://... \n    # will clone the superproject and recursively \n    # checkout any submodule being labeled label or label2\n    \n    git submodule add --label <name> git://... ..\n    # record a label while adding a submodule\n    \n    git config submodule.defaultGroups default\n    git config --add submodule.defaultGroups devel\n    # configure which submodules you are interested in.\n    \n    git submodule update\n    # update only the submodules in the default group if that is configured.\n    \n    git status\n    git diff\n    git submodule summary\n    # show only changes to submodules which are in the default group.\n\nAny feedback welcome, specially on the design level! \n(Do we want to have it stored in the .gitmodules file? Do we want to have \nthe groups configured in .git/config as \"submodule.groups\", any other way \nto make it future proof and extend the groups syntax?) \n\nThanks, \nStefan \n\nStefan Beller (15):\n  string_list: add string_list_duplicate\n  submodule doc: write down what we want to achieve in this series\n  submodule add: label submodules if asked to\n  submodule-config: keep labels around\n  submodule-config: check if submodule a submodule is in a group\n  submodule init: redirect stdout to stderr\n  submodule deinit: loose requirement for giving '.'\n  submodule--helper list: respect submodule groups\n  submodule--helper init: respect submodule groups\n  submodule--helper update_clone: respect submodule groups\n  diff: ignore submodules excluded by groups\n  git submodule summary respects groups\n  cmd_status: respect submodule groups\n  cmd_diff: respect submodule groups\n  clone: allow specification of submodules to be cloned\n\n Documentation/config.txt        |   4 +\n Documentation/git-clone.txt     |   6 +\n Documentation/git-submodule.txt |  13 +-\n builtin/clone.c                 |  40 +++++-\n builtin/commit.c                |   3 +\n builtin/diff.c                  |   2 +\n builtin/submodule--helper.c     |  94 ++++++++++++-\n diff.c                          |   3 +\n diff.h                          |   1 +\n git-submodule.sh                |  24 +++-\n string-list.c                   |  18 +++\n string-list.h                   |   2 +\n submodule-config.c              |  66 ++++++++++\n submodule-config.h              |   5 +\n t/t7400-submodule-basic.sh      | 129 +++++++++++++++++-\n t/t7406-submodule-update.sh     |  24 +++-\n t/t7413-submodule--helper.sh    | 285 ++++++++++++++++++++++++++++++++++++++++\n wt-status.c                     |   2 +\n wt-status.h                     |   1 +\n 19 files changed, 701 insertions(+), 21 deletions(-)\n create mode 100755 t/t7413-submodule--helper.sh\n\n-- \n2.8.0.41.g8d9aeb3\n"},{"id":"284594","messageId":"1461703833-10350-2-git-send-email-sbeller@google.com","threadId":"42151","inReplyTo":"1461703833-10350-1-git-send-email-sbeller@google.com","subject":"[PATCH 01/15] string_list: add string_list_duplicate","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2016-04-26T20:50:19Z","receivedAt":"2016-04-26T20:50:19Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"The result of git_config_get_value_multi do not seem to be stable and\nmay get overwritten. Have an easy way to preserve the results of that\nquery.\n\nSigned-off-by: Stefan Beller <sbeller@google.com>\n---\n string-list.c | 18 ++++++++++++++++++\n string-list.h |  2 ++\n 2 files changed, 20 insertions(+)\n\ndiff --git a/string-list.c b/string-list.c\nindex 2a32a3f..f981c8a 100644\n--- a/string-list.c\n+++ b/string-list.c\n@@ -7,6 +7,24 @@ void string_list_init(struct string_list *list, int strdup_strings)\n \tlist->strdup_strings = strdup_strings;\n }\n \n+struct string_list *string_list_duplicate(const struct string_list *src,\n+\t\t\t\t\t  int strdup_strings)\n+{\n+\tstruct string_list *list;\n+\tstruct string_list_item *item;\n+\n+\tif (!src)\n+\t\treturn NULL;\n+\n+\tlist = xmalloc(sizeof(*list));\n+\tstring_list_init(list, strdup_strings);\n+\tfor_each_string_list_item(item, src)\n+\t\tstring_list_append(list, item->string);\n+\n+\treturn list;\n+}\n+\n+\n /* if there is no exact match, point to the index where the entry could be\n  * inserted */\n static int get_entry_index(const struct string_list *list, const char *string,\ndiff --git a/string-list.h b/string-list.h\nindex d3809a1..1a5612f 100644\n--- a/string-list.h\n+++ b/string-list.h\n@@ -19,6 +19,8 @@ struct string_list {\n #define STRING_LIST_INIT_DUP   { NULL, 0, 0, 1, NULL }\n \n void string_list_init(struct string_list *list, int strdup_strings);\n+struct string_list *string_list_duplicate(const struct string_list *src,\n+\t\t\t\t\t  int strdup_strings);\n \n void print_string_list(const struct string_list *p, const char *text);\n void string_list_clear(struct string_list *list, int free_util);\n-- \n2.8.0.41.g8d9aeb3\n"},{"id":"284591","messageId":"1461703833-10350-3-git-send-email-sbeller@google.com","threadId":"42151","inReplyTo":"1461703833-10350-1-git-send-email-sbeller@google.com","subject":"[PATCH 02/15] submodule doc: write down what we want to achieve in this series","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2016-04-26T20:50:20Z","receivedAt":"2016-04-26T20:50:20Z","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 Documentation/config.txt        | 4 ++++\n Documentation/git-submodule.txt | 8 ++++++++\n 2 files changed, 12 insertions(+)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex 59d7046..c5b6a4e 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -2735,6 +2735,10 @@ submodule.fetchJobs::\n \tin parallel. A value of 0 will give some reasonable default.\n \tIf unset, it defaults to 1.\n \n+submodule.defaultGroup::\n+\tSpecifies the group of submodules to be operated on\n+\tin a command if no submodules were specified in the command.\n+\n tag.sort::\n \tThis variable controls the sort ordering of tags when displayed by\n \tlinkgit:git-tag[1]. Without the \"--sort=<value>\" option provided, the\ndiff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt\nindex 13adebf..8c4bbe2 100644\n--- a/Documentation/git-submodule.txt\n+++ b/Documentation/git-submodule.txt\n@@ -37,6 +37,14 @@ these will not be checked out by default; the 'init' and 'update'\n subcommands will maintain submodules checked out and at\n appropriate revision in your working tree.\n \n+When operating on submodules you can either give paths to specify the\n+desired submodules or give no paths at all to apply the command to the\n+default group of submodules. By default all submodules are included in\n+the default group. You can change the default group by configuring\n+submodule.defaultGroup. Once the default group is configured any\n+submodule operation without a specified set of submodules will use\n+the default group as the set to operate on.\n+\n Submodules are composed from a so-called `gitlink` tree entry\n in the main repository that refers to a particular commit object\n within the inner repository that is completely separate.\n-- \n2.8.0.41.g8d9aeb3\n"},{"id":"284592","messageId":"1461703833-10350-4-git-send-email-sbeller@google.com","threadId":"42151","inReplyTo":"1461703833-10350-1-git-send-email-sbeller@google.com","subject":"[PATCH 03/15] submodule add: label submodules if asked to","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2016-04-26T20:50:21Z","receivedAt":"2016-04-26T20:50:21Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"When adding new submodules, you can specify the\nlabel(s) the submodule belongs to by giving one or more\n--label arguments. This will record each label in the\n.gitmodules file as a value of the key\n\"submodule.$NAME.label\".\n\nSigned-off-by: Stefan Beller <sbeller@google.com>\n---\n Documentation/git-submodule.txt |  5 ++++-\n git-submodule.sh                | 14 +++++++++++++-\n t/t7400-submodule-basic.sh      | 32 ++++++++++++++++++++++++++++++++\n 3 files changed, 49 insertions(+), 2 deletions(-)\n\ndiff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt\nindex 8c4bbe2..349ead8 100644\n--- a/Documentation/git-submodule.txt\n+++ b/Documentation/git-submodule.txt\n@@ -9,7 +9,7 @@ git-submodule - Initialize, update or inspect submodules\n SYNOPSIS\n --------\n [verse]\n-'git submodule' [--quiet] add [-b <branch>] [-f|--force] [--name <name>]\n+'git submodule' [--quiet] add [-b <branch>] [-f|--force] [-l|--label <label>]\n \t      [--reference <repository>] [--depth <depth>] [--] <repository> [<path>]\n 'git submodule' [--quiet] status [--cached] [--recursive] [--] [<path>...]\n 'git submodule' [--quiet] init [--] [<path>...]\n@@ -109,6 +109,9 @@ is the superproject and submodule repositories will be kept\n together in the same relative location, and only the\n superproject's URL needs to be provided: git-submodule will correctly\n locate the submodule using the relative URL in .gitmodules.\n++\n+If at least one label argument was given, all labels are recorded in the\n+.gitmodules file in the label fields.\n \n status::\n \tShow the status of the submodules. This will print the SHA-1 of the\ndiff --git a/git-submodule.sh b/git-submodule.sh\nindex 82e95a9..d7a5e1a 100755\n--- a/git-submodule.sh\n+++ b/git-submodule.sh\n@@ -5,7 +5,7 @@\n # Copyright (c) 2007 Lars Hjemli\n \n dashless=$(basename \"$0\" | sed -e 's/-/ /')\n-USAGE=\"[--quiet] add [-b <branch>] [-f|--force] [--name <name>] [--reference <repository>] [--] <repository> [<path>]\n+USAGE=\"[--quiet] add [-b <branch>] [-f|--force] [--name <name>] [--reference <repository>] [-l|--label <label>][--] <repository> [<path>]\n    or: $dashless [--quiet] status [--cached] [--recursive] [--] [<path>...]\n    or: $dashless [--quiet] init [--] [<path>...]\n    or: $dashless [--quiet] deinit [-f|--force] [--] <path>...\n@@ -130,6 +130,7 @@ cmd_add()\n {\n \t# parse $args after \"submodule ... add\".\n \treference_path=\n+\tlabels=\n \twhile test $# -ne 0\n \tdo\n \t\tcase \"$1\" in\n@@ -165,6 +166,13 @@ cmd_add()\n \t\t--depth=*)\n \t\t\tdepth=$1\n \t\t\t;;\n+\t\t-l|--label)\n+\t\t\tlabels=\"${labels} $2\"\n+\t\t\tshift\n+\t\t\t;;\n+\t\t--label=*)\n+\t\t\tlabels=\"${labels} ${1#--label=}\"\n+\t\t\t;;\n \t\t--)\n \t\t\tshift\n \t\t\tbreak\n@@ -292,6 +300,10 @@ Use -f if you really want to add it.\" >&2\n \n \tgit config -f .gitmodules submodule.\"$sm_name\".path \"$sm_path\" &&\n \tgit config -f .gitmodules submodule.\"$sm_name\".url \"$repo\" &&\n+\tfor label in $labels\n+\tdo\n+\t\tgit config --add -f .gitmodules submodule.\"$sm_name\".label \"${label}\"\n+\tdone &&\n \tif test -n \"$branch\"\n \tthen\n \t\tgit config -f .gitmodules submodule.\"$sm_name\".branch \"$branch\"\ndiff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh\nindex f99f674..e9d1d58 100755\n--- a/t/t7400-submodule-basic.sh\n+++ b/t/t7400-submodule-basic.sh\n@@ -1040,6 +1040,7 @@ test_expect_success 'submodule with UTF-8 name' '\n '\n \n test_expect_success 'submodule add clone shallow submodule' '\n+\ttest_when_finished \"rm -rf super\" &&\n \tmkdir super &&\n \tpwd=$(pwd) &&\n \t(\n@@ -1078,5 +1079,36 @@ test_expect_success 'submodule helper list is not confused by common prefixes' '\n \ttest_cmp expect actual\n '\n \n+test_expect_success 'submodule add records a label' '\n+\ttest_when_finished \"rm -rf super\" &&\n+\tmkdir super &&\n+\tpwd=$(pwd) &&\n+\t(\n+\t\tcd super &&\n+\t\tgit init &&\n+\t\tgit submodule add --label labelA file://\"$pwd\"/example2 submodule &&\n+\t\tgit config -f .gitmodules submodule.\"submodule\".label >actual &&\n+\t\techo labelA >expected &&\n+\t\ttest_cmp expected actual\n+\t)\n+'\n+\n+cat >expected <<-EOF\n+labelA\n+labelB\n+EOF\n+\n+test_expect_success 'submodule add records multiple labels' '\n+\ttest_when_finished \"rm -rf super\" &&\n+\tmkdir super &&\n+\tpwd=$(pwd) &&\n+\t(\n+\t\tcd super &&\n+\t\tgit init &&\n+\t\tgit submodule add --label=labelA -l labelB file://\"$pwd\"/example2 submodule &&\n+\t\tgit config --get-all -f .gitmodules submodule.\"submodule\".label >../actual\n+\t) &&\n+\ttest_cmp expected actual\n+'\n \n test_done\n-- \n2.8.0.41.g8d9aeb3\n"},{"id":"284593","messageId":"1461703833-10350-5-git-send-email-sbeller@google.com","threadId":"42151","inReplyTo":"1461703833-10350-1-git-send-email-sbeller@google.com","subject":"[PATCH 04/15] submodule-config: keep labels around","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2016-04-26T20:50:22Z","receivedAt":"2016-04-26T20:50:22Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"We need the submodule labels in a later patch.\n\nSigned-off-by: Stefan Beller <sbeller@google.com>\n---\n submodule-config.c | 16 ++++++++++++++++\n submodule-config.h |  2 ++\n 2 files changed, 18 insertions(+)\n\ndiff --git a/submodule-config.c b/submodule-config.c\nindex b82d1fb..0cdb47e 100644\n--- a/submodule-config.c\n+++ b/submodule-config.c\n@@ -60,6 +60,10 @@ static void free_one_config(struct submodule_entry *entry)\n \tfree((void *) entry->config->path);\n \tfree((void *) entry->config->name);\n \tfree((void *) entry->config->update_strategy.command);\n+\tif (entry->config->labels) {\n+\t\tstring_list_clear(entry->config->labels, 0);\n+\t\tfree(entry->config->labels);\n+\t}\n \tfree(entry->config);\n }\n \n@@ -199,6 +203,7 @@ static struct submodule *lookup_or_create_by_name(struct submodule_cache *cache,\n \tsubmodule->update_strategy.command = NULL;\n \tsubmodule->fetch_recurse = RECURSE_SUBMODULES_NONE;\n \tsubmodule->ignore = NULL;\n+\tsubmodule->labels = NULL;\n \n \thashcpy(submodule->gitmodules_sha1, gitmodules_sha1);\n \n@@ -353,6 +358,17 @@ static int parse_config(const char *var, const char *value, void *data)\n \t\telse if (parse_submodule_update_strategy(value,\n \t\t\t &submodule->update_strategy) < 0)\n \t\t\t\tdie(_(\"invalid value for %s\"), var);\n+\t} else if (!strcmp(item.buf, \"label\")) {\n+\t\tif (!value)\n+\t\t\tret = config_error_nonbool(var);\n+\t\telse {\n+\t\t\tif (!submodule->labels) {\n+\t\t\t\tsubmodule->labels =\n+\t\t\t\t\txmalloc(sizeof(*submodule->labels));\n+\t\t\t\tstring_list_init(submodule->labels, 1);\n+\t\t\t}\n+\t\t\tstring_list_insert(submodule->labels, value);\n+\t\t}\n \t}\n \n \tstrbuf_release(&name);\ndiff --git a/submodule-config.h b/submodule-config.h\nindex e4857f5..d57da59 100644\n--- a/submodule-config.h\n+++ b/submodule-config.h\n@@ -18,6 +18,8 @@ struct submodule {\n \tstruct submodule_update_strategy update_strategy;\n \t/* the sha1 blob id of the responsible .gitmodules file */\n \tunsigned char gitmodules_sha1[20];\n+\t/* sorted, not as on disk */\n+\tstruct string_list *labels;\n };\n \n int parse_fetch_recurse_submodules_arg(const char *opt, const char *arg);\n-- \n2.8.0.41.g8d9aeb3\n"},{"id":"284602","messageId":"1461703833-10350-6-git-send-email-sbeller@google.com","threadId":"42151","inReplyTo":"1461703833-10350-1-git-send-email-sbeller@google.com","subject":"[PATCH 05/15] submodule-config: check if submodule a submodule is in a group","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2016-04-26T20:50:23Z","receivedAt":"2016-04-26T20:50:23Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"In later patches we need to tell if a submodule is in a group,\nwhich is defined by name, path or labels.\n\nSigned-off-by: Stefan Beller <sbeller@google.com>\n---\n builtin/submodule--helper.c  | 43 ++++++++++++++++++++++-\n submodule-config.c           | 50 +++++++++++++++++++++++++++\n submodule-config.h           |  3 ++\n t/t7413-submodule--helper.sh | 81 ++++++++++++++++++++++++++++++++++++++++++++\n 4 files changed, 176 insertions(+), 1 deletion(-)\n create mode 100755 t/t7413-submodule--helper.sh\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex b6d4f27..23d7224 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -814,6 +814,46 @@ static int update_clone(int argc, const char **argv, const char *prefix)\n \treturn 0;\n }\n \n+int in_group(int argc, const char **argv, const char *prefix)\n+{\n+\tconst struct string_list *list;\n+\tstruct string_list actual_list = STRING_LIST_INIT_DUP;\n+\tconst struct submodule *sub;\n+\tconst char *group = NULL;\n+\n+\tstruct option default_group_options[] = {\n+\t\tOPT_STRING('g', \"group\", &group, N_(\"group\"),\n+\t\t\t\tN_(\"group specifier for submodules\")),\n+\t\tOPT_END()\n+\t};\n+\n+\tconst char *const git_submodule_helper_usage[] = {\n+\t\tN_(\"git submodule--helper in-group <path>\"),\n+\t\tNULL\n+\t};\n+\n+\targc = parse_options(argc, argv, prefix, default_group_options,\n+\t\t\t     git_submodule_helper_usage, 0);\n+\n+\t/* Overlay the parsed .gitmodules file with .git/config */\n+\tgitmodules_config();\n+\tgit_config(submodule_config, NULL);\n+\n+\tif (argc != 1)\n+\t\tusage(git_submodule_helper_usage[0]);\n+\n+\tsub = submodule_from_path(null_sha1, argv[0]);\n+\n+\tif (!group)\n+\t\tlist = git_config_get_value_multi(\"submodule.defaultGroup\");\n+\telse {\n+\t\tstring_list_split(&actual_list, group, ',', -1);\n+\t\tlist = &actual_list;\n+\t}\n+\n+\treturn !submodule_in_group(list, sub);\n+}\n+\n struct cmd_struct {\n \tconst char *cmd;\n \tint (*fn)(int, const char **, const char *);\n@@ -826,7 +866,8 @@ static struct cmd_struct commands[] = {\n \t{\"update-clone\", update_clone},\n \t{\"resolve-relative-url\", resolve_relative_url},\n \t{\"resolve-relative-url-test\", resolve_relative_url_test},\n-\t{\"init\", module_init}\n+\t{\"init\", module_init},\n+\t{\"in-group\", in_group}\n };\n \n int cmd_submodule__helper(int argc, const char **argv, const char *prefix)\ndiff --git a/submodule-config.c b/submodule-config.c\nindex 0cdb47e..ebed0f2 100644\n--- a/submodule-config.c\n+++ b/submodule-config.c\n@@ -522,3 +522,53 @@ void submodule_free(void)\n \tcache_free(&cache);\n \tis_cache_init = 0;\n }\n+\n+int submodule_in_group(const struct string_list *group,\n+\t\t       const struct submodule *sub)\n+{\n+\tint matched = 0;\n+\tstruct strbuf sb = STRBUF_INIT;\n+\n+\tif (!group)\n+\t\t/*\n+\t\t * If no group is specified all, all submodules match to\n+\t\t * keep traditional behavior\n+\t\t */\n+\t\treturn 1;\n+\n+\tif (sub->labels) {\n+\t\tstruct string_list_item *item;\n+\t\tfor_each_string_list_item(item, sub->labels) {\n+\t\t\tstrbuf_reset(&sb);\n+\t\t\tstrbuf_addf(&sb, \"*%s\", item->string);\n+\t\t\tif (string_list_has_string(group, sb.buf)) {\n+\t\t\t\tmatched = 1;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t}\n+\t}\n+\tif (sub->path) {\n+\t\t/*\n+\t\t * NEEDSWORK: This currently works only for\n+\t\t * exact paths, but we want to enable\n+\t\t * inexact matches such wildcards.\n+\t\t */\n+\t\tstrbuf_reset(&sb);\n+\t\tstrbuf_addf(&sb, \"./%s\", sub->path);\n+\t\tif (string_list_has_string(group, sb.buf))\n+\t\t\tmatched = 1;\n+\t}\n+\tif (sub->name) {\n+\t\t/*\n+\t\t * NEEDSWORK: Same as with path. Do we want to\n+\t\t * support wildcards or such?\n+\t\t */\n+\t\tstrbuf_reset(&sb);\n+\t\tstrbuf_addf(&sb, \":%s\", sub->name);\n+\t\tif (string_list_has_string(group, sb.buf))\n+\t\t\tmatched = 1;\n+\t}\n+\tstrbuf_release(&sb);\n+\n+\treturn matched;\n+}\ndiff --git a/submodule-config.h b/submodule-config.h\nindex d57da59..4c696cc 100644\n--- a/submodule-config.h\n+++ b/submodule-config.h\n@@ -31,4 +31,7 @@ const struct submodule *submodule_from_path(const unsigned char *commit_sha1,\n \t\tconst char *path);\n void submodule_free(void);\n \n+int submodule_in_group(const struct string_list *group,\n+\t\t       const struct submodule *sub);\n+\n #endif /* SUBMODULE_CONFIG_H */\ndiff --git a/t/t7413-submodule--helper.sh b/t/t7413-submodule--helper.sh\nnew file mode 100755\nindex 0000000..c6939ab\n--- /dev/null\n+++ b/t/t7413-submodule--helper.sh\n@@ -0,0 +1,81 @@\n+#!/bin/sh\n+\n+# This should be merged with t7412 eventually.\n+# (currently in flight as jk/submodule-c-credential)\n+\n+\n+test_description='Basic plumbing support of submodule--helper\n+\n+This test verifies the submodule--helper plumbing command used to implement\n+git-submodule.\n+'\n+\n+. ./test-lib.sh\n+\n+test_expect_success 'setup superproject with submodules' '\n+\n+\tmkdir sub &&\n+\t(\n+\t\tcd sub &&\n+\t\tgit init &&\n+\t\ttest_commit test\n+\t\ttest_commit test2\n+\t) &&\n+\tmkdir super &&\n+\t(\n+\t\tcd super &&\n+\t\tgit init &&\n+\t\tgit submodule add ../sub sub0 &&\n+\t\tgit submodule add -l bit1 ../sub sub1 &&\n+\t\tgit submodule add -l bit2 ../sub sub2 &&\n+\t\tgit submodule add -l bit2 -l bit1 ../sub sub3 &&\n+\t\tgit commit -m \"add labeled submodules\"\n+\t)\n+'\n+\n+test_expect_success 'in-group' '\n+\t(\n+\t\tcd super &&\n+\t\t# we do not specify a group nor have set a default group,\n+\t\t# any submodule should be in the default group:\n+\t\tgit submodule--helper in-group sub0 &&\n+\t\tgit submodule--helper in-group sub1 &&\n+\t\tgit submodule--helper in-group sub2 &&\n+\t\tgit submodule--helper in-group sub3 &&\n+\n+\t\t# test bit1:\n+\t\ttest_must_fail git submodule--helper in-group --group=*bit1 sub0 &&\n+\t\t\t       git submodule--helper in-group --group=*bit1 sub1 &&\n+\t\ttest_must_fail git submodule--helper in-group --group=*bit1 sub2 &&\n+\t\t\t       git submodule--helper in-group --group=*bit1 sub3 &&\n+\n+\t\t# test by path:\n+\t\t\t       git submodule--helper in-group --group=./sub0 sub0 &&\n+\t\ttest_must_fail git submodule--helper in-group --group=./sub0 sub1 &&\n+\t\ttest_must_fail git submodule--helper in-group --group=./sub0 sub2 &&\n+\t\ttest_must_fail git submodule--helper in-group --group=./sub0 sub3 &&\n+\n+\t\t# test by name:\n+\t\t\t       git submodule--helper in-group --group=:sub0 sub0 &&\n+\t\ttest_must_fail git submodule--helper in-group --group=:sub0 sub1 &&\n+\t\ttest_must_fail git submodule--helper in-group --group=:sub0 sub2 &&\n+\t\ttest_must_fail git submodule--helper in-group --group=:sub0 sub3 &&\n+\n+\t\t# logical OR of path and labels\n+\t\t\t       git submodule--helper in-group --group=*bit1,./sub0 sub0 &&\n+\t\t\t       git submodule--helper in-group --group=*bit1,./sub0 sub1 &&\n+\t\ttest_must_fail git submodule--helper in-group --group=*bit1,./sub0 sub2 &&\n+\t\t\t       git submodule--helper in-group --group=*bit1,./sub0 sub3 &&\n+\n+\t\t# test if the config option is picked up\n+\t\tgit config --add submodule.defaultGroup *bit1 &&\n+\t\tgit config --add submodule.defaultGroup ./sub0 &&\n+\n+\t\t\t       git submodule--helper in-group sub0 &&\n+\t\t\t       git submodule--helper in-group sub1 &&\n+\t\ttest_must_fail git submodule--helper in-group sub2 &&\n+\t\t\t       git submodule--helper in-group sub3\n+\t)\n+'\n+\n+test_done\n-- \n2.8.0.41.g8d9aeb3\n"},{"id":"284590","messageId":"1461703833-10350-7-git-send-email-sbeller@google.com","threadId":"42151","inReplyTo":"1461703833-10350-1-git-send-email-sbeller@google.com","subject":"[PATCH 06/15] submodule init: redirect stdout to stderr","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2016-04-26T20:50:24Z","receivedAt":"2016-04-26T20:50:24Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"Reroute the output of stdout to stderr as it is just informative\nmessages, not to be consumed by machines.\n\nWe want to init submodules from the helper for `submodule update`\nin a later patch and the stdout output of said helper is consumed\nby the parts of `submodule update` which are still written in shell.\nSo we have to be careful which messages are on stdout.\n\nSigned-off-by: Stefan Beller <sbeller@google.com>\n---\n builtin/submodule--helper.c |  3 ++-\n t/t7406-submodule-update.sh | 24 ++++++++++++++++++------\n 2 files changed, 20 insertions(+), 7 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 23d7224..7b9a4d7 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -362,7 +362,8 @@ static void init_submodule(const char *path, const char *prefix, int quiet)\n \t\t\tdie(_(\"Failed to register url for submodule path '%s'\"),\n \t\t\t    displaypath);\n \t\tif (!quiet)\n-\t\t\tprintf(_(\"Submodule '%s' (%s) registered for path '%s'\\n\"),\n+\t\t\tfprintf(stderr,\n+\t\t\t\t_(\"Submodule '%s' (%s) registered for path '%s'\\n\"),\n \t\t\t\tsub->name, url, displaypath);\n \t}\n \ndiff --git a/t/t7406-submodule-update.sh b/t/t7406-submodule-update.sh\nindex fd741f5..5f27879 100755\n--- a/t/t7406-submodule-update.sh\n+++ b/t/t7406-submodule-update.sh\n@@ -108,24 +108,36 @@ pwd=$(pwd)\n \n cat <<EOF >expect\n Submodule path '../super': checked out '$supersha1'\n-Submodule 'merging' ($pwd/merging) registered for path '../super/merging'\n-Submodule 'none' ($pwd/none) registered for path '../super/none'\n-Submodule 'rebasing' ($pwd/rebasing) registered for path '../super/rebasing'\n-Submodule 'submodule' ($pwd/submodule) registered for path '../super/submodule'\n Submodule path '../super/merging': checked out '$mergingsha1'\n Submodule path '../super/none': checked out '$nonesha1'\n Submodule path '../super/rebasing': checked out '$rebasingsha1'\n Submodule path '../super/submodule': checked out '$submodulesha1'\n EOF\n \n+cat <<EOF >expect2\n+Submodule 'merging' ($pwd/merging) registered for path '../super/merging'\n+Submodule 'none' ($pwd/none) registered for path '../super/none'\n+Submodule 'rebasing' ($pwd/rebasing) registered for path '../super/rebasing'\n+Submodule 'submodule' ($pwd/submodule) registered for path '../super/submodule'\n+Cloning into '$pwd/recursivesuper/super/merging'...\n+done.\n+Cloning into '$pwd/recursivesuper/super/none'...\n+done.\n+Cloning into '$pwd/recursivesuper/super/rebasing'...\n+done.\n+Cloning into '$pwd/recursivesuper/super/submodule'...\n+done.\n+EOF\n+\n test_expect_success 'submodule update --init --recursive from subdirectory' '\n \tgit -C recursivesuper/super reset --hard HEAD^ &&\n \t(cd recursivesuper &&\n \t mkdir tmp &&\n \t cd tmp &&\n-\t git submodule update --init --recursive ../super >../../actual\n+\t git submodule update --init --recursive ../super >../../actual 2>../../actual2\n \t) &&\n-\ttest_cmp expect actual\n+\ttest_cmp expect actual &&\n+\ttest_cmp expect2 actual2\n '\n \n apos=\"'\";\n-- \n2.8.0.41.g8d9aeb3\n"},{"id":"284596","messageId":"1461703833-10350-8-git-send-email-sbeller@google.com","threadId":"42151","inReplyTo":"1461703833-10350-1-git-send-email-sbeller@google.com","subject":"[PATCH 07/15] submodule deinit: loose requirement for giving '.'","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2016-04-26T20:50:25Z","receivedAt":"2016-04-26T20:50:25Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"This is needed later to make a distinction between 'all specified'\nand the default group of submodules.\n\nSigned-off-by: Stefan Beller <sbeller@google.com>\n---\n git-submodule.sh           | 5 -----\n t/t7400-submodule-basic.sh | 1 -\n 2 files changed, 6 deletions(-)\n\ndiff --git a/git-submodule.sh b/git-submodule.sh\nindex d7a5e1a..253ad07 100755\n--- a/git-submodule.sh\n+++ b/git-submodule.sh\n@@ -440,11 +440,6 @@ cmd_deinit()\n \t\tshift\n \tdone\n \n-\tif test $# = 0\n-\tthen\n-\t\tdie \"$(eval_gettext \"Use '.' if you really want to deinitialize all submodules\")\"\n-\tfi\n-\n \tgit submodule--helper list --prefix \"$wt_prefix\" \"$@\" |\n \twhile read mode sha1 stage sm_path\n \tdo\ndiff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh\nindex e9d1d58..ac477b2 100755\n--- a/t/t7400-submodule-basic.sh\n+++ b/t/t7400-submodule-basic.sh\n@@ -932,7 +932,6 @@ test_expect_success 'submodule deinit . deinits all initialized submodules' '\n \tgit submodule update --init &&\n \tgit config submodule.example.foo bar &&\n \tgit config submodule.example2.frotz nitfol &&\n-\ttest_must_fail git submodule deinit &&\n \tgit submodule deinit . >actual &&\n \ttest -z \"$(git config --get-regexp \"submodule\\.example\\.\")\" &&\n \ttest -z \"$(git config --get-regexp \"submodule\\.example2\\.\")\" &&\n-- \n2.8.0.41.g8d9aeb3\n"},{"id":"284604","messageId":"1461703833-10350-9-git-send-email-sbeller@google.com","threadId":"42151","inReplyTo":"1461703833-10350-1-git-send-email-sbeller@google.com","subject":"[PATCH 08/15] submodule--helper list: respect submodule groups","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2016-04-26T20:50:26Z","receivedAt":"2016-04-26T20:50:26Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"As submodule--helper list is the building block for some submodule\ncommands (foreach, deinit, status, sync), also add tests for those.\n\nSigned-off-by: Stefan Beller <sbeller@google.com>\n---\n builtin/submodule--helper.c  | 13 ++++++\n t/t7413-submodule--helper.sh | 97 ++++++++++++++++++++++++++++++++++++++++++++\n 2 files changed, 110 insertions(+)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 7b9a4d7..adb6188 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -271,6 +271,7 @@ static int module_list(int argc, const char **argv, const char *prefix)\n \tint i;\n \tstruct pathspec pathspec;\n \tstruct module_list list = MODULE_LIST_INIT;\n+\tconst struct string_list *group = NULL;\n \n \tstruct option module_list_options[] = {\n \t\tOPT_STRING(0, \"prefix\", &prefix,\n@@ -292,9 +293,21 @@ static int module_list(int argc, const char **argv, const char *prefix)\n \t\treturn 1;\n \t}\n \n+\tif (!pathspec.nr)\n+\t\tgroup = git_config_get_value_multi(\"submodule.defaultGroup\");\n+\tif (group)\n+\t\tgitmodules_config();\n+\n \tfor (i = 0; i < list.nr; i++) {\n \t\tconst struct cache_entry *ce = list.entries[i];\n \n+\t\tif (group) {\n+\t\t\tconst struct submodule *sub =\n+\t\t\t\tsubmodule_from_path(null_sha1, ce->name);\n+\t\t\tif (!submodule_in_group(group, sub))\n+\t\t\t\tcontinue;\n+\t\t}\n+\n \t\tif (ce_stage(ce))\n \t\t\tprintf(\"%06o %s U\\t\", ce->ce_mode, sha1_to_hex(null_sha1));\n \t\telse\ndiff --git a/t/t7413-submodule--helper.sh b/t/t7413-submodule--helper.sh\nindex c6939ab..1b5d135 100755\n--- a/t/t7413-submodule--helper.sh\n+++ b/t/t7413-submodule--helper.sh\n@@ -78,4 +78,101 @@ test_expect_success 'in-group' '\n \t)\n '\n \n+submodule_sha1=$(git -C sub rev-parse HEAD)\n+\n+cat >expect <<-EOF\n+160000 $submodule_sha1 0\tsub0\n+160000 $submodule_sha1 0\tsub1\n+160000 $submodule_sha1 0\tsub3\n+EOF\n+\n+test_expect_success 'submodule--helper list respects groups' '\n+\t(\n+\t\tcd super &&\n+\t\tgit config --add submodule.defaultGroup *bit1 &&\n+\t\tgit config --add submodule.defaultGroup ./sub0 &&\n+\t\tgit submodule--helper list >../actual\n+\t) &&\n+\ttest_cmp expect actual\n+'\n+\n+cat >expect <<-EOF\n+Entering 'sub0'\n+$submodule_sha1 sub0\n+Entering 'sub1'\n+$submodule_sha1 sub1\n+Entering 'sub3'\n+$submodule_sha1 sub3\n+EOF\n+\n+test_expect_success 'submodule foreach respects groups' '\n+\t(\n+\t\tcd super &&\n+\t\tgit submodule foreach \"echo \\$sha1 \\$name\" >../actual\n+\t) &&\n+\ttest_cmp expect actual\n+'\n+\n+sub_priorsha1=$(git -C sub rev-parse HEAD^)\n+\n+cat >expect <<-EOF\n++$sub_priorsha1 sub0 (test)\n++$sub_priorsha1 sub1 (test)\n++$sub_priorsha1 sub3 (test)\n+EOF\n+\n+test_expect_success 'submodule status respects groups' '\n+\tgit clone --recurse-submodules super super_clone &&\n+\t(\n+\t\tcd super_clone &&\n+\t\tgit -C sub0 checkout HEAD^ &&\n+\t\tgit -C sub1 checkout HEAD^ &&\n+\t\tgit -C sub2 checkout HEAD^ &&\n+\t\tgit -C sub3 checkout HEAD^ &&\n+\t\tgit config --add submodule.defaultGroup *bit1 &&\n+\t\tgit config --add submodule.defaultGroup ./sub0 &&\n+\t\tgit submodule status >../actual &&\n+\t\tgit config --unset-all submodule.defaultGroup &&\n+\t\tgit submodule update\n+\t) &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success 'submodule deinit respects groups' '\n+\tsuburl=$(pwd)/sub &&\n+\t(\n+\t\tcd super_clone &&\n+\t\tgit config --add submodule.defaultGroup *bit1 &&\n+\t\tgit config --add submodule.defaultGroup ./sub0 &&\n+\t\tgit submodule deinit &&\n+\t\ttest_must_fail git config submodule.sub0.url &&\n+\t\ttest_must_fail git config submodule.sub1.url &&\n+\t\ttest \"$(git config submodule.sub2.url)\" = \"$suburl\" &&\n+\t\ttest_must_fail git config submodule.sub3.url &&\n+\t\tgit config --unset-all submodule.defaultGroup &&\n+\t\tgit submodule init\n+\t)\n+'\n+\n+test_expect_success 'submodule sync respects groups' '\n+\tsuburl=$(pwd)/sub &&\n+\t(\n+\t\tcd super_clone &&\n+\t\tgit config submodule.sub0.url nonsense &&\n+\t\tgit config submodule.sub1.url nonsense &&\n+\t\tgit config submodule.sub2.url nonsense &&\n+\t\tgit config submodule.sub3.url nonsense &&\n+\t\tgit config --add submodule.defaultGroup *bit1 &&\n+\t\tgit config --add submodule.defaultGroup ./sub0 &&\n+\t\tgit submodule sync &&\n+\t\tgit config --unset-all submodule.defaultGroup &&\n+\t\ttest \"$(git config submodule.sub0.url)\" = \"$suburl\" &&\n+\t\ttest \"$(git config submodule.sub1.url)\" = \"$suburl\" &&\n+\t\ttest \"$(git config submodule.sub2.url)\" = \"nonsense\" &&\n+\t\ttest \"$(git config submodule.sub3.url)\" = \"$suburl\" &&\n+\t\tgit submodule sync sub2 &&\n+\t\ttest \"$(git config submodule.sub2.url)\" = \"$suburl\"\n+\t)\n+'\n+\n test_done\n-- \n2.8.0.41.g8d9aeb3\n"},{"id":"284603","messageId":"1461703833-10350-10-git-send-email-sbeller@google.com","threadId":"42151","inReplyTo":"1461703833-10350-1-git-send-email-sbeller@google.com","subject":"[PATCH 09/15] submodule--helper init: respect submodule groups","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2016-04-26T20:50:27Z","receivedAt":"2016-04-26T20:50:27Z","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  | 19 +++++++++++++++++--\n t/t7413-submodule--helper.sh | 15 +++++++++++++++\n 2 files changed, 32 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex adb6188..29a345e 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -405,6 +405,7 @@ static int module_init(int argc, const char **argv, const char *prefix)\n {\n \tstruct pathspec pathspec;\n \tstruct module_list list = MODULE_LIST_INIT;\n+\tstruct string_list *group = NULL;\n \tint quiet = 0;\n \tint i;\n \n@@ -427,8 +428,22 @@ static int module_init(int argc, const char **argv, const char *prefix)\n \tif (module_list_compute(argc, argv, prefix, &pathspec, &list) < 0)\n \t\treturn 1;\n \n-\tfor (i = 0; i < list.nr; i++)\n-\t\tinit_submodule(list.entries[i]->name, prefix, quiet);\n+\tif (!pathspec.nr)\n+\t\tgroup = string_list_duplicate(\n+\t\t\tgit_config_get_value_multi(\"submodule.defaultGroup\"), 1);\n+\tif (group) {\n+\t\tgitmodules_config();\n+\t\tfor (i = 0; i < list.nr; i++) {\n+\t\t\tconst struct submodule *sub =\n+\t\t\t\tsubmodule_from_path(null_sha1,\n+\t\t\t\t\t\t    list.entries[i]->name);\n+\t\t\tif (submodule_in_group(group, sub))\n+\t\t\t\tinit_submodule(list.entries[i]->name, prefix, quiet);\n+\t\t}\n+\t\tstring_list_clear(group, 1);\n+\t} else\n+\t\tfor (i = 0; i < list.nr; i++)\n+\t\t\tinit_submodule(list.entries[i]->name, prefix, quiet);\n \n \treturn 0;\n }\ndiff --git a/t/t7413-submodule--helper.sh b/t/t7413-submodule--helper.sh\nindex 1b5d135..ef12c63 100755\n--- a/t/t7413-submodule--helper.sh\n+++ b/t/t7413-submodule--helper.sh\n@@ -175,4 +175,19 @@ test_expect_success 'submodule sync respects groups' '\n \t)\n '\n \n+test_expect_success 'submodule--helper init respects groups' '\n+\t(\n+\t\tcd super_clone &&\n+\t\tgit submodule deinit . &&\n+\t\tgit config --add submodule.defaultGroup *bit1 &&\n+\t\tgit config --add submodule.defaultGroup ./sub0 &&\n+\t\tgit submodule init &&\n+\t\tgit config --unset-all submodule.defaultGroup &&\n+\t\ttest \"$(git config submodule.sub0.url)\" = \"$suburl\" &&\n+\t\ttest \"$(git config submodule.sub1.url)\" = \"$suburl\" &&\n+\t\ttest_must_fail git config submodule.sub2.url &&\n+\t\ttest \"$(git config submodule.sub3.url)\" = \"$suburl\"\n+\t)\n+'\n+\n test_done\n-- \n2.8.0.41.g8d9aeb3\n"},{"id":"284595","messageId":"1461703833-10350-11-git-send-email-sbeller@google.com","threadId":"42151","inReplyTo":"1461703833-10350-1-git-send-email-sbeller@google.com","subject":"[PATCH 10/15] submodule--helper update_clone: respect submodule groups","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2016-04-26T20:50:28Z","receivedAt":"2016-04-26T20:50:28Z","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  | 16 ++++++++++++++++\n t/t7413-submodule--helper.sh | 36 ++++++++++++++++++++++++++++++++++++\n 2 files changed, 52 insertions(+)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 29a345e..aa838c5 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -610,6 +610,8 @@ struct submodule_update_clone {\n \n \t/* Machine-readable status lines to be consumed by git-submodule.sh */\n \tstruct string_list projectlines;\n+\t/* The group specification we'll be processing. */\n+\tstruct string_list *group;\n \n \t/* If we want to stop as fast as possible and return an error */\n \tunsigned quickstop : 1;\n@@ -646,6 +648,9 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,\n \n \tsub = submodule_from_path(null_sha1, ce->name);\n \n+\tif (!submodule_in_group(suc->group, sub))\n+\t\tgoto cleanup;\n+\n \tif (suc->recursive_prefix)\n \t\tdisplaypath = relative_path(suc->recursive_prefix,\n \t\t\t\t\t    ce->name, &displaypath_sb);\n@@ -771,6 +776,7 @@ static int update_clone(int argc, const char **argv, const char *prefix)\n \tstruct string_list_item *item;\n \tstruct pathspec pathspec;\n \tstruct submodule_update_clone suc = SUBMODULE_UPDATE_CLONE_INIT;\n+\tstruct string_list actual_group = STRING_LIST_INIT_DUP;\n \n \tstruct option module_update_clone_options[] = {\n \t\tOPT_STRING(0, \"prefix\", &prefix,\n@@ -810,6 +816,16 @@ static int update_clone(int argc, const char **argv, const char *prefix)\n \tif (module_list_compute(argc, argv, prefix, &pathspec, &suc.list) < 0)\n \t\treturn 1;\n \n+\tif (!pathspec.nr) {\n+\t\tconst struct string_list *group =\n+\t\t\tgroup = git_config_get_value_multi(\"submodule.defaultGroup\");\n+\t\tif (group) {\n+\t\t\tfor_each_string_list_item(item, group)\n+\t\t\t\tstring_list_append(&actual_group, item->string);\n+\t\t\tsuc.group = &actual_group;\n+\t\t}\n+\t}\n+\n \tif (pathspec.nr)\n \t\tsuc.warn_if_uninitialized = 1;\n \ndiff --git a/t/t7413-submodule--helper.sh b/t/t7413-submodule--helper.sh\nindex ef12c63..39e469f 100755\n--- a/t/t7413-submodule--helper.sh\n+++ b/t/t7413-submodule--helper.sh\n@@ -190,4 +190,40 @@ test_expect_success 'submodule--helper init respects groups' '\n \t)\n '\n \n+cat >expect <<-EOF\n+160000 $submodule_sha1 0 1\tsub0\n+160000 $submodule_sha1 0 1\tsub1\n+160000 $submodule_sha1 0 1\tsub3\n+EOF\n+\n+test_expect_success 'submodule--helper update-clone respects groups' '\n+\t(\n+\t\tcd super_clone &&\n+\t\tgit submodule init &&\n+\t\tgit config --add submodule.defaultGroup *bit1 &&\n+\t\tgit config --add submodule.defaultGroup ./sub0 &&\n+\t\tgit submodule--helper update-clone >../actual &&\n+\t\tgit config --unset-all submodule.defaultGroup\n+\t) &&\n+\ttest_cmp expect actual\n+'\n+\n+cat >expect <<-EOF\n+Submodule path 'sub0': checked out '$submodule_sha1'\n+Submodule path 'sub1': checked out '$submodule_sha1'\n+Submodule path 'sub3': checked out '$submodule_sha1'\n+EOF\n+\n+test_expect_success 'git submodule update respects groups' '\n+\t(\n+\t\tcd super_clone &&\n+\t\tgit submodule deinit -f . &&\n+\t\tgit config --add submodule.defaultGroup *bit1 &&\n+\t\tgit config --add submodule.defaultGroup ./sub0 &&\n+\t\tgit submodule update --init >../actual &&\n+\t\tgit config --unset-all submodule.defaultGroup\n+\t) &&\n+\ttest_cmp expect actual\n+'\n+\n test_done\n-- \n2.8.0.41.g8d9aeb3\n"},{"id":"284598","messageId":"1461703833-10350-12-git-send-email-sbeller@google.com","threadId":"42151","inReplyTo":"1461703833-10350-1-git-send-email-sbeller@google.com","subject":"[PATCH 11/15] diff: ignore submodules excluded by groups","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2016-04-26T20:50:29Z","receivedAt":"2016-04-26T20:50:29Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"We do not need to do anything special to initialize the `submodule_groups`\npointer as the diff options setup will fill in 0 by default.\n\nSigned-off-by: Stefan Beller <sbeller@google.com>\n---\n diff.c | 3 +++\n diff.h | 1 +\n 2 files changed, 4 insertions(+)\n\ndiff --git a/diff.c b/diff.c\nindex 059123c..5808d8a 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -4921,10 +4921,13 @@ static int is_submodule_ignored(const char *path, struct diff_options *options)\n {\n \tint ignored = 0;\n \tunsigned orig_flags = options->flags;\n+\tconst struct submodule *sub = submodule_from_path(null_sha1, path);\n \tif (!DIFF_OPT_TST(options, OVERRIDE_SUBMODULE_CONFIG))\n \t\tset_diffopt_flags_from_submodule_config(options, path);\n \tif (DIFF_OPT_TST(options, IGNORE_SUBMODULES))\n \t\tignored = 1;\n+\tif (!submodule_in_group(options->submodule_groups, sub))\n+\t\tignored = 1;\n \toptions->flags = orig_flags;\n \treturn ignored;\n }\ndiff --git a/diff.h b/diff.h\nindex e7d68ed..7d499fb 100644\n--- a/diff.h\n+++ b/diff.h\n@@ -178,6 +178,7 @@ struct diff_options {\n \tvoid *output_prefix_data;\n \n \tint diff_path_counter;\n+\tstruct string_list *submodule_groups;\n };\n \n enum color_diff {\n-- \n2.8.0.41.g8d9aeb3\n"},{"id":"284599","messageId":"1461703833-10350-13-git-send-email-sbeller@google.com","threadId":"42151","inReplyTo":"1461703833-10350-1-git-send-email-sbeller@google.com","subject":"[PATCH 12/15] git submodule summary respects groups","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2016-04-26T20:50:30Z","receivedAt":"2016-04-26T20:50:30Z","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 git-submodule.sh             |  5 +++++\n t/t7413-submodule--helper.sh | 26 ++++++++++++++++++++++++++\n 2 files changed, 31 insertions(+)\n\ndiff --git a/git-submodule.sh b/git-submodule.sh\nindex 253ad07..f065b1f 100755\n--- a/git-submodule.sh\n+++ b/git-submodule.sh\n@@ -833,6 +833,11 @@ cmd_summary() {\n \t\tsane_egrep '^:([0-7]* )?160000' |\n \t\twhile read mod_src mod_dst sha1_src sha1_dst status sm_path\n \t\tdo\n+\t\t\t# ignore modules not in group\n+\t\t\tif ! git submodule--helper in-group $sm_path\n+\t\t\tthen\n+\t\t\t\tcontinue\n+\t\t\tfi\n \t\t\t# Always show modules deleted or type-changed (blob<->module)\n \t\t\tif test \"$status\" = D || test \"$status\" = T\n \t\t\tthen\ndiff --git a/t/t7413-submodule--helper.sh b/t/t7413-submodule--helper.sh\nindex 39e469f..d01cdc6 100755\n--- a/t/t7413-submodule--helper.sh\n+++ b/t/t7413-submodule--helper.sh\n@@ -226,4 +226,30 @@ test_expect_success 'git submodule update respects groups' '\n \ttest_cmp expect actual\n '\n \n+range_back=\"$(echo $submodule_sha1|cut -c1-7)...$(echo $sub_priorsha1|cut -c1-7)\"\n+cat >expect <<-EOF\n+* sub0 $range_back (1):\n+  < test2\n+\n+* sub1 $range_back (1):\n+  < test2\n+\n+* sub3 $range_back (1):\n+  < test2\n+\n+EOF\n+\n+test_expect_success 'git submodule summary respects groups' '\n+\t(\n+\t\tcd super_clone &&\n+\t\tgit submodule update --init &&\n+\t\tgit submodule foreach \"git checkout HEAD^\" &&\n+\t\tgit config --add submodule.defaultGroup *bit1 &&\n+\t\tgit config --add submodule.defaultGroup ./sub0 &&\n+\t\tgit submodule summary >../actual &&\n+\t\tgit config --unset-all submodule.defaultGroup\n+\t) &&\n+\ttest_cmp expect actual\n+'\n+\n test_done\n-- \n2.8.0.41.g8d9aeb3\n"},{"id":"284600","messageId":"1461703833-10350-14-git-send-email-sbeller@google.com","threadId":"42151","inReplyTo":"1461703833-10350-1-git-send-email-sbeller@google.com","subject":"[PATCH 13/15] cmd_status: respect submodule groups","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2016-04-26T20:50:31Z","receivedAt":"2016-04-26T20:50:31Z","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/commit.c             |  3 +++\n t/t7413-submodule--helper.sh | 15 +++++++++++++++\n wt-status.c                  |  2 ++\n wt-status.h                  |  1 +\n 4 files changed, 21 insertions(+)\n\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex b3bd2d4..d29134d 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -1369,6 +1369,9 @@ int cmd_status(int argc, const char **argv, const char *prefix)\n \n \ts.is_initial = get_sha1(s.reference, sha1) ? 1 : 0;\n \ts.ignore_submodule_arg = ignore_submodule_arg;\n+\ts.submodule_groups = string_list_duplicate(\n+\t\tgit_config_get_value_multi(\"submodule.defaultGroup\"), 1);\n+\n \twt_status_collect(&s);\n \n \tif (0 <= fd)\ndiff --git a/t/t7413-submodule--helper.sh b/t/t7413-submodule--helper.sh\nindex d01cdc6..a3dbfea 100755\n--- a/t/t7413-submodule--helper.sh\n+++ b/t/t7413-submodule--helper.sh\n@@ -252,4 +252,19 @@ test_expect_success 'git submodule summary respects groups' '\n \ttest_cmp expect actual\n '\n \n+test_expect_success 'git status respects groups' '\n+\t# use setup from previous test\n+\t(\n+\t\tcd super_clone &&\n+\t\tgit config --add submodule.defaultGroup *bit1 &&\n+\t\tgit config --add submodule.defaultGroup ./sub0 &&\n+\t\tgit status >../actual\n+\t\tgit config --unset-all submodule.defaultGroup\n+\t) &&\n+\ttest_i18ngrep \"modified:   sub0\" actual &&\n+\ttest_i18ngrep \"modified:   sub1\" actual &&\n+\ttest_i18ngrep ! \"modified:   sub2\" actual &&\n+\ttest_i18ngrep \"modified:   sub3\" actual\n+'\n+\n test_done\ndiff --git a/wt-status.c b/wt-status.c\nindex ef74864..0d494ac 100644\n--- a/wt-status.c\n+++ b/wt-status.c\n@@ -502,6 +502,7 @@ static void wt_status_collect_changes_worktree(struct wt_status *s)\n \t\tDIFF_OPT_SET(&rev.diffopt, OVERRIDE_SUBMODULE_CONFIG);\n \t\thandle_ignore_submodules_arg(&rev.diffopt, s->ignore_submodule_arg);\n \t}\n+\trev.diffopt.submodule_groups = s->submodule_groups;\n \trev.diffopt.format_callback = wt_status_collect_changed_cb;\n \trev.diffopt.format_callback_data = s;\n \tcopy_pathspec(&rev.prune_data, &s->pathspec);\n@@ -532,6 +533,7 @@ static void wt_status_collect_changes_index(struct wt_status *s)\n \t\t */\n \t\thandle_ignore_submodules_arg(&rev.diffopt, \"dirty\");\n \t}\n+\trev.diffopt.submodule_groups = s->submodule_groups;\n \n \trev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;\n \trev.diffopt.format_callback = wt_status_collect_updated_cb;\ndiff --git a/wt-status.h b/wt-status.h\nindex c9b3b74..d66a2b5 100644\n--- a/wt-status.h\n+++ b/wt-status.h\n@@ -73,6 +73,7 @@ struct wt_status {\n \tstruct string_list change;\n \tstruct string_list untracked;\n \tstruct string_list ignored;\n+\tstruct string_list *submodule_groups;\n \tuint32_t untracked_in_ms;\n };\n \n-- \n2.8.0.41.g8d9aeb3\n"},{"id":"284597","messageId":"1461703833-10350-15-git-send-email-sbeller@google.com","threadId":"42151","inReplyTo":"1461703833-10350-1-git-send-email-sbeller@google.com","subject":"[PATCH 14/15] cmd_diff: respect submodule groups","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2016-04-26T20:50:32Z","receivedAt":"2016-04-26T20:50:32Z","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/diff.c               |  2 ++\n t/t7413-submodule--helper.sh | 15 +++++++++++++++\n 2 files changed, 17 insertions(+)\n\ndiff --git a/builtin/diff.c b/builtin/diff.c\nindex 52c98a9..1c6abd5 100644\n--- a/builtin/diff.c\n+++ b/builtin/diff.c\n@@ -366,6 +366,8 @@ int cmd_diff(int argc, const char **argv, const char *prefix)\n \n \tsetup_diff_pager(&rev.diffopt);\n \n+\trev.diffopt.submodule_groups = string_list_duplicate(\n+\t\tgit_config_get_value_multi(\"submodule.defaultGroup\"), 1);\n \t/*\n \t * Do we have --cached and not have a pending object, then\n \t * default to HEAD by hand.  Eek.\ndiff --git a/t/t7413-submodule--helper.sh b/t/t7413-submodule--helper.sh\nindex a3dbfea..1ca7878 100755\n--- a/t/t7413-submodule--helper.sh\n+++ b/t/t7413-submodule--helper.sh\n@@ -267,4 +267,19 @@ test_expect_success 'git status respects groups' '\n \ttest_i18ngrep \"modified:   sub3\" actual\n '\n \n+test_expect_success 'git diff respects groups' '\n+\t# use setup from previous test\n+\t(\n+\t\tcd super_clone &&\n+\t\tgit config --add submodule.defaultGroup *bit1 &&\n+\t\tgit config --add submodule.defaultGroup ./sub0 &&\n+\t\tgit diff >../actual\n+\t\tgit config --unset-all submodule.defaultGroup\n+\t) &&\n+\ttest_i18ngrep \"diff --git a/sub0 b/sub0\" actual &&\n+\ttest_i18ngrep \"diff --git a/sub1 b/sub1\" actual &&\n+\ttest_i18ngrep ! \"diff --git a/sub2 b/sub2\" actual &&\n+\ttest_i18ngrep \"diff --git a/sub3 b/sub3\" actual\n+'\n+\n test_done\n-- \n2.8.0.41.g8d9aeb3\n"},{"id":"284601","messageId":"1461703833-10350-16-git-send-email-sbeller@google.com","threadId":"42151","inReplyTo":"1461703833-10350-1-git-send-email-sbeller@google.com","subject":"[PATCH 15/15] clone: allow specification of submodules to be cloned","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2016-04-26T20:50:33Z","receivedAt":"2016-04-26T20:50:33Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"This is in line with clone being the contraction of\n    mkdir <path> && cd <path>\n    git init\n    git config\n    git fetch\n    git submodule update\n\nSigned-off-by: Stefan Beller <sbeller@google.com>\n---\n Documentation/git-clone.txt |  6 +++\n builtin/clone.c             | 40 +++++++++++++++++--\n t/t7400-submodule-basic.sh  | 96 +++++++++++++++++++++++++++++++++++++++++++++\n 3 files changed, 139 insertions(+), 3 deletions(-)\n\ndiff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt\nindex 45d74be..38b1948 100644\n--- a/Documentation/git-clone.txt\n+++ b/Documentation/git-clone.txt\n@@ -212,6 +212,12 @@ objects from the source repository into a pack in the cloned repository.\n \trepository does not have a worktree/checkout (i.e. if any of\n \t`--no-checkout`/`-n`, `--bare`, or `--mirror` is given)\n \n+--init-submodule::\n+\tAfter the repository is cloned, specified submodules are cloned.\n+\tIt is possible to give multiple specifications by repeating the\n+\targument. This option will be recorded in the repository config\n+\tas `submodule.defaultGroup`.\n+\n --separate-git-dir=<git dir>::\n \tInstead of placing the cloned repository where it is supposed\n \tto be, place the cloned repository at the specified directory,\ndiff --git a/builtin/clone.c b/builtin/clone.c\nindex 6576ecf..8371bc2 100644\n--- a/builtin/clone.c\n+++ b/builtin/clone.c\n@@ -52,6 +52,22 @@ static struct string_list option_config;\n static struct string_list option_reference;\n static int option_dissociate;\n static int max_jobs = -1;\n+static struct string_list init_submodules;\n+\n+static int init_submodules_cb(const struct option *opt, const char *arg, int unset)\n+{\n+\tstruct string_list_item *item;\n+\tstruct string_list sl = STRING_LIST_INIT_DUP;\n+\n+\tif (unset)\n+\t\treturn -1;\n+\n+\tstring_list_split(&sl, arg, ',', -1);\n+\tfor_each_string_list_item(item, &sl)\n+\t\tstring_list_append((struct string_list *)opt->value, item->string);\n+\n+\treturn 0;\n+}\n \n static struct option builtin_clone_options[] = {\n \tOPT__VERBOSITY(&option_verbosity),\n@@ -100,6 +116,8 @@ static struct option builtin_clone_options[] = {\n \t\t\tTRANSPORT_FAMILY_IPV4),\n \tOPT_SET_INT('6', \"ipv6\", &family, N_(\"use IPv6 addresses only\"),\n \t\t\tTRANSPORT_FAMILY_IPV6),\n+\tOPT_CALLBACK(0, \"init-submodule\", &init_submodules, N_(\"string\"),\n+\t\t\tN_(\"clone specific submodules\"), init_submodules_cb),\n \tOPT_END()\n };\n \n@@ -731,17 +749,24 @@ static int checkout(void)\n \terr |= run_hook_le(NULL, \"post-checkout\", sha1_to_hex(null_sha1),\n \t\t\t   sha1_to_hex(sha1), \"1\", NULL);\n \n-\tif (!err && option_recursive) {\n+\tif (err)\n+\t\tgoto out;\n+\n+\tif (option_recursive || init_submodules.nr > 0) {\n \t\tstruct argv_array args = ARGV_ARRAY_INIT;\n-\t\targv_array_pushl(&args, \"submodule\", \"update\", \"--init\", \"--recursive\", NULL);\n+\t\targv_array_pushl(&args, \"submodule\", \"update\", NULL);\n \n+\t\tif (option_recursive) {\n+\t\t\targv_array_pushf(&args, \"--init\");\n+\t\t\targv_array_pushf(&args, \"--recursive\");\n+\t\t}\n \t\tif (max_jobs != -1)\n \t\t\targv_array_pushf(&args, \"--jobs=%d\", max_jobs);\n \n \t\terr = run_command_v_opt(args.argv, RUN_GIT_CMD);\n \t\targv_array_clear(&args);\n \t}\n-\n+out:\n \treturn err;\n }\n \n@@ -876,6 +901,15 @@ int cmd_clone(int argc, const char **argv, const char *prefix)\n \t\toption_no_checkout = 1;\n \t}\n \n+\tif (init_submodules.nr > 0) {\n+\t\tstruct string_list_item *item;\n+\t\tstruct strbuf sb = STRBUF_INIT;\n+\t\tfor_each_string_list_item(item, &init_submodules) {\n+\t\t\tstrbuf_addf(&sb, \"submodule.defaultGroup=%s\", item->string);\n+\t\t\tstring_list_append(&option_config, strbuf_detach(&sb, 0));\n+\t\t}\n+\t}\n+\n \tif (!option_origin)\n \t\toption_origin = \"origin\";\n \ndiff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh\nindex ac477b2..1fd313b 100755\n--- a/t/t7400-submodule-basic.sh\n+++ b/t/t7400-submodule-basic.sh\n@@ -1110,4 +1110,100 @@ test_expect_success 'submodule add records multiple labels' '\n \ttest_cmp expected actual\n '\n \n+cat <<EOF > expected\n+submodule\n+EOF\n+\n+test_expect_success 'clone --init-submodule works' '\n+\ttest_when_finished \"rm -rf super super_clone\" &&\n+\tmkdir super &&\n+\tpwd=$(pwd) &&\n+\t(\n+\t\tcd super &&\n+\t\tgit init &&\n+\t\tgit submodule add --label labelA file://\"$pwd\"/example2 submodule &&\n+\t\tgit submodule add file://\"$pwd\"/example2 submodule1 &&\n+\t\tgit commit -a -m \"create repository with 2 submodules, one is in a group\"\n+\t) &&\n+\tgit clone --recurse-submodules --init-submodule \\*labelA super super_clone &&\n+\t(\n+\t\tcd super_clone &&\n+\t\tgit submodule status |cut -c1,42-52 | tr -d \" \" >../actual\n+\t) &&\n+\ttest_cmp actual expected\n+'\n+\n+cat <<EOF > expect\n+submoduleA\n+submoduleC\n+submoduleE\n+EOF\n+\n+test_expect_success 'clone with multiple --init-submodule options' '\n+\ttest_when_finished \"rm -rf super super_clone\" &&\n+\tmkdir super &&\n+\tpwd=$(pwd) &&\n+\t(\n+\t\tcd super &&\n+\t\tgit init &&\n+\t\tgit submodule add --label groupA file://\"$pwd\"/example2 submoduleA &&\n+\t\tgit submodule add --label groupB file://\"$pwd\"/example2 submoduleB &&\n+\t\tgit submodule add --label groupC file://\"$pwd\"/example2 submoduleC &&\n+\t\tgit submodule add --label groupD --name submoduleE file://\"$pwd\"/example2 submoduleD &&\n+\t\tgit submodule add --label groupE --name submoduleD file://\"$pwd\"/example2 submoduleE &&\n+\t\tgit submodule add file://\"$pwd\"/example2 submodule1 &&\n+\t\tgit commit -a -m \"create repository with submodules groups\"\n+\t) &&\n+\tgit clone --recurse-submodules --init-submodule=\\*groupA --init-submodule ./submoduleC --init-submodule :submoduleD super super_clone &&\n+\t(\n+\t\tcd super_clone &&\n+\t\tgit submodule status |cut -c1,42-52 | tr -d \" \" >../actual\n+\t) &&\n+\ttest_cmp expect actual\n+'\n+\n+cat <<EOF > expect\n+submoduleA\n+EOF\n+\n+cat <<EOF > expect2\n+submoduleA\n+submoduleC\n+EOF\n+\n+test_expect_success 'clone and subsequent updates correctly auto-initialize submodules' '\n+\ttest_when_finished \"rm -rf super super_clone\" &&\n+\tmkdir super &&\n+\tpwd=$(pwd) &&\n+\t(\n+\t\tcd super &&\n+\t\tgit init &&\n+\t\tgit submodule add --label LA file://\"$pwd\"/example2 submoduleA &&\n+\t\tgit submodule add file://\"$pwd\"/example2 submoduleB &&\n+\t\tgit commit -a -m \"create repository with submodules groups\"\n+\t) &&\n+\tgit clone --recurse-submodules --init-submodule=\\*LA super super_clone &&\n+\t(\n+\t\tcd super_clone &&\n+\t\tgit submodule status |cut -c1,42-52 | tr -d \" \" >../actual\n+\t) &&\n+\ttest_cmp expect actual &&\n+\t(\n+\t\tcd super &&\n+\t\tgit init &&\n+\t\tgit submodule add --label LA file://\"$pwd\"/example2 submoduleC &&\n+\t\tgit commit -a -m \"add another labled submodule\"\n+\t) &&\n+\t(\n+\t\tcd super_clone &&\n+\t\t# obtain the new superproject\n+\t\tgit pull &&\n+\t\t# submoduleC should just appear as it has the label LA\n+\t\t# which was configured in git clone\n+\t\tgit submodule update --init &&\n+\t\tgit submodule status |cut -c1,42-52 | tr -d \" \" >../actual\n+\t) &&\n+\ttest_cmp expect2 actual\n+'\n+\n test_done\n-- \n2.8.0.41.g8d9aeb3\n"},{"id":"284612","messageId":"xmqqshy8c8s2.fsf@gitster.mtv.corp.google.com","threadId":"42151","inReplyTo":"1461703833-10350-1-git-send-email-sbeller@google.com","subject":"Re: [PATCH 00/15] submodule groups (once again)","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-04-26T22:19:57Z","receivedAt":"2016-04-26T22:19:57Z","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> git diff is supposed to view the differences between \"what would I\n> get after checkout\" (i.e. what is in the index run through smudge filters)\n> compared to the actual worktree.\n\nI do not think it affects your conclusion, but the above is wrong.\n\"git diff\" is a preview of what you would add (i.e. what will be in\nthe index after passing working tree contents via the clean filter)\nrelative to what is actually in the index.\n"},{"id":"284613","messageId":"xmqqoa8wc8hl.fsf@gitster.mtv.corp.google.com","threadId":"42151","inReplyTo":"1461703833-10350-1-git-send-email-sbeller@google.com","subject":"Re: [PATCH 00/15] submodule groups (once again)","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-04-26T22:26:14Z","receivedAt":"2016-04-26T22:26: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> What is this series about?\n> ==========================\n>\n> If you have lots of submodules, you probably don't need all of them at once, \n> but you have functional units. Some submodules are absolutely required, \n> some are optional and only for very specific purposes. \n>\n> This patch series adds labels to submodules in the .gitmodules file. \n>\n> So you could have a .gitmodules file such as: \n>\n> [submodule \"gcc\"] \n>         path = gcc \n>         url = git://... \n>         label = default\n>         label = devel \n> [submodule \"linux\"] \n>         path = linux \n>         url = git://... \n>         label = default \n> [submodule \"nethack\"] \n>         path = nethack \n>         url = git://... \n>         label = optional\n>         label = games \n>\n> and by this series you can work on an arbitrary group of these submodules\n> composed by the labels, names or paths of the submodules.\n>\n>     git clone --recurse-submodules --init-submodule=label --init-submodule=label2   git://... \n>     # will clone the superproject and recursively \n>     # checkout any submodule being labeled label or label2\n>     \n>     git submodule add --label <name> git://... ..\n>     # record a label while adding a submodule\n>     \n>     git config submodule.defaultGroups default\n>     git config --add submodule.defaultGroups devel\n>     # configure which submodules you are interested in.\n>     \n>     git submodule update\n>     # update only the submodules in the default group if that is configured.\n>     \n>     git status\n>     git diff\n>     git submodule summary\n>     # show only changes to submodules which are in the default group.\n\nNicely designed.\n"},{"id":"284614","messageId":"xmqqh9eoc7zc.fsf@gitster.mtv.corp.google.com","threadId":"42151","inReplyTo":"1461703833-10350-2-git-send-email-sbeller@google.com","subject":"Re: [PATCH 01/15] string_list: add string_list_duplicate","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-04-26T22:37:11Z","receivedAt":"2016-04-26T22:37: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> The result of git_config_get_value_multi do not seem to be stable and\n> may get overwritten. Have an easy way to preserve the results of that\n> query.\n>\n> Signed-off-by: Stefan Beller <sbeller@google.com>\n> ---\n\nThis morning I reviewed a patch that adds something whose name ends\nwith _copy(), and this may want to follow suit.\n\nShould strdup_strings() be a separate parameter, or should it follow\nwhat src->strdup_strings has?\n\n\"Do not seem to be stable\" does not build confidence in the code,\nmaking it sound as if the developer is basing his work on guess not\nanalysis, and makes it hard to tell if this is a wrong workaround to\na valid issue (e.g. it could be \"making the result stable\" is what\nwe want in the longer term) or a valid solution to a problem that\nwould be common across callers of that API.\n\n>  string-list.c | 18 ++++++++++++++++++\n>  string-list.h |  2 ++\n>  2 files changed, 20 insertions(+)\n>\n> diff --git a/string-list.c b/string-list.c\n> index 2a32a3f..f981c8a 100644\n> --- a/string-list.c\n> +++ b/string-list.c\n> @@ -7,6 +7,24 @@ void string_list_init(struct string_list *list, int strdup_strings)\n>  \tlist->strdup_strings = strdup_strings;\n>  }\n>  \n> +struct string_list *string_list_duplicate(const struct string_list *src,\n> +\t\t\t\t\t  int strdup_strings)\n> +{\n> +\tstruct string_list *list;\n> +\tstruct string_list_item *item;\n> +\n> +\tif (!src)\n> +\t\treturn NULL;\n> +\n> +\tlist = xmalloc(sizeof(*list));\n> +\tstring_list_init(list, strdup_strings);\n> +\tfor_each_string_list_item(item, src)\n> +\t\tstring_list_append(list, item->string);\n> +\n> +\treturn list;\n> +}\n> +\n> +\n>  /* if there is no exact match, point to the index where the entry could be\n>   * inserted */\n>  static int get_entry_index(const struct string_list *list, const char *string,\n> diff --git a/string-list.h b/string-list.h\n> index d3809a1..1a5612f 100644\n> --- a/string-list.h\n> +++ b/string-list.h\n> @@ -19,6 +19,8 @@ struct string_list {\n>  #define STRING_LIST_INIT_DUP   { NULL, 0, 0, 1, NULL }\n>  \n>  void string_list_init(struct string_list *list, int strdup_strings);\n> +struct string_list *string_list_duplicate(const struct string_list *src,\n> +\t\t\t\t\t  int strdup_strings);\n>  \n>  void print_string_list(const struct string_list *p, const char *text);\n>  void string_list_clear(struct string_list *list, int free_util);\n"},{"id":"284615","messageId":"xmqqd1pcc7r4.fsf@gitster.mtv.corp.google.com","threadId":"42151","inReplyTo":"1461703833-10350-3-git-send-email-sbeller@google.com","subject":"Re: [PATCH 02/15] submodule doc: write down what we want to achieve in this series","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-04-26T22:42:07Z","receivedAt":"2016-04-26T22:42:07Z","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> +When operating on submodules you can either give paths to specify the\n> +desired submodules or give no paths at all to apply the command to the\n> +default group of submodules.\n\nSo, \"git submodule foo path1 path2\" would act on path1 and path2 but\nwould omit path3.  If you have path1 and path3 but not path2 in the\ndefault group, and do not give any path, i.e. \"git submodule foo\",\nit would act on path1 and path3 but would omit path2.\n\nOK so far.\n\n> +By default all submodules are included in\n> +the default group.\n\nSo if you do not do anything special, i.e. do not define any group,\n\"git submodule foo\" would act on path1, path2 and path3.\n\nI think that is in line with the way how module_list aka\n\"submodule--helper list\" works.\n\n> +You can change the default group by configuring\n> +submodule.defaultGroup. Once the default group is configured any\n> +submodule operation without a specified set of submodules will use\n> +the default group as the set to operate on.\n> +\n>  Submodules are composed from a so-called `gitlink` tree entry\n>  in the main repository that refers to a particular commit object\n>  within the inner repository that is completely separate.\n"},{"id":"284616","messageId":"xmqq7ffkc7e9.fsf@gitster.mtv.corp.google.com","threadId":"42151","inReplyTo":"1461703833-10350-4-git-send-email-sbeller@google.com","subject":"Re: [PATCH 03/15] submodule add: label submodules if asked to","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-04-26T22:49:50Z","receivedAt":"2016-04-26T22:49:50Z","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> When adding new submodules, you can specify the\n> label(s) the submodule belongs to by giving one or more\n> --label arguments. This will record each label in the\n> .gitmodules file as a value of the key\n> \"submodule.$NAME.label\".\n>\n> Signed-off-by: Stefan Beller <sbeller@google.com>\n> ---\n>  Documentation/git-submodule.txt |  5 ++++-\n>  git-submodule.sh                | 14 +++++++++++++-\n>  t/t7400-submodule-basic.sh      | 32 ++++++++++++++++++++++++++++++++\n>  3 files changed, 49 insertions(+), 2 deletions(-)\n>\n> diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt\n> index 8c4bbe2..349ead8 100644\n> --- a/Documentation/git-submodule.txt\n> +++ b/Documentation/git-submodule.txt\n> @@ -9,7 +9,7 @@ git-submodule - Initialize, update or inspect submodules\n>  SYNOPSIS\n>  --------\n>  [verse]\n> -'git submodule' [--quiet] add [-b <branch>] [-f|--force] [--name <name>]\n> +'git submodule' [--quiet] add [-b <branch>] [-f|--force] [-l|--label <label>]\n>  \t      [--reference <repository>] [--depth <depth>] [--] <repository> [<path>]\n>  'git submodule' [--quiet] status [--cached] [--recursive] [--] [<path>...]\n>  'git submodule' [--quiet] init [--] [<path>...]\n> @@ -109,6 +109,9 @@ is the superproject and submodule repositories will be kept\n>  together in the same relative location, and only the\n>  superproject's URL needs to be provided: git-submodule will correctly\n>  locate the submodule using the relative URL in .gitmodules.\n> ++\n> +If at least one label argument was given, all labels are recorded in the\n> +.gitmodules file in the label fields.\n\nI think this is better without \"If ... given,\".\n\nI am not sure if it is sensible to make \"label\" namespace always\nglobal to be shared with the project by updating .gitmodules,\nthough (it can cut both ways, so this is not an objection).\n\n> @@ -165,6 +166,13 @@ cmd_add()\n>  \t\t--depth=*)\n>  \t\t\tdepth=$1\n>  \t\t\t;;\n> +\t\t-l|--label)\n> +\t\t\tlabels=\"${labels} $2\"\n> +\t\t\tshift\n> +\t\t\t;;\n> +\t\t--label=*)\n> +\t\t\tlabels=\"${labels} ${1#--label=}\"\n> +\t\t\t;;\n>  \t\t--)\n>  \t\t\tshift\n>  \t\t\tbreak\n> @@ -292,6 +300,10 @@ Use -f if you really want to add it.\" >&2\n>  \n>  \tgit config -f .gitmodules submodule.\"$sm_name\".path \"$sm_path\" &&\n>  \tgit config -f .gitmodules submodule.\"$sm_name\".url \"$repo\" &&\n> +\tfor label in $labels\n> +\tdo\n> +\t\tgit config --add -f .gitmodules submodule.\"$sm_name\".label \"${label}\"\n> +\tdone &&\n\nIs the acceptable syntax for \"label\" defined and documented\nsomewhere?\n\nI didn't see it in the documentation patch.  I am seeing that we do\nnot allow $IFS whitespaces in them, but are there other restrictions\nwe want to enforce?  Remember, starting with narrow and widening as\nwe discover the need is the right way to design things.  Once we\nstart allowing random strings, it is very hard to later reject some\nto carve out namespace for ourselves.\n\nThe above implementation happens to allow users to say\n\n\tgit submodule add -l \"labelA labelB\" -- $there $path\n\nand give two labels to the module, and that will be something you\nend up needing to support forever, unless you restrict early.\n"},{"id":"284617","messageId":"CA+P7+xrPYHEoLPNbGaSDSniHUCLeqj+d85ei3T_uwnBmz68G1g@mail.gmail.com","threadId":"42151","inReplyTo":"1461703833-10350-4-git-send-email-sbeller@google.com","subject":"Re: [PATCH 03/15] submodule add: label submodules if asked to","fromName":"Jacob Keller","fromEmail":"jacob.keller@gmail.com","sentAt":"2016-04-26T22:50:59Z","receivedAt":"2016-04-26T22:50:59Z","isPatch":true,"sender":{"key":"jacob.keller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/874719?v=4"},"body":"On Tue, Apr 26, 2016 at 1:50 PM, Stefan Beller <sbeller@google.com> wrote:\n> When adding new submodules, you can specify the\n> label(s) the submodule belongs to by giving one or more\n> --label arguments. This will record each label in the\n> .gitmodules file as a value of the key\n> \"submodule.$NAME.label\".\n>\n\nOk so labels will be in the .gitmodules file. This means that if we go\nback in history using git bisect or something similar, we'll\npotentially change what the default submodules are for example?\n\nThis is sort of why having some submodule data appear in the\n.git/config file is useful since it helps keep things like the remote\nurl safe from being updated when doing this sort of thing.\n\nI am not sure if labels will be that important in this case?\n\nThanks,\nJake\n"},{"id":"284619","messageId":"xmqq37q8c6zz.fsf@gitster.mtv.corp.google.com","threadId":"42151","inReplyTo":"1461703833-10350-6-git-send-email-sbeller@google.com","subject":"Re: [PATCH 05/15] submodule-config: check if submodule a submodule is in a group","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-04-26T22:58:24Z","receivedAt":"2016-04-26T22:58:24Z","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> diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\n> index b6d4f27..23d7224 100644\n> --- a/builtin/submodule--helper.c\n> +++ b/builtin/submodule--helper.c\n> @@ -814,6 +814,46 @@ static int update_clone(int argc, const char **argv, const char *prefix)\n>  \treturn 0;\n>  }\n>  \n> +int in_group(int argc, const char **argv, const char *prefix)\n\nIt is inconceivable that \"submodule group\" will be the only user of\nthe concept whose name is \"group\".  Please do not give such a\ngeneric name to a helper function that is specific to \"submodule\ngroup\" and make it global.  Naming a file-scope static helper\nfunction as in_group() is perfectly fine; it is clear that such a\nfunction in submodule--helper.c is about submodule group.\n\n> +\tif (!group)\n> +\t\tlist = git_config_get_value_multi(\"submodule.defaultGroup\");\n> +\telse {\n> +\t\tstring_list_split(&actual_list, group, ',', -1);\n> +\t\tlist = &actual_list;\n\nHmm, where did this syntax to use comma-separated things come from?\nDid I miss it in 02/15?\n\n> +\tif (sub->labels) {\n> +\t\tstruct string_list_item *item;\n> +\t\tfor_each_string_list_item(item, sub->labels) {\n> +\t\t\tstrbuf_reset(&sb);\n> +\t\t\tstrbuf_addf(&sb, \"*%s\", item->string);\n> +\t\t\tif (string_list_has_string(group, sb.buf)) {\n> +\t\t\t\tmatched = 1;\n> +\t\t\t\tbreak;\n> +\t\t\t}\n> +\t\t}\n> +\t}\n> +\tif (sub->path) {\n> +\t\t/*\n> +\t\t * NEEDSWORK: This currently works only for\n> +\t\t * exact paths, but we want to enable\n> +\t\t * inexact matches such wildcards.\n> +\t\t */\n> +\t\tstrbuf_reset(&sb);\n> +\t\tstrbuf_addf(&sb, \"./%s\", sub->path);\n> +\t\tif (string_list_has_string(group, sb.buf))\n> +\t\t\tmatched = 1;\n> +\t}\n> +\tif (sub->name) {\n> +\t\t/*\n> +\t\t * NEEDSWORK: Same as with path. Do we want to\n> +\t\t * support wildcards or such?\n> +\t\t */\n> +\t\tstrbuf_reset(&sb);\n> +\t\tstrbuf_addf(&sb, \":%s\", sub->name);\n> +\t\tif (string_list_has_string(group, sb.buf))\n> +\t\t\tmatched = 1;\n> +\t}\n> +\tstrbuf_release(&sb);\n\nI see room for bikeshedding here, but the material to bikeshed\naround is not even documented yet ;-)\n\n * a token prefixed with '*' is a label.\n * a token prefixed with './' is a path.\n * a token prefixed with ':' is a name.\n\nHopefully I will see some description like that in later patches.\nI'll read on.\n"},{"id":"284620","messageId":"xmqqvb34arjj.fsf@gitster.mtv.corp.google.com","threadId":"42151","inReplyTo":"xmqq37q8c6zz.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH 05/15] submodule-config: check if submodule a submodule is in a group","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-04-26T23:17:36Z","receivedAt":"2016-04-26T23:17:36Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> I see room for bikeshedding here, but the material to bikeshed\n> around is not even documented yet ;-)\n>\n>  * a token prefixed with '*' is a label.\n>  * a token prefixed with './' is a path.\n>  * a token prefixed with ':' is a name.\n>\n> Hopefully I will see some description like that in later patches.\n> I'll read on.\n\nExtending this on a bit, I would suggest tweaking the above slightly\nand make the rule more like this:\n\n  * a token prefixed with '*' is a label.\n\n  * a token prefixed with ':' is a name.\n\n  * everything else is a path, but \"./\" at the front is skipped,\n    which can be used to disambiguate an unfortunate path that\n    begins with ':' or '*'.\n\nA bigger thing I am wondering is if it is bettter to do _without_\nadding a new --group=X option everywhere.  I am assuming that most\nif not all submodule subcommands already use \"module_list\" aka\n\"submodule--helper list\" that takes paths, and to them, extending\nthat interface to also understand the groups and names would be a\nmore natural way to extend the UI, no?  e.g.\n\n\t$ git submodule update -- 'path1' 'path2'\n        $ git submodule update -- '*default'\n        $ git submodule update -- ':named'\n\ninstead of\n\n\t$ git submodule update -- 'path1 'path2'\n        $ git submodule update --group='*default' --\n        $ git submodule update --group=':named' --\n\nwhich special-cases the way to specify a set of submodules by\nlisting their paths.\n"},{"id":"284621","messageId":"CAGZ79kZfGVhMweP_Sqx1dSAif6L46dneXgKYtEozNuxxay5TOg@mail.gmail.com","threadId":"42151","inReplyTo":"CA+P7+xrPYHEoLPNbGaSDSniHUCLeqj+d85ei3T_uwnBmz68G1g@mail.gmail.com","subject":"Re: [PATCH 03/15] submodule add: label submodules if asked to","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2016-04-26T23:19:04Z","receivedAt":"2016-04-26T23:19:04Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Tue, Apr 26, 2016 at 3:50 PM, Jacob Keller <jacob.keller@gmail.com> wrote:\n> On Tue, Apr 26, 2016 at 1:50 PM, Stefan Beller <sbeller@google.com> wrote:\n>> When adding new submodules, you can specify the\n>> label(s) the submodule belongs to by giving one or more\n>> --label arguments. This will record each label in the\n>> .gitmodules file as a value of the key\n>> \"submodule.$NAME.label\".\n>>\n>\n> Ok so labels will be in the .gitmodules file. This means that if we go\n> back in history using git bisect or something similar, we'll\n> potentially change what the default submodules are for example?\n\nGood point! Yes that's exactly what we want.\n\nConsider this:\nWe have:\n    libA\n    libB\n\nNow libB grows a lot and someone decides to split it up into\n2 libraries, so we'll have:\n    libA\n    libB-small\n    libC-was-part-of-B\n\nAs libB (the big one repo containing all the code) was no open source,\nwe can deprecate it fast and just keep developing in libB-small and\nlibC-was-part-of-B. As we do only small changes at a time, we'll keep\nthose 2 in the same label set, so the users can pick up the changes via\n\n    git submodule update\n    #  libB-small and  libC-was-part-of-B are in both the same group,\ne.g. default\n    # so they will be checked out.\n\nWhen a bug is found in the future, you'd use `git bisect` to find it.\nIn a repository with no\nsubmodules (analogy: think of splitting a file in two. Checking out\nolder revisions\nwill give the one old file, checking out newer revisions will give 2 new files.)\nthat works great. With submodules we want to have the same properties.\n\n    git checkout tag-before-libB-split\n    git submodule update\n    # get libB checked out\n\n    git checkout tag-after-libB-split\n    git submodule update\n    # get libB-small and libC-was-part-of-B checked out\n\nIdeally (read: in a later patch series), checkout will automatically\ncheckout submodules for you if you have configured `submodule.updateOnCheckout`,\nsuch that switching old and new revisions will add or delete\nsubmodules automatically.\n\n>\n> This is sort of why having some submodule data appear in the\n> .git/config file is useful since it helps keep things like the remote\n> url safe from being updated when doing this sort of thing.\n\n(Unrelated, but my thoughts on this)\nThe remote url mechanism is broken with the .gitmodules file in some use cases:\nConsider there is an upstream \"kernel.org\" which hosts a repository with\nsubmodules. Now you want to mirror that superproject to \"kernel.mymirror.org\"\nand you start with\n\n    git clone --mirror git://kernel.org/superproject\n\nWhen the superproject uses relative URLs for the submodules, this will\nbreak your mirror,\nif you did not mirror them exactly with the same relative path. Then\ncloning from\nyour mirror will result in broken submodule URLs.\n\nSo you would want an additional mechanism for URLs. Jonathan came up\nwith the idea of having another configuration file in a refs/submodules/config\nbranch which essentially allows to annotate/enhance the .gitmodules file.\n\nSo in such a configuration you could say:\n\n    defaultRelativeURLBase = kernel.org\n    [submodule.\"foo\"]\n        relativeURLBase = kernel.mymirror.org\n        protocol = ssh\n        # ssh as opposed to git:// which was inherited from the superproject\n\nwhich allows finer controls of submodule/repository mirroring.\nAs the refs/submodule/configuration is not part of the history of the\nsuperproject,\nmirroring can be done without changing history, but still having URLs changed to\nthe internal mirror.\n\n>\n> I am not sure if labels will be that important in this case?\n\nI am not sure. If it turns out to be a problem, maybe we can\nintroduce a hook, that will be called on adding new submodules via lables?\n\nThanks,\nStefan\n\n>\n> Thanks,\n> Jake\n"},{"id":"284624","messageId":"CA+P7+xpMhH+dU3y6ueGZ+1oRWdwE+9yt1u6CqJSSpq4f-0ta5Q@mail.gmail.com","threadId":"42151","inReplyTo":"CAGZ79kZfGVhMweP_Sqx1dSAif6L46dneXgKYtEozNuxxay5TOg@mail.gmail.com","subject":"Re: [PATCH 03/15] submodule add: label submodules if asked to","fromName":"Jacob Keller","fromEmail":"jacob.keller@gmail.com","sentAt":"2016-04-27T03:24:32Z","receivedAt":"2016-04-27T03:24:32Z","isPatch":true,"sender":{"key":"jacob.keller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/874719?v=4"},"body":"On Tue, Apr 26, 2016 at 4:19 PM, Stefan Beller <sbeller@google.com> wrote:\n> On Tue, Apr 26, 2016 at 3:50 PM, Jacob Keller <jacob.keller@gmail.com> wrote:\n>> On Tue, Apr 26, 2016 at 1:50 PM, Stefan Beller <sbeller@google.com> wrote:\n>>> When adding new submodules, you can specify the\n>>> label(s) the submodule belongs to by giving one or more\n>>> --label arguments. This will record each label in the\n>>> .gitmodules file as a value of the key\n>>> \"submodule.$NAME.label\".\n>>>\n>>\n>> Ok so labels will be in the .gitmodules file. This means that if we go\n>> back in history using git bisect or something similar, we'll\n>> potentially change what the default submodules are for example?\n>\n> Good point! Yes that's exactly what we want.\n>\n\nOk. That makes sense.\n\n> Ideally (read: in a later patch series), checkout will automatically\n> checkout submodules for you if you have configured `submodule.updateOnCheckout`,\n> such that switching old and new revisions will add or delete\n> submodules automatically.\n>\n\nThis is something I definitely would like to be able to tell people.\n\n>>\n>> This is sort of why having some submodule data appear in the\n>> .git/config file is useful since it helps keep things like the remote\n>> url safe from being updated when doing this sort of thing.\n>\n> (Unrelated, but my thoughts on this)\n> The remote url mechanism is broken with the .gitmodules file in some use cases:\n> Consider there is an upstream \"kernel.org\" which hosts a repository with\n> submodules. Now you want to mirror that superproject to \"kernel.mymirror.org\"\n> and you start with\n>\n>     git clone --mirror git://kernel.org/superproject\n>\n> When the superproject uses relative URLs for the submodules, this will\n> break your mirror,\n> if you did not mirror them exactly with the same relative path. Then\n> cloning from\n> your mirror will result in broken submodule URLs.\n>\n> So you would want an additional mechanism for URLs. Jonathan came up\n> with the idea of having another configuration file in a refs/submodules/config\n> branch which essentially allows to annotate/enhance the .gitmodules file.\n>\n\nI like the idea of refs/submodules/config.\n\n> So in such a configuration you could say:\n>\n>     defaultRelativeURLBase = kernel.org\n>     [submodule.\"foo\"]\n>         relativeURLBase = kernel.mymirror.org\n>         protocol = ssh\n>         # ssh as opposed to git:// which was inherited from the superproject\n>\n> which allows finer controls of submodule/repository mirroring.\n> As the refs/submodule/configuration is not part of the history of the\n> superproject,\n> mirroring can be done without changing history, but still having URLs changed to\n> the internal mirror.\n>\n>>\n>> I am not sure if labels will be that important in this case?\n>\n> I am not sure. If it turns out to be a problem, maybe we can\n> introduce a hook, that will be called on adding new submodules via lables?\n>\n> Thanks,\n> Stefan\n>\n>>\n>> Thanks,\n>> Jake\n"},{"id":"284700","messageId":"CAGZ79kbWMN3YG5Jtz8i8Y9A3id8bX-YxSWp19+yGAdzMX_wKKA@mail.gmail.com","threadId":"42151","inReplyTo":"xmqqh9eoc7zc.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH 01/15] string_list: add string_list_duplicate","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2016-04-27T18:02:29Z","receivedAt":"2016-04-27T18:02:29Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Tue, Apr 26, 2016 at 3:37 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> Stefan Beller <sbeller@google.com> writes:\n>\n>> The result of git_config_get_value_multi do not seem to be stable and\n>> may get overwritten. Have an easy way to preserve the results of that\n>> query.\n>>\n>> Signed-off-by: Stefan Beller <sbeller@google.com>\n>> ---\n>\n> This morning I reviewed a patch that adds something whose name ends\n> with _copy(), and this may want to follow suit.\n\nok, in case we need this patch, I'll rename.\n\n>\n> Should strdup_strings() be a separate parameter, or should it follow\n> what src->strdup_strings has?\n>\n> \"Do not seem to be stable\" does not build confidence in the code,\n> making it sound as if the developer is basing his work on guess not\n> analysis, and makes it hard to tell if this is a wrong workaround to\n> a valid issue (e.g. it could be \"making the result stable\" is what\n> we want in the longer term) or a valid solution to a problem that\n> would be common across callers of that API.\n\nWhen not duplicating git_config_get_value_multi(\"submodule.defaultGroup\");\nI run into\n\nProgram received signal SIGSEGV, Segmentation fault.\n0x0000000000579097 in get_entry_index (list=0x876848, string=0x8721e0\n\"./submodule1\", exact_match=0x7fffffffd6bc) at string-list.c:38\n38 int compare = cmp(string, list->items[middle].string);\n(gdb) bt\n#0  0x0000000000579097 in get_entry_index (list=0x876848,\nstring=0x8721e0 \"./submodule1\", exact_match=0x7fffffffd6bc) at\nstring-list.c:38\n#1  0x00000000005792d5 in string_list_has_string (list=0x876848,\nstring=0x8721e0 \"./submodule1\") at string-list.c:91\n#2  0x000000000057e78c in submodule_in_group (group=0x876848,\nsub=0x878510) at submodule-config.c:558\n#3  0x0000000000497cf9 in module_init (argc=0, argv=0x7fffffffdb28,\nprefix=0x0) at builtin/submodule--helper.c:441\n#4  0x00000000004993f6 in cmd_submodule__helper (argc=2,\nargv=0x7fffffffdb20, prefix=0x0) at builtin/submodule--helper.c:927\n#5  0x000000000040582e in run_builtin (p=0x83c0c0 <commands+2400>,\nargc=2, argv=0x7fffffffdb20) at git.c:353\n#6  0x0000000000405a1d in handle_builtin (argc=2, argv=0x7fffffffdb20)\nat git.c:540\n#7  0x0000000000405b3f in run_argv (argcp=0x7fffffffd9fc,\nargv=0x7fffffffda10) at git.c:594\n#8  0x0000000000405d32 in main (argc=2, av=0x7fffffffdb18) at git.c:701\n(gdb) print list->items[middle].string\nCannot access memory at address 0x746c006fd40bd151\n\nSo the string list seems to be corrupted here.\nSomeone stomping over our memory? How long is the result\nof git_config_get_value_multi deemed to be stable and usable?\n\nI did not find out myself how to properly answer these.\nSo it was symptom based programming (copying that stuff makes the\nerror go away).\n\nThis only happens in one code path, which is\n        group = NULL;\n        if (!pathspec.nr)\n                group = //string_list_duplicate(\n                        (struct string_list*)\n\ngit_config_get_value_multi(\"submodule.defaultGroup\");//, 1);\n        if (group) {\n                gitmodules_config();\n                for (i = 0; i < list.nr; i++) {\n                        const struct submodule *sub =\n                                submodule_from_path(null_sha1,\n                                                    list.entries[i]->name);\n                        if (submodule_in_group(group, sub))\n                                init_submodule(list.entries[i]->name,\nprefix, quiet);\n                }\n        }\n        ... // group is not further used\n\nMaybe gitmodules_config needs to be called before git_config_get_value_multi,\nas it changes that?\n\nI dunno, will debug more later.\n\nThanks,\nStefan\n\n\n\n\n>\n>>  string-list.c | 18 ++++++++++++++++++\n>>  string-list.h |  2 ++\n>>  2 files changed, 20 insertions(+)\n>>\n>> diff --git a/string-list.c b/string-list.c\n>> index 2a32a3f..f981c8a 100644\n>> --- a/string-list.c\n>> +++ b/string-list.c\n>> @@ -7,6 +7,24 @@ void string_list_init(struct string_list *list, int strdup_strings)\n>>       list->strdup_strings = strdup_strings;\n>>  }\n>>\n>> +struct string_list *string_list_duplicate(const struct string_list *src,\n>> +                                       int strdup_strings)\n>> +{\n>> +     struct string_list *list;\n>> +     struct string_list_item *item;\n>> +\n>> +     if (!src)\n>> +             return NULL;\n>> +\n>> +     list = xmalloc(sizeof(*list));\n>> +     string_list_init(list, strdup_strings);\n>> +     for_each_string_list_item(item, src)\n>> +             string_list_append(list, item->string);\n>> +\n>> +     return list;\n>> +}\n>> +\n>> +\n>>  /* if there is no exact match, point to the index where the entry could be\n>>   * inserted */\n>>  static int get_entry_index(const struct string_list *list, const char *string,\n>> diff --git a/string-list.h b/string-list.h\n>> index d3809a1..1a5612f 100644\n>> --- a/string-list.h\n>> +++ b/string-list.h\n>> @@ -19,6 +19,8 @@ struct string_list {\n>>  #define STRING_LIST_INIT_DUP   { NULL, 0, 0, 1, NULL }\n>>\n>>  void string_list_init(struct string_list *list, int strdup_strings);\n>> +struct string_list *string_list_duplicate(const struct string_list *src,\n>> +                                       int strdup_strings);\n>>\n>>  void print_string_list(const struct string_list *p, const char *text);\n>>  void string_list_clear(struct string_list *list, int free_util);\n"},{"id":"284748","messageId":"xmqqzise7o4l.fsf@gitster.mtv.corp.google.com","threadId":"42151","inReplyTo":"CAGZ79kbWMN3YG5Jtz8i8Y9A3id8bX-YxSWp19+yGAdzMX_wKKA@mail.gmail.com","subject":"Re: [PATCH 01/15] string_list: add string_list_duplicate","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-04-27T21:11:54Z","receivedAt":"2016-04-27T21:11:54Z","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> When not duplicating git_config_get_value_multi(\"submodule.defaultGroup\");\n> I run into\n>\n> Program received signal SIGSEGV, Segmentation fault.\n> ...\n> So the string list seems to be corrupted here.\n> Someone stomping over our memory? How long is the result\n> of git_config_get_value_multi deemed to be stable and usable?\n\nThat call goes to\n\n    git_config_get_value_multi()\n    -> git_configset_get_value_multi()\n       -> configset_find_element()\n\nthe returned value from there would be either NULL or the list of\nvalues that belong to the config cache layer, i.e. a caller of the\nAPI can peek but is not allowed to modify it.\n\nSo if you are modifying the value you obtain from the API, you must\nmake a copy; otherwise you will \"stomp over\" memory that belongs to\nthe config cache layer, not to you.\n"},{"id":"284750","messageId":"CAGZ79kagX5TJU_mbjpo4PKJDoc1wh24DhyS814Kkq76EU9aykA@mail.gmail.com","threadId":"42151","inReplyTo":"xmqqzise7o4l.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH 01/15] string_list: add string_list_duplicate","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2016-04-27T21:17:34Z","receivedAt":"2016-04-27T21:17:34Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Wed, Apr 27, 2016 at 2:11 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> Stefan Beller <sbeller@google.com> writes:\n>\n>> When not duplicating git_config_get_value_multi(\"submodule.defaultGroup\");\n>> I run into\n>>\n>> Program received signal SIGSEGV, Segmentation fault.\n>> ...\n>> So the string list seems to be corrupted here.\n>> Someone stomping over our memory? How long is the result\n>> of git_config_get_value_multi deemed to be stable and usable?\n>\n> That call goes to\n>\n>     git_config_get_value_multi()\n>     -> git_configset_get_value_multi()\n>        -> configset_find_element()\n>\n> the returned value from there would be either NULL or the list of\n> values that belong to the config cache layer, i.e. a caller of the\n> API can peek but is not allowed to modify it.\n>\n> So if you are modifying the value you obtain from the API, you must\n> make a copy; otherwise you will \"stomp over\" memory that belongs to\n> the config cache layer, not to you.\n\nYes, we do not modify the string_list (the return of git_config_get_value_multi)\n\nAnother way to corrupt it is to change the configuration (e.g. add\nthings to the config hashmap such that it reallocates and grows).\n\nThe problem arises after a call to submodule_from_path(...);\nwhich may change the cache for submodules. I assumed that was\ncompletely different from the regular config cache, but somehow there is\na relation, which I have not tracked down yet.\n\nThanks,\nStefan\n"},{"id":"284761","messageId":"CAGZ79kZRf=fTbPh5_Qx8dHfiD9gxeDhQqvqDnyZRrMfv_adHXQ@mail.gmail.com","threadId":"42151","inReplyTo":"xmqqvb34arjj.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH 05/15] submodule-config: check if submodule a submodule is in a group","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2016-04-27T23:00:12Z","receivedAt":"2016-04-27T23:00:12Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Tue, Apr 26, 2016 at 4:17 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> Junio C Hamano <gitster@pobox.com> writes:\n>\n>> I see room for bikeshedding here, but the material to bikeshed\n>> around is not even documented yet ;-)\n>>\n>>  * a token prefixed with '*' is a label.\n>>  * a token prefixed with './' is a path.\n>>  * a token prefixed with ':' is a name.\n>>\n>> Hopefully I will see some description like that in later patches.\n>> I'll read on.\n>\n> Extending this on a bit, I would suggest tweaking the above slightly\n> and make the rule more like this:\n>\n>   * a token prefixed with '*' is a label.\n>\n>   * a token prefixed with ':' is a name.\n>\n>   * everything else is a path, but \"./\" at the front is skipped,\n>     which can be used to disambiguate an unfortunate path that\n>     begins with ':' or '*'.\n>\n> A bigger thing I am wondering is if it is bettter to do _without_\n> adding a new --group=X option everywhere.  I am assuming that most\n> if not all submodule subcommands already use \"module_list\" aka\n> \"submodule--helper list\" that takes paths, and to them, extending\n> that interface to also understand the groups and names would be a\n> more natural way to extend the UI, no?  e.g.\n>\n>         $ git submodule update -- 'path1' 'path2'\n>         $ git submodule update -- '*default'\n>         $ git submodule update -- ':named'\n>\n> instead of\n>\n>         $ git submodule update -- 'path1 'path2'\n>         $ git submodule update --group='*default' --\n>         $ git submodule update --group=':named' --\n>\n> which special-cases the way to specify a set of submodules by\n> listing their paths.\n\nThis is indeed a better way.\n\nCurrently there is no way to initialize another group as that group\nspecified by submodule.defaultGroup. But having the possibility\nto use the grouping in such a way is more flexible.\n\nThanks,\nStefan\n"},{"id":"284762","messageId":"xmqqbn4u7ibp.fsf@gitster.mtv.corp.google.com","threadId":"42151","inReplyTo":"CAGZ79kagX5TJU_mbjpo4PKJDoc1wh24DhyS814Kkq76EU9aykA@mail.gmail.com","subject":"Re: [PATCH 01/15] string_list: add string_list_duplicate","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-04-27T23:17:14Z","receivedAt":"2016-04-27T23:17: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> Another way to corrupt it is to change the configuration (e.g. add\n> things to the config hashmap such that it reallocates and grows).\n\nYou're right.  But doesn't it hint that there is a deeper problem?\n\nBy making a copy and keeping it, you would hold onto a stale value\nand would not see the result of updates you yourself make to the\nsystem.\n"},{"id":"284763","messageId":"CAGZ79kYRhk8bH7+rGRjfvwk=HHy8=Yfg_P54pp8Goeb-bO1wSw@mail.gmail.com","threadId":"42151","inReplyTo":"xmqqbn4u7ibp.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH 01/15] string_list: add string_list_duplicate","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2016-04-27T23:24:41Z","receivedAt":"2016-04-27T23:24:41Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Wed, Apr 27, 2016 at 4:17 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> Stefan Beller <sbeller@google.com> writes:\n>\n>> Another way to corrupt it is to change the configuration (e.g. add\n>> things to the config hashmap such that it reallocates and grows).\n>\n> You're right.  But doesn't it hint that there is a deeper problem?\n>\n> By making a copy and keeping it, you would hold onto a stale value\n> and would not see the result of updates you yourself make to the\n> system.\n>\n\nIn this case the value doesn't go stale. We do not change\n\"submodule.defaultGroup\", but only new submodule.$NAME.url\nand such. The memory for accessing it goes stale, so in this case\nit is okay. I don't think we want to see repeated calls to\ngit_config_get_value_multi\nlike :\n\n        if (!pathspec.nr && git_config_get_value_multi(\n                        \"submodule.defaultGroup\")) {\n                gitmodules_config();\n                for (i = 0; i < list.nr; i++) {\n                        const struct submodule *sub =\n                                submodule_from_path(null_sha1,\n                                                    list.entries[i]->name);\n                        group =\ngit_config_get_value_multi(\"submodule.defaultGroup\")\n                        if (submodule_in_group(group, sub))\n                                init_submodule(list.entries[i]->name,\nprefix, quiet);\n                }\n        }\n\nMaybe I am overestimating the cost of git_config_get_value_multi, so it is no\nproblem?\n\nThanks,\nStefan\n"},{"id":"284962","messageId":"xmqqy47wxocr.fsf@gitster.mtv.corp.google.com","threadId":"42151","inReplyTo":"1461703833-10350-7-git-send-email-sbeller@google.com","subject":"Re: [PATCH 06/15] submodule init: redirect stdout to stderr","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-04-29T18:27:00Z","receivedAt":"2016-04-29T18:27:00Z","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> Reroute the output of stdout to stderr as it is just informative\n> messages, not to be consumed by machines.\n>\n> We want to init submodules from the helper for `submodule update`\n> in a later patch and the stdout output of said helper is consumed\n> by the parts of `submodule update` which are still written in shell.\n> So we have to be careful which messages are on stdout.\n>\n> Signed-off-by: Stefan Beller <sbeller@google.com>\n> ---\n\nI do not mind if this step is split out and queued as a separate\nfollow-up to sb/submodule-init.  The grouping and labelling is a\nbigger and more important change that deserves attention without\ndistraction than this single step, and making as many such things\ngraduate and allowing us to forget about them is better ;-)\n\n>  builtin/submodule--helper.c |  3 ++-\n>  t/t7406-submodule-update.sh | 24 ++++++++++++++++++------\n>  2 files changed, 20 insertions(+), 7 deletions(-)\n>\n> diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\n> index 23d7224..7b9a4d7 100644\n> --- a/builtin/submodule--helper.c\n> +++ b/builtin/submodule--helper.c\n> @@ -362,7 +362,8 @@ static void init_submodule(const char *path, const char *prefix, int quiet)\n>  \t\t\tdie(_(\"Failed to register url for submodule path '%s'\"),\n>  \t\t\t    displaypath);\n>  \t\tif (!quiet)\n> -\t\t\tprintf(_(\"Submodule '%s' (%s) registered for path '%s'\\n\"),\n> +\t\t\tfprintf(stderr,\n> +\t\t\t\t_(\"Submodule '%s' (%s) registered for path '%s'\\n\"),\n>  \t\t\t\tsub->name, url, displaypath);\n>  \t}\n>  \n> diff --git a/t/t7406-submodule-update.sh b/t/t7406-submodule-update.sh\n> index fd741f5..5f27879 100755\n> --- a/t/t7406-submodule-update.sh\n> +++ b/t/t7406-submodule-update.sh\n> @@ -108,24 +108,36 @@ pwd=$(pwd)\n>  \n>  cat <<EOF >expect\n>  Submodule path '../super': checked out '$supersha1'\n> -Submodule 'merging' ($pwd/merging) registered for path '../super/merging'\n> -Submodule 'none' ($pwd/none) registered for path '../super/none'\n> -Submodule 'rebasing' ($pwd/rebasing) registered for path '../super/rebasing'\n> -Submodule 'submodule' ($pwd/submodule) registered for path '../super/submodule'\n>  Submodule path '../super/merging': checked out '$mergingsha1'\n>  Submodule path '../super/none': checked out '$nonesha1'\n>  Submodule path '../super/rebasing': checked out '$rebasingsha1'\n>  Submodule path '../super/submodule': checked out '$submodulesha1'\n>  EOF\n>  \n> +cat <<EOF >expect2\n> +Submodule 'merging' ($pwd/merging) registered for path '../super/merging'\n> +Submodule 'none' ($pwd/none) registered for path '../super/none'\n> +Submodule 'rebasing' ($pwd/rebasing) registered for path '../super/rebasing'\n> +Submodule 'submodule' ($pwd/submodule) registered for path '../super/submodule'\n> +Cloning into '$pwd/recursivesuper/super/merging'...\n> +done.\n> +Cloning into '$pwd/recursivesuper/super/none'...\n> +done.\n> +Cloning into '$pwd/recursivesuper/super/rebasing'...\n> +done.\n> +Cloning into '$pwd/recursivesuper/super/submodule'...\n> +done.\n> +EOF\n> +\n>  test_expect_success 'submodule update --init --recursive from subdirectory' '\n>  \tgit -C recursivesuper/super reset --hard HEAD^ &&\n>  \t(cd recursivesuper &&\n>  \t mkdir tmp &&\n>  \t cd tmp &&\n> -\t git submodule update --init --recursive ../super >../../actual\n> +\t git submodule update --init --recursive ../super >../../actual 2>../../actual2\n>  \t) &&\n> -\ttest_cmp expect actual\n> +\ttest_cmp expect actual &&\n> +\ttest_cmp expect2 actual2\n>  '\n>  \n>  apos=\"'\";\n"},{"id":"284963","messageId":"xmqqtwikxobl.fsf@gitster.mtv.corp.google.com","threadId":"42151","inReplyTo":"1461703833-10350-8-git-send-email-sbeller@google.com","subject":"Re: [PATCH 07/15] submodule deinit: loose requirement for giving '.'","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-04-29T18:27:42Z","receivedAt":"2016-04-29T18:27:42Z","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> This is needed later to make a distinction between 'all specified'\n> and the default group of submodules.\n\ns/loose/lose/;\n\nAgain, this can be separated as an independent preliminary clean-up.\n\n\n>\n> Signed-off-by: Stefan Beller <sbeller@google.com>\n> ---\n>  git-submodule.sh           | 5 -----\n>  t/t7400-submodule-basic.sh | 1 -\n>  2 files changed, 6 deletions(-)\n>\n> diff --git a/git-submodule.sh b/git-submodule.sh\n> index d7a5e1a..253ad07 100755\n> --- a/git-submodule.sh\n> +++ b/git-submodule.sh\n> @@ -440,11 +440,6 @@ cmd_deinit()\n>  \t\tshift\n>  \tdone\n>  \n> -\tif test $# = 0\n> -\tthen\n> -\t\tdie \"$(eval_gettext \"Use '.' if you really want to deinitialize all submodules\")\"\n> -\tfi\n> -\n>  \tgit submodule--helper list --prefix \"$wt_prefix\" \"$@\" |\n>  \twhile read mode sha1 stage sm_path\n>  \tdo\n> diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh\n> index e9d1d58..ac477b2 100755\n> --- a/t/t7400-submodule-basic.sh\n> +++ b/t/t7400-submodule-basic.sh\n> @@ -932,7 +932,6 @@ test_expect_success 'submodule deinit . deinits all initialized submodules' '\n>  \tgit submodule update --init &&\n>  \tgit config submodule.example.foo bar &&\n>  \tgit config submodule.example2.frotz nitfol &&\n> -\ttest_must_fail git submodule deinit &&\n>  \tgit submodule deinit . >actual &&\n>  \ttest -z \"$(git config --get-regexp \"submodule\\.example\\.\")\" &&\n>  \ttest -z \"$(git config --get-regexp \"submodule\\.example2\\.\")\" &&\n"},{"id":"284964","messageId":"xmqqpot8xo4h.fsf@gitster.mtv.corp.google.com","threadId":"42151","inReplyTo":"1461703833-10350-9-git-send-email-sbeller@google.com","subject":"Re: [PATCH 08/15] submodule--helper list: respect submodule groups","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-04-29T18:31:58Z","receivedAt":"2016-04-29T18:31:58Z","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> As submodule--helper list is the building block for some submodule\n> commands (foreach, deinit, status, sync), also add tests for those.\n\nThe title is slightly misleading, isn't it?\n\nThis step only teaches the commands to limit the operation to the\ndefaultGroup instead of operating on everybody.  There is no\nmechanism (yet) to ask for arbitrary group(s) from the command line,\nwhich was my expectation of \"respecting submodule groups\", i.e. \"the\nonly way to limit the operation to subset of submodules used to be\nby giving pathspecs to match, but now a more general submodule group\nmechanism can be used\" is yet to come at this point in the series.\n"},{"id":"284965","messageId":"xmqqlh3wxnuq.fsf@gitster.mtv.corp.google.com","threadId":"42151","inReplyTo":"1461703833-10350-12-git-send-email-sbeller@google.com","subject":"Re: [PATCH 11/15] diff: ignore submodules excluded by groups","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-04-29T18:37:49Z","receivedAt":"2016-04-29T18:37:49Z","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> We do not need to do anything special to initialize the `submodule_groups`\n> pointer as the diff options setup will fill in 0 by default.\n>\n> Signed-off-by: Stefan Beller <sbeller@google.com>\n> ---\n>  diff.c | 3 +++\n>  diff.h | 1 +\n>  2 files changed, 4 insertions(+)\n\nIsn't this going in the opposite way from what you described in 0/15\nwith analogy to how \"ignore\" mechanism works?  Just like a path is\ntracked once it is tracked, whether it matches an ignore pattern,\nshouldn't we be getting a summary for a submodule for any submodule\nonce submodule/.git/HEAD is there (i.e. we can give a comparison),\nwhether it is specified by a separate mechanism that acts from\nsideways (e.g. the \"default group\").\n\n> diff --git a/diff.c b/diff.c\n> index 059123c..5808d8a 100644\n> --- a/diff.c\n> +++ b/diff.c\n> @@ -4921,10 +4921,13 @@ static int is_submodule_ignored(const char *path, struct diff_options *options)\n>  {\n>  \tint ignored = 0;\n>  \tunsigned orig_flags = options->flags;\n> +\tconst struct submodule *sub = submodule_from_path(null_sha1, path);\n>  \tif (!DIFF_OPT_TST(options, OVERRIDE_SUBMODULE_CONFIG))\n>  \t\tset_diffopt_flags_from_submodule_config(options, path);\n>  \tif (DIFF_OPT_TST(options, IGNORE_SUBMODULES))\n>  \t\tignored = 1;\n> +\tif (!submodule_in_group(options->submodule_groups, sub))\n> +\t\tignored = 1;\n>  \toptions->flags = orig_flags;\n>  \treturn ignored;\n>  }\n> diff --git a/diff.h b/diff.h\n> index e7d68ed..7d499fb 100644\n> --- a/diff.h\n> +++ b/diff.h\n> @@ -178,6 +178,7 @@ struct diff_options {\n>  \tvoid *output_prefix_data;\n>  \n>  \tint diff_path_counter;\n> +\tstruct string_list *submodule_groups;\n>  };\n>  \n>  enum color_diff {\n"},{"id":"284967","messageId":"xmqqh9ekxntn.fsf@gitster.mtv.corp.google.com","threadId":"42151","inReplyTo":"1461703833-10350-13-git-send-email-sbeller@google.com","subject":"Re: [PATCH 12/15] git submodule summary respects groups","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-04-29T18:38:28Z","receivedAt":"2016-04-29T18:38:28Z","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> Signed-off-by: Stefan Beller <sbeller@google.com>\n> ---\n\nSame comment as 11/15 applies here.\n\n>  git-submodule.sh             |  5 +++++\n>  t/t7413-submodule--helper.sh | 26 ++++++++++++++++++++++++++\n>  2 files changed, 31 insertions(+)\n>\n> diff --git a/git-submodule.sh b/git-submodule.sh\n> index 253ad07..f065b1f 100755\n> --- a/git-submodule.sh\n> +++ b/git-submodule.sh\n> @@ -833,6 +833,11 @@ cmd_summary() {\n>  \t\tsane_egrep '^:([0-7]* )?160000' |\n>  \t\twhile read mod_src mod_dst sha1_src sha1_dst status sm_path\n>  \t\tdo\n> +\t\t\t# ignore modules not in group\n> +\t\t\tif ! git submodule--helper in-group $sm_path\n> +\t\t\tthen\n> +\t\t\t\tcontinue\n> +\t\t\tfi\n>  \t\t\t# Always show modules deleted or type-changed (blob<->module)\n"},{"id":"284966","messageId":"CAGZ79kawUMng_hPju3MDW2xFmKkhqOQMVihFTA+7Wt0EaNdpug@mail.gmail.com","threadId":"42151","inReplyTo":"xmqqy47wxocr.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH 06/15] submodule init: redirect stdout to stderr","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2016-04-29T18:38:32Z","receivedAt":"2016-04-29T18:38:32Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Fri, Apr 29, 2016 at 11:27 AM, Junio C Hamano <gitster@pobox.com> wrote:\n> Stefan Beller <sbeller@google.com> writes:\n>\n>> Reroute the output of stdout to stderr as it is just informative\n>> messages, not to be consumed by machines.\n>>\n>> We want to init submodules from the helper for `submodule update`\n>> in a later patch and the stdout output of said helper is consumed\n>> by the parts of `submodule update` which are still written in shell.\n>> So we have to be careful which messages are on stdout.\n>>\n>> Signed-off-by: Stefan Beller <sbeller@google.com>\n>> ---\n>\n> I do not mind if this step is split out and queued as a separate\n> follow-up to sb/submodule-init.  The grouping and labelling is a\n> bigger and more important change that deserves attention without\n> distraction than this single step, and making as many such things\n> graduate and allowing us to forget about them is better ;-)\n\nCare to apply this onto the sb/submodule-init then?\n\n(It applies cleanly for me on top of \"submodule--helper update-clone:\nabort gracefully on missing .gitmodules\")\n\nI'll drop this patch in the groups series.\n\nThanks,\nStefan\n\n>\n>>  builtin/submodule--helper.c |  3 ++-\n>>  t/t7406-submodule-update.sh | 24 ++++++++++++++++++------\n>>  2 files changed, 20 insertions(+), 7 deletions(-)\n>>\n>> diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\n>> index 23d7224..7b9a4d7 100644\n>> --- a/builtin/submodule--helper.c\n>> +++ b/builtin/submodule--helper.c\n>> @@ -362,7 +362,8 @@ static void init_submodule(const char *path, const char *prefix, int quiet)\n>>                       die(_(\"Failed to register url for submodule path '%s'\"),\n>>                           displaypath);\n>>               if (!quiet)\n>> -                     printf(_(\"Submodule '%s' (%s) registered for path '%s'\\n\"),\n>> +                     fprintf(stderr,\n>> +                             _(\"Submodule '%s' (%s) registered for path '%s'\\n\"),\n>>                               sub->name, url, displaypath);\n>>       }\n>>\n>> diff --git a/t/t7406-submodule-update.sh b/t/t7406-submodule-update.sh\n>> index fd741f5..5f27879 100755\n>> --- a/t/t7406-submodule-update.sh\n>> +++ b/t/t7406-submodule-update.sh\n>> @@ -108,24 +108,36 @@ pwd=$(pwd)\n>>\n>>  cat <<EOF >expect\n>>  Submodule path '../super': checked out '$supersha1'\n>> -Submodule 'merging' ($pwd/merging) registered for path '../super/merging'\n>> -Submodule 'none' ($pwd/none) registered for path '../super/none'\n>> -Submodule 'rebasing' ($pwd/rebasing) registered for path '../super/rebasing'\n>> -Submodule 'submodule' ($pwd/submodule) registered for path '../super/submodule'\n>>  Submodule path '../super/merging': checked out '$mergingsha1'\n>>  Submodule path '../super/none': checked out '$nonesha1'\n>>  Submodule path '../super/rebasing': checked out '$rebasingsha1'\n>>  Submodule path '../super/submodule': checked out '$submodulesha1'\n>>  EOF\n>>\n>> +cat <<EOF >expect2\n>> +Submodule 'merging' ($pwd/merging) registered for path '../super/merging'\n>> +Submodule 'none' ($pwd/none) registered for path '../super/none'\n>> +Submodule 'rebasing' ($pwd/rebasing) registered for path '../super/rebasing'\n>> +Submodule 'submodule' ($pwd/submodule) registered for path '../super/submodule'\n>> +Cloning into '$pwd/recursivesuper/super/merging'...\n>> +done.\n>> +Cloning into '$pwd/recursivesuper/super/none'...\n>> +done.\n>> +Cloning into '$pwd/recursivesuper/super/rebasing'...\n>> +done.\n>> +Cloning into '$pwd/recursivesuper/super/submodule'...\n>> +done.\n>> +EOF\n>> +\n>>  test_expect_success 'submodule update --init --recursive from subdirectory' '\n>>       git -C recursivesuper/super reset --hard HEAD^ &&\n>>       (cd recursivesuper &&\n>>        mkdir tmp &&\n>>        cd tmp &&\n>> -      git submodule update --init --recursive ../super >../../actual\n>> +      git submodule update --init --recursive ../super >../../actual 2>../../actual2\n>>       ) &&\n>> -     test_cmp expect actual\n>> +     test_cmp expect actual &&\n>> +     test_cmp expect2 actual2\n>>  '\n>>\n>>  apos=\"'\";\n"},{"id":"284969","messageId":"CAGZ79kaOXxqDEqVnf5K3QjXg5bfmKW2XkmPT-mqJ93+RF5N40g@mail.gmail.com","threadId":"42151","inReplyTo":"xmqqlh3wxnuq.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH 11/15] diff: ignore submodules excluded by groups","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2016-04-29T19:17:43Z","receivedAt":"2016-04-29T19:17:43Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Fri, Apr 29, 2016 at 11:37 AM, Junio C Hamano <gitster@pobox.com> wrote:\n> Stefan Beller <sbeller@google.com> writes:\n>\n>> We do not need to do anything special to initialize the `submodule_groups`\n>> pointer as the diff options setup will fill in 0 by default.\n>>\n>> Signed-off-by: Stefan Beller <sbeller@google.com>\n>> ---\n>>  diff.c | 3 +++\n>>  diff.h | 1 +\n>>  2 files changed, 4 insertions(+)\n>\n> Isn't this going in the opposite way from what you described in 0/15\n> with analogy to how \"ignore\" mechanism works?  Just like a path is\n> tracked once it is tracked, whether it matches an ignore pattern,\n> shouldn't we be getting a summary for a submodule for any submodule\n> once submodule/.git/HEAD is there (i.e. we can give a comparison),\n> whether it is specified by a separate mechanism that acts from\n> sideways (e.g. the \"default group\").\n\nThat is why I started in 0/15 with\n> One pain point I am still aware of:\nas I did not do the right thing in these patches?\nThese patches do however:\n\n>    git status\n>    git diff\n>    git submodule summary\n>    # show only changes to submodules which are in the default group.\n\nwhich seems to be the wrong thing then.\n\nSo here is a thought experiment:\n\n    # get all submodules into the work tree\n    git submodule update --recursive --init\n\n    # The selected default group will not include all submodules\n    git config submodule.defaultGroup \"*SomeLabel\"\n\n    git status\n    # What do we expect now?\n    # either a \"nothing to commit, working directory clean\"\n    # or rather what was described in 0/15:\n\n        More than 2 submodules (123 actually) including\n            'path/foo'\n            'lib/baz'\n        are checked out, but not part of the default group.\n        You can add these submodules via\n            git config --add submodule.defaultGroup ./path/foo\n            git config --add submodule.defaultGroup ./lib/baz\n\nIf we want to go with the second option, the design described in 0/15\nis broken. Going one step further:\n\n    # in all submodules including the excluded via groups,\n    # by resetting the groups for this command\n    git -c submodule.defaultGroup= submodule foreach git reset --hard HEAD^\n\n    git status\n    # Reporting the changes from submodules in the default Group is\nuncontroversial:\n    On branch master\n    Your branch is up-to-date with 'origin/master'.\n    Changes not staged for commit:\n      (use \"git add <file>...\" to update what will be committed)\n      (use \"git checkout -- <file>...\" to discard changes in working directory)\n\n        modified:   subA (new commits)\n        modified:   subB (new commits)\n\n    no changes added to commit (use \"git add\" and/or \"git commit -a\")\n\n    # But what about subC which is not in the default group? It was\nchanged as well.\n    # one thing I could imagine, is similar to above:\n\n        More than 2 submodules (123 actually) including\n            modified:    'subC'  (new commits)\n            modified:   'lib/baz' (new commits)\n        are checked out, but not part of the default group.\n        You can add these submodules via\n            git config --add submodule.defaultGroup ./path/foo\n            git config --add submodule.defaultGroup ./lib/baz\n\n    # and the remaining 121 submodules are not reported in git status\n\n    git diff\n    # report them all below:\n    diff --git a/subA b/subA\n    index e4e79a2..6689f08 160000\n    --- a/subA\n    +++ b/subA\n    @@ -1 +1 @@\n    -Subproject commit e4e79a217576d24ef4d73b620766f62b155bcd98\n    +Subproject commit 6689f08735d08a057f8d6f91af98b04960afa517\n    ...\n     # goes on including 123 submodule not in the default group.\n\n\nIn case we report these submodules which are checked out but not in\nthe default group, we probably want to adapt \"git submodule update\" to\nun-checkout the work tree of the submodules in case they are clean.\n\nThanks,\nStefan\n"},{"id":"285594","messageId":"CAGZ79ka37jWYDJrAWy5KLhaaJmrLRbmTzRC6A5DneuE63+XCeQ@mail.gmail.com","threadId":"42151","inReplyTo":"CAGZ79kaOXxqDEqVnf5K3QjXg5bfmKW2XkmPT-mqJ93+RF5N40g@mail.gmail.com","subject":"Re: [PATCH 11/15] diff: ignore submodules excluded by groups","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2016-05-05T19:57:25Z","receivedAt":"2016-05-05T19:57:25Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"Any thoughts on my thoughts below?\n\nOn Fri, Apr 29, 2016 at 12:17 PM, Stefan Beller <sbeller@google.com> wrote:\n> On Fri, Apr 29, 2016 at 11:37 AM, Junio C Hamano <gitster@pobox.com> wrote:\n>> Stefan Beller <sbeller@google.com> writes:\n>>\n>>> We do not need to do anything special to initialize the `submodule_groups`\n>>> pointer as the diff options setup will fill in 0 by default.\n>>>\n>>> Signed-off-by: Stefan Beller <sbeller@google.com>\n>>> ---\n>>>  diff.c | 3 +++\n>>>  diff.h | 1 +\n>>>  2 files changed, 4 insertions(+)\n>>\n>> Isn't this going in the opposite way from what you described in 0/15\n>> with analogy to how \"ignore\" mechanism works?  Just like a path is\n>> tracked once it is tracked, whether it matches an ignore pattern,\n>> shouldn't we be getting a summary for a submodule for any submodule\n>> once submodule/.git/HEAD is there (i.e. we can give a comparison),\n>> whether it is specified by a separate mechanism that acts from\n>> sideways (e.g. the \"default group\").\n>\n> That is why I started in 0/15 with\n>> One pain point I am still aware of:\n> as I did not do the right thing in these patches?\n> These patches do however:\n>\n>>    git status\n>>    git diff\n>>    git submodule summary\n>>    # show only changes to submodules which are in the default group.\n>\n> which seems to be the wrong thing then.\n>\n> So here is a thought experiment:\n>\n>     # get all submodules into the work tree\n>     git submodule update --recursive --init\n>\n>     # The selected default group will not include all submodules\n>     git config submodule.defaultGroup \"*SomeLabel\"\n>\n>     git status\n>     # What do we expect now?\n>     # either a \"nothing to commit, working directory clean\"\n>     # or rather what was described in 0/15:\n>\n>         More than 2 submodules (123 actually) including\n>             'path/foo'\n>             'lib/baz'\n>         are checked out, but not part of the default group.\n>         You can add these submodules via\n>             git config --add submodule.defaultGroup ./path/foo\n>             git config --add submodule.defaultGroup ./lib/baz\n>\n> If we want to go with the second option, the design described in 0/15\n> is broken. Going one step further:\n>\n>     # in all submodules including the excluded via groups,\n>     # by resetting the groups for this command\n>     git -c submodule.defaultGroup= submodule foreach git reset --hard HEAD^\n>\n>     git status\n>     # Reporting the changes from submodules in the default Group is\n> uncontroversial:\n>     On branch master\n>     Your branch is up-to-date with 'origin/master'.\n>     Changes not staged for commit:\n>       (use \"git add <file>...\" to update what will be committed)\n>       (use \"git checkout -- <file>...\" to discard changes in working directory)\n>\n>         modified:   subA (new commits)\n>         modified:   subB (new commits)\n>\n>     no changes added to commit (use \"git add\" and/or \"git commit -a\")\n>\n>     # But what about subC which is not in the default group? It was\n> changed as well.\n>     # one thing I could imagine, is similar to above:\n>\n>         More than 2 submodules (123 actually) including\n>             modified:    'subC'  (new commits)\n>             modified:   'lib/baz' (new commits)\n>         are checked out, but not part of the default group.\n>         You can add these submodules via\n>             git config --add submodule.defaultGroup ./path/foo\n>             git config --add submodule.defaultGroup ./lib/baz\n>\n>     # and the remaining 121 submodules are not reported in git status\n>\n>     git diff\n>     # report them all below:\n>     diff --git a/subA b/subA\n>     index e4e79a2..6689f08 160000\n>     --- a/subA\n>     +++ b/subA\n>     @@ -1 +1 @@\n>     -Subproject commit e4e79a217576d24ef4d73b620766f62b155bcd98\n>     +Subproject commit 6689f08735d08a057f8d6f91af98b04960afa517\n>     ...\n>      # goes on including 123 submodule not in the default group.\n>\n>\n> In case we report these submodules which are checked out but not in\n> the default group, we probably want to adapt \"git submodule update\" to\n> un-checkout the work tree of the submodules in case they are clean.\n>\n> Thanks,\n> Stefan\n"},{"id":"285598","messageId":"xmqqy47o9s1h.fsf@gitster.mtv.corp.google.com","threadId":"42151","inReplyTo":"CAGZ79ka37jWYDJrAWy5KLhaaJmrLRbmTzRC6A5DneuE63+XCeQ@mail.gmail.com","subject":"Re: [PATCH 11/15] diff: ignore submodules excluded by groups","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-05-05T20:19:22Z","receivedAt":"2016-05-05T20:19:22Z","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> Any thoughts on my thoughts below?\n>\n>> So here is a thought experiment:\n>>\n>>     # get all submodules into the work tree\n>>     git submodule update --recursive --init\n>>\n>>     # The selected default group will not include all submodules\n>>     git config submodule.defaultGroup \"*SomeLabel\"\n>>\n>>     git status\n>>     # What do we expect now?\n>>     # either a \"nothing to commit, working directory clean\"\n>>     # or rather what was described in 0/15:\n>>\n>>         More than 2 submodules (123 actually) including\n>>             'path/foo'\n>>             'lib/baz'\n>>         are checked out, but not part of the default group.\n>>         You can add these submodules via\n>>             git config --add submodule.defaultGroup ./path/foo\n>>             git config --add submodule.defaultGroup ./lib/baz\n\nThat may be an interesting thing to know, but I am not sure if it\nadds value to the user.  The user wanted the defaultGroup to be\nthe set of submodules labeled with SomeLabel, and an alternative\nvalid suggestion could be\n\n\t'path/foo' and other submodules are not part of what you are\n\tinterested in; if you want to deinitialize them, do\n\n            git submodule deinit !defaultGroup\n\nBoth look equally valid to me, but offering both would be way too\nmuch.  I'd say you should give that only with \"status -v\" or\nsomething, perhaps?\n\n>> If we want to go with the second option,\n\nYou already lost me here, as it is not clear what two \"options\" you\nare comparing.\n\n>> If we want to go with the second option, the design described in 0/15\n>> is broken. Going one step further:\n>>\n>> ...\n>>     # But what about subC which is not in the default group? It was\n>> changed as well.\n\nSo why not show it?  Is there anything controversial?\n\nIf you are truly not interested in it by excluding it from the\ndefault group, you wouldn't have touched it in the first place.  If\nyou did touch it, then you are showing some special interest that\noverrides what you said in the default mechanism.\n\nIn short, I think I understood what you wanted with your analogy to\nthe ignore/exclude mechanism in 0/15.  Default is a handy way to say\n\"I do not want to bother specifying everything from the command line\nevery time\" but we can say that it is nothing more than that.  That\nis exactly how the ignore/exclude mechanism is used--\"git add\" by\ndefault will not add those that are ignored when discovering paths\nby recursively descending, but once added, that is part of what the\nuser told Git that she cares about.\n\n>> In case we report these submodules which are checked out but not in\n>> the default group, we probably want to adapt \"git submodule update\" to\n>> un-checkout the work tree of the submodules in case they are clean.\n\nWhy?\n\nLetting them know that they have such an option, and giving them a\nway to tell which submodules fall into that category, are both good\nthings.  But why is it a good thing to automatically clean what the\nuser has checked out (which I expect that she expects to remain\nuntil she explicitly tells us otherwise)?\n\nWe do not automatically \"git rm\" a clean tracked path that happens\nto match .gitignore pattern and I do not think it is a good thing to\ndo so.\n\nPuzzled.\n"},{"id":"285602","messageId":"CAGZ79kYGbjOKPQk8A-ag+JgvybW4Kf5=g8azVAOoMq79oXc5-Q@mail.gmail.com","threadId":"42151","inReplyTo":"xmqqy47o9s1h.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH 11/15] diff: ignore submodules excluded by groups","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2016-05-05T21:02:58Z","receivedAt":"2016-05-05T21:02:58Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Thu, May 5, 2016 at 1:19 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> Stefan Beller <sbeller@google.com> writes:\n>\n>> Any thoughts on my thoughts below?\n>>\n>>> So here is a thought experiment:\n>>>\n>>>     # get all submodules into the work tree\n>>>     git submodule update --recursive --init\n>>>\n>>>     # The selected default group will not include all submodules\n>>>     git config submodule.defaultGroup \"*SomeLabel\"\n>>>\n>>>     git status\n>>>     # What do we expect now?\n>>>     # either a \"nothing to commit, working directory clean\"\n>>>     # or rather what was described in 0/15:\n>>>\n>>>         More than 2 submodules (123 actually) including\n>>>             'path/foo'\n>>>             'lib/baz'\n>>>         are checked out, but not part of the default group.\n>>>         You can add these submodules via\n>>>             git config --add submodule.defaultGroup ./path/foo\n>>>             git config --add submodule.defaultGroup ./lib/baz\n>\n> That may be an interesting thing to know, but I am not sure if it\n> adds value to the user.  The user wanted the defaultGroup to be\n> the set of submodules labeled with SomeLabel, and an alternative\n> valid suggestion could be\n>\n>         'path/foo' and other submodules are not part of what you are\n>         interested in; if you want to deinitialize them, do\n>\n>             git submodule deinit !defaultGroup\n>\n> Both look equally valid to me, but offering both would be way too\n> much.  I'd say you should give that only with \"status -v\" or\n> something, perhaps?\n>\n>>> If we want to go with the second option,\n>\n> You already lost me here, as it is not clear what two \"options\" you\n> are comparing.\n\nThe first option is giving nothing:\n\n     git config submodule.defaultGroup \"*SomeLabel\"\n     git -C submodule-not-labeled reset --hard HEAD^\n     git status\n     # all good, no report about  submodule-not-labeled\n     # because it is not in the default group.\n     # (This is implemented in the series)\n\nThe \"second option\" is some sort of reporting. Either what I or you proposed.\n\n>\n>>> If we want to go with the second option, the design described in 0/15\n>>> is broken. Going one step further:\n>>>\n>>> ...\n>>>     # But what about subC which is not in the default group? It was\n>>> changed as well.\n>\n> So why not show it?  Is there anything controversial?\n\nThe user made clear to not be interested in subC by setting\nup the default group.\n\n>\n> If you are truly not interested in it by excluding it from the\n> default group, you wouldn't have touched it in the first place.\n\nWell it can get out of sync by not touching it as well, because others\nchanged the submodule pointer who are interested in that though.\n\n    # in the superproject\n    git checkout new-version\n    git submodule update\n    # checks out submodules to their version\n\n    git checkout some-ancient-version\n    git submodule update\n    # this would only update the submodules in the defaultGroup,\n    # not those which are initialized but \"uninteresting\"\n    # the labeling may have changed between the different versions\n    git status\n    # I don't want to see any submodule changes here.\n    # but there may be a submodule which is not at the right version\n    # as `git submodule update` only paid attention to the default group.\n\n> If\n> you did touch it, then you are showing some special interest that\n> overrides what you said in the default mechanism.\n>\n> In short, I think I understood what you wanted with your analogy to\n> the ignore/exclude mechanism in 0/15.  Default is a handy way to say\n> \"I do not want to bother specifying everything from the command line\n> every time\" but we can say that it is nothing more than that.  That\n> is exactly how the ignore/exclude mechanism is used--\"git add\" by\n> default will not add those that are ignored when discovering paths\n> by recursively descending, but once added, that is part of what the\n> user told Git that she cares about.\n>\n>>> In case we report these submodules which are checked out but not in\n>>> the default group, we probably want to adapt \"git submodule update\" to\n>>> un-checkout the work tree of the submodules in case they are clean.\n>\n> Why?\n>\n> Letting them know that they have such an option, and giving them a\n> way to tell which submodules fall into that category, are both good\n> things.  But why is it a good thing to automatically clean what the\n> user has checked out (which I expect that she expects to remain\n> until she explicitly tells us otherwise)?\n>\n> We do not automatically \"git rm\" a clean tracked path that happens\n> to match .gitignore pattern and I do not think it is a good thing to\n> do so.\n\ngit rm changes the index (which may show up in the next commit)\n\nThe state of a submodule (un-initialized, initialized, checked out)\ndoesn't change the index or anything. Only the working tree is affected.\n\nAnd by flipping between the initialized and checked-out state we do not\nlose any information (such as user configured remote urls) nor does it\naffect the \"state\" (index, recorded tree, history) of the repository.\n\nSo I just wonder if\n\n    git init <submodule group spec>\n    git deinit ! <submodule group spec>\n\nshould be done in `git submodule update <submodule group spec>`\n(or by having the default group configured and running `git submodule update`\nwith no arguments.)\n\n\n\n>\n> Puzzled.\n>\n"},{"id":"285634","messageId":"xmqqfutw9mfs.fsf@gitster.mtv.corp.google.com","threadId":"42151","inReplyTo":"CAGZ79kYGbjOKPQk8A-ag+JgvybW4Kf5=g8azVAOoMq79oXc5-Q@mail.gmail.com","subject":"Re: [PATCH 11/15] diff: ignore submodules excluded by groups","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-05-05T22:20:23Z","receivedAt":"2016-05-05T22:20:23Z","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 option is giving nothing:\n>\n>      git config submodule.defaultGroup \"*SomeLabel\"\n>      git -C submodule-not-labeled reset --hard HEAD^\n>      git status\n>      # all good, no report about  submodule-not-labeled\n>      # because it is not in the default group.\n>      # (This is implemented in the series)\n>\n> The \"second option\" is some sort of reporting. Either what I or you proposed.\n\nOK, although I didn't propose anything ;-).\n\n>\n>>\n>>>> If we want to go with the second option, the design described in 0/15\n>>>> is broken. Going one step further:\n>>>>\n>>>> ...\n>>>>     # But what about subC which is not in the default group? It was\n>>>> changed as well.\n>>\n>> So why not show it?  Is there anything controversial?\n>\n> The user made clear to not be interested in subC by setting\n> up the default group.\n\nI wonder if that is a valid argument.  Git's position has always\nbeen very clear after doing this:\n\n    git add -f foo.bin && echo \\*.bin >>.gitignore\n\nWhat the user might have said in the \"configuration\" is the default\nsuggestion, that is much weaker than what has been done to the\nrepository data.  I think \"the path is recorded in the index\" in the\nignore/exclude situation is similar to \"the submodule is initialized\nin the working tree\" in this context.\n\n> Well it can get out of sync by not touching it as well, because others\n> changed the submodule pointer who are interested in that though.\n\nWhich \"others\" are mucking with your working tree?  (don't respond:\nI'll come to the answer a few lines below).\n\n>\n>     # in the superproject\n>     git checkout new-version\n>     git submodule update\n>     # checks out submodules to their version\n>\n>     git checkout some-ancient-version\n>     git submodule update\n>     # this would only update the submodules in the defaultGroup,\n>     # not those which are initialized but \"uninteresting\"\n>     # the labeling may have changed between the different versions\n\nI see.  I think that is where the conceptual bug lies.  Thanks for\nan illustration.\n\nIf we take an approach similar to ignore/exclude, then yes the\n\"default\" action should be done to \"defaultGroup\" specified plus\nwhat the user instantiated in the working tree already.  And that\nis not limited to \"update\" operation.\n\nJust like \"git diff\" is not the only thing that would show\ndifference in foo.bin in the working tree even when *.bin is\nignored, but we consistently treat foo.bin as tracked.\n\n> The state of a submodule (un-initialized, initialized, checked out)\n> doesn't change the index or anything. Only the working tree is affected.\n>\n> And by flipping between the initialized and checked-out state we do not\n> lose any information (such as user configured remote urls) nor does it\n> affect the \"state\" (index, recorded tree, history) of the repository.\n\nUsers want to initialize a module and keep it checked out even if\nthey do intend to keep it pristine and not making any changes\nthemselves, only so that other parts of the tree that depends on the\nmodule can be built.  So \"removing a tracked and unmodified thing\nfrom the working tree does not hurt users\" is a nonsense argument,\nisn't it?  I would be very unhappy if \"git status\" removed pristine\npaths from the working tree and toggle assume-unchanged bit in my\nindex automatically.\n\nI am afraid you are focused too much on \"version control\" and losing\nsight of those who use the data stored in \"version control\", perhaps\nbecause you worked in submodule area too long and too hard?  \n"},{"id":"285641","messageId":"CAGZ79kYKbef7DTkmE3Vf3C=PLfgB3xf0ikVKHFUfQ8+KkgGHPg@mail.gmail.com","threadId":"42151","inReplyTo":"xmqqfutw9mfs.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH 11/15] diff: ignore submodules excluded by groups","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2016-05-05T22:50:54Z","receivedAt":"2016-05-05T22:50:54Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Thu, May 5, 2016 at 3:20 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> Stefan Beller <sbeller@google.com> writes:\n>\n>> The first option is giving nothing:\n>>\n>>      git config submodule.defaultGroup \"*SomeLabel\"\n>>      git -C submodule-not-labeled reset --hard HEAD^\n>>      git status\n>>      # all good, no report about  submodule-not-labeled\n>>      # because it is not in the default group.\n>>      # (This is implemented in the series)\n>>\n>> The \"second option\" is some sort of reporting. Either what I or you proposed.\n>\n> OK, although I didn't propose anything ;-).\n>\n>>\n>>>\n>>>>> If we want to go with the second option, the design described in 0/15\n>>>>> is broken. Going one step further:\n>>>>>\n>>>>> ...\n>>>>>     # But what about subC which is not in the default group? It was\n>>>>> changed as well.\n>>>\n>>> So why not show it?  Is there anything controversial?\n>>\n>> The user made clear to not be interested in subC by setting\n>> up the default group.\n>\n> I wonder if that is a valid argument.  Git's position has always\n> been very clear after doing this:\n>\n>     git add -f foo.bin && echo \\*.bin >>.gitignore\n>\n> What the user might have said in the \"configuration\" is the default\n> suggestion, that is much weaker than what has been done to the\n> repository data.  I think \"the path is recorded in the index\" in the\n> ignore/exclude situation is similar to \"the submodule is initialized\n> in the working tree\" in this context.\n>\n>> Well it can get out of sync by not touching it as well, because others\n>> changed the submodule pointer who are interested in that though.\n>\n> Which \"others\" are mucking with your working tree?  (don't respond:\n> I'll come to the answer a few lines below).\n>\n>>\n>>     # in the superproject\n>>     git checkout new-version\n>>     git submodule update\n>>     # checks out submodules to their version\n>>\n>>     git checkout some-ancient-version\n\nI think here is when the conceptual bug happens.\nWe would want a\n\n    git checkout --keep-submodules-to-pristine-default-group\n\n(intentionally long bad name)\nthat option would init new submodules and deinit old submodules\nwhich were clean before. Here we can compare it to a file,\ni.e. after checkout some files are newly there, some are deleted.\n(And that's totally expected)\n\nIf we had this `checkout --treat-submodules-as-files-for-defaultGroup`,\nthen the following command `git submodule update` would not be\nrequired.\n\nI think long term this is a far better approach.\n\nI just wonder what the `checkout --recurse-submodules` should do when\nthere is no defaultGroup configured. (i.e. should that delete submodules\nwhich were there before and delete them if they were clean? Just like files.)\n\n\n>>     git submodule update\n>>     # this would only update the submodules in the defaultGroup,\n>>     # not those which are initialized but \"uninteresting\"\n>>     # the labeling may have changed between the different versions\n>\n> I see.  I think that is where the conceptual bug lies.  Thanks for\n> an illustration.\n\nYes.\n\n>\n> If we take an approach similar to ignore/exclude, then yes the\n> \"default\" action should be done to \"defaultGroup\" specified plus\n> what the user instantiated in the working tree already.  And that\n> is not limited to \"update\" operation.\n>\n> Just like \"git diff\" is not the only thing that would show\n> difference in foo.bin in the working tree even when *.bin is\n> ignored, but we consistently treat foo.bin as tracked.\n>\n>> The state of a submodule (un-initialized, initialized, checked out)\n>> doesn't change the index or anything. Only the working tree is affected.\n>>\n>> And by flipping between the initialized and checked-out state we do not\n>> lose any information (such as user configured remote urls) nor does it\n>> affect the \"state\" (index, recorded tree, history) of the repository.\n>\n> Users want to initialize a module and keep it checked out even if\n> they do intend to keep it pristine and not making any changes\n> themselves, only so that other parts of the tree that depends on the\n> module can be built.\n\nThe `submodule init` command could learn to just add that path of the\nextra submodule to the defaultGroup, such that it persists between\ndifferent checkouts.\n\n> So \"removing a tracked and unmodified thing\n> from the working tree does not hurt users\" is a nonsense argument,\n> isn't it?  I would be very unhappy if \"git status\" removed pristine\n> paths from the working tree and toggle assume-unchanged bit in my\n> index automatically.\n\nNo, `checkout` did it for you. Assume we had a \"defaultGroup for files\",\n(others call it \"narrow clones\")\n\n    # in git.git\n    git set-file-default-group Documentation/RelNotes\n    git checkout v2.6.0\n\n    ls Documentation/RelNotes |grep v2.7\n    # no files! But this is uncontroversial as it's current behavior\n    # even with fictional \"files default group\" set to \"all files ever\"\n\n    ls builtin/\n    # does it exist? No because set-file-default-group\n    # did restrict out interest here.\n\n>\n> I am afraid you are focused too much on \"version control\" and losing\n> sight of those who use the data stored in \"version control\", perhaps\n> because you worked in submodule area too long and too hard?\n\nNot sure what you mean here. (Neither did I work long nor hard in that area.)\n\nI am aware that other operations such as a build system would be glad to\nhave the contents of the submodules there. But those would not use a\nrestrictive default group?\n"},{"id":"285643","messageId":"xmqqfutw85oz.fsf@gitster.mtv.corp.google.com","threadId":"42151","inReplyTo":"CAGZ79kYKbef7DTkmE3Vf3C=PLfgB3xf0ikVKHFUfQ8+KkgGHPg@mail.gmail.com","subject":"Re: [PATCH 11/15] diff: ignore submodules excluded by groups","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-05-05T23:07:24Z","receivedAt":"2016-05-05T23:07:24Z","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 am aware that other operations such as a build system would be glad to\n> have the contents of the submodules there. But those would not use a\n> restrictive default group?\n\nThe set of submodules you \"init\" to the working tree are the ones\nthat are interesting to you.  So once the tree is populated, you do\nnot ever have to look at the \"defaultGroup\" configuration.  You just\nneed to look at the working tree.\n\nBut there is a chicken-and-egg problem.  What should happen after\nthe initial clone, or you switched to a different branch in the\nsuperproject.\n\nThe concept of \"default\" would help by limiting these \"checkout to\nreflect my interest to my working tree\" step.\n\nSo \"if the user inititializes a submodule and we detect that it is\nnot in the default, add it to the default configuration\" pretty much\nfeels like a tail wagging a dog arrangement to me.\n\nThen there is another interesting issue: what should happen when the\nproject added a submodule when you decided what your \"default\" set\nshould be and wrote it in your configuration already.  I suspect\nthat an idea similar to \"the elaborate thing proposed (by whom I no\nlonger rememvber) in the ancient days\" I mentioned earlier might\nleads us to a nice solution.  When you define a default group, you\nremember what the set of available submodules were, and tie your\nchoice to that \"available set\".\n\nE.g. there may be submodules A, B and C in .gitmodules, and you\nchose to record a \"default\" that contains only A and B.  The exact\nway you chose does not matter; it could have been using labels, or\nyou may have explicitly named it.  When you record, you remember\nthat the decision of using A and B was made when A, B and C were the\navailable submodules.  Next time when you see .gitmodules talks\nabout A, B and D but no longer C, then instead of using the previous\n\"default\" choice blindly, you ask.  If the user says it still is the\nright \"default\" to use A and B, then you _also_ remember the set.\nSo that when the user switches between the state of the project with\nsubmodules A, B and C (original) and A, B and D (updated), the user\ndoes not have to answer the same question twice.\n"},{"id":"285665","messageId":"xmqqa8k37m6i.fsf@gitster.mtv.corp.google.com","threadId":"42151","inReplyTo":"xmqqfutw85oz.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH 11/15] diff: ignore submodules excluded by groups","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-05-06T06:08:53Z","receivedAt":"2016-05-06T06:08:53Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> The set of submodules you \"init\" to the working tree are the ones\n> that are interesting to you.  So once the tree is populated, you do\n> not ever have to look at the \"defaultGroup\" configuration.  You just\n> need to look at the working tree.\n> ...\n\nI forgot to prefix the first few paragraphs of that message with\n\"Here is how my version of the world should work.\"  I did not mean\nto say \"Here is how you must make your work work, or I won't talk to\nyou.\"  I was just hurried as I had to tend to other topics.\n\nI actually do not care too deeply (except for the \"automatically\nremove\" part, which I do not think we should do), as I do not think\nthere is a big fundamental difference between the two views.  To\nmake sure we are on the same page, let me rephrase the two views I\nhave in mind.\n\nThe difference is what should happen when the user does not give any\npathspec, *label, or :name to limit the set of submodules to act on,\nwhich, traditionally meant to work on everything, and we are trying\nto change that to some \"default\".\n\n (1) The default set is what the configuration file says is the\n     default group.  The working tree state is ignored.\n\n (2) The default set is what the configuration file says is the\n     default group, plus those the user showed interest by doing\n     \"submodule init\".\n\nSuppose that the user has a mostly satisfactory default configured,\ni.e. the set of submodules the configuration file says is the default\nis both necessary and sufficient to carry out her daily task.  Then\nthere is no difference between the two.\n\nFurther suppose that the user needs to view a submodule outside the\ndefault group temporarily (imagine: for a day or two), while\ncarrying out some specific task.  Perhaps she is working on the\ndocumentation submodule, which is her primary task hence her\nconfiguration file specifies it as the default, but needs to see the\nsubmodule that houses the implementation to describe the behaviour.\n\nSo she does \"init code-module/\"; this has explicit pathspec, so\nthere is no difference between the two.  Now, while reading the code\nmodule, she finds a typo in a comment, and wants to fix it.  We will\nstart to see differences.\n\n * When she wants to get a bird's eye view of everything she cares\n   about at the moment, i.e. wants to view the state of her usual\n   modules plus the code-module she is visiting, (1) is more\n   cumbersome.\n\n   With (1), \"diff --recursive\" will not step outside of her\n   configured default, so she says \"diff --recursive \\*default\n   code-module/\" to say \"I want to see both my default submodule(s)\n   and the one I checked out by hand\".\n\n   With (2), she does not have to do anything special, as manually\n   checked out code-module/ will be acted upon, in addition to the\n   configured default.\n\n\n * When she wants to see her usual modules ignoring the one-off\n   checkout, (1) is easier.\n\n   With (1), she can say \"diff --recursive\" and done. \n\n   With (2), she needs to say \"diff --recursive \\*default\" to\n   explicitly state \"I may have checkouts of other submodules, but\n   this time I want to view only the usual default of mine\".\n\nThe difference is not that big either case.\n\nWhichever way we choose to make the default behaviour, the user\nneeds to type a bit extra when asking a behaviour that is different\nfrom the default behaviour.\n\nThe amount of \"extra\" in the first use case necessary for (1) is\ngreater than the amount of \"extra\" in the second use case necessary\nfor (2), though.  In addition, in the second use case, (1) makes it\neasier for the user to miss important changes she made outside the\narea of her usual attention, while (2) forces her to make a\nconscious effort to exclude them.  These are the reasons why I have\na slight preference for (2) over (1).\n"},{"id":"285765","messageId":"CAGZ79kY5uDzG8PDLMh5e9afg+S3oTjEjq2aRo+s4ud86UCxZQA@mail.gmail.com","threadId":"42151","inReplyTo":"xmqqa8k37m6i.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH 11/15] diff: ignore submodules excluded by groups","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2016-05-06T18:23:59Z","receivedAt":"2016-05-06T18:23:59Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Thu, May 5, 2016 at 11:08 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> Junio C Hamano <gitster@pobox.com> writes:\n>\n>> The set of submodules you \"init\" to the working tree are the ones\n>> that are interesting to you.  So once the tree is populated, you do\n>> not ever have to look at the \"defaultGroup\" configuration.  You just\n>> need to look at the working tree.\n>> ...\n>\n> I forgot to prefix the first few paragraphs of that message with\n> \"Here is how my version of the world should work.\"  I did not mean\n> to say \"Here is how you must make your work work, or I won't talk to\n> you.\"  I was just hurried as I had to tend to other topics.\n>\n> I actually do not care too deeply (except for the \"automatically\n> remove\" part, which I do not think we should do), as I do not think\n> there is a big fundamental difference between the two views.  To\n> make sure we are on the same page, let me rephrase the two views I\n> have in mind.\n\nOk, maybe we can leave that automatically remove part out for the\nfirst series. (Eventually submodules should behave like files and we\ndelete files on checkout all the time, and it's a reasonable default)\n\nSo I think to reduce scope to only cover the clone/update first, all\nother operations behave like today, i.e.\n\n    git clone --recurse-submodules --init-submodule=label\n--init-submodule=label2   git://...\n    # will clone the superproject and recursively\n    # checkout any submodule being labeled label or label2\n\n    git config submodule.defaultGroups default\n    git config --add submodule.defaultGroups devel\n    # configure which submodules you are interested in.\n\n    git submodule add --label <name> git://... ..\n    # record a label while adding a submodule\n\n    git submodule update --init-labeled(=*label)\n    # will update all initialized submodules\n    # and learn a new switch to also initialize the grouped\n    # submodules (either the specified group or if none given\n    # the default group as configured before)\n\n\n\n\n    git status\n    git diff\n    git submodule summary\n    # care about all initialized submodules, i.e. (2) below\n    # a switch for recurse=label will be in a later series.\n\n\n\n>\n> The difference is what should happen when the user does not give any\n> pathspec, *label, or :name to limit the set of submodules to act on,\n> which, traditionally meant to work on everything, and we are trying\n> to change that to some \"default\".\n>\n>  (1) The default set is what the configuration file says is the\n>      default group.  The working tree state is ignored.\n>\n>  (2) The default set is what the configuration file says is the\n>      default group, plus those the user showed interest by doing\n>      \"submodule init\".\n>\n> Suppose that the user has a mostly satisfactory default configured,\n> i.e. the set of submodules the configuration file says is the default\n> is both necessary and sufficient to carry out her daily task.  Then\n> there is no difference between the two.\n>\n> Further suppose that the user needs to view a submodule outside the\n> default group temporarily (imagine: for a day or two), while\n> carrying out some specific task.  Perhaps she is working on the\n> documentation submodule, which is her primary task hence her\n> configuration file specifies it as the default, but needs to see the\n> submodule that houses the implementation to describe the behaviour.\n>\n> So she does \"init code-module/\"; this has explicit pathspec, so\n> there is no difference between the two.  Now, while reading the code\n> module, she finds a typo in a comment, and wants to fix it.  We will\n> start to see differences.\n\nAnother way (3) is to add code-module/ to the \"set of interesting\nsubmodules, i.e. to the default group\"\n\n    git config --all submodule.defaultGroup ./code-module\n    git submodule update\n\n>\n>  * When she wants to get a bird's eye view of everything she cares\n>    about at the moment, i.e. wants to view the state of her usual\n>    modules plus the code-module she is visiting, (1) is more\n>    cumbersome.\n>\n>    With (1), \"diff --recursive\" will not step outside of her\n>    configured default, so she says \"diff --recursive \\*default\n>    code-module/\" to say \"I want to see both my default submodule(s)\n>    and the one I checked out by hand\".\n>\n>    With (2), she does not have to do anything special, as manually\n>    checked out code-module/ will be acted upon, in addition to the\n>    configured default.\n\nIn (3), diff --recursive will also just work fine.\n\n>\n>\n>  * When she wants to see her usual modules ignoring the one-off\n>    checkout, (1) is easier.\n\nIn (3) you'd do\n\n    git config --unset submodule.defaultGroup ./code-module\n    # optionally: git submodule update\n\n>\n>    With (1), she can say \"diff --recursive\" and done.\n>\n>    With (2), she needs to say \"diff --recursive \\*default\" to\n>    explicitly state \"I may have checkouts of other submodules, but\n>    this time I want to view only the usual default of mine\".\n\nand diff --recursive works fine again as well.\n\n>\n> The difference is not that big either case.\n>\n> Whichever way we choose to make the default behaviour, the user\n> needs to type a bit extra when asking a behaviour that is different\n> from the default behaviour.\n>\n> The amount of \"extra\" in the first use case necessary for (1) is\n> greater than the amount of \"extra\" in the second use case necessary\n> for (2), though.  In addition, in the second use case, (1) makes it\n> easier for the user to miss important changes she made outside the\n> area of her usual attention, while (2) forces her to make a\n> conscious effort to exclude them.  These are the reasons why I have\n> a slight preference for (2) over (1).\n>\n\nThat makes sense.\n\nSo with (2)\n * there is no need to modify status, diff, log for the default case and the\n    --recursive \\*default\" may come later, so the initial series can be smaller.\n *\n"},{"id":"285770","messageId":"xmqqy47n2esc.fsf@gitster.mtv.corp.google.com","threadId":"42151","inReplyTo":"CAGZ79kY5uDzG8PDLMh5e9afg+S3oTjEjq2aRo+s4ud86UCxZQA@mail.gmail.com","subject":"Re: [PATCH 11/15] diff: ignore submodules excluded by groups","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-05-06T18:59:47Z","receivedAt":"2016-05-06T18:59:47Z","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>> Further suppose that the user needs to view a submodule outside the\n>> default group temporarily (imagine: for a day or two), while\n>> carrying out some specific task.  Perhaps she is working on the\n>> documentation submodule, which is her primary task hence her\n>> configuration file specifies it as the default, but needs to see the\n>> submodule that houses the implementation to describe the behaviour.\n>>\n>> So she does \"init code-module/\"; this has explicit pathspec, so\n>> there is no difference between the two.  Now, while reading the code\n>> module, she finds a typo in a comment, and wants to fix it.  We will\n>> start to see differences.\n>\n> Another way (3) is to add code-module/ to the \"set of interesting\n> submodules, i.e. to the default group\"\n\nI do not want to force her to do more than \"submodule deinit\" when\nshe is done with that temporary task that required her to have\ncode-module/ checked out, which is what you are doing with such a\nchange.  So that is a non-starter to me.\n\n>> The amount of \"extra\" in the first use case necessary for (1) is\n>> greater than the amount of \"extra\" in the second use case necessary\n>> for (2), though.  In addition, in the second use case, (1) makes it\n>> easier for the user to miss important changes she made outside the\n>> area of her usual attention, while (2) forces her to make a\n>> conscious effort to exclude them.  These are the reasons why I have\n>> a slight preference for (2) over (1).\n>>\n>\n> That makes sense.\n>\n> So with (2)\n>  * there is no need to modify status, diff, log for the default case and the\n>     --recursive \\*default\" may come later, so the initial series can be smaller.\n>  *\n\nI sense a premature \"Send\" button here ;-)\n\nIn any case, I care much more about the \"making it harder to miss\nthings outside the usual area of attention\" benefit than \"the user\nmay have to type less more often\" benefit, even though both are\nslightly in favor between (1) and (2).\n"}]}