Merge branch 'jt/connectivity-check-after-unshallow'
"git fetch" failed to correctly validate the set of objects it received when making a shallow history deeper, which has been corrected. * jt/connectivity-check-after-unshallow: fetch-pack: write shallow, then check connectivity fetch-pack: implement ref-in-want fetch-pack: put shallow info in output parameter fetch: refactor to make function args narrower fetch: refactor fetch_refs into two functions fetch: refactor the population of peer ref OIDs upload-pack: test negotiation with changing repository upload-pack: implement ref-in-want test-pkt-line: add unpack-sideband subcommand
This commit is contained in:
150
builtin/fetch.c
150
builtin/fetch.c
@ -242,9 +242,9 @@ static int will_fetch(struct ref **head, const unsigned char *sha1)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void find_non_local_tags(struct transport *transport,
|
||||
struct ref **head,
|
||||
struct ref ***tail)
|
||||
static void find_non_local_tags(const struct ref *refs,
|
||||
struct ref **head,
|
||||
struct ref ***tail)
|
||||
{
|
||||
struct string_list existing_refs = STRING_LIST_INIT_DUP;
|
||||
struct string_list remote_refs = STRING_LIST_INIT_NODUP;
|
||||
@ -252,7 +252,7 @@ static void find_non_local_tags(struct transport *transport,
|
||||
struct string_list_item *item = NULL;
|
||||
|
||||
for_each_ref(add_existing, &existing_refs);
|
||||
for (ref = transport_get_remote_refs(transport, NULL); ref; ref = ref->next) {
|
||||
for (ref = refs; ref; ref = ref->next) {
|
||||
if (!starts_with(ref->name, "refs/tags/"))
|
||||
continue;
|
||||
|
||||
@ -326,7 +326,8 @@ static void find_non_local_tags(struct transport *transport,
|
||||
string_list_clear(&remote_refs, 0);
|
||||
}
|
||||
|
||||
static struct ref *get_ref_map(struct transport *transport,
|
||||
static struct ref *get_ref_map(struct remote *remote,
|
||||
const struct ref *remote_refs,
|
||||
struct refspec *rs,
|
||||
int tags, int *autotags)
|
||||
{
|
||||
@ -334,26 +335,11 @@ static struct ref *get_ref_map(struct transport *transport,
|
||||
struct ref *rm;
|
||||
struct ref *ref_map = NULL;
|
||||
struct ref **tail = &ref_map;
|
||||
struct argv_array ref_prefixes = ARGV_ARRAY_INIT;
|
||||
|
||||
/* opportunistically-updated references: */
|
||||
struct ref *orefs = NULL, **oref_tail = &orefs;
|
||||
|
||||
const struct ref *remote_refs;
|
||||
|
||||
if (rs->nr)
|
||||
refspec_ref_prefixes(rs, &ref_prefixes);
|
||||
else if (transport->remote && transport->remote->fetch.nr)
|
||||
refspec_ref_prefixes(&transport->remote->fetch, &ref_prefixes);
|
||||
|
||||
if (ref_prefixes.argc &&
|
||||
(tags == TAGS_SET || (tags == TAGS_DEFAULT && !rs->nr))) {
|
||||
argv_array_push(&ref_prefixes, "refs/tags/");
|
||||
}
|
||||
|
||||
remote_refs = transport_get_remote_refs(transport, &ref_prefixes);
|
||||
|
||||
argv_array_clear(&ref_prefixes);
|
||||
struct string_list existing_refs = STRING_LIST_INIT_DUP;
|
||||
|
||||
if (rs->nr) {
|
||||
struct refspec *fetch_refspec;
|
||||
@ -390,7 +376,7 @@ static struct ref *get_ref_map(struct transport *transport,
|
||||
if (refmap.nr)
|
||||
fetch_refspec = &refmap;
|
||||
else
|
||||
fetch_refspec = &transport->remote->fetch;
|
||||
fetch_refspec = &remote->fetch;
|
||||
|
||||
for (i = 0; i < fetch_refspec->nr; i++)
|
||||
get_fetch_map(ref_map, &fetch_refspec->items[i], &oref_tail, 1);
|
||||
@ -398,7 +384,6 @@ static struct ref *get_ref_map(struct transport *transport,
|
||||
die("--refmap option is only meaningful with command-line refspec(s).");
|
||||
} else {
|
||||
/* Use the defaults */
|
||||
struct remote *remote = transport->remote;
|
||||
struct branch *branch = branch_get(NULL);
|
||||
int has_merge = branch_has_merge_config(branch);
|
||||
if (remote &&
|
||||
@ -437,7 +422,7 @@ static struct ref *get_ref_map(struct transport *transport,
|
||||
/* also fetch all tags */
|
||||
get_fetch_map(remote_refs, tag_refspec, &tail, 0);
|
||||
else if (tags == TAGS_DEFAULT && *autotags)
|
||||
find_non_local_tags(transport, &ref_map, &tail);
|
||||
find_non_local_tags(remote_refs, &ref_map, &tail);
|
||||
|
||||
/* Now append any refs to be updated opportunistically: */
|
||||
*tail = orefs;
|
||||
@ -446,7 +431,23 @@ static struct ref *get_ref_map(struct transport *transport,
|
||||
tail = &rm->next;
|
||||
}
|
||||
|
||||
return ref_remove_duplicates(ref_map);
|
||||
ref_map = ref_remove_duplicates(ref_map);
|
||||
|
||||
for_each_ref(add_existing, &existing_refs);
|
||||
for (rm = ref_map; rm; rm = rm->next) {
|
||||
if (rm->peer_ref) {
|
||||
struct string_list_item *peer_item =
|
||||
string_list_lookup(&existing_refs,
|
||||
rm->peer_ref->name);
|
||||
if (peer_item) {
|
||||
struct object_id *old_oid = peer_item->util;
|
||||
oidcpy(&rm->peer_ref->old_oid, old_oid);
|
||||
}
|
||||
}
|
||||
}
|
||||
string_list_clear(&existing_refs, 1);
|
||||
|
||||
return ref_map;
|
||||
}
|
||||
|
||||
#define STORE_REF_ERROR_OTHER 1
|
||||
@ -756,7 +757,7 @@ static int iterate_ref_map(void *cb_data, struct object_id *oid)
|
||||
}
|
||||
|
||||
static int store_updated_refs(const char *raw_url, const char *remote_name,
|
||||
struct ref *ref_map)
|
||||
int connectivity_checked, struct ref *ref_map)
|
||||
{
|
||||
FILE *fp;
|
||||
struct commit *commit;
|
||||
@ -778,10 +779,12 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
|
||||
else
|
||||
url = xstrdup("foreign");
|
||||
|
||||
rm = ref_map;
|
||||
if (check_connected(iterate_ref_map, &rm, NULL)) {
|
||||
rc = error(_("%s did not send all necessary objects\n"), url);
|
||||
goto abort;
|
||||
if (!connectivity_checked) {
|
||||
rm = ref_map;
|
||||
if (check_connected(iterate_ref_map, &rm, NULL)) {
|
||||
rc = error(_("%s did not send all necessary objects\n"), url);
|
||||
goto abort;
|
||||
}
|
||||
}
|
||||
|
||||
prepare_format_display(ref_map);
|
||||
@ -933,15 +936,32 @@ static int quickfetch(struct ref *ref_map)
|
||||
return check_connected(iterate_ref_map, &rm, &opt);
|
||||
}
|
||||
|
||||
static int fetch_refs(struct transport *transport, struct ref *ref_map)
|
||||
static int fetch_refs(struct transport *transport, struct ref *ref_map,
|
||||
struct ref **updated_remote_refs)
|
||||
{
|
||||
int ret = quickfetch(ref_map);
|
||||
if (ret)
|
||||
ret = transport_fetch_refs(transport, ref_map);
|
||||
ret = transport_fetch_refs(transport, ref_map,
|
||||
updated_remote_refs);
|
||||
if (!ret)
|
||||
ret |= store_updated_refs(transport->url,
|
||||
transport->remote->name,
|
||||
ref_map);
|
||||
/*
|
||||
* Keep the new pack's ".keep" file around to allow the caller
|
||||
* time to update refs to reference the new objects.
|
||||
*/
|
||||
return 0;
|
||||
transport_unlock_pack(transport);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Update local refs based on the ref values fetched from a remote */
|
||||
static int consume_refs(struct transport *transport, struct ref *ref_map)
|
||||
{
|
||||
int connectivity_checked = transport->smart_options
|
||||
? transport->smart_options->connectivity_checked : 0;
|
||||
int ret = store_updated_refs(transport->url,
|
||||
transport->remote->name,
|
||||
connectivity_checked,
|
||||
ref_map);
|
||||
transport_unlock_pack(transport);
|
||||
return ret;
|
||||
}
|
||||
@ -1087,7 +1107,8 @@ static void backfill_tags(struct transport *transport, struct ref *ref_map)
|
||||
transport_set_option(transport, TRANS_OPT_FOLLOWTAGS, NULL);
|
||||
transport_set_option(transport, TRANS_OPT_DEPTH, "0");
|
||||
transport_set_option(transport, TRANS_OPT_DEEPEN_RELATIVE, NULL);
|
||||
fetch_refs(transport, ref_map);
|
||||
if (!fetch_refs(transport, ref_map, NULL))
|
||||
consume_refs(transport, ref_map);
|
||||
|
||||
if (gsecondary) {
|
||||
transport_disconnect(gsecondary);
|
||||
@ -1098,13 +1119,12 @@ static void backfill_tags(struct transport *transport, struct ref *ref_map)
|
||||
static int do_fetch(struct transport *transport,
|
||||
struct refspec *rs)
|
||||
{
|
||||
struct string_list existing_refs = STRING_LIST_INIT_DUP;
|
||||
struct ref *ref_map;
|
||||
struct ref *rm;
|
||||
int autotags = (transport->remote->fetch_tags == 1);
|
||||
int retcode = 0;
|
||||
|
||||
for_each_ref(add_existing, &existing_refs);
|
||||
const struct ref *remote_refs;
|
||||
struct ref *updated_remote_refs = NULL;
|
||||
struct argv_array ref_prefixes = ARGV_ARRAY_INIT;
|
||||
|
||||
if (tags == TAGS_DEFAULT) {
|
||||
if (transport->remote->fetch_tags == 2)
|
||||
@ -1120,22 +1140,24 @@ static int do_fetch(struct transport *transport,
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ref_map = get_ref_map(transport, rs, tags, &autotags);
|
||||
if (rs->nr)
|
||||
refspec_ref_prefixes(rs, &ref_prefixes);
|
||||
else if (transport->remote && transport->remote->fetch.nr)
|
||||
refspec_ref_prefixes(&transport->remote->fetch, &ref_prefixes);
|
||||
|
||||
if (ref_prefixes.argc &&
|
||||
(tags == TAGS_SET || (tags == TAGS_DEFAULT && !rs->nr))) {
|
||||
argv_array_push(&ref_prefixes, "refs/tags/");
|
||||
}
|
||||
|
||||
remote_refs = transport_get_remote_refs(transport, &ref_prefixes);
|
||||
argv_array_clear(&ref_prefixes);
|
||||
|
||||
ref_map = get_ref_map(transport->remote, remote_refs, rs,
|
||||
tags, &autotags);
|
||||
if (!update_head_ok)
|
||||
check_not_current_branch(ref_map);
|
||||
|
||||
for (rm = ref_map; rm; rm = rm->next) {
|
||||
if (rm->peer_ref) {
|
||||
struct string_list_item *peer_item =
|
||||
string_list_lookup(&existing_refs,
|
||||
rm->peer_ref->name);
|
||||
if (peer_item) {
|
||||
struct object_id *old_oid = peer_item->util;
|
||||
oidcpy(&rm->peer_ref->old_oid, old_oid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (tags == TAGS_DEFAULT && autotags)
|
||||
transport_set_option(transport, TRANS_OPT_FOLLOWTAGS, "1");
|
||||
if (prune) {
|
||||
@ -1152,7 +1174,24 @@ static int do_fetch(struct transport *transport,
|
||||
transport->url);
|
||||
}
|
||||
}
|
||||
if (fetch_refs(transport, ref_map)) {
|
||||
|
||||
if (fetch_refs(transport, ref_map, &updated_remote_refs)) {
|
||||
free_refs(ref_map);
|
||||
retcode = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
if (updated_remote_refs) {
|
||||
/*
|
||||
* Regenerate ref_map using the updated remote refs. This is
|
||||
* to account for additional information which may be provided
|
||||
* by the transport (e.g. shallow info).
|
||||
*/
|
||||
free_refs(ref_map);
|
||||
ref_map = get_ref_map(transport->remote, updated_remote_refs, rs,
|
||||
tags, &autotags);
|
||||
free_refs(updated_remote_refs);
|
||||
}
|
||||
if (consume_refs(transport, ref_map)) {
|
||||
free_refs(ref_map);
|
||||
retcode = 1;
|
||||
goto cleanup;
|
||||
@ -1164,14 +1203,13 @@ static int do_fetch(struct transport *transport,
|
||||
if (tags == TAGS_DEFAULT && autotags) {
|
||||
struct ref **tail = &ref_map;
|
||||
ref_map = NULL;
|
||||
find_non_local_tags(transport, &ref_map, &tail);
|
||||
find_non_local_tags(remote_refs, &ref_map, &tail);
|
||||
if (ref_map)
|
||||
backfill_tags(transport, ref_map);
|
||||
free_refs(ref_map);
|
||||
}
|
||||
|
||||
cleanup:
|
||||
string_list_clear(&existing_refs, 1);
|
||||
return retcode;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user