Code

gitview: Fix the blame interface.
[git.git] / remote.c
index bc27a8e3df59915d13bdca357fbe76789caf646e..ed62a62fa0d5eab7d154233f94e4dad1fc9fbe2f 100644 (file)
--- a/remote.c
+++ b/remote.c
@@ -17,6 +17,15 @@ static void add_push_refspec(struct remote *remote, const char *ref)
        remote->push_refspec_nr = nr;
 }
 
+static void add_fetch_refspec(struct remote *remote, const char *ref)
+{
+       int nr = remote->fetch_refspec_nr + 1;
+       remote->fetch_refspec =
+               xrealloc(remote->fetch_refspec, nr * sizeof(char *));
+       remote->fetch_refspec[nr-1] = ref;
+       remote->fetch_refspec_nr = nr;
+}
+
 static void add_uri(struct remote *remote, const char *uri)
 {
        int nr = remote->uri_nr + 1;
@@ -74,6 +83,9 @@ static void read_remotes_file(struct remote *remote)
                } else if (!prefixcmp(buffer, "Push:")) {
                        value_list = 1;
                        s = buffer + 5;
+               } else if (!prefixcmp(buffer, "Pull:")) {
+                       value_list = 2;
+                       s = buffer + 5;
                } else
                        continue;
 
@@ -93,6 +105,9 @@ static void read_remotes_file(struct remote *remote)
                case 1:
                        add_push_refspec(remote, xstrdup(s));
                        break;
+               case 2:
+                       add_fetch_refspec(remote, xstrdup(s));
+                       break;
                }
        }
        fclose(f);
@@ -174,6 +189,8 @@ static int handle_config(const char *key, const char *value)
                add_uri(remote, xstrdup(value));
        } else if (!strcmp(subkey, ".push")) {
                add_push_refspec(remote, xstrdup(value));
+       } else if (!strcmp(subkey, ".fetch")) {
+               add_fetch_refspec(remote, xstrdup(value));
        } else if (!strcmp(subkey, ".receivepack")) {
                if (!remote->receivepack)
                        remote->receivepack = xstrdup(value);
@@ -257,10 +274,52 @@ struct remote *remote_get(const char *name)
                add_uri(ret, name);
        if (!ret->uri)
                return NULL;
+       ret->fetch = parse_ref_spec(ret->fetch_refspec_nr, ret->fetch_refspec);
        ret->push = parse_ref_spec(ret->push_refspec_nr, ret->push_refspec);
        return ret;
 }
 
+int remote_has_uri(struct remote *remote, const char *uri)
+{
+       int i;
+       for (i = 0; i < remote->uri_nr; i++) {
+               if (!strcmp(remote->uri[i], uri))
+                       return 1;
+       }
+       return 0;
+}
+
+int remote_find_tracking(struct remote *remote, struct refspec *refspec)
+{
+       int i;
+       for (i = 0; i < remote->fetch_refspec_nr; i++) {
+               struct refspec *fetch = &remote->fetch[i];
+               if (!fetch->dst)
+                       continue;
+               if (fetch->pattern) {
+                       if (!prefixcmp(refspec->src, fetch->src)) {
+                               refspec->dst =
+                                       xmalloc(strlen(fetch->dst) +
+                                               strlen(refspec->src) -
+                                               strlen(fetch->src) + 1);
+                               strcpy(refspec->dst, fetch->dst);
+                               strcpy(refspec->dst + strlen(fetch->dst),
+                                      refspec->src + strlen(fetch->src));
+                               refspec->force = fetch->force;
+                               return 0;
+                       }
+               } else {
+                       if (!strcmp(refspec->src, fetch->src)) {
+                               refspec->dst = xstrdup(fetch->dst);
+                               refspec->force = fetch->force;
+                               return 0;
+                       }
+               }
+       }
+       refspec->dst = NULL;
+       return -1;
+}
+
 static int count_refspec_match(const char *pattern,
                               struct ref *refs,
                               struct ref **matched_ref)
@@ -356,6 +415,10 @@ static int match_explicit_refs(struct ref *src, struct ref *dst,
                struct ref *matched_src, *matched_dst;
 
                const char *dst_value = rs[i].dst;
+
+               if (rs[i].pattern)
+                       continue;
+
                if (dst_value == NULL)
                        dst_value = rs[i].src;
 
@@ -438,32 +501,68 @@ static struct ref *find_ref_by_name(struct ref *list, const char *name)
        return NULL;
 }
 
+static const struct refspec *check_pattern_match(const struct refspec *rs,
+                                                int rs_nr,
+                                                const struct ref *src)
+{
+       int i;
+       for (i = 0; i < rs_nr; i++) {
+               if (rs[i].pattern && !prefixcmp(src->name, rs[i].src))
+                       return rs + i;
+       }
+       return NULL;
+}
+
 int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,
               int nr_refspec, char **refspec, int all)
 {
        struct refspec *rs =
                parse_ref_spec(nr_refspec, (const char **) refspec);
 
-       if (nr_refspec)
-               return match_explicit_refs(src, dst, dst_tail, rs, nr_refspec);
+       if (match_explicit_refs(src, dst, dst_tail, rs, nr_refspec))
+               return -1;
 
        /* pick the remainder */
        for ( ; src; src = src->next) {
                struct ref *dst_peer;
+               const struct refspec *pat = NULL;
+               char *dst_name;
                if (src->peer_ref)
                        continue;
-               dst_peer = find_ref_by_name(dst, src->name);
-               if ((dst_peer && dst_peer->peer_ref) || (!dst_peer && !all))
-                       continue;
+               if (nr_refspec) {
+                       pat = check_pattern_match(rs, nr_refspec, src);
+                       if (!pat)
+                               continue;
+               }
+
+               if (pat) {
+                       dst_name = xmalloc(strlen(pat->dst) +
+                                          strlen(src->name) -
+                                          strlen(pat->src) + 2);
+                       strcpy(dst_name, pat->dst);
+                       strcat(dst_name, src->name + strlen(pat->src));
+               } else
+                       dst_name = xstrdup(src->name);
+               dst_peer = find_ref_by_name(dst, dst_name);
+               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
+                        * explicit pattern, and we don't have
+                        * --all. */
+                       goto free_name;
                if (!dst_peer) {
                        /* Create a new one and link it */
-                       int len = strlen(src->name) + 1;
+                       int len = strlen(dst_name) + 1;
                        dst_peer = xcalloc(1, sizeof(*dst_peer) + len);
-                       memcpy(dst_peer->name, src->name, len);
+                       memcpy(dst_peer->name, dst_name, len);
                        hashcpy(dst_peer->new_sha1, src->new_sha1);
                        link_dst_tail(dst_peer, dst_tail);
                }
                dst_peer->peer_ref = src;
+       free_name:
+               free(dst_name);
        }
        return 0;
 }