]> git.ipfire.org Git - thirdparty/git.git/blobdiff - fetch-pack.c
submodules: fix of regression on fetching of non-init subsub-repo
[thirdparty/git.git] / fetch-pack.c
index 7f20eca4f81ce401f951361ce59e1be6aa31cd67..b10c4323155b77f2ef271564cef862147a880596 100644 (file)
@@ -108,24 +108,48 @@ static void for_each_cached_alternate(struct fetch_negotiator *negotiator,
                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 {
@@ -201,7 +225,7 @@ static void send_request(struct fetch_pack_args *args,
 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
@@ -230,13 +254,12 @@ static void mark_tips(struct fetch_negotiator *negotiator,
        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;
 }
 
@@ -262,10 +285,8 @@ static int find_common(struct fetch_negotiator *negotiator,
                           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) {
@@ -282,12 +303,8 @@ static int find_common(struct fetch_negotiator *negotiator,
                 * 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;
                }
@@ -387,8 +404,6 @@ static int find_common(struct fetch_negotiator *negotiator,
        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));
@@ -503,21 +518,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;
 }
@@ -653,9 +658,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
@@ -702,7 +705,7 @@ static void mark_complete_and_common_ref(struct fetch_negotiator *negotiator,
         */
        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)
@@ -716,16 +719,12 @@ static void mark_complete_and_common_ref(struct fetch_negotiator *negotiator,
         */
        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);
 
@@ -794,6 +793,10 @@ static void write_promisor_file(const char *keep_name,
        strbuf_release(&promisor_name);
 }
 
+/*
+ * 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).
+ */
 static int get_pack(struct fetch_pack_args *args,
                    int xd[2], struct string_list *pack_lockfiles,
                    int only_packfile,
@@ -866,13 +869,16 @@ static int get_pack(struct fetch_pack_args *args,
                         * 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)
+
+               if (args->from_promisor)
+                       /*
+                        * write_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 {
@@ -892,7 +898,7 @@ static int get_pack(struct fetch_pack_args *args,
            : transfer_fsck_objects >= 0
            ? transfer_fsck_objects
            : 0) {
-               if (args->from_promisor)
+               if (args->from_promisor || !only_packfile)
                        /*
                         * We cannot use --strict in index-pack because it
                         * checks both broken objects and links, but we only
@@ -960,12 +966,8 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
        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);
@@ -1053,15 +1055,11 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
        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)
@@ -1110,7 +1108,7 @@ static void add_shallow_requests(struct strbuf *req_buf,
                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);
 
@@ -1127,12 +1125,8 @@ static void add_wants(int no_dependents, const struct ref *wants, struct strbuf
                 * 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;
                }
@@ -1266,19 +1260,14 @@ static int send_fetch_request(struct fetch_negotiator *negotiator, int fd_out,
        }
 
        /* 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);
@@ -1538,12 +1527,8 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
        struct string_list packfile_uris = STRING_LIST_INIT_DUP;
        int i;
 
-       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 |
@@ -1567,21 +1552,16 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
                                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) {
@@ -1902,20 +1882,6 @@ struct ref *fetch_pack(struct fetch_pack_args *args,
        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"));