git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
* [RFC_PATCHv4 0/7] Git submodule labels
@ 2016-03-22  2:06 Stefan Beller
  2016-03-22  2:06 ` [RFC_PATCHv4 1/7] git submodule: teach `add` to label submodules Stefan Beller
                   ` (6 more replies)
  0 siblings, 7 replies; 22+ messages in thread
From: Stefan Beller @ 2016-03-22  2:06 UTC (permalink / raw)
  To: Jens.Lehmann, sschuberth; +Cc: git, Stefan Beller

This series introduces labels which you can attach to submodules like so:

    $ cat .gitmodules
    [submodule "gcc"]
        path = gcc
        url = git://...
        label = default
        label = devel
    [submodule "linux"]
        path = linux
        url = git://...
        label = default
        
    $ git submodule add --name emacs --label "editor" --label default git://...
    
    # If upstream has submodules properly labeled, you can make use of them:
    $ git config --add submodule.actionOnLabel "*default"
    $ git config --add submodule.actionOnLabel ":name"
    $ git config --add submodule.actionOnLabel "./by/path"
    # The prefix * denotes a label as found in .gitmodules
    # : goes before names 
    # path are prefixed ./ currently
    # both path and names need work

    # no --init necessary, partially initializes submodules (only those which
    # were specified by label, name or path)
    $ git submodule update
    
    # time passes, upstream may have added new submodules and we get them without
    # extra commands!
    $ git submodule update

    # The above configuration can be given to git clone directly via:
    $ git clone --init-submodule=*labelA ...
    
    # diff/status only apply to label-selected submodules
    git status

New since last round:
* Renamed to submodule.actionOnLabel as it is generic enough to be applicable
  for lots of commands (submodule update, status, diff, etc)
* Restructured the code to have a generic "Given these labels, would I
  want to operate on this submodule", which made the implementation for
  "submodule update" easier, as well as the new WIP patch for diff/status.

Any feedback would be welcome!
Thanks,
Stefan

An earlier version was posted at
http://thread.gmane.org/gmane.comp.version-control.git/284612

This applies on top of origin/sb/submodule-init or can be found at
https://github.com/stefanbeller/git/tree/submodule-groups-v4

Stefan Beller (7):
  git submodule: teach `add` to label submodules
  submodule-config: keep labels around
  submodule-config: add method to check for being labeled
  submodule init: redirect stdout to stderr
  submodule update: respect submodule.actionOnLabel
  clone: allow specification of submodules to be cloned
  WIP status/diff: respect submodule.actionOnLabel

 Documentation/git-clone.txt     |   6 +
 Documentation/git-submodule.txt |   5 +-
 builtin/clone.c                 |  40 +++++-
 builtin/submodule--helper.c     |  25 +++-
 git-submodule.sh                |  14 +-
 submodule-config.c              |  66 ++++++++-
 submodule-config.h              |   5 +
 submodule.c                     |  15 ++
 t/t7400-submodule-basic.sh      | 294 ++++++++++++++++++++++++++++++++++++++++
 9 files changed, 462 insertions(+), 8 deletions(-)

-- 
2.7.0.rc0.45.g6b4c145

^ permalink raw reply	[flat|nested] 22+ messages in thread

* [RFC_PATCHv4 1/7] git submodule: teach `add` to label submodules
  2016-03-22  2:06 [RFC_PATCHv4 0/7] Git submodule labels Stefan Beller
@ 2016-03-22  2:06 ` Stefan Beller
  2016-03-22 22:28   ` Junio C Hamano
  2016-03-22 22:34   ` Junio C Hamano
  2016-03-22  2:06 ` [RFC_PATCHv4 2/7] submodule-config: keep labels around Stefan Beller
                   ` (5 subsequent siblings)
  6 siblings, 2 replies; 22+ messages in thread
From: Stefan Beller @ 2016-03-22  2:06 UTC (permalink / raw)
  To: Jens.Lehmann, sschuberth; +Cc: git, Stefan Beller

When adding new submodules, you can specify the
label(s) the submodule belongs to by giving one or more
--label arguments. This will record each label in the
.gitmodules file as a value of the key
"submodule.$NAME.label".

Signed-off-by: Stefan Beller <sbeller@google.com>
---
 Documentation/git-submodule.txt |  5 ++++-
 git-submodule.sh                | 14 +++++++++++++-
 t/t7400-submodule-basic.sh      | 32 ++++++++++++++++++++++++++++++++
 3 files changed, 49 insertions(+), 2 deletions(-)

diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt
index 13adebf..c0744eb 100644
--- a/Documentation/git-submodule.txt
+++ b/Documentation/git-submodule.txt
@@ -9,7 +9,7 @@ git-submodule - Initialize, update or inspect submodules
 SYNOPSIS
 --------
 [verse]
-'git submodule' [--quiet] add [-b <branch>] [-f|--force] [--name <name>]
+'git submodule' [--quiet] add [-b <branch>] [-f|--force] [-l|--label <label>]
 	      [--reference <repository>] [--depth <depth>] [--] <repository> [<path>]
 'git submodule' [--quiet] status [--cached] [--recursive] [--] [<path>...]
 'git submodule' [--quiet] init [--] [<path>...]
@@ -101,6 +101,9 @@ is the superproject and submodule repositories will be kept
 together in the same relative location, and only the
 superproject's URL needs to be provided: git-submodule will correctly
 locate the submodule using the relative URL in .gitmodules.
++
+If at least one label argument was given, all labels are recorded in the
+.gitmodules file in the label fields.
 
 status::
 	Show the status of the submodules. This will print the SHA-1 of the
diff --git a/git-submodule.sh b/git-submodule.sh
index 97a3097..def1e1c 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -5,7 +5,7 @@
 # Copyright (c) 2007 Lars Hjemli
 
 dashless=$(basename "$0" | sed -e 's/-/ /')
-USAGE="[--quiet] add [-b <branch>] [-f|--force] [--name <name>] [--reference <repository>] [--] <repository> [<path>]
+USAGE="[--quiet] add [-b <branch>] [-f|--force] [--name <name>] [--reference <repository>] [-l|--label <label>][--] <repository> [<path>]
    or: $dashless [--quiet] status [--cached] [--recursive] [--] [<path>...]
    or: $dashless [--quiet] init [--] [<path>...]
    or: $dashless [--quiet] deinit [-f|--force] [--] <path>...
@@ -130,6 +130,7 @@ cmd_add()
 {
 	# parse $args after "submodule ... add".
 	reference_path=
+	labels=
 	while test $# -ne 0
 	do
 		case "$1" in
@@ -165,6 +166,13 @@ cmd_add()
 		--depth=*)
 			depth=$1
 			;;
+		-l|--label)
+			labels="${labels} $2"
+			shift
+			;;
+		--label=*)
+			labels="${labels} ${1#--label=}"
+			;;
 		--)
 			shift
 			break
@@ -292,6 +300,10 @@ Use -f if you really want to add it." >&2
 
 	git config -f .gitmodules submodule."$sm_name".path "$sm_path" &&
 	git config -f .gitmodules submodule."$sm_name".url "$repo" &&
+	for label in $labels
+	do
+		git config --add -f .gitmodules submodule."$sm_name".label "${label}"
+	done &&
 	if test -n "$branch"
 	then
 		git config -f .gitmodules submodule."$sm_name".branch "$branch"
diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh
index 5991e3c..fc948fd 100755
--- a/t/t7400-submodule-basic.sh
+++ b/t/t7400-submodule-basic.sh
@@ -986,6 +986,7 @@ test_expect_success 'submodule with UTF-8 name' '
 '
 
 test_expect_success 'submodule add clone shallow submodule' '
+	test_when_finished "rm -rf super" &&
 	mkdir super &&
 	pwd=$(pwd) &&
 	(
@@ -999,5 +1000,36 @@ test_expect_success 'submodule add clone shallow submodule' '
 	)
 '
 
+test_expect_success 'submodule add records a label' '
+	test_when_finished "rm -rf super" &&
+	mkdir super &&
+	pwd=$(pwd) &&
+	(
+		cd super &&
+		git init &&
+		git submodule add --label labelA file://"$pwd"/example2 submodule &&
+		git config -f .gitmodules submodule."submodule".label >actual &&
+		echo labelA >expected &&
+		test_cmp expected actual
+	)
+'
+
+cat >expected <<-EOF
+labelA
+labelB
+EOF
+
+test_expect_success 'submodule add records multiple labels' '
+	test_when_finished "rm -rf super" &&
+	mkdir super &&
+	pwd=$(pwd) &&
+	(
+		cd super &&
+		git init &&
+		git submodule add --label=labelA -l labelB file://"$pwd"/example2 submodule &&
+		git config --get-all -f .gitmodules submodule."submodule".label >../actual
+	) &&
+	test_cmp expected actual
+'
 
 test_done
-- 
2.7.0.rc0.45.g6b4c145

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [RFC_PATCHv4 2/7] submodule-config: keep labels around
  2016-03-22  2:06 [RFC_PATCHv4 0/7] Git submodule labels Stefan Beller
  2016-03-22  2:06 ` [RFC_PATCHv4 1/7] git submodule: teach `add` to label submodules Stefan Beller
@ 2016-03-22  2:06 ` Stefan Beller
  2016-03-22  2:06 ` [RFC_PATCHv4 3/7] submodule-config: add method to check for being labeled Stefan Beller
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 22+ messages in thread
From: Stefan Beller @ 2016-03-22  2:06 UTC (permalink / raw)
  To: Jens.Lehmann, sschuberth; +Cc: git, Stefan Beller

We need the submodule labels in a later patch.

Signed-off-by: Stefan Beller <sbeller@google.com>
---
 submodule-config.c | 18 +++++++++++++++++-
 submodule-config.h |  2 ++
 2 files changed, 19 insertions(+), 1 deletion(-)

diff --git a/submodule-config.c b/submodule-config.c
index 9fa2269..7b48e59 100644
--- a/submodule-config.c
+++ b/submodule-config.c
@@ -60,6 +60,10 @@ static void free_one_config(struct submodule_entry *entry)
 	free((void *) entry->config->path);
 	free((void *) entry->config->name);
 	free((void *) entry->config->update_strategy.command);
+	if (entry->config->labels) {
+		string_list_clear(entry->config->labels, 0);
+		free(entry->config->labels);
+	}
 	free(entry->config);
 }
 
@@ -199,6 +203,7 @@ static struct submodule *lookup_or_create_by_name(struct submodule_cache *cache,
 	submodule->update_strategy.command = NULL;
 	submodule->fetch_recurse = RECURSE_SUBMODULES_NONE;
 	submodule->ignore = NULL;
+	submodule->labels = NULL;
 
 	hashcpy(submodule->gitmodules_sha1, gitmodules_sha1);
 
@@ -324,7 +329,18 @@ static int parse_config(const char *var, const char *value, void *data)
 		else if (parse_submodule_update_strategy(value,
 			 &submodule->update_strategy) < 0)
 				die(_("invalid value for %s"), var);
-	}
+	} else if (!strcmp(item.buf, "label")) {
+		if (!value)
+			ret = config_error_nonbool(var);
+		else {
+			if (!submodule->labels) {
+				submodule->labels =
+					xmalloc(sizeof(*submodule->labels));
+				string_list_init(submodule->labels, 1);
+			}
+			string_list_insert(submodule->labels, value);
+		}
+ 	}
 
 	strbuf_release(&name);
 	strbuf_release(&item);
