attr: remove an implicit dependency on the_index
[gitweb.git] / builtin / fetch.c
index bda00e82628b94eedc2a32c91ab49686c3a21879..34d2bd123b3303a096edb99ab4f82c52a89b35f5 100644 (file)
@@ -6,6 +6,7 @@
 #include "repository.h"
 #include "refs.h"
 #include "refspec.h"
+#include "object-store.h"
 #include "commit.h"
 #include "builtin.h"
 #include "string-list.h"
@@ -63,6 +64,7 @@ static int shown_url = 0;
 static struct refspec refmap = REFSPEC_INIT_FETCH;
 static struct list_objects_filter_options filter_options;
 static struct string_list server_options = STRING_LIST_INIT_DUP;
+static struct string_list negotiation_tip = STRING_LIST_INIT_NODUP;
 
 static int git_fetch_config(const char *k, const char *v, void *cb)
 {
@@ -93,19 +95,6 @@ static int git_fetch_config(const char *k, const char *v, void *cb)
        return git_default_config(k, v, cb);
 }
 
-static int gitmodules_fetch_config(const char *var, const char *value, void *cb)
-{
-       if (!strcmp(var, "submodule.fetchjobs")) {
-               max_children = parse_submodule_fetchjobs(var, value);
-               return 0;
-       } else if (!strcmp(var, "fetch.recursesubmodules")) {
-               recurse_submodules = parse_fetch_recurse_submodules_arg(var, value);
-               return 0;
-       }
-
-       return 0;
-}
-
 static int parse_refmap_arg(const struct option *opt, const char *arg, int unset)
 {
        /*
@@ -174,6 +163,8 @@ static struct option builtin_fetch_options[] = {
                        TRANSPORT_FAMILY_IPV4),
        OPT_SET_INT('6', "ipv6", &family, N_("use IPv6 addresses only"),
                        TRANSPORT_FAMILY_IPV6),
+       OPT_STRING_LIST(0, "negotiation-tip", &negotiation_tip, N_("revision"),
+                       N_("report that we have only objects reachable from this object")),
        OPT_PARSE_LIST_OBJECTS_FILTER(&filter_options),
        OPT_END()
 };
@@ -684,8 +675,10 @@ static int update_local_ref(struct ref *ref,
                return r;
        }
 
-       current = lookup_commit_reference_gently(&ref->old_oid, 1);
-       updated = lookup_commit_reference_gently(&ref->new_oid, 1);
+       current = lookup_commit_reference_gently(the_repository,
+                                                &ref->old_oid, 1);
+       updated = lookup_commit_reference_gently(the_repository,
+                                                &ref->new_oid, 1);
        if (!current || !updated) {
                const char *msg;
                const char *what;
@@ -769,7 +762,7 @@ static int iterate_ref_map(void *cb_data, struct object_id *oid)
 }
 
 static int store_updated_refs(const char *raw_url, const char *remote_name,
-               struct ref *ref_map)
+                             int connectivity_checked, struct ref *ref_map)
 {
        FILE *fp;
        struct commit *commit;
@@ -778,7 +771,7 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
        const char *what, *kind;
        struct ref *rm;
        char *url;
-       const char *filename = dry_run ? "/dev/null" : git_path_fetch_head();
+       const char *filename = dry_run ? "/dev/null" : git_path_fetch_head(the_repository);
        int want_status;
        int summary_width = transport_summary_width(ref_map);
 
@@ -791,10 +784,12 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
        else
                url = xstrdup("foreign");
 
-       rm = ref_map;
-       if (check_connected(iterate_ref_map, &rm, NULL)) {
-               rc = error(_("%s did not send all necessary objects\n"), url);
-               goto abort;
+       if (!connectivity_checked) {
+               rm = ref_map;
+               if (check_connected(iterate_ref_map, &rm, NULL)) {
+                       rc = error(_("%s did not send all necessary objects\n"), url);
+                       goto abort;
+               }
        }
 
        prepare_format_display(ref_map);
@@ -818,7 +813,8 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
                                continue;
                        }
 
-                       commit = lookup_commit_reference_gently(&rm->old_oid,
+                       commit = lookup_commit_reference_gently(the_repository,
+                                                               &rm->old_oid,
                                                                1);
                        if (!commit)
                                rm->fetch_head_status = FETCH_HEAD_NOT_FOR_MERGE;
@@ -946,11 +942,13 @@ static int quickfetch(struct ref *ref_map)
        return check_connected(iterate_ref_map, &rm, &opt);
 }
 
-static int fetch_refs(struct transport *transport, struct ref *ref_map)
+static int fetch_refs(struct transport *transport, struct ref *ref_map,
+                     struct ref **updated_remote_refs)
 {
        int ret = quickfetch(ref_map);
        if (ret)
-               ret = transport_fetch_refs(transport, ref_map);
+               ret = transport_fetch_refs(transport, ref_map,
+                                          updated_remote_refs);
        if (!ret)
                /*
                 * Keep the new pack's ".keep" file around to allow the caller
@@ -964,8 +962,11 @@ static int fetch_refs(struct transport *transport, struct ref *ref_map)
 /* Update local refs based on the ref values fetched from a remote */
 static int consume_refs(struct transport *transport, struct ref *ref_map)
 {
+       int connectivity_checked = transport->smart_options
+               ? transport->smart_options->connectivity_checked : 0;
        int ret = store_updated_refs(transport->url,
                                     transport->remote->name,
+                                    connectivity_checked,
                                     ref_map);
        transport_unlock_pack(transport);
        return ret;
@@ -1042,7 +1043,7 @@ static void check_not_current_branch(struct ref *ref_map)
 
 static int truncate_fetch_head(void)
 {
-       const char *filename = git_path_fetch_head();
+       const char *filename = git_path_fetch_head(the_repository);
        FILE *fp = fopen_for_writing(filename);
 
        if (!fp)
@@ -1062,6 +1063,40 @@ static void set_option(struct transport *transport, const char *name, const char
                        name, transport->url);
 }
 
+
+static int add_oid(const char *refname, const struct object_id *oid, int flags,
+                  void *cb_data)
+{
+       struct oid_array *oids = cb_data;
+
+       oid_array_append(oids, oid);
+       return 0;
+}
+
+static void add_negotiation_tips(struct git_transport_options *smart_options)
+{
+       struct oid_array *oids = xcalloc(1, sizeof(*oids));
+       int i;
+
+       for (i = 0; i < negotiation_tip.nr; i++) {
+               const char *s = negotiation_tip.items[i].string;
+               int old_nr;
+               if (!has_glob_specials(s)) {
+                       struct object_id oid;
+                       if (get_oid(s, &oid))
+                               die("%s is not a valid object", s);
+                       oid_array_append(oids, &oid);
+                       continue;
+               }
+               old_nr = oids->nr;
+               for_each_glob_ref(add_oid, s, oids);
+               if (old_nr == oids->nr)
+                       warning("Ignoring --negotiation-tip=%s because it does not match any refs",
+                               s);
+       }
+       smart_options->negotiation_tips = oids;
+}
+
 static struct transport *prepare_transport(struct remote *remote, int deepen)
 {
        struct transport *transport;
@@ -1088,6 +1123,12 @@ static struct transport *prepare_transport(struct remote *remote, int deepen)
                           filter_options.filter_spec);
                set_option(transport, TRANS_OPT_FROM_PROMISOR, "1");
        }
+       if (negotiation_tip.nr) {
+               if (transport->smart_options)
+                       add_negotiation_tips(transport->smart_options);
+               else
+                       warning("Ignoring --negotiation-tip because the protocol does not support it.");
+       }
        return transport;
 }
 
