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

@ -20,6 +20,7 @@
#include "oidset.h"
#include "packfile.h"
#include "object-store.h"
#include "connected.h"
static int transfer_unpack_limit = -1;
static int fetch_unpack_limit = -1;
@ -1103,9 +1104,10 @@ static void add_shallow_requests(struct strbuf *req_buf,
static void add_wants(const struct ref *wants, struct strbuf *req_buf)
{
int use_ref_in_want = server_supports_feature("fetch", "ref-in-want", 0);
for ( ; wants ; wants = wants->next) {
const struct object_id *remote = &wants->old_oid;
const char *remote_hex;
struct object *o;
/*
@ -1123,8 +1125,10 @@ static void add_wants(const struct ref *wants, struct strbuf *req_buf)
continue;
}
remote_hex = oid_to_hex(remote);
packet_buf_write(req_buf, "want %s\n", remote_hex);
if (!use_ref_in_want || wants->exact_oid)
packet_buf_write(req_buf, "want %s\n", oid_to_hex(remote));
else
packet_buf_write(req_buf, "want-ref %s\n", wants->name);
}
}
@ -1335,6 +1339,32 @@ static void receive_shallow_info(struct fetch_pack_args *args,
args->deepen = 1;
}
static void receive_wanted_refs(struct packet_reader *reader, struct ref *refs)
{
process_section_header(reader, "wanted-refs", 0);
while (packet_reader_read(reader) == PACKET_READ_NORMAL) {
struct object_id oid;
const char *end;
struct ref *r = NULL;
if (parse_oid_hex(reader->line, &oid, &end) || *end++ != ' ')
die("expected wanted-ref, got '%s'", reader->line);
for (r = refs; r; r = r->next) {
if (!strcmp(end, r->name)) {
oidcpy(&r->old_oid, &oid);
break;
}
}
if (!r)
die("unexpected wanted-ref: '%s'", reader->line);
}
if (reader->status != PACKET_READ_DELIM)
die("error processing wanted refs: %d", reader->status);
}
enum fetch_state {
FETCH_CHECK_LOCAL = 0,
FETCH_SEND_REQUEST,
@ -1409,6 +1439,9 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
if (process_section_header(&reader, "shallow-info", 1))
receive_shallow_info(args, &reader);
if (process_section_header(&reader, "wanted-refs", 1))
receive_wanted_refs(&reader, ref);
/* get the pack */
process_section_header(&reader, "packfile", 0);
if (get_pack(args, fd, pack_lockfile))
@ -1471,12 +1504,13 @@ static int remove_duplicates_in_refs(struct ref **ref, int nr)
}
static void update_shallow(struct fetch_pack_args *args,
struct ref **sought, int nr_sought,
struct ref *refs,
struct shallow_info *si)
{
struct oid_array ref = OID_ARRAY_INIT;
int *status;
int i;
struct ref *r;
if (args->deepen && alternate_shallow_file) {
if (*alternate_shallow_file == '\0') { /* --unshallow */
@ -1518,8 +1552,8 @@ static void update_shallow(struct fetch_pack_args *args,
remove_nonexistent_theirs_shallow(si);
if (!si->nr_ours && !si->nr_theirs)
return;
for (i = 0; i < nr_sought; i++)
oid_array_append(&ref, &sought[i]->old_oid);
for (r = refs; r; r = r->next)
oid_array_append(&ref, &r->old_oid);
si->ref = &ref;
if (args->update_shallow) {
@ -1553,17 +1587,29 @@ static void update_shallow(struct fetch_pack_args *args,
* remote is also shallow, check what ref is safe to update
* without updating .git/shallow
*/
status = xcalloc(nr_sought, sizeof(*status));
status = xcalloc(ref.nr, sizeof(*status));
assign_shallow_commits_to_refs(si, NULL, status);
if (si->nr_ours || si->nr_theirs) {
for (i = 0; i < nr_sought; i++)
for (r = refs, i = 0; r; r = r->next, i++)
if (status[i])
sought[i]->status = REF_STATUS_REJECT_SHALLOW;
r->status = REF_STATUS_REJECT_SHALLOW;
}
free(status);
oid_array_clear(&ref);
}
static int iterate_ref_map(void *cb_data, struct object_id *oid)
{
struct ref **rm = cb_data;
struct ref *ref = *rm;
if (!ref)
return -1; /* end of the list */
*rm = ref->next;
oidcpy(oid, &ref->old_oid);
return 0;
}
struct ref *fetch_pack(struct fetch_pack_args *args,
int fd[], struct child_process *conn,
const struct ref *ref,
@ -1592,7 +1638,25 @@ struct ref *fetch_pack(struct fetch_pack_args *args,
ref_cpy = do_fetch_pack(args, fd, ref, sought, nr_sought,
&si, pack_lockfile);
reprepare_packed_git(the_repository);
update_shallow(args, sought, nr_sought, &si);
if (!args->cloning && args->deepen) {
struct check_connected_options opt = CHECK_CONNECTED_INIT;
struct ref *iterator = ref_cpy;
opt.shallow_file = alternate_shallow_file;
if (args->deepen)
opt.is_deepening_fetch = 1;
if (check_connected(iterate_ref_map, &iterator, &opt)) {
error(_("remote did not send all necessary objects"));
free_refs(ref_cpy);
ref_cpy = NULL;
rollback_lock_file(&shallow_lock);
goto cleanup;
}
args->connectivity_checked = 1;
}
update_shallow(args, ref_cpy, &si);
cleanup:
clear_shallow_info(&si);
return ref_cpy;
}