diff --git a/submodule-config.h b/submodule-config.h
index 092ebfc..8d61df3 100644
--- a/submodule-config.h
+++ b/submodule-config.h
@@ -18,6 +18,8 @@ struct submodule {
 	struct submodule_update_strategy update_strategy;
 	/* the sha1 blob id of the responsible .gitmodules file */
 	unsigned char gitmodules_sha1[20];
+	/* sorted, not as on disk */
+	struct string_list *labels;
 };
 
 int parse_fetch_recurse_submodules_arg(const char *opt, const char *arg);
-- 
2.7.0.rc0.45.g6b4c145

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [RFC_PATCHv4 3/7] submodule-config: add method to check for being labeled
  2016-03-22  2:06 [RFC_PATCHv4 0/7] Git submodule labels Stefan Beller
  2016-03-22  2:06 ` [RFC_PATCHv4 1/7] git submodule: teach `add` to label submodules Stefan Beller
  2016-03-22  2:06 ` [RFC_PATCHv4 2/7] submodule-config: keep labels around Stefan Beller
@ 2016-03-22  2:06 ` Stefan Beller
  2016-03-22 22:30   ` Junio C Hamano
  2016-03-22  2:06 ` [RFC_PATCHv4 4/7] submodule init: redirect stdout to stderr Stefan Beller
                   ` (3 subsequent siblings)
  6 siblings, 1 reply; 22+ messages in thread
From: Stefan Beller @ 2016-03-22  2:06 UTC (permalink / raw)
  To: Jens.Lehmann, sschuberth; +Cc: git, Stefan Beller

In later patches we need to tell if a submodule is labeled by
the given labels.

Signed-off-by: Stefan Beller <sbeller@google.com>
---
 submodule-config.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
 submodule-config.h |  3 +++
 2 files changed, 51 insertions(+)

diff --git a/submodule-config.c b/submodule-config.c
index 7b48e59..b10a773 100644
--- a/submodule-config.c
+++ b/submodule-config.c
@@ -493,3 +493,51 @@ void submodule_free(void)
 	cache_free(&cache);
 	is_cache_init = 0;
 }
+
+int submodule_applicable_by_labels(const struct string_list *list,
+				   const struct submodule *sub)
+{
+	int label_apply = 0;
+	struct strbuf sb = STRBUF_INIT;
+
+	if (!list)
+		return 1;
+
+	if (sub->labels) {
+		struct string_list_item *item;
+		for_each_string_list_item(item, sub->labels) {
+			strbuf_reset(&sb);
+			strbuf_addf(&sb, "*%s", item->string);
+			if (string_list_has_string(list, sb.buf)) {
+				label_apply = 1;
+				break;
+			}
+		}
+	}
+	if (sub->path) {
+		/*
+		 * NEEDSWORK: This currently works only for
+		 * exact paths, but we want to enable
+		 * inexact matches such wildcards.
+		 */
+		strbuf_reset(&sb);
+		strbuf_addf(&sb, "./%s", sub->path);
+		if (string_list_has_string(list, sb.buf)) {
+			label_apply = 1;
+		}
+	}
+	if (sub->name) {
+		/*
+		 * NEEDSWORK: Same as with path. Do we want to
+		 * support wildcards or such?
+		 */
+		strbuf_reset(&sb);
+		strbuf_addf(&sb, ":%s", sub->name);
+		if (string_list_has_string(list, sb.buf)) {
+			label_apply = 1;
+		}
+	}
+	strbuf_release(&sb);
+
+	return label_apply;
+}
diff --git a/submodule-config.h b/submodule-config.h
index 8d61df3..d67f666 100644
--- a/submodule-config.h
+++ b/submodule-config.h
@@ -30,4 +30,7 @@ const struct submodule *submodule_from_path(const unsigned char *commit_sha1,
 		const char *path);
 void submodule_free(void);
 
+int submodule_applicable_by_labels(const struct string_list *list,
+				   const struct submodule *sub);
+
 #endif /* SUBMODULE_CONFIG_H */
-- 
2.7.0.rc0.45.g6b4c145

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [RFC_PATCHv4 4/7] submodule init: redirect stdout to stderr
  2016-03-22  2:06 [RFC_PATCHv4 0/7] Git submodule labels Stefan Beller
                   ` (2 preceding siblings ...)
  2016-03-22  2:06 ` [RFC_PATCHv4 3/7] submodule-config: add method to check for being labeled Stefan Beller
@ 2016-03-22  2:06 ` Stefan Beller
  2016-03-22  7:46   ` Sebastian Schuberth
  2016-03-22  2:06 ` [RFC_PATCHv4 5/7] submodule update: respect submodule.actionOnLabel Stefan Beller
                   ` (2 subsequent siblings)
  6 siblings, 1 reply; 22+ messages in thread
From: Stefan Beller @ 2016-03-22  2:06 UTC (permalink / raw)
  To: Jens.Lehmann, sschuberth; +Cc: git, Stefan Beller

Reroute the output of stdout to stderr as it is just informative
messages, not to be consumed by machines.

We want to init submodules from the helper for `submodule update`
in a later patch and the stdout output of said helper is consumed
by the parts of `submodule update` which are still written in shell.
So we have to be careful which messages are on stdout.

Signed-off-by: Stefan Beller <sbeller@google.com>
---
 builtin/submodule--helper.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index d942463..a69b1f4 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -268,7 +268,8 @@ static void init_submodule(const char *path, const char *prefix, int quiet)
 			die(_("Failed to register url for submodule path '%s'"),
 			    displaypath);
 		if (!quiet)
-			printf(_("Submodule '%s' (%s) registered for path '%s'\n"),
+			fprintf(stderr,
+				_("Submodule '%s' (%s) registered for path '%s'\n"),
 				sub->name, url, displaypath);
 	}
 
-- 
2.7.0.rc0.45.g6b4c145

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [RFC_PATCHv4 5/7] submodule update: respect submodule.actionOnLabel
  2016-03-22  2:06 [RFC_PATCHv4 0/7] Git submodule labels Stefan Beller
                   ` (3 preceding siblings ...)
  2016-03-22  2:06 ` [RFC_PATCHv4 4/7] submodule init: redirect stdout to stderr Stefan Beller
@ 2016-03-22  2:06 ` Stefan Beller
  2016-03-22 22:40   ` Junio C Hamano
  2016-03-22  2:06 ` [RFC_PATCHv4 6/7] clone: allow specification of submodules to be cloned Stefan Beller
  2016-03-22  2:06 ` [RFC_PATCHv4 7/7] WIP status/diff: respect submodule.actionOnLabel Stefan Beller
  6 siblings, 1 reply; 22+ messages in thread
From: Stefan Beller @ 2016-03-22  2:06 UTC (permalink / raw)
  To: Jens.Lehmann, sschuberth; +Cc: git, Stefan Beller

This change introduces the 'submodule.actionOnLabel' variable
in a repository configuration. Generally speaking 'submodule.actionOnLabel'
restricts the action of a command when no submodules are selected via the
command line explicitely to those submodules, which are selected by
'submodule.actionOnLabel'. It can occur multiple times and can specify
the path, the name or one of the labels of a submodule to select that
submodule.

The introduction of 'submodule.actionOnLabel' starts with
'git submodule update' in this patch and other commands will follow
in later patches.

'submodule.actionOnLabel' implies '--init' in 'git submodule update'.

Signed-off-by: Stefan Beller <sbeller@google.com>

