diff options
Diffstat (limited to 'remote.c')
| -rw-r--r-- | remote.c | 207 |
1 files changed, 115 insertions, 92 deletions
@@ -333,7 +333,6 @@ static int count_refspec_match(const char *pattern, for (weak_match = match = 0; refs; refs = refs->next) { char *name = refs->name; int namelen = strlen(name); - int weak_match; if (namelen < patlen || memcmp(name + namelen - patlen, pattern, patlen)) @@ -406,90 +405,96 @@ static struct ref *try_explicit_object_name(const char *name) return ref; } -static int match_explicit_refs(struct ref *src, struct ref *dst, - struct ref ***dst_tail, struct refspec *rs, - int rs_nr) +static struct ref *make_dst(const char *name, struct ref ***dst_tail) { - int i, errs; - for (i = errs = 0; i < rs_nr; i++) { - struct ref *matched_src, *matched_dst; + struct ref *dst; + size_t len; - const char *dst_value = rs[i].dst; + len = strlen(name) + 1; + dst = xcalloc(1, sizeof(*dst) + len); + memcpy(dst->name, name, len); + link_dst_tail(dst, dst_tail); + return dst; +} - if (rs[i].pattern) - continue; +static int match_explicit(struct ref *src, struct ref *dst, + struct ref ***dst_tail, + struct refspec *rs, + int errs) +{ + struct ref *matched_src, *matched_dst; - if (dst_value == NULL) - dst_value = rs[i].src; + const char *dst_value = rs->dst; - matched_src = matched_dst = NULL; - switch (count_refspec_match(rs[i].src, src, &matched_src)) { - case 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[i].src); - if (matched_src) - break; - errs = 1; - error("src refspec %s does not match any.", - rs[i].src); - break; - default: - errs = 1; - error("src refspec %s matches more than one.", - rs[i].src); - break; - } - switch (count_refspec_match(dst_value, dst, &matched_dst)) { - case 1: - break; - case 0: - if (!memcmp(dst_value, "refs/", 5)) { - int len = strlen(dst_value) + 1; - matched_dst = xcalloc(1, sizeof(*dst) + len); - memcpy(matched_dst->name, dst_value, len); - link_dst_tail(matched_dst, dst_tail); - } - else if (!strcmp(rs[i].src, dst_value) && - matched_src) { - /* pushing "master:master" when - * remote does not have master yet. - */ - int len = strlen(matched_src->name) + 1; - matched_dst = xcalloc(1, sizeof(*dst) + len); - memcpy(matched_dst->name, matched_src->name, - len); - link_dst_tail(matched_dst, dst_tail); - } - else { - errs = 1; - error("dst refspec %s does not match any " - "existing ref on the remote and does " - "not start with refs/.", dst_value); - } - break; - default: - errs = 1; - error("dst refspec %s matches more than one.", - dst_value); + if (rs->pattern) + return errs; + + matched_src = matched_dst = NULL; + switch (count_refspec_match(rs->src, src, &matched_src)) { + case 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) break; - } - if (errs) - continue; - if (matched_dst->peer_ref) { - errs = 1; - error("dst ref %s receives from more than one src.", - matched_dst->name); - } - else { - matched_dst->peer_ref = matched_src; - matched_dst->force = rs[i].force; - } + 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); + break; + } + + if (!matched_src) + errs = 1; + + if (dst_value == NULL) + dst_value = matched_src->name; + + switch (count_refspec_match(dst_value, dst, &matched_dst)) { + case 1: + break; + case 0: + if (!memcmp(dst_value, "refs/", 5)) + matched_dst = make_dst(dst_value, dst_tail); + else + error("dst refspec %s does not match any " + "existing ref on the remote and does " + "not start with refs/.", dst_value); + break; + default: + matched_dst = NULL; + error("dst refspec %s matches more than one.", + dst_value); + break; } + if (errs || matched_dst == NULL) + return 1; + if (matched_dst->peer_ref) { + errs = 1; + error("dst ref %s receives from more than one src.", + matched_dst->name); + } + else { + matched_dst->peer_ref = matched_src; + matched_dst->force = rs->force; + } + return errs; +} + +static int match_explicit_refs(struct ref *src, struct ref *dst, + struct ref ***dst_tail, struct refspec *rs, + int rs_nr) +{ + int i, errs; + for (i = errs = 0; i < rs_nr; i++) + errs |= match_explicit(src, dst, dst_tail, &rs[i], errs); return -errs; } @@ -501,18 +506,23 @@ static struct ref *find_ref_by_name(struct ref *list, const char *name) return NULL; } -static int check_pattern_match(struct refspec *rs, int rs_nr, struct ref *src) +static const struct refspec *check_pattern_match(const struct refspec *rs, + int rs_nr, + const struct ref *src) { int i; - if (!rs_nr) - return 1; for (i = 0; i < rs_nr; i++) { if (rs[i].pattern && !prefixcmp(src->name, rs[i].src)) - return 1; + return rs + i; } - return 0; + return NULL; } +/* + * Note. This is used only by "push"; refspec matching rules for + * push and fetch are subtly different, so do not try to reuse it + * without thinking. + */ int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail, int nr_refspec, char **refspec, int all) { @@ -525,29 +535,42 @@ int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail, /* 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; - if (!check_pattern_match(rs, nr_refspec, src)) - continue; + if (nr_refspec) { + pat = check_pattern_match(rs, nr_refspec, src); + if (!pat) + continue; + } - dst_peer = find_ref_by_name(dst, src->name); + if (pat) { + const char *dst_side = pat->dst ? pat->dst : pat->src; + dst_name = xmalloc(strlen(dst_side) + + strlen(src->name) - + strlen(pat->src) + 2); + strcpy(dst_name, dst_side); + 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. */ - continue; + 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. */ - continue; + goto free_name; if (!dst_peer) { /* Create a new one and link it */ - int len = strlen(src->name) + 1; - dst_peer = xcalloc(1, sizeof(*dst_peer) + len); - memcpy(dst_peer->name, src->name, len); + dst_peer = make_dst(dst_name, dst_tail); 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; } |
