diff options
Diffstat (limited to 'remote.c')
| -rw-r--r-- | remote.c | 176 | 
1 files changed, 82 insertions, 94 deletions
@@ -493,23 +493,6 @@ static void read_config(void)  }  /* - * We need to make sure the tracking branches are well formed, but a - * wildcard refspec in "struct refspec" must have a trailing slash. We - * temporarily drop the trailing '/' while calling check_ref_format(), - * and put it back.  The caller knows that a CHECK_REF_FORMAT_ONELEVEL - * error return is Ok for a wildcard refspec. - */ -static int verify_refname(char *name, int is_glob) -{ -	int result; - -	result = check_ref_format(name); -	if (is_glob && result == CHECK_REF_FORMAT_WILDCARD) -		result = CHECK_REF_FORMAT_OK; -	return result; -} - -/*   * This function frees a refspec array.   * Warning: code paths should be checked to ensure that the src   *          and dst pointers are always freeable pointers as well @@ -532,13 +515,13 @@ static void free_refspecs(struct refspec *refspec, int nr_refspec)  static struct refspec *parse_refspec_internal(int nr_refspec, const char **refspec, int fetch, int verify)  {  	int i; -	int st;  	struct refspec *rs = xcalloc(sizeof(*rs), nr_refspec);  	for (i = 0; i < nr_refspec; i++) {  		size_t llen;  		int is_glob;  		const char *lhs, *rhs; +		int flags;  		is_glob = 0; @@ -576,6 +559,7 @@ static struct refspec *parse_refspec_internal(int nr_refspec, const char **refsp  		rs[i].pattern = is_glob;  		rs[i].src = xstrndup(lhs, llen); +		flags = REFNAME_ALLOW_ONELEVEL | (is_glob ? REFNAME_REFSPEC_PATTERN : 0);  		if (fetch) {  			/* @@ -585,26 +569,20 @@ static struct refspec *parse_refspec_internal(int nr_refspec, const char **refsp  			 */  			if (!*rs[i].src)  				; /* empty is ok */ -			else { -				st = verify_refname(rs[i].src, is_glob); -				if (st && st != CHECK_REF_FORMAT_ONELEVEL) -					goto invalid; -			} +			else if (check_refname_format(rs[i].src, flags)) +				goto invalid;  			/*  			 * RHS  			 * - missing is ok, and is same as empty.  			 * - empty is ok; it means not to store.  			 * - otherwise it must be a valid looking ref.  			 */ -			if (!rs[i].dst) { +			if (!rs[i].dst)  				; /* ok */ -			} else if (!*rs[i].dst) { +			else if (!*rs[i].dst)  				; /* ok */ -			} else { -				st = verify_refname(rs[i].dst, is_glob); -				if (st && st != CHECK_REF_FORMAT_ONELEVEL) -					goto invalid; -			} +			else if (check_refname_format(rs[i].dst, flags)) +				goto invalid;  		} else {  			/*  			 * LHS @@ -616,8 +594,7 @@ static struct refspec *parse_refspec_internal(int nr_refspec, const char **refsp  			if (!*rs[i].src)  				; /* empty is ok */  			else if (is_glob) { -				st = verify_refname(rs[i].src, is_glob); -				if (st && st != CHECK_REF_FORMAT_ONELEVEL) +				if (check_refname_format(rs[i].src, flags))  					goto invalid;  			}  			else @@ -630,14 +607,12 @@ static struct refspec *parse_refspec_internal(int nr_refspec, const char **refsp  			 * - otherwise it must be a valid looking ref.  			 */  			if (!rs[i].dst) { -				st = verify_refname(rs[i].src, is_glob); -				if (st && st != CHECK_REF_FORMAT_ONELEVEL) +				if (check_refname_format(rs[i].src, flags))  					goto invalid;  			} else if (!*rs[i].dst) {  				goto invalid;  			} else { -				st = verify_refname(rs[i].dst, is_glob); -				if (st && st != CHECK_REF_FORMAT_ONELEVEL) +				if (check_refname_format(rs[i].dst, flags))  					goto invalid;  			}  		} @@ -828,59 +803,56 @@ static int match_name_with_pattern(const char *key, const char *name,  	return ret;  } -char *apply_refspecs(struct refspec *refspecs, int nr_refspec, -		     const char *name) +static int query_refspecs(struct refspec *refs, int ref_count, struct refspec *query)  {  	int i; -	char *ret = NULL; -	for (i = 0; i < nr_refspec; i++) { -		struct refspec *refspec = refspecs + i; -		if (refspec->pattern) { -			if (match_name_with_pattern(refspec->src, name, -						    refspec->dst, &ret)) -				return ret; -		} else if (!strcmp(refspec->src, name)) -			return strdup(refspec->dst); -	} -	return NULL; -} +	int find_src = !query->src; -int remote_find_tracking(struct remote *remote, struct refspec *refspec) -{ -	int find_src = refspec->src == NULL; -	char *needle, **result; -	int i; +	if (find_src && !query->dst) +		return error("query_refspecs: need either src or dst"); -	if (find_src) { -		if (!refspec->dst) -			return error("find_tracking: need either src or dst"); -		needle = refspec->dst; -		result = &refspec->src; -	} else { -		needle = refspec->src; -		result = &refspec->dst; -	} +	for (i = 0; i < ref_count; i++) { +		struct refspec *refspec = &refs[i]; +		const char *key = find_src ? refspec->dst : refspec->src; +		const char *value = find_src ? refspec->src : refspec->dst; +		const char *needle = find_src ? query->dst : query->src; +		char **result = find_src ? &query->src : &query->dst; -	for (i = 0; i < remote->fetch_refspec_nr; i++) { -		struct refspec *fetch = &remote->fetch[i]; -		const char *key = find_src ? fetch->dst : fetch->src; -		const char *value = find_src ? fetch->src : fetch->dst; -		if (!fetch->dst) +		if (!refspec->dst)  			continue; -		if (fetch->pattern) { +		if (refspec->pattern) {  			if (match_name_with_pattern(key, needle, value, result)) { -				refspec->force = fetch->force; +				query->force = refspec->force;  				return 0;  			}  		} else if (!strcmp(needle, key)) {  			*result = xstrdup(value); -			refspec->force = fetch->force; +			query->force = refspec->force;  			return 0;  		}  	}  	return -1;  } +char *apply_refspecs(struct refspec *refspecs, int nr_refspec, +		     const char *name) +{ +	struct refspec query; + +	memset(&query, 0, sizeof(struct refspec)); +	query.src = (char *)name; + +	if (query_refspecs(refspecs, nr_refspec, &query)) +		return NULL; + +	return query.dst; +} + +int remote_find_tracking(struct remote *remote, struct refspec *refspec) +{ +	return query_refspecs(remote->fetch, remote->fetch_refspec_nr, refspec); +} +  static struct ref *alloc_ref_with_prefix(const char *prefix, size_t prefixlen,  		const char *name)  { @@ -896,7 +868,7 @@ struct ref *alloc_ref(const char *name)  	return alloc_ref_with_prefix("", 0, name);  } -static struct ref *copy_ref(const struct ref *ref) +struct ref *copy_ref(const struct ref *ref)  {  	struct ref *cpy;  	size_t len; @@ -1170,12 +1142,15 @@ static struct ref **tail_ref(struct ref **head)  }  /* - * Note. This is used only by "push"; refspec matching rules for - * push and fetch are subtly different, so do not try to reuse it - * without thinking. + * Given the set of refs the local repository has, the set of refs the + * remote repository has, and the refspec used for push, determine + * what remote refs we will update and with what value by setting + * peer_ref (which object is being pushed) and force (if the push is + * forced) in elements of "dst". The function may add new elements to + * dst (e.g. pushing to a new branch, done in match_explicit_refs).   */ -int match_refs(struct ref *src, struct ref **dst, -	       int nr_refspec, const char **refspec, int flags) +int match_push_refs(struct ref *src, struct ref **dst, +		    int nr_refspec, const char **refspec, int flags)  {  	struct refspec *rs;  	int send_all = flags & MATCH_REFS_ALL; @@ -1427,8 +1402,8 @@ int get_fetch_map(const struct ref *remote_refs,  	for (rmp = &ref_map; *rmp; ) {  		if ((*rmp)->peer_ref) { -			int st = check_ref_format((*rmp)->peer_ref->name + 5); -			if (st && st != CHECK_REF_FORMAT_ONELEVEL) { +			if (check_refname_format((*rmp)->peer_ref->name + 5, +				REFNAME_ALLOW_ONELEVEL)) {  				struct ref *ignore = *rmp;  				error("* Ignoring funny ref '%s' locally",  				      (*rmp)->peer_ref->name); @@ -1620,7 +1595,7 @@ static int one_local_ref(const char *refname, const unsigned char *sha1, int fla  	int len;  	/* we already know it starts with refs/ to get here */ -	if (check_ref_format(refname + 5)) +	if (check_refname_format(refname + 5, 0))  		return 0;  	len = strlen(refname) + 1; @@ -1667,7 +1642,9 @@ struct ref *guess_remote_head(const struct ref *head,  	/* Look for another ref that points there */  	for (r = refs; r; r = r->next) { -		if (r != head && !hashcmp(r->old_sha1, head->old_sha1)) { +		if (r != head && +		    !prefixcmp(r->name, "refs/heads/") && +		    !hashcmp(r->old_sha1, head->old_sha1)) {  			*tail = copy_ref(r);  			tail = &((*tail)->next);  			if (!all) @@ -1679,36 +1656,47 @@ struct ref *guess_remote_head(const struct ref *head,  }  struct stale_heads_info { -	struct remote *remote;  	struct string_list *ref_names;  	struct ref **stale_refs_tail; +	struct refspec *refs; +	int ref_count;  };  static int get_stale_heads_cb(const char *refname,  	const unsigned char *sha1, int flags, void *cb_data)  {  	struct stale_heads_info *info = cb_data; -	struct refspec refspec; -	memset(&refspec, 0, sizeof(refspec)); -	refspec.dst = (char *)refname; -	if (!remote_find_tracking(info->remote, &refspec)) { -		if (!((flags & REF_ISSYMREF) || -		    string_list_has_string(info->ref_names, refspec.src))) { -			struct ref *ref = make_linked_ref(refname, &info->stale_refs_tail); -			hashcpy(ref->new_sha1, sha1); -		} +	struct refspec query; +	memset(&query, 0, sizeof(struct refspec)); +	query.dst = (char *)refname; + +	if (query_refspecs(info->refs, info->ref_count, &query)) +		return 0; /* No matches */ + +	/* +	 * If we did find a suitable refspec and it's not a symref and +	 * it's not in the list of refs that currently exist in that +	 * remote we consider it to be stale. +	 */ +	if (!((flags & REF_ISSYMREF) || +	      string_list_has_string(info->ref_names, query.src))) { +		struct ref *ref = make_linked_ref(refname, &info->stale_refs_tail); +		hashcpy(ref->new_sha1, sha1);  	} + +	free(query.src);  	return 0;  } -struct ref *get_stale_heads(struct remote *remote, struct ref *fetch_map) +struct ref *get_stale_heads(struct refspec *refs, int ref_count, struct ref *fetch_map)  {  	struct ref *ref, *stale_refs = NULL;  	struct string_list ref_names = STRING_LIST_INIT_NODUP;  	struct stale_heads_info info; -	info.remote = remote;  	info.ref_names = &ref_names;  	info.stale_refs_tail = &stale_refs; +	info.refs = refs; +	info.ref_count = ref_count;  	for (ref = fetch_map; ref; ref = ref->next)  		string_list_append(&ref_names, ref->name);  	sort_string_list(&ref_names);  | 
