send-pack: segfault fix on forced push
[gitweb.git] / remote.c
index e7d735b98af231610c460c7aa34f12cdd6f37460..59defdbf1460b5c476364f611cf212cf90f567e3 100644 (file)
--- a/remote.c
+++ b/remote.c
@@ -380,6 +380,33 @@ int for_each_remote(each_remote_fn fn, void *priv)
        return result;
 }
 
+void ref_remove_duplicates(struct ref *ref_map)
+{
+       struct ref **posn;
+       struct ref *next;
+       for (; ref_map; ref_map = ref_map->next) {
+               if (!ref_map->peer_ref)
+                       continue;
+               posn = &ref_map->next;
+               while (*posn) {
+                       if ((*posn)->peer_ref &&
+                           !strcmp((*posn)->peer_ref->name,
+                                   ref_map->peer_ref->name)) {
+                               if (strcmp((*posn)->name, ref_map->name))
+                                       die("%s tracks both %s and %s",
+                                           ref_map->peer_ref->name,
+                                           (*posn)->name, ref_map->name);
+                               next = (*posn)->next;
+                               free((*posn)->peer_ref);
+                               free(*posn);
+                               *posn = next;
+                       } else {
+                               posn = &(*posn)->next;
+                       }
+               }
+       }
+}
+
 int remote_has_url(struct remote *remote, const char *url)
 {
        int i;
@@ -458,7 +485,7 @@ struct ref *alloc_ref(unsigned namelen)
        return ret;
 }
 
-static struct ref *copy_ref(struct ref *ref)
+static struct ref *copy_ref(const struct ref *ref)
 {
        struct ref *ret = xmalloc(sizeof(struct ref) + strlen(ref->name) + 1);
        memcpy(ret, ref, sizeof(struct ref) + strlen(ref->name) + 1);
@@ -466,6 +493,18 @@ static struct ref *copy_ref(struct ref *ref)
        return ret;
 }
 
+struct ref *copy_ref_list(const struct ref *ref)
+{
+       struct ref *ret = NULL;
+       struct ref **tail = &ret;
+       while (ref) {
+               *tail = copy_ref(ref);
+               ref = ref->next;
+               tail = &((*tail)->next);
+       }
+       return ret;
+}
+
 void free_refs(struct ref *ref)
 {
        struct ref *next;
@@ -683,7 +722,7 @@ static const struct refspec *check_pattern_match(const struct refspec *rs,
  * without thinking.
  */
 int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,
-              int nr_refspec, char **refspec, int all)
+              int nr_refspec, const char **refspec, int all)
 {
        struct refspec *rs =
                parse_ref_spec(nr_refspec, (const char **) refspec);
@@ -735,6 +774,8 @@ int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,
                        hashcpy(dst_peer->new_sha1, src->new_sha1);
                }
                dst_peer->peer_ref = src;
+               if (pat)
+                       dst_peer->force = pat->force;
        free_name:
                free(dst_name);
        }
@@ -781,10 +822,10 @@ int branch_merge_matches(struct branch *branch,
        return ref_matches_abbrev(branch->merge[i]->src, refname);
 }
 
-static struct ref *get_expanded_map(struct ref *remote_refs,
+static struct ref *get_expanded_map(const struct ref *remote_refs,
                                    const struct refspec *refspec)
 {
-       struct ref *ref;
+       const struct ref *ref;
        struct ref *ret = NULL;
        struct ref **tail = &ret;
 
@@ -795,7 +836,7 @@ static struct ref *get_expanded_map(struct ref *remote_refs,
                if (strchr(ref->name, '^'))
                        continue; /* a dereference item */
                if (!prefixcmp(ref->name, refspec->src)) {
-                       char *match;
+                       const char *match;
                        struct ref *cpy = copy_ref(ref);
                        match = ref->name + remote_prefix_len;
 
@@ -813,9 +854,9 @@ static struct ref *get_expanded_map(struct ref *remote_refs,
        return ret;
 }
 
-static struct ref *find_ref_by_name_abbrev(struct ref *refs, const char *name)
+static const struct ref *find_ref_by_name_abbrev(const struct ref *refs, const char *name)
 {
-       struct ref *ref;
+       const struct ref *ref;
        for (ref = refs; ref; ref = ref->next) {
                if (ref_matches_abbrev(name, ref->name))
                        return ref;
@@ -823,12 +864,12 @@ static struct ref *find_ref_by_name_abbrev(struct ref *refs, const char *name)
        return NULL;
 }
 
-struct ref *get_remote_ref(struct ref *remote_refs, const char *name)
+struct ref *get_remote_ref(const struct ref *remote_refs, const char *name)
 {
-       struct ref *ref = find_ref_by_name_abbrev(remote_refs, name);
+       const struct ref *ref = find_ref_by_name_abbrev(remote_refs, name);
 
        if (!ref)
-               die("Couldn't find remote ref %s\n", name);
+               return NULL;
 
        return copy_ref(ref);
 }
@@ -858,22 +899,26 @@ static struct ref *get_local_ref(const char *name)
        return ret;
 }
 
-int get_fetch_map(struct ref *remote_refs,
+int get_fetch_map(const struct ref *remote_refs,
                  const struct refspec *refspec,
-                 struct ref ***tail)
+                 struct ref ***tail,
+                 int missing_ok)
 {
        struct ref *ref_map, *rm;
 
        if (refspec->pattern) {
                ref_map = get_expanded_map(remote_refs, refspec);
        } else {
-               ref_map = get_remote_ref(remote_refs,
-                                        refspec->src[0] ?
-                                        refspec->src : "HEAD");
-
-               ref_map->peer_ref = get_local_ref(refspec->dst);
-               if (ref_map->peer_ref && refspec->force)
-                       ref_map->peer_ref->force = 1;
+               const char *name = refspec->src[0] ? refspec->src : "HEAD";
+
+               ref_map = get_remote_ref(remote_refs, name);
+               if (!missing_ok && !ref_map)
+                       die("Couldn't find remote ref %s", name);
+               if (ref_map) {
+                       ref_map->peer_ref = get_local_ref(refspec->dst);
+                       if (ref_map->peer_ref && refspec->force)
+                               ref_map->peer_ref->force = 1;
+               }
        }
 
        for (rm = ref_map; rm; rm = rm->next) {
@@ -882,7 +927,8 @@ int get_fetch_map(struct ref *remote_refs,
                            rm->peer_ref->name);
        }
 
-       tail_link_ref(ref_map, tail);
+       if (ref_map)
+               tail_link_ref(ref_map, tail);
 
        return 0;
 }