{"thread":{"id":"36048","subject":"[RFC] make --set-upstream work for local branches not in refs/heads","startedAt":"2014-03-04T14:07:25Z","lastAt":"2014-03-06T09:27:28Z","messageCount":4,"participants":["Krzesimir Nowak","Junio C Hamano"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"235993","messageId":"1393942046-11488-1-git-send-email-krzesimir@endocode.com","threadId":"36048","inReplyTo":null,"subject":"[RFC] make --set-upstream work for local branches not in refs/heads","fromName":"Krzesimir Nowak","fromEmail":"krzesimir@endocode.com","sentAt":"2014-03-04T14:07:25Z","receivedAt":"2014-03-04T14:07:25Z","isPatch":false,"sender":{"key":"krzesimir@endocode.com","avatar":"https://avatars.githubusercontent.com/u/96081?v=4"},"body":"It might be possible (in \"Gerrited\" setups) to have local branches\noutside refs/heads/, like for example in following fetch config:\n\n[remote \"origin\"]\n\turl = ssh://user@example.com/my-project\n\tfetch = +refs/heads/*:refs/remotes/origin/*\n\tfetch = +refs/wip/*:refs/remotes/origin-wip/*\n\nLet's say that 'test' branch already exist in origin/refs/wip/. If I\ncall:\n\ngit checkout test\n\nthen it will create a new branch and add an entry to .git/config:\n\n[branch \"test\"]\n\tremote = origin\n\tmerge = refs/wip/test\n\nBut if I create a branch 'test2' and call:\n\ngit push --set-upstream origin test2:refs/wip/test2\n\nthen branch is pushed, but no entry in .git config is created. I have\nto do it manually. I attached a hack-patch to have it working just to\ncheck with you if anything like that would be accepted. Obviously the\nget_local_refs() would need to compute the actual list of local\nhierarchies (if it is possible at all). And it probably should get a\nbetter name. And probably something else.\n\nWhat do you think?\n\nKrzesimir Nowak (1):\n  RFC: make --set-upstream work for branches not in refs/heads/\n\n transport.c | 41 ++++++++++++++++++++++++++++++++++-------\n 1 file changed, 34 insertions(+), 7 deletions(-)\n\n-- \n1.8.3.1\n"},{"id":"235994","messageId":"1393942046-11488-2-git-send-email-krzesimir@endocode.com","threadId":"36048","inReplyTo":"1393942046-11488-1-git-send-email-krzesimir@endocode.com","subject":"[PATCH] RFC: make --set-upstream work for branches not in refs/heads/","fromName":"Krzesimir Nowak","fromEmail":"krzesimir@endocode.com","sentAt":"2014-03-04T14:07:26Z","receivedAt":"2014-03-04T14:07:26Z","isPatch":true,"sender":{"key":"krzesimir@endocode.com","avatar":"https://avatars.githubusercontent.com/u/96081?v=4"},"body":"---\n transport.c | 41 ++++++++++++++++++++++++++++++++++-------\n 1 file changed, 34 insertions(+), 7 deletions(-)\n\ndiff --git a/transport.c b/transport.c\nindex ca7bb44..ac933ee 100644\n--- a/transport.c\n+++ b/transport.c\n@@ -143,6 +143,25 @@ static void insert_packed_refs(const char *packed_refs, struct ref **list)\n \t}\n }\n \n+/* That of course should not be hardcoded. */\n+static const char* list_of_local_refs[] = {\"refs/heads/\", \"refs/wip/\", NULL};\n+static const char** get_local_refs(void)\n+{\n+\treturn list_of_local_refs;\n+}\n+\n+static int is_local_ref(const char *ref)\n+{\n+\tconst char **local_refs = get_local_refs();\n+\tconst char **iter;\n+\n+\tfor (iter = local_refs; iter != NULL; ++iter)\n+\t\tif (starts_with(ref, *iter))\n+\t\t\treturn strlen(*iter);\n+\n+\treturn 0;\n+}\n+\n static void set_upstreams(struct transport *transport, struct ref *refs,\n \tint pretend)\n {\n@@ -153,6 +172,8 @@ static void set_upstreams(struct transport *transport, struct ref *refs,\n \t\tconst char *remotename;\n \t\tunsigned char sha[20];\n \t\tint flag = 0;\n+\t\tint localadd = 0;\n+\t\tint remoteadd = 0;\n \t\t/*\n \t\t * Check suitability for tracking. Must be successful /\n \t\t * already up-to-date ref create/modify (not delete).\n@@ -169,23 +190,29 @@ static void set_upstreams(struct transport *transport, struct ref *refs,\n \t\tlocalname = ref->peer_ref->name;\n \t\tremotename = ref->name;\n \t\ttmp = resolve_ref_unsafe(localname, sha, 1, &flag);\n-\t\tif (tmp && flag & REF_ISSYMREF &&\n-\t\t\tstarts_with(tmp, \"refs/heads/\"))\n-\t\t\tlocalname = tmp;\n+\n+\t\tif (tmp && flag & REF_ISSYMREF) {\n+\t\t\tlocaladd = is_local_ref (tmp);\n+\t\t\tif (localadd > 0)\n+\t\t\t\tlocalname = tmp;\n+\t\t}\n+\t\tif (localadd == 0)\n+\t\t\tlocaladd = is_local_ref(localname);\n+\t\tremoteadd = is_local_ref(remotename);\n \n \t\t/* Both source and destination must be local branches. */\n-\t\tif (!localname || !starts_with(localname, \"refs/heads/\"))\n+\t\tif (!localname || localadd == 0)\n \t\t\tcontinue;\n-\t\tif (!remotename || !starts_with(remotename, \"refs/heads/\"))\n+\t\tif (!remotename || remoteadd == 0)\n \t\t\tcontinue;\n \n \t\tif (!pretend)\n \t\t\tinstall_branch_config(BRANCH_CONFIG_VERBOSE,\n-\t\t\t\tlocalname + 11, transport->remote->name,\n+\t\t\t\tlocalname + localadd, transport->remote->name,\n \t\t\t\tremotename);\n \t\telse\n \t\t\tprintf(\"Would set upstream of '%s' to '%s' of '%s'\\n\",\n-\t\t\t\tlocalname + 11, remotename + 11,\n+\t\t\t\tlocalname + localadd, remotename + remoteadd,\n \t\t\t\ttransport->remote->name);\n \t}\n }\n-- \n1.8.3.1\n"},{"id":"236024","messageId":"xmqqlhwpkats.fsf@gitster.dls.corp.google.com","threadId":"36048","inReplyTo":"1393942046-11488-1-git-send-email-krzesimir@endocode.com","subject":"Re: [RFC] make --set-upstream work for local branches not in refs/heads","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2014-03-04T19:44:47Z","receivedAt":"2014-03-04T19:44:47Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Krzesimir Nowak <krzesimir@endocode.com> writes:\n\n> It might be possible (in \"Gerrited\" setups) to have local branches\n> outside refs/heads/, like for example in following fetch config:\n>\n> [remote \"origin\"]\n> \turl = ssh://user@example.com/my-project\n> \tfetch = +refs/heads/*:refs/remotes/origin/*\n> \tfetch = +refs/wip/*:refs/remotes/origin-wip/*\n>\n> Let's say that 'test' branch already exist in origin/refs/wip/. If I\n> call:\n>\n> git checkout test\n>\n> then it will create a new branch and add an entry to .git/config:\n>\n> [branch \"test\"]\n> \tremote = origin\n> \tmerge = refs/wip/test\n>\n> But if I create a branch 'test2' and call:\n>\n> git push --set-upstream origin test2:refs/wip/test2\n>\n> then branch is pushed, but no entry in .git config is created.\n\nBy definition anything otuside refs/heads/ is not a branch, so do\nnot call things in refs/wip \"branches\".  Retitle it to \"work for\nlocal refs outside refs/heads\" or something.\n\nHaving said that, I do not see a major problem if we allowed\n\n\t[branch \"test2\"]\n\t\tremote = origin\n                merge = refs/wip/test2\n\nto be created when \"push --setupstream\" is requested, making\ntest2@{upstream} to point at refs/remotes/origin-wip/test2.\n\nI do not know what the correct implementation of such a feature\nshould be, though.\n"},{"id":"236155","messageId":"1394098048.2050.19.camel@localhost.localdomain","threadId":"36048","inReplyTo":"xmqqlhwpkats.fsf@gitster.dls.corp.google.com","subject":"Re: [RFC] make --set-upstream work for local branches not in refs/heads","fromName":"Krzesimir Nowak","fromEmail":"krzesimir@endocode.com","sentAt":"2014-03-06T09:27:28Z","receivedAt":"2014-03-06T09:27:28Z","isPatch":false,"sender":{"key":"krzesimir@endocode.com","avatar":"https://avatars.githubusercontent.com/u/96081?v=4"},"body":"On Tue, 2014-03-04 at 11:44 -0800, Junio C Hamano wrote:\n> Krzesimir Nowak <krzesimir@endocode.com> writes:\n> \n> > It might be possible (in \"Gerrited\" setups) to have local branches\n> > outside refs/heads/, like for example in following fetch config:\n> >\n> > [remote \"origin\"]\n> > \turl = ssh://user@example.com/my-project\n> > \tfetch = +refs/heads/*:refs/remotes/origin/*\n> > \tfetch = +refs/wip/*:refs/remotes/origin-wip/*\n> >\n> > Let's say that 'test' branch already exist in origin/refs/wip/. If I\n> > call:\n> >\n> > git checkout test\n> >\n> > then it will create a new branch and add an entry to .git/config:\n> >\n> > [branch \"test\"]\n> > \tremote = origin\n> > \tmerge = refs/wip/test\n> >\n> > But if I create a branch 'test2' and call:\n> >\n> > git push --set-upstream origin test2:refs/wip/test2\n> >\n> > then branch is pushed, but no entry in .git config is created.\n> \n> By definition anything otuside refs/heads/ is not a branch, so do\n> not call things in refs/wip \"branches\".  Retitle it to \"work for\n> local refs outside refs/heads\" or something.\n\nI always have problems with proper use of git's terminology. Sorry.\n\n> \n> Having said that, I do not see a major problem if we allowed\n> \n> \t[branch \"test2\"]\n> \t\tremote = origin\n>                 merge = refs/wip/test2\n> \n> to be created when \"push --setupstream\" is requested, making\n> test2@{upstream} to point at refs/remotes/origin-wip/test2.\n> \n> I do not know what the correct implementation of such a feature\n> should be, though.\n\nHm, have some idea about it, though I will leave its sanity to judge to\nyou.\n\nGiven the following config snippet:\n[remote \"origin\"]\n\turl = ssh://user@example.com/my-project\n\tfetch = +refs/heads/*:refs/remotes/origin/*\n\tfetch = +refs/wip/*:refs/remotes/origin-wip/*\n\nWe could have get_local_ref_hierarchies function defined somewhat as\nfollows (memory management details are left out):\n\nchar **get_local_ref_hierarchies(char *remote)\n{\n\tchar **refspecs = get_fetch_refspecs_for_remote (remote);\n\tchar **iter;\n\tchar **local = NULL;\n\n\tfor (iter = refspecs; iter && *iter; ++iter) {\n\t\tchar *src = get_src_refspec_part (*iter);\n\t\tpush (&local, src);\n\t}\n\n\t/* maybe filter dups and make refs/heads/ first */\n\treturn local;\n}\n\nI'm sure that there are some corner-cases this code does not handle.\n\nAlso, maybe it would be good to add some information when --set-upstream\ndoes nothing. Something like after doing \"git push --set-upstream origin\ntest:refs/wip/test\":\n\n\"\"\"\nCould not set temp to track refs/wip/test. Either call:\ngit config branch.test.remote origin\ngit config branch.test.merge refs/wip/test\n\nor (this part would appear if this solution in patch is accepted)\n\ngit config --add remote.origin.fetch \\\n\"+refs/wip/*:refs/remotes/origin-wip/*\n\"\"\"\n\nCheers,\n-- \nKrzesimir Nowak\nSoftware Developer\nEndocode AG\n\nkrzesimir@endocode.com\n\n------\nEndocode AG, Johannisstraße 20, 10117 Berlin\ninfo@endocode.com | www.endocode.com\n\nVorstandsvorsitzender: Mirko Boehm\nVorstände: Dr. Karl Beecher, Chris Kühl, Sebastian Sucker\nAufsichtsratsvorsitzende: Jennifer Beecher\n\nRegistergericht: Amtsgericht Charlottenburg - HRB 150748 B\n"}]}