Skip to content

Commit 8d9ac96

Browse files
jacob-kellergitster
authored andcommitted
submodule--helper: improve logic for fallback remote name
The repo_get_default_remote() function in submodule--helper currently tries to figure out the proper remote name to use for a submodule based on a few factors. First, it tries to find the remote for the currently checked out branch. This works if the submodule is configured to checkout to a branch instead of a detached HEAD state. In the detached HEAD state, the code calls back to using "origin", on the assumption that this is the default remote name. Some users may change this, such as by setting clone.defaultRemoteName, or by changing the remote name manually within the submodule repository. As a first step to improving this situation, refactor to reuse the logic from remotes_remote_for_branch(). This function uses the remote from the branch if it has one. If it doesn't then it checks to see if there is exactly one remote. It uses this remote first before attempting to fall back to "origin". To allow using this helper function, introduce a repo_default_remote() helper to remote.c which takes a repository structure. This helper will load the remote configuration and get the "HEAD" branch. Then it will call remotes_remote_for_branch to find the default remote. Replace calls of repo_get_default_remote() with the calls to this new function. To maintain consistency with the existing callers, continue copying the returned string with xstrdup. This isn't a perfect solution for users who change remote names, but it should help in cases where the remote name is changed but users haven't added any additional remotes. Signed-off-by: Jacob Keller <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 46d82a1 commit 8d9ac96

File tree

4 files changed

+57
-46
lines changed

4 files changed

+57
-46
lines changed

builtin/submodule--helper.c

Lines changed: 5 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -41,61 +41,25 @@
4141
typedef void (*each_submodule_fn)(const struct cache_entry *list_item,
4242
void *cb_data);
4343

44-
static int repo_get_default_remote(struct repository *repo, char **default_remote)
45-
{
46-
char *dest = NULL;
47-
struct strbuf sb = STRBUF_INIT;
48-
struct ref_store *store = get_main_ref_store(repo);
49-
const char *refname = refs_resolve_ref_unsafe(store, "HEAD", 0, NULL,
50-
NULL);
51-
52-
if (!refname)
53-
return die_message(_("No such ref: %s"), "HEAD");
54-
55-
/* detached HEAD */
56-
if (!strcmp(refname, "HEAD")) {
57-
*default_remote = xstrdup("origin");
58-
return 0;
59-
}
60-
61-
if (!skip_prefix(refname, "refs/heads/", &refname))
62-
return die_message(_("Expecting a full ref name, got %s"),
63-
refname);
64-
65-
strbuf_addf(&sb, "branch.%s.remote", refname);
66-
if (repo_config_get_string(repo, sb.buf, &dest))
67-
*default_remote = xstrdup("origin");
68-
else
69-
*default_remote = dest;
70-
71-
strbuf_release(&sb);
72-
return 0;
73-
}
74-
7544
static int get_default_remote_submodule(const char *module_path, char **default_remote)
7645
{
7746
struct repository subrepo;
78-
int ret;
7947

8048
if (repo_submodule_init(&subrepo, the_repository, module_path,
8149
null_oid(the_hash_algo)) < 0)
8250
return die_message(_("could not get a repository handle for submodule '%s'"),
8351
module_path);
84-
ret = repo_get_default_remote(&subrepo, default_remote);
52+
53+
*default_remote = xstrdup(repo_default_remote(&subrepo));
54+
8555
repo_clear(&subrepo);
8656

87-
return ret;
57+
return 0;
8858
}
8959

9060
static char *get_default_remote(void)
9161
{
92-
char *default_remote;
93-
int code = repo_get_default_remote(the_repository, &default_remote);
94-
95-
if (code)
96-
exit(code);
97-
98-
return default_remote;
62+
return xstrdup(repo_default_remote(the_repository));
9963
}
10064

10165
static char *resolve_relative_url(const char *rel_url, const char *up_path, int quiet)

remote.c

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1772,20 +1772,35 @@ static void set_merge(struct repository *repo, struct branch *ret)
17721772
}
17731773
}
17741774

1775-
struct branch *branch_get(const char *name)
1775+
static struct branch *repo_branch_get(struct repository *repo, const char *name)
17761776
{
17771777
struct branch *ret;
17781778

1779-
read_config(the_repository, 0);
1779+
read_config(repo, 0);
17801780
if (!name || !*name || !strcmp(name, "HEAD"))
1781-
ret = the_repository->remote_state->current_branch;
1781+
ret = repo->remote_state->current_branch;
17821782
else
1783-
ret = make_branch(the_repository->remote_state, name,
1783+
ret = make_branch(repo->remote_state, name,
17841784
strlen(name));
1785-
set_merge(the_repository, ret);
1785+
set_merge(repo, ret);
17861786
return ret;
17871787
}
17881788

1789+
struct branch *branch_get(const char *name)
1790+
{
1791+
return repo_branch_get(the_repository, name);
1792+
}
1793+
1794+
const char *repo_default_remote(struct repository *repo)
1795+
{
1796+
struct branch *branch;
1797+
1798+
read_config(repo, 0);
1799+
branch = repo_branch_get(repo, "HEAD");
1800+
1801+
return remotes_remote_for_branch(repo->remote_state, branch, NULL);
1802+
}
1803+
17891804
int branch_has_merge_config(struct branch *branch)
17901805
{
17911806
return branch && !!branch->merge;

remote.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
struct option;
1111
struct transport_ls_refs_options;
12+
struct repository;
1213

1314
/**
1415
* The API gives access to the configuration related to remotes. It handles
@@ -338,6 +339,8 @@ const char *remote_for_branch(struct branch *branch, int *explicit);
338339
const char *pushremote_for_branch(struct branch *branch, int *explicit);
339340
char *remote_ref_for_branch(struct branch *branch, int for_push);
340341

342+
const char *repo_default_remote(struct repository *repo);
343+
341344
/* returns true if the given branch has merge configuration given. */
342345
int branch_has_merge_config(struct branch *branch);
343346

t/t7406-submodule-update.sh

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1134,6 +1134,35 @@ test_expect_success 'setup clean recursive superproject' '
11341134
git clone --recurse-submodules top top-clean
11351135
'
11361136

1137+
test_expect_success 'submodule update with renamed remote' '
1138+
test_when_finished "rm -fr top-cloned" &&
1139+
cp -r top-clean top-cloned &&
1140+
1141+
# Create a commit in each repo, starting with bottom
1142+
test_commit -C bottom rename_commit &&
1143+
# Create middle commit
1144+
git -C middle/bottom fetch &&
1145+
git -C middle/bottom checkout -f FETCH_HEAD &&
1146+
git -C middle add bottom &&
1147+
git -C middle commit -m "rename_commit" &&
1148+
# Create top commit
1149+
git -C top/middle fetch &&
1150+
git -C top/middle checkout -f FETCH_HEAD &&
1151+
git -C top add middle &&
1152+
git -C top commit -m "rename_commit" &&
1153+
1154+
# rename the submodule remote
1155+
git -C top-cloned/middle remote rename origin upstream &&
1156+
1157+
# Make the update of "middle" a no-op, otherwise we error out
1158+
# because of its unmerged state
1159+
test_config -C top-cloned submodule.middle.update !true &&
1160+
git -C top-cloned submodule update --recursive 2>actual.err &&
1161+
cat >expect.err <<-\EOF &&
1162+
EOF
1163+
test_cmp expect.err actual.err
1164+
'
1165+
11371166
test_expect_success 'submodule update should skip unmerged submodules' '
11381167
test_when_finished "rm -fr top-cloned" &&
11391168
cp -r top-clean top-cloned &&

0 commit comments

Comments
 (0)