threads / patch / 44736

patch, 3 partspush only submodules

Subject: [PATCH 0/3] push only submodules

## tl;dr

7 messages between Dec 19, 2016 and Dec 20, 2016. Diffs are folded; open one to read it.

replies: 6people: 3as markdown or json

Brandon Williams· Dec 19, 2016, 18:25 UTC · lore

This series teaches 'git push' to be able to only push submodules while leaving a superproject unpushed.

This is a desirable feature in a scenario where updates to the superproject are handled automatically by some other means, perhaps a code review tool. In this scenario a developer could make a change which spans multiple submodules and then push their commits for code review. Upon completion of the code review, their commits can be accepted and applied to their respective submodules while the code review tool can then automatically update the superproject to the most recent SHA1 of each submodule. This would eliminate the merge conflicts in the superproject that could occur if multiple people are contributing to the same submodule.

Brandon Williams (3):
  transport: refactor flag #defines to be more readable
  submodules: add RECURSE_SUBMODULES_ONLY value
  push: add option to push only submodules
 builtin/push.c                 |  2 ++
 submodule-config.c             |  2 ++
 submodule.h                    |  1 +
 t/t5531-deep-submodule-push.sh | 21 +++++++++++++++++++++
 transport.c                    | 15 +++++++++++----
 transport.h                    | 31 ++++++++++++++++---------------
 6 files changed, 53 insertions(+), 19 deletions(-)
-- 
2.8.0.rc3.226.g39d4020
Brandon Williams· Dec 19, 2016, 18:25 UTC · re: Brandon Williams · lore

[PATCH 1/3] transport: refactor flag #defines to be more readable

All of the #defines for the TRANSPORT_* flags are hardcoded to be powers of two. This can be error prone when adding a new flag and is difficult to read. This patch refactors these defines to instead use a shift operation to generate the flags. This makes adding an additional flag simpilar and makes the defines easier to read.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 transport.h | 30 +++++++++++++++---------------
 1 file changed, 15 insertions(+), 15 deletions(-)
Show changes to transport.h +15 −15
diff --git a/transport.h b/transport.h
index b8e4ee8..1b65458 100644
--- a/transport.h
+++ b/transport.h
@@ -131,21 +131,21 @@ struct transport {
 	enum transport_family family;
 };
 
-#define TRANSPORT_PUSH_ALL 1
-#define TRANSPORT_PUSH_FORCE 2
-#define TRANSPORT_PUSH_DRY_RUN 4
-#define TRANSPORT_PUSH_MIRROR 8
-#define TRANSPORT_PUSH_PORCELAIN 16
-#define TRANSPORT_PUSH_SET_UPSTREAM 32
-#define TRANSPORT_RECURSE_SUBMODULES_CHECK 64
-#define TRANSPORT_PUSH_PRUNE 128
-#define TRANSPORT_RECURSE_SUBMODULES_ON_DEMAND 256
-#define TRANSPORT_PUSH_NO_HOOK 512
-#define TRANSPORT_PUSH_FOLLOW_TAGS 1024
-#define TRANSPORT_PUSH_CERT_ALWAYS 2048
-#define TRANSPORT_PUSH_CERT_IF_ASKED 4096
-#define TRANSPORT_PUSH_ATOMIC 8192
-#define TRANSPORT_PUSH_OPTIONS 16384
+#define TRANSPORT_PUSH_ALL			(1<<0)
+#define TRANSPORT_PUSH_FORCE			(1<<1)
+#define TRANSPORT_PUSH_DRY_RUN			(1<<2)
+#define TRANSPORT_PUSH_MIRROR			(1<<3)
+#define TRANSPORT_PUSH_PORCELAIN		(1<<4)
+#define TRANSPORT_PUSH_SET_UPSTREAM		(1<<5)
+#define TRANSPORT_RECURSE_SUBMODULES_CHECK	(1<<6)
+#define TRANSPORT_PUSH_PRUNE			(1<<7)
+#define TRANSPORT_RECURSE_SUBMODULES_ON_DEMAND	(1<<8)
+#define TRANSPORT_PUSH_NO_HOOK			(1<<9)
+#define TRANSPORT_PUSH_FOLLOW_TAGS		(1<<10)
+#define TRANSPORT_PUSH_CERT_ALWAYS		(1<<11)
+#define TRANSPORT_PUSH_CERT_IF_ASKED		(1<<12)
+#define TRANSPORT_PUSH_ATOMIC			(1<<13)
+#define TRANSPORT_PUSH_OPTIONS			(1<<14)
 
 extern int transport_summary_width(const struct ref *refs);
 
-- 
2.8.0.rc3.226.g39d4020
Brandon Williams· Dec 19, 2016, 18:25 UTC · re: Brandon Williams · lore

[PATCH 2/3] submodules: add RECURSE_SUBMODULES_ONLY value

Add the `RECURSE_SUBMODULES_ONLY` enum value to submodule.h. This enum value will be used in a later patch to push to indicate that only submodules should be pushed, while the superproject should remain unpushed.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 submodule-config.c | 2 ++
 submodule.h        | 1 +
 2 files changed, 3 insertions(+)
