X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=remote.c;h=9e4f2b84d90cb97a6cb19779325f9ea443a76e43;hb=325566cc5d14a409bdbc76aac50344294961f143;hp=870d224a3931bf0468c0b74334c0fb49a06ad731;hpb=dc484f2213a34ced5abe5eb968650035204b6035;p=git.git diff --git a/remote.c b/remote.c index 870d224a3..9e4f2b84d 100644 --- a/remote.c +++ b/remote.c @@ -434,6 +434,16 @@ static struct refspec *parse_refspec_internal(int nr_refspec, const char **refsp } rhs = strrchr(lhs, ':'); + + /* + * Before going on, special case ":" (or "+:") as a refspec + * for matching refs. + */ + if (!fetch && rhs == lhs && rhs[1] == '\0') { + rs[i].matching = 1; + continue; + } + if (rhs) { rhs++; rlen = strlen(rhs); @@ -691,6 +701,13 @@ struct ref *alloc_ref(unsigned namelen) return ret; } +struct ref *alloc_ref_from_str(const char* str) +{ + struct ref *ret = alloc_ref(strlen(str) + 1); + strcpy(ret->name, str); + return ret; +} + static struct ref *copy_ref(const struct ref *ref) { struct ref *ret = xmalloc(sizeof(struct ref) + strlen(ref->name) + 1); @@ -711,13 +728,22 @@ struct ref *copy_ref_list(const struct ref *ref) return ret; } +void free_ref(struct ref *ref) +{ + if (!ref) + return; + free(ref->remote_status); + free(ref->symref); + free(ref); +} + void free_refs(struct ref *ref) { struct ref *next; while (ref) { next = ref->next; free(ref->peer_ref); - free(ref); + free_ref(ref); ref = next; } } @@ -788,7 +814,6 @@ static struct ref *try_explicit_object_name(const char *name) { unsigned char sha1[20]; struct ref *ref; - int len; if (!*name) { ref = alloc_ref(20); @@ -798,21 +823,14 @@ static struct ref *try_explicit_object_name(const char *name) } if (get_sha1(name, sha1)) return NULL; - len = strlen(name) + 1; - ref = alloc_ref(len); - memcpy(ref->name, name, len); + ref = alloc_ref_from_str(name); hashcpy(ref->new_sha1, sha1); return ref; } static struct ref *make_linked_ref(const char *name, struct ref ***tail) { - struct ref *ret; - size_t len; - - len = strlen(name) + 1; - ret = alloc_ref(len); - memcpy(ret->name, name, len); + struct ref *ret = alloc_ref_from_str(name); tail_link_ref(ret, tail); return ret; } @@ -847,7 +865,7 @@ static int match_explicit(struct ref *src, struct ref *dst, const char *dst_value = rs->dst; char *dst_guess; - if (rs->pattern) + if (rs->pattern || rs->matching) return errs; matched_src = matched_dst = NULL; @@ -937,13 +955,23 @@ static const struct refspec *check_pattern_match(const struct refspec *rs, const struct ref *src) { int i; + int matching_refs = -1; for (i = 0; i < rs_nr; i++) { + if (rs[i].matching && + (matching_refs == -1 || rs[i].force)) { + matching_refs = i; + continue; + } + if (rs[i].pattern && !prefixcmp(src->name, rs[i].src) && src->name[strlen(rs[i].src)] == '/') return rs + i; } - return NULL; + if (matching_refs != -1) + return rs + matching_refs; + else + return NULL; } /* @@ -954,11 +982,16 @@ static const struct refspec *check_pattern_match(const struct refspec *rs, int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail, int nr_refspec, const char **refspec, int flags) { - struct refspec *rs = - parse_push_refspec(nr_refspec, (const char **) refspec); + struct refspec *rs; int send_all = flags & MATCH_REFS_ALL; int send_mirror = flags & MATCH_REFS_MIRROR; + static const char *default_refspec[] = { ":", 0 }; + if (!nr_refspec) { + nr_refspec = 1; + refspec = default_refspec; + } + rs = parse_push_refspec(nr_refspec, (const char **) refspec); if (match_explicit_refs(src, dst, dst_tail, rs, nr_refspec)) return -1; @@ -969,48 +1002,50 @@ int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail, char *dst_name; if (src->peer_ref) continue; - if (nr_refspec) { - pat = check_pattern_match(rs, nr_refspec, src); - if (!pat) - continue; - } - else if (!send_mirror && prefixcmp(src->name, "refs/heads/")) + + pat = check_pattern_match(rs, nr_refspec, src); + if (!pat) + continue; + + if (pat->matching) { /* * "matching refs"; traditionally we pushed everything * including refs outside refs/heads/ hierarchy, but * that does not make much sense these days. */ - continue; + if (!send_mirror && prefixcmp(src->name, "refs/heads/")) + continue; + dst_name = xstrdup(src->name); - if (pat) { + } else { 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. */ - goto free_name; + if (dst_peer) { + if (dst_peer->peer_ref) + /* We're already sending something to this ref. */ + goto free_name; + + } else { + if (pat->matching && !(send_all || send_mirror)) + /* + * Remote doesn't have it, and we have no + * explicit pattern, and we don't have + * --all nor --mirror. + */ + goto free_name; - 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 nor --mirror. - */ - goto free_name; - if (!dst_peer) { /* Create a new one and link it */ dst_peer = make_linked_ref(dst_name, dst_tail); hashcpy(dst_peer->new_sha1, src->new_sha1); } dst_peer->peer_ref = src; - if (pat) - dst_peer->force = pat->force; + dst_peer->force = pat->force; free_name: free(dst_name); } @@ -1116,9 +1151,7 @@ static struct ref *get_local_ref(const char *name) return NULL; if (!prefixcmp(name, "refs/")) { - ret = alloc_ref(strlen(name) + 1); - strcpy(ret->name, name); - return ret; + return alloc_ref_from_str(name); } if (!prefixcmp(name, "heads/") || @@ -1177,3 +1210,15 @@ int get_fetch_map(const struct ref *remote_refs, return 0; } + +int resolve_remote_symref(struct ref *ref, struct ref *list) +{ + if (!ref->symref) + return 0; + for (; list; list = list->next) + if (!strcmp(ref->symref, list->name)) { + hashcpy(ref->old_sha1, list->old_sha1); + return 0; + } + return 1; +}