]> git.ipfire.org Git - thirdparty/git.git/commitdiff
Merge branch 'jt/fetch-pack-request-fix' into jt/push-negotiation
authorJunio C Hamano <gitster@pobox.com>
Fri, 9 Apr 2021 04:50:10 +0000 (21:50 -0700)
committerJunio C Hamano <gitster@pobox.com>
Fri, 9 Apr 2021 04:50:10 +0000 (21:50 -0700)
* jt/fetch-pack-request-fix:
  fetch-pack: buffer object-format with other args

1  2 
fetch-pack.c

diff --combined fetch-pack.c
index 6e68276aa3a2969ac3f13d93fe29d64e89d04463,30a08675f0ff79c4a5f379b0eab14ef9b4176d20..2318ebe680cf9fb814afee355f9a308c6b8e80a3
@@@ -35,10 -35,8 +35,10 @@@ static int fetch_fsck_objects = -1
  static int transfer_fsck_objects = -1;
  static int agent_supported;
  static int server_supports_filtering;
 +static int advertise_sid;
  static struct shallow_lock shallow_lock;
  static const char *alternate_shallow_file;
 +static struct fsck_options fsck_options = FSCK_OPTIONS_MISSING_GITMODULES;
  static struct strbuf fsck_msg_types = STRBUF_INIT;
  static struct string_list uri_protocols = STRING_LIST_INIT_DUP;
  
