]> asedeno.scripts.mit.edu Git - git.git/blobdiff - remote.c
receive-pack: check object type of sha1 before using them as commits
[git.git] / remote.c
index 711aa04ce157e59cece118ff2a77a558e93e2df5..0e006804ef3cc190fa286c85e2de034a33791886 100644 (file)
--- a/remote.c
+++ b/remote.c
@@ -32,13 +32,13 @@ static void add_fetch_refspec(struct remote *remote, const char *ref)
        remote->fetch_refspec_nr = nr;
 }
 
-static void add_uri(struct remote *remote, const char *uri)
+static void add_url(struct remote *remote, const char *url)
 {
-       int nr = remote->uri_nr + 1;
-       remote->uri =
-               xrealloc(remote->uri, nr * sizeof(char *));
-       remote->uri[nr-1] = uri;
-       remote->uri_nr = nr;
+       int nr = remote->url_nr + 1;
+       remote->url =
+               xrealloc(remote->url, nr * sizeof(char *));
+       remote->url[nr-1] = url;
+       remote->url_nr = nr;
 }
 
 static struct remote *make_remote(const char *name, int len)
@@ -154,7 +154,7 @@ static void read_remotes_file(struct remote *remote)
 
                switch (value_list) {
                case 0:
-                       add_uri(remote, xstrdup(s));
+                       add_url(remote, xstrdup(s));
                        break;
                case 1:
                        add_push_refspec(remote, xstrdup(s));
@@ -206,8 +206,9 @@ static void read_branches_file(struct remote *remote)
        } else {
                branch = "refs/heads/master";
        }
-       add_uri(remote, p);
+       add_url(remote, p);
        add_fetch_refspec(remote, branch);
+       remote->fetch_tags = 1; /* always auto-follow */
 }
 
 static int handle_config(const char *key, const char *value)
@@ -219,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)
@@ -259,7 +260,7 @@ static int handle_config(const char *key, const char *value)
                return 0; /* ignore unknown booleans */
        }
        if (!strcmp(subkey, ".url")) {
-               add_uri(remote, xstrdup(value));
+               add_url(remote, xstrdup(value));
        } else if (!strcmp(subkey, ".push")) {
                add_push_refspec(remote, xstrdup(value));
        } else if (!strcmp(subkey, ".fetch")) {
@@ -274,6 +275,11 @@ static int handle_config(const char *key, const char *value)
                        remote->uploadpack = xstrdup(value);
                else
                        error("more than one uploadpack given, using the first");
+       } 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;
 }
@@ -296,7 +302,7 @@ static void read_config(void)
        git_config(handle_config);
 }
 
-static struct refspec *parse_ref_spec(int nr_refspec, const char **refspec)
+struct refspec *parse_ref_spec(int nr_refspec, const char **refspec)
 {
        int i;
        struct refspec *rs = xcalloc(sizeof(*rs), nr_refspec);
@@ -343,14 +349,14 @@ struct remote *remote_get(const char *name)
                name = default_remote_name;
        ret = make_remote(name, 0);
        if (name[0] != '/') {
-               if (!ret->uri)
+               if (!ret->url)
                        read_remotes_file(ret);
-               if (!ret->uri)
+               if (!ret->url)
                        read_branches_file(ret);
        }
-       if (!ret->uri)
-               add_uri(ret, name);
-       if (!ret->uri)
+       if (!ret->url)
+               add_url(ret, name);
+       if (!ret->url)
                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);
@@ -376,33 +382,41 @@ int for_each_remote(each_remote_fn fn, void *priv)
        return result;
 }
 
-int remote_has_uri(struct remote *remote, const char *uri)
+void ref_remove_duplicates(struct ref *ref_map)
 {
-       int i;
-       for (i = 0; i < remote->uri_nr; i++) {
-               if (!strcmp(remote->uri[i], uri))
-                       return 1;
+       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;
+                       }
+               }
        }
-       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)
+int remote_has_url(struct remote *remote, const char *url)
 {
-       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 i;
+       for (i = 0; i < remote->url_nr; i++) {
+               if (!strcmp(remote->url[i], url))
+                       return 1;
+       }
+       return 0;
 }
 
 int remote_find_tracking(struct remote *remote, struct refspec *refspec)
