Merge branch 'jt/partial-clone-missing-ref-delta-base' into maint
[gitweb.git] / fetch-pack.c
index 812be15d7e568522973227bb939343d94c008ceb..1c10f54e788ca53b548a226a66dd1eec96a8cb22 100644 (file)
@@ -191,8 +191,10 @@ static void send_request(struct fetch_pack_args *args,
        if (args->stateless_rpc) {
                send_sideband(fd, -1, buf->buf, buf->len, LARGE_PACKET_MAX);
                packet_flush(fd);
-       } else
-               write_or_die(fd, buf->buf, buf->len);
+       } else {
+               if (write_in_full(fd, buf->buf, buf->len) < 0)
+                       die_errno(_("unable to write to remote"));
+       }
 }
 
 static void insert_one_alternate_object(struct fetch_negotiator *negotiator,
@@ -571,9 +573,14 @@ static void filter_refs(struct fetch_pack_args *args,
                next = ref->next;
 
                if (starts_with(ref->name, "refs/") &&
-                   check_refname_format(ref->name, 0))
-                       ; /* trash */
-               else {
+                   check_refname_format(ref->name, 0)) {
+                       /*
+                        * trash or a peeled value; do not even add it to
+                        * unmatched list
+                        */
+                       free_one_ref(ref);
+                       continue;
+               } else {
                        while (i < nr_sought) {
                                int cmp = strcmp(ref->name, sought[i]->name);
                                if (cmp < 0)
@@ -628,10 +635,7 @@ static void filter_refs(struct fetch_pack_args *args,
        }
 
        oidset_clear(&tip_oids);
-       for (ref = unmatched; ref; ref = next) {
-               next = ref->next;
-               free(ref);
-       }
+       free_refs(unmatched);
 
        *refs = newlist;
 }
@@ -1111,7 +1115,7 @@ static int send_fetch_request(struct fetch_negotiator *negotiator, int fd_out,
            server_supports_v2("server-option", 1)) {
                int i;
                for (i = 0; i < args->server_options->nr; i++)
-                       packet_write_fmt(fd_out, "server-option=%s",
+                       packet_buf_write(&req_buf, "server-option=%s",
                                         args->server_options->items[i].string);
        }
 
@@ -1163,7 +1167,8 @@ static int send_fetch_request(struct fetch_negotiator *negotiator, int fd_out,
 
        /* Send request */
        packet_buf_flush(&req_buf);
-       write_or_die(fd_out, req_buf.buf, req_buf.len);
+       if (write_in_full(fd_out, req_buf.buf, req_buf.len) < 0)
+               die_errno(_("unable to write request to remote"));
 
        strbuf_release(&req_buf);
        return ret;
@@ -1250,9 +1255,11 @@ static int process_acks(struct fetch_negotiator *negotiator,
 }
 
 static void receive_shallow_info(struct fetch_pack_args *args,
-                                struct packet_reader *reader)
+                                struct packet_reader *reader,
+                                struct oid_array *shallows,
+                                struct shallow_info *si)
 {
-       int line_received = 0;
+       int unshallow_received = 0;
 
        process_section_header(reader, "shallow-info", 0);
        while (packet_reader_read(reader) == PACKET_READ_NORMAL) {
@@ -1262,8 +1269,7 @@ 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(the_repository, &oid);
-                       line_received = 1;
+                       oid_array_append(shallows, &oid);
                        continue;
                }
                if (skip_prefix(reader->line, "unshallow ", &arg)) {
@@ -1276,7 +1282,7 @@ static void receive_shallow_info(struct fetch_pack_args *args,
                                die(_("error in object: %s"), reader->line);
                        if (unregister_shallow(&oid))
                                die(_("no shallow found: %s"), reader->line);
-                       line_received = 1;
+                       unshallow_received = 1;
                        continue;
                }
                die(_("expected shallow/unshallow, got %s"), reader->line);
@@ -1286,15 +1292,41 @@ static void receive_shallow_info(struct fetch_pack_args *args,
            reader->status != PACKET_READ_DELIM)
                die(_("error processing shallow info: %d"), reader->status);
 
-       if (line_received) {
+       if (args->deepen || unshallow_received) {
+               /*
+                * Treat these as shallow lines caused by our depth settings.
+                * In v0, these lines cannot cause refs to be rejected; do the
+                * same.
+                */
+               int i;
+
+               for (i = 0; i < shallows->nr; i++)
+                       register_shallow(the_repository, &shallows->oid[i]);
                setup_alternate_shallow(&shallow_lock, &alternate_shallow_file,
                                        NULL);
                args->deepen = 1;
+       } else if (shallows->nr) {
+               /*
+                * Treat these as shallow lines caused by the remote being
+                * shallow. In v0, remote refs that reach these objects are
+                * rejected (unless --update-shallow is set); do the same.
+                */
+               prepare_shallow_info(si, shallows);
+               if (si->nr_ours || si->nr_theirs)
+                       alternate_shallow_file =
+                               setup_temporary_shallow(si->shallow);
+               else
+                       alternate_shallow_file = NULL;
        } else {
                alternate_shallow_file = NULL;
        }
 }
 
+static int cmp_name_ref(const void *name, const void *ref)
+{
+       return strcmp(name, (*(struct ref **)ref)->name);
+}
+
 static void receive_wanted_refs(struct packet_reader *reader,
                                struct ref **sought, int nr_sought)
 {
@@ -1302,20 +1334,16 @@ static void receive_wanted_refs(struct packet_reader *reader,
        while (packet_reader_read(reader) == PACKET_READ_NORMAL) {
                struct object_id oid;
                const char *end;
-               int i;
+               struct ref **found;
 
                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)
+               found = bsearch(end, sought, nr_sought, sizeof(*sought),
+                               cmp_name_ref);
+               if (!found)
                        die(_("unexpected wanted-ref: '%s'"), reader->line);
+               oidcpy(&(*found)->old_oid, &oid);
        }
 
        if (reader->status != PACKET_READ_DELIM)
@@ -1334,6 +1362,8 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
                                    int fd[2],
                                    const struct ref *orig_ref,
                                    struct ref **sought, int nr_sought,
+                                   struct oid_array *shallows,
+                                   struct shallow_info *si,
                                    char **pack_lockfile)
 {
        struct ref *ref = copy_ref_list(orig_ref);
@@ -1408,7 +1438,7 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
                case FETCH_GET_PACK:
                        /* Check for shallow-info section */
                        if (process_section_header(&reader, "shallow-info", 1))
-                               receive_shallow_info(args, &reader);
+                               receive_shallow_info(args, &reader, shallows, si);
 
                        if (process_section_header(&reader, "wanted-refs", 1))
                                receive_wanted_refs(&reader, sought, nr_sought);
@@ -1612,9 +1642,8 @@ static int iterate_ref_map(void *cb_data, struct object_id *oid)
 }
 
 struct ref *fetch_pack(struct fetch_pack_args *args,
-                      int fd[], struct child_process *conn,
+                      int fd[],
                       const struct ref *ref,
-                      const char *dest,
                       struct ref **sought, int nr_sought,
                       struct oid_array *shallow,
                       char **pack_lockfile,
@@ -1622,6 +1651,7 @@ struct ref *fetch_pack(struct fetch_pack_args *args,
 {
        struct ref *ref_cpy;
        struct shallow_info si;
+       struct oid_array shallows_scratch = OID_ARRAY_INIT;
 
        fetch_pack_setup();
        if (nr_sought)
@@ -1645,13 +1675,18 @@ struct ref *fetch_pack(struct fetch_pack_args *args,
                packet_flush(fd[1]);
                die(_("no matching remote head"));
        }
-       prepare_shallow_info(&si, shallow);
-       if (version == protocol_v2)
+       if (version == protocol_v2) {
+               if (shallow->nr)
+                       BUG("Protocol V2 does not provide shallows at this point in the fetch");
+               memset(&si, 0, sizeof(si));
                ref_cpy = do_fetch_pack_v2(args, fd, ref, sought, nr_sought,
+                                          &shallows_scratch, &si,
                                           pack_lockfile);
-       else
+       } else {
+               prepare_shallow_info(&si, shallow);
                ref_cpy = do_fetch_pack(args, fd, ref, sought, nr_sought,
                                        &si, pack_lockfile);
+       }
        reprepare_packed_git(the_repository);
 
        if (!args->cloning && args->deepen) {
@@ -1673,6 +1708,7 @@ struct ref *fetch_pack(struct fetch_pack_args *args,
        update_shallow(args, sought, nr_sought, &si);
 cleanup:
        clear_shallow_info(&si);
+       oid_array_clear(&shallows_scratch);
        return ref_cpy;
 }