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` | ||||
| 	also prints "[gone]" whenever unknown upstream ref is | ||||
| 	encountered. Append `:track,nobracket` to show tracking | ||||
| 	information without brackets (i.e "ahead N, behind M").  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. | ||||
| 	information without brackets (i.e "ahead N, behind M"). | ||||
| + | ||||
| For any remote-tracking branch `%(upstream)`, `%(upstream:remotename)` | ||||
| and `%(upstream:remoteref)` refer to the name of the remote and the | ||||
| 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:: | ||||
| 	The name of a local ref which represents the `@{push}` | ||||
| 	location for the displayed ref. Respects `:short`, `:lstrip`, | ||||
| 	`:rstrip`, `:track`, and `:trackshort` options as `upstream` | ||||
| 	does. Produces an empty string if no `@{push}` ref is | ||||
| 	configured. | ||||
| 	`:rstrip`, `:track`, `:trackshort`, `:remotename`, and `:remoteref` | ||||
| 	options as `upstream` does. Produces an empty string if no `@{push}` | ||||
| 	ref is configured. | ||||
|  | ||||
| HEAD:: | ||||
| 	'*' 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]; | ||||
| 		struct align align; | ||||
| 		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; | ||||
| 			unsigned int nobracket : 1; | ||||
| 			unsigned int nobracket : 1, push : 1, push_remote : 1; | ||||
| 		} remote_ref; | ||||
| 		struct { | ||||
| 			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; | ||||
| 	int i; | ||||
|  | ||||
| 	if (!strcmp(atom->name, "push") || starts_with(atom->name, "push:")) | ||||
| 		atom->u.remote_ref.push = 1; | ||||
|  | ||||
| 	if (!arg) { | ||||
| 		atom->u.remote_ref.option = RR_REF; | ||||
| 		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; | ||||
| 		else if (!strcmp(s, "nobracket")) | ||||
| 			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; | ||||
| 			refname_atom_parser_internal(&atom->u.remote_ref.refname, | ||||
| 						     arg, atom->name); | ||||
|  | @ -1268,6 +1279,25 @@ static void fill_remote_ref_details(struct used_atom *atom, const char *refname, | |||
| 			*s = ">"; | ||||
| 		else | ||||
| 			*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 | ||||
| 		die("BUG: unhandled RR_* enum"); | ||||
| } | ||||
|  | @ -1377,16 +1407,20 @@ static void populate_value(struct ref_array_item *ref) | |||
| 			if (refname) | ||||
| 				fill_remote_ref_details(atom, refname, branch, &v->s); | ||||
| 			continue; | ||||
| 		} else if (starts_with(name, "push")) { | ||||
| 		} else if (atom->u.remote_ref.push) { | ||||
| 			const char *branch_name; | ||||
| 			if (!skip_prefix(ref->refname, "refs/heads/", | ||||
| 					 &branch_name)) | ||||
| 				continue; | ||||
| 			branch = branch_get(branch_name); | ||||
|  | ||||
| 			if (atom->u.remote_ref.push_remote) | ||||
| 				refname = NULL; | ||||
| 			else { | ||||
| 				refname = branch_get_push(branch, NULL); | ||||
| 				if (!refname) | ||||
| 					continue; | ||||
| 			} | ||||
| 			fill_remote_ref_details(atom, refname, branch, &v->s); | ||||
| 			continue; | ||||
| 		} 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); | ||||
| } | ||||
|  | ||||
| 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, | ||||
| 				   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); | ||||
| const char *remote_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_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_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 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 Junio C Hamano
						Junio C Hamano