TODO: generic documentation for submodule.actionOnLabel
TODO: documentation for submodule update
Signed-off-by: Stefan Beller <sbeller@google.com>
---
 builtin/submodule--helper.c |  22 ++++++++-
 t/t7400-submodule-basic.sh  | 115 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 136 insertions(+), 1 deletion(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index a69b1f4..93760ec 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -573,6 +573,8 @@ struct submodule_update_clone {
 	int current;
 	struct module_list list;
 	unsigned warn_if_uninitialized : 1;
+	/* patterns to initialize */
+	struct string_list *initialize;
 
 	/* update parameter passed via commandline */
 	struct submodule_update_strategy update;
@@ -590,7 +592,7 @@ struct submodule_update_clone {
 	/* If we want to stop as fast as possible and return an error */
 	unsigned quickstop : 1;
 };
-#define SUBMODULE_UPDATE_CLONE_INIT {0, MODULE_LIST_INIT, 0, \
+#define SUBMODULE_UPDATE_CLONE_INIT {0, MODULE_LIST_INIT, 0, NULL, \
 	SUBMODULE_UPDATE_STRATEGY_INIT, 0, NULL, NULL, NULL, NULL, \
 	STRING_LIST_INIT_DUP, 0}
 
@@ -644,6 +646,15 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,
 	strbuf_reset(&sb);
 	strbuf_addf(&sb, "submodule.%s.url", sub->name);
 	git_config_get_string(sb.buf, &url);
+	if (suc->initialize) {
+		if (!url) {
+			init_submodule(sub->path, suc->prefix, suc->quiet);
+			url = xstrdup(sub->url);
+		}
+		if (!submodule_applicable_by_labels(suc->initialize, sub)
+		    && !suc->warn_if_uninitialized)
+			goto cleanup;
+	}
 	if (!url) {
 		/*
 		 * Only mention uninitialized submodules when their
@@ -745,6 +756,7 @@ static int update_clone(int argc, const char **argv, const char *prefix)
 	const char *update = NULL;
 	int max_jobs = -1;
 	struct string_list_item *item;
+	const struct string_list *list;
 	struct pathspec pathspec;
 	struct submodule_update_clone suc = SUBMODULE_UPDATE_CLONE_INIT;
 
@@ -793,6 +805,14 @@ static int update_clone(int argc, const char **argv, const char *prefix)
 	gitmodules_config();
 	git_config(submodule_config, NULL);
 
+	list = git_config_get_value_multi("submodule.actionOnLabel");
+	if (list) {
+		suc.initialize = xmalloc(sizeof(*suc.initialize));
+		string_list_init(suc.initialize, 1);
+		for_each_string_list_item(item, list)
+			string_list_insert(suc.initialize, item->string);
+	}
+
 	if (max_jobs < 0)
 		max_jobs = parallel_submodules();
 
diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh
index fc948fd..dc45551 100755
--- a/t/t7400-submodule-basic.sh
+++ b/t/t7400-submodule-basic.sh
@@ -1032,4 +1032,119 @@ test_expect_success 'submodule add records multiple labels' '
 	test_cmp expected actual
 '
 
+cat <<EOF > expected
+submodule
+-submodule2
+EOF
+
+test_expect_success 'update initializes all modules when action-on-label configured' '
+	test_when_finished "rm -rf super super_clone" &&
+	mkdir super &&
+	pwd=$(pwd) &&
+	(
+		cd super &&
+		git init &&
+		git submodule add --label labelA file://"$pwd"/example2 submodule &&
+		git submodule add file://"$pwd"/example2 submodule2 &&
+		git commit -a -m "add two modules, one is labled"
+	) &&
+	git clone super super_clone &&
+	(
+		cd super_clone &&
+		git config submodule.actionOnLabel \*labelA &&
+		git submodule update &&
+		git submodule status |cut -c1,42-52 | tr -d " " >../actual
+	) &&
+	test_cmp actual expected
+'
+
+test_expect_success 'submodule update applies to action-on-label selection' '
+	test_when_finished "rm -rf super super_clone" &&
+	mkdir super &&
+	oldSubmoduleHead=$(cd example2 && git rev-parse HEAD) &&
+	pwd=$(pwd) &&
+	(
+		cd super &&
+		git init &&
+		git submodule add --label labelA file://"$pwd"/example2 submodule1 &&
+		git submodule add --label labelA file://"$pwd"/example2 submodule2 &&
+		git submodule add --label labelA file://"$pwd"/example2 submodule3 &&
+		git commit -a -m "add two modules, both are labled"
+	) &&
+	git clone super super_clone &&
+	(
+		cd super_clone &&
+		git config submodule.actionOnLabel \*labelA &&
+		git submodule update
+	) &&
+	(
+		cd example2 &&
+		touch anotherfile &&
+		git add anotherfile &&
+		git commit -m "advance example2" &&
+		git checkout -b branchName
+	) &&
+	newSubmoduleHead=$(cd example2 && git rev-parse HEAD) &&
+	(
+		cd super &&
+		git submodule add --label labelA file://"$pwd"/example2 submodule4 &&
+		git commit -a -m "add another labeled module" &&
+		git config -f .gitmodules submodule.submodule2.label labelB &&
+		git config -f .gitmodules --unset submodule.submodule3.label &&
+		git commit -a -m "unlabel 2 and 3 upstream" &&
+		git submodule foreach git pull origin branchName &&
+		git commit -a -m "update all submodules" &&
+		git submodule status |cut -c1-52 >../actual
+	) &&
+	cat <<EOF >expected &&
+ $newSubmoduleHead submodule1
+ $newSubmoduleHead submodule2
+ $newSubmoduleHead submodule3
+ $newSubmoduleHead submodule4
+EOF
+	test_cmp actual expected &&
+	(
+		cd super_clone &&
+		git pull &&
+		git submodule update &&
+		git submodule status |cut -c1-52 >../actual
+	) &&
+	cat <<EOF >expected &&
+ $newSubmoduleHead submodule1
++$oldSubmoduleHead submodule2
++$oldSubmoduleHead submodule3
+ $newSubmoduleHead submodule4
+EOF
+	test_cmp actual expected
+'
+
+cat <<EOF > expected
+submodule1
+submodule2
+-submodule3
+EOF
+
+test_expect_success 'Change labels in .git/config' '
+	test_when_finished "rm -rf super super_clone" &&
+	mkdir super &&
+	pwd=$(pwd) &&
+	(
+		cd super &&
+		git init &&
+		git submodule add --label labelA file://"$pwd"/example2 submodule1 &&
+		git submodule add file://"$pwd"/example2 submodule2 &&
+		git submodule add file://"$pwd"/example2 submodule3 &&
+		git commit -a -m "add two modules, one is labled"
+	) &&
+	git clone super super_clone &&
+	(
+		cd super_clone &&
+		git config submodule.actionOnLabel \*labelA &&
+		git config submodule.submodule2.label labelA
+		git submodule update &&
+		git submodule status |cut -c1,42-52 | tr -d " " >../actual
+	) &&
+	test_cmp actual expected
+'
+
 test_done
-- 
2.7.0.rc0.45.g6b4c145

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [RFC_PATCHv4 6/7] clone: allow specification of submodules to be cloned
  2016-03-22  2:06 [RFC_PATCHv4 0/7] Git submodule labels Stefan Beller
                   ` (4 preceding siblings ...)
  2016-03-22  2:06 ` [RFC_PATCHv4 5/7] submodule update: respect submodule.actionOnLabel Stefan Beller
@ 2016-03-22  2:06 ` Stefan Beller
  2016-03-22  2:06 ` [RFC_PATCHv4 7/7] WIP status/diff: respect submodule.actionOnLabel Stefan Beller
  6 siblings, 0 replies; 22+ messages in thread
From: Stefan Beller @ 2016-03-22  2:06 UTC (permalink / raw)
  To: Jens.Lehmann, sschuberth; +Cc: git, Stefan Beller

This is in line with clone being the contraction of
    mkdir <path> && cd <path>
    git init
    git config
    git fetch
    git submodule update

Signed-off-by: Stefan Beller <sbeller@google.com>
---
 Documentation/git-clone.txt |   6 ++
 builtin/clone.c             |  40 ++++++++++++-
 t/t7400-submodule-basic.sh  | 134 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 177 insertions(+), 3 deletions(-)

diff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt
index 6db7b6d..4baf444 100644
--- a/Documentation/git-clone.txt
+++ b/Documentation/git-clone.txt
@@ -214,6 +214,12 @@ objects from the source repository into a pack in the cloned repository.
 	repository does not have a worktree/checkout (i.e. if any of
 	`--no-checkout`/`-n`, `--bare`, or `--mirror` is given)
 
+--init-submodule::
+	After the repository is cloned, specified submodules are cloned.
+	It is possible to give multiple specifications by repeating the
+	argument. This option will be recorded in the repository config
+	as `submodule.autoInitialize`.
+
 --separate-git-dir=<git dir>::
 	Instead of placing the cloned repository where it is supposed
 	to be, place the cloned repository at the specified directory,
diff --git a/builtin/clone.c b/builtin/clone.c
index b004fb4..e2af9b8 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -51,6 +51,22 @@ static struct string_list option_config;
 static struct string_list option_reference;
 static int option_dissociate;
 static int max_jobs = -1;
+static struct string_list init_submodules;
+
+static int init_submodules_cb(const struct option *opt, const char *arg, int unset)
+{
+	struct string_list_item *item;
+	struct string_list sl = STRING_LIST_INIT_DUP;
+
+	if (unset)
+		return -1;
+
+	string_list_split(&sl, arg, ',', -1);
+	for_each_string_list_item(item, &sl)
+		string_list_append((struct string_list *)opt->value, item->string);
+
+	return 0;
+}
 
 static struct option builtin_clone_options[] = {
 	OPT__VERBOSITY(&option_verbosity),
@@ -95,6 +111,8 @@ static struct option builtin_clone_options[] = {
 		   N_("separate git dir from working tree")),
 	OPT_STRING_LIST('c', "config", &option_config, N_("key=value"),
 			N_("set config inside the new repository")),
+	OPT_CALLBACK(0, "init-submodule", &init_submodules, N_("string"),
+			N_("clone specific submodules"), init_submodules_cb),
 	OPT_END()
 };
 
@@ -723,17 +741,24 @@ static int checkout(void)
 	err |= run_hook_le(NULL, "post-checkout", sha1_to_hex(null_sha1),
 			   sha1_to_hex(sha1), "1", NULL);
 
-	if (!err && option_recursive) {
+	if (err)
+		goto out;
+
+	if (option_recursive || init_submodules.nr > 0) {
 		struct argv_array args = ARGV_ARRAY_INIT;
-		argv_array_pushl(&args, "submodule", "update", "--init", "--recursive", NULL);
+		argv_array_pushl(&args, "submodule", "update", NULL);
 
+		if (option_recursive) {
+			argv_array_pushf(&args, "--init");
+			argv_array_pushf(&args, "--recursive");
+		}
 		if (max_jobs != -1)
 			argv_array_pushf(&args, "--jobs=%d", max_jobs);
 
 		err = run_command_v_opt(args.argv, RUN_GIT_CMD);
 		argv_array_clear(&args);
 	}
-
+out:
 	return err;
 }
 
@@ -868,6 +893,15 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
 		option_no_checkout = 1;
 	}
 
+	if (init_submodules.nr > 0) {
+		struct string_list_item *item;
+		struct strbuf sb = STRBUF_INIT;
+		for_each_string_list_item(item, &init_submodules) {
+			strbuf_addf(&sb, "submodule.actionOnLabel=%s", item->string);
+			string_list_append(&option_config, strbuf_detach(&sb, 0));
+		}
+	}
+
 	if (!option_origin)
 		option_origin = "origin";
 
diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh
index dc45551..58da5c4 100755
--- a/t/t7400-submodule-basic.sh
+++ b/t/t7400-submodule-basic.sh
@@ -1147,4 +1147,138 @@ test_expect_success 'Change labels in .git/config' '
 	test_cmp actual expected
 '
 
+cat <<EOF > expected
+submodule
+submodule1
+submodule2
+-submodule3
+EOF
+
+test_expect_success 'submodule update auto-initializes submodules' '
+	test_when_finished "rm -rf super super_clone" &&
+	mkdir super &&
+	pwd=$(pwd) &&
+	(
+		cd super &&
+		git init &&
+		git submodule add --label labelA file://"$pwd"/example2 submodule &&
+		git submodule add --name specialSnowflake file://"$pwd"/example2 submodule1 &&
+		git submodule add file://"$pwd"/example2 submodule2 &&
+		git submodule add file://"$pwd"/example2 submodule3 &&
+		git commit -a -m "create repository with 4 submodules, one is labeled"
+	) &&
+	git clone super super_clone &&
+	(
+		cd super_clone &&
+		git config submodule.actionOnLabel \*labelA &&
+		git config --add submodule.actionOnLabel :specialSnowflake &&
+		git config --add submodule.actionOnLabel ./submodule2 &&
+		git submodule update &&
+		git submodule status |cut -c1,42-52 | tr -d " " >../actual
+	) &&
+	test_cmp actual expected
+'
+
+cat <<EOF > expected
+submodule
+-submodule1
+EOF
+
+test_expect_success 'clone --init-submodule works' '
+	test_when_finished "rm -rf super super_clone" &&
+	mkdir super &&
+	pwd=$(pwd) &&
+	(
+		cd super &&
+		git init &&
+		git submodule add --label labelA file://"$pwd"/example2 submodule &&
+		git submodule add file://"$pwd"/example2 submodule1 &&
+		git commit -a -m "create repository with 2 submodules, one is in a group"
+	) &&
+	git clone --init-submodule \*labelA super super_clone &&
+	(
+		cd super_clone &&
+		git submodule status |cut -c1,42-52 | tr -d " " >../actual
+	) &&
+	test_cmp actual expected
+'
+
+cat <<EOF > expected
+-submodule1
+submoduleA
+-submoduleB
+submoduleC
+-submoduleD
+submoduleE
+EOF
+
+test_expect_success 'clone with multiple --init-submodule options' '
+	test_when_finished "rm -rf super super_clone" &&
+	mkdir super &&
+	pwd=$(pwd) &&
+	(
+		cd super &&
+		git init &&
+		git submodule add --label groupA file://"$pwd"/example2 submoduleA &&
+		git submodule add --label groupB file://"$pwd"/example2 submoduleB &&
+		git submodule add --label groupC file://"$pwd"/example2 submoduleC &&
+		git submodule add --label groupD --name submoduleE file://"$pwd"/example2 submoduleD &&
+		git submodule add --label groupE --name submoduleD file://"$pwd"/example2 submoduleE &&
+		git submodule add file://"$pwd"/example2 submodule1 &&
+		git commit -a -m "create repository with submodules groups"
+	) &&
+	git clone --init-submodule=\*groupA --init-submodule ./submoduleC --init-submodule :submoduleD super super_clone &&
+	(
+		cd super_clone &&
+		git submodule status |cut -c1,42-52 | tr -d " " >../actual
+	) &&
+	test_cmp actual expected
+'
+
+cat <<EOF > expected1
+submoduleA
+-submoduleB
+EOF
+
+cat <<EOF > expected2
+submoduleA
+-submoduleB
+submoduleC
+EOF
+
+test_expect_success 'clone and subsequent updates correctly auto-initialize submodules' '
+	test_when_finished "rm -rf super super_clone" &&
+	mkdir super &&
+	pwd=$(pwd) &&
+	(
+		cd super &&
+		git init &&
+		git submodule add --label LA file://"$pwd"/example2 submoduleA &&
+		git submodule add file://"$pwd"/example2 submoduleB &&
+		git commit -a -m "create repository with submodules groups"
+	) &&
+	git clone --init-submodule=\*LA super super_clone &&
+	(
+		cd super_clone &&
+		git submodule status |cut -c1,42-52 | tr -d " " >../actual
+	) &&
+	test_cmp actual expected1 &&
+	(
+		cd super &&
+		git init &&
+		git submodule add --label LA file://"$pwd"/example2 submoduleC &&
+		git commit -a -m "add another labled submodule"
+	) &&
+	(
+		cd super_clone &&
+		# obtain the new superproject
+		git pull &&
+		# submoduleC should just appear as it has the label LA
+		# which was configured to autoInitialize in git clone
+		git submodule update &&
+		git submodule status |cut -c1,42-52 | tr -d " " >../actual
+	) &&
+	test_cmp actual expected2
+'
+
 test_done
-- 
2.7.0.rc0.45.g6b4c145

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [RFC_PATCHv4 7/7] WIP status/diff: respect submodule.actionOnLabel
  2016-03-22  2:06 [RFC_PATCHv4 0/7] Git submodule labels Stefan Beller
                   ` (5 preceding siblings ...)
  2016-03-22  2:06 ` [RFC_PATCHv4 6/7] clone: allow specification of submodules to be cloned Stefan Beller
@ 2016-03-22  2:06 ` Stefan Beller
  6 siblings, 0 replies; 22+ messages in thread
From: Stefan Beller @ 2016-03-22  2:06 UTC (permalink / raw)
  To: Jens.Lehmann, sschuberth; +Cc: git, Stefan Beller

When 'submodule.actionOnLabel' is set, submodules which are selected by
a label will be inspected in status and diff. If a submodule is not
selected, it is ignored.

Signed-off-by: Stefan Beller <sbeller@google.com>
---
 submodule.c                | 15 +++++++++++++++
 t/t7400-submodule-basic.sh | 13 +++++++++++++
 2 files changed, 28 insertions(+)

diff --git a/submodule.c b/submodule.c
index 458189c..86c0a49 100644
--- a/submodule.c
+++ b/submodule.c
@@ -20,6 +20,8 @@ static struct string_list changed_submodule_paths;
 static int initialized_fetch_ref_tips;
 static struct sha1_array ref_tips_before_fetch;
 static struct sha1_array ref_tips_after_fetch;
+static struct string_list action_labels = STRING_LIST_INIT_DUP;
+static int use_action_labels;
 
 /*
  * The following flag is set if the .gitmodules file is unmerged. We then
@@ -161,10 +163,20 @@ void set_diffopt_flags_from_submodule_config(struct diff_options *diffopt,
 {
 	const struct submodule *submodule = submodule_from_path(null_sha1, path);
 	if (submodule) {
+		char *ignoreMode;
 		if (submodule->ignore)
 			handle_ignore_submodules_arg(diffopt, submodule->ignore);
 		else if (gitmodules_is_unmerged)
 			DIFF_OPT_SET(diffopt, IGNORE_SUBMODULES);
+
+		if (!use_action_labels)
+			return;
+
+		if (submodule_applicable_by_labels(&action_labels, submodule))
+			ignoreMode = "none";
+		else
+			ignoreMode = "all";
+		handle_ignore_submodules_arg(diffopt, ignoreMode);
 	}
 }
 
@@ -175,6 +187,9 @@ int submodule_config(const char *var, const char *value, void *cb)
 		if (parallel_jobs < 0)
 			die(_("negative values not allowed for submodule.fetchJobs"));
 		return 0;
+	} else if (!strcmp(var, "submodule.actiononlabel")) {
+		use_action_labels = 1;
+		string_list_append(&action_labels, value);
 	} else if (starts_with(var, "submodule."))
 		return parse_submodule_config_option(var, value);
 	else if (!strcmp(var, "fetch.recursesubmodules")) {
diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh
index 58da5c4..52ea3c6 100755
--- a/t/t7400-submodule-basic.sh
+++ b/t/t7400-submodule-basic.sh
@@ -1281,4 +1281,17 @@ test_expect_success 'clone and subsequent updates correctly auto-initialize subm
 	test_cmp actual expected2
 '
 
+test_expect_success 'status ignores unlabeled submodules' '
+	# Add submodules with and without label
+	# perform a change on disk
+	# observe the change indicated by git status
+	# the submodule not in the label system is ignored.
+	true && true
+'
+
+test_expect_success 'diff applies to action-on-label selection' '
+	# similar to status
+	true && true
+'
+
 test_done
-- 
2.7.0.rc0.45.g6b4c145

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* Re: [RFC_PATCHv4 4/7] submodule init: redirect stdout to stderr
  2016-03-22  2:06 ` [RFC_PATCHv4 4/7] submodule init: redirect stdout to stderr Stefan Beller
@ 2016-03-22  7:46   ` Sebastian Schuberth
  2016-03-22 16:14     ` Junio C Hamano
  0 siblings, 1 reply; 22+ messages in thread
From: Sebastian Schuberth @ 2016-03-22  7:46 UTC (permalink / raw)
  To: Stefan Beller; +Cc: Jens.Lehmann, Git Mailing List

On Tue, Mar 22, 2016 at 3:06 AM, Stefan Beller <sbeller@google.com> wrote:

> Reroute the output of stdout to stderr as it is just informative
> messages, not to be consumed by machines.

Just wondering, what's Git's policy on this? This message is neither
an error nor a warning, but just purely informational. As such it
semantically does not belong to stderr, or? On the other hand I see
multiple places in Git's code where printing to stderr is (mis-)used
for informational messages, probably to separate output to be consumed
by humans from output to be consumed by machines, like you do here.

-- 
Sebastian Schuberth

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [RFC_PATCHv4 4/7] submodule init: redirect stdout to stderr
  2016-03-22  7:46   ` Sebastian Schuberth
@ 2016-03-22 16:14     ` Junio C Hamano
  2016-03-22 16:47       ` Stefan Beller
  2016-03-22 17:15       ` Junio C Hamano
  0 siblings, 2 replies; 22+ messages in thread
From: Junio C Hamano @ 2016-03-22 16:14 UTC (permalink / raw)
  To: Sebastian Schuberth; +Cc: Stefan Beller, Jens.Lehmann, Git Mailing List

Sebastian Schuberth <sschuberth@gmail.com> writes:

> Just wondering, what's Git's policy on this? This message is neither
> an error nor a warning, but just purely informational. As such it
> semantically does not belong to stderr, or?

Some people believe that a clean execution should not give anything
to stderr (Tcl is one example, IIRC), but I think the core part of
Git takes the opposite stance (probably unix tradition?).  Anything
that is not the primary output of the program should go to stdout.

We may not have been very strict in code reviews to enfore it, and
especially on the fringes of the system it may be easy to find
violators, though.

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [RFC_PATCHv4 4/7] submodule init: redirect stdout to stderr
  2016-03-22 16:14     ` Junio C Hamano
@ 2016-03-22 16:47       ` Stefan Beller
  2016-03-22 16:56         ` Sebastian Schuberth
  2016-03-22 17:15       ` Junio C Hamano
  1 sibling, 1 reply; 22+ messages in thread
From: Stefan Beller @ 2016-03-22 16:47 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Sebastian Schuberth, Jens Lehmann, Git Mailing List

On Tue, Mar 22, 2016 at 9:14 AM, Junio C Hamano <gitster@pobox.com> wrote:
> Sebastian Schuberth <sschuberth@gmail.com> writes:

My commit message is bad, and I should feel bad. ;)
Quoting from 68b939b2f097b6675 (2013-09-18, clone: send diagnostic
messages to stderr, by Jeff who writes the best commit messages):
    Putting messages like "Cloning into.." and "done" on stdout
    is un-Unix and uselessly clutters the stdout channel. Send
    them to stderr.
    ...
    This should not regress any scripts that try to parse the
    current output, as the output is already internationalized
    and therefore unstable.

Quoting another fbf71645d12d302 (Tue Dec 15 16:04:06 2015,
submodule.c: write "Fetching submodule <foo>" to stderr, by Jonathan)
    The "Pushing submodule <foo>" progress output correctly goes to
    stderr, but "Fetching submodule <foo>" is going to stdout by
    mistake.  Fix it to write to stderr.

>> Just wondering, what's Git's policy on this? This message is neither
>> an error nor a warning, but just purely informational. As such it
>> semantically does not belong to stderr, or?

I think the stance of Git is to write only machine readable stuff to stdout,
and essentially all _(translated) stuff (i.e. human readable) goes to stderr as
some sort of help or progress indication.

>

>
> Some people believe that a clean execution should not give anything
> to stderr (Tcl is one example, IIRC), but I think the core part of
> Git takes the opposite stance (probably unix tradition?).  Anything
> that is not the primary output of the program should go to stdout.
>
> We may not have been very strict in code reviews to enfore it, and
> especially on the fringes of the system it may be easy to find
> violators, though.
>

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [RFC_PATCHv4 4/7] submodule init: redirect stdout to stderr
  2016-03-22 16:47       ` Stefan Beller
@ 2016-03-22 16:56         ` Sebastian Schuberth
  0 siblings, 0 replies; 22+ messages in thread
From: Sebastian Schuberth @ 2016-03-22 16:56 UTC (permalink / raw)
  To: Stefan Beller; +Cc: Junio C Hamano, Jens Lehmann, Git Mailing List

On Tue, Mar 22, 2016 at 5:47 PM, Stefan Beller <sbeller@google.com> wrote:

> I think the stance of Git is to write only machine readable stuff to stdout,
> and essentially all _(translated) stuff (i.e. human readable) goes to stderr as
> some sort of help or progress indication.

Thanks for the clarification.

-- 
Sebastian Schuberth

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [RFC_PATCHv4 4/7] submodule init: redirect stdout to stderr
  2016-03-22 16:14     ` Junio C Hamano
  2016-03-22 16:47       ` Stefan Beller
@ 2016-03-22 17:15       ` Junio C Hamano
  1 sibling, 0 replies; 22+ messages in thread
From: Junio C Hamano @ 2016-03-22 17:15 UTC (permalink / raw)
  To: Sebastian Schuberth; +Cc: Stefan Beller, Jens.Lehmann, Git Mailing List

Junio C Hamano <gitster@pobox.com> writes:

> Sebastian Schuberth <sschuberth@gmail.com> writes:
>
>> Just wondering, what's Git's policy on this? This message is neither
>> an error nor a warning, but just purely informational. As such it
>> semantically does not belong to stderr, or?
>
> Some people believe that a clean execution should not give anything
> to stderr (Tcl is one example, IIRC), but I think the core part of
> Git takes the opposite stance (probably unix tradition?).  Anything
> that is not the primary output of the program should go to stdout.

Ehh, "should go to" is obviously "should not go to".

>
> We may not have been very strict in code reviews to enfore it, and
> especially on the fringes of the system it may be easy to find
> violators, though.

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [RFC_PATCHv4 1/7] git submodule: teach `add` to label submodules
  2016-03-22  2:06 ` [RFC_PATCHv4 1/7] git submodule: teach `add` to label submodules Stefan Beller
@ 2016-03-22 22:28   ` Junio C Hamano
  2016-03-22 22:34   ` Junio C Hamano
  1 sibling, 0 replies; 22+ messages in thread
From: Junio C Hamano @ 2016-03-22 22:28 UTC (permalink / raw)
  To: Stefan Beller; +Cc: Jens.Lehmann, sschuberth, git

Stefan Beller <sbeller@google.com> writes:

> When adding new submodules, you can specify the
> label(s) the submodule belongs to by giving one or more
> --label arguments. This will record each label in the
> .gitmodules file as a value of the key
> "submodule.$NAME.label".

Can you define the semantics of "label" with a bit more detail in
the doc?  For example, it is unclear from the description if a
submodule can have multiple labels (I can read the patch, and I am
not asking you to explain it to _me_).  It also is unclear if a user
can tweak the set of labels a submodule has locally, iow, without
modifying .gitmodules that would end up affecting other people.

I think the expected use of "label" is to have the whole project to
share which labels a given submodule should have (i.e. it is not
like branches you can freely create in your repository, but more
like tags that give all project participant shared understanding of
stable anchoring points), and I am guessing that there is no need
for "repository local labels" for that reason, but we'd need to see
that kind of design decisions spelled out in the documentation to
avoid end-user confusion.

Thanks.

> Signed-off-by: Stefan Beller <sbeller@google.com>
> ---
>  Documentation/git-submodule.txt |  5 ++++-
>  git-submodule.sh                | 14 +++++++++++++-
>  t/t7400-submodule-basic.sh      | 32 ++++++++++++++++++++++++++++++++
>  3 files changed, 49 insertions(+), 2 deletions(-)
>
> diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt
> index 13adebf..c0744eb 100644
> --- a/Documentation/git-submodule.txt
> +++ b/Documentation/git-submodule.txt
> @@ -9,7 +9,7 @@ git-submodule - Initialize, update or inspect submodules
>  SYNOPSIS
>  --------
>  [verse]
> -'git submodule' [--quiet] add [-b <branch>] [-f|--force] [--name <name>]
> +'git submodule' [--quiet] add [-b <branch>] [-f|--force] [-l|--label <label>]
>  	      [--reference <repository>] [--depth <depth>] [--] <repository> [<path>]
>  'git submodule' [--quiet] status [--cached] [--recursive] [--] [<path>...]
>  'git submodule' [--quiet] init [--] [<path>...]
> @@ -101,6 +101,9 @@ is the superproject and submodule repositories will be kept
>  together in the same relative location, and only the
>  superproject's URL needs to be provided: git-submodule will correctly
>  locate the submodule using the relative URL in .gitmodules.
> ++
> +If at least one label argument was given, all labels are recorded in the
> +.gitmodules file in the label fields.
>  
>  status::
>  	Show the status of the submodules. This will print the SHA-1 of the
> diff --git a/git-submodule.sh b/git-submodule.sh
> index 97a3097..def1e1c 100755
> --- a/git-submodule.sh
> +++ b/git-submodule.sh
> @@ -5,7 +5,7 @@
>  # Copyright (c) 2007 Lars Hjemli
>  
>  dashless=$(basename "$0" | sed -e 's/-/ /')
> -USAGE="[--quiet] add [-b <branch>] [-f|--force] [--name <name>] [--reference <repository>] [--] <repository> [<path>]
> +USAGE="[--quiet] add [-b <branch>] [-f|--force] [--name <name>] [--reference <repository>] [-l|--label <label>][--] <repository> [<path>]
>     or: $dashless [--quiet] status [--cached] [--recursive] [--] [<path>...]
>     or: $dashless [--quiet] init [--] [<path>...]
>     or: $dashless [--quiet] deinit [-f|--force] [--] <path>...
> @@ -130,6 +130,7 @@ cmd_add()
>  {
>  	# parse $args after "submodule ... add".
>  	reference_path=
> +	labels=
>  	while test $# -ne 0
>  	do
>  		case "$1" in
> @@ -165,6 +166,13 @@ cmd_add()
>  		--depth=*)
>  			depth=$1
>  			;;
> +		-l|--label)
> +			labels="${labels} $2"
> +			shift
> +			;;
> +		--label=*)
> +			labels="${labels} ${1#--label=}"
> +			;;
>  		--)
>  			shift
>  			break
> @@ -292,6 +300,10 @@ Use -f if you really want to add it." >&2
>  
>  	git config -f .gitmodules submodule."$sm_name".path "$sm_path" &&
>  	git config -f .gitmodules submodule."$sm_name".url "$repo" &&
> +	for label in $labels
> +	do
> +		git config --add -f .gitmodules submodule."$sm_name".label "${label}"
> +	done &&
>  	if test -n "$branch"
>  	then
>  		git config -f .gitmodules submodule."$sm_name".branch "$branch"
> diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh
> index 5991e3c..fc948fd 100755
> --- a/t/t7400-submodule-basic.sh
> +++ b/t/t7400-submodule-basic.sh
> @@ -986,6 +986,7 @@ test_expect_success 'submodule with UTF-8 name' '
>  '
>  
>  test_expect_success 'submodule add clone shallow submodule' '
> +	test_when_finished "rm -rf super" &&
>  	mkdir super &&
>  	pwd=$(pwd) &&
>  	(
> @@ -999,5 +1000,36 @@ test_expect_success 'submodule add clone shallow submodule' '
>  	)
>  '
>  
> +test_expect_success 'submodule add records a label' '
> +	test_when_finished "rm -rf super" &&
> +	mkdir super &&
> +	pwd=$(pwd) &&
> +	(
> +		cd super &&
> +		git init &&
> +		git submodule add --label labelA file://"$pwd"/example2 submodule &&
> +		git config -f .gitmodules submodule."submodule".label >actual &&
> +		echo labelA >expected &&
> +		test_cmp expected actual
> +	)
> +'
> +
> +cat >expected <<-EOF
> +labelA
> +labelB
> +EOF
> +
> +test_expect_success 'submodule add records multiple labels' '
> +	test_when_finished "rm -rf super" &&
> +	mkdir super &&
> +	pwd=$(pwd) &&
> +	(
> +		cd super &&
> +		git init &&
> +		git submodule add --label=labelA -l labelB file://"$pwd"/example2 submodule &&
> +		git config --get-all -f .gitmodules submodule."submodule".label >../actual
> +	) &&
> +	test_cmp expected actual
> +'
>  
>  test_done

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [RFC_PATCHv4 3/7] submodule-config: add method to check for being labeled
  2016-03-22  2:06 ` [RFC_PATCHv4 3/7] submodule-config: add method to check for being labeled Stefan Beller
@ 2016-03-22 22:30   ` Junio C Hamano
  2016-03-23 21:05     ` Stefan Beller
  0 siblings, 1 reply; 22+ messages in thread
From: Junio C Hamano @ 2016-03-22 22:30 UTC (permalink / raw)
  To: Stefan Beller; +Cc: Jens.Lehmann, sschuberth, git

Stefan Beller <sbeller@google.com> writes:

> In later patches we need to tell if a submodule is labeled by
> the given labels.
>
> Signed-off-by: Stefan Beller <sbeller@google.com>
> ---

Hmph, I would have expected that something like this would touch the
module_list() implementation.  Probably that would happen in future
steps, I guess?

>  submodule-config.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
>  submodule-config.h |  3 +++
>  2 files changed, 51 insertions(+)
>
> diff --git a/submodule-config.c b/submodule-config.c
> index 7b48e59..b10a773 100644
> --- a/submodule-config.c
> +++ b/submodule-config.c
> @@ -493,3 +493,51 @@ void submodule_free(void)
>  	cache_free(&cache);
>  	is_cache_init = 0;
>  }
> +
> +int submodule_applicable_by_labels(const struct string_list *list,
> +				   const struct submodule *sub)
> +{
> +	int label_apply = 0;
> +	struct strbuf sb = STRBUF_INIT;
> +
> +	if (!list)
> +		return 1;
> +
> +	if (sub->labels) {
> +		struct string_list_item *item;
> +		for_each_string_list_item(item, sub->labels) {
> +			strbuf_reset(&sb);
> +			strbuf_addf(&sb, "*%s", item->string);
> +			if (string_list_has_string(list, sb.buf)) {
> +				label_apply = 1;
> +				break;
> +			}
> +		}
> +	}
> +	if (sub->path) {
> +		/*
> +		 * NEEDSWORK: This currently works only for
> +		 * exact paths, but we want to enable
> +		 * inexact matches such wildcards.
> +		 */
> +		strbuf_reset(&sb);
> +		strbuf_addf(&sb, "./%s", sub->path);
> +		if (string_list_has_string(list, sb.buf)) {
> +			label_apply = 1;
> +		}
> +	}
> +	if (sub->name) {
> +		/*
> +		 * NEEDSWORK: Same as with path. Do we want to
> +		 * support wildcards or such?
> +		 */
> +		strbuf_reset(&sb);
> +		strbuf_addf(&sb, ":%s", sub->name);
> +		if (string_list_has_string(list, sb.buf)) {
> +			label_apply = 1;
> +		}
> +	}
> +	strbuf_release(&sb);
> +
> +	return label_apply;
> +}
> diff --git a/submodule-config.h b/submodule-config.h
> index 8d61df3..d67f666 100644
> --- a/submodule-config.h
> +++ b/submodule-config.h
> @@ -30,4 +30,7 @@ const struct submodule *submodule_from_path(const unsigned char *commit_sha1,
>  		const char *path);
>  void submodule_free(void);
>  
> +int submodule_applicable_by_labels(const struct string_list *list,
> +				   const struct submodule *sub);
> +
>  #endif /* SUBMODULE_CONFIG_H */

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [RFC_PATCHv4 1/7] git submodule: teach `add` to label submodules
  2016-03-22  2:06 ` [RFC_PATCHv4 1/7] git submodule: teach `add` to label submodules Stefan Beller
  2016-03-22 22:28   ` Junio C Hamano
