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:
Junio C Hamano
2009-03-20 14:30:00 -07:00
5 changed files with 90 additions and 64 deletions

View File

@ -330,7 +330,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
char *src_ref_prefix = "refs/heads/"; char *src_ref_prefix = "refs/heads/";
int err = 0; int err = 0;
struct refspec refspec; struct refspec *refspec;
const char *fetch_pattern;
junk_pid = getpid(); 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(&branch_top, "refs/remotes/%s/", option_origin);
} }
strbuf_addf(&value, "+%s*:%s*", src_ref_prefix, branch_top.buf);
if (option_mirror || !option_bare) { if (option_mirror || !option_bare) {
/* Configure the remote */ /* 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) { if (option_mirror) {
strbuf_addf(&key, "remote.%s.mirror", option_origin); strbuf_addf(&key, "remote.%s.mirror", option_origin);
git_config_set(key.buf, "true"); 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); strbuf_addf(&key, "remote.%s.url", option_origin);
git_config_set(key.buf, repo); 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(&key);
strbuf_reset(&value);
} }
refspec.force = 0; fetch_pattern = value.buf;
refspec.pattern = 1; refspec = parse_fetch_refspec(1, &fetch_pattern);
refspec.src = src_ref_prefix;
refspec.dst = branch_top.buf; strbuf_reset(&value);
if (path && !is_bundle) if (path && !is_bundle)
refs = clone_local(path, git_dir); refs = clone_local(path, git_dir);
@ -491,7 +492,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
if (refs) { if (refs) {
clear_extra_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"); remote_head = find_ref_by_name(refs, "HEAD");
head_points_at = guess_remote_head(remote_head, mapped_refs, 0); head_points_at = guess_remote_head(remote_head, mapped_refs, 0);

View File

@ -358,14 +358,9 @@ static int get_push_ref_states_noquery(struct ref_states *states)
} }
for (i = 0; i < remote->push_refspec_nr; i++) { for (i = 0; i < remote->push_refspec_nr; i++) {
struct refspec *spec = remote->push + i; struct refspec *spec = remote->push + i;
char buf[PATH_MAX];
if (spec->matching) if (spec->matching)
item = string_list_append("(matching)", &states->push); item = string_list_append("(matching)", &states->push);
else if (spec->pattern) { else if (strlen(spec->src))
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))
item = string_list_append(spec->src, &states->push); item = string_list_append(spec->src, &states->push);
else else
item = string_list_append("(delete)", &states->push); 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 = item->util = xcalloc(sizeof(struct push_info), 1);
info->forced = spec->force; info->forced = spec->force;
info->status = PUSH_STATUS_NOTQUERIED; info->status = PUSH_STATUS_NOTQUERIED;
if (spec->pattern) info->dest = xstrdup(spec->dst ? spec->dst : item->string);
info->dest = xstrdup(buf);
else
info->dest = xstrdup(spec->dst ? spec->dst : item->string);
} }
return 0; return 0;
} }
@ -389,7 +381,7 @@ static int get_head_names(const struct ref *remote_refs, struct ref_states *stat
refspec.force = 0; refspec.force = 0;
refspec.pattern = 1; refspec.pattern = 1;
refspec.src = refspec.dst = "refs/heads/"; refspec.src = refspec.dst = "refs/heads/*";
states->heads.strdup_strings = 1; states->heads.strdup_strings = 1;
get_fetch_map(remote_refs, &refspec, &fetch_map_tail, 0); get_fetch_map(remote_refs, &refspec, &fetch_map_tail, 0);
matches = guess_remote_head(find_ref_by_name(remote_refs, "HEAD"), matches = guess_remote_head(find_ref_by_name(remote_refs, "HEAD"),

15
refs.c
View File

@ -694,6 +694,7 @@ static inline int bad_ref_char(int ch)
int check_ref_format(const char *ref) int check_ref_format(const char *ref)
{ {
int ch, level, bad_type; int ch, level, bad_type;
int ret = CHECK_REF_FORMAT_OK;
const char *cp = ref; const char *cp = ref;
level = 0; level = 0;
@ -709,18 +710,18 @@ int check_ref_format(const char *ref)
return CHECK_REF_FORMAT_ERROR; return CHECK_REF_FORMAT_ERROR;
bad_type = bad_ref_char(ch); bad_type = bad_ref_char(ch);
if (bad_type) { if (bad_type) {
return (bad_type == 2 && !*cp) if (bad_type == 2 && (!*cp || *cp == '/') &&
? CHECK_REF_FORMAT_WILDCARD ret == CHECK_REF_FORMAT_OK)
: CHECK_REF_FORMAT_ERROR; ret = CHECK_REF_FORMAT_WILDCARD;
else
return CHECK_REF_FORMAT_ERROR;
} }
/* scan the rest of the path component */ /* scan the rest of the path component */
while ((ch = *cp++) != 0) { while ((ch = *cp++) != 0) {
bad_type = bad_ref_char(ch); bad_type = bad_ref_char(ch);
if (bad_type) { if (bad_type) {
return (bad_type == 2 && !*cp) return CHECK_REF_FORMAT_ERROR;
? CHECK_REF_FORMAT_WILDCARD
: CHECK_REF_FORMAT_ERROR;
} }
if (ch == '/') if (ch == '/')
break; break;
@ -731,7 +732,7 @@ int check_ref_format(const char *ref)
if (!ch) { if (!ch) {
if (level < 2) if (level < 2)
return CHECK_REF_FORMAT_ONELEVEL; return CHECK_REF_FORMAT_ONELEVEL;
return CHECK_REF_FORMAT_OK; return ret;
} }
} }
} }

