Re-implement 'git remote update' using 'git fetch'
[gitweb.git] / builtin-remote.c
index 658d578588fed5d9f0c8a9c16808b6182c34f657..fb0d66d8c5ab94156326fe5eb9ef91acb4992c00 100644 (file)
@@ -227,32 +227,10 @@ struct ref_states {
        int queried;
 };
 
-static int handle_one_branch(const char *refname,
-       const unsigned char *sha1, int flags, void *cb_data)
-{
-       struct ref_states *states = cb_data;
-       struct refspec refspec;
-
-       memset(&refspec, 0, sizeof(refspec));
-       refspec.dst = (char *)refname;
-       if (!remote_find_tracking(states->remote, &refspec)) {
-               struct string_list_item *item;
-               const char *name = abbrev_branch(refspec.src);
-               /* symbolic refs pointing nowhere were handled already */
-               if ((flags & REF_ISSYMREF) ||
-                   string_list_has_string(&states->tracked, name) ||
-                   string_list_has_string(&states->new, name))
-                       return 0;
-               item = string_list_append(name, &states->stale);
-               item->util = xstrdup(refname);
-       }
-       return 0;
-}
-
 static int get_ref_states(const struct ref *remote_refs, struct ref_states *states)
 {
        struct ref *fetch_map = NULL, **tail = &fetch_map;
-       struct ref *ref;
+       struct ref *ref, *stale_refs;
        int i;
 
        for (i = 0; i < states->remote->fetch_refspec_nr; i++)
@@ -268,11 +246,17 @@ static int get_ref_states(const struct ref *remote_refs, struct ref_states *stat
                else
                        string_list_append(abbrev_branch(ref->name), &states->tracked);
        }
+       stale_refs = get_stale_heads(states->remote, fetch_map);
+       for (ref = stale_refs; ref; ref = ref->next) {
+               struct string_list_item *item =
+                       string_list_append(abbrev_branch(ref->name), &states->stale);
+               item->util = xstrdup(ref->name);
+       }
+       free_refs(stale_refs);
        free_refs(fetch_map);
 
        sort_string_list(&states->new);
        sort_string_list(&states->tracked);
-       for_each_ref(handle_one_branch, states);
        sort_string_list(&states->stale);
 
        return 0;
@@ -385,7 +369,7 @@ static int get_head_names(const struct ref *remote_refs, struct ref_states *stat
        get_fetch_map(remote_refs, &refspec, &fetch_map_tail, 0);
        matches = guess_remote_head(find_ref_by_name(remote_refs, "HEAD"),
                                    fetch_map, 1);
-       for(ref = matches; ref; ref = ref->next)
+       for (ref = matches; ref; ref = ref->next)
                string_list_append(abbrev_branch(ref->name), &states->heads);
 
        free_refs(fetch_map);
@@ -484,7 +468,7 @@ static int read_remote_branches(const char *refname,
        const char *symref;
 
        strbuf_addf(&buf, "refs/remotes/%s", rename->old);
-       if(!prefixcmp(refname, buf.buf)) {
+       if (!prefixcmp(refname, buf.buf)) {
                item = string_list_append(xstrdup(refname), rename->remote_branches);
                symref = resolve_ref(refname, orig_sha1, 1, &flag);
                if (flag & REF_ISSYMREF)
@@ -787,7 +771,7 @@ static int get_remote_ref_states(const char *name,
        read_branches();
 
        if (query) {
-               transport = transport_get(NULL, states->remote->url_nr > 0 ?
+               transport = transport_get(states->remote, states->remote->url_nr > 0 ?
                        states->remote->url[0] : NULL);
                remote_refs = transport_get_remote_refs(transport);
                transport_disconnect(transport);
@@ -1182,109 +1166,76 @@ static int prune_remote(const char *remote, int dry_run)
 
                printf(" * [%s] %s\n", dry_run ? "would prune" : "pruned",
                       abbrev_ref(refname, "refs/remotes/"));
-               warn_dangling_symref(dangling_msg, refname);
+               warn_dangling_symref(stdout, dangling_msg, refname);
        }
 
        free_remote_ref_states(&states);
        return result;
 }
 
-static int get_one_remote_for_update(struct remote *remote, void *priv)
-{
-       struct string_list *list = priv;
-       if (!remote->skip_default_update)
-               string_list_append(remote->name, list);
-       return 0;
-}
-
-static struct remote_group {
-       const char *name;
-       struct string_list *list;
-} remote_group;
-
-static int get_remote_group(const char *key, const char *value, void *num_hits)
+static int get_remote_default(const char *key, const char *value, void *priv)
 {
-       if (!prefixcmp(key, "remotes.") &&
-                       !strcmp(key + 8, remote_group.name)) {
-               /* split list by white space */
-               int space = strcspn(value, " \t\n");
-               while (*value) {
-                       if (space > 1) {
-                               string_list_append(xstrndup(value, space),
-                                               remote_group.list);
-                               ++*((int *)num_hits);
-                       }
-                       value += space + (value[space] != '\0');
-                       space = strcspn(value, " \t\n");
-               }
+       if (strcmp(key, "remotes.default") == 0) {
+               int *found = priv;
+               *found = 1;
        }
-
        return 0;
 }
 
 static int update(int argc, const char **argv)
 {
-       int i, result = 0, prune = 0;
-       struct string_list list = { NULL, 0, 0, 0 };
-       static const char *default_argv[] = { NULL, "default", NULL };
+       int i, prune = 0;
        struct option options[] = {
                OPT_GROUP("update specific options"),
                OPT_BOOLEAN('p', "prune", &prune,
                            "prune remotes after fetching"),
                OPT_END()
        };
+       const char **fetch_argv;
+       int fetch_argc = 0;
+       int default_defined = 0;
+
+       fetch_argv = xmalloc(sizeof(char *) * (argc+5));
 
        argc = parse_options(argc, argv, NULL, options, builtin_remote_usage,
                             PARSE_OPT_KEEP_ARGV0);
-       if (argc < 2) {
-               argc = 2;
-               argv = default_argv;
-       }
 
-       remote_group.list = &list;
-       for (i = 1; i < argc; i++) {
-               int groups_found = 0;
-               remote_group.name = argv[i];
-               result = git_config(get_remote_group, &groups_found);
-               if (!groups_found && (i != 1 || strcmp(argv[1], "default"))) {
-                       struct remote *remote;
-                       if (!remote_is_configured(argv[i]))
-                               die("No such remote or remote group: %s",
-                                   argv[i]);
-                       remote = remote_get(argv[i]);
-                       string_list_append(remote->name, remote_group.list);
-               }
-       }
+       fetch_argv[fetch_argc++] = "fetch";
 
-       if (!result && !list.nr  && argc == 2 && !strcmp(argv[1], "default"))
-               result = for_each_remote(get_one_remote_for_update, &list);
+       if (prune)
+               fetch_argv[fetch_argc++] = "--prune";
+       if (verbose)
+               fetch_argv[fetch_argc++] = "-v";
+       if (argc < 2) {
+               fetch_argv[fetch_argc++] = "default";
+       } else {
+               fetch_argv[fetch_argc++] = "--multiple";
+               for (i = 1; i < argc; i++)
+                       fetch_argv[fetch_argc++] = argv[i];
+       }
 
-       for (i = 0; i < list.nr; i++) {
-               int err = fetch_remote(list.items[i].string);
-               result |= err;
-               if (!err && prune)
-                       result |= prune_remote(list.items[i].string, 0);
+       if (strcmp(fetch_argv[fetch_argc-1], "default") == 0) {
+               git_config(get_remote_default, &default_defined);
+               if (!default_defined)
+                       fetch_argv[fetch_argc-1] = "--all";
        }
 
-       /* all names were strdup()ed or strndup()ed */
-       list.strdup_strings = 1;
-       string_list_clear(&list, 0);
+       fetch_argv[fetch_argc] = NULL;
 
-       return result;
+       return run_command_v_opt(fetch_argv, RUN_GIT_CMD);
 }
 
 static int get_one_entry(struct remote *remote, void *priv)
 {
        struct string_list *list = priv;
+       struct strbuf url_buf = STRBUF_INIT;
        const char **url;
        int i, url_nr;
-       void **utilp;
 
        if (remote->url_nr > 0) {
-               utilp = &(string_list_append(remote->name, list)->util);
-               *utilp = xmalloc(strlen(remote->url[0])+strlen(" (fetch)")+1);
-               strcpy((char *) *utilp, remote->url[0]);
-               strcat((char *) *utilp, " (fetch)");
+               strbuf_addf(&url_buf, "%s (fetch)", remote->url[0]);
+               string_list_append(remote->name, list)->util =
+                               strbuf_detach(&url_buf, NULL);
        } else
                string_list_append(remote->name, list)->util = NULL;
        if (remote->pushurl_nr) {
@@ -1296,10 +1247,9 @@ static int get_one_entry(struct remote *remote, void *priv)
        }
        for (i = 0; i < url_nr; i++)
        {
-               utilp = &(string_list_append(remote->name, list)->util);
-               *utilp = xmalloc(strlen(url[i])+strlen(" (push)")+1);
-               strcpy((char *) *utilp, url[i]);
-               strcat((char *) *utilp, " (push)");
+               strbuf_addf(&url_buf, "%s (push)", url[i]);
+               string_list_append(remote->name, list)->util =
+                               strbuf_detach(&url_buf, NULL);
        }
 
        return 0;