@ 2016-03-22 22:34   ` Junio C Hamano
  1 sibling, 0 replies; 22+ messages in thread
From: Junio C Hamano @ 2016-03-22 22:34 UTC (permalink / raw)
  To: Stefan Beller; +Cc: Jens.Lehmann, sschuberth, git

Stefan Beller <sbeller@google.com> writes:

> When adding new submodules, you can specify the
> label(s) the submodule belongs to by giving one or more
> --label arguments. This will record each label in the
> .gitmodules file as a value of the key
> "submodule.$NAME.label".

Having an ability to add a label when adding a brand new submodule
would be a "nice-to-have" convenience feature, but I think it is
better to start a series to add a new concept by "need-to-have"
infrastructure that is lower-level.  E.g. "git submodule label"
command that allows you to things like:

 - query the labels on a given submodule
 - add a label to a given submodule (or to a set of submodules)
 - remove a label to a given submodule (or to a set of submodules)

And with that, the user can start using the feature without having
"git submodule add --label".

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [RFC_PATCHv4 5/7] submodule update: respect submodule.actionOnLabel
  2016-03-22  2:06 ` [RFC_PATCHv4 5/7] submodule update: respect submodule.actionOnLabel Stefan Beller
@ 2016-03-22 22:40   ` Junio C Hamano
  2016-03-23 23:21     ` Stefan Beller
  0 siblings, 1 reply; 22+ messages in thread
