git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: [PATCH 2/3] for-each-ref: let upstream/push optionally report merge name.

From
Junio C Hamano <gitster@pobox.com>
Date
Oct 4, 2017, 09:12 UTC
Message-ID
<xmqq4lrfb7jk.fsf@gitster.mtv.corp.google.com>
In-Reply-To
<f615fcc05fa358b4c7e3531cbdbd91661be321aa.1506952571.git.johannes.schindelin@gmx.de>
Johannes Schindelin <johannes.schindelin@gmx.de> writes:
Show 32 quoted lines
> From: J Wyman <jwyman@microsoft.com>
>
> There are times when scripts want to know not only the name of the
> push branch on the remote, but also the name of the branch as known
> by the remote repository.
>
> A useful example of this is with the push command where
> `branch.<name>.merge` is useful as the <to> value. Example:
>
> 	$ git push <remote> <from>:<to>
>
> This patch offers the new suffix :merge for the push atom, allowing to
> show exactly that. Example:
>
> 	$ cat .git/config
> 	...
> 	[remote "origin"]
> 		url = https://where.do.we.come/from
> 		fetch = refs/heads/*:refs/remote/origin/*
> 	[branch "master"]
> 		remote = origin
> 		merge = refs/heads/master
> 	[branch "develop/with/topics"]
> 		remote = origin
> 		merge = refs/heads/develop/with/topics
> 	...
>
> 	$ git for-each-ref \
> 		--format='%(push) %(push:remote-ref)' \
> 		refs/heads
> 	refs/remotes/origin/master refs/heads/master
> 	refs/remotes/origin/develop/with/topics refs/heads/develop/with/topics

Ah, now it is clear that we _need_ to figure out how to spell "multi-word" modifier to the format specifiers, as "push:remote" would not let us differenciate the products of 1/3 and 2/3 X-<.

> ---

We need two Signed-off-by: lines at the end, one by Wyman and then another by you in this order.

> --- a/Documentation/git-for-each-ref.txt
> +++ b/Documentation/git-for-each-ref.txt
Changes to this file in this patch looks sane.
Show 10 quoted lines
> --- a/ref-filter.c
> +++ b/ref-filter.c
> @@ -1260,6 +1262,14 @@ static void fill_remote_ref_details(struct used_atom *atom, const char *refname,
>  			*s = xstrdup(remote);
>  		else
>  			*s = "";
> +	} else if (atom->u.remote_ref.option == RR_REMOTE_REF) {
> +		int explicit, for_push = starts_with(atom->name, "push");
> +		const char *merge = remote_ref_for_branch(branch, for_push,
> +							  &explicit);

Having multiple variables defined like this _and_ initialized with anything other than a trivial constant, is somewhat hard to follow. Can we split the above more like:

		int explicit;
		int for_push = starts_with(...);
		const char *merge = remote_ref_for_branch(...);
Actually, if you did it this way, you do not even need "for_push":
		int explicit;
		const char *merge;
		merge = remote_ref_for_branch(branch,
					      starts_with(atom->name, "push"),
					      &explicit);
which may be a lot easier to follow.

By the way, the spirit of parsing used atoms first before the "learn what we care about this single ref" function like the above are called repeatedly for each ref is because we want to hoist the overhead of doing the constant computation like "does the atom's name begins with 'push'?" out of the latter.

Can we add a field in atom->u.remote_ref to precompute this bit so that we do not even have to say "Are we doing this for push? Let's see if the atom's name begins with 'push'" each time this function is called for a ref? That makes this function a lot more in line with the spirit of the design of the subsystem, I would think.

This comment probably applies equally to both 1/3 and this one.
> +		if (explicit)
> +			*s = xstrdup(merge);
> +		else
> +			*s = "";

Here is the same "who are we trying to help---users who want to know where their push goes, or users who are debugging where the push destination is defined?" question. I do not have a strong opinion either way, but I think giving the end result with fallback (i.e. not nullifying when the result is not explicit) may be easier to use by "push" users.

Show 22 quoted lines
> diff --git a/remote.c b/remote.c
> index b220f0dfc61..2bdcfc280cd 100644
> --- a/remote.c
> +++ b/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);
Again,
			const char *dst, *remote_name;
                        struct remote *remote;
			remote_name = pushremote_for_branch(branch, NULL);
                        remote = remote_get(remote_name);

may be easier to follow, if only that it allows eyes to scan without having to be distracted by jagged lines.

Show 14 quoted lines
> +			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 "";
> +}

What the function does looks reasonable; the assignment in if() condition looks a bit unfortunate, though.

Previous: Johannes SchindelinNext: Junio C Hamano
Message 7 of 32 in “for-each-ref: add :remote-ref and :remote-name specifiers”
  1. 0/3 for-each-ref: add :remote-ref and :remote-name specifiersJohannes Schindelin, Oct 2, 2017
  2. 1/3 for-each-ref: let upstream/push optionally report the remote nameJohannes Schindelin, Oct 2, 2017
  3. Junio C HamanoOct 4, 2017
  4. Junio C HamanoOct 4, 2017
  5. Johannes SchindelinOct 5, 2017
  6. 2/3 for-each-ref: let upstream/push optionally report merge name.Johannes Schindelin, Oct 2, 2017
  7. Junio C HamanoOct 4, 2017
  8. Junio C HamanoOct 4, 2017
  9. Junio C HamanoOct 5, 2017
  10. 3/3 for-each-ref: test :remote-name and :remote-refJohannes Schindelin, Oct 2, 2017
  11. Junio C HamanoOct 5, 2017
  12. 0/3 for-each-ref: add :remoteref and :remotename specifiersJohannes Schindelin, Oct 5, 2017
  13. 1/3 for-each-ref: let upstream/push optionally report the remote nameJohannes Schindelin, Oct 5, 2017
  14. Junio C HamanoOct 10, 2017
  15. Junio C HamanoOct 11, 2017
  16. 2/3 for-each-ref: let upstream/push optionally remote ref nameJohannes Schindelin, Oct 5, 2017
  17. Junio C HamanoOct 6, 2017
  18. Junio C HamanoOct 11, 2017
  19. Johannes SchindelinOct 12, 2017
  20. Junio C HamanoOct 13, 2017
  21. Johannes SchindelinOct 15, 2017
  22. Kevin DaudtOct 13, 2017
  23. Junio C HamanoOct 14, 2017
  24. Johannes SchindelinOct 15, 2017
  25. Junio C HamanoOct 16, 2017
  26. Johannes SchindelinOct 16, 2017
  27. 3/3 for-each-ref: test :remotename and :remoterefJohannes Schindelin, Oct 5, 2017
  28. 0/3 for-each-ref: add :remoteref and :remotename specifiersJohannes Schindelin, Nov 7, 2017
  29. 1/3 for-each-ref: let upstream/push optionally report the remote nameJohannes Schindelin, Nov 7, 2017
  30. 2/3 for-each-ref: let upstream/push report the remote ref nameJohannes Schindelin, Nov 7, 2017
  31. 3/3 for-each-ref: test :remotename and :remoterefJohannes Schindelin, Nov 7, 2017
  32. Junio C HamanoNov 8, 2017

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.