Move refspec parser from connect.c and cache.h to remote.{c,h}
Signed-off-by: Daniel Barkalow <barkalow@iabervon.org> Signed-off-by: Junio C Hamano <junkio@cox.net>maint
							parent
							
								
									5751f49010
								
							
						
					
					
						commit
						6b62816cb1
					
				
							
								
								
									
										2
									
								
								cache.h
								
								
								
								
							
							
						
						
									
										2
									
								
								cache.h
								
								
								
								
							|  | @ -467,8 +467,6 @@ struct ref { | ||||||
| extern pid_t git_connect(int fd[2], char *url, const char *prog, int flags); | extern pid_t git_connect(int fd[2], char *url, const char *prog, int flags); | ||||||
| extern int finish_connect(pid_t pid); | extern int finish_connect(pid_t pid); | ||||||
| extern int path_match(const char *path, int nr, char **match); | extern int path_match(const char *path, int nr, char **match); | ||||||
| extern int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail, |  | ||||||
| 		      int nr_refspec, char **refspec, int all); |  | ||||||
| extern int get_ack(int fd, unsigned char *result_sha1); | extern int get_ack(int fd, unsigned char *result_sha1); | ||||||
| extern struct ref **get_remote_heads(int in, struct ref **list, int nr_match, char **match, unsigned int flags); | extern struct ref **get_remote_heads(int in, struct ref **list, int nr_match, char **match, unsigned int flags); | ||||||
| extern int server_supports(const char *feature); | extern int server_supports(const char *feature); | ||||||
|  |  | ||||||
							
								
								
									
										240
									
								
								connect.c
								
								
								
								
							
							
						
						
									
										240
									
								
								connect.c
								
								
								
								
							|  | @ -4,6 +4,7 @@ | ||||||
