Merge branch 'js/for-each-ref-remote-name-and-ref'
The "--format=..." option "git for-each-ref" takes learned to show the name of the 'remote' repository and the ref at the remote side that is affected for 'upstream' and 'push' via "%(push:remotename)" and friends. * js/for-each-ref-remote-name-and-ref: for-each-ref: test :remotename and :remoteref for-each-ref: let upstream/push report the remote ref name for-each-ref: let upstream/push optionally report the remote namemaint
						commit
						093048b229
					
				|  | @ -145,18 +145,25 @@ upstream:: | ||||||
| 	(behind), "<>" (ahead and behind), or "=" (in sync). `:track` | 	(behind), "<>" (ahead and behind), or "=" (in sync). `:track` | ||||||
| 	also prints "[gone]" whenever unknown upstream ref is | 	also prints "[gone]" whenever unknown upstream ref is | ||||||
| 	encountered. Append `:track,nobracket` to show tracking | 	encountered. Append `:track,nobracket` to show tracking | ||||||
| 	information without brackets (i.e "ahead N, behind M").  Has | 	information without brackets (i.e "ahead N, behind M"). | ||||||
| 	no effect if the ref does not have tracking information | + | ||||||
| 	associated with it.  All the options apart from `nobracket` | For any remote-tracking branch `%(upstream)`, `%(upstream:remotename)` | ||||||
| 	are mutually exclusive, but if used together the last option | and `%(upstream:remoteref)` refer to the name of the remote and the | ||||||
| 	is selected. | name of the tracked remote ref, respectively. In other words, the | ||||||
|  | remote-tracking branch can be updated explicitly and individually by | ||||||
|  | using the refspec `%(upstream:remoteref):%(upstream)` to fetch from | ||||||
|  | `%(upstream:remotename)`. | ||||||
|  | + | ||||||
|  | Has no effect if the ref does not have tracking information associated | ||||||
|  | with it.  All the options apart from `nobracket` are mutually exclusive, | ||||||
|  | but if used together the last option is selected. | ||||||
|  |  | ||||||
| push:: | push:: | ||||||
| 	The name of a local ref which represents the `@{push}` | 	The name of a local ref which represents the `@{push}` | ||||||
| 	location for the displayed ref. Respects `:short`, `:lstrip`, | 	location for the displayed ref. Respects `:short`, `:lstrip`, | ||||||
| 	`:rstrip`, `:track`, and `:trackshort` options as `upstream` | 	`:rstrip`, `:track`, `:trackshort`, `:remotename`, and `:remoteref` | ||||||
| 	does. Produces an empty string if no `@{push}` ref is | 	options as `upstream` does. Produces an empty string if no `@{push}` | ||||||
| 	configured. | 	ref is configured. | ||||||
|  |  | ||||||
| HEAD:: | HEAD:: | ||||||
| 	'*' if HEAD matches current ref (the checked out branch), ' ' | 	'*' if HEAD matches current ref (the checked out branch), ' ' | ||||||
|  |  | ||||||
							
								
								
									
										42
									
								
								ref-filter.c
								
								
								
								
							
							
						
						
									
										42
									
								
								ref-filter.c
								
								
								
								
							|  | @ -76,9 +76,11 @@ static struct used_atom { | ||||||
| 		char color[COLOR_MAXLEN]; | 		char color[COLOR_MAXLEN]; | ||||||
| 		struct align align; | 		struct align align; | ||||||
| 		struct { | 		struct { | ||||||
| 			enum { RR_REF, RR_TRACK, RR_TRACKSHORT } option; | 			enum { | ||||||
|  | 				RR_REF, RR_TRACK, RR_TRACKSHORT, RR_REMOTE_NAME, RR_REMOTE_REF | ||||||
|  | 			} option; | ||||||
| 			struct refname_atom refname; | 			struct refname_atom refname; | ||||||
| 			unsigned int nobracket : 1; | 			unsigned int nobracket : 1, push : 1, push_remote : 1; | ||||||
| 		} remote_ref; | 		} remote_ref; | ||||||
| 		struct { | 		struct { | ||||||
| 			enum { C_BARE, C_BODY, C_BODY_DEP, C_LINES, C_SIG, C_SUB, C_TRAILERS } option; | 			enum { C_BARE, C_BODY, C_BODY_DEP, C_LINES, C_SIG, C_SUB, C_TRAILERS } option; | ||||||
|  | @ -138,6 +140,9 @@ static void remote_ref_atom_parser(const struct ref_format *format, struct used_ | ||||||
| 	struct string_list params = STRING_LIST_INIT_DUP; | 	struct string_list params = STRING_LIST_INIT_DUP; | ||||||
| 	int i; | 	int i; | ||||||
|  |  | ||||||
|  | 	if (!strcmp(atom->name, "push") || starts_with(atom->name, "push:")) | ||||||
|  | 		atom->u.remote_ref.push = 1; | ||||||
|  |  | ||||||
| 	if (!arg) { | 	if (!arg) { | ||||||
| 		atom->u.remote_ref.option = RR_REF; | 		atom->u.remote_ref.option = RR_REF; | ||||||
| 		refname_atom_parser_internal(&atom->u.remote_ref.refname, | 		refname_atom_parser_internal(&atom->u.remote_ref.refname, | ||||||
|  | @ -157,7 +162,13 @@ static void remote_ref_atom_parser(const struct ref_format *format, struct used_ | ||||||
| 			atom->u.remote_ref.option = RR_TRACKSHORT; | 			atom->u.remote_ref.option = RR_TRACKSHORT; | ||||||
| 		else if (!strcmp(s, "nobracket")) | 		else if (!strcmp(s, "nobracket")) | ||||||
| 			atom->u.remote_ref.nobracket = 1; | 			atom->u.remote_ref.nobracket = 1; | ||||||
| 		else { | 		else if (!strcmp(s, "remotename")) { | ||||||
|  | 			atom->u.remote_ref.option = RR_REMOTE_NAME; | ||||||
|  | 			atom->u.remote_ref.push_remote = 1; | ||||||
|  | 		} else if (!strcmp(s, "remoteref")) { | ||||||
|  | 			atom->u.remote_ref.option = RR_REMOTE_REF; | ||||||
|  | 			atom->u.remote_ref.push_remote = 1; | ||||||
|  | 		} else { | ||||||
| 			atom->u.remote_ref.option = RR_REF; | 			atom->u.remote_ref.option = RR_REF; | ||||||
| 			refname_atom_parser_internal(&atom->u.remote_ref.refname, | 			refname_atom_parser_internal(&atom->u.remote_ref.refname, | ||||||
| 						     arg, atom->name); | 						     arg, atom->name); | ||||||
|  | @ -1268,6 +1279,25 @@ static void fill_remote_ref_details(struct used_atom *atom, const char *refname, | ||||||
| 			*s = ">"; | 			*s = ">"; | ||||||
| 		else | 		else | ||||||
| 			*s = "<>"; | 			*s = "<>"; | ||||||
|  | 	} else if (atom->u.remote_ref.option == RR_REMOTE_NAME) { | ||||||
|  | 		int explicit; | ||||||
|  | 		const char *remote = atom->u.remote_ref.push ? | ||||||
|  | 			pushremote_for_branch(branch, &explicit) : | ||||||
|  | 			remote_for_branch(branch, &explicit); | ||||||
|  | 		if (explicit) | ||||||
|  | 			*s = xstrdup(remote); | ||||||
|  | 		else | ||||||
|  | 			*s = ""; | ||||||
|  | 	} else if (atom->u.remote_ref.option == RR_REMOTE_REF) { | ||||||
|  | 		int explicit; | ||||||
|  | 		const char *merge; | ||||||
|  |  | ||||||
|  | 		merge = remote_ref_for_branch(branch, atom->u.remote_ref.push, | ||||||
|  | 					      &explicit); | ||||||
|  | 		if (explicit) | ||||||
|  | 			*s = xstrdup(merge); | ||||||
|  | 		else | ||||||
|  | 			*s = ""; | ||||||
| 	} else | 	} else | ||||||
| 		die("BUG: unhandled RR_* enum"); | 		die("BUG: unhandled RR_* enum"); | ||||||
| } | } | ||||||
|  | @ -1377,16 +1407,20 @@ static void populate_value(struct ref_array_item *ref) | ||||||
| 			if (refname) | 			if (refname) | ||||||
| 				fill_remote_ref_details(atom, refname, branch, &v->s); | 				fill_remote_ref_details(atom, refname, branch, &v->s); | ||||||
| 			continue; | 			continue; | ||||||
| 		} else if (starts_with(name, "push")) { | 		} else if (atom->u.remote_ref.push) { | ||||||
| 			const char *branch_name; | 			const char *branch_name; | ||||||
| 			if (!skip_prefix(ref->refname, "refs/heads/", | 			if (!skip_prefix(ref->refname, "refs/heads/", | ||||||
| 					 &branch_name)) | 					 &branch_name)) | ||||||
| 				continue; | 				continue; | ||||||
| 			branch = branch_get(branch_name); | 			branch = branch_get(branch_name); | ||||||
|  |  | ||||||
|  | 			if (atom->u.remote_ref.push_remote) | ||||||
|  | 				refname = NULL; | ||||||
|  | 			else { | ||||||
| 				refname = branch_get_push(branch, NULL); | 				refname = branch_get_push(branch, NULL); | ||||||
| 				if (!refname) | 				if (!refname) | ||||||
| 					continue; | 					continue; | ||||||
|  | 			} | ||||||
| 			fill_remote_ref_details(atom, refname, branch, &v->s); | 			fill_remote_ref_details(atom, refname, branch, &v->s); | ||||||
| 			continue; | 			continue; | ||||||
| 		} else if (starts_with(name, "color:")) { | 		} else if (starts_with(name, "color:")) { | ||||||
|  |  | ||||||
							
								
								
									
										30
									
								
								remote.c
								
								
								
								
							
							
						
						
									
										30
									
								
								remote.c
								
								
								
								
							|  | @ -675,6 +675,36 @@ const char *pushremote_for_branch(struct branch *branch, int *explicit) | ||||||
| 	return remote_for_branch(branch, explicit); | 	return remote_for_branch(branch, explicit); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | const char *remote_ref_for_branch(struct branch *branch, int for_push, | ||||||
|  | 				  int *explicit) | ||||||
|  | { | ||||||
|  | 	if (branch) { | ||||||
|  | 		if (!for_push) { | ||||||
|  | 			if (branch->merge_nr) { | ||||||
|  | 				if (explicit) | ||||||
|  | 					*explicit = 1; | ||||||
|  | 				return branch->merge_name[0]; | ||||||
|  | 			} | ||||||
|  | 		} else { | ||||||
|  | 			const char *dst, *remote_name = | ||||||
|  | 				pushremote_for_branch(branch, NULL); | ||||||
|  | 			struct remote *remote = remote_get(remote_name); | ||||||
|  |  | ||||||
|  | 			if (remote && remote->push_refspec_nr && | ||||||
|  | 			    (dst = apply_refspecs(remote->push, | ||||||
|  | 						  remote->push_refspec_nr, | ||||||
|  | 						  branch->refname))) { | ||||||
|  | 				if (explicit) | ||||||
|  | 					*explicit = 1; | ||||||
|  | 				return dst; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	if (explicit) | ||||||
|  | 		*explicit = 0; | ||||||
|  | 	return ""; | ||||||
|  | } | ||||||
|  |  | ||||||
| static struct remote *remote_get_1(const char *name, | static struct remote *remote_get_1(const char *name, | ||||||
| 				   const char *(*get_default)(struct branch *, int *)) | 				   const char *(*get_default)(struct branch *, int *)) | ||||||
| { | { | ||||||
|  |  | ||||||
							
								
								
									
										2
									
								
								remote.h
								
								
								
								
							
							
						
						
									
										2
									
								
								remote.h
								
								
								
								
							|  | @ -223,6 +223,8 @@ struct branch { | ||||||
| struct branch *branch_get(const char *name); | struct branch *branch_get(const char *name); | ||||||
| const char *remote_for_branch(struct branch *branch, int *explicit); | const char *remote_for_branch(struct branch *branch, int *explicit); | ||||||
| const char *pushremote_for_branch(struct branch *branch, int *explicit); | const char *pushremote_for_branch(struct branch *branch, int *explicit); | ||||||
|  | const char *remote_ref_for_branch(struct branch *branch, int for_push, | ||||||
|  | 				  int *explicit); | ||||||
|  |  | ||||||
| int branch_has_merge_config(struct branch *branch); | int branch_has_merge_config(struct branch *branch); | ||||||
| int branch_merge_matches(struct branch *, int n, const char *); | int branch_merge_matches(struct branch *, int n, const char *); | ||||||
|  |  | ||||||
|  | @ -766,4 +766,36 @@ test_expect_success 'Verify usage of %(symref:rstrip) atom' ' | ||||||
| 	test_cmp expected actual | 	test_cmp expected actual | ||||||
| ' | ' | ||||||
|  |  | ||||||
|  | test_expect_success ':remotename and :remoteref' ' | ||||||
|  | 	git init remote-tests && | ||||||
|  | 	( | ||||||
|  | 		cd remote-tests && | ||||||
|  | 		test_commit initial && | ||||||
|  | 		git remote add from fifth.coffee:blub && | ||||||
|  | 		git config branch.master.remote from && | ||||||
|  | 		git config branch.master.merge refs/heads/stable && | ||||||
|  | 		git remote add to southridge.audio:repo && | ||||||
|  | 		git config remote.to.push "refs/heads/*:refs/heads/pushed/*" && | ||||||
|  | 		git config branch.master.pushRemote to && | ||||||
|  | 		for pair in "%(upstream)=refs/remotes/from/stable" \ | ||||||
|  | 			"%(upstream:remotename)=from" \ | ||||||
|  | 			"%(upstream:remoteref)=refs/heads/stable" \ | ||||||
|  | 			"%(push)=refs/remotes/to/pushed/master" \ | ||||||
|  | 			"%(push:remotename)=to" \ | ||||||
|  | 			"%(push:remoteref)=refs/heads/pushed/master" | ||||||
|  | 		do | ||||||
|  | 			echo "${pair#*=}" >expect && | ||||||
|  | 			git for-each-ref --format="${pair%=*}" \ | ||||||
|  | 				refs/heads/master >actual && | ||||||
|  | 			test_cmp expect actual | ||||||
|  | 		done && | ||||||
|  | 		git branch push-simple && | ||||||
|  | 		git config branch.push-simple.pushRemote from && | ||||||
|  | 		actual="$(git for-each-ref \ | ||||||
|  | 			--format="%(push:remotename),%(push:remoteref)" \ | ||||||
|  | 			refs/heads/push-simple)" && | ||||||
|  | 		test from, = "$actual" | ||||||
|  | 	) | ||||||
|  | ' | ||||||
|  |  | ||||||
| test_done | test_done | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	 Junio C Hamano
						Junio C Hamano