builtin-fetch: add --prune option
[gitweb.git] / builtin-fetch.c
index e6bbdc7a171dd050dd8fc94def946931244e87b6..81974ea363c445700c856c10d565779c944282ce 100644 (file)
@@ -15,6 +15,7 @@
 static const char * const builtin_fetch_usage[] = {
        "git fetch [options] [<repository> <refspec>...]",
        "git fetch [options] <group>",
+       "git fetch --multiple [options] [<repository> | <group>]...",
        "git fetch --all [options]",
        NULL
 };
@@ -25,7 +26,7 @@ enum {
        TAGS_SET = 2
 };
 
-static int all, append, force, keep, update_head_ok, verbosity;
+static int all, append, force, keep, multiple, prune, update_head_ok, verbosity;
 static int tags = TAGS_DEFAULT;
 static const char *depth;
 static const char *upload_pack;
@@ -42,10 +43,14 @@ static struct option builtin_fetch_options[] = {
                   "path to upload pack on remote end"),
        OPT_BOOLEAN('f', "force", &force,
                    "force overwrite of local branch"),
+       OPT_BOOLEAN('m', "multiple", &multiple,
+                   "fetch from multiple remotes"),
        OPT_SET_INT('t', "tags", &tags,
                    "fetch all tags and associated objects", TAGS_SET),
        OPT_SET_INT('n', NULL, &tags,
                    "do not fetch all tags (--no-tags)", TAGS_UNSET),
+       OPT_BOOLEAN('p', "prune", &prune,
+                   "prune tracking branches no longer on remote"),
        OPT_BOOLEAN('k', "keep", &keep, "keep downloaded pack"),
        OPT_BOOLEAN('u', "update-head-ok", &update_head_ok,
                    "allow updating of HEAD ref"),
@@ -489,6 +494,28 @@ static int fetch_refs(struct transport *transport, struct ref *ref_map)
        return ret;
 }
 
+static int prune_refs(struct transport *transport, struct ref *ref_map)
+{
+       int result = 0;
+       struct ref *ref, *stale_refs = get_stale_heads(transport->remote, ref_map);
+       const char *dangling_msg = dry_run
+               ? "   (%s will become dangling)\n"
+               : "   (%s has become dangling)\n";
+
+       for (ref = stale_refs; ref; ref = ref->next) {
+               if (!dry_run)
+                       result |= delete_ref(ref->name, NULL, 0);
+               if (verbosity >= 0) {
+                       fprintf(stderr, " x %-*s %-*s -> %s\n",
+                               SUMMARY_WIDTH, "[deleted]",
+                               REFCOL_WIDTH, "(none)", prettify_refname(ref->name));
+                       warn_dangling_symref(stderr, dangling_msg, ref->name);
+               }
+       }
+       free_refs(stale_refs);
+       return result;
+}
+
 static int add_existing(const char *refname, const unsigned char *sha1,
                        int flag, void *cbdata)
 {
@@ -613,6 +640,8 @@ static int do_fetch(struct transport *transport,
                free_refs(ref_map);
                return 1;
        }
+       if (prune)
+               prune_refs(transport, ref_map);
        free_refs(ref_map);
 
        /* if neither --no-tags nor --tags was specified, do automated tag
@@ -646,7 +675,8 @@ static void set_option(const char *name, const char *value)
 static int get_one_remote_for_fetch(struct remote *remote, void *priv)
 {
        struct string_list *list = priv;
-       string_list_append(remote->name, list);
+       if (!remote->skip_default_update)
+               string_list_append(remote->name, list);
        return 0;
 }
 
@@ -695,9 +725,11 @@ static int add_remote_or_group(const char *name, struct string_list *list)
 static int fetch_multiple(struct string_list *list)
 {
        int i, result = 0;
-       const char *argv[] = { "fetch", NULL, NULL, NULL, NULL };
+       const char *argv[] = { "fetch", NULL, NULL, NULL, NULL, NULL };
        int argc = 1;
 
+       if (prune)
+               argv[argc++] = "--prune";
        if (verbosity >= 2)
                argv[argc++] = "-v";
        if (verbosity >= 1)
@@ -798,6 +830,12 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
                /* No arguments -- use default remote */
                remote = remote_get(NULL);
                result = fetch_one(remote, argc, argv);
+       } else if (multiple) {
+               /* All arguments are assumed to be remotes or groups */
+               for (i = 0; i < argc; i++)
+                       if (!add_remote_or_group(argv[i], &list))
+                               die("No such remote or remote group: %s", argv[i]);
+               result = fetch_multiple(&list);
        } else {
                /* Single remote or group */
                (void) add_remote_or_group(argv[0], &list);