From: Junio C Hamano @ 2016-03-22 22:40 UTC (permalink / raw)
  To: Stefan Beller; +Cc: Jens.Lehmann, sschuberth, git

Stefan Beller <sbeller@google.com> writes:

> This change introduces the 'submodule.actionOnLabel' variable
> in a repository configuration. Generally speaking 'submodule.actionOnLabel'
> restricts the action of a command when no submodules are selected via the
> command line explicitely to those submodules, which are selected by
> 'submodule.actionOnLabel'. It can occur multiple times and can specify
> the path, the name or one of the labels of a submodule to select that
> submodule.
>
> The introduction of 'submodule.actionOnLabel' starts with
> 'git submodule update' in this patch and other commands will follow
> in later patches.
>
> 'submodule.actionOnLabel' implies '--init' in 'git submodule update'.
>
> Signed-off-by: Stefan Beller <sbeller@google.com>
>
> TODO: generic documentation for submodule.actionOnLabel
> TODO: documentation for submodule update

TODO: a name that matches the concept better.

So in general

	$ git submodule $subcmd .

may be the way to say "do $subcmd to all submodules", and

	$ git submodule $subcmd

may have been "operate on nothing" (or may have been "operate on
everything"), but with this feature, 

	$ git submodule $subcmd

will by default operate on submodules that match the criteria the
new configuration variable specifies?

I suspect that copying this from .gitmodules to .git/config will
have security implications and will not be done?  What is the
expected way for projects to suggest which set of submodules are the
good ones to work on by default using this mechanism?

> Signed-off-by: Stefan Beller <sbeller@google.com>
> ---
>  builtin/submodule--helper.c |  22 ++++++++-
>  t/t7400-submodule-basic.sh  | 115 ++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 136 insertions(+), 1 deletion(-)
>
> diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
> index a69b1f4..93760ec 100644
> --- a/builtin/submodule--helper.c
> +++ b/builtin/submodule--helper.c
> @@ -573,6 +573,8 @@ struct submodule_update_clone {
>  	int current;
>  	struct module_list list;
>  	unsigned warn_if_uninitialized : 1;
> +	/* patterns to initialize */
> +	struct string_list *initialize;
>  
>  	/* update parameter passed via commandline */
>  	struct submodule_update_strategy update;
> @@ -590,7 +592,7 @@ struct submodule_update_clone {
>  	/* If we want to stop as fast as possible and return an error */
>  	unsigned quickstop : 1;
>  };
> -#define SUBMODULE_UPDATE_CLONE_INIT {0, MODULE_LIST_INIT, 0, \
> +#define SUBMODULE_UPDATE_CLONE_INIT {0, MODULE_LIST_INIT, 0, NULL, \
>  	SUBMODULE_UPDATE_STRATEGY_INIT, 0, NULL, NULL, NULL, NULL, \
>  	STRING_LIST_INIT_DUP, 0}
>  
> @@ -644,6 +646,15 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,
>  	strbuf_reset(&sb);
>  	strbuf_addf(&sb, "submodule.%s.url", sub->name);
>  	git_config_get_string(sb.buf, &url);
> +	if (suc->initialize) {
> +		if (!url) {
> +			init_submodule(sub->path, suc->prefix, suc->quiet);
> +			url = xstrdup(sub->url);
> +		}
> +		if (!submodule_applicable_by_labels(suc->initialize, sub)
> +		    && !suc->warn_if_uninitialized)
> +			goto cleanup;
> +	}
>  	if (!url) {
>  		/*
>  		 * Only mention uninitialized submodules when their
> @@ -745,6 +756,7 @@ static int update_clone(int argc, const char **argv, const char *prefix)
>  	const char *update = NULL;
>  	int max_jobs = -1;
>  	struct string_list_item *item;
> +	const struct string_list *list;
>  	struct pathspec pathspec;
>  	struct submodule_update_clone suc = SUBMODULE_UPDATE_CLONE_INIT;
>  
> @@ -793,6 +805,14 @@ static int update_clone(int argc, const char **argv, const char *prefix)
>  	gitmodules_config();
>  	git_config(submodule_config, NULL);
>  
> +	list = git_config_get_value_multi("submodule.actionOnLabel");
> +	if (list) {
> +		suc.initialize = xmalloc(sizeof(*suc.initialize));
> +		string_list_init(suc.initialize, 1);
> +		for_each_string_list_item(item, list)
> +			string_list_insert(suc.initialize, item->string);
> +	}
> +
>  	if (max_jobs < 0)
>  		max_jobs = parallel_submodules();
>  
> diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh
> index fc948fd..dc45551 100755
> --- a/t/t7400-submodule-basic.sh
> +++ b/t/t7400-submodule-basic.sh
> @@ -1032,4 +1032,119 @@ test_expect_success 'submodule add records multiple labels' '
>  	test_cmp expected actual
>  '
>  
> +cat <<EOF > expected
> +submodule
> +-submodule2
> +EOF
> +
> +test_expect_success 'update initializes all modules when action-on-label configured' '
> +	test_when_finished "rm -rf super super_clone" &&
> +	mkdir super &&
> +	pwd=$(pwd) &&
> +	(
> +		cd super &&
> +		git init &&
> +		git submodule add --label labelA file://"$pwd"/example2 submodule &&
> +		git submodule add file://"$pwd"/example2 submodule2 &&
> +		git commit -a -m "add two modules, one is labled"
> +	) &&
> +	git clone super super_clone &&
> +	(
> +		cd super_clone &&
> +		git config submodule.actionOnLabel \*labelA &&
> +		git submodule update &&
> +		git submodule status |cut -c1,42-52 | tr -d " " >../actual
> +	) &&
> +	test_cmp actual expected
> +'
> +
> +test_expect_success 'submodule update applies to action-on-label selection' '
> +	test_when_finished "rm -rf super super_clone" &&
> +	mkdir super &&
> +	oldSubmoduleHead=$(cd example2 && git rev-parse HEAD) &&
> +	pwd=$(pwd) &&
> +	(
> +		cd super &&
> +		git init &&
> +		git submodule add --label labelA file://"$pwd"/example2 submodule1 &&
> +		git submodule add --label labelA file://"$pwd"/example2 submodule2 &&
> +		git submodule add --label labelA file://"$pwd"/example2 submodule3 &&
> +		git commit -a -m "add two modules, both are labled"
> +	) &&
> +	git clone super super_clone &&
> +	(
> +		cd super_clone &&
> +		git config submodule.actionOnLabel \*labelA &&
> +		git submodule update
> +	) &&
> +	(
> +		cd example2 &&
> +		touch anotherfile &&
> +		git add anotherfile &&
> +		git commit -m "advance example2" &&
> +		git checkout -b branchName
> +	) &&
> +	newSubmoduleHead=$(cd example2 && git rev-parse HEAD) &&
> +	(
> +		cd super &&
> +		git submodule add --label labelA file://"$pwd"/example2 submodule4 &&
> +		git commit -a -m "add another labeled module" &&
> +		git config -f .gitmodules submodule.submodule2.label labelB &&
> +		git config -f .gitmodules --unset submodule.submodule3.label &&
> +		git commit -a -m "unlabel 2 and 3 upstream" &&
> +		git submodule foreach git pull origin branchName &&
> +		git commit -a -m "update all submodules" &&
> +		git submodule status |cut -c1-52 >../actual
> +	) &&
> +	cat <<EOF >expected &&
> + $newSubmoduleHead submodule1
> + $newSubmoduleHead submodule2
> + $newSubmoduleHead submodule3
> + $newSubmoduleHead submodule4
> +EOF
> +	test_cmp actual expected &&
> +	(
> +		cd super_clone &&
> +		git pull &&
> +		git submodule update &&
> +		git submodule status |cut -c1-52 >../actual
> +	) &&
> +	cat <<EOF >expected &&
> + $newSubmoduleHead submodule1
> ++$oldSubmoduleHead submodule2
> ++$oldSubmoduleHead submodule3
> + $newSubmoduleHead submodule4
> +EOF
> +	test_cmp actual expected
> +'
> +
> +cat <<EOF > expected
> +submodule1
> +submodule2
> +-submodule3
> +EOF
> +
> +test_expect_success 'Change labels in .git/config' '
> +	test_when_finished "rm -rf super super_clone" &&
> +	mkdir super &&
> +	pwd=$(pwd) &&
> +	(
> +		cd super &&
> +		git init &&
> +		git submodule add --label labelA file://"$pwd"/example2 submodule1 &&
> +		git submodule add file://"$pwd"/example2 submodule2 &&
> +		git submodule add file://"$pwd"/example2 submodule3 &&
> +		git commit -a -m "add two modules, one is labled"
> +	) &&
> +	git clone super super_clone &&
> +	(
> +		cd super_clone &&
> +		git config submodule.actionOnLabel \*labelA &&
> +		git config submodule.submodule2.label labelA
> +		git submodule update &&
> +		git submodule status |cut -c1,42-52 | tr -d " " >../actual
> +	) &&
> +	test_cmp actual expected
> +'
> +
>  test_done

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [RFC_PATCHv4 3/7] submodule-config: add method to check for being labeled
  2016-03-22 22:30   ` Junio C Hamano
@ 2016-03-23 21:05     ` Stefan Beller
  0 siblings, 0 replies; 22+ messages in thread
From: Stefan Beller @ 2016-03-23 21:05 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jens Lehmann, Sebastian Schuberth, git@vger.kernel.org

On Tue, Mar 22, 2016 at 3:30 PM, Junio C Hamano <gitster@pobox.com> wrote:
> Stefan Beller <sbeller@google.com> writes:
>
>> In later patches we need to tell if a submodule is labeled by
>> the given labels.
>>
>> Signed-off-by: Stefan Beller <sbeller@google.com>
>> ---
>
> Hmph, I would have expected that something like this would touch the
> module_list() implementation.  Probably that would happen in future
> steps, I guess?

I would have guessed, too. And I was about to say Jens argued against that in
an earlier patch series [1]. However I miss remembered and Jens pointed at
"git submodule init --label/groups" being a bad idea, not in the helper.

So we could still have a "git submodule--helper labels_apply <submodule>"
query to expose this to shell parts. Most of the shell parts use module_list
so we could integrate that there too. ("git submodule_helper list
--labeled-only")

[1] $gmane/281670, specifically $gmane/281720


>
>>  submodule-config.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
>>  submodule-config.h |  3 +++
>>  2 files changed, 51 insertions(+)
>>
>> diff --git a/submodule-config.c b/submodule-config.c
>> index 7b48e59..b10a773 100644
>> --- a/submodule-config.c
>> +++ b/submodule-config.c
>> @@ -493,3 +493,51 @@ void submodule_free(void)
>>       cache_free(&cache);
>>       is_cache_init = 0;
>>  }
>> +
>> +int submodule_applicable_by_labels(const struct string_list *list,
>> +                                const struct submodule *sub)
>> +{
>> +     int label_apply = 0;
>> +     struct strbuf sb = STRBUF_INIT;
>> +
>> +     if (!list)
>> +             return 1;
>> +
>> +     if (sub->labels) {
>> +             struct string_list_item *item;
>> +             for_each_string_list_item(item, sub->labels) {
>> +                     strbuf_reset(&sb);
>> +                     strbuf_addf(&sb, "*%s", item->string);
>> +                     if (string_list_has_string(list, sb.buf)) {
>> +                             label_apply = 1;
>> +                             break;
>> +                     }
>> +             }
>> +     }
>> +     if (sub->path) {
>> +             /*
>> +              * NEEDSWORK: This currently works only for
>> +              * exact paths, but we want to enable
>> +              * inexact matches such wildcards.
>> +              */
>> +             strbuf_reset(&sb);
>> +             strbuf_addf(&sb, "./%s", sub->path);
>> +             if (string_list_has_string(list, sb.buf)) {
>> +                     label_apply = 1;
>> +             }
>> +     }
>> +     if (sub->name) {
>> +             /*
>> +              * NEEDSWORK: Same as with path. Do we want to
>> +              * support wildcards or such?
>> +              */
>> +             strbuf_reset(&sb);
>> +             strbuf_addf(&sb, ":%s", sub->name);
>> +             if (string_list_has_string(list, sb.buf)) {
>> +                     label_apply = 1;
>> +             }
>> +     }
>> +     strbuf_release(&sb);
>> +
>> +     return label_apply;
>> +}
>> diff --git a/submodule-config.h b/submodule-config.h
>> index 8d61df3..d67f666 100644
>> --- a/submodule-config.h
>> +++ b/submodule-config.h
>> @@ -30,4 +30,7 @@ const struct submodule *submodule_from_path(const unsigned char *commit_sha1,
>>               const char *path);
>>  void submodule_free(void);
>>
>> +int submodule_applicable_by_labels(const struct string_list *list,
>> +                                const struct submodule *sub);
>> +
>>  #endif /* SUBMODULE_CONFIG_H */

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [RFC_PATCHv4 5/7] submodule update: respect submodule.actionOnLabel
  2016-03-22 22:40   ` Junio C Hamano
@ 2016-03-23 23:21     ` Stefan Beller
  2016-03-24  0:13       ` Junio C Hamano
  0 siblings, 1 reply; 22+ messages in thread
From: Stefan Beller @ 2016-03-23 23:21 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jens Lehmann, Sebastian Schuberth, git@vger.kernel.org

On Tue, Mar 22, 2016 at 3:40 PM, Junio C Hamano <gitster@pobox.com> wrote:
> Stefan Beller <sbeller@google.com> writes:
>
>> This change introduces the 'submodule.actionOnLabel' variable
>> in a repository configuration. Generally speaking 'submodule.actionOnLabel'
>> restricts the action of a command when no submodules are selected via the
>> command line explicitely to those submodules, which are selected by
>> 'submodule.actionOnLabel'. It can occur multiple times and can specify
>> the path, the name or one of the labels of a submodule to select that
>> submodule.
>>
>> The introduction of 'submodule.actionOnLabel' starts with
>> 'git submodule update' in this patch and other commands will follow
>> in later patches.
>>
>> 'submodule.actionOnLabel' implies '--init' in 'git submodule update'.
>>
>> Signed-off-by: Stefan Beller <sbeller@google.com>
>>
>> TODO: generic documentation for submodule.actionOnLabel
>> TODO: documentation for submodule update
>
> TODO: a name that matches the concept better.

This is one of the hardest parts of the series so far. The last reviews
were mostly bike shedding about the name of the concept and I thought
we were settled to actionOnLabel as that fits best to what we want to do.

So let's revisit that. My current understanding of the design:

Generic properties in the data model:
 * Each submodule has a set of "things" attached to it. (A submodule
   can have none, one or many)
 * A "thing" can be attached to many submodules (That's why
   it was called groups in v1, and labels now)
 * The attachments of "things" to submodules can be viewed as a bipartite
   graph.
 * The attachment needs to work in a way, such that upstream
   can influence and redefine these attachments (e.g. .gitmodules file
   as part of the repo; another approach would be to have yet another file
   .gitlabels or such where you'd have a list of submodules belonging to a
   "thing")
 * If this feature is enabled, the user can select a set of submodules by
   selecting a set of "things" and all submodules connected to these things
   in the bipartite graph are selected. The expectation for a graph is to
   select a lot fewer "things" than submodules. By having this indirection
   via the graph, the selection of a subset of submodules is expected to
   be easier.

Properties I derived from discussion and the data model:
 * The user does not need to have a way of overwriting the bipartite graph,
   because they can specify submodules by these "things", by path or by name.
   (It would be convenient to do be able to overwrite these, but it is
not a strict
   requirement as the you can get any specification via a set of paths)

 * The user needs to make the explicit choice to use the new feature
   or not, as it has implications on the default behavior of submodule
   commands.

 * To make change of selection easy (which happens e.g. when switching
   branches or pulling in upstream changes), all submodules are initialized
   by default.

 * Once this feature is enabled a command doesn't apply to all initialized
   submodules by default any more, but the
   default set of submodules will be the selected set via the
   bipartite graph of "things".

(Originally I typed out some implementation specific thoughts, but they are
loaded with even more assumptions, so maybe we'd want to stay on this
high level first)

So any other naming proposals?

Thanks,
Stefan

>
> So in general
>
>         $ git submodule $subcmd .
>
> may be the way to say "do $subcmd to all submodules", and
>
>         $ git submodule $subcmd
>
> may have been "operate on nothing" (or may have been "operate on
> everything"), but with this feature,
>
>         $ git submodule $subcmd
>
> will by default operate on submodules that match the criteria the
> new configuration variable specifies?
>
> I suspect that copying this from .gitmodules to .git/config will
> have security implications and will not be done?  What is the
> expected way for projects to suggest which set of submodules are the
> good ones to work on by default using this mechanism?
>
>> Signed-off-by: Stefan Beller <sbeller@google.com>
>> ---
>>  builtin/submodule--helper.c |  22 ++++++++-
>>  t/t7400-submodule-basic.sh  | 115 ++++++++++++++++++++++++++++++++++++++++++++
>>  2 files changed, 136 insertions(+), 1 deletion(-)
>>
>> diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
>> index a69b1f4..93760ec 100644
>> --- a/builtin/submodule--helper.c
>> +++ b/builtin/submodule--helper.c
>> @@ -573,6 +573,8 @@ struct submodule_update_clone {
>>       int current;
>>       struct module_list list;
>>       unsigned warn_if_uninitialized : 1;
>> +     /* patterns to initialize */
>> +     struct string_list *initialize;
>>
>>       /* update parameter passed via commandline */
>>       struct submodule_update_strategy update;
>> @@ -590,7 +592,7 @@ struct submodule_update_clone {
>>       /* If we want to stop as fast as possible and return an error */
>>       unsigned quickstop : 1;
>>  };
>> -#define SUBMODULE_UPDATE_CLONE_INIT {0, MODULE_LIST_INIT, 0, \
>> +#define SUBMODULE_UPDATE_CLONE_INIT {0, MODULE_LIST_INIT, 0, NULL, \
>>       SUBMODULE_UPDATE_STRATEGY_INIT, 0, NULL, NULL, NULL, NULL, \
>>       STRING_LIST_INIT_DUP, 0}
>>
>> @@ -644,6 +646,15 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,
>>       strbuf_reset(&sb);
>>       strbuf_addf(&sb, "submodule.%s.url", sub->name);
>>       git_config_get_string(sb.buf, &url);
>> +     if (suc->initialize) {
>> +             if (!url) {
>> +                     init_submodule(sub->path, suc->prefix, suc->quiet);
>> +                     url = xstrdup(sub->url);
>> +             }
>> +             if (!submodule_applicable_by_labels(suc->initialize, sub)
>> +                 && !suc->warn_if_uninitialized)
>> +                     goto cleanup;
>> +     }
>>       if (!url) {
>>               /*
>>                * Only mention uninitialized submodules when their
>> @@ -745,6 +756,7 @@ static int update_clone(int argc, const char **argv, const char *prefix)
>>       const char *update = NULL;
>>       int max_jobs = -1;
>>       struct string_list_item *item;
>> +     const struct string_list *list;
>>       struct pathspec pathspec;
>>       struct submodule_update_clone suc = SUBMODULE_UPDATE_CLONE_INIT;
>>
>> @@ -793,6 +805,14 @@ static int update_clone(int argc, const char **argv, const char *prefix)
>>       gitmodules_config();
>>       git_config(submodule_config, NULL);
>>
>> +     list = git_config_get_value_multi("submodule.actionOnLabel");
>> +     if (list) {
>> +             suc.initialize = xmalloc(sizeof(*suc.initialize));
>> +             string_list_init(suc.initialize, 1);
>> +             for_each_string_list_item(item, list)
>> +                     string_list_insert(suc.initialize, item->string);
>> +     }
>> +
>>       if (max_jobs < 0)
>>               max_jobs = parallel_submodules();
>>
>> diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh
>> index fc948fd..dc45551 100755
>> --- a/t/t7400-submodule-basic.sh
>> +++ b/t/t7400-submodule-basic.sh
>> @@ -1032,4 +1032,119 @@ test_expect_success 'submodule add records multiple labels' '
>>       test_cmp expected actual
>>  '
>>
>> +cat <<EOF > expected
>> +submodule
>> +-submodule2
>> +EOF
>> +
>> +test_expect_success 'update initializes all modules when action-on-label configured' '
>> +     test_when_finished "rm -rf super super_clone" &&
>> +     mkdir super &&
>> +     pwd=$(pwd) &&
>> +     (
>> +             cd super &&
>> +             git init &&
>> +             git submodule add --label labelA file://"$pwd"/example2 submodule &&
>> +             git submodule add file://"$pwd"/example2 submodule2 &&
>> +             git commit -a -m "add two modules, one is labled"
>> +     ) &&
>> +     git clone super super_clone &&
>> +     (
>> +             cd super_clone &&
>> +             git config submodule.actionOnLabel \*labelA &&
>> +             git submodule update &&
>> +             git submodule status |cut -c1,42-52 | tr -d " " >../actual
>> +     ) &&
>> +     test_cmp actual expected
>> +'
>> +
>> +test_expect_success 'submodule update applies to action-on-label selection' '
>> +     test_when_finished "rm -rf super super_clone" &&
>> +     mkdir super &&
>> +     oldSubmoduleHead=$(cd example2 && git rev-parse HEAD) &&
>> +     pwd=$(pwd) &&
>> +     (
>> +             cd super &&
>> +             git init &&
>> +             git submodule add --label labelA file://"$pwd"/example2 submodule1 &&
>> +             git submodule add --label labelA file://"$pwd"/example2 submodule2 &&
>> +             git submodule add --label labelA file://"$pwd"/example2 submodule3 &&
>> +             git commit -a -m "add two modules, both are labled"
>> +     ) &&
>> +     git clone super super_clone &&
>> +     (
>> +             cd super_clone &&
>> +             git config submodule.actionOnLabel \*labelA &&
>> +             git submodule update
>> +     ) &&
>> +     (
>> +             cd example2 &&
>> +             touch anotherfile &&
>> +             git add anotherfile &&
>> +             git commit -m "advance example2" &&
>> +             git checkout -b branchName
>> +     ) &&
>> +     newSubmoduleHead=$(cd example2 && git rev-parse HEAD) &&
>> +     (
>> +             cd super &&
>> +             git submodule add --label labelA file://"$pwd"/example2 submodule4 &&
>> +             git commit -a -m "add another labeled module" &&
>> +             git config -f .gitmodules submodule.submodule2.label labelB &&
>> +             git config -f .gitmodules --unset submodule.submodule3.label &&
>> +             git commit -a -m "unlabel 2 and 3 upstream" &&
>> +             git submodule foreach git pull origin branchName &&
>> +             git commit -a -m "update all submodules" &&
>> +             git submodule status |cut -c1-52 >../actual
>> +     ) &&
>> +     cat <<EOF >expected &&
>> + $newSubmoduleHead submodule1
>> + $newSubmoduleHead submodule2
>> + $newSubmoduleHead submodule3
>> + $newSubmoduleHead submodule4
>> +EOF
>> +     test_cmp actual expected &&
>> +     (
>> +             cd super_clone &&
>> +             git pull &&
>> +             git submodule update &&
>> +             git submodule status |cut -c1-52 >../actual
>> +     ) &&
>> +     cat <<EOF >expected &&
>> + $newSubmoduleHead submodule1
>> ++$oldSubmoduleHead submodule2
>> ++$oldSubmoduleHead submodule3
>> + $newSubmoduleHead submodule4
>> +EOF
>> +     test_cmp actual expected
>> +'
>> +
>> +cat <<EOF > expected
>> +submodule1
>> +submodule2
>> +-submodule3
>> +EOF
>> +
>> +test_expect_success 'Change labels in .git/config' '
>> +     test_when_finished "rm -rf super super_clone" &&
>> +     mkdir super &&
>> +     pwd=$(pwd) &&
>> +     (
>> +             cd super &&
>> +             git init &&
>> +             git submodule add --label labelA file://"$pwd"/example2 submodule1 &&
>> +             git submodule add file://"$pwd"/example2 submodule2 &&
>> +             git submodule add file://"$pwd"/example2 submodule3 &&
>> +             git commit -a -m "add two modules, one is labled"
>> +     ) &&
>> +     git clone super super_clone &&
>> +     (
>> +             cd super_clone &&
>> +             git config submodule.actionOnLabel \*labelA &&
>> +             git config submodule.submodule2.label labelA
>> +             git submodule update &&
>> +             git submodule status |cut -c1,42-52 | tr -d " " >../actual
>> +     ) &&
>> +     test_cmp actual expected
>> +'
>> +
>>  test_done

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [RFC_PATCHv4 5/7] submodule update: respect submodule.actionOnLabel
  2016-03-23 23:21     ` Stefan Beller