@@@ -110,48 -108,24 +110,48 @@@ static void for_each_cached_alternate(s
                cb(negotiator, cache.items[i]);
  }
  
 +static struct commit *deref_without_lazy_fetch(const struct object_id *oid,
 +                                             int mark_tags_complete)
 +{
 +      enum object_type type;
 +      struct object_info info = { .typep = &type };
 +
 +      while (1) {
 +              if (oid_object_info_extended(the_repository, oid, &info,
 +                                           OBJECT_INFO_SKIP_FETCH_OBJECT | OBJECT_INFO_QUICK))
 +                      return NULL;
 +              if (type == OBJ_TAG) {
 +                      struct tag *tag = (struct tag *)
 +                              parse_object(the_repository, oid);
 +
 +                      if (!tag->tagged)
 +                              return NULL;
 +                      if (mark_tags_complete)
 +                              tag->object.flags |= COMPLETE;
 +                      oid = &tag->tagged->oid;
 +              } else {
 +                      break;
 +              }
 +      }
 +      if (type == OBJ_COMMIT)
 +              return (struct commit *) parse_object(the_repository, oid);
 +      return NULL;
 +}
 +
  static int rev_list_insert_ref(struct fetch_negotiator *negotiator,
 -                             const char *refname,
                               const struct object_id *oid)
  {
 -      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);
 +      struct commit *c = deref_without_lazy_fetch(oid, 0);
  
 +      if (c)
 +              negotiator->add_tip(negotiator, c);
        return 0;
  }
  
  static int rev_list_insert_ref_oid(const char *refname, const struct object_id *oid,
                                   int flag, void *cb_data)
  {
 -      return rev_list_insert_ref(cb_data, refname, oid);
 +      return rev_list_insert_ref(cb_data, oid);
  }
  
  enum ack_type {
@@@ -227,7 -201,7 +227,7 @@@ static void send_request(struct fetch_p
  static void insert_one_alternate_object(struct fetch_negotiator *negotiator,
                                        struct object *obj)
  {
 -      rev_list_insert_ref(negotiator, NULL, &obj->oid);
 +      rev_list_insert_ref(negotiator, &obj->oid);
  }
  
  #define INITIAL_FLUSH 16
@@@ -256,12 -230,13 +256,12 @@@ static void mark_tips(struct fetch_nego
        int i;
  
        if (!negotiation_tips) {
 -              for_each_ref(rev_list_insert_ref_oid, negotiator);
 +              for_each_rawref(rev_list_insert_ref_oid, negotiator);
                return;
        }
  
        for (i = 0; i < negotiation_tips->nr; i++)
 -              rev_list_insert_ref(negotiator, NULL,
 -                                  &negotiation_tips->oid[i]);
 +              rev_list_insert_ref(negotiator, &negotiation_tips->oid[i]);
        return;
  }
  
@@@ -287,8 -262,10 +287,8 @@@ static int find_common(struct fetch_neg
                           PACKET_READ_CHOMP_NEWLINE |
                           PACKET_READ_DIE_ON_ERR_PACKET);
  
 -      if (!args->no_dependents) {
 -              mark_tips(negotiator, args->negotiation_tips);
 -              for_each_cached_alternate(negotiator, insert_one_alternate_object);
 -      }
 +      mark_tips(negotiator, args->negotiation_tips);
 +      for_each_cached_alternate(negotiator, insert_one_alternate_object);
  
        fetching = 0;
        for ( ; refs ; refs = refs->next) {
                 * We use lookup_object here because we are only
                 * interested in the case we *know* the object is
                 * reachable and we have already scanned it.
 -               *
 -               * Do this only if args->no_dependents is false (if it is true,
 -               * we cannot trust the object flags).
                 */
 -              if (!args->no_dependents &&
 -                  ((o = lookup_object(the_repository, remote)) != NULL) &&
 +              if (((o = lookup_object(the_repository, remote)) != NULL) &&
                                (o->flags & COMPLETE)) {
                        continue;
                }
                        if (deepen_not_ok)      strbuf_addstr(&c, " deepen-not");
                        if (agent_supported)    strbuf_addf(&c, " agent=%s",
                                                            git_user_agent_sanitized());
 +                      if (advertise_sid)
 +                              strbuf_addf(&c, " session-id=%s", trace2_session_id());
                        if (args->filter_options.choice)
                                strbuf_addstr(&c, " filter");
                        packet_buf_write(&req_buf, "want %s%s\n", remote_hex, c.buf);
        trace2_region_enter("fetch-pack", "negotiation_v0_v1", the_repository);
        flushes = 0;
        retval = -1;
 -      if (args->no_dependents)
 -              goto done;
        while ((oid = negotiator->next(negotiator))) {
                packet_buf_write(&req_buf, "have %s\n", oid_to_hex(oid));
                print_verbose(args, "have %s", oid_to_hex(oid));
@@@ -522,11 -503,21 +522,11 @@@ static struct commit_list *complete
  
  static int mark_complete(const struct object_id *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(the_repository, &t->tagged->oid);
 -      }
 -      if (o && o->type == OBJ_COMMIT) {
 -              struct commit *commit = (struct commit *)o;
 -              if (!(commit->object.flags & COMPLETE)) {
 -                      commit->object.flags |= COMPLETE;
 -                      commit_list_insert(commit, &complete);
 -              }
 +      struct commit *commit = deref_without_lazy_fetch(oid, 1);
 +
 +      if (commit && !(commit->object.flags & COMPLETE)) {
 +              commit->object.flags |= COMPLETE;
 +              commit_list_insert(commit, &complete);
        }
        return 0;
  }
@@@ -662,7 -653,9 +662,7 @@@ struct loose_object_iter 
  
  /*
   * Mark recent commits available locally and reachable from a local ref as
 - * COMPLETE. If args->no_dependents is false, also mark COMPLETE remote refs as
 - * COMMON_REF (otherwise, we are not planning to participate in negotiation, and
 - * thus do not need COMMON_REF marks).
 + * COMPLETE.
   *
   * The cutoff time for recency is determined by this heuristic: it is the
   * earliest commit time of the objects in refs that are commits and that we know
@@@ -709,7 -702,7 +709,7 @@@ static void mark_complete_and_common_re
         */
        trace2_region_enter("fetch-pack", "mark_complete_local_refs", NULL);
        if (!args->deepen) {
 -              for_each_ref(mark_complete_oid, NULL);
 +              for_each_rawref(mark_complete_oid, NULL);
                for_each_cached_alternate(NULL, mark_alternate_complete);
                commit_list_sort_by_date(&complete);
                if (cutoff)
         */
        trace2_region_enter("fetch-pack", "mark_common_remote_refs", NULL);
        for (ref = *refs; ref; ref = ref->next) {
 -              struct object *o = deref_tag(the_repository,
 -                                           lookup_object(the_repository,
 -                                           &ref->old_oid),
 -                                           NULL, 0);
 +              struct commit *c = deref_without_lazy_fetch(&ref->old_oid, 0);
  
 -              if (!o || o->type != OBJ_COMMIT || !(o->flags & COMPLETE))
 +              if (!c || !(c->object.flags & COMPLETE))
                        continue;
  
 -              negotiator->known_common(negotiator,
 -                                       (struct commit *)o);
 +              negotiator->known_common(negotiator, c);
        }
        trace2_region_leave("fetch-pack", "mark_common_remote_refs", NULL);
  
@@@ -773,11 -770,13 +773,11 @@@ static int sideband_demux(int in, int o
        return ret;
  }
  
 -static void write_promisor_file(const char *keep_name,
 -                              struct ref **sought, int nr_sought)
 +static void create_promisor_file(const char *keep_name,
 +                               struct ref **sought, int nr_sought)
  {
        struct strbuf promisor_name = STRBUF_INIT;
        int suffix_stripped;
 -      FILE *output;
 -      int i;
  
        strbuf_addstr(&promisor_name, keep_name);
        suffix_stripped = strbuf_strip_suffix(&promisor_name, ".keep");
                    keep_name);
        strbuf_addstr(&promisor_name, ".promisor");
  
 -      output = xfopen(promisor_name.buf, "w");
 -      for (i = 0; i < nr_sought; i++)
 -              fprintf(output, "%s %s\n", oid_to_hex(&sought[i]->old_oid),
 -                      sought[i]->name);
 -      fclose(output);
 +      write_promisor_file(promisor_name.buf, sought, nr_sought);
  
        strbuf_release(&promisor_name);
  }
  
 +static void parse_gitmodules_oids(int fd, struct oidset *gitmodules_oids)
 +{
 +      int len = the_hash_algo->hexsz + 1; /* hash + NL */
 +
 +      do {
 +              char hex_hash[GIT_MAX_HEXSZ + 1];
 +              int read_len = read_in_full(fd, hex_hash, len);
 +              struct object_id oid;
 +              const char *end;
 +
 +              if (!read_len)
 +                      return;
 +              if (read_len != len)
 +                      die("invalid length read %d", read_len);
 +              if (parse_oid_hex(hex_hash, &oid, &end) || *end != '\n')
 +                      die("invalid hash");
 +              oidset_insert(gitmodules_oids, &oid);
 +      } while (1);
 +}
 +
 +/*
 + * If packfile URIs were provided, pass a non-NULL pointer to index_pack_args.
 + * The strings to pass as the --index-pack-arg arguments to http-fetch will be
 + * stored there. (It must be freed by the caller.)
 + */
  static int get_pack(struct fetch_pack_args *args,
                    int xd[2], struct string_list *pack_lockfiles,
 -                  int only_packfile,
 -                  struct ref **sought, int nr_sought)
 +                  struct strvec *index_pack_args,
 +                  struct ref **sought, int nr_sought,
 +                  struct oidset *gitmodules_oids)
  {
        struct async demux;
        int do_keep = args->keep_pack;
        struct pack_header header;
        int pass_header = 0;
        struct child_process cmd = CHILD_PROCESS_INIT;
 +      int fsck_objects = 0;
        int ret;
  
        memset(&demux, 0, sizeof(demux));
        else
                demux.out = xd[0];
  
 -      if (!args->keep_pack && unpack_limit) {
 +      if (!args->keep_pack && unpack_limit && !index_pack_args) {
  
                if (read_pack_header(demux.out, &header))
                        die(_("protocol error: bad pack header"));
        }
  
        if (alternate_shallow_file) {
 -              argv_array_push(&cmd.args, "--shallow-file");
 -              argv_array_push(&cmd.args, alternate_shallow_file);
 +              strvec_push(&cmd.args, "--shallow-file");
 +              strvec_push(&cmd.args, alternate_shallow_file);
        }
  
 -      if (do_keep || args->from_promisor) {
 -              if (pack_lockfiles)
 +      if (fetch_fsck_objects >= 0
 +          ? fetch_fsck_objects
 +          : transfer_fsck_objects >= 0
 +          ? transfer_fsck_objects
 +          : 0)
 +              fsck_objects = 1;
 +
 +      if (do_keep || args->from_promisor || index_pack_args || fsck_objects) {
 +              if (pack_lockfiles || fsck_objects)
                        cmd.out = -1;
                cmd_name = "index-pack";
 -              argv_array_push(&cmd.args, cmd_name);
 -              argv_array_push(&cmd.args, "--stdin");
 +              strvec_push(&cmd.args, cmd_name);
 +              strvec_push(&cmd.args, "--stdin");
                if (!args->quiet && !args->no_progress)
 -                      argv_array_push(&cmd.args, "-v");
 +                      strvec_push(&cmd.args, "-v");
                if (args->use_thin_pack)
 -                      argv_array_push(&cmd.args, "--fix-thin");
 -              if (do_keep && (args->lock_pack || unpack_limit)) {
 +                      strvec_push(&cmd.args, "--fix-thin");
 +              if ((do_keep || index_pack_args) && (args->lock_pack || unpack_limit)) {
                        char hostname[HOST_NAME_MAX + 1];
                        if (xgethostname(hostname, sizeof(hostname)))
                                xsnprintf(hostname, sizeof(hostname), "localhost");
 -                      argv_array_pushf(&cmd.args,
 -                                      "--keep=fetch-pack %"PRIuMAX " on %s",
 -                                      (uintmax_t)getpid(), hostname);
 +                      strvec_pushf(&cmd.args,
 +                                   "--keep=fetch-pack %"PRIuMAX " on %s",
 +                                   (uintmax_t)getpid(), hostname);
                }
 -              if (only_packfile && args->check_self_contained_and_connected)
 -                      argv_array_push(&cmd.args, "--check-self-contained-and-connected");
 +              if (!index_pack_args && args->check_self_contained_and_connected)
 +                      strvec_push(&cmd.args, "--check-self-contained-and-connected");
                else
                        /*
                         * We cannot perform any connectivity checks because
                         * have this responsibility.
                         */
                        args->check_self_contained_and_connected = 0;
 -              /*
 -               * If we're obtaining the filename of a lockfile, we'll use
 -               * that filename to write a .promisor file with more
 -               * information below. If not, we need index-pack to do it for
 -               * us.
 -               */
 -              if (!(do_keep && pack_lockfiles) && args->from_promisor)
 -                      argv_array_push(&cmd.args, "--promisor");
 +
 +              if (args->from_promisor)
 +                      /*
 +                       * create_promisor_file() may be called afterwards but
 +                       * we still need index-pack to know that this is a
 +                       * promisor pack. For example, if transfer.fsckobjects
 +                       * is true, index-pack needs to know that .gitmodules
 +                       * is a promisor object (so that it won't complain if
 +                       * it is missing).
 +                       */
 +                      strvec_push(&cmd.args, "--promisor");
        }
        else {
                cmd_name = "unpack-objects";
 -              argv_array_push(&cmd.args, cmd_name);
 +              strvec_push(&cmd.args, cmd_name);
                if (args->quiet || args->no_progress)
 -                      argv_array_push(&cmd.args, "-q");
 +                      strvec_push(&cmd.args, "-q");
                args->check_self_contained_and_connected = 0;
        }
  
        if (pass_header)
 -              argv_array_pushf(&cmd.args, "--pack_header=%"PRIu32",%"PRIu32,
 -                               ntohl(header.hdr_version),
 +              strvec_pushf(&cmd.args, "--pack_header=%"PRIu32",%"PRIu32,
 +                           ntohl(header.hdr_version),
                                 ntohl(header.hdr_entries));
 -      if (fetch_fsck_objects >= 0
 -          ? fetch_fsck_objects
 -          : transfer_fsck_objects >= 0
 -          ? transfer_fsck_objects
 -          : 0) {
 -              if (args->from_promisor)
 +      if (fsck_objects) {
 +              if (args->from_promisor || index_pack_args)
                        /*
                         * We cannot use --strict in index-pack because it
                         * checks both broken objects and links, but we only
                         * want to check for broken objects.
                         */
 -                      argv_array_push(&cmd.args, "--fsck-objects");
 +                      strvec_push(&cmd.args, "--fsck-objects");
                else
 -                      argv_array_pushf(&cmd.args, "--strict%s",
 -                                       fsck_msg_types.buf);
 +                      strvec_pushf(&cmd.args, "--strict%s",
 +                                   fsck_msg_types.buf);
 +      }
 +
 +      if (index_pack_args) {
 +              int i;
 +
 +              for (i = 0; i < cmd.args.nr; i++)
 +                      strvec_push(index_pack_args, cmd.args.v[i]);
        }
  
        cmd.in = demux.out;
        cmd.git_cmd = 1;
        if (start_command(&cmd))
                die(_("fetch-pack: unable to fork off %s"), cmd_name);
 -      if (do_keep && pack_lockfiles) {
 -              string_list_append_nodup(pack_lockfiles,
 -                                       index_pack_lockfile(cmd.out));
 +      if (do_keep && (pack_lockfiles || fsck_objects)) {
 +              int is_well_formed;
 +              char *pack_lockfile = index_pack_lockfile(cmd.out, &is_well_formed);
 +
 +              if (!is_well_formed)
 +                      die(_("fetch-pack: invalid index-pack output"));
 +              if (pack_lockfile)
 +                      string_list_append_nodup(pack_lockfiles, pack_lockfile);
 +              parse_gitmodules_oids(cmd.out, gitmodules_oids);
                close(cmd.out);
        }
  
         * obtained .keep filename if necessary
         */
        if (do_keep && pack_lockfiles && pack_lockfiles->nr && args->from_promisor)
 -              write_promisor_file(pack_lockfiles->items[0].string, sought, nr_sought);
 +              create_promisor_file(pack_lockfiles->items[0].string, sought, nr_sought);
  
        return 0;
  }
@@@ -1003,8 -960,12 +1003,8 @@@ static struct ref *do_fetch_pack(struc
        struct fetch_negotiator negotiator_alloc;
        struct fetch_negotiator *negotiator;
  
 -      if (args->no_dependents) {
 -              negotiator = NULL;
 -      } else {
 -              negotiator = &negotiator_alloc;
 -              fetch_negotiator_init(r, negotiator);
 -      }
 +      negotiator = &negotiator_alloc;
 +      fetch_negotiator_init(r, negotiator);
  
        sort_ref_list(&ref, ref_compare_name);
        QSORT(sought, nr_sought, cmp_ref_by_name);
                                      agent_len, agent_feature);
        }
  
 +      if (!server_supports("session-id"))
 +              advertise_sid = 0;
 +
        if (server_supports("shallow"))
                print_verbose(args, _("Server supports %s"), "shallow");
        else if (args->depth > 0 || is_repository_shallow(r))
        if (!server_supports_hash(the_hash_algo->name, NULL))
                die(_("Server does not support this repository's object format"));
  
 -      if (!args->no_dependents) {
 -              mark_complete_and_common_ref(negotiator, args, &ref);
 -              filter_refs(args, &ref, sought, nr_sought);
 -              if (everything_local(args, &ref)) {
 -                      packet_flush(fd[1]);
 -                      goto all_done;
 -              }
 -      } else {
 -              filter_refs(args, &ref, sought, nr_sought);
 +      mark_complete_and_common_ref(negotiator, args, &ref);
 +      filter_refs(args, &ref, sought, nr_sought);
 +      if (everything_local(args, &ref)) {
 +              packet_flush(fd[1]);
 +              goto all_done;
        }
        if (find_common(negotiator, args, fd, &oid, ref) < 0)
                if (!args->keep_pack)
        if (args->deepen)
                setup_alternate_shallow(&shallow_lock, &alternate_shallow_file,
                                        NULL);
 -      else if (si->nr_ours || si->nr_theirs)
 +      else if (si->nr_ours || si->nr_theirs) {
 +              if (args->reject_shallow_remote)
 +                      die(_("source repository is shallow, reject to clone."));
                alternate_shallow_file = setup_temporary_shallow(si->shallow);
 -      else
 +      else
                alternate_shallow_file = NULL;
 -      if (get_pack(args, fd, pack_lockfiles, 1, sought, nr_sought))
 +      if (get_pack(args, fd, pack_lockfiles, NULL, sought, nr_sought,
 +                   &fsck_options.gitmodules_found))
                die(_("git fetch-pack: fetch failed."));
 +      if (fsck_finish(&fsck_options))
 +              die("fsck failed");
  
   all_done:
        if (negotiator)
@@@ -1153,7 -1110,7 +1153,7 @@@ static void add_shallow_requests(struc
                packet_buf_write(req_buf, "deepen-relative\n");
  }
  
 -static void add_wants(int no_dependents, const struct ref *wants, 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);
  
                 * We use lookup_object here because we are only
                 * interested in the case we *know* the object is
                 * reachable and we have already scanned it.
 -               *
 -               * Do this only if args->no_dependents is false (if it is true,
 -               * we cannot trust the object flags).
                 */
 -              if (!no_dependents &&
 -                  ((o = lookup_object(the_repository, remote)) != NULL) &&
 +              if (((o = lookup_object(the_repository, remote)) != NULL) &&
                    (o->flags & COMPLETE)) {
                        continue;
                }
@@@ -1236,8 -1197,6 +1236,8 @@@ static int send_fetch_request(struct fe
                packet_buf_write(&req_buf, "command=fetch");
        if (server_supports_v2("agent", 0))
                packet_buf_write(&req_buf, "agent=%s", git_user_agent_sanitized());
 +      if (advertise_sid && server_supports_v2("session-id", 0))
 +              packet_buf_write(&req_buf, "session-id=%s", trace2_session_id());
        if (args->server_options && args->server_options->nr &&
            server_supports_v2("server-option", 1)) {
                int i;
                if (hash_algo_by_ptr(the_hash_algo) != hash_algo)
                        die(_("mismatched algorithms: client %s; server %s"),
                            the_hash_algo->name, hash_name);
-               packet_write_fmt(fd_out, "object-format=%s", the_hash_algo->name);
+               packet_buf_write(&req_buf, "object-format=%s", the_hash_algo->name);
        } else if (hash_algo_by_ptr(the_hash_algo) != GIT_HASH_SHA1) {
                die(_("the server does not support algorithm '%s'"),
                    the_hash_algo->name);
        }
  
        /* add wants */
 -      add_wants(args->no_dependents, wants, &req_buf);
 +      add_wants(wants, &req_buf);
  
 -      if (args->no_dependents) {
 -              packet_buf_write(&req_buf, "done");
 -              ret = 1;
 -      } else {
 -              /* Add all of the common commits we've found in previous rounds */
 -              add_common(&req_buf, common);
 +      /* Add all of the common commits we've found in previous rounds */
 +      add_common(&req_buf, common);
  
 -              /* Add initial haves */
 -              ret = add_haves(negotiator, seen_ack, &req_buf,
 -                              haves_to_send, in_vain);
 -      }
 +      /* Add initial haves */
 +      ret = add_haves(negotiator, seen_ack, &req_buf,
 +                      haves_to_send, in_vain);
  
        /* Send request */
        packet_buf_flush(&req_buf);
@@@ -1485,12 -1449,10 +1485,12 @@@ static void receive_shallow_info(struc
                 * rejected (unless --update-shallow is set); do the same.
                 */
                prepare_shallow_info(si, shallows);
 -              if (si->nr_ours || si->nr_theirs)
 +              if (si->nr_ours || si->nr_theirs) {
 +                      if (args->reject_shallow_remote)
 +                              die(_("source repository is shallow, reject to clone."));
                        alternate_shallow_file =
                                setup_temporary_shallow(si->shallow);
 -              else
 +              else
                        alternate_shallow_file = NULL;
        } else {
                alternate_shallow_file = NULL;
@@@ -1575,10 -1537,13 +1575,10 @@@ static struct ref *do_fetch_pack_v2(str
        int seen_ack = 0;
        struct string_list packfile_uris = STRING_LIST_INIT_DUP;
        int i;
 +      struct strvec index_pack_args = STRVEC_INIT;
  
 -      if (args->no_dependents) {
 -              negotiator = NULL;
 -      } else {
 -              negotiator = &negotiator_alloc;
 -              fetch_negotiator_init(r, negotiator);
 -      }
 +      negotiator = &negotiator_alloc;
 +      fetch_negotiator_init(r, negotiator);
  
        packet_reader_init(&reader, fd[0], NULL, 0,
                           PACKET_READ_CHOMP_NEWLINE |
                                args->deepen = 1;
  
                        /* Filter 'ref' by 'sought' and those that aren't local */
 -                      if (!args->no_dependents) {
 -                              mark_complete_and_common_ref(negotiator, args, &ref);
 -                              filter_refs(args, &ref, sought, nr_sought);
 -                              if (everything_local(args, &ref))
 -                                      state = FETCH_DONE;
 -                              else
 -                                      state = FETCH_SEND_REQUEST;
 -
 -                              mark_tips(negotiator, args->negotiation_tips);
 -                              for_each_cached_alternate(negotiator,
 -                                                        insert_one_alternate_object);
 -                      } else {
 -                              filter_refs(args, &ref, sought, nr_sought);
 +                      mark_complete_and_common_ref(negotiator, args, &ref);
 +                      filter_refs(args, &ref, sought, nr_sought);
 +                      if (everything_local(args, &ref))
 +                              state = FETCH_DONE;
 +                      else
                                state = FETCH_SEND_REQUEST;
 -                      }
 +
 +                      mark_tips(negotiator, args->negotiation_tips);
 +                      for_each_cached_alternate(negotiator,
 +                                                insert_one_alternate_object);
                        break;
                case FETCH_SEND_REQUEST:
                        if (!negotiation_started) {
                                receive_packfile_uris(&reader, &packfile_uris);
                        process_section_header(&reader, "packfile", 0);
                        if (get_pack(args, fd, pack_lockfiles,
 -                                   !packfile_uris.nr, sought, nr_sought))
 +                                   packfile_uris.nr ? &index_pack_args : NULL,
 +                                   sought, nr_sought, &fsck_options.gitmodules_found))
                                die(_("git fetch-pack: fetch failed."));
                        do_check_stateless_delimiter(args, &reader);
  
        }
  
        for (i = 0; i < packfile_uris.nr; i++) {
 +              int j;
                struct child_process cmd = CHILD_PROCESS_INIT;
                char packname[GIT_MAX_HEXSZ + 1];
                const char *uri = packfile_uris.items[i].string +
                        the_hash_algo->hexsz + 1;
  
 -              argv_array_push(&cmd.args, "http-fetch");
 -              argv_array_pushf(&cmd.args, "--packfile=%.*s",
 -                               (int) the_hash_algo->hexsz,
 -                               packfile_uris.items[i].string);
 -              argv_array_push(&cmd.args, uri);
 +              strvec_push(&cmd.args, "http-fetch");
 +              strvec_pushf(&cmd.args, "--packfile=%.*s",
 +                           (int) the_hash_algo->hexsz,
 +                           packfile_uris.items[i].string);
 +              for (j = 0; j < index_pack_args.nr; j++)
 +                      strvec_pushf(&cmd.args, "--index-pack-arg=%s",
 +                                   index_pack_args.v[j]);
 +              strvec_push(&cmd.args, uri);
                cmd.git_cmd = 1;
                cmd.no_stdin = 1;
                cmd.out = -1;
  
                packname[the_hash_algo->hexsz] = '\0';
  
 +              parse_gitmodules_oids(cmd.out, &fsck_options.gitmodules_found);
 +
                close(cmd.out);
  
                if (finish_command(&cmd))
                                                 packname));
        }
        string_list_clear(&packfile_uris, 0);
 +      strvec_clear(&index_pack_args);
 +
 +      if (fsck_finish(&fsck_options))
 +              die("fsck failed");
  
        if (negotiator)
                negotiator->release(negotiator);
@@@ -1772,7 -1731,6 +1772,7 @@@ static void fetch_pack_config(void
        git_config_get_bool("repack.usedeltabaseoffset", &prefer_ofs_delta);
        git_config_get_bool("fetch.fsckobjects", &fetch_fsck_objects);
        git_config_get_bool("transfer.fsckobjects", &transfer_fsck_objects);
 +      git_config_get_bool("transfer.advertisesid", &advertise_sid);
        if (!uri_protocols.nr) {
                char *str;
  
@@@ -1905,7 -1863,7 +1905,7 @@@ static void update_shallow(struct fetch
         * remote is also shallow, check what ref is safe to update
         * without updating .git/shallow
         */
 -      status = xcalloc(nr_sought, sizeof(*status));
 +      CALLOC_ARRAY(status, nr_sought);
        assign_shallow_commits_to_refs(si, NULL, status);
        if (si->nr_ours || si->nr_theirs) {
                for (i = 0; i < nr_sought; i++)
@@@ -1944,6 -1902,20 +1944,6 @@@ struct ref *fetch_pack(struct fetch_pac
        if (nr_sought)
                nr_sought = remove_duplicates_in_refs(sought, nr_sought);
  
 -      if (args->no_dependents && !args->filter_options.choice) {
 -              /*
 -               * The protocol does not support requesting that only the
 -               * wanted objects be sent, so approximate this by setting a
 -               * "blob:none" filter if no filter is already set. This works
 -               * for all object types: note that wanted blobs will still be
 -               * sent because they are directly specified as a "want".
 -               *
 -               * NEEDSWORK: Add an option in the protocol to request that
 -               * only the wanted objects be sent, and implement it.
 -               */
 -              parse_list_objects_filter(&args->filter_options, "blob:none");
 -      }
 -
        if (version != protocol_v2 && !ref) {
                packet_flush(fd[1]);
                die(_("no matching remote head"));