| #include "quote.h" | #include "quote.h" | ||||||
| #include "refs.h" | #include "refs.h" | ||||||
| #include "run-command.h" | #include "run-command.h" | ||||||
|  | #include "remote.h" | ||||||
|  |  | ||||||
| static char *server_capabilities; | static char *server_capabilities; | ||||||
|  |  | ||||||
|  | @ -128,245 +129,6 @@ int path_match(const char *path, int nr, char **match) | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| struct refspec { |  | ||||||
| 	char *src; |  | ||||||
| 	char *dst; |  | ||||||
| 	char force; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| /* |  | ||||||
|  * A:B means fast forward remote B with local A. |  | ||||||
|  * +A:B means overwrite remote B with local A. |  | ||||||
|  * +A is a shorthand for +A:A. |  | ||||||
|  * A is a shorthand for A:A. |  | ||||||
|  * :B means delete remote B. |  | ||||||
|  */ |  | ||||||
| static struct refspec *parse_ref_spec(int nr_refspec, char **refspec) |  | ||||||
| { |  | ||||||
| 	int i; |  | ||||||
| 	struct refspec *rs = xcalloc(sizeof(*rs), (nr_refspec + 1)); |  | ||||||
| 	for (i = 0; i < nr_refspec; i++) { |  | ||||||
| 		char *sp, *dp, *ep; |  | ||||||
| 		sp = refspec[i]; |  | ||||||
| 		if (*sp == '+') { |  | ||||||
| 			rs[i].force = 1; |  | ||||||
| 			sp++; |  | ||||||
| 		} |  | ||||||
| 		ep = strchr(sp, ':'); |  | ||||||
| 		if (ep) { |  | ||||||
| 			dp = ep + 1; |  | ||||||
| 			*ep = 0; |  | ||||||
| 		} |  | ||||||
| 		else |  | ||||||
| 			dp = sp; |  | ||||||
| 		rs[i].src = sp; |  | ||||||
| 		rs[i].dst = dp; |  | ||||||
| 	} |  | ||||||
| 	rs[nr_refspec].src = rs[nr_refspec].dst = NULL; |  | ||||||
| 	return rs; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static int count_refspec_match(const char *pattern, |  | ||||||
| 			       struct ref *refs, |  | ||||||
| 			       struct ref **matched_ref) |  | ||||||
| { |  | ||||||
| 	int patlen = strlen(pattern); |  | ||||||
| 	struct ref *matched_weak = NULL; |  | ||||||
| 	struct ref *matched = NULL; |  | ||||||
| 	int weak_match = 0; |  | ||||||
| 	int match = 0; |  | ||||||
|  |  | ||||||
| 	for (weak_match = match = 0; refs; refs = refs->next) { |  | ||||||
| 		char *name = refs->name; |  | ||||||
| 		int namelen = strlen(name); |  | ||||||
| 		int weak_match; |  | ||||||
|  |  | ||||||
| 		if (namelen < patlen || |  | ||||||
| 		    memcmp(name + namelen - patlen, pattern, patlen)) |  | ||||||
| 			continue; |  | ||||||
| 		if (namelen != patlen && name[namelen - patlen - 1] != '/') |  | ||||||
| 			continue; |  | ||||||
|  |  | ||||||
| 		/* A match is "weak" if it is with refs outside |  | ||||||
| 		 * heads or tags, and did not specify the pattern |  | ||||||
| 		 * in full (e.g. "refs/remotes/origin/master") or at |  | ||||||
| 		 * least from the toplevel (e.g. "remotes/origin/master"); |  | ||||||
| 		 * otherwise "git push $URL master" would result in |  | ||||||
| 		 * ambiguity between remotes/origin/master and heads/master |  | ||||||
| 		 * at the remote site. |  | ||||||
| 		 */ |  | ||||||
| 		if (namelen != patlen && |  | ||||||
| 		    patlen != namelen - 5 && |  | ||||||
| 		    prefixcmp(name, "refs/heads/") && |  | ||||||
| 		    prefixcmp(name, "refs/tags/")) { |  | ||||||
| 			/* We want to catch the case where only weak |  | ||||||
| 			 * matches are found and there are multiple |  | ||||||
| 			 * matches, and where more than one strong |  | ||||||
| 			 * matches are found, as ambiguous.  One |  | ||||||
| 			 * strong match with zero or more weak matches |  | ||||||
| 			 * are acceptable as a unique match. |  | ||||||
| 			 */ |  | ||||||
| 			matched_weak = refs; |  | ||||||
| 			weak_match++; |  | ||||||
| 		} |  | ||||||
| 		else { |  | ||||||
| 			matched = refs; |  | ||||||
| 			match++; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	if (!matched) { |  | ||||||
| 		*matched_ref = matched_weak; |  | ||||||
| 		return weak_match; |  | ||||||
| 	} |  | ||||||
| 	else { |  | ||||||
| 		*matched_ref = matched; |  | ||||||
| 		return match; |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static void link_dst_tail(struct ref *ref, struct ref ***tail) |  | ||||||
| { |  | ||||||
| 	**tail = ref; |  | ||||||
| 	*tail = &ref->next; |  | ||||||
| 	**tail = NULL; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static struct ref *try_explicit_object_name(const char *name) |  | ||||||
| { |  | ||||||
| 	unsigned char sha1[20]; |  | ||||||
| 	struct ref *ref; |  | ||||||
| 	int len; |  | ||||||
|  |  | ||||||
| 	if (!*name) { |  | ||||||
| 		ref = xcalloc(1, sizeof(*ref) + 20); |  | ||||||
| 		strcpy(ref->name, "(delete)"); |  | ||||||
| 		hashclr(ref->new_sha1); |  | ||||||
| 		return ref; |  | ||||||
| 	} |  | ||||||
| 	if (get_sha1(name, sha1)) |  | ||||||
| 		return NULL; |  | ||||||
| 	len = strlen(name) + 1; |  | ||||||
| 	ref = xcalloc(1, sizeof(*ref) + len); |  | ||||||
| 	memcpy(ref->name, name, len); |  | ||||||
| 	hashcpy(ref->new_sha1, sha1); |  | ||||||
| 	return ref; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static int match_explicit_refs(struct ref *src, struct ref *dst, |  | ||||||
| 			       struct ref ***dst_tail, struct refspec *rs) |  | ||||||
| { |  | ||||||
| 	int i, errs; |  | ||||||
| 	for (i = errs = 0; rs[i].src; i++) { |  | ||||||
| 		struct ref *matched_src, *matched_dst; |  | ||||||
|  |  | ||||||
| 		matched_src = matched_dst = NULL; |  | ||||||
| 		switch (count_refspec_match(rs[i].src, src, &matched_src)) { |  | ||||||
| 		case 1: |  | ||||||
| 			break; |  | ||||||
| 		case 0: |  | ||||||
| 			/* The source could be in the get_sha1() format |  | ||||||
| 			 * not a reference name.  :refs/other is a |  | ||||||
| 			 * way to delete 'other' ref at the remote end. |  | ||||||
| 			 */ |  | ||||||
| 			matched_src = try_explicit_object_name(rs[i].src); |  | ||||||
| 			if (matched_src) |  | ||||||
| 				break; |  | ||||||
| 			errs = 1; |  | ||||||
| 			error("src refspec %s does not match any.", |  | ||||||
| 			      rs[i].src); |  | ||||||
| 			break; |  | ||||||
| 		default: |  | ||||||
| 			errs = 1; |  | ||||||
| 			error("src refspec %s matches more than one.", |  | ||||||
| 			      rs[i].src); |  | ||||||
| 			break; |  | ||||||
| 		} |  | ||||||
| 		switch (count_refspec_match(rs[i].dst, dst, &matched_dst)) { |  | ||||||
| 		case 1: |  | ||||||
| 			break; |  | ||||||
| 		case 0: |  | ||||||
| 			if (!memcmp(rs[i].dst, "refs/", 5)) { |  | ||||||
| 				int len = strlen(rs[i].dst) + 1; |  | ||||||
| 				matched_dst = xcalloc(1, sizeof(*dst) + len); |  | ||||||
| 				memcpy(matched_dst->name, rs[i].dst, len); |  | ||||||
| 				link_dst_tail(matched_dst, dst_tail); |  | ||||||
| 			} |  | ||||||
| 			else if (!strcmp(rs[i].src, rs[i].dst) && |  | ||||||
| 				 matched_src) { |  | ||||||
| 				/* pushing "master:master" when |  | ||||||
| 				 * remote does not have master yet. |  | ||||||
| 				 */ |  | ||||||
| 				int len = strlen(matched_src->name) + 1; |  | ||||||
| 				matched_dst = xcalloc(1, sizeof(*dst) + len); |  | ||||||
| 				memcpy(matched_dst->name, matched_src->name, |  | ||||||
| 				       len); |  | ||||||
| 				link_dst_tail(matched_dst, dst_tail); |  | ||||||
| 			} |  | ||||||
| 			else { |  | ||||||
| 				errs = 1; |  | ||||||
| 				error("dst refspec %s does not match any " |  | ||||||
| 				      "existing ref on the remote and does " |  | ||||||
| 				      "not start with refs/.", rs[i].dst); |  | ||||||
| 			} |  | ||||||
| 			break; |  | ||||||
| 		default: |  | ||||||
| 			errs = 1; |  | ||||||
| 			error("dst refspec %s matches more than one.", |  | ||||||
| 			      rs[i].dst); |  | ||||||
| 			break; |  | ||||||
| 		} |  | ||||||
| 		if (errs) |  | ||||||
| 			continue; |  | ||||||
| 		if (matched_dst->peer_ref) { |  | ||||||
| 			errs = 1; |  | ||||||
| 			error("dst ref %s receives from more than one src.", |  | ||||||
| 			      matched_dst->name); |  | ||||||
| 		} |  | ||||||
| 		else { |  | ||||||
| 			matched_dst->peer_ref = matched_src; |  | ||||||
| 			matched_dst->force = rs[i].force; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return -errs; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static struct ref *find_ref_by_name(struct ref *list, const char *name) |  | ||||||
| { |  | ||||||
| 	for ( ; list; list = list->next) |  | ||||||
| 		if (!strcmp(list->name, name)) |  | ||||||
| 			return list; |  | ||||||
| 	return NULL; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail, |  | ||||||
| 	       int nr_refspec, char **refspec, int all) |  | ||||||
| { |  | ||||||
| 	struct refspec *rs = parse_ref_spec(nr_refspec, refspec); |  | ||||||
|  |  | ||||||
| 	if (nr_refspec) |  | ||||||
| 		return match_explicit_refs(src, dst, dst_tail, rs); |  | ||||||
|  |  | ||||||
| 	/* pick the remainder */ |  | ||||||
| 	for ( ; src; src = src->next) { |  | ||||||
| 		struct ref *dst_peer; |  | ||||||
| 		if (src->peer_ref) |  | ||||||
| 			continue; |  | ||||||
| 		dst_peer = find_ref_by_name(dst, src->name); |  | ||||||
| 		if ((dst_peer && dst_peer->peer_ref) || (!dst_peer && !all)) |  | ||||||
| 			continue; |  | ||||||
| 		if (!dst_peer) { |  | ||||||
| 			/* Create a new one and link it */ |  | ||||||
| 			int len = strlen(src->name) + 1; |  | ||||||
| 			dst_peer = xcalloc(1, sizeof(*dst_peer) + len); |  | ||||||
| 			memcpy(dst_peer->name, src->name, len); |  | ||||||
| 			hashcpy(dst_peer->new_sha1, src->new_sha1); |  | ||||||
| 			link_dst_tail(dst_peer, dst_tail); |  | ||||||
| 		} |  | ||||||
| 		dst_peer->peer_ref = src; |  | ||||||
| 	} |  | ||||||
| 	return 0; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| enum protocol { | enum protocol { | ||||||
| 	PROTO_LOCAL = 1, | 	PROTO_LOCAL = 1, | ||||||
| 	PROTO_SSH, | 	PROTO_SSH, | ||||||
|  |  | ||||||
|  | @ -9,6 +9,7 @@ | ||||||
| #include "diff.h" | #include "diff.h" | ||||||
| #include "revision.h" | #include "revision.h" | ||||||
| #include "exec_cmd.h" | #include "exec_cmd.h" | ||||||
|  | #include "remote.h" | ||||||
|  |  | ||||||
| #include <expat.h> | #include <expat.h> | ||||||
|  |  | ||||||
|  |  | ||||||
							
								
								
									
										246
									
								
								remote.c
								
								
								
								
							
							
						
						
									
										246
									
								
								remote.c
								
								
								
								
							|  | @ -201,6 +201,44 @@ static void read_config(void) | ||||||
| 	git_config(handle_config); | 	git_config(handle_config); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | static struct refspec *parse_ref_spec(int nr_refspec, const char **refspec) | ||||||
|  | { | ||||||
|  | 	int i; | ||||||
|  | 	struct refspec *rs = xcalloc(sizeof(*rs), nr_refspec); | ||||||
|  | 	for (i = 0; i < nr_refspec; i++) { | ||||||
|  | 		const char *sp, *ep, *gp; | ||||||
|  | 		sp = refspec[i]; | ||||||
|  | 		if (*sp == '+') { | ||||||
|  | 			rs[i].force = 1; | ||||||
|  | 			sp++; | ||||||
|  | 		} | ||||||
|  | 		gp = strchr(sp, '*'); | ||||||
|  | 		ep = strchr(sp, ':'); | ||||||
|  | 		if (gp && ep && gp > ep) | ||||||
|  | 			gp = NULL; | ||||||
|  | 		if (ep) { | ||||||
|  | 			if (ep[1]) { | ||||||
|  | 				const char *glob = strchr(ep + 1, '*'); | ||||||
|  | 				if (!glob) | ||||||
|  | 					gp = NULL; | ||||||
|  | 				if (gp) | ||||||
|  | 					rs[i].dst = xstrndup(ep + 1, | ||||||
|  | 							     glob - ep - 1); | ||||||
|  | 				else | ||||||
|  | 					rs[i].dst = xstrdup(ep + 1); | ||||||
|  | 			} | ||||||
|  | 		} else { | ||||||
|  | 			ep = sp + strlen(sp); | ||||||
|  | 		} | ||||||
|  | 		if (gp) { | ||||||
|  | 			rs[i].pattern = 1; | ||||||
|  | 			ep = gp; | ||||||
|  | 		} | ||||||
|  | 		rs[i].src = xstrndup(sp, ep - sp); | ||||||
|  | 	} | ||||||
|  | 	return rs; | ||||||
|  | } | ||||||
|  |  | ||||||
| struct remote *remote_get(const char *name) | struct remote *remote_get(const char *name) | ||||||
| { | { | ||||||
| 	struct remote *ret; | 	struct remote *ret; | ||||||
|  | @ -219,5 +257,213 @@ struct remote *remote_get(const char *name) | ||||||
| 		add_uri(ret, name); | 		add_uri(ret, name); | ||||||
| 	if (!ret->uri) | 	if (!ret->uri) | ||||||
| 		return NULL; | 		return NULL; | ||||||
|  | 	ret->push = parse_ref_spec(ret->push_refspec_nr, ret->push_refspec); | ||||||
| 	return ret; | 	return ret; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | static int count_refspec_match(const char *pattern, | ||||||
|  | 			       struct ref *refs, | ||||||
|  | 			       struct ref **matched_ref) | ||||||
|  | { | ||||||
|  | 	int patlen = strlen(pattern); | ||||||
|  | 	struct ref *matched_weak = NULL; | ||||||
|  | 	struct ref *matched = NULL; | ||||||
|  | 	int weak_match = 0; | ||||||
|  | 	int match = 0; | ||||||
|  |  | ||||||
|  | 	for (weak_match = match = 0; refs; refs = refs->next) { | ||||||
|  | 		char *name = refs->name; | ||||||
|  | 		int namelen = strlen(name); | ||||||
|  | 		int weak_match; | ||||||
|  |  | ||||||
|  | 		if (namelen < patlen || | ||||||
|  | 		    memcmp(name + namelen - patlen, pattern, patlen)) | ||||||
|  | 			continue; | ||||||
|  | 		if (namelen != patlen && name[namelen - patlen - 1] != '/') | ||||||
|  | 			continue; | ||||||
|  |  | ||||||
|  | 		/* A match is "weak" if it is with refs outside | ||||||
|  | 		 * heads or tags, and did not specify the pattern | ||||||
|  | 		 * in full (e.g. "refs/remotes/origin/master") or at | ||||||
|  | 		 * least from the toplevel (e.g. "remotes/origin/master"); | ||||||
|  | 		 * otherwise "git push $URL master" would result in | ||||||
|  | 		 * ambiguity between remotes/origin/master and heads/master | ||||||
|  | 		 * at the remote site. | ||||||
|  | 		 */ | ||||||
|  | 		if (namelen != patlen && | ||||||
|  | 		    patlen != namelen - 5 && | ||||||
|  | 		    prefixcmp(name, "refs/heads/") && | ||||||
|  | 		    prefixcmp(name, "refs/tags/")) { | ||||||
|  | 			/* We want to catch the case where only weak | ||||||
|  | 			 * matches are found and there are multiple | ||||||
|  | 			 * matches, and where more than one strong | ||||||
|  | 			 * matches are found, as ambiguous.  One | ||||||
|  | 			 * strong match with zero or more weak matches | ||||||
|  | 			 * are acceptable as a unique match. | ||||||
|  | 			 */ | ||||||
|  | 			matched_weak = refs; | ||||||
|  | 			weak_match++; | ||||||
|  | 		} | ||||||
|  | 		else { | ||||||
|  | 			matched = refs; | ||||||
|  | 			match++; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	if (!matched) { | ||||||
|  | 		*matched_ref = matched_weak; | ||||||
|  | 		return weak_match; | ||||||
|  | 	} | ||||||
|  | 	else { | ||||||
|  | 		*matched_ref = matched; | ||||||
|  | 		return match; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void link_dst_tail(struct ref *ref, struct ref ***tail) | ||||||
|  | { | ||||||
|  | 	**tail = ref; | ||||||
|  | 	*tail = &ref->next; | ||||||
|  | 	**tail = NULL; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static struct ref *try_explicit_object_name(const char *name) | ||||||
|  | { | ||||||
|  | 	unsigned char sha1[20]; | ||||||
|  | 	struct ref *ref; | ||||||
|  | 	int len; | ||||||
|  |  | ||||||
|  | 	if (!*name) { | ||||||
|  | 		ref = xcalloc(1, sizeof(*ref) + 20); | ||||||
|  | 		strcpy(ref->name, "(delete)"); | ||||||
|  | 		hashclr(ref->new_sha1); | ||||||
|  | 		return ref; | ||||||
|  | 	} | ||||||
|  | 	if (get_sha1(name, sha1)) | ||||||
|  | 		return NULL; | ||||||
|  | 	len = strlen(name) + 1; | ||||||
|  | 	ref = xcalloc(1, sizeof(*ref) + len); | ||||||
|  | 	memcpy(ref->name, name, len); | ||||||
|  | 	hashcpy(ref->new_sha1, sha1); | ||||||
|  | 	return ref; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int match_explicit_refs(struct ref *src, struct ref *dst, | ||||||
|  | 			       struct ref ***dst_tail, struct refspec *rs, | ||||||
|  | 			       int rs_nr) | ||||||
|  | { | ||||||
|  | 	int i, errs; | ||||||
|  | 	for (i = errs = 0; i < rs_nr; i++) { | ||||||
|  | 		struct ref *matched_src, *matched_dst; | ||||||
|  |  | ||||||
|  | 		const char *dst_value = rs[i].dst; | ||||||
|  | 		if (dst_value == NULL) | ||||||
|  | 			dst_value = rs[i].src; | ||||||
|  |  | ||||||
|  | 		matched_src = matched_dst = NULL; | ||||||
|  | 		switch (count_refspec_match(rs[i].src, src, &matched_src)) { | ||||||
|  | 		case 1: | ||||||
|  | 			break; | ||||||
|  | 		case 0: | ||||||
|  | 			/* The source could be in the get_sha1() format | ||||||
|  | 			 * not a reference name.  :refs/other is a | ||||||
|  | 			 * way to delete 'other' ref at the remote end. | ||||||
|  | 			 */ | ||||||
|  | 			matched_src = try_explicit_object_name(rs[i].src); | ||||||
|  | 			if (matched_src) | ||||||
|  | 				break; | ||||||
|  | 			errs = 1; | ||||||
|  | 			error("src refspec %s does not match any.", | ||||||
|  | 			      rs[i].src); | ||||||
|  | 			break; | ||||||
|  | 		default: | ||||||
|  | 			errs = 1; | ||||||
|  | 			error("src refspec %s matches more than one.", | ||||||
|  | 			      rs[i].src); | ||||||
|  | 			break; | ||||||
|  | 		} | ||||||
|  | 		switch (count_refspec_match(dst_value, dst, &matched_dst)) { | ||||||
|  | 		case 1: | ||||||
|  | 			break; | ||||||
|  | 		case 0: | ||||||
|  | 			if (!memcmp(dst_value, "refs/", 5)) { | ||||||
|  | 				int len = strlen(dst_value) + 1; | ||||||
|  | 				matched_dst = xcalloc(1, sizeof(*dst) + len); | ||||||
|  | 				memcpy(matched_dst->name, dst_value, len); | ||||||
|  | 				link_dst_tail(matched_dst, dst_tail); | ||||||
|  | 			} | ||||||
|  | 			else if (!strcmp(rs[i].src, dst_value) && | ||||||
|  | 				 matched_src) { | ||||||
|  | 				/* pushing "master:master" when | ||||||
|  | 				 * remote does not have master yet. | ||||||
|  | 				 */ | ||||||
|  | 				int len = strlen(matched_src->name) + 1; | ||||||
|  | 				matched_dst = xcalloc(1, sizeof(*dst) + len); | ||||||
|  | 				memcpy(matched_dst->name, matched_src->name, | ||||||
|  | 				       len); | ||||||
|  | 				link_dst_tail(matched_dst, dst_tail); | ||||||
|  | 			} | ||||||
|  | 			else { | ||||||
|  | 				errs = 1; | ||||||
|  | 				error("dst refspec %s does not match any " | ||||||
|  | 				      "existing ref on the remote and does " | ||||||
|  | 				      "not start with refs/.", dst_value); | ||||||
|  | 			} | ||||||
|  | 			break; | ||||||
|  | 		default: | ||||||
|  | 			errs = 1; | ||||||
|  | 			error("dst refspec %s matches more than one.", | ||||||
|  | 			      dst_value); | ||||||
|  | 			break; | ||||||
|  | 		} | ||||||
|  | 		if (errs) | ||||||
|  | 			continue; | ||||||
|  | 		if (matched_dst->peer_ref) { | ||||||
|  | 			errs = 1; | ||||||
|  | 			error("dst ref %s receives from more than one src.", | ||||||
|  | 			      matched_dst->name); | ||||||
|  | 		} | ||||||
|  | 		else { | ||||||
|  | 			matched_dst->peer_ref = matched_src; | ||||||
|  | 			matched_dst->force = rs[i].force; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return -errs; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static struct ref *find_ref_by_name(struct ref *list, const char *name) | ||||||
|  | { | ||||||
|  | 	for ( ; list; list = list->next) | ||||||
|  | 		if (!strcmp(list->name, name)) | ||||||
|  | 			return list; | ||||||
|  | 	return NULL; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail, | ||||||
|  | 	       int nr_refspec, char **refspec, int all) | ||||||
|  | { | ||||||
|  | 	struct refspec *rs = | ||||||
|  | 		parse_ref_spec(nr_refspec, (const char **) refspec); | ||||||
|  |  | ||||||
|  | 	if (nr_refspec) | ||||||
|  | 		return match_explicit_refs(src, dst, dst_tail, rs, nr_refspec); | ||||||
|  |  | ||||||
|  | 	/* pick the remainder */ | ||||||
|  | 	for ( ; src; src = src->next) { | ||||||
|  | 		struct ref *dst_peer; | ||||||
|  | 		if (src->peer_ref) | ||||||
|  | 			continue; | ||||||
|  | 		dst_peer = find_ref_by_name(dst, src->name); | ||||||
|  | 		if ((dst_peer && dst_peer->peer_ref) || (!dst_peer && !all)) | ||||||
|  | 			continue; | ||||||
|  | 		if (!dst_peer) { | ||||||
|  | 			/* Create a new one and link it */ | ||||||
|  | 			int len = strlen(src->name) + 1; | ||||||
|  | 			dst_peer = xcalloc(1, sizeof(*dst_peer) + len); | ||||||
|  | 			memcpy(dst_peer->name, src->name, len); | ||||||
|  | 			hashcpy(dst_peer->new_sha1, src->new_sha1); | ||||||
|  | 			link_dst_tail(dst_peer, dst_tail); | ||||||
|  | 		} | ||||||
|  | 		dst_peer->peer_ref = src; | ||||||
|  | 	} | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
							
								
								
									
										12
									
								
								remote.h
								
								
								
								
							
							
						
						
									
										12
									
								
								remote.h
								
								
								
								
							|  | @ -8,6 +8,7 @@ struct remote { | ||||||
| 	int uri_nr; | 	int uri_nr; | ||||||
|  |  | ||||||
| 	const char **push_refspec; | 	const char **push_refspec; | ||||||
|  | 	struct refspec *push; | ||||||
| 	int push_refspec_nr; | 	int push_refspec_nr; | ||||||
|  |  | ||||||
| 	const char *receivepack; | 	const char *receivepack; | ||||||
|  | @ -15,4 +16,15 @@ struct remote { | ||||||
|  |  | ||||||
| struct remote *remote_get(const char *name); | struct remote *remote_get(const char *name); | ||||||
|  |  | ||||||
|  | struct refspec { | ||||||
|  | 	unsigned force : 1; | ||||||
|  | 	unsigned pattern : 1; | ||||||
|  |  | ||||||
|  | 	const char *src; | ||||||
|  | 	char *dst; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail, | ||||||
|  | 	       int nr_refspec, char **refspec, int all); | ||||||
|  |  | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | @ -4,6 +4,7 @@ | ||||||
| #include "refs.h" | #include "refs.h" | ||||||
| #include "pkt-line.h" | #include "pkt-line.h" | ||||||
| #include "run-command.h" | #include "run-command.h" | ||||||
|  | #include "remote.h" | ||||||
|  |  | ||||||
| static const char send_pack_usage[] = | static const char send_pack_usage[] = | ||||||
| "git-send-pack [--all] [--force] [--receive-pack=<git-receive-pack>] [--verbose] [--thin] [<host>:]<directory> [<ref>...]\n" | "git-send-pack [--all] [--force] [--receive-pack=<git-receive-pack>] [--verbose] [--thin] [<host>:]<directory> [<ref>...]\n" | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	 Daniel Barkalow
						Daniel Barkalow