From: Brandon Williams <bmwill@google.com>
To: git@vger.kernel.org
Cc: Brandon Williams <bmwill@google.com>, jrnieder@gmail.com
Subject: [PATCH v3 5/5] push: propagate remote and refspec with --recurse-submodules
Date: Wed, 5 Apr 2017 10:47:19 -0700 [thread overview]
Message-ID: <20170405174719.1297-6-bmwill@google.com> (raw)
In-Reply-To: <20170405174719.1297-1-bmwill@google.com>
Teach "push --recurse-submodules" to propagate, if given a name as remote, the
provided remote and refspec recursively to the pushes performed in the
submodules. The push will therefore only succeed if all submodules have a
remote with such a name configured.
Note that "push --recurse-submodules" with a path or URL as remote will not
propagate the remote or refspec and instead use the default remote and refspec
configured in the submodule, preserving the current behavior.
Signed-off-by: Brandon Williams <bmwill@google.com>
---
submodule.c | 63 ++++++++++++++++++++++++++++++++++++++++--
submodule.h | 4 ++-
t/t5531-deep-submodule-push.sh | 52 ++++++++++++++++++++++++++++++++++
transport.c | 3 +-
4 files changed, 117 insertions(+), 5 deletions(-)
diff --git a/submodule.c b/submodule.c
index de444be61..49ab132d0 100644
--- a/submodule.c
+++ b/submodule.c
@@ -14,6 +14,7 @@
#include "blob.h"
#include "thread-utils.h"
#include "quote.h"
+#include "remote.h"
#include "worktree.h"
static int config_fetch_recurse_submodules = RECURSE_SUBMODULES_ON_DEMAND;
@@ -783,6 +784,8 @@ int find_unpushed_submodules(struct sha1_array *commits,
}
static int push_submodule(const char *path,
+ const struct remote *remote,
+ const char **refspec, int refspec_nr,
const struct string_list *push_options,
int dry_run)
{
@@ -801,6 +804,14 @@ static int push_submodule(const char *path,
argv_array_pushf(&cp.args, "--push-option=%s",
item->string);
}
+
+ if (remote->origin != REMOTE_UNCONFIGURED) {
+ int i;
+ argv_array_push(&cp.args, remote->name);
+ for (i = 0; i < refspec_nr; i++)
+ argv_array_push(&cp.args, refspec[i]);
+ }
+
prepare_submodule_repo_env(&cp.env_array);
cp.git_cmd = 1;
cp.no_stdin = 1;
@@ -813,21 +824,67 @@ static int push_submodule(const char *path,
return 1;
}
+/*
+ * Perform a check in the submodule to see if the remote and refspec work.
+ * Die if the submodule can't be pushed.
+ */
+static void submodule_push_check(const char *path, const struct remote *remote,
+ const char **refspec, int refspec_nr)
+{
+ struct child_process cp = CHILD_PROCESS_INIT;
+ int i;
+
+ argv_array_push(&cp.args, "submodule--helper");
+ argv_array_push(&cp.args, "push-check");
+ argv_array_push(&cp.args, remote->name);
+
+ for (i = 0; i < refspec_nr; i++)
+ argv_array_push(&cp.args, refspec[i]);
+
+ prepare_submodule_repo_env(&cp.env_array);
+ cp.git_cmd = 1;
+ cp.no_stdin = 1;
+ cp.no_stdout = 1;
+ cp.dir = path;
+
+ /*
+ * Simply indicate if 'submodule--helper push-check' failed.
+ * More detailed error information will be provided by the
+ * child process.
+ */
+ if (run_command(&cp))
+ die("process for submodule '%s' failed", path);
+}
+
int push_unpushed_submodules(struct sha1_array *commits,
- const char *remotes_name,
+ const struct remote *remote,
+ const char **refspec, int refspec_nr,
const struct string_list *push_options,
int dry_run)
{
int i, ret = 1;
struct string_list needs_pushing = STRING_LIST_INIT_DUP;
- if (!find_unpushed_submodules(commits, remotes_name, &needs_pushing))
+ if (!find_unpushed_submodules(commits, remote->name, &needs_pushing))
return 1;
+ /*
+ * Verify that the remote and refspec can be propagated to all
+ * submodules. This check can be skipped if the remote and refspec
+ * won't be propagated due to the remote being unconfigured (e.g. a URL
+ * instead of a remote name).
+ */
+ if (remote->origin != REMOTE_UNCONFIGURED)
+ for (i = 0; i < needs_pushing.nr; i++)
+ submodule_push_check(needs_pushing.items[i].string,
+ remote, refspec, refspec_nr);
+
+ /* Actually push the submodules */
for (i = 0; i < needs_pushing.nr; i++) {
const char *path = needs_pushing.items[i].string;
fprintf(stderr, "Pushing submodule '%s'\n", path);
- if (!push_submodule(path, push_options, dry_run)) {
+ if (!push_submodule(path, remote, refspec, refspec_nr,
+ push_options, dry_run)) {
fprintf(stderr, "Unable to push submodule '%s'\n", path);
ret = 0;
}
diff --git a/submodule.h b/submodule.h
index 0e26430fd..127ff9be8 100644
--- a/submodule.h
+++ b/submodule.h
@@ -4,6 +4,7 @@
struct diff_options;
struct argv_array;
struct sha1_array;
+struct remote;
enum {
RECURSE_SUBMODULES_ONLY = -5,
@@ -91,7 +92,8 @@ extern int find_unpushed_submodules(struct sha1_array *commits,
const char *remotes_name,
struct string_list *needs_pushing);
extern int push_unpushed_submodules(struct sha1_array *commits,
- const char *remotes_name,
+ const struct remote *remote,
+ const char **refspec, int refspec_nr,
const struct string_list *push_options,
int dry_run);
extern void connect_work_tree_and_git_dir(const char *work_tree, const char *git_dir);
diff --git a/t/t5531-deep-submodule-push.sh b/t/t5531-deep-submodule-push.sh
index f55137f76..57ba32262 100755
--- a/t/t5531-deep-submodule-push.sh
+++ b/t/t5531-deep-submodule-push.sh
@@ -475,4 +475,56 @@ test_expect_success 'push only unpushed submodules recursively' '
test_cmp expected_pub actual_pub
'
+test_expect_success 'push propagating the remotes name to a submodule' '
+ git -C work remote add origin ../pub.git &&
+ git -C work remote add pub ../pub.git &&
+
+ > work/gar/bage/junk10 &&
+ git -C work/gar/bage add junk10 &&
+ git -C work/gar/bage commit -m "Tenth junk" &&
+ git -C work add gar/bage &&
+ git -C work commit -m "Tenth junk added to gar/bage" &&
+
+ # Fails when submodule does not have a matching remote
+ test_must_fail git -C work push --recurse-submodules=on-demand pub master &&
+ # Succeeds when submodules has matching remote and refspec
+ git -C work push --recurse-submodules=on-demand origin master &&
+
+ git -C submodule.git rev-parse master >actual_submodule &&
+ git -C pub.git rev-parse master >actual_pub &&
+ git -C work/gar/bage rev-parse master >expected_submodule &&
+ git -C work rev-parse master >expected_pub &&
+ test_cmp expected_submodule actual_submodule &&
+ test_cmp expected_pub actual_pub
+'
+
+test_expect_success 'push propagating refspec to a submodule' '
+ > work/gar/bage/junk11 &&
+ git -C work/gar/bage add junk11 &&
+ git -C work/gar/bage commit -m "Eleventh junk" &&
+
+ git -C work checkout branch2 &&
+ git -C work add gar/bage &&
+ git -C work commit -m "updating gar/bage in branch2" &&
+
+ # Fails when submodule does not have a matching branch
+ test_must_fail git -C work push --recurse-submodules=on-demand origin branch2 &&
+ # Fails when refspec includes an object id
+ test_must_fail git -C work push --recurse-submodules=on-demand origin \
+ "$(git -C work rev-parse branch2):refs/heads/branch2" &&
+ # Fails when refspec includes 'HEAD' as it is unsupported at this time
+ test_must_fail git -C work push --recurse-submodules=on-demand origin \
+ HEAD:refs/heads/branch2 &&
+
+ git -C work/gar/bage branch branch2 master &&
+ git -C work push --recurse-submodules=on-demand origin branch2 &&
+
+ git -C submodule.git rev-parse branch2 >actual_submodule &&
+ git -C pub.git rev-parse branch2 >actual_pub &&
+ git -C work/gar/bage rev-parse branch2 >expected_submodule &&
+ git -C work rev-parse branch2 >expected_pub &&
+ test_cmp expected_submodule actual_submodule &&
+ test_cmp expected_pub actual_pub
+'
+
test_done
diff --git a/transport.c b/transport.c
index 64e60b635..a62e5118c 100644
--- a/transport.c
+++ b/transport.c
@@ -1030,7 +1030,8 @@ int transport_push(struct transport *transport,
sha1_array_append(&commits, ref->new_oid.hash);
if (!push_unpushed_submodules(&commits,
- transport->remote->name,
+ transport->remote,
+ refspec, refspec_nr,
transport->push_options,
pretend)) {
sha1_array_clear(&commits);
--
2.12.2.715.g7642488e1d-goog
next prev parent reply other threads:[~2017-04-05 17:49 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-03-31 23:11 [PATCH] push: propagate push-options with --recurse-submodules Brandon Williams
2017-03-31 23:20 ` Jonathan Nieder
2017-03-31 23:26 ` Brandon Williams
2017-03-31 23:56 ` [PATCH v2 0/2] propagate push-options Brandon Williams
2017-03-31 23:56 ` [PATCH v2 1/2] push: unmark a local variable as static Brandon Williams
2017-04-01 0:11 ` Jonathan Nieder
2017-04-01 0:16 ` Brandon Williams
2017-03-31 23:56 ` [PATCH v2 2/2] push: propagate push-options with --recurse-submodules Brandon Williams
2017-04-01 0:19 ` Jonathan Nieder
2017-04-06 0:17 ` Jacob Keller
2017-04-06 17:39 ` Brandon Williams
2017-04-05 17:47 ` [PATCH v3 0/5] propagating push-options, remote and refspec Brandon Williams
2017-04-05 17:47 ` [PATCH v3 1/5] push: unmark a local variable as static Brandon Williams
2017-04-05 17:47 ` [PATCH v3 2/5] push: propagate push-options with --recurse-submodules Brandon Williams
2017-04-05 17:47 ` [PATCH v3 3/5] remote: expose parse_push_refspec function Brandon Williams
2017-04-05 17:47 ` [PATCH v3 4/5] submodule--helper: add push-check subcommand Brandon Williams
2017-04-05 17:47 ` Brandon Williams [this message]
2017-04-11 7:44 ` [PATCH v3 0/5] propagating push-options, remote and refspec Junio C Hamano
2017-04-11 16:33 ` Brandon Williams
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: http://vger.kernel.org/majordomo-info.html
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20170405174719.1297-6-bmwill@google.com \
--to=bmwill@google.com \
--cc=git@vger.kernel.org \
--cc=jrnieder@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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).