|
|
@ -434,6 +434,16 @@ static struct refspec *parse_refspec_internal(int nr_refspec, const char **refsp |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
rhs = strrchr(lhs, ':'); |
|
|
|
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) { |
|
|
|
if (rhs) { |
|
|
|
rhs++; |
|
|
|
rhs++; |
|
|
|
rlen = strlen(rhs); |
|
|
|
rlen = strlen(rhs); |
|
|
@ -855,7 +865,7 @@ static int match_explicit(struct ref *src, struct ref *dst, |
|
|
|
const char *dst_value = rs->dst; |
|
|
|
const char *dst_value = rs->dst; |
|
|
|
char *dst_guess; |
|
|
|
char *dst_guess; |
|
|
|
|
|
|
|
|
|
|
|
if (rs->pattern) |
|
|
|
if (rs->pattern || rs->matching) |
|
|
|
return errs; |
|
|
|
return errs; |
|
|
|
|
|
|
|
|
|
|
|
matched_src = matched_dst = NULL; |
|
|
|
matched_src = matched_dst = NULL; |
|
|
@ -945,13 +955,23 @@ static const struct refspec *check_pattern_match(const struct refspec *rs, |
|
|
|
const struct ref *src) |
|
|
|
const struct ref *src) |
|
|
|
{ |
|
|
|
{ |
|
|
|
int i; |
|
|
|
int i; |
|
|
|
|
|
|
|
int matching_refs = -1; |
|
|
|
for (i = 0; i < rs_nr; i++) { |
|
|
|
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 && |
|
|
|
if (rs[i].pattern && |
|
|
|
!prefixcmp(src->name, rs[i].src) && |
|
|
|
!prefixcmp(src->name, rs[i].src) && |
|
|
|
src->name[strlen(rs[i].src)] == '/') |
|
|
|
src->name[strlen(rs[i].src)] == '/') |
|
|
|
return rs + i; |
|
|
|
return rs + i; |
|
|
|
} |
|
|
|
} |
|
|
|
return NULL; |
|
|
|
if (matching_refs != -1) |
|
|
|
|
|
|
|
return rs + matching_refs; |
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
return NULL; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* |
|
|
|
/* |
|
|
@ -962,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 match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail, |
|
|
|
int nr_refspec, const char **refspec, int flags) |
|
|
|
int nr_refspec, const char **refspec, int flags) |
|
|
|
{ |
|
|
|
{ |
|
|
|
struct refspec *rs = |
|
|
|
struct refspec *rs; |
|
|
|
parse_push_refspec(nr_refspec, (const char **) refspec); |
|
|
|
|
|
|
|
int send_all = flags & MATCH_REFS_ALL; |
|
|
|
int send_all = flags & MATCH_REFS_ALL; |
|
|
|
int send_mirror = flags & MATCH_REFS_MIRROR; |
|
|
|
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)) |
|
|
|
if (match_explicit_refs(src, dst, dst_tail, rs, nr_refspec)) |
|
|
|
return -1; |
|
|
|
return -1; |
|
|
|
|
|
|
|
|
|
|
@ -977,48 +1002,50 @@ int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail, |
|
|
|
char *dst_name; |
|
|
|
char *dst_name; |
|
|
|
if (src->peer_ref) |
|
|
|
if (src->peer_ref) |
|
|
|
continue; |
|
|
|
continue; |
|
|
|
if (nr_refspec) { |
|
|
|
|
|
|
|
pat = check_pattern_match(rs, nr_refspec, src); |
|
|
|
pat = check_pattern_match(rs, nr_refspec, src); |
|
|
|
if (!pat) |
|
|
|
if (!pat) |
|
|
|
continue; |
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
|
else if (!send_mirror && prefixcmp(src->name, "refs/heads/")) |
|
|
|
if (pat->matching) { |
|
|
|
/* |
|
|
|
/* |
|
|
|
* "matching refs"; traditionally we pushed everything |
|
|
|
* "matching refs"; traditionally we pushed everything |
|
|
|
* including refs outside refs/heads/ hierarchy, but |
|
|
|
* including refs outside refs/heads/ hierarchy, but |
|
|
|
* that does not make much sense these days. |
|
|
|
* 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; |
|
|
|
const char *dst_side = pat->dst ? pat->dst : pat->src; |
|
|
|
dst_name = xmalloc(strlen(dst_side) + |
|
|
|
dst_name = xmalloc(strlen(dst_side) + |
|
|
|
strlen(src->name) - |
|
|
|
strlen(src->name) - |
|
|
|
strlen(pat->src) + 2); |
|
|
|
strlen(pat->src) + 2); |
|
|
|
strcpy(dst_name, dst_side); |
|
|
|
strcpy(dst_name, dst_side); |
|
|
|
strcat(dst_name, src->name + strlen(pat->src)); |
|
|
|
strcat(dst_name, src->name + strlen(pat->src)); |
|
|
|
} else |
|
|
|
} |
|
|
|
dst_name = xstrdup(src->name); |
|
|
|
|
|
|
|
dst_peer = find_ref_by_name(dst, dst_name); |
|
|
|
dst_peer = find_ref_by_name(dst, dst_name); |
|
|
|
if (dst_peer && dst_peer->peer_ref) |
|
|
|
if (dst_peer) { |
|
|
|
/* We're already sending something to this ref. */ |
|
|
|
if (dst_peer->peer_ref) |
|
|
|
goto free_name; |
|
|
|
/* 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 */ |
|
|
|
/* Create a new one and link it */ |
|
|
|
dst_peer = make_linked_ref(dst_name, dst_tail); |
|
|
|
dst_peer = make_linked_ref(dst_name, dst_tail); |
|
|
|
hashcpy(dst_peer->new_sha1, src->new_sha1); |
|
|
|
hashcpy(dst_peer->new_sha1, src->new_sha1); |
|
|
|
} |
|
|
|
} |
|
|
|
dst_peer->peer_ref = src; |
|
|
|
dst_peer->peer_ref = src; |
|
|
|
if (pat) |
|
|
|
dst_peer->force = pat->force; |
|
|
|
dst_peer->force = pat->force; |
|
|
|
|
|
|
|
free_name: |
|
|
|
free_name: |
|
|
|
free(dst_name); |
|
|
|
free(dst_name); |
|
|
|
} |
|
|
|
} |
|
|
|