Merge branch 'bw/protocol-v2' into HEAD
[gitweb.git] / builtin / fetch.c
index a39e9d7b1579fd6adb8d421ac8984bc0592b5eda..7ee83ac0f8170d9e68c374a21caebfe01cf64533 100644 (file)
@@ -39,6 +39,10 @@ static int fetch_prune_config = -1; /* unspecified */
 static int prune = -1; /* unspecified */
 #define PRUNE_BY_DEFAULT 0 /* do we prune by default? */
 
+static int fetch_prune_tags_config = -1; /* unspecified */
+static int prune_tags = -1; /* unspecified */
+#define PRUNE_TAGS_BY_DEFAULT 0 /* do we prune tags by default? */
+
 static int all, append, dry_run, force, keep, multiple, update_head_ok, verbosity, deepen_relative;
 static int progress = -1;
 static int tags = TAGS_DEFAULT, unshallow, update_shallow, deepen;
@@ -66,6 +70,11 @@ static int git_fetch_config(const char *k, const char *v, void *cb)
                return 0;
        }
 
+       if (!strcmp(k, "fetch.prunetags")) {
+               fetch_prune_tags_config = git_config_bool(k, v);
+               return 0;
+       }
+
        if (!strcmp(k, "submodule.recurse")) {
                int r = git_config_bool(k, v) ?
                        RECURSE_SUBMODULES_ON : RECURSE_SUBMODULES_OFF;
@@ -117,7 +126,7 @@ static struct option builtin_fetch_options[] = {
                 N_("append to .git/FETCH_HEAD instead of overwriting")),
        OPT_STRING(0, "upload-pack", &upload_pack, N_("path"),
                   N_("path to upload pack on remote end")),
-       OPT__FORCE(&force, N_("force overwrite of local branch")),
+       OPT__FORCE(&force, N_("force overwrite of local branch"), 0),
        OPT_BOOL('m', "multiple", &multiple,
                 N_("fetch from multiple remotes")),
        OPT_SET_INT('t', "tags", &tags,
@@ -128,6 +137,8 @@ static struct option builtin_fetch_options[] = {
                    N_("number of submodules fetched in parallel")),
        OPT_BOOL('p', "prune", &prune,
                 N_("prune remote-tracking branches no longer on remote")),
+       OPT_BOOL('P', "prune-tags", &prune_tags,
+                N_("prune local tags no longer on remote and clobber changed tags")),
        { OPTION_CALLBACK, 0, "recurse-submodules", &recurse_submodules, N_("on-demand"),
                    N_("control recursive fetching of submodules"),
                    PARSE_OPT_OPTARG, option_fetch_parse_recurse_submodules },
@@ -253,7 +264,7 @@ static void find_non_local_tags(struct transport *transport,
        struct string_list_item *item = NULL;
 
        for_each_ref(add_existing, &existing_refs);
-       for (ref = transport_get_remote_refs(transport); ref; ref = ref->next) {
+       for (ref = transport_get_remote_refs(transport, NULL); ref; ref = ref->next) {
                if (!starts_with(ref->name, "refs/tags/"))
                        continue;
 
@@ -335,11 +346,28 @@ static struct ref *get_ref_map(struct transport *transport,
        struct ref *rm;
        struct ref *ref_map = NULL;
        struct ref **tail = &ref_map;
+       struct argv_array ref_prefixes = ARGV_ARRAY_INIT;
 
        /* opportunistically-updated references: */
        struct ref *orefs = NULL, **oref_tail = &orefs;
 
-       const struct ref *remote_refs = transport_get_remote_refs(transport);
+       const struct ref *remote_refs;
+
+       for (i = 0; i < refspec_count; i++) {
+               if (!refspecs[i].exact_sha1) {
+                       const char *glob = strchr(refspecs[i].src, '*');
+                       if (glob)
+                               argv_array_pushf(&ref_prefixes, "%.*s",
+                                                (int)(glob - refspecs[i].src),
+                                                refspecs[i].src);
+                       else
+                               expand_ref_prefix(&ref_prefixes, refspecs[i].src);
+               }
+       }
+
+       remote_refs = transport_get_remote_refs(transport, &ref_prefixes);
+
+       argv_array_clear(&ref_prefixes);
 
        if (refspec_count) {
                struct refspec *fetch_refspec;
@@ -626,7 +654,7 @@ static int update_local_ref(struct ref *ref,
        struct branch *current_branch = branch_get(NULL);
        const char *pretty_ref = prettify_refname(ref->name);
 
-       type = sha1_object_info(ref->new_oid.hash, NULL);
+       type = oid_object_info(&ref->new_oid, NULL);
        if (type < 0)
                die(_("object %s not found"), oid_to_hex(&ref->new_oid));
 
@@ -697,9 +725,9 @@ static int update_local_ref(struct ref *ref,
        if (in_merge_bases(current, updated)) {
                struct strbuf quickref = STRBUF_INIT;
                int r;
-               strbuf_add_unique_abbrev(&quickref, current->object.oid.hash, DEFAULT_ABBREV);
+               strbuf_add_unique_abbrev(&quickref, &current->object.oid, DEFAULT_ABBREV);
                strbuf_addstr(&quickref, "..");
-               strbuf_add_unique_abbrev(&quickref, ref->new_oid.hash, DEFAULT_ABBREV);
+               strbuf_add_unique_abbrev(&quickref, &ref->new_oid, DEFAULT_ABBREV);
                if ((recurse_submodules != RECURSE_SUBMODULES_OFF) &&
                    (recurse_submodules != RECURSE_SUBMODULES_ON))
                        check_for_new_submodule_commits(&ref->new_oid);
@@ -712,9 +740,9 @@ static int update_local_ref(struct ref *ref,
        } else if (force || ref->force) {
                struct strbuf quickref = STRBUF_INIT;
                int r;
-               strbuf_add_unique_abbrev(&quickref, current->object.oid.hash, DEFAULT_ABBREV);
+               strbuf_add_unique_abbrev(&quickref, &current->object.oid, DEFAULT_ABBREV);
                strbuf_addstr(&quickref, "...");
-               strbuf_add_unique_abbrev(&quickref, ref->new_oid.hash, DEFAULT_ABBREV);
+               strbuf_add_unique_abbrev(&quickref, &ref->new_oid, DEFAULT_ABBREV);
                if ((recurse_submodules != RECURSE_SUBMODULES_OFF) &&
                    (recurse_submodules != RECURSE_SUBMODULES_ON))
                        check_for_new_submodule_commits(&ref->new_oid);
@@ -1220,6 +1248,8 @@ static void add_options_to_argv(struct argv_array *argv)
                argv_array_push(argv, "--dry-run");
        if (prune != -1)
                argv_array_push(argv, prune ? "--prune" : "--no-prune");
+       if (prune_tags != -1)
+               argv_array_push(argv, prune_tags ? "--prune-tags" : "--no-prune-tags");
        if (update_head_ok)
                argv_array_push(argv, "--update-head-ok");
        if (force)
@@ -1323,12 +1353,15 @@ static inline void fetch_one_setup_partial(struct remote *remote)
        return;
 }
 
-static int fetch_one(struct remote *remote, int argc, const char **argv)
+static int fetch_one(struct remote *remote, int argc, const char **argv, int prune_tags_ok)
 {
        static const char **refs = NULL;
        struct refspec *refspec;
        int ref_nr = 0;
+       int j = 0;
        int exit_code;
+       int maybe_prune_tags;
+       int remote_via_config = remote_is_configured(remote, 0);
 
        if (!remote)
                die(_("No remote repository specified.  Please, specify either a URL or a\n"
@@ -1338,18 +1371,39 @@ static int fetch_one(struct remote *remote, int argc, const char **argv)
 
        if (prune < 0) {
                /* no command line request */
-               if (0 <= gtransport->remote->prune)
-                       prune = gtransport->remote->prune;
+               if (0 <= remote->prune)
+                       prune = remote->prune;
                else if (0 <= fetch_prune_config)
                        prune = fetch_prune_config;
                else
                        prune = PRUNE_BY_DEFAULT;
        }
 
+       if (prune_tags < 0) {
+               /* no command line request */
+               if (0 <= remote->prune_tags)
+                       prune_tags = remote->prune_tags;
+               else if (0 <= fetch_prune_tags_config)
+                       prune_tags = fetch_prune_tags_config;
+               else
+                       prune_tags = PRUNE_TAGS_BY_DEFAULT;
+       }
+
+       maybe_prune_tags = prune_tags_ok && prune_tags;
+       if (maybe_prune_tags && remote_via_config)
+               add_prune_tags_to_fetch_refspec(remote);
+
+       if (argc > 0 || (maybe_prune_tags && !remote_via_config)) {
+               size_t nr_alloc = st_add3(argc, maybe_prune_tags, 1);
+               refs = xcalloc(nr_alloc, sizeof(const char *));
+               if (maybe_prune_tags) {
+                       refs[j++] = xstrdup("refs/tags/*:refs/tags/*");
+                       ref_nr++;
+               }
+       }
+
        if (argc > 0) {
-               int j = 0;
                int i;
-               refs = xcalloc(st_add(argc, 1), sizeof(const char *));
                for (i = 0; i < argc; i++) {
                        if (!strcmp(argv[i], "tag")) {
                                i++;
@@ -1359,9 +1413,8 @@ static int fetch_one(struct remote *remote, int argc, const char **argv)
                                                    argv[i], argv[i]);
                        } else
                                refs[j++] = argv[i];
+                       ref_nr++;
                }
-               refs[j] = NULL;
-               ref_nr = j;
        }
 
        sigchain_push_common(unlock_pack_on_signal);
@@ -1380,6 +1433,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
        struct string_list list = STRING_LIST_INIT_DUP;
        struct remote *remote = NULL;
        int result = 0;
+       int prune_tags_ok = 1;
        struct argv_array argv_gc_auto = ARGV_ARRAY_INIT;
 
        packet_trace_identity("fetch");
@@ -1446,6 +1500,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
                } else {
                        /* Zero or one remotes */
                        remote = remote_get(argv[0]);
+                       prune_tags_ok = (argc == 1);
                        argc--;
                        argv++;
                }
@@ -1454,7 +1509,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
        if (remote) {
                if (filter_options.choice || repository_format_partial_clone)
                        fetch_one_setup_partial(remote);
-               result = fetch_one(remote, argc, argv);
+               result = fetch_one(remote, argc, argv, prune_tags_ok);
        } else {
                if (filter_options.choice)
                        die(_("--filter can only be used with the remote configured in core.partialClone"));