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:
parent
9b288516ee
commit
d71ab17470
125
remote.c
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;
|
||||
}
|
||||
|
24
remote.h
24
remote.h
@ -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.
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user