mirror of
https://github.com/git/git.git
synced 2026-01-11 13:23:12 +09:00
Merge branch 'jk/submodule-remote-lookup-cleanup'
Updating submodules from the upstream did not work well when submodule's HEAD is detached, which has been improved. * jk/submodule-remote-lookup-cleanup: submodule: look up remotes by URL first submodule: move get_default_remote_submodule() submodule--helper: improve logic for fallback remote name remote: remove the_repository from some functions dir: move starts_with_dot(_dot)_slash to dir.h remote: fix tear down of struct remote remote: remove branch->merge_name and fix branch_release()
This commit is contained in:
commit
7310e539ad
4
branch.c
4
branch.c
@ -230,7 +230,7 @@ static int inherit_tracking(struct tracking *tracking, const char *orig_ref)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (branch->merge_nr < 1 || !branch->merge_name || !branch->merge_name[0]) {
|
if (branch->merge_nr < 1 || !branch->merge || !branch->merge[0] || !branch->merge[0]->src) {
|
||||||
warning(_("asked to inherit tracking from '%s', but no merge configuration is set"),
|
warning(_("asked to inherit tracking from '%s', but no merge configuration is set"),
|
||||||
bare_ref);
|
bare_ref);
|
||||||
return -1;
|
return -1;
|
||||||
@ -238,7 +238,7 @@ static int inherit_tracking(struct tracking *tracking, const char *orig_ref)
|
|||||||
|
|
||||||
tracking->remote = branch->remote_name;
|
tracking->remote = branch->remote_name;
|
||||||
for (i = 0; i < branch->merge_nr; i++)
|
for (i = 0; i < branch->merge_nr; i++)
|
||||||
string_list_append(tracking->srcs, branch->merge_name[i]);
|
string_list_append(tracking->srcs, branch->merge[i]->src);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -490,7 +490,7 @@ static void NORETURN die_no_merge_candidates(const char *repo, const char **refs
|
|||||||
} else
|
} else
|
||||||
fprintf_ln(stderr, _("Your configuration specifies to merge with the ref '%s'\n"
|
fprintf_ln(stderr, _("Your configuration specifies to merge with the ref '%s'\n"
|
||||||
"from the remote, but no such ref was fetched."),
|
"from the remote, but no such ref was fetched."),
|
||||||
*curr_branch->merge_name);
|
curr_branch->merge[0]->src);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -41,61 +41,9 @@
|
|||||||
typedef void (*each_submodule_fn)(const struct cache_entry *list_item,
|
typedef void (*each_submodule_fn)(const struct cache_entry *list_item,
|
||||||
void *cb_data);
|
void *cb_data);
|
||||||
|
|
||||||
static int repo_get_default_remote(struct repository *repo, char **default_remote)
|
|
||||||
{
|
|
||||||
char *dest = NULL;
|
|
||||||
struct strbuf sb = STRBUF_INIT;
|
|
||||||
struct ref_store *store = get_main_ref_store(repo);
|
|
||||||
const char *refname = refs_resolve_ref_unsafe(store, "HEAD", 0, NULL,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
if (!refname)
|
|
||||||
return die_message(_("No such ref: %s"), "HEAD");
|
|
||||||
|
|
||||||
/* detached HEAD */
|
|
||||||
if (!strcmp(refname, "HEAD")) {
|
|
||||||
*default_remote = xstrdup("origin");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!skip_prefix(refname, "refs/heads/", &refname))
|
|
||||||
return die_message(_("Expecting a full ref name, got %s"),
|
|
||||||
refname);
|
|
||||||
|
|
||||||
strbuf_addf(&sb, "branch.%s.remote", refname);
|
|
||||||
if (repo_config_get_string(repo, sb.buf, &dest))
|
|
||||||
*default_remote = xstrdup("origin");
|
|
||||||
else
|
|
||||||
*default_remote = dest;
|
|
||||||
|
|
||||||
strbuf_release(&sb);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int get_default_remote_submodule(const char *module_path, char **default_remote)
|
|
||||||
{
|
|
||||||
struct repository subrepo;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
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);
|
|
||||||
ret = repo_get_default_remote(&subrepo, default_remote);
|
|
||||||
repo_clear(&subrepo);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static char *get_default_remote(void)
|
static char *get_default_remote(void)
|
||||||
{
|
{
|
||||||
char *default_remote;
|
return xstrdup(repo_default_remote(the_repository));
|
||||||
int code = repo_get_default_remote(the_repository, &default_remote);
|
|
||||||
|
|
||||||
if (code)
|
|
||||||
exit(code);
|
|
||||||
|
|
||||||
return default_remote;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *resolve_relative_url(const char *rel_url, const char *up_path, int quiet)
|
static char *resolve_relative_url(const char *rel_url, const char *up_path, int quiet)
|
||||||
@ -122,6 +70,46 @@ static char *resolve_relative_url(const char *rel_url, const char *up_path, int
|
|||||||
return resolved_url;
|
return resolved_url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
}
|
||||||
|
|
||||||
/* the result should be freed by the caller. */
|
/* the result should be freed by the caller. */
|
||||||
static char *get_submodule_displaypath(const char *path, const char *prefix,
|
static char *get_submodule_displaypath(const char *path, const char *prefix,
|
||||||
const char *super_prefix)
|
const char *super_prefix)
|
||||||
@ -438,18 +426,6 @@ cleanup:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int starts_with_dot_slash(const char *const path)
|
|
||||||
{
|
|
||||||
return path_match_flags(path, PATH_MATCH_STARTS_WITH_DOT_SLASH |
|
|
||||||
PATH_MATCH_XPLATFORM);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int starts_with_dot_dot_slash(const char *const path)
|
|
||||||
{
|
|
||||||
return path_match_flags(path, PATH_MATCH_STARTS_WITH_DOT_DOT_SLASH |
|
|
||||||
PATH_MATCH_XPLATFORM);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct init_cb {
|
struct init_cb {
|
||||||
const char *prefix;
|
const char *prefix;
|
||||||
const char *super_prefix;
|
const char *super_prefix;
|
||||||
|
|||||||
23
dir.h
23
dir.h
@ -676,4 +676,27 @@ static inline int starts_with_dot_dot_slash_native(const char *const path)
|
|||||||
return path_match_flags(path, what | PATH_MATCH_NATIVE);
|
return path_match_flags(path, what | PATH_MATCH_NATIVE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* starts_with_dot_slash: convenience wrapper for
|
||||||
|
* patch_match_flags() with PATH_MATCH_STARTS_WITH_DOT_SLASH and
|
||||||
|
* PATH_MATCH_XPLATFORM.
|
||||||
|
*/
|
||||||
|
static inline int starts_with_dot_slash(const char *const path)
|
||||||
|
{
|
||||||
|
const enum path_match_flags what = PATH_MATCH_STARTS_WITH_DOT_SLASH;
|
||||||
|
|
||||||
|
return path_match_flags(path, what | PATH_MATCH_XPLATFORM);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* starts_with_dot_dot_slash: convenience wrapper for
|
||||||
|
* patch_match_flags() with PATH_MATCH_STARTS_WITH_DOT_DOT_SLASH and
|
||||||
|
* PATH_MATCH_XPLATFORM.
|
||||||
|
*/
|
||||||
|
static inline int starts_with_dot_dot_slash(const char *const path)
|
||||||
|
{
|
||||||
|
const enum path_match_flags what = PATH_MATCH_STARTS_WITH_DOT_DOT_SLASH;
|
||||||
|
|
||||||
|
return path_match_flags(path, what | PATH_MATCH_XPLATFORM);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
149
remote.c
149
remote.c
@ -165,6 +165,9 @@ static void remote_clear(struct remote *remote)
|
|||||||
strvec_clear(&remote->url);
|
strvec_clear(&remote->url);
|
||||||
strvec_clear(&remote->pushurl);
|
strvec_clear(&remote->pushurl);
|
||||||
|
|
||||||
|
refspec_clear(&remote->push);
|
||||||
|
refspec_clear(&remote->fetch);
|
||||||
|
|
||||||
free((char *)remote->receivepack);
|
free((char *)remote->receivepack);
|
||||||
free((char *)remote->uploadpack);
|
free((char *)remote->uploadpack);
|
||||||
FREE_AND_NULL(remote->http_proxy);
|
FREE_AND_NULL(remote->http_proxy);
|
||||||
@ -174,9 +177,15 @@ static void remote_clear(struct remote *remote)
|
|||||||
|
|
||||||
static void add_merge(struct branch *branch, const char *name)
|
static void add_merge(struct branch *branch, const char *name)
|
||||||
{
|
{
|
||||||
ALLOC_GROW(branch->merge_name, branch->merge_nr + 1,
|
struct refspec_item *merge;
|
||||||
|
|
||||||
|
ALLOC_GROW(branch->merge, branch->merge_nr + 1,
|
||||||
branch->merge_alloc);
|
branch->merge_alloc);
|
||||||
branch->merge_name[branch->merge_nr++] = name;
|
|
||||||
|
merge = xcalloc(1, sizeof(*merge));
|
||||||
|
merge->src = xstrdup(name);
|
||||||
|
|
||||||
|
branch->merge[branch->merge_nr++] = merge;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct branches_hash_key {
|
struct branches_hash_key {
|
||||||
@ -247,15 +256,23 @@ static struct branch *make_branch(struct remote_state *remote_state,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void merge_clear(struct branch *branch)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < branch->merge_nr; i++) {
|
||||||
|
refspec_item_clear(branch->merge[i]);
|
||||||
|
free(branch->merge[i]);
|
||||||
|
}
|
||||||
|
FREE_AND_NULL(branch->merge);
|
||||||
|
branch->merge_nr = 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void branch_release(struct branch *branch)
|
static void branch_release(struct branch *branch)
|
||||||
{
|
{
|
||||||
free((char *)branch->name);
|
free((char *)branch->name);
|
||||||
free((char *)branch->refname);
|
free((char *)branch->refname);
|
||||||
free(branch->remote_name);
|
free(branch->remote_name);
|
||||||
free(branch->pushremote_name);
|
free(branch->pushremote_name);
|
||||||
for (int i = 0; i < branch->merge_nr; i++)
|
merge_clear(branch);
|
||||||
refspec_item_clear(branch->merge[i]);
|
|
||||||
free(branch->merge);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct rewrite *make_rewrite(struct rewrites *r,
|
static struct rewrite *make_rewrite(struct rewrites *r,
|
||||||
@ -317,11 +334,10 @@ static void warn_about_deprecated_remote_type(const char *type,
|
|||||||
type, remote->name, remote->name, remote->name);
|
type, remote->name, remote->name, remote->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void read_remotes_file(struct remote_state *remote_state,
|
static void read_remotes_file(struct repository *repo, struct remote *remote)
|
||||||
struct remote *remote)
|
|
||||||
{
|
{
|
||||||
struct strbuf buf = STRBUF_INIT;
|
struct strbuf buf = STRBUF_INIT;
|
||||||
FILE *f = fopen_or_warn(repo_git_path_append(the_repository, &buf,
|
FILE *f = fopen_or_warn(repo_git_path_append(repo, &buf,
|
||||||
"remotes/%s", remote->name), "r");
|
"remotes/%s", remote->name), "r");
|
||||||
|
|
||||||
if (!f)
|
if (!f)
|
||||||
@ -337,7 +353,7 @@ static void read_remotes_file(struct remote_state *remote_state,
|
|||||||
strbuf_rtrim(&buf);
|
strbuf_rtrim(&buf);
|
||||||
|
|
||||||
if (skip_prefix(buf.buf, "URL:", &v))
|
if (skip_prefix(buf.buf, "URL:", &v))
|
||||||
add_url_alias(remote_state, remote,
|
add_url_alias(repo->remote_state, remote,
|
||||||
skip_spaces(v));
|
skip_spaces(v));
|
||||||
else if (skip_prefix(buf.buf, "Push:", &v))
|
else if (skip_prefix(buf.buf, "Push:", &v))
|
||||||
refspec_append(&remote->push, skip_spaces(v));
|
refspec_append(&remote->push, skip_spaces(v));
|
||||||
@ -350,12 +366,11 @@ out:
|
|||||||
strbuf_release(&buf);
|
strbuf_release(&buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void read_branches_file(struct remote_state *remote_state,
|
static void read_branches_file(struct repository *repo, struct remote *remote)
|
||||||
struct remote *remote)
|
|
||||||
{
|
{
|
||||||
char *frag, *to_free = NULL;
|
char *frag, *to_free = NULL;
|
||||||
struct strbuf buf = STRBUF_INIT;
|
struct strbuf buf = STRBUF_INIT;
|
||||||
FILE *f = fopen_or_warn(repo_git_path_append(the_repository, &buf,
|
FILE *f = fopen_or_warn(repo_git_path_append(repo, &buf,
|
||||||
"branches/%s", remote->name), "r");
|
"branches/%s", remote->name), "r");
|
||||||
|
|
||||||
if (!f)
|
if (!f)
|
||||||
@ -382,9 +397,9 @@ static void read_branches_file(struct remote_state *remote_state,
|
|||||||
if (frag)
|
if (frag)
|
||||||
*(frag++) = '\0';
|
*(frag++) = '\0';
|
||||||
else
|
else
|
||||||
frag = to_free = repo_default_branch_name(the_repository, 0);
|
frag = to_free = repo_default_branch_name(repo, 0);
|
||||||
|
|
||||||
add_url_alias(remote_state, remote, buf.buf);
|
add_url_alias(repo->remote_state, remote, buf.buf);
|
||||||
refspec_appendf(&remote->fetch, "refs/heads/%s:refs/heads/%s",
|
refspec_appendf(&remote->fetch, "refs/heads/%s:refs/heads/%s",
|
||||||
frag, remote->name);
|
frag, remote->name);
|
||||||
|
|
||||||
@ -429,7 +444,7 @@ static int handle_config(const char *key, const char *value,
|
|||||||
} else if (!strcmp(subkey, "merge")) {
|
} else if (!strcmp(subkey, "merge")) {
|
||||||
if (!value)
|
if (!value)
|
||||||
return config_error_nonbool(key);
|
return config_error_nonbool(key);
|
||||||
add_merge(branch, xstrdup(value));
|
add_merge(branch, value);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -681,7 +696,7 @@ const char *pushremote_for_branch(struct branch *branch, int *explicit)
|
|||||||
branch, explicit);
|
branch, explicit);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct remote *remotes_remote_get(struct remote_state *remote_state,
|
static struct remote *remotes_remote_get(struct repository *repo,
|
||||||
const char *name);
|
const char *name);
|
||||||
|
|
||||||
char *remote_ref_for_branch(struct branch *branch, int for_push)
|
char *remote_ref_for_branch(struct branch *branch, int for_push)
|
||||||
@ -692,7 +707,7 @@ char *remote_ref_for_branch(struct branch *branch, int for_push)
|
|||||||
if (branch) {
|
if (branch) {
|
||||||
if (!for_push) {
|
if (!for_push) {
|
||||||
if (branch->merge_nr) {
|
if (branch->merge_nr) {
|
||||||
return xstrdup(branch->merge_name[0]);
|
return xstrdup(branch->merge[0]->src);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
char *dst;
|
char *dst;
|
||||||
@ -700,7 +715,7 @@ char *remote_ref_for_branch(struct branch *branch, int for_push)
|
|||||||
the_repository->remote_state, branch,
|
the_repository->remote_state, branch,
|
||||||
NULL);
|
NULL);
|
||||||
struct remote *remote = remotes_remote_get(
|
struct remote *remote = remotes_remote_get(
|
||||||
the_repository->remote_state, remote_name);
|
the_repository, remote_name);
|
||||||
|
|
||||||
if (remote && remote->push.nr &&
|
if (remote && remote->push.nr &&
|
||||||
(dst = apply_refspecs(&remote->push,
|
(dst = apply_refspecs(&remote->push,
|
||||||
@ -757,10 +772,11 @@ loop_cleanup:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static struct remote *
|
static struct remote *
|
||||||
remotes_remote_get_1(struct remote_state *remote_state, const char *name,
|
remotes_remote_get_1(struct repository *repo, const char *name,
|
||||||
const char *(*get_default)(struct remote_state *,
|
const char *(*get_default)(struct remote_state *,
|
||||||
struct branch *, int *))
|
struct branch *, int *))
|
||||||
{
|
{
|
||||||
|
struct remote_state *remote_state = repo->remote_state;
|
||||||
struct remote *ret;
|
struct remote *ret;
|
||||||
int name_given = 0;
|
int name_given = 0;
|
||||||
|
|
||||||
@ -774,9 +790,9 @@ remotes_remote_get_1(struct remote_state *remote_state, const char *name,
|
|||||||
#ifndef WITH_BREAKING_CHANGES
|
#ifndef WITH_BREAKING_CHANGES
|
||||||
if (valid_remote_nick(name) && have_git_dir()) {
|
if (valid_remote_nick(name) && have_git_dir()) {
|
||||||
if (!valid_remote(ret))
|
if (!valid_remote(ret))
|
||||||
read_remotes_file(remote_state, ret);
|
read_remotes_file(repo, ret);
|
||||||
if (!valid_remote(ret))
|
if (!valid_remote(ret))
|
||||||
read_branches_file(remote_state, ret);
|
read_branches_file(repo, ret);
|
||||||
}
|
}
|
||||||
#endif /* WITH_BREAKING_CHANGES */
|
#endif /* WITH_BREAKING_CHANGES */
|
||||||
if (name_given && !valid_remote(ret))
|
if (name_given && !valid_remote(ret))
|
||||||
@ -790,35 +806,33 @@ remotes_remote_get_1(struct remote_state *remote_state, const char *name,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline struct remote *
|
static inline struct remote *
|
||||||
remotes_remote_get(struct remote_state *remote_state, const char *name)
|
remotes_remote_get(struct repository *repo, const char *name)
|
||||||
{
|
{
|
||||||
return remotes_remote_get_1(remote_state, name,
|
return remotes_remote_get_1(repo, name, remotes_remote_for_branch);
|
||||||
remotes_remote_for_branch);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct remote *remote_get(const char *name)
|
struct remote *remote_get(const char *name)
|
||||||
{
|
{
|
||||||
read_config(the_repository, 0);
|
read_config(the_repository, 0);
|
||||||
return remotes_remote_get(the_repository->remote_state, name);
|
return remotes_remote_get(the_repository, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct remote *remote_get_early(const char *name)
|
struct remote *remote_get_early(const char *name)
|
||||||
{
|
{
|
||||||
read_config(the_repository, 1);
|
read_config(the_repository, 1);
|
||||||
return remotes_remote_get(the_repository->remote_state, name);
|
return remotes_remote_get(the_repository, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline struct remote *
|
static inline struct remote *
|
||||||
remotes_pushremote_get(struct remote_state *remote_state, const char *name)
|
remotes_pushremote_get(struct repository *repo, const char *name)
|
||||||
{
|
{
|
||||||
return remotes_remote_get_1(remote_state, name,
|
return remotes_remote_get_1(repo, name, remotes_pushremote_for_branch);
|
||||||
remotes_pushremote_for_branch);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct remote *pushremote_get(const char *name)
|
struct remote *pushremote_get(const char *name)
|
||||||
{
|
{
|
||||||
read_config(the_repository, 0);
|
read_config(the_repository, 0);
|
||||||
return remotes_pushremote_get(the_repository->remote_state, name);
|
return remotes_pushremote_get(the_repository, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
int remote_is_configured(struct remote *remote, int in_repo)
|
int remote_is_configured(struct remote *remote, int in_repo)
|
||||||
@ -1722,7 +1736,7 @@ void set_ref_status_for_push(struct ref *remote_refs, int send_mirror,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_merge(struct remote_state *remote_state, struct branch *ret)
|
static void set_merge(struct repository *repo, struct branch *ret)
|
||||||
{
|
{
|
||||||
struct remote *remote;
|
struct remote *remote;
|
||||||
char *ref;
|
char *ref;
|
||||||
@ -1731,52 +1745,80 @@ static void set_merge(struct remote_state *remote_state, struct branch *ret)
|
|||||||
|
|
||||||
if (!ret)
|
if (!ret)
|
||||||
return; /* no branch */
|
return; /* no branch */
|
||||||
if (ret->merge)
|
if (ret->set_merge)
|
||||||
return; /* already run */
|
return; /* already run */
|
||||||
if (!ret->remote_name || !ret->merge_nr) {
|
if (!ret->remote_name || !ret->merge_nr) {
|
||||||
/*
|
/*
|
||||||
* no merge config; let's make sure we don't confuse callers
|
* no merge config; let's make sure we don't confuse callers
|
||||||
* with a non-zero merge_nr but a NULL merge
|
* with a non-zero merge_nr but a NULL merge
|
||||||
*/
|
*/
|
||||||
ret->merge_nr = 0;
|
merge_clear(ret);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
ret->set_merge = 1;
|
||||||
|
|
||||||
remote = remotes_remote_get(remote_state, ret->remote_name);
|
remote = remotes_remote_get(repo, ret->remote_name);
|
||||||
|
|
||||||
CALLOC_ARRAY(ret->merge, ret->merge_nr);
|
|
||||||
for (i = 0; i < ret->merge_nr; i++) {
|
for (i = 0; i < ret->merge_nr; i++) {
|
||||||
ret->merge[i] = xcalloc(1, sizeof(**ret->merge));
|
|
||||||
ret->merge[i]->src = xstrdup(ret->merge_name[i]);
|
|
||||||
if (!remote_find_tracking(remote, ret->merge[i]) ||
|
if (!remote_find_tracking(remote, ret->merge[i]) ||
|
||||||
strcmp(ret->remote_name, "."))
|
strcmp(ret->remote_name, "."))
|
||||||
continue;
|
continue;
|
||||||
if (repo_dwim_ref(the_repository, ret->merge_name[i],
|
if (repo_dwim_ref(repo, ret->merge[i]->src,
|
||||||
strlen(ret->merge_name[i]), &oid, &ref,
|
strlen(ret->merge[i]->src), &oid, &ref,
|
||||||
0) == 1)
|
0) == 1)
|
||||||
ret->merge[i]->dst = ref;
|
ret->merge[i]->dst = ref;
|
||||||
else
|
else
|
||||||
ret->merge[i]->dst = xstrdup(ret->merge_name[i]);
|
ret->merge[i]->dst = xstrdup(ret->merge[i]->src);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct branch *repo_branch_get(struct repository *repo, const char *name)
|
||||||
|
{
|
||||||
|
struct branch *ret;
|
||||||
|
|
||||||
|
read_config(repo, 0);
|
||||||
|
if (!name || !*name || !strcmp(name, "HEAD"))
|
||||||
|
ret = repo->remote_state->current_branch;
|
||||||
|
else
|
||||||
|
ret = make_branch(repo->remote_state, name,
|
||||||
|
strlen(name));
|
||||||
|
set_merge(repo, ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
struct branch *branch_get(const char *name)
|
struct branch *branch_get(const char *name)
|
||||||
{
|
{
|
||||||
struct branch *ret;
|
return repo_branch_get(the_repository, name);
|
||||||
|
}
|
||||||
|
|
||||||
read_config(the_repository, 0);
|
const char *repo_default_remote(struct repository *repo)
|
||||||
if (!name || !*name || !strcmp(name, "HEAD"))
|
{
|
||||||
ret = the_repository->remote_state->current_branch;
|
struct branch *branch;
|
||||||
else
|
|
||||||
ret = make_branch(the_repository->remote_state, name,
|
read_config(repo, 0);
|
||||||
strlen(name));
|
branch = repo_branch_get(repo, "HEAD");
|
||||||
set_merge(the_repository->remote_state, ret);
|
|
||||||
return ret;
|
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)
|
int branch_has_merge_config(struct branch *branch)
|
||||||
{
|
{
|
||||||
return branch && !!branch->merge;
|
return branch && branch->set_merge;
|
||||||
}
|
}
|
||||||
|
|
||||||
int branch_merge_matches(struct branch *branch,
|
int branch_merge_matches(struct branch *branch,
|
||||||
@ -1841,13 +1883,14 @@ static const char *tracking_for_push_dest(struct remote *remote,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *branch_get_push_1(struct remote_state *remote_state,
|
static const char *branch_get_push_1(struct repository *repo,
|
||||||
struct branch *branch, struct strbuf *err)
|
struct branch *branch, struct strbuf *err)
|
||||||
{
|
{
|
||||||
|
struct remote_state *remote_state = repo->remote_state;
|
||||||
struct remote *remote;
|
struct remote *remote;
|
||||||
|
|
||||||
remote = remotes_remote_get(
|
remote = remotes_remote_get(
|
||||||
remote_state,
|
repo,
|
||||||
remotes_pushremote_for_branch(remote_state, branch, NULL));
|
remotes_pushremote_for_branch(remote_state, branch, NULL));
|
||||||
if (!remote)
|
if (!remote)
|
||||||
return error_buf(err,
|
return error_buf(err,
|
||||||
@ -1914,7 +1957,7 @@ const char *branch_get_push(struct branch *branch, struct strbuf *err)
|
|||||||
|
|
||||||
if (!branch->push_tracking_ref)
|
if (!branch->push_tracking_ref)
|
||||||
branch->push_tracking_ref = branch_get_push_1(
|
branch->push_tracking_ref = branch_get_push_1(
|
||||||
the_repository->remote_state, branch, err);
|
the_repository, branch, err);
|
||||||
return branch->push_tracking_ref;
|
return branch->push_tracking_ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
8
remote.h
8
remote.h
@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
struct option;
|
struct option;
|
||||||
struct transport_ls_refs_options;
|
struct transport_ls_refs_options;
|
||||||
|
struct repository;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The API gives access to the configuration related to remotes. It handles
|
* The API gives access to the configuration related to remotes. It handles
|
||||||
@ -315,8 +316,8 @@ struct branch {
|
|||||||
|
|
||||||
char *pushremote_name;
|
char *pushremote_name;
|
||||||
|
|
||||||
/* An array of the "merge" lines in the configuration. */
|
/* True if set_merge() has been called to finalize the merge array */
|
||||||
const char **merge_name;
|
int set_merge;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An array of the struct refspecs used for the merge lines. That is,
|
* An array of the struct refspecs used for the merge lines. That is,
|
||||||
@ -338,6 +339,9 @@ const char *remote_for_branch(struct branch *branch, int *explicit);
|
|||||||
const char *pushremote_for_branch(struct branch *branch, int *explicit);
|
const char *pushremote_for_branch(struct branch *branch, int *explicit);
|
||||||
char *remote_ref_for_branch(struct branch *branch, int for_push);
|
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. */
|
/* returns true if the given branch has merge configuration given. */
|
||||||
int branch_has_merge_config(struct branch *branch);
|
int branch_has_merge_config(struct branch *branch);
|
||||||
|
|
||||||
|
|||||||
@ -235,18 +235,6 @@ in_component:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int starts_with_dot_slash(const char *const path)
|
|
||||||
{
|
|
||||||
return path_match_flags(path, PATH_MATCH_STARTS_WITH_DOT_SLASH |
|
|
||||||
PATH_MATCH_XPLATFORM);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int starts_with_dot_dot_slash(const char *const path)
|
|
||||||
{
|
|
||||||
return path_match_flags(path, PATH_MATCH_STARTS_WITH_DOT_DOT_SLASH |
|
|
||||||
PATH_MATCH_XPLATFORM);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int submodule_url_is_relative(const char *url)
|
static int submodule_url_is_relative(const char *url)
|
||||||
{
|
{
|
||||||
return starts_with_dot_slash(url) || starts_with_dot_dot_slash(url);
|
return starts_with_dot_slash(url) || starts_with_dot_dot_slash(url);
|
||||||
|
|||||||
@ -1137,6 +1137,67 @@ test_expect_success 'setup clean recursive superproject' '
|
|||||||
git clone --recurse-submodules top top-clean
|
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 &&
|
||||||
|
|
||||||
|
# Create a commit in each repo, starting with bottom
|
||||||
|
test_commit -C bottom rename_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 "rename_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 "rename_commit" &&
|
||||||
|
|
||||||
|
# rename the submodule remote
|
||||||
|
git -C top-cloned/middle remote rename origin upstream &&
|
||||||
|
|
||||||
|
# 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 should skip unmerged submodules' '
|
test_expect_success 'submodule update should skip unmerged submodules' '
|
||||||
test_when_finished "rm -fr top-cloned" &&
|
test_when_finished "rm -fr top-cloned" &&
|
||||||
cp -r top-clean top-cloned &&
|
cp -r top-clean top-cloned &&
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user