{"thread":{"id":"52034","subject":"[RFC PATCH 0/1] Teach remote add a --prefix-tags option","startedAt":"2019-10-14T22:02:13Z","lastAt":"2019-10-16T05:02:59Z","messageCount":6,"participants":["Wink Saville","Junio C Hamano","Jacob Keller"],"isPatch":true,"patchVersion":1,"patchTotal":1},"messages":[{"id":"384041","messageId":"cover.1571089481.git.wink@saville.com","threadId":"52034","inReplyTo":null,"subject":"[RFC PATCH 0/1] Teach remote add a --prefix-tags option","fromName":"Wink Saville","fromEmail":"wink@saville.com","sentAt":"2019-10-14T22:00:59Z","receivedAt":"2019-10-14T22:02:13Z","isPatch":true,"sender":{"key":"wink@saville.com","avatar":"https://avatars.githubusercontent.com/u/1024284?v=4"},"body":"Hello,\n\nThis patch was originally created as a pull request on github [1] and\nthen languisheh as I forgot about it. Recently I was asked to revive it\nand have done so. I've rebased on top of master and validated it still\nworks.\n\nPlease review.\n\n-- Wink\n\n[1]: https://github.com/git/git/pull/486\n\nWink Saville (1):\n  Teach remote add the --prefix-tags option\n\n Documentation/git-remote.txt |  8 +++++--\n builtin/remote.c             | 42 ++++++++++++++++++++++++++++++++----\n remote.c                     |  2 ++\n 3 files changed, 46 insertions(+), 6 deletions(-)\n\n-- \n2.16.2.7164.g7daebe18fb\n\n"},{"id":"384042","messageId":"d47c5de5fc812b1fbd04bb259a522e453d4b21e2.1571089481.git.wink@saville.com","threadId":"52034","inReplyTo":"cover.1571089481.git.wink@saville.com","subject":"[RFC PATCH 1/1] Teach remote add the --prefix-tags option","fromName":"Wink Saville","fromEmail":"wink@saville.com","sentAt":"2019-10-14T22:01:00Z","receivedAt":"2019-10-14T22:02:29Z","isPatch":true,"sender":{"key":"wink@saville.com","avatar":"https://avatars.githubusercontent.com/u/1024284?v=4"},"body":"When --prefix-tags is passed to `git remote add` the tagopt is set to\n--prefix-tags and a second fetch line is added so tags are placed in\na separate hierarchy per remote.\n\nFor example:\n  $ git remote add -f --prefix-tags gbenchmark git@github.com:google/benchmark\n  Updating gbenchmark\n  warning: no common commits\n  remote: Counting objects: 4406, done.\n  remote: Compressing objects: 100% (18/18), done.\n  remote: Total 4406 (delta 7), reused 13 (delta 6), pack-reused 4382\n  Receiving objects: 100% (4406/4406), 1.34 MiB | 7.58 MiB/s, done.\n  Resolving deltas: 100% (2865/2865), done.\n  From github.com:google/benchmark\n   * [new branch]      clangtidy       -> gbenchmark/clangtidy\n   * [new branch]      iter_report     -> gbenchmark/iter_report\n   * [new branch]      master          -> gbenchmark/master\n   * [new branch]      releasing       -> gbenchmark/releasing\n   * [new branch]      reportercleanup -> gbenchmark/reportercleanup\n   * [new branch]      rmheaders       -> gbenchmark/rmheaders\n   * [new branch]      v2              -> gbenchmark/v2\n   * [new tag]         v0.0.9          -> tags/gbenchmark/v0.0.9\n   * [new tag]         v0.1.0          -> tags/gbenchmark/v0.1.0\n   * [new tag]         v1.0.0          -> tags/gbenchmark/v1.0.0\n   * [new tag]         v1.1.0          -> tags/gbenchmark/v1.1.0\n   * [new tag]         v1.2.0          -> tags/gbenchmark/v1.2.0\n   * [new tag]         v1.3.0          -> tags/gbenchmark/v1.3.0\n   * [new tag]         v1.4.0          -> tags/gbenchmark/v1.4.0\n\nAnd the .git/config remote \"gbenchmark\" section looks like:\n  [remote \"gbenchmark\"]\n    url = git@github.com:google/benchmark\n    fetch = +refs/heads/*:refs/remotes/gbenchmark/*\n    fetch = +refs/tags/*:refs/remotes/tags/gbenchmark/*\n    tagopt = --prefix-tags\n\nBased on a solution proposed by Junio on the email list [1]\n\n[1]: https://public-inbox.org/git/xmqqbme51rgn.fsf@gitster-ct.c.googlers.com/T/#me7f7f153b8ba742c0dc48d8ec79c280c9682d32e\n\nHelped-by: Junio C Hamano <gitster@pobox.com>\nHelped-by: Jacob Keller <jacob.keller@gmail.com>\nSigned-off-by: Wink Saville <wink@saville.com>\n---\n Documentation/git-remote.txt |  8 +++++--\n builtin/remote.c             | 42 ++++++++++++++++++++++++++++++++----\n remote.c                     |  2 ++\n 3 files changed, 46 insertions(+), 6 deletions(-)\n\ndiff --git a/Documentation/git-remote.txt b/Documentation/git-remote.txt\nindex 9659abbf8e..db0238e8bd 100644\n--- a/Documentation/git-remote.txt\n+++ b/Documentation/git-remote.txt\n@@ -10,7 +10,7 @@ SYNOPSIS\n --------\n [verse]\n 'git remote' [-v | --verbose]\n-'git remote add' [-t <branch>] [-m <master>] [-f] [--[no-]tags] [--mirror=<fetch|push>] <name> <url>\n+'git remote add' [-t <branch>] [-m <master>] [-f] [--tags | --prefix-tags | --no-tags] [--mirror=<fetch|push>] <name> <url>\n 'git remote rename' <old> <new>\n 'git remote remove' <name>\n 'git remote set-head' <name> (-a | --auto | -d | --delete | <branch>)\n@@ -54,7 +54,11 @@ With `-f` option, `git fetch <name>` is run immediately after\n the remote information is set up.\n +\n With `--tags` option, `git fetch <name>` imports every tag from the\n-remote repository.\n+remote repository to refs/tags, use --prefix-tags to import them\n+to refs/remotes/tags/<name>/<tag>.\n++\n+With `--prefix-tags` option, `git fetch <name>` imports every tag from the\n+remote repository to refs/remotes/tags/<name>/<tag>.\n +\n With `--no-tags` option, `git fetch <name>` does not import tags from\n the remote repository.\ndiff --git a/builtin/remote.c b/builtin/remote.c\nindex 5591cef775..88991f9fbe 100644\n--- a/builtin/remote.c\n+++ b/builtin/remote.c\n@@ -14,7 +14,7 @@\n \n static const char * const builtin_remote_usage[] = {\n \tN_(\"git remote [-v | --verbose]\"),\n-\tN_(\"git remote add [-t <branch>] [-m <master>] [-f] [--tags | --no-tags] [--mirror=<fetch|push>] <name> <url>\"),\n+\tN_(\"git remote add [-t <branch>] [-m <master>] [-f] [--prefix-tags | --tags | --no-tags] [--mirror=<fetch|push>] <name> <url>\"),\n \tN_(\"git remote rename <old> <new>\"),\n \tN_(\"git remote remove <name>\"),\n \tN_(\"git remote set-head <name> (-a | --auto | -d | --delete | <branch>)\"),\n@@ -104,7 +104,8 @@ static int fetch_remote(const char *name)\n enum {\n \tTAGS_UNSET = 0,\n \tTAGS_DEFAULT = 1,\n-\tTAGS_SET = 2\n+\tTAGS_SET = 2,\n+\tTAGS_SET_PREFIX = 3\n };\n \n #define MIRROR_NONE 0\n@@ -126,6 +127,14 @@ static void add_branch(const char *key, const char *branchname,\n \tgit_config_set_multivar(key, tmp->buf, \"^$\", 0);\n }\n \n+static void add_remote_tags(const char *key, const char *remotename,\n+\t\t\t    struct strbuf *tmp)\n+{\n+\tstrbuf_reset(tmp);\n+\tstrbuf_addf(tmp, \"+refs/tags/*:refs/remotes/tags/%s/*\", remotename);\n+\tgit_config_set_multivar(key, tmp->buf, \"^$\", 0);\n+}\n+\n static const char mirror_advice[] =\n N_(\"--mirror is dangerous and deprecated; please\\n\"\n    \"\\t use --mirror=fetch or --mirror=push instead\");\n@@ -164,6 +173,9 @@ static int add(int argc, const char **argv)\n \t\tOPT_SET_INT(0, \"tags\", &fetch_tags,\n \t\t\t    N_(\"import all tags and associated objects when fetching\"),\n \t\t\t    TAGS_SET),\n+\t\tOPT_SET_INT(0, \"prefix-tags\", &fetch_tags,\n+\t\t\t    N_(\"import all tags and associated objects when fetching and prefix with <name>\"),\n+\t\t\t    TAGS_SET_PREFIX),\n \t\tOPT_SET_INT(0, NULL, &fetch_tags,\n \t\t\t    N_(\"or do not fetch any tag at all (--no-tags)\"), TAGS_UNSET),\n \t\tOPT_STRING_LIST('t', \"track\", &track, N_(\"branch\"),\n@@ -185,6 +197,8 @@ static int add(int argc, const char **argv)\n \t\tdie(_(\"specifying a master branch makes no sense with --mirror\"));\n \tif (mirror && !(mirror & MIRROR_FETCH) && track.nr)\n \t\tdie(_(\"specifying branches to track makes sense only with fetch mirrors\"));\n+\tif (mirror && (fetch_tags == TAGS_SET_PREFIX))\n+\t\tdie(_(\"specifying a --prefix-tags makes no sense with --mirror\"));\n \n \tname = argv[0];\n \turl = argv[1];\n@@ -218,10 +232,30 @@ static int add(int argc, const char **argv)\n \t}\n \n \tif (fetch_tags != TAGS_DEFAULT) {\n+\t\tif (fetch_tags == TAGS_SET_PREFIX) {\n+\t\t\tstrbuf_reset(&buf);\n+\t\t\tstrbuf_addf(&buf, \"remote.%s.fetch\", name);\n+\t\t\tadd_remote_tags(buf.buf, name, &buf2);\n+\t\t}\n+\n \t\tstrbuf_reset(&buf);\n \t\tstrbuf_addf(&buf, \"remote.%s.tagopt\", name);\n-\t\tgit_config_set(buf.buf,\n-\t\t\t       fetch_tags == TAGS_SET ? \"--tags\" : \"--no-tags\");\n+\t\tchar *config_val = NULL;\n+\t\tswitch (fetch_tags) {\n+\t\tcase TAGS_UNSET:\n+\t\t\tconfig_val = \"--no-tags\";\n+\t\t\tbreak;\n+\t\tcase TAGS_SET:\n+\t\t\tconfig_val = \"--tags\";\n+\t\t\tbreak;\n+\t\tcase TAGS_SET_PREFIX:\n+\t\t\tconfig_val = \"--prefix-tags\";\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\tdie(_(\"Unexpected TAGS enum %d\"), fetch_tags);\n+\t\t\tbreak;\n+\t\t}\n+\t\tgit_config_set(buf.buf, config_val);\n \t}\n \n \tif (fetch && fetch_remote(name))\ndiff --git a/remote.c b/remote.c\nindex e50f7602ed..d916fda029 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -421,6 +421,8 @@ static int handle_config(const char *key, const char *value, void *cb)\n \t\t\tremote->fetch_tags = -1;\n \t\telse if (!strcmp(value, \"--tags\"))\n \t\t\tremote->fetch_tags = 2;\n+\t\telse if (!strcmp(value, \"--prefix-tags\"))\n+\t\t\tremote->fetch_tags = -1;\n \t} else if (!strcmp(subkey, \"proxy\")) {\n \t\treturn git_config_string((const char **)&remote->http_proxy,\n \t\t\t\t\t key, value);\n-- \n2.16.2.7164.g7daebe18fb\n\n"},{"id":"384060","messageId":"xmqq4l0ad7vn.fsf@gitster-ct.c.googlers.com","threadId":"52034","inReplyTo":"d47c5de5fc812b1fbd04bb259a522e453d4b21e2.1571089481.git.wink@saville.com","subject":"Re: [RFC PATCH 1/1] Teach remote add the --prefix-tags option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-10-15T03:07:08Z","receivedAt":"2019-10-15T03:07:17Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Wink Saville <wink@saville.com> writes:\n\n> When --prefix-tags is passed to `git remote add` the tagopt is set to\n> --prefix-tags and a second fetch line is added so tags are placed in\n> a separate hierarchy per remote.\n\n\nIn the olden days, there was no refs/remotes/$remoteName/ hiearchy,\nand until we made it the default at around Git 1.5.0, such a modern\nlayout for the branches were called the \"separate remote\" layout,\nand can be opted into with \"clone --use-separate-remote\" by early\nadopters.\n\nI doubt that use of refs/tags/$remoteName/ is a good design if we\nwant to achieve similar isolation between local tags and and tags\nobtained from each remote.\n\nAn obvious alternative, refs/remotes/$remoteName/tags/, is not a\ngood design for exactly the same reason.  You cannot tell between a\nlocal tag foo/bar and a tag bar obtained from remote foo when you\nsee refs/tags/foo/bar, and you cannot tell between a branch tag/bar\nobtained from remote foo and a tag bar obtained from remote foo when\nyou see refs/remotes/foo/tags/bar.  In the past, people suggested to\nuse refs/remoteTags/$remoteName/ for proper isolation, and it might\nbe a better middle-ground than either of the two, at least in the\nshorter term, but not ideal.\n\nIn short, if you truly want to see \"separate hierarchy per remote\",\nyou should consider how you can reliably implement an equivalent of\n\"git branch --list --remote\"; a design that does not allow it is a\nfailure.\n\nA better solution with longer lifetime would probably be to use\n\n\trefs/remotes/$remoteName/{heads,tags,...}/\n\nwhen core.useTotallySeparateRemote configuration exists (and\neventually at Git 3.0 make the layout the default).  It would\ninvolve changes in the refname look-up rules, but it would not have\nto pollute refs/ namespace like the refs/remoteTags/ half-ground\ndesign, which would require us to add refs/remoteNotes/ and friends,\nwho knows how many more we would end up having to support if we go\nthat route.\n\nThanks.\n\n\n\n"},{"id":"384111","messageId":"CAKk8isq0W86ONoEMxh7kiik75qeOxvznh2j1-91GEehZQDzRrA@mail.gmail.com","threadId":"52034","inReplyTo":"xmqq4l0ad7vn.fsf@gitster-ct.c.googlers.com","subject":"Re: [RFC PATCH 1/1] Teach remote add the --prefix-tags option","fromName":"Wink Saville","fromEmail":"wink@saville.com","sentAt":"2019-10-15T17:56:00Z","receivedAt":"2019-10-15T17:56:16Z","isPatch":true,"sender":{"key":"wink@saville.com","avatar":"https://avatars.githubusercontent.com/u/1024284?v=4"},"body":"> In short, if you truly want to see \"separate hierarchy per remote\",\n> you should consider how you can reliably implement an equivalent of\n> \"git branch --list --remote\"; a design that does not allow it is a\n> failure.\n>\n> A better solution with longer lifetime would probably be to use\n>\n>         refs/remotes/$remoteName/{heads,tags,...}/\n>\n> when core.useTotallySeparateRemote configuration exists (and\n> eventually at Git 3.0 make the layout the default).  It would\n> involve changes in the refname look-up rules, but it would not have\n> to pollute refs/ namespace like the refs/remoteTags/ half-ground\n> design, which would require us to add refs/remoteNotes/ and friends,\n> who knows how many more we would end up having to support if we go\n> that route.\n\nI've used submodules a little bit and in some sense it seems to\nalready implement\ncore.useTotallySeparateRemote. So from my perspective trying to make this change\nsignificantly different this isn't worth the effort and I'm not sure I\nhave the expertise\nto do it well.\n\nIs there a roadmap and or timeline for Git 3.0?\n"},{"id":"384113","messageId":"CA+P7+xr-4WXuDFL-D8pmoxFvLB0Rkm4zsGO9=aOy5-3o=m=5Tg@mail.gmail.com","threadId":"52034","inReplyTo":"xmqq4l0ad7vn.fsf@gitster-ct.c.googlers.com","subject":"Re: [RFC PATCH 1/1] Teach remote add the --prefix-tags option","fromName":"Jacob Keller","fromEmail":"jacob.keller@gmail.com","sentAt":"2019-10-15T18:33:52Z","receivedAt":"2019-10-15T18:34:08Z","isPatch":true,"sender":{"key":"jacob.keller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/874719?v=4"},"body":"On Mon, Oct 14, 2019 at 8:07 PM Junio C Hamano <gitster@pobox.com> wrote:\n>\n> Wink Saville <wink@saville.com> writes:\n>\n> > When --prefix-tags is passed to `git remote add` the tagopt is set to\n> > --prefix-tags and a second fetch line is added so tags are placed in\n> > a separate hierarchy per remote.\n>\n>\n> In the olden days, there was no refs/remotes/$remoteName/ hiearchy,\n> and until we made it the default at around Git 1.5.0, such a modern\n> layout for the branches were called the \"separate remote\" layout,\n> and can be opted into with \"clone --use-separate-remote\" by early\n> adopters.\n>\n> I doubt that use of refs/tags/$remoteName/ is a good design if we\n> want to achieve similar isolation between local tags and and tags\n> obtained from each remote.\n>\n> An obvious alternative, refs/remotes/$remoteName/tags/, is not a\n> good design for exactly the same reason.  You cannot tell between a\n> local tag foo/bar and a tag bar obtained from remote foo when you\n> see refs/tags/foo/bar, and you cannot tell between a branch tag/bar\n> obtained from remote foo and a tag bar obtained from remote foo when\n> you see refs/remotes/foo/tags/bar.  In the past, people suggested to\n> use refs/remoteTags/$remoteName/ for proper isolation, and it might\n> be a better middle-ground than either of the two, at least in the\n> shorter term, but not ideal.\n>\n> In short, if you truly want to see \"separate hierarchy per remote\",\n> you should consider how you can reliably implement an equivalent of\n> \"git branch --list --remote\"; a design that does not allow it is a\n> failure.\n>\n> A better solution with longer lifetime would probably be to use\n>\n>         refs/remotes/$remoteName/{heads,tags,...}/\n>\n> when core.useTotallySeparateRemote configuration exists (and\n> eventually at Git 3.0 make the layout the default).  It would\n> involve changes in the refname look-up rules, but it would not have\n> to pollute refs/ namespace like the refs/remoteTags/ half-ground\n> design, which would require us to add refs/remoteNotes/ and friends,\n> who knows how many more we would end up having to support if we go\n> that route.\n>\n> Thanks.\n>\n\nSomething like this makes sense and I've thought about the problem for\na long time. Unfortunately it's quite a bit trickier to do this.\n\nIt would solve the problem more generally though, and definitely seems\nlike the right approach.. but at least for me, every time I looked at\ntrying this I got lost. I haven't had time to investigate it recently\n:(\n\nThanks,\nJake\n"},{"id":"384159","messageId":"CA+P7+xpdYMA8L-_Y+W5q7_zbj9RNcH1erY=dVbDG-EDOiHhTwA@mail.gmail.com","threadId":"52034","inReplyTo":"CAKk8isrcR2TgiQ9B8nYgfKKLoLSs9moLrqQ007+NA5VzOG3Evg@mail.gmail.com","subject":"Re: [RFC PATCH 1/1] Teach remote add the --prefix-tags option","fromName":"Jacob Keller","fromEmail":"jacob.keller@gmail.com","sentAt":"2019-10-16T05:02:45Z","receivedAt":"2019-10-16T05:02:59Z","isPatch":true,"sender":{"key":"jacob.keller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/874719?v=4"},"body":"On Tue, Oct 15, 2019 at 2:13 PM Wink Saville <wink@saville.com> wrote:\n>>\n>> Something like this makes sense and I've thought about the problem for\n>> a long time. Unfortunately it's quite a bit trickier to do this.\n>>\n>> It would solve the problem more generally though, and definitely seems\n>> like the right approach.. but at least for me, every time I looked at\n>> trying this I got lost. I haven't had time to investigate it recently\n>> :(\n>>\n>> Thanks,\n>> Jake\n>\n>\n> Give it a go, you'll learn something at a minimum :)\n\nI've started a couple of times, but mostly it's lack of time to\ninvest, since $DAYJOB hasn't given me cycles to try at the moment.\n\nThanks,\nJake\n"}]}