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:
Junio C Hamano
2018-07-24 14:50:44 -07:00
22 changed files with 837 additions and 82 deletions

View File

@ -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;
}