builtin/remote.c: rearrange xcalloc arguments
[gitweb.git] / remote.c
index fde7b52f9340fd5c2517f0f48532bb0f1f169ac8..eea2c8de45052e3e3a59fb150eef3f54c6086800 100644 (file)
--- a/remote.c
+++ b/remote.c
@@ -49,6 +49,7 @@ static int branches_nr;
 
 static struct branch *current_branch;
 static const char *default_remote_name;
+static const char *branch_pushremote_name;
 static const char *pushremote_name;
 static int explicit_default_remote_name;
 
@@ -76,7 +77,7 @@ static const char *alias_url(const char *url, struct rewrites *r)
                if (!r->rewrite[i])
                        continue;
                for (j = 0; j < r->rewrite[i]->instead_of_nr; j++) {
-                       if (!prefixcmp(url, r->rewrite[i]->instead_of[j].s) &&
+                       if (starts_with(url, r->rewrite[i]->instead_of[j].s) &&
                            (!longest ||
                             longest->len < r->rewrite[i]->instead_of[j].len)) {
                                longest = &(r->rewrite[i]->instead_of[j]);
@@ -239,13 +240,13 @@ static void read_remotes_file(struct remote *remote)
                int value_list;
                char *s, *p;
 
-               if (!prefixcmp(buffer, "URL:")) {
+               if (starts_with(buffer, "URL:")) {
                        value_list = 0;
                        s = buffer + 4;
-               } else if (!prefixcmp(buffer, "Push:")) {
+               } else if (starts_with(buffer, "Push:")) {
                        value_list = 1;
                        s = buffer + 5;
-               } else if (!prefixcmp(buffer, "Pull:")) {
+               } else if (starts_with(buffer, "Pull:")) {
                        value_list = 2;
                        s = buffer + 5;
                } else
@@ -337,7 +338,7 @@ static int handle_config(const char *key, const char *value, void *cb)
        const char *subkey;
        struct remote *remote;
        struct branch *branch;
-       if (!prefixcmp(key, "branch.")) {
+       if (starts_with(key, "branch.")) {
                name = key + 7;
                subkey = strrchr(name, '.');
                if (!subkey)
@@ -352,7 +353,7 @@ static int handle_config(const char *key, const char *value, void *cb)
                        }
                } else if (!strcmp(subkey, ".pushremote")) {
                        if (branch == current_branch)
-                               if (git_config_string(&pushremote_name, key, value))
+                               if (git_config_string(&branch_pushremote_name, key, value))
                                        return -1;
                } else if (!strcmp(subkey, ".merge")) {
                        if (!value)
@@ -361,7 +362,7 @@ static int handle_config(const char *key, const char *value, void *cb)
                }
                return 0;
        }
-       if (!prefixcmp(key, "url.")) {
+       if (starts_with(key, "url.")) {
                struct rewrite *rewrite;
                name = key + 4;
                subkey = strrchr(name, '.');
@@ -380,7 +381,7 @@ static int handle_config(const char *key, const char *value, void *cb)
                }
        }
 
-       if (prefixcmp(key,  "remote."))
+       if (!starts_with(key,  "remote."))
                return 0;
        name = key + 7;
 
@@ -487,11 +488,15 @@ static void read_config(void)
        current_branch = NULL;
        head_ref = resolve_ref_unsafe("HEAD", sha1, 0, &flag);
        if (head_ref && (flag & REF_ISSYMREF) &&
-           !prefixcmp(head_ref, "refs/heads/")) {
+           starts_with(head_ref, "refs/heads/")) {
                current_branch =
                        make_branch(head_ref + strlen("refs/heads/"), 0);
        }
        git_config(handle_config, NULL);
+       if (branch_pushremote_name) {
+               free((char *)pushremote_name);
+               pushremote_name = branch_pushremote_name;
+       }
        alias_all_urls();
 }
 
@@ -745,35 +750,66 @@ int for_each_remote(each_remote_fn fn, void *priv)
        return result;
 }
 
-void ref_remove_duplicates(struct ref *ref_map)
+static void handle_duplicate(struct ref *ref1, struct ref *ref2)
+{
+       if (strcmp(ref1->name, ref2->name)) {
+               if (ref1->fetch_head_status != FETCH_HEAD_IGNORE &&
+                   ref2->fetch_head_status != FETCH_HEAD_IGNORE) {
+                       die(_("Cannot fetch both %s and %s to %s"),
+                           ref1->name, ref2->name, ref2->peer_ref->name);
+               } else if (ref1->fetch_head_status != FETCH_HEAD_IGNORE &&
+                          ref2->fetch_head_status == FETCH_HEAD_IGNORE) {
+                       warning(_("%s usually tracks %s, not %s"),
+                               ref2->peer_ref->name, ref2->name, ref1->name);
+               } else if (ref1->fetch_head_status == FETCH_HEAD_IGNORE &&
+                          ref2->fetch_head_status == FETCH_HEAD_IGNORE) {
+                       die(_("%s tracks both %s and %s"),
+                           ref2->peer_ref->name, ref1->name, ref2->name);
+               } else {
+                       /*
+                        * This last possibility doesn't occur because
+                        * FETCH_HEAD_IGNORE entries always appear at
+                        * the end of the list.
+                        */
+                       die(_("Internal error"));
+               }
+       }
+       free(ref2->peer_ref);
+       free(ref2);
+}
+
+struct ref *ref_remove_duplicates(struct ref *ref_map)
 {
        struct string_list refs = STRING_LIST_INIT_NODUP;
-       struct string_list_item *item = NULL;
-       struct ref *prev = NULL, *next = NULL;
-       for (; ref_map; prev = ref_map, ref_map = next) {
-               next = ref_map->next;
-               if (!ref_map->peer_ref)
-                       continue;
+       struct ref *retval = NULL;
+       struct ref **p = &retval;
 
-               item = string_list_lookup(&refs, ref_map->peer_ref->name);
-               if (item) {
-                       if (strcmp(((struct ref *)item->util)->name,
-                                  ref_map->name))
-                               die("%s tracks both %s and %s",
-                                   ref_map->peer_ref->name,
-                                   ((struct ref *)item->util)->name,
-                                   ref_map->name);
-                       prev->next = ref_map->next;
-                       free(ref_map->peer_ref);
-                       free(ref_map);
-                       ref_map = prev; /* skip this; we freed it */
-                       continue;
-               }
+       while (ref_map) {
+               struct ref *ref = ref_map;
+
+               ref_map = ref_map->next;
+               ref->next = NULL;
 
-               item = string_list_insert(&refs, ref_map->peer_ref->name);
-               item->util = ref_map;
+               if (!ref->peer_ref) {
+                       *p = ref;
+                       p = &ref->next;
+               } else {
+                       struct string_list_item *item =
+                               string_list_insert(&refs, ref->peer_ref->name);
+
+                       if (item->util) {
+                               /* Entry already existed */
+                               handle_duplicate((struct ref *)item->util, ref);
+                       } else {
+                               *p = ref;
+                               p = &ref->next;
+                               item->util = ref;
+                       }
+               }
        }
+
        string_list_clear(&refs, 0);
+       return retval;
 }
 
 int remote_has_url(struct remote *remote, const char *url)
@@ -847,10 +883,12 @@ static void query_refspecs_multiple(struct refspec *refs, int ref_count, struct
        }
 }
 
-static int query_refspecs(struct refspec *refs, int ref_count, struct refspec *query)
+int query_refspecs(struct refspec *refs, int ref_count, struct refspec *query)
 {
        int i;
        int find_src = !query->src;
+       const char *needle = find_src ? query->dst : query->src;
+       char **result = find_src ? &query->src : &query->dst;
 
        if (find_src && !query->dst)
                return error("query_refspecs: need either src or dst");
@@ -859,8 +897,6 @@ static int query_refspecs(struct refspec *refs, int ref_count, struct refspec *q
                struct refspec *refspec = &refs[i];
                const char *key = find_src ? refspec->dst : refspec->src;
                const char *value = find_src ? refspec->src : refspec->dst;
-               const char *needle = find_src ? query->dst : query->src;
-               char **result = find_src ? &query->src : &query->dst;
 
                if (!refspec->dst)
                        continue;
@@ -981,9 +1017,9 @@ void sort_ref_list(struct ref **l, int (*cmp)(const void *, const void *))
        *l = llist_mergesort(*l, ref_list_get_next, ref_list_set_next, cmp);
 }
 
-static int count_refspec_match(const char *pattern,
-                              struct ref *refs,
-                              struct ref **matched_ref)
+int count_refspec_match(const char *pattern,
+                       struct ref *refs,
+                       struct ref **matched_ref)
 {
        int patlen = strlen(pattern);
        struct ref *matched_weak = NULL;
@@ -995,7 +1031,7 @@ static int count_refspec_match(const char *pattern,
                char *name = refs->name;
                int namelen = strlen(name);
 
-               if (!refname_match(pattern, name, ref_rev_parse_rules))
+               if (!refname_match(pattern, name))
                        continue;
 
                /* A match is "weak" if it is with refs outside
@@ -1008,8 +1044,8 @@ static int count_refspec_match(const char *pattern,
                 */
                if (namelen != patlen &&
                    patlen != namelen - 5 &&
-                   prefixcmp(name, "refs/heads/") &&
-                   prefixcmp(name, "refs/tags/")) {
+                   !starts_with(name, "refs/heads/") &&
+                   !starts_with(name, "refs/tags/")) {
                        /* We want to catch the case where only weak
                         * matches are found and there are multiple
                         * matches, and where more than one strong
@@ -1026,11 +1062,13 @@ static int count_refspec_match(const char *pattern,
                }
        }
        if (!matched) {
-               *matched_ref = matched_weak;
+               if (matched_ref)
+                       *matched_ref = matched_weak;
                return weak_match;
        }
        else {
-               *matched_ref = matched;
+               if (matched_ref)
+                       *matched_ref = matched;
                return match;
        }
 }
@@ -1050,18 +1088,25 @@ static struct ref *alloc_delete_ref(void)
        return ref;
 }
 
-static struct ref *try_explicit_object_name(const char *name)
+static int try_explicit_object_name(const char *name,
+                                   struct ref **match)
 {
        unsigned char sha1[20];
-       struct ref *ref;
 
-       if (!*name)
-               return alloc_delete_ref();
+       if (!*name) {
+               if (match)
+                       *match = alloc_delete_ref();
+               return 0;
+       }
+
        if (get_sha1(name, sha1))
-               return NULL;
-       ref = alloc_ref(name);
-       hashcpy(ref->new_sha1, sha1);
-       return ref;
+               return -1;
+
+       if (match) {
+               *match = alloc_ref(name);
+               hashcpy((*match)->new_sha1, sha1);
+       }
+       return 0;
 }
 
 static struct ref *make_linked_ref(const char *name, struct ref ***tail)
@@ -1080,9 +1125,9 @@ static char *guess_ref(const char *name, struct ref *peer)
        if (!r)
                return NULL;
 
-       if (!prefixcmp(r, "refs/heads/"))
+       if (starts_with(r, "refs/heads/"))
                strbuf_addstr(&buf, "refs/heads/");
-       else if (!prefixcmp(r, "refs/tags/"))
+       else if (starts_with(r, "refs/tags/"))
                strbuf_addstr(&buf, "refs/tags/");
        else
                return NULL;
@@ -1091,12 +1136,37 @@ static char *guess_ref(const char *name, struct ref *peer)
        return strbuf_detach(&buf, NULL);
 }
 
+static int match_explicit_lhs(struct ref *src,
+                             struct refspec *rs,
+                             struct ref **match,
+                             int *allocated_match)
+{
+       switch (count_refspec_match(rs->src, src, match)) {
+       case 1:
+               if (allocated_match)
+                       *allocated_match = 0;
+               return 0;
+       case 0:
+               /* The source could be in the get_sha1() format
+                * not a reference name.  :refs/other is a
+                * way to delete 'other' ref at the remote end.
+                */
+               if (try_explicit_object_name(rs->src, match) < 0)
+                       return error("src refspec %s does not match any.", rs->src);
+               if (allocated_match)
+                       *allocated_match = 1;
+               return 0;
+       default:
+               return error("src refspec %s matches more than one.", rs->src);
+       }
+}
+
 static int match_explicit(struct ref *src, struct ref *dst,
                          struct ref ***dst_tail,
                          struct refspec *rs)
 {
        struct ref *matched_src, *matched_dst;
-       int copy_src;
+       int allocated_src;
 
        const char *dst_value = rs->dst;
        char *dst_guess;
@@ -1105,23 +1175,8 @@ static int match_explicit(struct ref *src, struct ref *dst,
                return 0;
 
        matched_src = matched_dst = NULL;
-       switch (count_refspec_match(rs->src, src, &matched_src)) {
-       case 1:
-               copy_src = 1;
-               break;
-       case 0:
-               /* The source could be in the get_sha1() format
-                * not a reference name.  :refs/other is a
-                * way to delete 'other' ref at the remote end.
-                */
-               matched_src = try_explicit_object_name(rs->src);
-               if (!matched_src)
-                       return error("src refspec %s does not match any.", rs->src);
-               copy_src = 0;
-               break;
-       default:
-               return error("src refspec %s matches more than one.", rs->src);
-       }
+       if (match_explicit_lhs(src, rs, &matched_src, &allocated_src) < 0)
+               return -1;
 
        if (!dst_value) {
                unsigned char sha1[20];
@@ -1130,7 +1185,7 @@ static int match_explicit(struct ref *src, struct ref *dst,
                dst_value = resolve_ref_unsafe(matched_src->name, sha1, 1, &flag);
                if (!dst_value ||
                    ((flag & REF_ISSYMREF) &&
-                    prefixcmp(dst_value, "refs/heads/")))
+                    !starts_with(dst_value, "refs/heads/")))
                        die("%s cannot be resolved to branch.",
                            matched_src->name);
        }
@@ -1166,7 +1221,9 @@ static int match_explicit(struct ref *src, struct ref *dst,
                return error("dst ref %s receives from more than one src.",
                      matched_dst->name);
        else {
-               matched_dst->peer_ref = copy_src ? copy_ref(matched_src) : matched_src;
+               matched_dst->peer_ref = allocated_src ?
+                                       matched_src :
+                                       copy_ref(matched_src);
                matched_dst->force = rs->force;
        }
        return 0;
@@ -1219,7 +1276,7 @@ static char *get_ref_match(const struct refspec *rs, int rs_nr, const struct ref
                 * including refs outside refs/heads/ hierarchy, but
                 * that does not make much sense these days.
                 */
-               if (!send_mirror && prefixcmp(ref->name, "refs/heads/"))
+               if (!send_mirror && !starts_with(ref->name, "refs/heads/"))
                        return NULL;
                name = xstrdup(ref->name);
        }
@@ -1274,7 +1331,7 @@ static void add_missing_tags(struct ref *src, struct ref **dst, struct ref ***ds
                        add_to_tips(&sent_tips, ref->peer_ref->new_sha1);
                else
                        add_to_tips(&sent_tips, ref->old_sha1);
-               if (!prefixcmp(ref->name, "refs/tags/"))
+               if (starts_with(ref->name, "refs/tags/"))
                        string_list_append(&dst_tag, ref->name);
        }
        clear_commit_marks_many(sent_tips.nr, sent_tips.tip, TMP_MARK);
@@ -1283,7 +1340,7 @@ static void add_missing_tags(struct ref *src, struct ref **dst, struct ref ***ds
 
        /* Collect tags they do not have. */
        for (ref = src; ref; ref = ref->next) {
-               if (prefixcmp(ref->name, "refs/tags/"))
+               if (!starts_with(ref->name, "refs/tags/"))
                        continue; /* not a tag */
                if (string_list_has_string(&dst_tag, ref->name))
                        continue; /* they already have it */
@@ -1347,6 +1404,31 @@ static void prepare_ref_index(struct string_list *ref_index, struct ref *ref)
        sort_string_list(ref_index);
 }
 
+/*
+ * Given only the set of local refs, sanity-check the set of push
+ * refspecs. We can't catch all errors that match_push_refs would,
+ * but we can catch some errors early before even talking to the
+ * remote side.
+ */
+int check_push_refs(struct ref *src, int nr_refspec, const char **refspec_names)
+{
+       struct refspec *refspec = parse_push_refspec(nr_refspec, refspec_names);
+       int ret = 0;
+       int i;
+
+       for (i = 0; i < nr_refspec; i++) {
+               struct refspec *rs = refspec + i;
+
+               if (rs->pattern || rs->matching)
+                       continue;
+
+               ret |= match_explicit_lhs(src, rs, NULL, NULL);
+       }
+
+       free_refspec(nr_refspec, refspec);
+       return ret;
+}
+
 /*
  * Given the set of refs the local repository has, the set of refs the
  * remote repository has, and the refspec used for push, determine
@@ -1399,7 +1481,7 @@ int match_push_refs(struct ref *src, struct ref **dst,
                                /*
                                 * Remote doesn't have it, and we have no
                                 * explicit pattern, and we don't have
-                                * --all nor --mirror.
+                                * --all or --mirror.
                                 */
                                goto free_name;
 
@@ -1507,7 +1589,7 @@ void set_ref_status_for_push(struct ref *remote_refs, int send_mirror,
                 */
 
                else if (!ref->deletion && !is_null_sha1(ref->old_sha1)) {
-                       if (!prefixcmp(ref->name, "refs/tags/"))
+                       if (starts_with(ref->name, "refs/tags/"))
                                reject_reason = REF_STATUS_REJECT_ALREADY_EXISTS;
                        else if (!has_sha1_file(ref->old_sha1))
                                reject_reason = REF_STATUS_REJECT_FETCH_FIRST;
@@ -1566,7 +1648,7 @@ int branch_merge_matches(struct branch *branch,
 {
        if (!branch || i < 0 || i >= branch->merge_nr)
                return 0;
-       return refname_match(branch->merge[i]->src, refname, ref_fetch_rules);
+       return refname_match(branch->merge[i]->src, refname);
 }
 
 static int ignore_symref_update(const char *refname)
@@ -1579,6 +1661,13 @@ static int ignore_symref_update(const char *refname)
        return (flag & REF_ISSYMREF);
 }
 
+/*
+ * Create and return a list of (struct ref) consisting of copies of
+ * each remote_ref that matches refspec.  refspec must be a pattern.
+ * Fill in the copies' peer_ref to describe the local tracking refs to
+ * which they map.  Omit any references that would map to an existing
+ * local symbolic ref.
+ */
 static struct ref *get_expanded_map(const struct ref *remote_refs,
                                    const struct refspec *refspec)
 {
@@ -1586,9 +1675,9 @@ static struct ref *get_expanded_map(const struct ref *remote_refs,
        struct ref *ret = NULL;
        struct ref **tail = &ret;
 
-       char *expn_name;
-
        for (ref = remote_refs; ref; ref = ref->next) {
+               char *expn_name = NULL;
+
                if (strchr(ref->name, '^'))
                        continue; /* a dereference item */
                if (match_name_with_pattern(refspec->src, ref->name,
@@ -1597,12 +1686,12 @@ static struct ref *get_expanded_map(const struct ref *remote_refs,
                        struct ref *cpy = copy_ref(ref);
 
                        cpy->peer_ref = alloc_ref(expn_name);
-                       free(expn_name);
                        if (refspec->force)
                                cpy->peer_ref->force = 1;
                        *tail = cpy;
                        tail = &cpy->next;
                }
+               free(expn_name);
        }
 
        return ret;
@@ -1612,7 +1701,7 @@ static const struct ref *find_ref_by_name_abbrev(const struct ref *refs, const c
 {
        const struct ref *ref;
        for (ref = refs; ref; ref = ref->next) {
-               if (refname_match(name, ref->name, ref_fetch_rules))
+               if (refname_match(name, ref->name))
                        return ref;
        }
        return NULL;
@@ -1633,12 +1722,12 @@ static struct ref *get_local_ref(const char *name)
        if (!name || name[0] == '\0')
                return NULL;
 
-       if (!prefixcmp(name, "refs/"))
+       if (starts_with(name, "refs/"))
                return alloc_ref(name);
 
-       if (!prefixcmp(name, "heads/") ||
-           !prefixcmp(name, "tags/") ||
-           !prefixcmp(name, "remotes/"))
+       if (starts_with(name, "heads/") ||
+           starts_with(name, "tags/") ||
+           starts_with(name, "remotes/"))
                return alloc_ref_with_prefix("refs/", 5, name);
 
        return alloc_ref_with_prefix("refs/heads/", 11, name);
@@ -1673,7 +1762,7 @@ int get_fetch_map(const struct ref *remote_refs,
 
        for (rmp = &ref_map; *rmp; ) {
                if ((*rmp)->peer_ref) {
-                       if (prefixcmp((*rmp)->peer_ref->name, "refs/") ||
+                       if (!starts_with((*rmp)->peer_ref->name, "refs/") ||
                            check_refname_format((*rmp)->peer_ref->name, 0)) {
                                struct ref *ignore = *rmp;
                                error("* Ignoring funny ref '%s' locally",
@@ -1957,7 +2046,7 @@ struct ref *guess_remote_head(const struct ref *head,
        /* Look for another ref that points there */
        for (r = refs; r; r = r->next) {
                if (r != head &&
-                   !prefixcmp(r->name, "refs/heads/") &&
+                   starts_with(r->name, "refs/heads/") &&
                    !hashcmp(r->old_sha1, head->old_sha1)) {
                        *tail = copy_ref(r);
                        tail = &((*tail)->next);
@@ -2121,7 +2210,7 @@ static void apply_cas(struct push_cas_option *cas,
        /* Find an explicit --<option>=<name>[:<value>] entry */
        for (i = 0; i < cas->nr; i++) {
                struct push_cas *entry = &cas->entry[i];
-               if (!refname_match(entry->refname, ref->name, ref_rev_parse_rules))
+               if (!refname_match(entry->refname, ref->name))
                        continue;
                ref->expect_old_sha1 = 1;
                if (!entry->use_tracking)