]> git.ipfire.org Git - thirdparty/git.git/blobdiff - fetch-pack.c
Merge branch 'cm/rebase-i-updates'
[thirdparty/git.git] / fetch-pack.c
index 1eaedcb5dc2ed45e18e29bf185958a663f89eccb..fb04a76ca263042b145b40adf1577a81c6d7e12d 100644 (file)
@@ -790,14 +790,36 @@ static void create_promisor_file(const char *keep_name,
        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);
+}
+
 /*
- * Pass 1 as "only_packfile" if the pack received is the only pack in this
- * fetch request (that is, if there were no packfile URIs provided).
+ * 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;
@@ -805,6 +827,7 @@ static int get_pack(struct fetch_pack_args *args,
        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));
@@ -823,7 +846,7 @@ static int get_pack(struct fetch_pack_args *args,
        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"));
@@ -839,8 +862,15 @@ static int get_pack(struct fetch_pack_args *args,
                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";
                strvec_push(&cmd.args, cmd_name);
@@ -849,7 +879,7 @@ static int get_pack(struct fetch_pack_args *args,
                        strvec_push(&cmd.args, "-v");
                if (args->use_thin_pack)
                        strvec_push(&cmd.args, "--fix-thin");
-               if (do_keep && (args->lock_pack || unpack_limit)) {
+               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");
@@ -857,7 +887,7 @@ static int get_pack(struct fetch_pack_args *args,
                                     "--keep=fetch-pack %"PRIuMAX " on %s",
                                     (uintmax_t)getpid(), hostname);
                }
-               if (only_packfile && 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
                        /*
@@ -890,12 +920,8 @@ static int get_pack(struct fetch_pack_args *args,
                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 || !only_packfile)
+       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
@@ -907,14 +933,26 @@ static int get_pack(struct fetch_pack_args *args,
                                     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) {
-               char *pack_lockfile = 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);
        }
 
@@ -949,6 +987,22 @@ static int cmp_ref_by_name(const void *a_, const void *b_)
        return strcmp(a->name, b->name);
 }
 
+static void fsck_gitmodules_oids(struct oidset *gitmodules_oids)
+{
+       struct oidset_iter iter;
+       const struct object_id *oid;
+       struct fsck_options fo = FSCK_OPTIONS_STRICT;
+
+       if (!oidset_size(gitmodules_oids))
+               return;
+
+       oidset_iter_init(gitmodules_oids, &iter);
+       while ((oid = oidset_iter_next(&iter)))
+               register_found_gitmodules(oid);
+       if (fsck_finish(&fo))
+               die("fsck failed");
+}
+
 static struct ref *do_fetch_pack(struct fetch_pack_args *args,
                                 int fd[2],
                                 const struct ref *orig_ref,
@@ -963,6 +1017,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
        int agent_len;
        struct fetch_negotiator negotiator_alloc;
        struct fetch_negotiator *negotiator;
+       struct oidset gitmodules_oids = OIDSET_INIT;
 
        negotiator = &negotiator_alloc;
        fetch_negotiator_init(r, negotiator);
@@ -1078,8 +1133,10 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
                alternate_shallow_file = setup_temporary_shallow(si->shallow);
        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,
+                    &gitmodules_oids))
                die(_("git fetch-pack: fetch failed."));
+       fsck_gitmodules_oids(&gitmodules_oids);
 
  all_done:
        if (negotiator)
@@ -1529,6 +1586,8 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
        int seen_ack = 0;
        struct string_list packfile_uris = STRING_LIST_INIT_DUP;
        int i;
+       struct strvec index_pack_args = STRVEC_INIT;
+       struct oidset gitmodules_oids = OIDSET_INIT;
 
        negotiator = &negotiator_alloc;
        fetch_negotiator_init(r, negotiator);
@@ -1618,7 +1677,8 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
                                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, &gitmodules_oids))
                                die(_("git fetch-pack: fetch failed."));
                        do_check_stateless_delimiter(args, &reader);
 
@@ -1630,6 +1690,7 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
        }
 
        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 +
@@ -1639,6 +1700,9 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
                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;
@@ -1657,6 +1721,8 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
 
                packname[the_hash_algo->hexsz] = '\0';
 
+               parse_gitmodules_oids(cmd.out, &gitmodules_oids);
+
                close(cmd.out);
 
                if (finish_command(&cmd))
@@ -1674,6 +1740,9 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
                                                 packname));
        }
        string_list_clear(&packfile_uris, 0);
+       strvec_clear(&index_pack_args);
+
+       fsck_gitmodules_oids(&gitmodules_oids);
 
        if (negotiator)
                negotiator->release(negotiator);
@@ -1847,7 +1916,7 @@ 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));
+       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++)