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 &&