aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--builtin/submodule--helper.c26
-rw-r--r--remote.c15
-rw-r--r--remote.h1
-rwxr-xr-xt/t7406-submodule-update.sh32
4 files changed, 73 insertions, 1 deletions
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 1aa87435c2..84a96d300d 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -72,16 +72,40 @@ static char *resolve_relative_url(const char *rel_url, const char *up_path, int
static int get_default_remote_submodule(const char *module_path, char **default_remote)
{
+ const struct submodule *sub;
struct repository subrepo;
+ const char *remote_name = NULL;
+ char *url = NULL;
+
+ sub = submodule_from_path(the_repository, null_oid(the_hash_algo), module_path);
+ if (sub && sub->url) {
+ url = xstrdup(sub->url);
+
+ /* Possibly a url relative to parent */
+ if (starts_with_dot_dot_slash(url) ||
+ starts_with_dot_slash(url)) {
+ char *oldurl = url;
+
+ url = resolve_relative_url(oldurl, NULL, 1);
+ free(oldurl);
+ }
+ }
if (repo_submodule_init(&subrepo, the_repository, module_path,
null_oid(the_hash_algo)) < 0)
return die_message(_("could not get a repository handle for submodule '%s'"),
module_path);
- *default_remote = xstrdup(repo_default_remote(&subrepo));
+ /* Look up by URL first */
+ if (url)
+ remote_name = repo_remote_from_url(&subrepo, url);
+ if (!remote_name)
+ remote_name = repo_default_remote(&subrepo);
+
+ *default_remote = xstrdup(remote_name);
repo_clear(&subrepo);
+ free(url);
return 0;
}
diff --git a/remote.c b/remote.c
index e35cf7ec61..60b4aec3de 100644
--- a/remote.c
+++ b/remote.c
@@ -1801,6 +1801,21 @@ const char *repo_default_remote(struct repository *repo)
return remotes_remote_for_branch(repo->remote_state, branch, NULL);
}
+const char *repo_remote_from_url(struct repository *repo, const char *url)
+{
+ read_config(repo, 0);
+
+ for (int i = 0; i < repo->remote_state->remotes_nr; i++) {
+ struct remote *remote = repo->remote_state->remotes[i];
+ if (!remote)
+ continue;
+
+ if (remote_has_url(remote, url))
+ return remote->name;
+ }
+ return NULL;
+}
+
int branch_has_merge_config(struct branch *branch)
{
return branch && branch->set_merge;
diff --git a/remote.h b/remote.h
index 8dc5cfa49e..0ca399e183 100644
--- a/remote.h
+++ b/remote.h
@@ -340,6 +340,7 @@ const char *pushremote_for_branch(struct branch *branch, int *explicit);
char *remote_ref_for_branch(struct branch *branch, int for_push);
const char *repo_default_remote(struct repository *repo);
+const char *repo_remote_from_url(struct repository *repo, const char *url);
/* returns true if the given branch has merge configuration given. */
int branch_has_merge_config(struct branch *branch);
diff --git a/t/t7406-submodule-update.sh b/t/t7406-submodule-update.sh
index 748b529745..c09047b5f4 100755
--- a/t/t7406-submodule-update.sh
+++ b/t/t7406-submodule-update.sh
@@ -1134,6 +1134,38 @@ test_expect_success 'setup clean recursive superproject' '
git clone --recurse-submodules top top-clean
'
+test_expect_success 'submodule update with multiple remotes' '
+ test_when_finished "rm -fr top-cloned" &&
+ cp -r top-clean top-cloned &&
+
+ # Create a commit in each repo, starting with bottom
+ test_commit -C bottom multiple_remote_commit &&
+ # Create middle commit
+ git -C middle/bottom fetch &&
+ git -C middle/bottom checkout -f FETCH_HEAD &&
+ git -C middle add bottom &&
+ git -C middle commit -m "multiple_remote_commit" &&
+ # Create top commit
+ git -C top/middle fetch &&
+ git -C top/middle checkout -f FETCH_HEAD &&
+ git -C top add middle &&
+ git -C top commit -m "multiple_remote_commit" &&
+
+ # rename the submodule remote
+ git -C top-cloned/middle remote rename origin upstream &&
+
+ # Add another remote
+ git -C top-cloned/middle remote add other bogus &&
+
+ # Make the update of "middle" a no-op, otherwise we error out
+ # because of its unmerged state
+ test_config -C top-cloned submodule.middle.update !true &&
+ git -C top-cloned submodule update --recursive 2>actual.err &&
+ cat >expect.err <<-\EOF &&
+ EOF
+ test_cmp expect.err actual.err
+'
+
test_expect_success 'submodule update with renamed remote' '
test_when_finished "rm -fr top-cloned" &&
cp -r top-clean top-cloned &&