@ 2016-03-24  0:13       ` Junio C Hamano
  2016-03-24 19:54         ` Stefan Beller
  0 siblings, 1 reply; 22+ messages in thread
From: Junio C Hamano @ 2016-03-24  0:13 UTC (permalink / raw)
  To: Stefan Beller; +Cc: Jens Lehmann, Sebastian Schuberth, git@vger.kernel.org

Stefan Beller <sbeller@google.com> writes:

> On Tue, Mar 22, 2016 at 3:40 PM, Junio C Hamano <gitster@pobox.com> wrote:
>> Stefan Beller <sbeller@google.com> writes:
>>
>>> This change introduces the 'submodule.actionOnLabel' variable
>>> in a repository configuration. Generally speaking 'submodule.actionOnLabel'
>>> restricts the action of a command when no submodules are selected via the
>>> command line explicitely to those submodules, which are selected by
>>> 'submodule.actionOnLabel'. It can occur multiple times and can specify
>>> the path, the name or one of the labels of a submodule to select that
>>> submodule.
>>>
>>> The introduction of 'submodule.actionOnLabel' starts with
>>> 'git submodule update' in this patch and other commands will follow
>>> in later patches.
>>>
>>> 'submodule.actionOnLabel' implies '--init' in 'git submodule update'.
>>>
>>> Signed-off-by: Stefan Beller <sbeller@google.com>
>>>
>>> TODO: generic documentation for submodule.actionOnLabel
>>> TODO: documentation for submodule update
>>
>> TODO: a name that matches the concept better.
>
> This is one of the hardest parts of the series so far. The last reviews
> were mostly bike shedding about the name of the concept and I thought
> we were settled to actionOnLabel as that fits best to what we want to do.
>
> So let's revisit that. My current understanding of the design:

