diff options
| author | Bence Ferdinandy <bence@ferdinandy.com> | 2024-11-22 13:28:50 +0100 |
|---|---|---|
| committer | Junio C Hamano <gitster@pobox.com> | 2024-11-25 11:46:37 +0900 |
| commit | 3f763ddf28d28fe63963991513c8db4045eabadc (patch) | |
| tree | 128738e283defd82ac8e3155745988a41c74937c /builtin/fetch.c | |
| parent | refs: add create_only option to refs_update_symref_extended (diff) | |
| download | git-3f763ddf28d28fe63963991513c8db4045eabadc.tar.gz git-3f763ddf28d28fe63963991513c8db4045eabadc.zip | |
fetch: set remote/HEAD if it does not exist
When cloning a repository remote/HEAD is created, but when the user
creates a repository with git init, and later adds a remote, remote/HEAD
is only created if the user explicitly runs a variant of "remote
set-head". Attempt to set remote/HEAD during fetch, if the user does not
have it already set. Silently ignore any errors.
Signed-off-by: Bence Ferdinandy <bence@ferdinandy.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'builtin/fetch.c')
| -rw-r--r-- | builtin/fetch.c | 68 |
1 files changed, 68 insertions, 0 deletions
diff --git a/builtin/fetch.c b/builtin/fetch.c index c900f57721..b2a36a5d95 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -1577,6 +1577,66 @@ static int backfill_tags(struct display_state *display_state, return retcode; } +static const char *strip_refshead(const char *name){ + skip_prefix(name, "refs/heads/", &name); + return name; +} + +static int set_head(const struct ref *remote_refs) +{ + int result = 0; + struct strbuf b_head = STRBUF_INIT, b_remote_head = STRBUF_INIT; + const char *remote = gtransport->remote->name; + char *head_name = NULL; + struct ref *ref, *matches; + struct ref *fetch_map = NULL, **fetch_map_tail = &fetch_map; + struct refspec_item refspec = { + .force = 0, + .pattern = 1, + .src = (char *) "refs/heads/*", + .dst = (char *) "refs/heads/*", + }; + struct string_list heads = STRING_LIST_INIT_DUP; + struct ref_store *refs = get_main_ref_store(the_repository); + + get_fetch_map(remote_refs, &refspec, &fetch_map_tail, 0); + matches = guess_remote_head(find_ref_by_name(remote_refs, "HEAD"), + fetch_map, 1); + for (ref = matches; ref; ref = ref->next) { + string_list_append(&heads, strip_refshead(ref->name)); + } + + + if (!heads.nr) + result = 1; + else if (heads.nr > 1) + result = 1; + else + head_name = xstrdup(heads.items[0].string); + + if (!head_name) + goto cleanup; + strbuf_addf(&b_head, "refs/remotes/%s/HEAD", remote); + strbuf_addf(&b_remote_head, "refs/remotes/%s/%s", remote, head_name); + /* make sure it's valid */ + if (!refs_ref_exists(refs, b_remote_head.buf)) { + result = 1; + goto cleanup; + } + if (refs_update_symref_extended(refs, b_head.buf, b_remote_head.buf, + "fetch", NULL, 1)) + result = 1; + +cleanup: + free(head_name); + free_refs(fetch_map); + free_refs(matches); + string_list_clear(&heads, 0); + strbuf_release(&b_head); + strbuf_release(&b_remote_head); + return result; +} + static int do_fetch(struct transport *transport, struct refspec *rs, const struct fetch_config *config) @@ -1646,6 +1706,8 @@ static int do_fetch(struct transport *transport, "refs/tags/"); } + strvec_push(&transport_ls_refs_options.ref_prefixes, "HEAD"); + if (must_list_refs) { trace2_region_enter("fetch", "remote_refs", the_repository); remote_refs = transport_get_remote_refs(transport, @@ -1790,6 +1852,12 @@ static int do_fetch(struct transport *transport, "you need to specify exactly one branch with the --set-upstream option")); } } + if (set_head(remote_refs)) + ; + /* + * Way too many cases where this can go wrong + * so let's just fail silently for now. + */ cleanup: if (retcode) { |