View File

@ -11,8 +11,8 @@ static struct refspec s_tag_refspec = {
0, 0,
1, 1,
0, 0,
"refs/tags/", "refs/tags/*",
"refs/tags/" "refs/tags/*"
}; };
const struct refspec *tag_refspec = &s_tag_refspec; 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) 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); result = check_ref_format(name);
if (is_glob) if (is_glob && result == CHECK_REF_FORMAT_WILDCARD)
name[len - 1] = '/'; result = CHECK_REF_FORMAT_OK;
return result; return result;
} }
@ -520,16 +515,15 @@ static struct refspec *parse_refspec_internal(int nr_refspec, const char **refsp
if (rhs) { if (rhs) {
size_t rlen = strlen(++rhs); size_t rlen = strlen(++rhs);
is_glob = (2 <= rlen && !strcmp(rhs + rlen - 2, "/*")); is_glob = (1 <= rlen && strchr(rhs, '*'));
rs[i].dst = xstrndup(rhs, rlen - is_glob); rs[i].dst = xstrndup(rhs, rlen);
} }
llen = (rhs ? (rhs - lhs - 1) : strlen(lhs)); 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)) if ((rhs && !is_glob) || (!rhs && fetch))
goto invalid; goto invalid;
is_glob = 1; is_glob = 1;
llen--;
} else if (rhs && is_glob) { } else if (rhs && is_glob) {
goto invalid; goto invalid;
} }
@ -729,6 +723,41 @@ int remote_has_url(struct remote *remote, const char *url)
return 0; 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 remote_find_tracking(struct remote *remote, struct refspec *refspec)
{ {
int find_src = refspec->src == NULL; int find_src = refspec->src == NULL;
@ -752,13 +781,7 @@ int remote_find_tracking(struct remote *remote, struct refspec *refspec)
if (!fetch->dst) if (!fetch->dst)
continue; continue;
if (fetch->pattern) { if (fetch->pattern) {
if (!prefixcmp(needle, key)) { if (match_name_with_pattern(key, needle, value, result)) {
*result = xmalloc(strlen(value) +
strlen(needle) -
strlen(key) + 1);
strcpy(*result, value);
strcpy(*result + strlen(value),
needle + strlen(key));
refspec->force = fetch->force; refspec->force = fetch->force;
return 0; return 0;
} }
@ -1041,7 +1064,8 @@ static const struct refspec *check_pattern_match(const struct refspec *rs,
continue; 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; return rs + i;
} }
if (matching_refs != -1) if (matching_refs != -1)
@ -1095,11 +1119,9 @@ int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,
} else { } 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) + if (!match_name_with_pattern(pat->src, src->name,
strlen(src->name) - dst_side, &dst_name))
strlen(pat->src) + 2); die("Didn't think it matches any more");
strcpy(dst_name, dst_side);
strcat(dst_name, src->name + strlen(pat->src));
} }
dst_peer = find_ref_by_name(dst, dst_name); dst_peer = find_ref_by_name(dst, dst_name);
if (dst_peer) { if (dst_peer) {
@ -1177,19 +1199,17 @@ static struct ref *get_expanded_map(const struct ref *remote_refs,
struct ref *ret = NULL; struct ref *ret = NULL;
struct ref **tail = &ret; struct ref **tail = &ret;
int remote_prefix_len = strlen(refspec->src); char *expn_name;
int local_prefix_len = strlen(refspec->dst);
for (ref = remote_refs; ref; ref = ref->next) { for (ref = remote_refs; ref; ref = ref->next) {
if (strchr(ref->name, '^')) if (strchr(ref->name, '^'))
continue; /* a dereference item */ continue; /* a dereference item */
if (!prefixcmp(ref->name, refspec->src)) { if (match_name_with_pattern(refspec->src, ref->name,
const char *match; refspec->dst, &expn_name)) {
struct ref *cpy = copy_ref(ref); struct ref *cpy = copy_ref(ref);
match = ref->name + remote_prefix_len;
cpy->peer_ref = alloc_ref_with_prefix(refspec->dst, cpy->peer_ref = alloc_ref(expn_name);
local_prefix_len, match); free(expn_name);
if (refspec->force) if (refspec->force)
cpy->peer_ref->force = 1; cpy->peer_ref->force = 1;
*tail = cpy; *tail = cpy;

View File

@ -72,4 +72,16 @@ test_refspec fetch ':refs/remotes/frotz/HEAD-to-me'
test_refspec push ':refs/remotes/frotz/delete me' invalid test_refspec push ':refs/remotes/frotz/delete me' invalid
test_refspec fetch ':refs/remotes/frotz/HEAD to 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 test_done