I am not questioning the name "label" to call the facility that
allows projects to group submodules together, and that serves as one
of the ways to choose what subset of submodules are worked on by
default.  There is no need to revisit that part.

What I am questioning is

	action On Label

because

 (1) it sounds as if that configuration were a way to choose what
     action is done to the chosen subset of submodules;

 (2) it sounds as if the only way to choose a subset of submodules
     to be operated on by default is via the "label" mechanism.

And from your writing (omitted), I think we agree that we definitely
want to avoid the misunderstanding that is (1).  This variable does
not specify what is done--this specifies what subset of submodules
are to be operated on.  Having "action" in the name of the variable
is wrong.

And from the proposed log message, it is clear that "label" is not
the only way to specify the subset of submodules to be worked on,
i.e. "... can specify the path, name or the labels".   Having
"label" in the variable name is wrong.

I am tempted to suggest submodule.defaultOperand and I am fairly
sure "default" part of that name gets the concept much better than
"actionOnLabel", but there probably are much better words than
Operand.

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [RFC_PATCHv4 5/7] submodule update: respect submodule.actionOnLabel
  2016-03-24  0:13       ` Junio C Hamano
@ 2016-03-24 19:54         ` Stefan Beller
  2016-03-24 21:14           ` Junio C Hamano
  0 siblings, 1 reply; 22+ messages in thread
From: Stefan Beller @ 2016-03-24 19:54 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jens Lehmann, Sebastian Schuberth, git@vger.kernel.org

On Wed, Mar 23, 2016 at 5:13 PM, Junio C Hamano <gitster@pobox.com> wrote:
> Stefan Beller <sbeller@google.com> writes:
>
>> On Tue, Mar 22, 2016 at 3:40 PM, Junio C Hamano <gitster@pobox.com> wrote:
>>> Stefan Beller <sbeller@google.com> writes:
>>>
>>>> This change introduces the 'submodule.actionOnLabel' variable
>>>> in a repository configuration. Generally speaking 'submodule.actionOnLabel'
>>>> restricts the action of a command when no submodules are selected via the
>>>> command line explicitely to those submodules, which are selected by
>>>> 'submodule.actionOnLabel'. It can occur multiple times and can specify
>>>> the path, the name or one of the labels of a submodule to select that
>>>> submodule.
>>>>
>>>> The introduction of 'submodule.actionOnLabel' starts with
>>>> 'git submodule update' in this patch and other commands will follow
>>>> in later patches.
>>>>
>>>> 'submodule.actionOnLabel' implies '--init' in 'git submodule update'.
>>>>
>>>> Signed-off-by: Stefan Beller <sbeller@google.com>
>>>>
>>>> TODO: generic documentation for submodule.actionOnLabel
>>>> TODO: documentation for submodule update
>>>
>>> TODO: a name that matches the concept better.
>>
>> This is one of the hardest parts of the series so far. The last reviews
>> were mostly bike shedding about the name of the concept and I thought
>> we were settled to actionOnLabel as that fits best to what we want to do.
>>
>> So let's revisit that. My current understanding of the design:
>
> I am not questioning the name "label" to call the facility that
> allows projects to group submodules together, and that serves as one
> of the ways to choose what subset of submodules are worked on by
> default.  There is no need to revisit that part.
>
> What I am questioning is
>
>         action On Label
>
> because
>
>  (1) it sounds as if that configuration were a way to choose what
>      action is done to the chosen subset of submodules;
>
>  (2) it sounds as if the only way to choose a subset of submodules
>      to be operated on by default is via the "label" mechanism.
>
> And from your writing (omitted), I think we agree that we definitely
> want to avoid the misunderstanding that is (1).  This variable does
> not specify what is done--this specifies what subset of submodules
> are to be operated on.  Having "action" in the name of the variable
> is wrong.
>
> And from the proposed log message, it is clear that "label" is not
> the only way to specify the subset of submodules to be worked on,
> i.e. "... can specify the path, name or the labels".   Having
> "label" in the variable name is wrong.
>
> I am tempted to suggest submodule.defaultOperand and I am fairly
> sure "default" part of that name gets the concept much better than
> "actionOnLabel", but there probably are much better words than
> Operand.

I immediately thought of defaultActionset, because "default", as well as the
"actionset" conveys the concept of choosing a subset of submodules to operate
on. However You may mistake it as defaultActionSet, i.e. what action is set
by default.

Maybe we can revive the term "group" and call it submodule.defaultGroup.
The defaultGroup is defined by selection of names, paths and labels.

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [RFC_PATCHv4 5/7] submodule update: respect submodule.actionOnLabel
  2016-03-24 19:54         ` Stefan Beller