@@ -1112,7 +1153,7 @@ static void backfill_tags(struct transport *transport, struct ref *ref_map)
        transport_set_option(transport, TRANS_OPT_FOLLOWTAGS, NULL);
        transport_set_option(transport, TRANS_OPT_DEPTH, "0");
        transport_set_option(transport, TRANS_OPT_DEEPEN_RELATIVE, NULL);
-       if (!fetch_refs(transport, ref_map))
+       if (!fetch_refs(transport, ref_map, NULL))
                consume_refs(transport, ref_map);
 
        if (gsecondary) {
@@ -1128,6 +1169,7 @@ static int do_fetch(struct transport *transport,
        int autotags = (transport->remote->fetch_tags == 1);
        int retcode = 0;
        const struct ref *remote_refs;
+       struct ref *updated_remote_refs = NULL;
        struct argv_array ref_prefixes = ARGV_ARRAY_INIT;
 
        if (tags == TAGS_DEFAULT) {
@@ -1178,7 +1220,24 @@ static int do_fetch(struct transport *transport,
                                   transport->url);
                }
        }
-       if (fetch_refs(transport, ref_map) || consume_refs(transport, ref_map)) {
+
+       if (fetch_refs(transport, ref_map, &updated_remote_refs)) {
+               free_refs(ref_map);
+               retcode = 1;
+               goto cleanup;
+       }
+       if (updated_remote_refs) {
+               /*
+                * Regenerate ref_map using the updated remote refs.  This is
+                * to account for additional information which may be provided
+                * by the transport (e.g. shallow info).
+                */
+               free_refs(ref_map);
+               ref_map = get_ref_map(transport->remote, updated_remote_refs, rs,
+                                     tags, &autotags);
+               free_refs(updated_remote_refs);
+       }
+       if (consume_refs(transport, ref_map)) {
                free_refs(ref_map);
                retcode = 1;
                goto cleanup;
@@ -1446,7 +1505,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
        for (i = 1; i < argc; i++)
                strbuf_addf(&default_rla, " %s", argv[i]);
 
-       config_from_gitmodules(gitmodules_fetch_config, NULL);
+       fetch_config_from_gitmodules(&max_children, &recurse_submodules);
        git_config(git_fetch_config, NULL);
 
        argc = parse_options(argc, argv, prefix,
@@ -1462,7 +1521,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
        if (unshallow) {
                if (depth)
                        die(_("--depth and --unshallow cannot be used together"));
-               else if (!is_repository_shallow())
+               else if (!is_repository_shallow(the_repository))
                        die(_("--unshallow on a complete repository does not make sense"));
                else
                        depth = xstrfmt("%d", INFINITE_DEPTH);