Add matching and parsing for fetch-side refspec rules

Also exports parse_ref_spec().

Signed-off-by: Daniel Barkalow <barkalow@iabervon.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Daniel Barkalow 2007-09-10 23:03:08 -04:00 коммит произвёл Junio C Hamano
Родитель 9b288516ee
Коммит d71ab17470
2 изменённых файлов: 148 добавлений и 1 удалений

125
remote.c
Просмотреть файл

@ -208,6 +208,7 @@ static void read_branches_file(struct remote *remote)
}
add_uri(remote, p);
add_fetch_refspec(remote, branch);
remote->fetch_tags = 1; /* always auto-follow */
}
static int handle_config(const char *key, const char *value)
@ -274,6 +275,9 @@ static int handle_config(const char *key, const char *value)
remote->uploadpack = xstrdup(value);
else
error("more than one uploadpack given, using the first");
} else if (!strcmp(subkey, ".tagopt")) {
if (!strcmp(value, "--no-tags"))
remote->fetch_tags = -1;
}
return 0;
}
@ -296,7 +300,7 @@ static void read_config(void)
git_config(handle_config);
}
static struct refspec *parse_ref_spec(int nr_refspec, const char **refspec)
struct refspec *parse_ref_spec(int nr_refspec, const char **refspec)
{
int i;
struct refspec *rs = xcalloc(sizeof(*rs), nr_refspec);
@ -352,6 +356,10 @@ struct remote *remote_get(const char *name)
add_uri(ret, name);
if (!ret->uri)
return NULL;
if (!strcmp(name, ".")) {
// we always fetch "refs/*:refs/*", which is trivial
add_fetch_refspec(ret, "refs/*:refs/*");
}
ret->fetch = parse_ref_spec(ret->fetch_refspec_nr, ret->fetch_refspec);
ret->push = parse_ref_spec(ret->push_refspec_nr, ret->push_refspec);
return ret;
@ -454,6 +462,14 @@ struct ref *alloc_ref(unsigned namelen)
return ret;
}
static struct ref *copy_ref(struct ref *ref)
{
struct ref *ret = xmalloc(sizeof(struct ref) + strlen(ref->name) + 1);
memcpy(ret, ref, sizeof(struct ref) + strlen(ref->name) + 1);
ret->next = NULL;
return ret;
}
void free_refs(struct ref *ref)
{
struct ref *next;
@ -771,3 +787,110 @@ int branch_merges(struct branch *branch, const char *refname)
}
return 0;
}
static struct ref *get_expanded_map(struct ref *remote_refs,
const struct refspec *refspec)
{
struct ref *ref;
struct ref *ret = NULL;
struct ref **tail = &ret;
int remote_prefix_len = strlen(refspec->src);
int local_prefix_len = strlen(refspec->dst);
for (ref = remote_refs; ref; ref = ref->next) {
if (strchr(ref->name, '^'))
continue; /* a dereference item */
if (!prefixcmp(ref->name, refspec->src)) {
char *match;
struct ref *cpy = copy_ref(ref);
match = ref->name + remote_prefix_len;
cpy->peer_ref = alloc_ref(local_prefix_len +
strlen(match) + 1);
sprintf(cpy->peer_ref->name, "%s%s",
refspec->dst, match);
if (refspec->force)
cpy->peer_ref->force = 1;
*tail = cpy;
tail = &cpy->next;
}
}
return ret;
}
static struct ref *find_ref_by_name_abbrev(struct ref *refs, const char *name)
{
struct ref *ref;
for (ref = refs; ref; ref = ref->next) {
if (ref_matches_abbrev(name, ref->name))
return ref;
}
return NULL;
}
struct ref *get_remote_ref(struct ref *remote_refs, const char *name)
{
struct ref *ref = find_ref_by_name_abbrev(remote_refs, name);
if (!ref)
die("Couldn't find remote ref %s\n", name);
return copy_ref(ref);
}
static struct ref *get_local_ref(const char *name)
{
struct ref *ret;
if (!name)
return NULL;
if (!prefixcmp(name, "refs/")) {
ret = alloc_ref(strlen(name) + 1);
strcpy(ret->name, name);
return ret;
}
if (!prefixcmp(name, "heads/") ||
!prefixcmp(name, "tags/") ||
!prefixcmp(name, "remotes/")) {
ret = alloc_ref(strlen(name) + 6);
sprintf(ret->name, "refs/%s", name);
return ret;
}
ret = alloc_ref(strlen(name) + 12);
sprintf(ret->name, "refs/heads/%s", name);
return ret;
}
int get_fetch_map(struct ref *remote_refs,
const struct refspec *refspec,
struct ref ***tail)
{
struct ref *ref_map, *rm;
if (refspec->pattern) {
ref_map = get_expanded_map(remote_refs, refspec);
} else {
ref_map = get_remote_ref(remote_refs,
refspec->src[0] ?
refspec->src : "HEAD");
ref_map->peer_ref = get_local_ref(refspec->dst);
if (refspec->force)
ref_map->peer_ref->force = 1;
}
for (rm = ref_map; rm; rm = rm->next) {
if (rm->peer_ref && check_ref_format(rm->peer_ref->name + 5))
die("* refusing to create funny ref '%s' locally",
rm->peer_ref->name);
}
tail_link_ref(ref_map, tail);
return 0;
}

Просмотреть файл

@ -15,6 +15,14 @@ struct remote {
struct refspec *fetch;
int fetch_refspec_nr;
/*
* -1 to never fetch tags
* 0 to auto-follow tags on heuristic (default)
* 1 to always auto-follow tags
* 2 to always fetch tags
*/
int fetch_tags;
const char *receivepack;
const char *uploadpack;
};
@ -41,9 +49,25 @@ struct ref *alloc_ref(unsigned namelen);
*/
void free_refs(struct ref *ref);
struct refspec *parse_ref_spec(int nr_refspec, const char **refspec);
int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,
int nr_refspec, char **refspec, int all);
/*
* Given a list of the remote refs and the specification of things to
* fetch, makes a (separate) list of the refs to fetch and the local
* refs to store into.
*
* *tail is the pointer to the tail pointer of the list of results
* beforehand, and will be set to the tail pointer of the list of
* results afterward.
*/
int get_fetch_map(struct ref *remote_refs, const struct refspec *refspec,
struct ref ***tail);
struct ref *get_remote_ref(struct ref *remote_refs, const char *name);
/*
* For the given remote, reads the refspec's src and sets the other fields.
*/