Show changes to 2 files +3 −0

submodule-config.c, submodule.h

diff --git a/submodule-config.c b/submodule-config.c
index 098085b..33eb62d 100644
--- a/submodule-config.c
+++ b/submodule-config.c
@@ -251,6 +251,8 @@ static int parse_push_recurse(const char *opt, const char *arg,
 			return RECURSE_SUBMODULES_ON_DEMAND;
 		else if (!strcmp(arg, "check"))
 			return RECURSE_SUBMODULES_CHECK;
+		else if (!strcmp(arg, "only"))
+			return RECURSE_SUBMODULES_ONLY;
 		else if (die_on_error)
 			die("bad %s argument: %s", opt, arg);
 		else
diff --git a/submodule.h b/submodule.h
index 23d7668..4a83a4c 100644
--- a/submodule.h
+++ b/submodule.h
@@ -6,6 +6,7 @@ struct argv_array;
 struct sha1_array;
 
 enum {
+	RECURSE_SUBMODULES_ONLY = -5,
 	RECURSE_SUBMODULES_CHECK = -4,
 	RECURSE_SUBMODULES_ERROR = -3,
 	RECURSE_SUBMODULES_NONE = -2,
-- 
2.8.0.rc3.226.g39d4020
Brandon Williams· Dec 19, 2016, 18:25 UTC · re: Brandon Williams · lore

[PATCH 3/3] push: add option to push only submodules

Teach push the --recurse-submodules=only option. This enables push to recursively push all unpushed submodules while leaving the superproject unpushed.

This is a desirable feature in a scenario where updates to the superproject are handled automatically by some other means, perhaps a code review tool. In this scenario a developer could make a change which spans multiple submodules and then push their commits for code review. Upon completion of the code review, their commits can be accepted and applied to their respective submodules while the code review tool can then automatically update the superproject to the most recent SHA1 of each submodule. This would eliminate the merge conflicts in the superproject that could occur if multiple people are contributing to the same submodule.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 builtin/push.c                 |  2 ++
 t/t5531-deep-submodule-push.sh | 21 +++++++++++++++++++++
 transport.c                    | 15 +++++++++++----
 transport.h                    |  1 +
 4 files changed, 35 insertions(+), 4 deletions(-)
Show changes to 4 files +35 −4

builtin/push.c, t/t5531-deep-submodule-push.sh, transport.c, transport.h

diff --git a/builtin/push.c b/builtin/push.c
index 3bb9d6b..9433797 100644
--- a/builtin/push.c
+++ b/builtin/push.c
@@ -565,6 +565,8 @@ int cmd_push(int argc, const char **argv, const char *prefix)
 		flags |= TRANSPORT_RECURSE_SUBMODULES_CHECK;
 	else if (recurse_submodules == RECURSE_SUBMODULES_ON_DEMAND)
 		flags |= TRANSPORT_RECURSE_SUBMODULES_ON_DEMAND;
+	else if (recurse_submodules == RECURSE_SUBMODULES_ONLY)
+		flags |= TRANSPORT_RECURSE_SUBMODULES_ONLY;
 
 	if (tags)
 		add_refspec("refs/tags/*");
diff --git a/t/t5531-deep-submodule-push.sh b/t/t5531-deep-submodule-push.sh
index 1524ff5..676d686 100755
--- a/t/t5531-deep-submodule-push.sh
+++ b/t/t5531-deep-submodule-push.sh
@@ -454,4 +454,25 @@ test_expect_success 'push --dry-run does not recursively update submodules' '
 	test_cmp expected_submodule actual_submodule
 '
 
+test_expect_success 'push --dry-run does not recursively update submodules' '
+	git -C work push --dry-run --recurse-submodules=only ../pub.git master &&
+
+	git -C submodule.git rev-parse master >actual_submodule &&
+	git -C pub.git rev-parse master >actual_pub &&
+	test_cmp expected_pub actual_pub &&
+	test_cmp expected_submodule actual_submodule
+'
+
+test_expect_success 'push only unpushed submodules recursively' '
+	git -C pub.git rev-parse master >expected_pub &&
+	git -C work/gar/bage rev-parse master >expected_submodule &&
+
+	git -C work push --recurse-submodules=only ../pub.git master &&
+
+	git -C submodule.git rev-parse master >actual_submodule &&
+	git -C pub.git rev-parse master >actual_pub &&
+	test_cmp expected_submodule actual_submodule &&
+	test_cmp expected_pub actual_pub
+'
+
 test_done
diff --git a/transport.c b/transport.c
index 04e5d66..20ebee8 100644
--- a/transport.c
+++ b/transport.c
@@ -947,7 +947,9 @@ int transport_push(struct transport *transport,
 			if (run_pre_push_hook(transport, remote_refs))
 				return -1;
 
-		if ((flags & TRANSPORT_RECURSE_SUBMODULES_ON_DEMAND) && !is_bare_repository()) {
+		if ((flags & (TRANSPORT_RECURSE_SUBMODULES_ON_DEMAND |
+			      TRANSPORT_RECURSE_SUBMODULES_ONLY)) &&
+		    !is_bare_repository()) {
 			struct ref *ref = remote_refs;
 			struct sha1_array commits = SHA1_ARRAY_INIT;
 
@@ -965,7 +967,8 @@ int transport_push(struct transport *transport,
 		}
 
 		if (((flags & TRANSPORT_RECURSE_SUBMODULES_CHECK) ||
-		     ((flags & TRANSPORT_RECURSE_SUBMODULES_ON_DEMAND) &&
+		     ((flags & (TRANSPORT_RECURSE_SUBMODULES_ON_DEMAND |
+				TRANSPORT_RECURSE_SUBMODULES_ONLY)) &&
 		      !pretend)) && !is_bare_repository()) {
 			struct ref *ref = remote_refs;
 			struct string_list needs_pushing = STRING_LIST_INIT_DUP;
@@ -984,7 +987,10 @@ int transport_push(struct transport *transport,
 			sha1_array_clear(&commits);
 		}
 
-		push_ret = transport->push_refs(transport, remote_refs, flags);
+		if (!(flags & TRANSPORT_RECURSE_SUBMODULES_ONLY))
+			push_ret = transport->push_refs(transport, remote_refs, flags);
+		else
+			push_ret = 0;
 		err = push_had_errors(remote_refs);
 		ret = push_ret | err;
 
@@ -996,7 +1002,8 @@ int transport_push(struct transport *transport,
 		if (flags & TRANSPORT_PUSH_SET_UPSTREAM)
 			set_upstreams(transport, remote_refs, pretend);
 
-		if (!(flags & TRANSPORT_PUSH_DRY_RUN)) {
+		if (!(flags & (TRANSPORT_PUSH_DRY_RUN |
+			       TRANSPORT_RECURSE_SUBMODULES_ONLY))) {
 			struct ref *ref;
 			for (ref = remote_refs; ref; ref = ref->next)
 				transport_update_tracking_ref(transport->remote, ref, verbose);
diff --git a/transport.h b/transport.h
index 1b65458..efd5fb6 100644
--- a/transport.h
+++ b/transport.h
@@ -146,6 +146,7 @@ struct transport {
 #define TRANSPORT_PUSH_CERT_IF_ASKED		(1<<12)
 #define TRANSPORT_PUSH_ATOMIC			(1<<13)
 #define TRANSPORT_PUSH_OPTIONS			(1<<14)
+#define TRANSPORT_RECURSE_SUBMODULES_ONLY	(1<<15)
 
 extern int transport_summary_width(const struct ref *refs);
 
-- 
2.8.0.rc3.226.g39d4020
Stefan Beller· Dec 19, 2016, 18:56 UTC · re: Brandon Williams · lore

Re: [PATCH 3/3] push: add option to push only submodules

On Mon, Dec 19, 2016 at 10:25 AM, Brandon Williams <bmwill@google.com> wrote:
Show 6 quoted lines
> Teach push the --recurse-submodules=only option.  This enables push to
> recursively push all unpushed submodules while leaving the superproject
> unpushed.
>
> This is a desirable feature in a scenario where updates to the
> superproject are handled automatically by some other means, perhaps a
e.g. Gerrit. (No need to be shy about our code review tool)
Show 9 quoted lines
>
> code review tool.  In this scenario a developer could make a change
> which spans multiple submodules and then push their commits for code
> review.  Upon completion of the code review, their commits can be
> accepted and applied to their respective submodules while the code
> review tool can then automatically update the superproject to the most
> recent SHA1 of each submodule.  This would eliminate the merge conflicts
> in the superproject that could occur if multiple people are contributing
> to the same submodule.

Code and tests look good to me, I think the commit message is good enough, but let's hear Junio on this one.

Thanks, Stefan

Junio C Hamano· Dec 19, 2016, 18:41 UTC · re: Brandon Williams · lore

Re: [PATCH 0/3] push only submodules

Brandon Williams <bmwill@google.com> writes:
> This series teaches 'git push' to be able to only push submodules
> while leaving a superproject unpushed.
> ...
>  builtin/push.c                 |  2 ++

My knee-jerk reaction is "why is this even part of 'git push' if it does not push?"

I think "git submodule foreach git push" is probably a mouthful to say, but I am not sure "git push --recurse-submodule=only" is a short-hand that is way better than that.

Maybe I'll find why the latter is better after reading the patches through ;-)

Junio C Hamano· Dec 20, 2016, 19:25 UTC · re: Brandon Williams · lore

Re: [PATCH 0/3] push only submodules

Brandon Williams <bmwill@google.com> writes:
> This series teaches 'git push' to be able to only push submodules
> while leaving a superproject unpushed.

It somehow feels a bit strange to single out the top-level as special like this one (iow, shouldn't it be equally as easy to push out the superproject and two submodules leaving one submodule alone, as to push out these three submodules leaving the superproject alone?), but I will queue these for now with tweaks to address a few minor points.

 * What is done with 1/3 I do not think is "refactor".
 * "perhaps a code review tool" -> "perhaps a tool like Gerrit code
   review" as suggested by Stefan.
 * Swap the order expected_pub and expected_submodule are generated
   to match the order they are used for final verification in the
   test.

← back to recent threads