Re: [PATCH 2/2] push: --follow-tag
On Mon, Mar 04, 2013 at 04:54:39PM -0800, Junio C Hamano wrote: This is primarily to scratch my own itch; after tagging an rc or final release, I've been doing git push k.org v1.8.2 git push k.org and the first step can easily be forgotten. With git push k.org --follow-tag I no longer should have to worry about that. It will push out whatever would be pushed out without --follow-tag, and also tags that are missing from my k.org repository that point into the history being pushed out. I've run into the same problem. It's a minor annoyance, but your patch should make it smoother. Should this be called --follow-tags? That makes more sense to me, as you are catching all tags. For consistency, should this match the naming of git-fetch's options (or vice versa)? There we have: default: auto-follow tags --tags: fetch all of refs/heads/tags --no-tags: do not auto-follow I think that naming has caused some confusion in the past. And there is no way to explicitly specify the default behavior. I wonder if both should support: --follow-tags: auto-follow tags --no-follow-tags: do not auto-follow tags --tags: fetch/push all of refs/heads/tags --no-tags: turn off auto-following, and cancel any previous --tags The default for push should probably keep auto-follow off, though. +--follow-tag:: + Push all the refs that would be pushed without this option, + and also push the refs under `refs/tags` that are missing + from the remote but are reachable from the refs that would + be pushed without this option. + This reads OK to me, though it is a little confusing in that there are two sets of refs being discussed, and the refs that would be pushed without this option is quite a long noun phrase (that gets used twice). You also don't define reachable here. Being familiar with git, I assume it is the commit that the refs/tag entry peels to is an ancestor of a commit that is at the tip of a pushed ref. Maybe that is obvious enough that it doesn't need to be spelled out. I think you could just drop the second refs that would be pushed without this option, and just say pushed refs. That is ambiguous (is it all pushed refs, or refs that would be pushed without this option?), but since reachability is transitive, they are the same set (i.e., if we add a ref due to this option, then its ancestors are already candidates, and it does not affect the outcome). Maybe: In addition to any refs that would be pushed without this option, also push any refs under `refs/tags` that are missing from the remote but are reachable from the pushed refs. I dunno. I don't really like that version much, either. + /* + * At this point, src_tag lists tags that are missing from + * dst, and sent_tips lists the tips we are pushing (or those + * that we know they already have). An element in the src_tag + * that is not an ancestor of any of the sent_tips need to be + * sent to the other side. + */ + if (sent_tips.nr) { + for_each_string_list_item(item, src_tag) { + struct ref *ref = item-util; + struct ref *dst_ref; + struct commit *commit; + + if (is_null_sha1(ref-new_sha1)) + continue; + commit = lookup_commit_reference_gently(ref-new_sha1, 1); + if (!commit) + /* not pushing a commit, which is not an error */ + continue; This will find anything under refs/tags, including annotated and non-annotated tags. I wonder if it is worth making a distinction. In many workflows, unannotated tags should not be leaked out to public repos. But because this feature finds any reachable tags, it will push a tag you made a long time ago as a bookmarker on some part of the history unrelated to the release you are making now. One obvious alternative is only to push annotated tags with this feature. That has the downside of not matching fetch's behavior, as well as withholding the feature from people whose workflow uses only unannotated tags. Another alternative would be to change the inclusion rule from reachable to points at the tip of something being sent. But then we lose the feature that it would backfill any old tags the remote happens to be missing. -Peff -- To unsubscribe from this list: send the line unsubscribe git in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 2/2] push: --follow-tag
On 03/05/2013 09:22 AM, Jeff King wrote: On Mon, Mar 04, 2013 at 04:54:39PM -0800, Junio C Hamano wrote: [...] This will find anything under refs/tags, including annotated and non-annotated tags. I wonder if it is worth making a distinction. In many workflows, unannotated tags should not be leaked out to public repos. But because this feature finds any reachable tags, it will push a tag you made a long time ago as a bookmarker on some part of the history unrelated to the release you are making now. One obvious alternative is only to push annotated tags with this feature. That has the downside of not matching fetch's behavior, as well as withholding the feature from people whose workflow uses only unannotated tags. Another alternative would be to change the inclusion rule from reachable to points at the tip of something being sent. But then we lose the feature that it would backfill any old tags the remote happens to be missing. I have no opinion on this matter, but ISTM that another obvious alternative would be to push tags that point at *any* commits that are being sent (not just at the tip), but not those that point to older commits already known to the server. This would reduce the potential for accidental pushes of distant tags. Michael -- Michael Haggerty mhag...@alum.mit.edu http://softwareswirl.blogspot.com/ -- To unsubscribe from this list: send the line unsubscribe git in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 2/2] push: --follow-tag
Jeff King p...@peff.net writes: Should this be called --follow-tags? That makes more sense to me, as you are catching all tags. Perhaps. We are sending all zero-or-more relevant tags, so I agree that plural form is more appropriate. I have a doubt about follow, though; inertia made me use follow, but I am not sure what we are following. We certainly are not following tags. If anything, we are making tags to piggy back on the history being pushed. For consistency, should this match the naming of git-fetch's options (or vice versa)? There we have: default: auto-follow tags --tags: fetch all of refs/heads/tags --no-tags: do not auto-follow I think that naming has caused some confusion in the past. --tags does not belong in the discussion of auto following. It does not have to do with any auto-ness. Renaming --no-tags to --no-follow-tags does make sense, though. And there is no way to explicitly specify the default behavior. I wonder if both should support: --follow-tags: auto-follow tags --no-follow-tags: do not auto-follow tags Yup, I like that. Perhaps make --no-tags a deprecated synonym to the latter. --tags: fetch/push all of refs/heads/tags --no-tags: turn off auto-following, and cancel any previous --tags Sounds sensible. The default for push should probably keep auto-follow off, though. +--follow-tag:: +Push all the refs that would be pushed without this option, +and also push the refs under `refs/tags` that are missing +from the remote but are reachable from the refs that would +be pushed without this option. + This reads OK to me, though it is a little confusing in that there are two sets of refs being discussed, and the refs that would be pushed without this option is quite a long noun phrase (that gets used twice). Yes, exactly why I said I do not like the phrasing of this one. This will find anything under refs/tags, including annotated and non-annotated tags. I wonder if it is worth making a distinction. In many workflows, unannotated tags should not be leaked out to public repos. But because this feature finds any reachable tags, it will push a tag you made a long time ago as a bookmarker on some part of the history unrelated to the release you are making now. What does the auto-follow feature of git fetch do currently? Whatever we do here on the git push side should match it. If somebody wants to add some form of filtering mechanism based on the tagname (e.g. '--auto-follow-tags=v[0-9]*'), I would not have a strong objection to it, but I think that is something we should do on top and consistently between fetch and push. I am not thrilled by the idea of conflating annotated-ness and the public-ness of tags. Thanks. -- To unsubscribe from this list: send the line unsubscribe git in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 2/2] push: --follow-tag
On Tue, Mar 05, 2013 at 07:58:45AM -0800, Junio C Hamano wrote: This will find anything under refs/tags, including annotated and non-annotated tags. I wonder if it is worth making a distinction. In many workflows, unannotated tags should not be leaked out to public repos. But because this feature finds any reachable tags, it will push a tag you made a long time ago as a bookmarker on some part of the history unrelated to the release you are making now. What does the auto-follow feature of git fetch do currently? Whatever we do here on the git push side should match it. It fetches anything in refs/tags, unannotated or not. And that is certainly a point in favor of git push doing the same. But I wonder if fetching and pushing are different in that respect. You are (usually) fetching from a public publishing point, and it is assumed that whatever is there is useful for sharing. The only reason to limit it is to save time transferring objects the user does not want. But for push, you are on the publishing side, which usually means you need to be a little more careful. It is not just an optimization; it is about deciding what should be shared. You do not want to accidentally push cruft or work in progress in your private repository. I think it's the same logic that leads us to fetch refs/heads/* by default, but only push matching (or more recently HEAD). If somebody wants to add some form of filtering mechanism based on the tagname (e.g. '--auto-follow-tags=v[0-9]*'), I would not have a strong objection to it, but I think that is something we should do on top and consistently between fetch and push. I am not thrilled by the idea of conflating annotated-ness and the public-ness of tags. I don't like it either. But I also don't want to introduce a feature that causes people to accidentally publish cruft. It may not be a problem in practice; I'm just thinking out loud at this point. -Peff -- To unsubscribe from this list: send the line unsubscribe git in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 2/2] push: --follow-tag
Jeff King p...@peff.net writes: But I wonder if fetching and pushing are different in that respect. You are (usually) fetching from a public publishing point, and it is assumed that whatever is there is useful for sharing. The only reason to limit it is to save time transferring objects the user does not want. There are those who have to emulate git fetch with a reverse git push (or vice versa) due to network connection limitations, so I do not think hardcoding such a policy decision in the direction is necessarily a good idea. ... But I also don't want to introduce a feature that causes people to accidentally publish cruft. It may not be a problem in practice; I'm just thinking out loud at this point. Likewise. -- To unsubscribe from this list: send the line unsubscribe git in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 2/2] push: --follow-tag
On Tue, Mar 05, 2013 at 10:15:20AM -0800, Junio C Hamano wrote: Jeff King p...@peff.net writes: But I wonder if fetching and pushing are different in that respect. You are (usually) fetching from a public publishing point, and it is assumed that whatever is there is useful for sharing. The only reason to limit it is to save time transferring objects the user does not want. There are those who have to emulate git fetch with a reverse git push (or vice versa) due to network connection limitations, so I do not think hardcoding such a policy decision in the direction is necessarily a good idea. Yeah, but I think it makes sense to optimize the defaults for the common cases, and let people doing unusual things override the behavior via options (or even config). Don't get me wrong, I think there is value in the simplicity of having the push/fetch transactions be as symmetric as possible. But given the potentially high cost of a mistaken push (i.e., retracting published history can be embarrassing or complicated), there's also value in safe defaults. And I feel like we've already gone in that direction with the default refspecs being different between fetch and push. -Peff -- To unsubscribe from this list: send the line unsubscribe git in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 2/2] push: --follow-tag
On Tue, Mar 05, 2013 at 12:49:57PM +0100, Michael Haggerty wrote: One obvious alternative is only to push annotated tags with this feature. That has the downside of not matching fetch's behavior, as well as withholding the feature from people whose workflow uses only unannotated tags. Another alternative would be to change the inclusion rule from reachable to points at the tip of something being sent. But then we lose the feature that it would backfill any old tags the remote happens to be missing. I have no opinion on this matter, but ISTM that another obvious alternative would be to push tags that point at *any* commits that are being sent (not just at the tip), but not those that point to older commits already known to the server. This would reduce the potential for accidental pushes of distant tags. Yeah, I think that is another sensible variant. It does not really backfill in the way that Junio's patch does (e.g., if you forgot to push out v1.6 to a remote 2 weeks ago and now you are pushing out v1.7, Junio's patch will magically fill it in). But I do not see a huge value in backfilling. It is anyone's guess whether you simply forgot to push out v1.6 or whether you intended to hold it back. And I'd rather err on the side of not-pushing because of the difficulty of retraction. -Peff -- To unsubscribe from this list: send the line unsubscribe git in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 2/2] push: --follow-tag
Jeff King p...@peff.net writes: Yeah, I think that is another sensible variant. It does not really backfill in the way that Junio's patch does (e.g., if you forgot to push out v1.6 to a remote 2 weeks ago and now you are pushing out v1.7, Junio's patch will magically fill it in). I may have tentatively tagged the tip of 'master' as v1.8.2 in my private repository, started the integration testing, but may not be confident enough to push out the branch nor the tag yet. I may have an experimental topic that I want to share with others before I am done with the release to unblock them, and the topic may build on the 'master' I may or may not want to redo before the release. I can do so with git push github jc/topic (no --follow-tags). After doing such a you may want to start with this push, I can continue working on the release, and the 'master' branch may turn out to be good to go without redoing. A later git push github --follow-tags master in such a case should send v1.8.2 out. It is inexcuable to break it, saying Oh, I've seen that commit already---it is part of the previous update to jc/topic. That defeats the whole point of --follow-tags. The other tags at the tip is slightly less problematic than ignore the commits the receiving end has already seen, but it will break if I tag the tip of 'maint' as v1.8.1.6, continue working without being able to push perhaps due to network disruption, and have already started building towards v1.8.1.7 when the network comes back. 'maint' may be past v1.8.1.6 and its tip won't be pointing at that tag, but it still is missing from the public repository. While I agree with your goal to make it safer to use push, both ignore commits that the receiving end already saw and only look at the commits at the tip being sent castrate the option too much to the point that it is meaningless. The whole point of asking explicitly with the --follow-tags option to push to push out relevant tags is, eh, to push out relevant tags. I do not think it is magical at all. backfill is an integral part of the option. -- To unsubscribe from this list: send the line unsubscribe git in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 2/2] push: --follow-tag
On Tue, Mar 05, 2013 at 11:17:11AM -0800, Junio C Hamano wrote: I may have tentatively tagged the tip of 'master' as v1.8.2 in my private repository, started the integration testing, but may not be confident enough to push out the branch nor the tag yet. I may have an experimental topic that I want to share with others before I am done with the release to unblock them, and the topic may build on the 'master' I may or may not want to redo before the release. I can do so with git push github jc/topic (no --follow-tags). After doing such a you may want to start with this push, I can continue working on the release, and the 'master' branch may turn out to be good to go without redoing. A later git push github --follow-tags master in such a case should send v1.8.2 out. It is inexcuable to break it, saying Oh, I've seen that commit already---it is part of the previous update to jc/topic. That defeats the whole point of --follow-tags. That depends on the specifics of the rule. If the rule is any commit that the server already has, then yes, it runs afoul of that problem. But what if it is any commit in the ref update being sent? That is, we would look at the range origin/master..master and send any tags that point to commits in that range. The other tags at the tip is slightly less problematic than ignore the commits the receiving end has already seen, but it will break if I tag the tip of 'maint' as v1.8.1.6, continue working without being able to push perhaps due to network disruption, and have already started building towards v1.8.1.7 when the network comes back. 'maint' may be past v1.8.1.6 and its tip won't be pointing at that tag, but it still is missing from the public repository. Right, I think tags at the tip is too likely to miss things you did want to send. While I agree with your goal to make it safer to use push, both ignore commits that the receiving end already saw and only look at the commits at the tip being sent castrate the option too much to the point that it is meaningless. The whole point of asking explicitly with the --follow-tags option to push to push out relevant tags is, eh, to push out relevant tags. I do not think it is magical at all. backfill is an integral part of the option. I know, and I'm willing to accept that the right resolution is we should not have this feature (or possibly the documentation must warn about caveats of the feature). I'm just worried about it accidentally being misused and causing problems. -Peff -- To unsubscribe from this list: send the line unsubscribe git in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 2/2] push: --follow-tag
The new option --follow-tag tells git push to push tags that are missing from the other side and that can be reached by the history that is otherwise pushed out. For example, if you are using the simple, current, or upstream push, you would ordinarily push the history leading to the commit at your current HEAD and nothing else. With this option, you would also push all tags that can be reached from that commit to the other side. Signed-off-by: Junio C Hamano gits...@pobox.com --- * The previous and this were built on 'maint', and may have trivial conflicts with 'master' and upwards. This is primarily to scratch my own itch; after tagging an rc or final release, I've been doing git push k.org v1.8.2 git push k.org and the first step can easily be forgotten. With git push k.org --follow-tag I no longer should have to worry about that. It will push out whatever would be pushed out without --follow-tag, and also tags that are missing from my k.org repository that point into the history being pushed out. I'd certainly need help with phrasing in the documentation, by the way. Documentation/git-push.txt | 8 +++- builtin/push.c | 2 + remote.c | 92 ++ remote.h | 3 +- t/t5516-fetch-push.sh | 73 transport.c| 2 + transport.h| 1 + 7 files changed, 179 insertions(+), 2 deletions(-) diff --git a/Documentation/git-push.txt b/Documentation/git-push.txt index 8b637d3..5020662 100644 --- a/Documentation/git-push.txt +++ b/Documentation/git-push.txt @@ -9,7 +9,7 @@ git-push - Update remote refs along with associated objects SYNOPSIS [verse] -'git push' [--all | --mirror | --tags] [-n | --dry-run] [--receive-pack=git-receive-pack] +'git push' [--all | --mirror | --tags] [--follow-tag] [-n | --dry-run] [--receive-pack=git-receive-pack] [--repo=repository] [-f | --force] [--prune] [-v | --verbose] [-u | --set-upstream] [repository [refspec...]] @@ -111,6 +111,12 @@ no `push.default` configuration variable is set. addition to refspecs explicitly listed on the command line. +--follow-tag:: + Push all the refs that would be pushed without this option, + and also push the refs under `refs/tags` that are missing + from the remote but are reachable from the refs that would + be pushed without this option. + --receive-pack=git-receive-pack:: --exec=git-receive-pack:: Path to the 'git-receive-pack' program on the remote diff --git a/builtin/push.c b/builtin/push.c index db9ba30..08e3db1 100644 --- a/builtin/push.c +++ b/builtin/push.c @@ -399,6 +399,8 @@ int cmd_push(int argc, const char **argv, const char *prefix) OPT_BOOL(0, progress, progress, N_(force progress reporting)), OPT_BIT(0, prune, flags, N_(prune locally removed refs), TRANSPORT_PUSH_PRUNE), + OPT_BIT(0, follow-tag, flags, N_(push missing but relevant tags), + TRANSPORT_PUSH_FOLLOW_TAG), OPT_END() }; diff --git a/remote.c b/remote.c index ca1f8f2..4441944 100644 --- a/remote.c +++ b/remote.c @@ -1195,6 +1195,94 @@ static struct ref **tail_ref(struct ref **head) return tail; } +struct tips { + struct commit **tip; + int nr, alloc; +}; + +static void add_to_tips(struct tips *tips, struct ref *ref) +{ + struct commit *commit; + + if (is_null_sha1(ref-new_sha1)) + return; + commit = lookup_commit_reference_gently(ref-new_sha1, 1); + if (!commit) + return; /* not pushing a commit, which is not an error */ + ALLOC_GROW(tips-tip, tips-nr + 1, tips-alloc); + tips-tip[tips-nr++] = commit; +} + +static void add_missing_tags(struct ref *src, struct ref **dst, struct ref ***dst_tail) +{ + struct string_list dst_tag = STRING_LIST_INIT_NODUP; + struct string_list src_tag = STRING_LIST_INIT_NODUP; + struct string_list_item *item; + struct ref *ref; + struct tips sent_tips; + + /* +* Collect everything we are going to send +* and collect all tags they have. +*/ + memset(sent_tips, 0, sizeof(sent_tips)); + for (ref = *dst; ref; ref = ref-next) { + if (ref-peer_ref + !is_null_sha1(ref-peer_ref-new_sha1)) + add_to_tips(sent_tips, ref-peer_ref); + if (!prefixcmp(ref-name, refs/tags/)) + string_list_append(dst_tag, ref-name); + } + sort_string_list(dst_tag); + + /* Collect tags they do not have. */ + for (ref = src; ref; ref = ref-next) { + if (prefixcmp(ref-name, refs/tags/)) + continue; + if