@ 2016-03-24 21:14           ` Junio C Hamano
  0 siblings, 0 replies; 22+ messages in thread
From: Junio C Hamano @ 2016-03-24 21:14 UTC (permalink / raw)
  To: Stefan Beller; +Cc: Jens Lehmann, Sebastian Schuberth, git@vger.kernel.org

Stefan Beller <sbeller@google.com> writes:

> Maybe we can revive the term "group" and call it submodule.defaultGroup.
> The defaultGroup is defined by selection of names, paths and labels.

There are many ways to specify one or more of submodules:

 - By giving "pathspecs", you would choose submodules whose paths
   match them;

 - By giving one or more "names", you would choose the submodule
   with one of these names; or

 - By giving one or more "labels", you would choose submodules that
   have one of these labels.

It is perfectly fine to call the chosen set of submodules "group of
submodules".  It does not have any connotation on what is to be done
about the group, so that is probably the best word suggested so far
in the thread.

^ permalink raw reply	[flat|nested] 22+ messages in thread

end of thread, other threads:[~2016-03-24 21:14 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-03-22  2:06 [RFC_PATCHv4 0/7] Git submodule labels Stefan Beller
2016-03-22  2:06 ` [RFC_PATCHv4 1/7] git submodule: teach `add` to label submodules Stefan Beller
2016-03-22 22:28   ` Junio C Hamano
2016-03-22 22:34   ` Junio C Hamano
2016-03-22  2:06 ` [RFC_PATCHv4 2/7] submodule-config: keep labels around Stefan Beller
2016-03-22  2:06 ` [RFC_PATCHv4 3/7] submodule-config: add method to check for being labeled Stefan Beller
2016-03-22 22:30   ` Junio C Hamano
2016-03-23 21:05     ` Stefan Beller
2016-03-22  2:06 ` [RFC_PATCHv4 4/7] submodule init: redirect stdout to stderr Stefan Beller
2016-03-22  7:46   ` Sebastian Schuberth
2016-03-22 16:14     ` Junio C Hamano
2016-03-22 16:47       ` Stefan Beller
2016-03-22 16:56         ` Sebastian Schuberth
2016-03-22 17:15       ` Junio C Hamano
2016-03-22  2:06 ` [RFC_PATCHv4 5/7] submodule update: respect submodule.actionOnLabel Stefan Beller
2016-03-22 22:40   ` Junio C Hamano
2016-03-23 23:21     ` Stefan Beller
2016-03-24  0:13       ` Junio C Hamano
2016-03-24 19:54         ` Stefan Beller
2016-03-24 21:14           ` Junio C Hamano
2016-03-22  2:06 ` [RFC_PATCHv4 6/7] clone: allow specification of submodules to be cloned Stefan Beller
2016-03-22  2:06 ` [RFC_PATCHv4 7/7] WIP status/diff: respect submodule.actionOnLabel Stefan Beller

Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).