@@ -412,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;
@@ -454,6 +468,26 @@ struct ref *alloc_ref(unsigned namelen)
        return ret;
 }
 
+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);
+       ret->next = NULL;
+       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;
@@ -480,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
@@ -586,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:
@@ -621,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;
@@ -645,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)
@@ -671,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;
@@ -691,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
@@ -712,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 */
@@ -723,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);
        }
@@ -760,14 +790,122 @@ int branch_has_merge_config(struct branch *branch)
        return branch && !!branch->merge;
 }
 
-int branch_merges(struct branch *branch, const char *refname)
+int branch_merge_matches(struct branch *branch,
+                                int i,
+                                const char *refname)
 {
-       int i;
-       if (!branch)
+       if (!branch || i < 0 || i >= branch->merge_nr)
                return 0;
-       for (i = 0; i < branch->merge_nr; i++) {
-               if (ref_matches_abbrev(branch->merge[i]->src, refname))
-                       return 1;
+       return refname_match(branch->merge[i]->src, refname, ref_fetch_rules);
+}
+
+static struct ref *get_expanded_map(const struct ref *remote_refs,
+                                   const struct refspec *refspec)
+{
+       const struct ref *ref;
+       struct ref *ret = NULL;
+       struct ref **tail = &ret;
+
+       int remote_prefix_len = strlen(refspec->src);
+       int local_prefix_len = strlen(refspec->dst);
+
+       for (ref = remote_refs; ref; ref = ref->next) {
+               if (strchr(ref->name, '^'))
+                       continue; /* a dereference item */
+               if (!prefixcmp(ref->name, refspec->src)) {
+                       const char *match;
+                       struct ref *cpy = copy_ref(ref);
+                       match = ref->name + remote_prefix_len;
+
+                       cpy->peer_ref = alloc_ref(local_prefix_len +
+                                                 strlen(match) + 1);
+                       sprintf(cpy->peer_ref->name, "%s%s",
+                               refspec->dst, match);
+                       if (refspec->force)
+                               cpy->peer_ref->force = 1;
+                       *tail = cpy;
+                       tail = &cpy->next;
+               }
+       }
+
+       return ret;
+}
+
+static const struct ref *find_ref_by_name_abbrev(const struct ref *refs, const char *name)
+{
+       const struct ref *ref;
+       for (ref = refs; ref; ref = ref->next) {
+               if (refname_match(name, ref->name, ref_fetch_rules))
+                       return ref;
+       }
+       return NULL;
+}
+
+struct ref *get_remote_ref(const struct ref *remote_refs, const char *name)
+{
+       const struct ref *ref = find_ref_by_name_abbrev(remote_refs, name);
+
+       if (!ref)
+               return NULL;
+
+       return copy_ref(ref);
+}
+
+static struct ref *get_local_ref(const char *name)
+{
+       struct ref *ret;
+       if (!name)
+               return NULL;
+
+       if (!prefixcmp(name, "refs/")) {
+               ret = alloc_ref(strlen(name) + 1);
+               strcpy(ret->name, name);
+               return ret;
        }
+
+       if (!prefixcmp(name, "heads/") ||
+           !prefixcmp(name, "tags/") ||
+           !prefixcmp(name, "remotes/")) {
+               ret = alloc_ref(strlen(name) + 6);
+               sprintf(ret->name, "refs/%s", name);
+               return ret;
+       }
+
+       ret = alloc_ref(strlen(name) + 12);
+       sprintf(ret->name, "refs/heads/%s", name);
+       return ret;
+}
+
+int get_fetch_map(const struct ref *remote_refs,
+                 const struct refspec *refspec,
+                 struct ref ***tail,
+                 int missing_ok)
+{
+       struct ref *ref_map, *rm;
+
+       if (refspec->pattern) {
+               ref_map = get_expanded_map(remote_refs, refspec);
+       } else {
+               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) {
+               if (rm->peer_ref && check_ref_format(rm->peer_ref->name + 5))
+                       die("* refusing to create funny ref '%s' locally",
+                           rm->peer_ref->name);
+       }
+
+       if (ref_map)
+               tail_link_ref(ref_map, tail);
+
        return 0;
 }