зеркало из https://github.com/microsoft/git.git
Merge branch 'xx/db-refspec-vs-js-remote'
* xx/db-refspec-vs-js-remote: Support '*' in the middle of a refspec Keep '*' in pattern refspecs Use the matching function to generate the match results Use a single function to match names against patterns Make clone parse the default refspec with the normal code
This commit is contained in:
Коммит
8e50ada553
|
@ -330,7 +330,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
|
|||
char *src_ref_prefix = "refs/heads/";
|
||||
int err = 0;
|
||||
|
||||
struct refspec refspec;
|
||||
struct refspec *refspec;
|
||||
const char *fetch_pattern;
|
||||
|
||||
junk_pid = getpid();
|
||||
|
||||
|
@ -435,8 +436,14 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
|
|||
strbuf_addf(&branch_top, "refs/remotes/%s/", option_origin);
|
||||
}
|
||||
|
||||
strbuf_addf(&value, "+%s*:%s*", src_ref_prefix, branch_top.buf);
|
||||
|
||||
if (option_mirror || !option_bare) {
|
||||
/* Configure the remote */
|
||||
strbuf_addf(&key, "remote.%s.fetch", option_origin);
|
||||
git_config_set_multivar(key.buf, value.buf, "^$", 0);
|
||||
strbuf_reset(&key);
|
||||
|
||||
if (option_mirror) {
|
||||
strbuf_addf(&key, "remote.%s.mirror", option_origin);
|
||||
git_config_set(key.buf, "true");
|
||||
|
@ -445,19 +452,13 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
|
|||
|
||||
strbuf_addf(&key, "remote.%s.url", option_origin);
|
||||
git_config_set(key.buf, repo);
|
||||
strbuf_reset(&key);
|
||||
|
||||
strbuf_addf(&key, "remote.%s.fetch", option_origin);
|
||||
strbuf_addf(&value, "+%s*:%s*", src_ref_prefix, branch_top.buf);
|
||||
git_config_set_multivar(key.buf, value.buf, "^$", 0);
|
||||
strbuf_reset(&key);
|
||||
strbuf_reset(&value);
|
||||
}
|
||||
|
||||
refspec.force = 0;
|
||||
refspec.pattern = 1;
|
||||
refspec.src = src_ref_prefix;
|
||||
refspec.dst = branch_top.buf;
|
||||
fetch_pattern = value.buf;
|
||||
refspec = parse_fetch_refspec(1, &fetch_pattern);
|
||||
|
||||
strbuf_reset(&value);
|
||||
|
||||
if (path && !is_bundle)
|
||||
refs = clone_local(path, git_dir);
|
||||
|
@ -491,7 +492,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
|
|||
if (refs) {
|
||||
clear_extra_refs();
|
||||
|
||||
mapped_refs = write_remote_refs(refs, &refspec, reflog_msg.buf);
|
||||
mapped_refs = write_remote_refs(refs, refspec, reflog_msg.buf);
|
||||
|
||||
remote_head = find_ref_by_name(refs, "HEAD");
|
||||
head_points_at = guess_remote_head(remote_head, mapped_refs, 0);
|
||||
|
|
|
@ -358,14 +358,9 @@ static int get_push_ref_states_noquery(struct ref_states *states)
|
|||
}
|
||||
for (i = 0; i < remote->push_refspec_nr; i++) {
|
||||
struct refspec *spec = remote->push + i;
|
||||
char buf[PATH_MAX];
|
||||
if (spec->matching)
|
||||
item = string_list_append("(matching)", &states->push);
|
||||
else if (spec->pattern) {
|
||||
snprintf(buf, (sizeof(buf)), "%s*", spec->src);
|
||||
item = string_list_append(buf, &states->push);
|
||||
snprintf(buf, (sizeof(buf)), "%s*", spec->dst);
|
||||
} else if (strlen(spec->src))
|
||||
else if (strlen(spec->src))
|
||||
item = string_list_append(spec->src, &states->push);
|
||||
else
|
||||
item = string_list_append("(delete)", &states->push);
|
||||
|
@ -373,10 +368,7 @@ static int get_push_ref_states_noquery(struct ref_states *states)
|
|||
info = item->util = xcalloc(sizeof(struct push_info), 1);
|
||||
info->forced = spec->force;
|
||||
info->status = PUSH_STATUS_NOTQUERIED;
|
||||
if (spec->pattern)
|
||||
info->dest = xstrdup(buf);
|
||||
else
|
||||
info->dest = xstrdup(spec->dst ? spec->dst : item->string);
|
||||
info->dest = xstrdup(spec->dst ? spec->dst : item->string);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -389,7 +381,7 @@ static int get_head_names(const struct ref *remote_refs, struct ref_states *stat
|
|||
|
||||
refspec.force = 0;
|
||||
refspec.pattern = 1;
|
||||
refspec.src = refspec.dst = "refs/heads/";
|
||||
refspec.src = refspec.dst = "refs/heads/*";
|
||||
states->heads.strdup_strings = 1;
|
||||
get_fetch_map(remote_refs, &refspec, &fetch_map_tail, 0);
|
||||
matches = guess_remote_head(find_ref_by_name(remote_refs, "HEAD"),
|
||||
|
|
15
refs.c
15
refs.c
|
@ -694,6 +694,7 @@ static inline int bad_ref_char(int ch)
|
|||
int check_ref_format(const char *ref)
|
||||
{
|
||||
int ch, level, bad_type;
|
||||
int ret = CHECK_REF_FORMAT_OK;
|
||||
const char *cp = ref;
|
||||
|
||||
level = 0;
|
||||
|
@ -709,18 +710,18 @@ int check_ref_format(const char *ref)
|
|||
return CHECK_REF_FORMAT_ERROR;
|
||||
bad_type = bad_ref_char(ch);
|
||||
if (bad_type) {
|
||||
return (bad_type == 2 && !*cp)
|
||||
? CHECK_REF_FORMAT_WILDCARD
|
||||
: CHECK_REF_FORMAT_ERROR;
|
||||
if (bad_type == 2 && (!*cp || *cp == '/') &&
|
||||
ret == CHECK_REF_FORMAT_OK)
|
||||
ret = CHECK_REF_FORMAT_WILDCARD;
|
||||
else
|
||||
return CHECK_REF_FORMAT_ERROR;
|
||||
}
|
||||
|
||||
/* scan the rest of the path component */
|
||||
while ((ch = *cp++) != 0) {
|
||||
bad_type = bad_ref_char(ch);
|
||||
if (bad_type) {
|
||||
return (bad_type == 2 && !*cp)
|
||||
? CHECK_REF_FORMAT_WILDCARD
|
||||
: CHECK_REF_FORMAT_ERROR;
|
||||
return CHECK_REF_FORMAT_ERROR;
|
||||
}
|
||||
if (ch == '/')
|
||||
break;
|
||||
|
@ -731,7 +732,7 @@ int check_ref_format(const char *ref)
|
|||
if (!ch) {
|
||||
if (level < 2)
|
||||
return CHECK_REF_FORMAT_ONELEVEL;
|
||||
return CHECK_REF_FORMAT_OK;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
88
remote.c
88
remote.c
|
@ -11,8 +11,8 @@ static struct refspec s_tag_refspec = {
|
|||
0,
|
||||
1,
|
||||
0,
|
||||
"refs/tags/",
|
||||
"refs/tags/"
|
||||
"refs/tags/*",
|
||||
"refs/tags/*"
|
||||
};
|
||||
|
||||
const struct refspec *tag_refspec = &s_tag_refspec;
|
||||
|
@ -455,16 +455,11 @@ static void read_config(void)
|
|||
*/
|
||||
static int verify_refname(char *name, int is_glob)
|
||||
{
|
||||
int result, len = -1;
|
||||
int result;
|
||||
|
||||
if (is_glob) {
|
||||
len = strlen(name);
|
||||
assert(name[len - 1] == '/');
|
||||
name[len - 1] = '\0';
|
||||
}
|
||||
result = check_ref_format(name);
|
||||
if (is_glob)
|
||||
name[len - 1] = '/';
|
||||
if (is_glob && result == CHECK_REF_FORMAT_WILDCARD)
|
||||
result = CHECK_REF_FORMAT_OK;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -520,16 +515,15 @@ static struct refspec *parse_refspec_internal(int nr_refspec, const char **refsp
|
|||
|
||||
if (rhs) {
|
||||
size_t rlen = strlen(++rhs);
|
||||
is_glob = (2 <= rlen && !strcmp(rhs + rlen - 2, "/*"));
|
||||
rs[i].dst = xstrndup(rhs, rlen - is_glob);
|
||||
is_glob = (1 <= rlen && strchr(rhs, '*'));
|
||||
rs[i].dst = xstrndup(rhs, rlen);
|
||||
}
|
||||
|
||||
llen = (rhs ? (rhs - lhs - 1) : strlen(lhs));
|
||||
if (2 <= llen && !memcmp(lhs + llen - 2, "/*", 2)) {
|
||||
if (1 <= llen && memchr(lhs, '*', llen)) {
|
||||
if ((rhs && !is_glob) || (!rhs && fetch))
|
||||
goto invalid;
|
||||
is_glob = 1;
|
||||
llen--;
|
||||
} else if (rhs && is_glob) {
|
||||
goto invalid;
|
||||
}
|
||||
|
@ -729,6 +723,41 @@ int remote_has_url(struct remote *remote, const char *url)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int match_name_with_pattern(const char *key, const char *name,
|
||||
const char *value, char **result)
|
||||
{
|
||||
const char *kstar = strchr(key, '*');
|
||||
size_t klen;
|
||||
size_t ksuffixlen;
|
||||
size_t namelen;
|
||||
int ret;
|
||||
if (!kstar)
|
||||
die("Key '%s' of pattern had no '*'", key);
|
||||
klen = kstar - key;
|
||||
ksuffixlen = strlen(kstar + 1);
|
||||
namelen = strlen(name);
|
||||
ret = !strncmp(name, key, klen) && namelen >= klen + ksuffixlen &&
|
||||
!memcmp(name + namelen - ksuffixlen, kstar + 1, ksuffixlen);
|
||||
if (ret && value) {
|
||||
const char *vstar = strchr(value, '*');
|
||||
size_t vlen;
|
||||
size_t vsuffixlen;
|
||||
if (!vstar)
|
||||
die("Value '%s' of pattern has no '*'", value);
|
||||
vlen = vstar - value;
|
||||
vsuffixlen = strlen(vstar + 1);
|
||||
*result = xmalloc(vlen + vsuffixlen +
|
||||
strlen(name) -
|
||||
klen - ksuffixlen + 1);
|
||||
strncpy(*result, value, vlen);
|
||||
strncpy(*result + vlen,
|
||||
name + klen, namelen - klen - ksuffixlen);
|
||||
strcpy(*result + vlen + namelen - klen - ksuffixlen,
|
||||
vstar + 1);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int remote_find_tracking(struct remote *remote, struct refspec *refspec)
|
||||
{
|
||||
int find_src = refspec->src == NULL;
|
||||
|
@ -752,13 +781,7 @@ int remote_find_tracking(struct remote *remote, struct refspec *refspec)
|
|||
if (!fetch->dst)
|
||||
continue;
|
||||
if (fetch->pattern) {
|
||||
if (!prefixcmp(needle, key)) {
|
||||
*result = xmalloc(strlen(value) +
|
||||
strlen(needle) -
|
||||
strlen(key) + 1);
|
||||
strcpy(*result, value);
|
||||
strcpy(*result + strlen(value),
|
||||
needle + strlen(key));
|
||||
if (match_name_with_pattern(key, needle, value, result)) {
|
||||
refspec->force = fetch->force;
|
||||
return 0;
|
||||
}
|
||||
|
@ -1041,7 +1064,8 @@ static const struct refspec *check_pattern_match(const struct refspec *rs,
|
|||
continue;
|
||||
}
|
||||
|
||||
if (rs[i].pattern && !prefixcmp(src->name, rs[i].src))
|
||||
if (rs[i].pattern && match_name_with_pattern(rs[i].src, src->name,
|
||||
NULL, NULL))
|
||||
return rs + i;
|
||||
}
|
||||
if (matching_refs != -1)
|
||||
|
@ -1095,11 +1119,9 @@ int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,
|
|||
|
||||
} 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));
|
||||
if (!match_name_with_pattern(pat->src, src->name,
|
||||
dst_side, &dst_name))
|
||||
die("Didn't think it matches any more");
|
||||
}
|
||||
dst_peer = find_ref_by_name(dst, dst_name);
|
||||
if (dst_peer) {
|
||||
|
@ -1177,19 +1199,17 @@ static struct ref *get_expanded_map(const struct ref *remote_refs,
|
|||
struct ref *ret = NULL;
|
||||
struct ref **tail = &ret;
|
||||
|
||||
int remote_prefix_len = strlen(refspec->src);
|
||||
int local_prefix_len = strlen(refspec->dst);
|
||||
char *expn_name;
|
||||
|
||||
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;
|
||||
if (match_name_with_pattern(refspec->src, ref->name,
|
||||
refspec->dst, &expn_name)) {
|
||||
struct ref *cpy = copy_ref(ref);
|
||||
match = ref->name + remote_prefix_len;
|
||||
|
||||
cpy->peer_ref = alloc_ref_with_prefix(refspec->dst,
|
||||
local_prefix_len, match);
|
||||
cpy->peer_ref = alloc_ref(expn_name);
|
||||
free(expn_name);
|
||||
if (refspec->force)
|
||||
cpy->peer_ref->force = 1;
|
||||
*tail = cpy;
|
||||
|
|
|
@ -72,4 +72,16 @@ test_refspec fetch ':refs/remotes/frotz/HEAD-to-me'
|
|||
test_refspec push ':refs/remotes/frotz/delete me' invalid
|
||||
test_refspec fetch ':refs/remotes/frotz/HEAD to me' invalid
|
||||
|
||||
test_refspec fetch 'refs/heads/*/for-linus:refs/remotes/mine/*-blah' invalid
|
||||
test_refspec push 'refs/heads/*/for-linus:refs/remotes/mine/*-blah' invalid
|
||||
|
||||
test_refspec fetch 'refs/heads*/for-linus:refs/remotes/mine/*' invalid
|
||||
test_refspec push 'refs/heads*/for-linus:refs/remotes/mine/*' invalid
|
||||
|
||||
test_refspec fetch 'refs/heads/*/*/for-linus:refs/remotes/mine/*' invalid
|
||||
test_refspec push 'refs/heads/*/*/for-linus:refs/remotes/mine/*' invalid
|
||||
|
||||
test_refspec fetch 'refs/heads/*/for-linus:refs/remotes/mine/*'
|
||||
test_refspec push 'refs/heads/*/for-linus:refs/remotes/mine/*'
|
||||
|
||||
test_done
|
||||
|
|
Загрузка…
Ссылка в новой задаче