diff options
Diffstat (limited to 'fetch-pack.c')
| -rw-r--r-- | fetch-pack.c | 171 |
1 files changed, 135 insertions, 36 deletions
diff --git a/fetch-pack.c b/fetch-pack.c index 50773fdde3..88a078e9be 100644 --- a/fetch-pack.c +++ b/fetch-pack.c @@ -18,7 +18,10 @@ #include "sha1-array.h" #include "oidset.h" #include "packfile.h" +#include "object-store.h" +#include "connected.h" #include "fetch-negotiator.h" +#include "fsck.h" static int transfer_unpack_limit = -1; static int fetch_unpack_limit = -1; @@ -34,6 +37,7 @@ static int server_supports_filtering; static struct lock_file shallow_lock; static const char *alternate_shallow_file; static char *negotiation_algorithm; +static struct strbuf fsck_msg_types = STRBUF_INIT; /* Remember to update object flag allocation in object.h */ #define COMPLETE (1U << 0) @@ -77,7 +81,7 @@ static void cache_one_alternate(const char *refname, void *vcache) { struct alternate_object_cache *cache = vcache; - struct object *obj = parse_object(oid); + struct object *obj = parse_object(the_repository, oid); if (!obj || (obj->flags & ALTERNATE)) return; @@ -108,7 +112,9 @@ static int rev_list_insert_ref(struct fetch_negotiator *negotiator, const char *refname, const struct object_id *oid) { - struct object *o = deref_tag(parse_object(oid), refname, 0); + struct object *o = deref_tag(the_repository, + parse_object(the_repository, oid), + refname, 0); if (o && o->type == OBJ_COMMIT) negotiator->add_tip(negotiator, (struct commit *)o); @@ -266,7 +272,7 @@ static int find_common(struct fetch_negotiator *negotiator, * interested in the case we *know* the object is * reachable and we have already scanned it. */ - if (((o = lookup_object(remote->hash)) != NULL) && + if (((o = lookup_object(the_repository, remote->hash)) != NULL) && (o->flags & COMPLETE)) { continue; } @@ -303,7 +309,7 @@ static int find_common(struct fetch_negotiator *negotiator, return 1; } - if (is_repository_shallow()) + if (is_repository_shallow(the_repository)) write_shallow_commits(&req_buf, 1, NULL); if (args->depth > 0) packet_buf_write(&req_buf, "deepen %d", args->depth); @@ -334,16 +340,16 @@ static int find_common(struct fetch_negotiator *negotiator, if (skip_prefix(line, "shallow ", &arg)) { if (get_oid_hex(arg, &oid)) die(_("invalid shallow line: %s"), line); - register_shallow(&oid); + register_shallow(the_repository, &oid); continue; } if (skip_prefix(line, "unshallow ", &arg)) { if (get_oid_hex(arg, &oid)) die(_("invalid unshallow line: %s"), line); - if (!lookup_object(oid.hash)) + if (!lookup_object(the_repository, oid.hash)) die(_("object not found: %s"), line); /* make sure that it is parsed as shallow */ - if (!parse_object(&oid)) + if (!parse_object(the_repository, &oid)) die(_("error in object: %s"), line); if (unregister_shallow(&oid)) die(_("no shallow found: %s"), line); @@ -402,8 +408,10 @@ static int find_common(struct fetch_negotiator *negotiator, case ACK_ready: case ACK_continue: { struct commit *commit = - lookup_commit(result_oid); + lookup_commit(the_repository, + result_oid); int was_common; + if (!commit) die(_("invalid commit %s"), oid_to_hex(result_oid)); was_common = negotiator->ack(negotiator, commit); @@ -477,14 +485,14 @@ static struct commit_list *complete; static int mark_complete(const struct object_id *oid) { - struct object *o = parse_object(oid); + struct object *o = parse_object(the_repository, oid); while (o && o->type == OBJ_TAG) { struct tag *t = (struct tag *) o; if (!t->tagged) break; /* broken repository */ o->flags |= COMPLETE; - o = parse_object(&t->tagged->oid); + o = parse_object(the_repository, &t->tagged->oid); } if (o && o->type == OBJ_COMMIT) { struct commit *commit = (struct commit *)o; @@ -565,11 +573,11 @@ static void filter_refs(struct fetch_pack_args *args, } i++; } - } - if (!keep && args->fetch_all && - (!args->deepen || !starts_with(ref->name, "refs/tags/"))) - keep = 1; + if (!keep && args->fetch_all && + (!args->deepen || !starts_with(ref->name, "refs/tags/"))) + keep = 1; + } if (keep) { *newtail = ref; @@ -685,7 +693,7 @@ static void mark_complete_and_common_ref(struct fetch_negotiator *negotiator, if (!has_object_file_with_flags(&ref->old_oid, flags)) continue; - o = parse_object(&ref->old_oid); + o = parse_object(the_repository, &ref->old_oid); if (!o) continue; @@ -716,7 +724,9 @@ static void mark_complete_and_common_ref(struct fetch_negotiator *negotiator, * Don't mark them common yet; the server has to be told so first. */ for (ref = *refs; ref; ref = ref->next) { - struct object *o = deref_tag(lookup_object(ref->old_oid.hash), + struct object *o = deref_tag(the_repository, + lookup_object(the_repository, + ref->old_oid.hash), NULL, 0); if (!o || o->type != OBJ_COMMIT || !(o->flags & COMPLETE)) @@ -744,7 +754,7 @@ static int everything_local(struct fetch_pack_args *args, const struct object_id *remote = &ref->old_oid; struct object *o; - o = lookup_object(remote->hash); + o = lookup_object(the_repository, remote->hash); if (!o || !(o->flags & COMPLETE)) { retval = 0; print_verbose(args, "want %s (%s)", oid_to_hex(remote), @@ -859,7 +869,8 @@ static int get_pack(struct fetch_pack_args *args, */ argv_array_push(&cmd.args, "--fsck-objects"); else - argv_array_push(&cmd.args, "--strict"); + argv_array_pushf(&cmd.args, "--strict%s", + fsck_msg_types.buf); } cmd.in = demux.out; @@ -911,7 +922,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args, sort_ref_list(&ref, ref_compare_name); QSORT(sought, nr_sought, cmp_ref_by_name); - if ((args->depth > 0 || is_repository_shallow()) && !server_supports("shallow")) + if ((args->depth > 0 || is_repository_shallow(the_repository)) && !server_supports("shallow")) die(_("Server does not support shallow clients")); if (args->depth > 0 || args->deepen_since || args->deepen_not) args->deepen = 1; @@ -1012,7 +1023,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args, static void add_shallow_requests(struct strbuf *req_buf, const struct fetch_pack_args *args) { - if (is_repository_shallow()) + if (is_repository_shallow(the_repository)) write_shallow_commits(req_buf, 1, NULL); if (args->depth > 0) packet_buf_write(req_buf, "deepen %d", args->depth); @@ -1031,9 +1042,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; /* @@ -1046,13 +1058,15 @@ static void add_wants(const struct ref *wants, struct strbuf *req_buf) * interested in the case we *know* the object is * reachable and we have already scanned it. */ - if (((o = lookup_object(remote->hash)) != NULL) && + if (((o = lookup_object(the_repository, remote->hash)) != NULL) && (o->flags & COMPLETE)) { 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); } } @@ -1127,7 +1141,7 @@ static int send_fetch_request(struct fetch_negotiator *negotiator, int fd_out, /* Add shallow-info and deepen request */ if (server_supports_feature("fetch", "shallow", 0)) add_shallow_requests(&req_buf, args); - else if (is_repository_shallow() || args->deepen) + else if (is_repository_shallow(the_repository) || args->deepen) die(_("Server does not support shallow requests")); /* Add filter */ @@ -1174,13 +1188,13 @@ static int process_section_header(struct packet_reader *reader, int ret; if (packet_reader_peek(reader) != PACKET_READ_NORMAL) - die("error reading section header '%s'", section); + die(_("error reading section header '%s'"), section); ret = !strcmp(reader->line, section); if (!peek) { if (!ret) - die("expected '%s', received '%s'", + die(_("expected '%s', received '%s'"), section, reader->line); packet_reader_read(reader); } @@ -1208,7 +1222,7 @@ static int process_acks(struct fetch_negotiator *negotiator, if (!get_oid_hex(arg, &oid)) { struct commit *commit; oidset_insert(common, &oid); - commit = lookup_commit(&oid); + commit = lookup_commit(the_repository, &oid); negotiator->ack(negotiator, commit); } continue; @@ -1219,12 +1233,12 @@ static int process_acks(struct fetch_negotiator *negotiator, continue; } - die("unexpected acknowledgment line: '%s'", reader->line); + die(_("unexpected acknowledgment line: '%s'"), reader->line); } if (reader->status != PACKET_READ_FLUSH && reader->status != PACKET_READ_DELIM) - die("error processing acks: %d", reader->status); + die(_("error processing acks: %d"), reader->status); /* return 0 if no common, 1 if there are common, or 2 if ready */ return received_ready ? 2 : (received_ack ? 1 : 0); @@ -1241,16 +1255,16 @@ static void receive_shallow_info(struct fetch_pack_args *args, if (skip_prefix(reader->line, "shallow ", &arg)) { if (get_oid_hex(arg, &oid)) die(_("invalid shallow line: %s"), reader->line); - register_shallow(&oid); + register_shallow(the_repository, &oid); continue; } if (skip_prefix(reader->line, "unshallow ", &arg)) { if (get_oid_hex(arg, &oid)) die(_("invalid unshallow line: %s"), reader->line); - if (!lookup_object(oid.hash)) + if (!lookup_object(the_repository, oid.hash)) die(_("object not found: %s"), reader->line); /* make sure that it is parsed as shallow */ - if (!parse_object(&oid)) + if (!parse_object(the_repository, &oid)) die(_("error in object: %s"), reader->line); if (unregister_shallow(&oid)) die(_("no shallow found: %s"), reader->line); @@ -1261,12 +1275,39 @@ static void receive_shallow_info(struct fetch_pack_args *args, if (reader->status != PACKET_READ_FLUSH && reader->status != PACKET_READ_DELIM) - die("error processing shallow info: %d", reader->status); + die(_("error processing shallow info: %d"), reader->status); setup_alternate_shallow(&shallow_lock, &alternate_shallow_file, NULL); args->deepen = 1; } +static void receive_wanted_refs(struct packet_reader *reader, + struct ref **sought, int nr_sought) +{ + process_section_header(reader, "wanted-refs", 0); + while (packet_reader_read(reader) == PACKET_READ_NORMAL) { + struct object_id oid; + const char *end; + int i; + + if (parse_oid_hex(reader->line, &oid, &end) || *end++ != ' ') + die(_("expected wanted-ref, got '%s'"), reader->line); + + for (i = 0; i < nr_sought; i++) { + if (!strcmp(end, sought[i]->name)) { + oidcpy(&sought[i]->old_oid, &oid); + break; + } + } + + if (i == nr_sought) + 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, @@ -1343,6 +1384,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, sought, nr_sought); + /* get the pack */ process_section_header(&reader, "packfile", 0); if (get_pack(args, fd, pack_lockfile)) @@ -1360,6 +1404,31 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args, return ref; } +static int fetch_pack_config_cb(const char *var, const char *value, void *cb) +{ + if (strcmp(var, "fetch.fsck.skiplist") == 0) { + const char *path; + + if (git_config_pathname(&path, var, value)) + return 1; + strbuf_addf(&fsck_msg_types, "%cskiplist=%s", + fsck_msg_types.len ? ',' : '=', path); + free((char *)path); + return 0; + } + + if (skip_prefix(var, "fetch.fsck.", &var)) { + if (is_valid_msg_type(var, value)) + strbuf_addf(&fsck_msg_types, "%c%s=%s", + fsck_msg_types.len ? ',' : '=', var, value); + else + warning("Skipping unknown msg id '%s'", var); + return 0; + } + + return git_default_config(var, value, cb); +} + static void fetch_pack_config(void) { git_config_get_int("fetch.unpacklimit", &fetch_unpack_limit); @@ -1370,7 +1439,7 @@ static void fetch_pack_config(void) git_config_get_string("fetch.negotiationalgorithm", &negotiation_algorithm); - git_config(git_default_config, NULL); + git_config(fetch_pack_config_cb, NULL); } static void fetch_pack_setup(void) @@ -1417,7 +1486,7 @@ static void update_shallow(struct fetch_pack_args *args, if (args->deepen && alternate_shallow_file) { if (*alternate_shallow_file == '\0') { /* --unshallow */ - unlink_or_warn(git_path_shallow()); + unlink_or_warn(git_path_shallow(the_repository)); rollback_lock_file(&shallow_lock); } else commit_lock_file(&shallow_lock); @@ -1501,6 +1570,18 @@ static void update_shallow(struct fetch_pack_args *args, 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, @@ -1529,7 +1610,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); + + 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, sought, nr_sought, &si); +cleanup: clear_shallow_info(&si); return ref_cpy; } |
