Reduce the number of connects when fetching
[gitweb.git] / remote.c
index e3c3df556d540db887d0b0291a306fe073065d41..0e006804ef3cc190fa286c85e2de034a33791886 100644 (file)
--- a/remote.c
+++ b/remote.c
@@ -220,11 +220,11 @@ static int handle_config(const char *key, const char *value)
        if (!prefixcmp(key, "branch.")) {
                name = key + 7;
                subkey = strrchr(name, '.');
-               branch = make_branch(name, subkey - name);
                if (!subkey)
                        return 0;
                if (!value)
                        return 0;
+               branch = make_branch(name, subkey - name);
                if (!strcmp(subkey, ".remote")) {
                        branch->remote_name = xstrdup(value);
                        if (branch == current_branch)
@@ -278,6 +278,8 @@ static int handle_config(const char *key, const char *value)
        } else if (!strcmp(subkey, ".tagopt")) {
                if (!strcmp(value, "--no-tags"))
                        remote->fetch_tags = -1;
+       } else if (!strcmp(subkey, ".proxy")) {
+               remote->http_proxy = xstrdup(value);
        }
        return 0;
 }
@@ -380,6 +382,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;
@@ -390,25 +419,6 @@ int remote_has_url(struct remote *remote, const char *url)
        return 0;
 }
 
-/*
- * Returns true if, under the matching rules for fetching, name is the
- * same as the given full name.
- */
-static int ref_matches_abbrev(const char *name, const char *full)
-{
-       if (!prefixcmp(name, "refs/") || !strcmp(name, "HEAD"))
-               return !strcmp(name, full);
-       if (prefixcmp(full, "refs/"))
-               return 0;
-       if (!prefixcmp(name, "heads/") ||
-           !prefixcmp(name, "tags/") ||
-           !prefixcmp(name, "remotes/"))
-               return !strcmp(name, full + 5);
-       if (prefixcmp(full + 5, "heads/"))
-               return 0;
-       return !strcmp(full + 11, name);
-}
-
 int remote_find_tracking(struct remote *remote, struct refspec *refspec)
 {
        int find_src = refspec->src == NULL;
@@ -416,7 +426,7 @@ int remote_find_tracking(struct remote *remote, struct refspec *refspec)
        int i;
 
        if (find_src) {
-               if (refspec->dst == NULL)
+               if (!refspec->dst)
                        return error("find_tracking: need either src or dst");
                needle = refspec->dst;
                result = &refspec->src;
@@ -458,7 +468,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 +476,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;
@@ -492,10 +514,7 @@ static int count_refspec_match(const char *pattern,
                char *name = refs->name;
                int namelen = strlen(name);
 
-               if (namelen < patlen ||
-                   memcmp(name + namelen - patlen, pattern, patlen))
-                       continue;
-               if (namelen != patlen && name[namelen - patlen - 1] != '/')
+               if (!refname_match(pattern, name, ref_rev_parse_rules))
                        continue;
 
                /* A match is "weak" if it is with refs outside
@@ -598,23 +617,23 @@ static int match_explicit(struct ref *src, struct ref *dst,
                 * way to delete 'other' ref at the remote end.
                 */
                matched_src = try_explicit_object_name(rs->src);
-               if (matched_src)
-                       break;
-               error("src refspec %s does not match any.",
-                     rs->src);
+               if (!matched_src)
+                       error("src refspec %s does not match any.", rs->src);
                break;
        default:
                matched_src = NULL;
-               error("src refspec %s matches more than one.",
-                     rs->src);
+               error("src refspec %s matches more than one.", rs->src);
                break;
        }
 
        if (!matched_src)
                errs = 1;
 
-       if (dst_value == NULL)
+       if (!dst_value) {
+               if (!matched_src)
+                       return errs;
                dst_value = matched_src->name;
+       }
 
        switch (count_refspec_match(dst_value, dst, &matched_dst)) {
        case 1:
@@ -633,7 +652,7 @@ static int match_explicit(struct ref *src, struct ref *dst,
                      dst_value);
                break;
        }
-       if (errs || matched_dst == NULL)
+       if (errs || !matched_dst)
                return 1;
        if (matched_dst->peer_ref) {
                errs = 1;
@@ -657,14 +676,6 @@ static int match_explicit_refs(struct ref *src, struct ref *dst,
        return -errs;
 }
 
-static struct ref *find_ref_by_name(struct ref *list, const char *name)
-{
-       for ( ; list; list = list->next)
-               if (!strcmp(list->name, name))
-                       return list;
-       return NULL;
-}
-
 static const struct refspec *check_pattern_match(const struct refspec *rs,
                                                 int rs_nr,
                                                 const struct ref *src)
@@ -683,10 +694,12 @@ 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 flags)
 {
        struct refspec *rs =
                parse_ref_spec(nr_refspec, (const char **) refspec);
+       int send_all = flags & MATCH_REFS_ALL;
+       int send_mirror = flags & MATCH_REFS_MIRROR;
 
        if (match_explicit_refs(src, dst, dst_tail, rs, nr_refspec))
                return -1;
@@ -703,7 +716,7 @@ int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,
                        if (!pat)
                                continue;
                }
-               else if (prefixcmp(src->name, "refs/heads/"))
+               else if (!send_mirror && prefixcmp(src->name, "refs/heads/"))
                        /*
                         * "matching refs"; traditionally we pushed everything
                         * including refs outside refs/heads/ hierarchy, but
@@ -724,10 +737,13 @@ int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,
                if (dst_peer && dst_peer->peer_ref)
                        /* We're already sending something to this ref. */
                        goto free_name;
-               if (!dst_peer && !nr_refspec && !all)
-                       /* Remote doesn't have it, and we have no
+
+               if (!dst_peer && !nr_refspec && !(send_all || send_mirror))
+                       /*
+                        * Remote doesn't have it, and we have no
                         * explicit pattern, and we don't have
-                        * --all. */
+                        * --all nor --mirror.
+                        */
                        goto free_name;
                if (!dst_peer) {
                        /* Create a new one and link it */
@@ -735,6 +751,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);
        }
@@ -778,13 +796,13 @@ int branch_merge_matches(struct branch *branch,
 {
        if (!branch || i < 0 || i >= branch->merge_nr)
                return 0;
-       return ref_matches_abbrev(branch->merge[i]->src, refname);
+       return refname_match(branch->merge[i]->src, refname, ref_fetch_rules);
 }
 
-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 +813,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,22 +831,22 @@ 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))
+               if (refname_match(name, ref->name, ref_fetch_rules))
                        return ref;
        }
        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 +876,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 +904,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;
 }