{"thread":{"id":"46883","subject":"[PATCH 0/3] for-each-ref: add :remote-ref and :remote-name specifiers","startedAt":"2017-10-02T13:56:43Z","lastAt":"2017-11-08T01:37:00Z","messageCount":32,"participants":["Johannes Schindelin","Junio C Hamano","Kevin Daudt"],"isPatch":true,"patchVersion":1,"patchTotal":3},"messages":[{"id":"329440","messageId":"cover.1506952571.git.johannes.schindelin@gmx.de","threadId":"46883","inReplyTo":null,"subject":"[PATCH 0/3] for-each-ref: add :remote-ref and :remote-name specifiers","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-10-02T13:56:32Z","receivedAt":"2017-10-02T13:56:43Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"This introduces support for\n\n\tgit for-each-ref \\\n\t\t--format=\"%(merge:remote-name),%(merge:remote-ref)\"\n\tgit for-each-ref \\\n\t\t--format=\"%(push:remote-name),%(push:remote-ref)\"\n\nto figure out the remote nickname as well as the name of the corresponding\nbranch on the remote.\n\nNote: the `%(push:remote-name)` placeholder is only interpolated by the value\nof `branch.<name>.pushRemote`; unlike `git push`, it does not fall back to\n`branch.<name>.remote`. Likewise, `%(push:remote-ref)` interpolates to the\nempty string unless `remote.<nick>.pushRefs` is configured.\n\nThis is useful for third-party tools that need to know this type of information\nfor tons of branches.\n\n\nJ Wyman (1):\n  for-each-ref: let upstream/push optionally report merge name.\n\nJohannes Schindelin (2):\n  for-each-ref: let upstream/push optionally report the remote name\n  for-each-ref: test :remote-name and :remote-ref\n\n Documentation/git-for-each-ref.txt | 19 +++++++++++--------\n ref-filter.c                       | 35 +++++++++++++++++++++++++++++++----\n remote.c                           | 30 ++++++++++++++++++++++++++++++\n remote.h                           |  2 ++\n t/t6300-for-each-ref.sh            | 32 ++++++++++++++++++++++++++++++++\n 5 files changed, 106 insertions(+), 12 deletions(-)\n\n\nbase-commit: ea220ee40cbb03a63ebad2be902057bf742492fd\nPublished-As: https://github.com/dscho/git/releases/tag/ref-filter-remote-name-v1\nFetch-It-Via: git fetch https://github.com/dscho/git ref-filter-remote-name-v1\n-- \n2.14.2.windows.1\n\n"},{"id":"329441","messageId":"0e03bf1e50e24a52f57be0f51d19f4657c68d2fa.1506952571.git.johannes.schindelin@gmx.de","threadId":"46883","inReplyTo":"cover.1506952571.git.johannes.schindelin@gmx.de","subject":"[PATCH 1/3] for-each-ref: let upstream/push optionally report the remote name","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-10-02T13:56:37Z","receivedAt":"2017-10-02T13:56:48Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"There are times when e.g. scripts want to know not only the name of the\nupstream branch on the remote repository, but also the name of the\nremote.\n\nThis patch offers the new suffix :remote for the upstream and for the\npush atoms, allowing to show exactly that. Example:\n\n\t$ cat .git/config\n\t...\n\t[remote \"origin\"]\n\t\turl = https://where.do.we.come/from\n\t\tfetch = refs/heads/*:refs/remote/origin/*\n\t[remote \"hello-world\"]\n\t\turl = https://hello.world/git\n\t\tfetch = refs/heads/*:refs/remote/origin/*\n\t\tpushURL = hello.world:git\n\t\tpush = refs/heads/*:refs/heads/*\n\t[branch \"master\"]\n\t\tremote = origin\n\t\tpushRemote = hello-world\n\t...\n\n\t$ git for-each-ref \\\n\t\t--format='%(upstream) %(upstream:remote) %(push:remote)' \\\n\t\trefs/heads/master\n\trefs/remotes/origin/master origin hello-world\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n Documentation/git-for-each-ref.txt | 16 +++++++++-------\n ref-filter.c                       | 25 +++++++++++++++++++++----\n 2 files changed, 30 insertions(+), 11 deletions(-)\n\ndiff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt\nindex 66b4e0a4050..776368ee531 100644\n--- a/Documentation/git-for-each-ref.txt\n+++ b/Documentation/git-for-each-ref.txt\n@@ -140,17 +140,19 @@ upstream::\n \t(behind), \"<>\" (ahead and behind), or \"=\" (in sync). `:track`\n \talso prints \"[gone]\" whenever unknown upstream ref is\n \tencountered. Append `:track,nobracket` to show tracking\n-\tinformation without brackets (i.e \"ahead N, behind M\").  Has\n-\tno effect if the ref does not have tracking information\n-\tassociated with it.  All the options apart from `nobracket`\n-\tare mutually exclusive, but if used together the last option\n-\tis selected.\n+\tinformation without brackets (i.e \"ahead N, behind M\").  Also\n+\trespects `:remote-name` to state the name of the *remote* instead of\n+\tthe ref.\n++\n+Has no effect if the ref does not have tracking information associated\n+with it.  All the options apart from `nobracket` are mutually exclusive,\n+but if used together the last option is selected.\n \n push::\n \tThe name of a local ref which represents the `@{push}`\n \tlocation for the displayed ref. Respects `:short`, `:lstrip`,\n-\t`:rstrip`, `:track`, and `:trackshort` options as `upstream`\n-\tdoes. Produces an empty string if no `@{push}` ref is\n+\t`:rstrip`, `:track`, `:trackshort` and `:remote-name` options as\n+\t`upstream` does. Produces an empty string if no `@{push}` ref is\n \tconfigured.\n \n HEAD::\ndiff --git a/ref-filter.c b/ref-filter.c\nindex bc591f4f3de..58d53c09390 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -76,7 +76,9 @@ static struct used_atom {\n \t\tchar color[COLOR_MAXLEN];\n \t\tstruct align align;\n \t\tstruct {\n-\t\t\tenum { RR_REF, RR_TRACK, RR_TRACKSHORT } option;\n+\t\t\tenum {\n+\t\t\t\tRR_REF, RR_TRACK, RR_TRACKSHORT, RR_REMOTE_NAME\n+\t\t\t} option;\n \t\t\tstruct refname_atom refname;\n \t\t\tunsigned int nobracket : 1;\n \t\t} remote_ref;\n@@ -156,6 +158,8 @@ static void remote_ref_atom_parser(const struct ref_format *format, struct used_\n \t\t\tatom->u.remote_ref.option = RR_TRACKSHORT;\n \t\telse if (!strcmp(s, \"nobracket\"))\n \t\t\tatom->u.remote_ref.nobracket = 1;\n+\t\telse if (!strcmp(s, \"remote-name\"))\n+\t\t\tatom->u.remote_ref.option = RR_REMOTE_NAME;\n \t\telse {\n \t\t\tatom->u.remote_ref.option = RR_REF;\n \t\t\trefname_atom_parser_internal(&atom->u.remote_ref.refname,\n@@ -1247,6 +1251,15 @@ static void fill_remote_ref_details(struct used_atom *atom, const char *refname,\n \t\t\t*s = \">\";\n \t\telse\n \t\t\t*s = \"<>\";\n+\t} else if (atom->u.remote_ref.option == RR_REMOTE_NAME) {\n+\t\tint explicit;\n+\t\tconst char *remote = starts_with(atom->name, \"push\") ?\n+\t\t\tpushremote_for_branch(branch, &explicit) :\n+\t\t\tremote_for_branch(branch, &explicit);\n+\t\tif (explicit)\n+\t\t\t*s = xstrdup(remote);\n+\t\telse\n+\t\t\t*s = \"\";\n \t} else\n \t\tdie(\"BUG: unhandled RR_* enum\");\n }\n@@ -1364,9 +1377,13 @@ static void populate_value(struct ref_array_item *ref)\n \t\t\t\tcontinue;\n \t\t\tbranch = branch_get(branch_name);\n \n-\t\t\trefname = branch_get_push(branch, NULL);\n-\t\t\tif (!refname)\n-\t\t\t\tcontinue;\n+\t\t\tif (starts_with(name, \"push:remote-\"))\n+\t\t\t\trefname = NULL;\n+\t\t\telse {\n+\t\t\t\trefname = branch_get_push(branch, NULL);\n+\t\t\t\tif (!refname)\n+\t\t\t\t\tcontinue;\n+\t\t\t}\n \t\t\tfill_remote_ref_details(atom, refname, branch, &v->s);\n \t\t\tcontinue;\n \t\t} else if (starts_with(name, \"color:\")) {\n-- \n2.14.2.windows.1\n\n\n"},{"id":"329442","messageId":"f615fcc05fa358b4c7e3531cbdbd91661be321aa.1506952571.git.johannes.schindelin@gmx.de","threadId":"46883","inReplyTo":"cover.1506952571.git.johannes.schindelin@gmx.de","subject":"[PATCH 2/3] for-each-ref: let upstream/push optionally report merge name.","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-10-02T13:57:46Z","receivedAt":"2017-10-02T13:57:59Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: J Wyman <jwyman@microsoft.com>\n\nThere are times when scripts want to know not only the name of the\npush branch on the remote, but also the name of the branch as known\nby the remote repository.\n\nA useful example of this is with the push command where\n`branch.<name>.merge` is useful as the <to> value. Example:\n\n\t$ git push <remote> <from>:<to>\n\nThis patch offers the new suffix :merge for the push atom, allowing to\nshow exactly that. Example:\n\n\t$ cat .git/config\n\t...\n\t[remote \"origin\"]\n\t\turl = https://where.do.we.come/from\n\t\tfetch = refs/heads/*:refs/remote/origin/*\n\t[branch \"master\"]\n\t\tremote = origin\n\t\tmerge = refs/heads/master\n\t[branch \"develop/with/topics\"]\n\t\tremote = origin\n\t\tmerge = refs/heads/develop/with/topics\n\t...\n\n\t$ git for-each-ref \\\n\t\t--format='%(push) %(push:remote-ref)' \\\n\t\trefs/heads\n\trefs/remotes/origin/master refs/heads/master\n\trefs/remotes/origin/develop/with/topics refs/heads/develop/with/topics\n---\n Documentation/git-for-each-ref.txt | 11 ++++++-----\n ref-filter.c                       | 12 +++++++++++-\n remote.c                           | 30 ++++++++++++++++++++++++++++++\n remote.h                           |  2 ++\n 4 files changed, 49 insertions(+), 6 deletions(-)\n\ndiff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt\nindex 776368ee531..ba1147a1223 100644\n--- a/Documentation/git-for-each-ref.txt\n+++ b/Documentation/git-for-each-ref.txt\n@@ -141,8 +141,9 @@ upstream::\n \talso prints \"[gone]\" whenever unknown upstream ref is\n \tencountered. Append `:track,nobracket` to show tracking\n \tinformation without brackets (i.e \"ahead N, behind M\").  Also\n-\trespects `:remote-name` to state the name of the *remote* instead of\n-\tthe ref.\n+\trespects `:remote-name` to state the name of the *remote* instead\n+\tof the ref, and `:remote-ref` to state the name of the *reference*\n+\tas locally known by the remote.\n +\n Has no effect if the ref does not have tracking information associated\n with it.  All the options apart from `nobracket` are mutually exclusive,\n@@ -151,9 +152,9 @@ but if used together the last option is selected.\n push::\n \tThe name of a local ref which represents the `@{push}`\n \tlocation for the displayed ref. Respects `:short`, `:lstrip`,\n-\t`:rstrip`, `:track`, `:trackshort` and `:remote-name` options as\n-\t`upstream` does. Produces an empty string if no `@{push}` ref is\n-\tconfigured.\n+\t`:rstrip`, `:track`, `:trackshort`, `:remote-name`, and `:remote-ref`\n+\toptions as `upstream` does. Produces an empty string if no `@{push}`\n+\tref is configured.\n \n HEAD::\n \t'*' if HEAD matches current ref (the checked out branch), ' '\ndiff --git a/ref-filter.c b/ref-filter.c\nindex 58d53c09390..4401e573b8a 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -77,7 +77,7 @@ static struct used_atom {\n \t\tstruct align align;\n \t\tstruct {\n \t\t\tenum {\n-\t\t\t\tRR_REF, RR_TRACK, RR_TRACKSHORT, RR_REMOTE_NAME\n+\t\t\t\tRR_REF, RR_TRACK, RR_TRACKSHORT, RR_REMOTE_NAME, RR_REMOTE_REF\n \t\t\t} option;\n \t\t\tstruct refname_atom refname;\n \t\t\tunsigned int nobracket : 1;\n@@ -160,6 +160,8 @@ static void remote_ref_atom_parser(const struct ref_format *format, struct used_\n \t\t\tatom->u.remote_ref.nobracket = 1;\n \t\telse if (!strcmp(s, \"remote-name\"))\n \t\t\tatom->u.remote_ref.option = RR_REMOTE_NAME;\n+\t\telse if (!strcmp(s, \"remote-ref\"))\n+\t\t\tatom->u.remote_ref.option = RR_REMOTE_REF;\n \t\telse {\n \t\t\tatom->u.remote_ref.option = RR_REF;\n \t\t\trefname_atom_parser_internal(&atom->u.remote_ref.refname,\n@@ -1260,6 +1262,14 @@ static void fill_remote_ref_details(struct used_atom *atom, const char *refname,\n \t\t\t*s = xstrdup(remote);\n \t\telse\n \t\t\t*s = \"\";\n+\t} else if (atom->u.remote_ref.option == RR_REMOTE_REF) {\n+\t\tint explicit, for_push = starts_with(atom->name, \"push\");\n+\t\tconst char *merge = remote_ref_for_branch(branch, for_push,\n+\t\t\t\t\t\t\t  &explicit);\n+\t\tif (explicit)\n+\t\t\t*s = xstrdup(merge);\n+\t\telse\n+\t\t\t*s = \"\";\n \t} else\n \t\tdie(\"BUG: unhandled RR_* enum\");\n }\ndiff --git a/remote.c b/remote.c\nindex b220f0dfc61..2bdcfc280cd 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -675,6 +675,36 @@ const char *pushremote_for_branch(struct branch *branch, int *explicit)\n \treturn remote_for_branch(branch, explicit);\n }\n \n+const char *remote_ref_for_branch(struct branch *branch, int for_push,\n+\t\t\t\t  int *explicit)\n+{\n+\tif (branch) {\n+\t\tif (!for_push) {\n+\t\t\tif (branch->merge_nr) {\n+\t\t\t\tif (explicit)\n+\t\t\t\t\t*explicit = 1;\n+\t\t\t\treturn branch->merge_name[0];\n+\t\t\t}\n+\t\t} else {\n+\t\t\tconst char *dst, *remote_name =\n+\t\t\t\tpushremote_for_branch(branch, NULL);\n+\t\t\tstruct remote *remote = remote_get(remote_name);\n+\n+\t\t\tif (remote && remote->push_refspec_nr &&\n+\t\t\t    (dst = apply_refspecs(remote->push,\n+\t\t\t\t\t\t  remote->push_refspec_nr,\n+\t\t\t\t\t\t  branch->refname))) {\n+\t\t\t\tif (explicit)\n+\t\t\t\t\t*explicit = 1;\n+\t\t\t\treturn dst;\n+\t\t\t}\n+\t\t}\n+\t}\n+\tif (explicit)\n+\t\t*explicit = 0;\n+\treturn \"\";\n+}\n+\n static struct remote *remote_get_1(const char *name,\n \t\t\t\t   const char *(*get_default)(struct branch *, int *))\n {\ndiff --git a/remote.h b/remote.h\nindex 2ecf4c8c74c..1f6611be214 100644\n--- a/remote.h\n+++ b/remote.h\n@@ -223,6 +223,8 @@ struct branch {\n struct branch *branch_get(const char *name);\n const char *remote_for_branch(struct branch *branch, int *explicit);\n const char *pushremote_for_branch(struct branch *branch, int *explicit);\n+const char *remote_ref_for_branch(struct branch *branch, int for_push,\n+\t\t\t\t  int *explicit);\n \n int branch_has_merge_config(struct branch *branch);\n int branch_merge_matches(struct branch *, int n, const char *);\n-- \n2.14.2.windows.1\n\n\n"},{"id":"329443","messageId":"2d67e8e061c268ef996845e43b065630dc0330ad.1506952571.git.johannes.schindelin@gmx.de","threadId":"46883","inReplyTo":"cover.1506952571.git.johannes.schindelin@gmx.de","subject":"[PATCH 3/3] for-each-ref: test :remote-name and :remote-ref","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-10-02T13:57:52Z","receivedAt":"2017-10-02T13:58:01Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"This not only prevents regressions, but also serves as documentation\nwhat this new feature is expected to do.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n t/t6300-for-each-ref.sh | 32 ++++++++++++++++++++++++++++++++\n 1 file changed, 32 insertions(+)\n\ndiff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh\nindex 2274a4b7331..edc73dd79aa 100755\n--- a/t/t6300-for-each-ref.sh\n+++ b/t/t6300-for-each-ref.sh\n@@ -675,4 +675,36 @@ test_expect_success 'Verify usage of %(symref:rstrip) atom' '\n \ttest_cmp expected actual\n '\n \n+test_expect_success ':remote-name and :remote-ref' '\n+\tgit init remote-tests &&\n+\t(\n+\t\tcd remote-tests &&\n+\t\ttest_commit initial &&\n+\t\tgit remote add from fifth.coffee:blub &&\n+\t\tgit config branch.master.remote from &&\n+\t\tgit config branch.master.merge refs/heads/stable &&\n+\t\tgit remote add to southridge.audio:repo &&\n+\t\tgit config remote.to.push \"refs/heads/*:refs/heads/pushed/*\" &&\n+\t\tgit config branch.master.pushRemote to &&\n+\t\tfor pair in \"%(upstream)=refs/remotes/from/stable\" \\\n+\t\t\t\"%(upstream:remote-name)=from\" \\\n+\t\t\t\"%(upstream:remote-ref)=refs/heads/stable\" \\\n+\t\t\t\"%(push)=refs/remotes/to/pushed/master\" \\\n+\t\t\t\"%(push:remote-name)=to\" \\\n+\t\t\t\"%(push:remote-ref)=refs/heads/pushed/master\"\n+\t\tdo\n+\t\t\techo \"${pair#*=}\" >expect &&\n+\t\t\tgit for-each-ref --format=\"${pair%=*}\" \\\n+\t\t\t\trefs/heads/master >actual &&\n+\t\t\ttest_cmp expect actual\n+\t\tdone &&\n+\t\tgit branch push-simple &&\n+\t\tgit config branch.push-simple.pushRemote from &&\n+\t\tactual=\"$(git for-each-ref \\\n+\t\t\t--format=\"%(push:remote-name),%(push:remote-ref)\" \\\n+\t\t\trefs/heads/push-simple)\" &&\n+\t\ttest from, = \"$actual\"\n+\t)\n+'\n+\n test_done\n-- \n2.14.2.windows.1\n"},{"id":"329660","messageId":"xmqq376zcrls.fsf@gitster.mtv.corp.google.com","threadId":"46883","inReplyTo":"0e03bf1e50e24a52f57be0f51d19f4657c68d2fa.1506952571.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH 1/3] for-each-ref: let upstream/push optionally report the remote name","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-10-04T07:14:07Z","receivedAt":"2017-10-04T07:14:20Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n\n> This patch offers the new suffix :remote for the upstream and for the\n> push atoms, allowing to show exactly that.\n\nHas the design changed since this description and examples were\nwritten?  The documentation talks about \":remote-name\".  I suspect\ncalling this \":remote\" might be less hassle, as we do not have to\nvet the current vocabulary to see if \"remote-name\" is the right way\nto name a multi-word modifer (as opposed to \"remotename\", or\n\"remoteName\", or \"remote_name\", or...).\n\n> \t...\n>\n> \t$ git for-each-ref \\\n> \t\t--format='%(upstream) %(upstream:remote) %(push:remote)' \\\n> \t\trefs/heads/master\n\n> diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt\n> index 66b4e0a4050..776368ee531 100644\n> --- a/Documentation/git-for-each-ref.txt\n> +++ b/Documentation/git-for-each-ref.txt\n> @@ -140,17 +140,19 @@ upstream::\n\nAside from \"':remote-name'?  Do we really want that?\" issue I\nalready mentioned, the changes to this file look sensible.\n\n> diff --git a/ref-filter.c b/ref-filter.c\n> index bc591f4f3de..58d53c09390 100644\n> --- a/ref-filter.c\n> +++ b/ref-filter.c\n> @@ -76,7 +76,9 @@ static struct used_atom {\n>  \t\tchar color[COLOR_MAXLEN];\n>  \t\tstruct align align;\n>  \t\tstruct {\n> -\t\t\tenum { RR_REF, RR_TRACK, RR_TRACKSHORT } option;\n> +\t\t\tenum {\n> +\t\t\t\tRR_REF, RR_TRACK, RR_TRACKSHORT, RR_REMOTE_NAME\n> +\t\t\t} option;\n>  \t\t\tstruct refname_atom refname;\n>  \t\t\tunsigned int nobracket : 1;\n>  \t\t} remote_ref;\n> @@ -156,6 +158,8 @@ static void remote_ref_atom_parser(const struct ref_format *format, struct used_\n>  \t\t\tatom->u.remote_ref.option = RR_TRACKSHORT;\n>  \t\telse if (!strcmp(s, \"nobracket\"))\n>  \t\t\tatom->u.remote_ref.nobracket = 1;\n> +\t\telse if (!strcmp(s, \"remote-name\"))\n> +\t\t\tatom->u.remote_ref.option = RR_REMOTE_NAME;\n>  \t\telse {\n>  \t\t\tatom->u.remote_ref.option = RR_REF;\n>  \t\t\trefname_atom_parser_internal(&atom->u.remote_ref.refname,\n> @@ -1247,6 +1251,15 @@ static void fill_remote_ref_details(struct used_atom *atom, const char *refname,\n>  \t\t\t*s = \">\";\n>  \t\telse\n>  \t\t\t*s = \"<>\";\n> +\t} else if (atom->u.remote_ref.option == RR_REMOTE_NAME) {\n> +\t\tint explicit;\n> +\t\tconst char *remote = starts_with(atom->name, \"push\") ?\n> +\t\t\tpushremote_for_branch(branch, &explicit) :\n> +\t\t\tremote_for_branch(branch, &explicit);\n\nI think \"int explicit = 0;\" is needed, as pushremote_for_branch()\ndoes seem to expect that the \"explicit\" return parameter is\ninitialized by the caller.\n\n> +\t\tif (explicit)\n> +\t\t\t*s = xstrdup(remote);\n> +\t\telse\n> +\t\t\t*s = \"\";\n\nThis one is debatable.  For the user of \"push\" who wants to learn\nwhere the branch is pushed to, the choice this patch makes is not\nuseful (i.e. such a user does not care where the definition comes\nfrom; s/he only wants to know where the push goes).  For the user of\n\"git config\" who wants to know how pushremote is configured, and\ndoes not want to accept the fallback to remote, the behaviour of\nthis patch is useful.  I have a mild suspicion that majority of\nusers who would want to use this feature would fall into the former\ncategory, i.e. users of \"push\", rather than the latter, i.e.\ndebuggers of their config files, and if that is true, we can drop\nthe whole \"explicit\" business to simplify the code and get a more\nuseful behaviour at the same time ;-)\n\n> @@ -1364,9 +1377,13 @@ static void populate_value(struct ref_array_item *ref)\n>  \t\t\t\tcontinue;\n>  \t\t\tbranch = branch_get(branch_name);\n>  \n> -\t\t\trefname = branch_get_push(branch, NULL);\n> -\t\t\tif (!refname)\n> -\t\t\t\tcontinue;\n> +\t\t\tif (starts_with(name, \"push:remote-\"))\n\nI am not sure what is going on here.  \n\nAre we expecting \"push:remote-name\" here, or anticipating\n\"push:remote-bar\" can also be given or what?\n\n> +\t\t\t\trefname = NULL;\n> +\t\t\telse {\n> +\t\t\t\trefname = branch_get_push(branch, NULL);\n> +\t\t\t\tif (!refname)\n> +\t\t\t\t\tcontinue;\n> +\t\t\t}\n>  \t\t\tfill_remote_ref_details(atom, refname, branch, &v->s);\n>  \t\t\tcontinue;\n>  \t\t} else if (starts_with(name, \"color:\")) {\n"},{"id":"329670","messageId":"xmqq7ewbb7qq.fsf@gitster.mtv.corp.google.com","threadId":"46883","inReplyTo":"xmqq376zcrls.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH 1/3] for-each-ref: let upstream/push optionally report the remote name","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-10-04T09:08:29Z","receivedAt":"2017-10-04T09:08:36Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n>> +\t} else if (atom->u.remote_ref.option == RR_REMOTE_NAME) {\n>> +\t\tint explicit;\n>> +\t\tconst char *remote = starts_with(atom->name, \"push\") ?\n>> +\t\t\tpushremote_for_branch(branch, &explicit) :\n>> +\t\t\tremote_for_branch(branch, &explicit);\n>\n> I think \"int explicit = 0;\" is needed, as pushremote_for_branch()\n> does seem to expect that the \"explicit\" return parameter is\n> initialized by the caller.\n\nNot really. I misread these helper functions.  pushremote_for_branch()\nends up calling remote_for_branch() which does clear, so we are OK\nwithout caller initializing it.\n"},{"id":"329671","messageId":"xmqq4lrfb7jk.fsf@gitster.mtv.corp.google.com","threadId":"46883","inReplyTo":"f615fcc05fa358b4c7e3531cbdbd91661be321aa.1506952571.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH 2/3] for-each-ref: let upstream/push optionally report merge name.","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-10-04T09:12:47Z","receivedAt":"2017-10-04T09:12:54Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n\n> From: J Wyman <jwyman@microsoft.com>\n>\n> There are times when scripts want to know not only the name of the\n> push branch on the remote, but also the name of the branch as known\n> by the remote repository.\n>\n> A useful example of this is with the push command where\n> `branch.<name>.merge` is useful as the <to> value. Example:\n>\n> \t$ git push <remote> <from>:<to>\n>\n> This patch offers the new suffix :merge for the push atom, allowing to\n> show exactly that. Example:\n>\n> \t$ cat .git/config\n> \t...\n> \t[remote \"origin\"]\n> \t\turl = https://where.do.we.come/from\n> \t\tfetch = refs/heads/*:refs/remote/origin/*\n> \t[branch \"master\"]\n> \t\tremote = origin\n> \t\tmerge = refs/heads/master\n> \t[branch \"develop/with/topics\"]\n> \t\tremote = origin\n> \t\tmerge = refs/heads/develop/with/topics\n> \t...\n>\n> \t$ git for-each-ref \\\n> \t\t--format='%(push) %(push:remote-ref)' \\\n> \t\trefs/heads\n> \trefs/remotes/origin/master refs/heads/master\n> \trefs/remotes/origin/develop/with/topics refs/heads/develop/with/topics\n\nAh, now it is clear that we _need_ to figure out how to spell\n\"multi-word\" modifier to the format specifiers, as \"push:remote\"\nwould not let us differenciate the products of 1/3 and 2/3 X-<.\n\n> ---\n\nWe need two Signed-off-by: lines at the end, one by Wyman and then\nanother by you in this order.\n\n> --- a/Documentation/git-for-each-ref.txt\n> +++ b/Documentation/git-for-each-ref.txt\n\nChanges to this file in this patch looks sane.\n\n> --- a/ref-filter.c\n> +++ b/ref-filter.c\n> @@ -1260,6 +1262,14 @@ static void fill_remote_ref_details(struct used_atom *atom, const char *refname,\n>  \t\t\t*s = xstrdup(remote);\n>  \t\telse\n>  \t\t\t*s = \"\";\n> +\t} else if (atom->u.remote_ref.option == RR_REMOTE_REF) {\n> +\t\tint explicit, for_push = starts_with(atom->name, \"push\");\n> +\t\tconst char *merge = remote_ref_for_branch(branch, for_push,\n> +\t\t\t\t\t\t\t  &explicit);\n\nHaving multiple variables defined like this _and_ initialized with\nanything other than a trivial constant, is somewhat hard to follow.\nCan we split the above more like:\n\n\t\tint explicit;\n\t\tint for_push = starts_with(...);\n\t\tconst char *merge = remote_ref_for_branch(...);\n\nActually, if you did it this way, you do not even need \"for_push\":\n\n\t\tint explicit;\n\t\tconst char *merge;\n\n\t\tmerge = remote_ref_for_branch(branch,\n\t\t\t\t\t      starts_with(atom->name, \"push\"),\n\t\t\t\t\t      &explicit);\n\nwhich may be a lot easier to follow.\n\nBy the way, the spirit of parsing used atoms first before the \"learn\nwhat we care about this single ref\" function like the above are\ncalled repeatedly for each ref is because we want to hoist the\noverhead of doing the constant computation like \"does the atom's\nname begins with 'push'?\" out of the latter.  \n\nCan we add a field in atom->u.remote_ref to precompute this bit so\nthat we do not even have to say \"Are we doing this for push?  Let's\nsee if the atom's name begins with 'push'\" each time this function\nis called for a ref?  That makes this function a lot more in line\nwith the spirit of the design of the subsystem, I would think.\n\nThis comment probably applies equally to both 1/3 and this one.\n\n> +\t\tif (explicit)\n> +\t\t\t*s = xstrdup(merge);\n> +\t\telse\n> +\t\t\t*s = \"\";\n\nHere is the same \"who are we trying to help---users who want to know\nwhere their push goes, or users who are debugging where the push\ndestination is defined?\" question.  I do not have a strong opinion\neither way, but I think giving the end result with fallback (i.e.\nnot nullifying when the result is not explicit) may be easier to use\nby \"push\" users.\n\n> diff --git a/remote.c b/remote.c\n> index b220f0dfc61..2bdcfc280cd 100644\n> --- a/remote.c\n> +++ b/remote.c\n> @@ -675,6 +675,36 @@ const char *pushremote_for_branch(struct branch *branch, int *explicit)\n>  \treturn remote_for_branch(branch, explicit);\n>  }\n>  \n> +const char *remote_ref_for_branch(struct branch *branch, int for_push,\n> +\t\t\t\t  int *explicit)\n> +{\n> +\tif (branch) {\n> +\t\tif (!for_push) {\n> +\t\t\tif (branch->merge_nr) {\n> +\t\t\t\tif (explicit)\n> +\t\t\t\t\t*explicit = 1;\n> +\t\t\t\treturn branch->merge_name[0];\n> +\t\t\t}\n> +\t\t} else {\n> +\t\t\tconst char *dst, *remote_name =\n> +\t\t\t\tpushremote_for_branch(branch, NULL);\n> +\t\t\tstruct remote *remote = remote_get(remote_name);\n\nAgain,\n\n\t\t\tconst char *dst, *remote_name;\n                        struct remote *remote;\n\n\t\t\tremote_name = pushremote_for_branch(branch, NULL);\n                        remote = remote_get(remote_name);\n\nmay be easier to follow, if only that it allows eyes to scan without\nhaving to be distracted by jagged lines.\n\n> +\t\t\tif (remote && remote->push_refspec_nr &&\n> +\t\t\t    (dst = apply_refspecs(remote->push,\n> +\t\t\t\t\t\t  remote->push_refspec_nr,\n> +\t\t\t\t\t\t  branch->refname))) {\n> +\t\t\t\tif (explicit)\n> +\t\t\t\t\t*explicit = 1;\n> +\t\t\t\treturn dst;\n> +\t\t\t}\n> +\t\t}\n> +\t}\n> +\tif (explicit)\n> +\t\t*explicit = 0;\n> +\treturn \"\";\n> +}\n\nWhat the function does looks reasonable; the assignment in if()\ncondition looks a bit unfortunate, though.\n"},{"id":"329677","messageId":"xmqqvajv9m2k.fsf@gitster.mtv.corp.google.com","threadId":"46883","inReplyTo":"xmqq4lrfb7jk.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH 2/3] for-each-ref: let upstream/push optionally report merge name.","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-10-04T11:41:55Z","receivedAt":"2017-10-04T11:42:04Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n>> +\t\tif (explicit)\n>> +\t\t\t*s = xstrdup(merge);\n>> +\t\telse\n>> +\t\t\t*s = \"\";\n>\n> Here is the same \"who are we trying to help---users who want to know\n> where their push goes, or users who are debugging where the push\n> destination is defined?\" question.  I do not have a strong opinion\n> either way, but I think giving the end result with fallback (i.e.\n> not nullifying when the result is not explicit) may be easier to use\n> by \"push\" users.\n\nNow after thinking about it a bit more, I actually have a moderate\npreference to doing it the way your patches do.  With programatic\n%(if)%(else)%(end) support we acquired recently, the fallback can be\ncoded in the --format=... language if the user wanted to using the\n\"internal fallbacks, explicit==0, are ignored\" behaviour that are\nimplemented by these two patches.  The reverse is not true.\n\nI think the remaining points from my reviews are:\n\n - It would be better to compute precomputable stuff when used atoms\n   are parsed, instead of running starts_with() in these functions;\n\n - We want to make sure there is no existing multi-word modifiers\n   (in which case we can safely declare \"multi-word\" is the way we\n   spell them from now on).  Or if there are existing ones, they\n   already spell themselves as \"multi-word\".\n\n   I have nothing against \"remote-name\"; I just want to make sure we\n   are not making things inconsistent.  If there are only few (but\n   non zero number of) multi-word modifiers that are not spelled\n   \"multi-word\", as long as they are only few and their spelling are\n   inferiour (e.g. concatenatedwords is much worse than\n   concatenated-words), we could still declare \"multi-word\" is the\n   right way to spell them going forward, declare that we will give\n   them synonyms and deprecate the bad spelling out over time, and\n   leave that plan as #leftover bits thing (i.e. not doing the\n   deprecation of these other modifiers as part of this series.\n\n   The only thing I want to happen in the scope of _this_ series, as\n   due diligence, is to make sure we are happy with \"multi-word\",\n   and also to know if we need a follow-up work (just yes/no,\n   possibly with plans, but no actual work yet).\n\nThanks.\n"},{"id":"329717","messageId":"xmqqy3oq8ilw.fsf@gitster.mtv.corp.google.com","threadId":"46883","inReplyTo":"cover.1506952571.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH 0/3] for-each-ref: add :remote-ref and :remote-name specifiers","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-10-05T01:54:19Z","receivedAt":"2017-10-05T01:54:25Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n\n> Note: the `%(push:remote-name)` placeholder is only interpolated by the value\n> of `branch.<name>.pushRemote`; unlike `git push`, it does not fall back to\n> `branch.<name>.remote`. Likewise, `%(push:remote-ref)` interpolates to the\n> empty string unless `remote.<nick>.pushRefs` is configured.\n\nI think the reason why I had to spend more time than necessary on\nthe above point during my review on this (otherwise mostly well\ndone) topic was because of this note.  It says what it does, but\ndoes not say why this behaviour is better than the other obvious\nalternative.\n\nIn a reroll to address the remaining points, please update the log\nmessage (not the cover, which won't be in the committed history) to\nexplain why we think this is a better choice than an obvious\nalternative.  Let's help future readers of \"git log\".\n\nThanks.\n\n"},{"id":"329733","messageId":"xmqqzi966jn9.fsf@gitster.mtv.corp.google.com","threadId":"46883","inReplyTo":"xmqqvajv9m2k.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH 2/3] for-each-ref: let upstream/push optionally report merge name.","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-10-05T09:14:50Z","receivedAt":"2017-10-05T09:14:59Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> I think the remaining points from my reviews are:\n>\n>  - It would be better to compute precomputable stuff when used atoms\n>    are parsed, instead of running starts_with() in these functions;\n\nAfter reading the original (before these three patches) code for\npopulate_value(), I think reverting this mess back to how the thing\nwas originally envisioned to be would be outside the scope of this\naddition.  It was way too messy before your series than I expected.\n\nSo, unless you or your collaborator feel like helping us to clean up\nthe codebase for better future, let's forget about that point, and\nleave the cleaning up for now.\n\nFor those who want to help with the #leftoverbits, the first step of\ncleaning up would be to introduce an enum field that sits next to\nused_atom[i].name, and have the if/else if/... cascades use that\ninstead of these starts_with(name) to choose what value to grab from\nthe given ref.\n\n"},{"id":"329758","messageId":"cover.1507205895.git.johannes.schindelin@gmx.de","threadId":"46883","inReplyTo":"cover.1506952571.git.johannes.schindelin@gmx.de","subject":"[PATCH v2 0/3] for-each-ref: add :remoteref and :remotename specifiers","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-10-05T12:19:03Z","receivedAt":"2017-10-05T12:19:14Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"This introduces support for\n\n\tgit for-each-ref \\\n\t\t--format=\"%(merge:remotename),%(merge:remoteref)\"\n\tgit for-each-ref \\\n\t\t--format=\"%(push:remotename),%(push:remoteref)\"\n\nto figure out the remote nickname as well as the name of the corresponding\nbranch on the remote.\n\nNote: the `%(push:remotename)` placeholder is only interpolated by the value\nof `branch.<name>.pushRemote`; unlike `git push`, it does not fall back to\n`branch.<name>.remote`. Likewise, `%(push:remoteref)` interpolates to the\nempty string unless `remote.<nick>.pushRefs` is configured.\n\nThis is useful for third-party tools that need to know this type of information\nfor tons of branches.\n\nChanges since v1:\n\n- added the missing sign-offs\n\n- removed a full stop from the end of the oneline of 2/3 (quite frankly, I am\n  surprised I was not slammed for that in the first round of reviews ;-))\n\n- fixed stale commit message parts that were leftovers from previous, internal\n  review rounds\n\n- moved the added git-for-each-ref.txt documentation into its own paragraph\n\n- renamed the :remote-name and :remote-ref suffixes into the dashless form\n  :remotename and :remoteref, following the example of :trackshort\n\n- clarified the motivation for not DWIMming in the commit messages\n\n- added fields `push` and `push_remote` to the atom to precompute whether we\n  are talking about a `push` atom and whether it has a suffix starting with\n  `remote`, respectively\n\nNote that this last point actually fixes a bug when the user specified more\nthan one suffix (`push:short,remotename`; even if that `short` has no effect,\nthe `remotename` should).\n\n\nJ Wyman (1):\n  for-each-ref: let upstream/push optionally remote ref name\n\nJohannes Schindelin (2):\n  for-each-ref: let upstream/push optionally report the remote name\n  for-each-ref: test :remotename and :remoteref\n\n Documentation/git-for-each-ref.txt | 20 ++++++++++-------\n ref-filter.c                       | 46 ++++++++++++++++++++++++++++++++------\n remote.c                           | 30 +++++++++++++++++++++++++\n remote.h                           |  2 ++\n t/t6300-for-each-ref.sh            | 32 ++++++++++++++++++++++++++\n 5 files changed, 115 insertions(+), 15 deletions(-)\n\n\nbase-commit: 217f2767cbcb562872437eed4dec62e00846d90c\nPublished-As: https://github.com/dscho/git/releases/tag/ref-filter-remote-name-v2\nFetch-It-Via: git fetch https://github.com/dscho/git ref-filter-remote-name-v2\n\nInterdiff vs v1:\n diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt\n index ba1147a1223..22767025850 100644\n --- a/Documentation/git-for-each-ref.txt\n +++ b/Documentation/git-for-each-ref.txt\n @@ -140,10 +140,11 @@ upstream::\n  \t(behind), \"<>\" (ahead and behind), or \"=\" (in sync). `:track`\n  \talso prints \"[gone]\" whenever unknown upstream ref is\n  \tencountered. Append `:track,nobracket` to show tracking\n -\tinformation without brackets (i.e \"ahead N, behind M\").  Also\n -\trespects `:remote-name` to state the name of the *remote* instead\n -\tof the ref, and `:remote-ref` to state the name of the *reference*\n -\tas locally known by the remote.\n +\tinformation without brackets (i.e \"ahead N, behind M\").\n ++\n +Also respects `:remotename` to state the name of the *remote* instead\n +of the ref, and `:remoteref` to state the name of the *reference* as\n +locally known by the remote.\n  +\n  Has no effect if the ref does not have tracking information associated\n  with it.  All the options apart from `nobracket` are mutually exclusive,\n @@ -152,7 +153,7 @@ but if used together the last option is selected.\n  push::\n  \tThe name of a local ref which represents the `@{push}`\n  \tlocation for the displayed ref. Respects `:short`, `:lstrip`,\n -\t`:rstrip`, `:track`, `:trackshort`, `:remote-name`, and `:remote-ref`\n +\t`:rstrip`, `:track`, `:trackshort`, `:remotename`, and `:remoteref`\n  \toptions as `upstream` does. Produces an empty string if no `@{push}`\n  \tref is configured.\n  \n diff --git a/ref-filter.c b/ref-filter.c\n index 696a8241408..b4b2c9b2190 100644\n --- a/ref-filter.c\n +++ b/ref-filter.c\n @@ -80,7 +80,7 @@ static struct used_atom {\n  \t\t\t\tRR_REF, RR_TRACK, RR_TRACKSHORT, RR_REMOTE_NAME, RR_REMOTE_REF\n  \t\t\t} option;\n  \t\t\tstruct refname_atom refname;\n -\t\t\tunsigned int nobracket : 1;\n +\t\t\tunsigned int nobracket : 1, push : 1, push_remote : 1;\n  \t\t} remote_ref;\n  \t\tstruct {\n  \t\t\tenum { C_BARE, C_BODY, C_BODY_DEP, C_LINES, C_SIG, C_SUB, C_TRAILERS } option;\n @@ -139,6 +139,9 @@ static void remote_ref_atom_parser(const struct ref_format *format, struct used_\n  \tstruct string_list params = STRING_LIST_INIT_DUP;\n  \tint i;\n  \n +\tif (!strcmp(atom->name, \"push\") || starts_with(atom->name, \"push:\"))\n +\t\tatom->u.remote_ref.push = 1;\n +\n  \tif (!arg) {\n  \t\tatom->u.remote_ref.option = RR_REF;\n  \t\trefname_atom_parser_internal(&atom->u.remote_ref.refname,\n @@ -158,11 +161,13 @@ static void remote_ref_atom_parser(const struct ref_format *format, struct used_\n  \t\t\tatom->u.remote_ref.option = RR_TRACKSHORT;\n  \t\telse if (!strcmp(s, \"nobracket\"))\n  \t\t\tatom->u.remote_ref.nobracket = 1;\n -\t\telse if (!strcmp(s, \"remote-name\"))\n +\t\telse if (!strcmp(s, \"remotename\")) {\n  \t\t\tatom->u.remote_ref.option = RR_REMOTE_NAME;\n -\t\telse if (!strcmp(s, \"remote-ref\"))\n +\t\t\tatom->u.remote_ref.push_remote = 1;\n +\t\t} else if (!strcmp(s, \"remoteref\")) {\n  \t\t\tatom->u.remote_ref.option = RR_REMOTE_REF;\n -\t\telse {\n +\t\t\tatom->u.remote_ref.push_remote = 1;\n +\t\t} else {\n  \t\t\tatom->u.remote_ref.option = RR_REF;\n  \t\t\trefname_atom_parser_internal(&atom->u.remote_ref.refname,\n  \t\t\t\t\t\t     arg, atom->name);\n @@ -1253,7 +1258,7 @@ static void fill_remote_ref_details(struct used_atom *atom, const char *refname,\n  \t\t\t*s = \"<>\";\n  \t} else if (atom->u.remote_ref.option == RR_REMOTE_NAME) {\n  \t\tint explicit;\n -\t\tconst char *remote = starts_with(atom->name, \"push\") ?\n +\t\tconst char *remote = atom->u.remote_ref.push ?\n  \t\t\tpushremote_for_branch(branch, &explicit) :\n  \t\t\tremote_for_branch(branch, &explicit);\n  \t\tif (explicit)\n @@ -1377,14 +1382,14 @@ static void populate_value(struct ref_array_item *ref)\n  \t\t\tif (refname)\n  \t\t\t\tfill_remote_ref_details(atom, refname, branch, &v->s);\n  \t\t\tcontinue;\n -\t\t} else if (starts_with(name, \"push\")) {\n +\t\t} else if (atom->u.remote_ref.push) {\n  \t\t\tconst char *branch_name;\n  \t\t\tif (!skip_prefix(ref->refname, \"refs/heads/\",\n  \t\t\t\t\t &branch_name))\n  \t\t\t\tcontinue;\n  \t\t\tbranch = branch_get(branch_name);\n  \n -\t\t\tif (starts_with(name, \"push:remote-\"))\n +\t\t\tif (atom->u.remote_ref.push_remote)\n  \t\t\t\trefname = NULL;\n  \t\t\telse {\n  \t\t\t\trefname = branch_get_push(branch, NULL);\n diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh\n index edc73dd79aa..d9eb2be0256 100755\n --- a/t/t6300-for-each-ref.sh\n +++ b/t/t6300-for-each-ref.sh\n @@ -675,7 +675,7 @@ test_expect_success 'Verify usage of %(symref:rstrip) atom' '\n  \ttest_cmp expected actual\n  '\n  \n -test_expect_success ':remote-name and :remote-ref' '\n +test_expect_success ':remotename and :remoteref' '\n  \tgit init remote-tests &&\n  \t(\n  \t\tcd remote-tests &&\n @@ -687,11 +687,11 @@ test_expect_success ':remote-name and :remote-ref' '\n  \t\tgit config remote.to.push \"refs/heads/*:refs/heads/pushed/*\" &&\n  \t\tgit config branch.master.pushRemote to &&\n  \t\tfor pair in \"%(upstream)=refs/remotes/from/stable\" \\\n -\t\t\t\"%(upstream:remote-name)=from\" \\\n -\t\t\t\"%(upstream:remote-ref)=refs/heads/stable\" \\\n +\t\t\t\"%(upstream:remotename)=from\" \\\n +\t\t\t\"%(upstream:remoteref)=refs/heads/stable\" \\\n  \t\t\t\"%(push)=refs/remotes/to/pushed/master\" \\\n -\t\t\t\"%(push:remote-name)=to\" \\\n -\t\t\t\"%(push:remote-ref)=refs/heads/pushed/master\"\n +\t\t\t\"%(push:remotename)=to\" \\\n +\t\t\t\"%(push:remoteref)=refs/heads/pushed/master\"\n  \t\tdo\n  \t\t\techo \"${pair#*=}\" >expect &&\n  \t\t\tgit for-each-ref --format=\"${pair%=*}\" \\\n @@ -701,7 +701,7 @@ test_expect_success ':remote-name and :remote-ref' '\n  \t\tgit branch push-simple &&\n  \t\tgit config branch.push-simple.pushRemote from &&\n  \t\tactual=\"$(git for-each-ref \\\n -\t\t\t--format=\"%(push:remote-name),%(push:remote-ref)\" \\\n +\t\t\t--format=\"%(push:remotename),%(push:remoteref)\" \\\n  \t\t\trefs/heads/push-simple)\" &&\n  \t\ttest from, = \"$actual\"\n  \t)\n-- \n2.14.2.windows.1.2.gdc85205db4d\n\n"},{"id":"329759","messageId":"964525df50e6d35847bcf57b0fe0949c99f0dbca.1507205895.git.johannes.schindelin@gmx.de","threadId":"46883","inReplyTo":"cover.1507205895.git.johannes.schindelin@gmx.de","subject":"[PATCH v2 1/3] for-each-ref: let upstream/push optionally report the remote name","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-10-05T12:19:09Z","receivedAt":"2017-10-05T12:19:20Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"There are times when e.g. scripts want to know not only the name of the\nupstream branch on the remote repository, but also the name of the\nremote.\n\nThis patch offers the new suffix :remotename for the upstream and for\nthe push atoms, allowing to show exactly that. Example:\n\n\t$ cat .git/config\n\t...\n\t[remote \"origin\"]\n\t\turl = https://where.do.we.come/from\n\t\tfetch = refs/heads/*:refs/remote/origin/*\n\t[remote \"hello-world\"]\n\t\turl = https://hello.world/git\n\t\tfetch = refs/heads/*:refs/remote/origin/*\n\t\tpushURL = hello.world:git\n\t\tpush = refs/heads/*:refs/heads/*\n\t[branch \"master\"]\n\t\tremote = origin\n\t\tpushRemote = hello-world\n\t...\n\n\t$ git for-each-ref \\\n\t\t--format='%(upstream) %(upstream:remote) %(push:remote)' \\\n\t\trefs/heads/master\n\trefs/remotes/origin/master origin hello-world\n\nThe implementation chooses *not* to DWIM the push remote if no explicit\npush remote was configured; The reason is that it is possible to DWIM this\nby using\n\n\t%(if)%(push:remotename)%(then)\n\t\t%(push:remotename)\n\t%(else)\n\t\t%(upstream:remotename)\n\t%(end)\n\nwhile it would be impossible to \"un-DWIM\" the information in case the\ncaller is really only interested in explicit push remotes.\n\nWhile `:remote` would be shorter, it would also be a bit more ambiguous,\nand it would also shut the door e.g. for `:remoteref` (which would\nobviously refer to the corresponding ref in the remote repository).\n\nNote: the dashless, non-CamelCased form `:remotename` follows the\nexample of the `:trackshort` example.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n Documentation/git-for-each-ref.txt | 17 ++++++++++-------\n ref-filter.c                       | 35 ++++++++++++++++++++++++++++-------\n 2 files changed, 38 insertions(+), 14 deletions(-)\n\ndiff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt\nindex 66b4e0a4050..39f50bd53eb 100644\n--- a/Documentation/git-for-each-ref.txt\n+++ b/Documentation/git-for-each-ref.txt\n@@ -140,17 +140,20 @@ upstream::\n \t(behind), \"<>\" (ahead and behind), or \"=\" (in sync). `:track`\n \talso prints \"[gone]\" whenever unknown upstream ref is\n \tencountered. Append `:track,nobracket` to show tracking\n-\tinformation without brackets (i.e \"ahead N, behind M\").  Has\n-\tno effect if the ref does not have tracking information\n-\tassociated with it.  All the options apart from `nobracket`\n-\tare mutually exclusive, but if used together the last option\n-\tis selected.\n+\tinformation without brackets (i.e \"ahead N, behind M\").\n++\n+Also respects `:remotename` to state the name of the *remote* instead of\n+the ref.\n++\n+Has no effect if the ref does not have tracking information associated\n+with it.  All the options apart from `nobracket` are mutually exclusive,\n+but if used together the last option is selected.\n \n push::\n \tThe name of a local ref which represents the `@{push}`\n \tlocation for the displayed ref. Respects `:short`, `:lstrip`,\n-\t`:rstrip`, `:track`, and `:trackshort` options as `upstream`\n-\tdoes. Produces an empty string if no `@{push}` ref is\n+\t`:rstrip`, `:track`, `:trackshort` and `:remotename` options as\n+\t`upstream` does. Produces an empty string if no `@{push}` ref is\n \tconfigured.\n \n HEAD::\ndiff --git a/ref-filter.c b/ref-filter.c\nindex 55323620ab2..4819707d032 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -76,9 +76,11 @@ static struct used_atom {\n \t\tchar color[COLOR_MAXLEN];\n \t\tstruct align align;\n \t\tstruct {\n-\t\t\tenum { RR_REF, RR_TRACK, RR_TRACKSHORT } option;\n+\t\t\tenum {\n+\t\t\t\tRR_REF, RR_TRACK, RR_TRACKSHORT, RR_REMOTE_NAME\n+\t\t\t} option;\n \t\t\tstruct refname_atom refname;\n-\t\t\tunsigned int nobracket : 1;\n+\t\t\tunsigned int nobracket : 1, push : 1, push_remote : 1;\n \t\t} remote_ref;\n \t\tstruct {\n \t\t\tenum { C_BARE, C_BODY, C_BODY_DEP, C_LINES, C_SIG, C_SUB, C_TRAILERS } option;\n@@ -137,6 +139,9 @@ static void remote_ref_atom_parser(const struct ref_format *format, struct used_\n \tstruct string_list params = STRING_LIST_INIT_DUP;\n \tint i;\n \n+\tif (!strcmp(atom->name, \"push\") || starts_with(atom->name, \"push:\"))\n+\t\tatom->u.remote_ref.push = 1;\n+\n \tif (!arg) {\n \t\tatom->u.remote_ref.option = RR_REF;\n \t\trefname_atom_parser_internal(&atom->u.remote_ref.refname,\n@@ -156,7 +161,10 @@ static void remote_ref_atom_parser(const struct ref_format *format, struct used_\n \t\t\tatom->u.remote_ref.option = RR_TRACKSHORT;\n \t\telse if (!strcmp(s, \"nobracket\"))\n \t\t\tatom->u.remote_ref.nobracket = 1;\n-\t\telse {\n+\t\telse if (!strcmp(s, \"remotename\")) {\n+\t\t\tatom->u.remote_ref.option = RR_REMOTE_NAME;\n+\t\t\tatom->u.remote_ref.push_remote = 1;\n+\t\t} else {\n \t\t\tatom->u.remote_ref.option = RR_REF;\n \t\t\trefname_atom_parser_internal(&atom->u.remote_ref.refname,\n \t\t\t\t\t\t     arg, atom->name);\n@@ -1245,6 +1253,15 @@ static void fill_remote_ref_details(struct used_atom *atom, const char *refname,\n \t\t\t*s = \">\";\n \t\telse\n \t\t\t*s = \"<>\";\n+\t} else if (atom->u.remote_ref.option == RR_REMOTE_NAME) {\n+\t\tint explicit;\n+\t\tconst char *remote = atom->u.remote_ref.push ?\n+\t\t\tpushremote_for_branch(branch, &explicit) :\n+\t\t\tremote_for_branch(branch, &explicit);\n+\t\tif (explicit)\n+\t\t\t*s = xstrdup(remote);\n+\t\telse\n+\t\t\t*s = \"\";\n \t} else\n \t\tdie(\"BUG: unhandled RR_* enum\");\n }\n@@ -1354,16 +1371,20 @@ static void populate_value(struct ref_array_item *ref)\n \t\t\tif (refname)\n \t\t\t\tfill_remote_ref_details(atom, refname, branch, &v->s);\n \t\t\tcontinue;\n-\t\t} else if (starts_with(name, \"push\")) {\n+\t\t} else if (atom->u.remote_ref.push) {\n \t\t\tconst char *branch_name;\n \t\t\tif (!skip_prefix(ref->refname, \"refs/heads/\",\n \t\t\t\t\t &branch_name))\n \t\t\t\tcontinue;\n \t\t\tbranch = branch_get(branch_name);\n \n-\t\t\trefname = branch_get_push(branch, NULL);\n-\t\t\tif (!refname)\n-\t\t\t\tcontinue;\n+\t\t\tif (atom->u.remote_ref.push_remote)\n+\t\t\t\trefname = NULL;\n+\t\t\telse {\n+\t\t\t\trefname = branch_get_push(branch, NULL);\n+\t\t\t\tif (!refname)\n+\t\t\t\t\tcontinue;\n+\t\t\t}\n \t\t\tfill_remote_ref_details(atom, refname, branch, &v->s);\n \t\t\tcontinue;\n \t\t} else if (starts_with(name, \"color:\")) {\n-- \n2.14.2.windows.1.2.gdc85205db4d\n\n\n"},{"id":"329760","messageId":"7da6c7e2563d14cb7cd7ff2637c79c51896a9788.1507205895.git.johannes.schindelin@gmx.de","threadId":"46883","inReplyTo":"cover.1507205895.git.johannes.schindelin@gmx.de","subject":"[PATCH v2 2/3] for-each-ref: let upstream/push optionally remote ref name","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-10-05T12:19:15Z","receivedAt":"2017-10-05T12:19:35Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: J Wyman <jwyman@microsoft.com>\n\nThere are times when scripts want to know not only the name of the\npush branch on the remote, but also the name of the branch as known\nby the remote repository.\n\nAn example of this is when a tool wants to push to the very same branch\nfrom which it would pull automatically, i.e. the `<remote>` and the `<to>`\nin `git push <remote> <from>:<to>` would be provided by\n`%(upstream:remotename)` and `%(upstream:remoteref)`, respectively.\n\nThis patch offers the new suffix :remoteref for the `upstream` and `push`\natoms, allowing to show exactly that. Example:\n\n\t$ cat .git/config\n\t...\n\t[remote \"origin\"]\n\t\turl = https://where.do.we.come/from\n\t\tfetch = refs/heads/*:refs/remote/origin/*\n\t[branch \"master\"]\n\t\tremote = origin\n\t\tmerge = refs/heads/master\n\t[branch \"develop/with/topics\"]\n\t\tremote = origin\n\t\tmerge = refs/heads/develop/with/topics\n\t...\n\n\t$ git for-each-ref \\\n\t\t--format='%(push) %(push:remoteref)' \\\n\t\trefs/heads\n\trefs/remotes/origin/master refs/heads/master\n\trefs/remotes/origin/develop/with/topics refs/heads/develop/with/topics\n\nSigned-off-by: J Wyman <jwyman@microsoft.com>\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n Documentation/git-for-each-ref.txt | 11 ++++++-----\n ref-filter.c                       | 13 ++++++++++++-\n remote.c                           | 30 ++++++++++++++++++++++++++++++\n remote.h                           |  2 ++\n 4 files changed, 50 insertions(+), 6 deletions(-)\n\ndiff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt\nindex 39f50bd53eb..22767025850 100644\n--- a/Documentation/git-for-each-ref.txt\n+++ b/Documentation/git-for-each-ref.txt\n@@ -142,8 +142,9 @@ upstream::\n \tencountered. Append `:track,nobracket` to show tracking\n \tinformation without brackets (i.e \"ahead N, behind M\").\n +\n-Also respects `:remotename` to state the name of the *remote* instead of\n-the ref.\n+Also respects `:remotename` to state the name of the *remote* instead\n+of the ref, and `:remoteref` to state the name of the *reference* as\n+locally known by the remote.\n +\n Has no effect if the ref does not have tracking information associated\n with it.  All the options apart from `nobracket` are mutually exclusive,\n@@ -152,9 +153,9 @@ but if used together the last option is selected.\n push::\n \tThe name of a local ref which represents the `@{push}`\n \tlocation for the displayed ref. Respects `:short`, `:lstrip`,\n-\t`:rstrip`, `:track`, `:trackshort` and `:remotename` options as\n-\t`upstream` does. Produces an empty string if no `@{push}` ref is\n-\tconfigured.\n+\t`:rstrip`, `:track`, `:trackshort`, `:remotename`, and `:remoteref`\n+\toptions as `upstream` does. Produces an empty string if no `@{push}`\n+\tref is configured.\n \n HEAD::\n \t'*' if HEAD matches current ref (the checked out branch), ' '\ndiff --git a/ref-filter.c b/ref-filter.c\nindex 4819707d032..b4b2c9b2190 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -77,7 +77,7 @@ static struct used_atom {\n \t\tstruct align align;\n \t\tstruct {\n \t\t\tenum {\n-\t\t\t\tRR_REF, RR_TRACK, RR_TRACKSHORT, RR_REMOTE_NAME\n+\t\t\t\tRR_REF, RR_TRACK, RR_TRACKSHORT, RR_REMOTE_NAME, RR_REMOTE_REF\n \t\t\t} option;\n \t\t\tstruct refname_atom refname;\n \t\t\tunsigned int nobracket : 1, push : 1, push_remote : 1;\n@@ -164,6 +164,9 @@ static void remote_ref_atom_parser(const struct ref_format *format, struct used_\n \t\telse if (!strcmp(s, \"remotename\")) {\n \t\t\tatom->u.remote_ref.option = RR_REMOTE_NAME;\n \t\t\tatom->u.remote_ref.push_remote = 1;\n+\t\t} else if (!strcmp(s, \"remoteref\")) {\n+\t\t\tatom->u.remote_ref.option = RR_REMOTE_REF;\n+\t\t\tatom->u.remote_ref.push_remote = 1;\n \t\t} else {\n \t\t\tatom->u.remote_ref.option = RR_REF;\n \t\t\trefname_atom_parser_internal(&atom->u.remote_ref.refname,\n@@ -1262,6 +1265,14 @@ static void fill_remote_ref_details(struct used_atom *atom, const char *refname,\n \t\t\t*s = xstrdup(remote);\n \t\telse\n \t\t\t*s = \"\";\n+\t} else if (atom->u.remote_ref.option == RR_REMOTE_REF) {\n+\t\tint explicit, for_push = starts_with(atom->name, \"push\");\n+\t\tconst char *merge = remote_ref_for_branch(branch, for_push,\n+\t\t\t\t\t\t\t  &explicit);\n+\t\tif (explicit)\n+\t\t\t*s = xstrdup(merge);\n+\t\telse\n+\t\t\t*s = \"\";\n \t} else\n \t\tdie(\"BUG: unhandled RR_* enum\");\n }\ndiff --git a/remote.c b/remote.c\nindex b220f0dfc61..2bdcfc280cd 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -675,6 +675,36 @@ const char *pushremote_for_branch(struct branch *branch, int *explicit)\n \treturn remote_for_branch(branch, explicit);\n }\n \n+const char *remote_ref_for_branch(struct branch *branch, int for_push,\n+\t\t\t\t  int *explicit)\n+{\n+\tif (branch) {\n+\t\tif (!for_push) {\n+\t\t\tif (branch->merge_nr) {\n+\t\t\t\tif (explicit)\n+\t\t\t\t\t*explicit = 1;\n+\t\t\t\treturn branch->merge_name[0];\n+\t\t\t}\n+\t\t} else {\n+\t\t\tconst char *dst, *remote_name =\n+\t\t\t\tpushremote_for_branch(branch, NULL);\n+\t\t\tstruct remote *remote = remote_get(remote_name);\n+\n+\t\t\tif (remote && remote->push_refspec_nr &&\n+\t\t\t    (dst = apply_refspecs(remote->push,\n+\t\t\t\t\t\t  remote->push_refspec_nr,\n+\t\t\t\t\t\t  branch->refname))) {\n+\t\t\t\tif (explicit)\n+\t\t\t\t\t*explicit = 1;\n+\t\t\t\treturn dst;\n+\t\t\t}\n+\t\t}\n+\t}\n+\tif (explicit)\n+\t\t*explicit = 0;\n+\treturn \"\";\n+}\n+\n static struct remote *remote_get_1(const char *name,\n \t\t\t\t   const char *(*get_default)(struct branch *, int *))\n {\ndiff --git a/remote.h b/remote.h\nindex 2ecf4c8c74c..1f6611be214 100644\n--- a/remote.h\n+++ b/remote.h\n@@ -223,6 +223,8 @@ struct branch {\n struct branch *branch_get(const char *name);\n const char *remote_for_branch(struct branch *branch, int *explicit);\n const char *pushremote_for_branch(struct branch *branch, int *explicit);\n+const char *remote_ref_for_branch(struct branch *branch, int for_push,\n+\t\t\t\t  int *explicit);\n \n int branch_has_merge_config(struct branch *branch);\n int branch_merge_matches(struct branch *, int n, const char *);\n-- \n2.14.2.windows.1.2.gdc85205db4d\n\n\n"},{"id":"329761","messageId":"36f7929801fdb95953a2b2575a0461ae270ea530.1507205895.git.johannes.schindelin@gmx.de","threadId":"46883","inReplyTo":"cover.1507205895.git.johannes.schindelin@gmx.de","subject":"[PATCH v2 3/3] for-each-ref: test :remotename and :remoteref","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-10-05T12:19:19Z","receivedAt":"2017-10-05T12:19:58Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"This not only prevents regressions, but also serves as documentation\nwhat this new feature is expected to do.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n t/t6300-for-each-ref.sh | 32 ++++++++++++++++++++++++++++++++\n 1 file changed, 32 insertions(+)\n\ndiff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh\nindex 2274a4b7331..d9eb2be0256 100755\n--- a/t/t6300-for-each-ref.sh\n+++ b/t/t6300-for-each-ref.sh\n@@ -675,4 +675,36 @@ test_expect_success 'Verify usage of %(symref:rstrip) atom' '\n \ttest_cmp expected actual\n '\n \n+test_expect_success ':remotename and :remoteref' '\n+\tgit init remote-tests &&\n+\t(\n+\t\tcd remote-tests &&\n+\t\ttest_commit initial &&\n+\t\tgit remote add from fifth.coffee:blub &&\n+\t\tgit config branch.master.remote from &&\n+\t\tgit config branch.master.merge refs/heads/stable &&\n+\t\tgit remote add to southridge.audio:repo &&\n+\t\tgit config remote.to.push \"refs/heads/*:refs/heads/pushed/*\" &&\n+\t\tgit config branch.master.pushRemote to &&\n+\t\tfor pair in \"%(upstream)=refs/remotes/from/stable\" \\\n+\t\t\t\"%(upstream:remotename)=from\" \\\n+\t\t\t\"%(upstream:remoteref)=refs/heads/stable\" \\\n+\t\t\t\"%(push)=refs/remotes/to/pushed/master\" \\\n+\t\t\t\"%(push:remotename)=to\" \\\n+\t\t\t\"%(push:remoteref)=refs/heads/pushed/master\"\n+\t\tdo\n+\t\t\techo \"${pair#*=}\" >expect &&\n+\t\t\tgit for-each-ref --format=\"${pair%=*}\" \\\n+\t\t\t\trefs/heads/master >actual &&\n+\t\t\ttest_cmp expect actual\n+\t\tdone &&\n+\t\tgit branch push-simple &&\n+\t\tgit config branch.push-simple.pushRemote from &&\n+\t\tactual=\"$(git for-each-ref \\\n+\t\t\t--format=\"%(push:remotename),%(push:remoteref)\" \\\n+\t\t\trefs/heads/push-simple)\" &&\n+\t\ttest from, = \"$actual\"\n+\t)\n+'\n+\n test_done\n-- \n2.14.2.windows.1.2.gdc85205db4d\n"},{"id":"329762","messageId":"alpine.DEB.2.21.1.1710051419590.40514@virtualbox","threadId":"46883","inReplyTo":"xmqq376zcrls.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH 1/3] for-each-ref: let upstream/push optionally report the remote name","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-10-05T12:20:53Z","receivedAt":"2017-10-05T12:21:02Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Wed, 4 Oct 2017, Junio C Hamano wrote:\n\n> Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n> \n> > This patch offers the new suffix :remote for the upstream and for the\n> > push atoms, allowing to show exactly that.\n> \n> Has the design changed since this description and examples were\n> written?\n\nObviously.\n\nAlso, I tried to address all of your concerns (or at least those that were\nremaining in the end).\n\nThank you for your review,\nDscho\n"},{"id":"329850","messageId":"xmqqvajsx3o0.fsf@gitster.mtv.corp.google.com","threadId":"46883","inReplyTo":"7da6c7e2563d14cb7cd7ff2637c79c51896a9788.1507205895.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH v2 2/3] for-each-ref: let upstream/push optionally remote ref name","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-10-06T05:10:07Z","receivedAt":"2017-10-06T05:10:14Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n\n> Subject: Re: [PATCH v2 2/3] for-each-ref: let upstream/push optionally remote ref name\n\nNo verb?  s/optionally/report/ perhaps?\n\n> diff --git a/ref-filter.c b/ref-filter.c\n> index 4819707d032..b4b2c9b2190 100644\n> --- a/ref-filter.c\n> +++ b/ref-filter.c\n> @@ -77,7 +77,7 @@ static struct used_atom {\n>  \t\tstruct align align;\n>  \t\tstruct {\n>  \t\t\tenum {\n> -\t\t\t\tRR_REF, RR_TRACK, RR_TRACKSHORT, RR_REMOTE_NAME\n> +\t\t\t\tRR_REF, RR_TRACK, RR_TRACKSHORT, RR_REMOTE_NAME, RR_REMOTE_REF\n>  \t\t\t} option;\n>  \t\t\tstruct refname_atom refname;\n>  \t\t\tunsigned int nobracket : 1, push : 1, push_remote : 1;\n> @@ -164,6 +164,9 @@ static void remote_ref_atom_parser(const struct ref_format *format, struct used_\n>  \t\telse if (!strcmp(s, \"remotename\")) {\n>  \t\t\tatom->u.remote_ref.option = RR_REMOTE_NAME;\n>  \t\t\tatom->u.remote_ref.push_remote = 1;\n> +\t\t} else if (!strcmp(s, \"remoteref\")) {\n> +\t\t\tatom->u.remote_ref.option = RR_REMOTE_REF;\n> +\t\t\tatom->u.remote_ref.push_remote = 1;\n>  \t\t} else {\n>  \t\t\tatom->u.remote_ref.option = RR_REF;\n>  \t\t\trefname_atom_parser_internal(&atom->u.remote_ref.refname,\n> @@ -1262,6 +1265,14 @@ static void fill_remote_ref_details(struct used_atom *atom, const char *refname,\n>  \t\t\t*s = xstrdup(remote);\n>  \t\telse\n>  \t\t\t*s = \"\";\n> +\t} else if (atom->u.remote_ref.option == RR_REMOTE_REF) {\n> +\t\tint explicit, for_push = starts_with(atom->name, \"push\");\n\nHmph, the previous step got rid of starts_with() rather nicely by\nintroducing atom->u.remote_ref.push bit; can't we do the same in\nthis step?\n\nOther than that, looks nicer.\n\nThanks.\n"},{"id":"330101","messageId":"xmqqlgkjpcqf.fsf@gitster.mtv.corp.google.com","threadId":"46883","inReplyTo":"964525df50e6d35847bcf57b0fe0949c99f0dbca.1507205895.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH v2 1/3] for-each-ref: let upstream/push optionally report the remote name","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-10-10T09:35:04Z","receivedAt":"2017-10-10T09:35:20Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n\n> There are times when e.g. scripts want to know not only the name of the\n> upstream branch on the remote repository, but also the name of the\n> remote.\n>\n> This patch offers the new suffix :remotename for the upstream and for\n> the push atoms, allowing to show exactly that. Example:\n> ...\n> \t$ git for-each-ref \\\n> \t\t--format='%(upstream) %(upstream:remote) %(push:remote)' \\\n> \t\trefs/heads/master\n> \trefs/remotes/origin/master origin hello-world\n\nWhile doing the regular re-review of the topics in flight, I noticed\nthat there are two references to :remote here that should be :remotename,\nso I tweaked them locally and pushed the result out as part of 'pu'.\n\nThanks.\n"},{"id":"330145","messageId":"xmqqinfmo2sf.fsf@gitster.mtv.corp.google.com","threadId":"46883","inReplyTo":"964525df50e6d35847bcf57b0fe0949c99f0dbca.1507205895.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH v2 1/3] for-each-ref: let upstream/push optionally report the remote name","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-10-11T02:07:28Z","receivedAt":"2017-10-11T02:07:35Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n\n> The implementation chooses *not* to DWIM the push remote if no explicit\n> push remote was configured; The reason is that it is possible to DWIM this\n> by using\n>\n> \t%(if)%(push:remotename)%(then)\n> \t\t%(push:remotename)\n> \t%(else)\n> \t\t%(upstream:remotename)\n> \t%(end)\n>\n> while it would be impossible to \"un-DWIM\" the information in case the\n> caller is really only interested in explicit push remotes.\n\nGood.\n\n> Note: the dashless, non-CamelCased form `:remotename` follows the\n> example of the `:trackshort` example.\n\nGood.  Come to think of it, aside from modifiers, the use of\nsquashedwords like committerdate and objecttype has long been the\nnorm in the for-each-ref atom names, so \"remotename\" is much more in\nline with other formats.\n\n> @@ -1354,16 +1371,20 @@ static void populate_value(struct ref_array_item *ref)\n>  \t\t\tif (refname)\n>  \t\t\t\tfill_remote_ref_details(atom, refname, branch, &v->s);\n>  \t\t\tcontinue;\n> -\t\t} else if (starts_with(name, \"push\")) {\n> +\t\t} else if (atom->u.remote_ref.push) {\n>  \t\t\tconst char *branch_name;\n>  \t\t\tif (!skip_prefix(ref->refname, \"refs/heads/\",\n>  \t\t\t\t\t &branch_name))\n>  \t\t\t\tcontinue;\n>  \t\t\tbranch = branch_get(branch_name);\n>  \n> -\t\t\trefname = branch_get_push(branch, NULL);\n> -\t\t\tif (!refname)\n> -\t\t\t\tcontinue;\n> +\t\t\tif (atom->u.remote_ref.push_remote)\n> +\t\t\t\trefname = NULL;\n> +\t\t\telse {\n> +\t\t\t\trefname = branch_get_push(branch, NULL);\n> +\t\t\t\tif (!refname)\n> +\t\t\t\t\tcontinue;\n> +\t\t\t}\n>  \t\t\tfill_remote_ref_details(atom, refname, branch, &v->s);\n\nIt still feels a bit strange to pass NULL refname to\nfill_remote_ref_details() function, but fixing it would require\noverhaul of this if/else if cascade, I think, so let's not worry too\nmuch about it at least for now.\n\nLooks much better than the previous one.  Thanks.  Queued.\n\n"},{"id":"330151","messageId":"xmqqvajmmdii.fsf@gitster.mtv.corp.google.com","threadId":"46883","inReplyTo":"xmqqvajsx3o0.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v2 2/3] for-each-ref: let upstream/push optionally remote ref name","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-10-11T05:58:45Z","receivedAt":"2017-10-11T05:58:53Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n>\n>> Subject: Re: [PATCH v2 2/3] for-each-ref: let upstream/push optionally remote ref name\n>\n> No verb?  s/optionally/report/ perhaps?\n\nI just noticed that I didn't tweak the copy I have in my tree after\nsending this message, but now I did s/optionally/& report the/;\n\nI am still puzzled by the hunk below, though.\n\n>> @@ -1262,6 +1265,14 @@ static void fill_remote_ref_details(struct used_atom *atom, const char *refname,\n>>  \t\t\t*s = xstrdup(remote);\n>>  \t\telse\n>>  \t\t\t*s = \"\";\n>> +\t} else if (atom->u.remote_ref.option == RR_REMOTE_REF) {\n>> +\t\tint explicit, for_push = starts_with(atom->name, \"push\");\n>\n> Hmph, the previous step got rid of starts_with() rather nicely by\n> introducing atom->u.remote_ref.push bit; can't we do the same in\n> this step?\n>\n> Other than that, looks nicer.\n\nThanks.\n"},{"id":"330298","messageId":"alpine.DEB.2.21.1.1710122110170.40514@virtualbox","threadId":"46883","inReplyTo":"xmqqvajmmdii.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v2 2/3] for-each-ref: let upstream/push optionally remote ref name","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-10-12T19:13:40Z","receivedAt":"2017-10-12T19:13:53Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Wed, 11 Oct 2017, Junio C Hamano wrote:\n\n> Junio C Hamano <gitster@pobox.com> writes:\n> \n> > Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n> >\n> >> Subject: Re: [PATCH v2 2/3] for-each-ref: let upstream/push optionally remote ref name\n> >\n> > No verb?  s/optionally/report/ perhaps?\n> \n> I just noticed that I didn't tweak the copy I have in my tree after\n> sending this message, but now I did s/optionally/& report the/;\n\nYes, sorry for not reading this earlier, this is what I meant the commit\nsubject to say.\n\n> I am still puzzled by the hunk below, though.\n> \n> >> @@ -1262,6 +1265,14 @@ static void fill_remote_ref_details(struct used_atom *atom, const char *refname,\n> >>  \t\t\t*s = xstrdup(remote);\n> >>  \t\telse\n> >>  \t\t\t*s = \"\";\n> >> +\t} else if (atom->u.remote_ref.option == RR_REMOTE_REF) {\n> >> +\t\tint explicit, for_push = starts_with(atom->name, \"push\");\n> >\n> > Hmph, the previous step got rid of starts_with() rather nicely by\n> > introducing atom->u.remote_ref.push bit; can't we do the same in\n> > this step?\n\nRight, I forgot to edit this. FWIW I have this in my branch now:\n\n-- snip --\n[PATCH] squash! for-each-ref: let upstream/push optionally remote ref\n name\n\nfor-each-ref: let upstream/push optionally report the remote ref name\n\nThere are times when scripts want to know not only the name of the\npush branch on the remote, but also the name of the branch as known\nby the remote repository.\n\nAn example of this is when a tool wants to push to the very same branch\nfrom which it would pull automatically, i.e. the `<remote>` and the `<to>`\nin `git push <remote> <from>:<to>` would be provided by\n`%(upstream:remotename)` and `%(upstream:remoteref)`, respectively.\n\nThis patch offers the new suffix :remoteref for the `upstream` and `push`\natoms, allowing to show exactly that. Example:\n\n\t$ cat .git/config\n\t...\n\t[remote \"origin\"]\n\t\turl = https://where.do.we.come/from\n\t\tfetch = refs/heads/*:refs/remote/origin/*\n\t[branch \"master\"]\n\t\tremote = origin\n\t\tmerge = refs/heads/master\n\t[branch \"develop/with/topics\"]\n\t\tremote = origin\n\t\tmerge = refs/heads/develop/with/topics\n\t...\n\n\t$ git for-each-ref \\\n\t\t--format='%(push) %(push:remoteref)' \\\n\t\trefs/heads\n\trefs/remotes/origin/master refs/heads/master\n\trefs/remotes/origin/develop/with/topics refs/heads/develop/with/topics\n\nSigned-off-by: J Wyman <jwyman@microsoft.com>\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n ref-filter.c | 8 +++++---\n 1 file changed, 5 insertions(+), 3 deletions(-)\n\ndiff --git a/ref-filter.c b/ref-filter.c\nindex 2556c7885de..6ab12658cb3 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -1268,9 +1268,11 @@ static void fill_remote_ref_details(struct used_atom *atom, const char *refname,\n \t\telse\n \t\t\t*s = \"\";\n \t} else if (atom->u.remote_ref.option == RR_REMOTE_REF) {\n-\t\tint explicit, for_push = starts_with(atom->name, \"push\");\n-\t\tconst char *merge = remote_ref_for_branch(branch, for_push,\n-\t\t\t\t\t\t\t  &explicit);\n+\t\tint explicit;\n+\t\tconst char *merge;\n+\n+\t\tmerge = remote_ref_for_branch(branch, atom->u.remote_ref.push,\n+\t\t\t\t\t      &explicit);\n \t\tif (explicit)\n \t\t\t*s = xstrdup(merge);\n \t\telse\n-- \n2.14.2.windows.2\n-- snap --\n\n(The funny \"squash!\" followed by a complete version of the rewritten\ncommit message is what I do until I -- or anybody else -- comes up with a\npatch to implement support for \"reword!\".)\n\nI'll let this simmer until next week and send out a new iteration of the\npatch series then.\n\nThanks,\nDscho\n"},{"id":"330324","messageId":"xmqq60bjyjna.fsf@gitster.mtv.corp.google.com","threadId":"46883","inReplyTo":"alpine.DEB.2.21.1.1710122110170.40514@virtualbox","subject":"Re: [PATCH v2 2/3] for-each-ref: let upstream/push optionally remote ref name","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-10-13T00:30:01Z","receivedAt":"2017-10-13T00:30:11Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n>> (The funny \"squash!\" followed by a complete version of the\n>> rewritten commit message is what I do until I -- or anybody else\n>> -- comes up with a patch to implement support for \"reword!\".)\n\nI have wished for something like that for a long time; it has been\n(and it still is) a bit unclear what the semantics and UI should\nlook like, but still, such a feature would be quite useful.\n\n"},{"id":"330368","messageId":"20171013163923.GA5598@alpha.vpn.ikke.info","threadId":"46883","inReplyTo":"7da6c7e2563d14cb7cd7ff2637c79c51896a9788.1507205895.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH v2 2/3] for-each-ref: let upstream/push optionally remote ref name","fromName":"Kevin Daudt","fromEmail":"me@ikke.info","sentAt":"2017-10-13T16:39:23Z","receivedAt":"2017-10-13T16:39:30Z","isPatch":true,"sender":{"key":"me@ikke.info","avatar":"https://avatars.githubusercontent.com/u/135698?v=4"},"body":"On Thu, Oct 05, 2017 at 02:19:15PM +0200, Johannes Schindelin wrote:\n> From: J Wyman <jwyman@microsoft.com>\n> [..] \n> \n> diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt\n> index 39f50bd53eb..22767025850 100644\n> --- a/Documentation/git-for-each-ref.txt\n> +++ b/Documentation/git-for-each-ref.txt\n> @@ -142,8 +142,9 @@ upstream::\n>  \tencountered. Append `:track,nobracket` to show tracking\n>  \tinformation without brackets (i.e \"ahead N, behind M\").\n>  +\n> -Also respects `:remotename` to state the name of the *remote* instead of\n> -the ref.\n> +Also respects `:remotename` to state the name of the *remote* instead\n> +of the ref, and `:remoteref` to state the name of the *reference* as\n> +locally known by the remote.\n\nWhat does \"locally known by the remote\" mean in this sentence?\n\n>  +\n>  Has no effect if the ref does not have tracking information associated\n>  with it.  All the options apart from `nobracket` are mutually exclusive,\n> @@ -152,9 +153,9 @@ but if used together the last option is selected.\n"},{"id":"330386","messageId":"xmqqinfiv5u2.fsf@gitster.mtv.corp.google.com","threadId":"46883","inReplyTo":"20171013163923.GA5598@alpha.vpn.ikke.info","subject":"Re: [PATCH v2 2/3] for-each-ref: let upstream/push optionally remote ref name","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-10-14T02:08:53Z","receivedAt":"2017-10-14T02:09:03Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Kevin Daudt <me@ikke.info> writes:\n\n> On Thu, Oct 05, 2017 at 02:19:15PM +0200, Johannes Schindelin wrote:\n>> From: J Wyman <jwyman@microsoft.com>\n>> [..] \n>> \n>> diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt\n>> index 39f50bd53eb..22767025850 100644\n>> --- a/Documentation/git-for-each-ref.txt\n>> +++ b/Documentation/git-for-each-ref.txt\n>> @@ -142,8 +142,9 @@ upstream::\n>>  \tencountered. Append `:track,nobracket` to show tracking\n>>  \tinformation without brackets (i.e \"ahead N, behind M\").\n>>  +\n>> -Also respects `:remotename` to state the name of the *remote* instead of\n>> -the ref.\n>> +Also respects `:remotename` to state the name of the *remote* instead\n>> +of the ref, and `:remoteref` to state the name of the *reference* as\n>> +locally known by the remote.\n>\n> What does \"locally known by the remote\" mean in this sentence?\n\nGood question.  I cannot offhand offer a better and concise\nphrasing, but I think can explain what it wants to describe ;-).\n\nFor a local branch we have (say, 'topic'), there may be different\nthings outside this repository that regularly interact with it.\n\nWe may update 'topic' with work others did, by\n\n\tgit checkout topic && git pull\n\nwithout any extra command line argument to \"git pull\".  We are\npulling from the 'upstream' of the 'topic', which is a branch in a\nremote repository, and the (nick)name of the remote is :remotename.\nWhen we do this pull, we would grab one of the branches the remote\nhas and merge it into our 'topic'.  IOW, when the above command line\nis written in longhand, the \"git pull\" step may look like this [*1*]:\n\n\tgit pull origin devel\n\nif we were building on top of the 'devel' branch at the 'origin'\nremote.  The full refname of that branch, 'refs/heads/devel', is\n:remoteref, and that is the reference locally known to the 'origin'\nremote.\n\nThe \"locally known by the remote\" is an attempt by the patch authors\nto stress the fact that the result is not refs/remotes/origin/devel\n(which is where _you_ would keep a local copy of that reference in\nthis repository).\n\nTwo other things outside this repository that interact with 'topic'\nare where the result of our work is pushed out to, which is a branch\nat the 'push' remote.\n\n\n[Footnotes]\n\n*1* Modulo the details of other refs fetched that are unrelated to\n    the resulting merge and local copies stored as remote-tracking\n    branches in this repository.\n\n\n"},{"id":"330405","messageId":"alpine.DEB.2.21.1.1710151754070.40514@virtualbox","threadId":"46883","inReplyTo":"xmqq60bjyjna.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v2 2/3] for-each-ref: let upstream/push optionally remote ref name","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-10-15T16:02:31Z","receivedAt":"2017-10-15T16:02:50Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Fri, 13 Oct 2017, Junio C Hamano wrote:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n> >> (The funny \"squash!\" followed by a complete version of the\n> >> rewritten commit message is what I do until I -- or anybody else\n> >> -- comes up with a patch to implement support for \"reword!\".)\n> \n> I have wished for something like that for a long time; it has been\n> (and it still is) a bit unclear what the semantics and UI should\n> look like, but still, such a feature would be quite useful.\n\nOh, the reword! semantics are relatively easy in my mind: it would be\ncalled as\n\n\tgit commit --reword <commit>\n\nwould take staged changes (if any), otherwise implicitly --allow-empty,\nthen create a commit message to be edited in this style:\n\n\treword! <original-oneline>\n\n\t<original-oneline>\n\n\t<original-body>\n\nThis would be presented to the user in an editor (similar to `git commit\n--amend`).\n\nUpon rebase --autosquash, it would work like a squash! but comment out all\nprevious commit messages, and also comment out the reword! line and the\nempty line after that.\n\nIn case of multiple reword!, the last one would win, and it would\nnaturally integrate in any fixup!/squash! workflow.\n\nWhat is *more* difficult is something else I frequently need: drop!\n<oneline>. That is, I want to explicitly mark a commit to be excluded in\nsubsequent rebase --autosquash. I *guess* the best way would be to\nimplement a\n\n\tgit revert --drop <commit>\n\nthat would work as if you called `git revert -n <commit> && git commit -m\n'drop! '\"$(git show -s --oneline <commit>)\", and upon rebase --autosquash,\nit would reorder like fixup!/squash!/reword!, replace the `pick` of the\nprevious line (if it was a `pick`) by `drop` and comment out the current\n`pick drop! <oneline>` line.\n\nThe reason why the semantics are more difficult in that case is that drop!\ndoes not mix well with fixup!/squash!/reword!.\n\nCiao,\nDscho\n"},{"id":"330406","messageId":"alpine.DEB.2.21.1.1710151804060.40514@virtualbox","threadId":"46883","inReplyTo":"xmqqinfiv5u2.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v2 2/3] for-each-ref: let upstream/push optionally remote ref name","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-10-15T16:05:35Z","receivedAt":"2017-10-15T16:05:54Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Sat, 14 Oct 2017, Junio C Hamano wrote:\n\n> Kevin Daudt <me@ikke.info> writes:\n> \n> > On Thu, Oct 05, 2017 at 02:19:15PM +0200, Johannes Schindelin wrote:\n> >> From: J Wyman <jwyman@microsoft.com>\n> >> [..] \n> >> \n> >> diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt\n> >> index 39f50bd53eb..22767025850 100644\n> >> --- a/Documentation/git-for-each-ref.txt\n> >> +++ b/Documentation/git-for-each-ref.txt\n> >> @@ -142,8 +142,9 @@ upstream::\n> >>  \tencountered. Append `:track,nobracket` to show tracking\n> >>  \tinformation without brackets (i.e \"ahead N, behind M\").\n> >>  +\n> >> -Also respects `:remotename` to state the name of the *remote* instead of\n> >> -the ref.\n> >> +Also respects `:remotename` to state the name of the *remote* instead\n> >> +of the ref, and `:remoteref` to state the name of the *reference* as\n> >> +locally known by the remote.\n> >\n> > What does \"locally known by the remote\" mean in this sentence?\n> \n> Good question.  I cannot offhand offer a better and concise\n> phrasing, but I think can explain what it wants to describe ;-).\n\nYep, described it well.\n\nMaybe \"and `:remoteref` to state the name by which the remote knows the\n*reference*\"?\n\nCiao,\nDscho\n"},{"id":"330438","messageId":"xmqqk1zvuahz.fsf@gitster.mtv.corp.google.com","threadId":"46883","inReplyTo":"alpine.DEB.2.21.1.1710151804060.40514@virtualbox","subject":"Re: [PATCH v2 2/3] for-each-ref: let upstream/push optionally remote ref name","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-10-16T01:50:16Z","receivedAt":"2017-10-16T01:50:26Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n>> >> -Also respects `:remotename` to state the name of the *remote* instead of\n>> >> -the ref.\n>> >> +Also respects `:remotename` to state the name of the *remote* instead\n>> >> +of the ref, and `:remoteref` to state the name of the *reference* as\n>> >> +locally known by the remote.\n>> >\n>> > What does \"locally known by the remote\" mean in this sentence?\n>> \n>> Good question.  I cannot offhand offer a better and concise\n>> phrasing, but I think can explain what it wants to describe ;-).\n>\n> Yep, described it well.\n>\n> Maybe \"and `:remoteref` to state the name by which the remote knows the\n> *reference*\"?\n\nI dunno.  \n\nThe original and your update both seem to come from a worldview\nwhere there is a single conceptual thing called \"reference\" that is\nshared between our repository and the remote repository we pull from\n(or push to), and the name we call it is \"refs/remotes/origin/devel\"\nwhile the name they use to call it is \"refs/heads/devel\".  If you\nsubscribe to that worldview, then the updated sentence might make it\nclearer than the original.\n\nBut I do not share that worldview, and I am not sure (note: I am\ntruly unsure---it's not like I am convinced it is a good idea but\nsugarcoating my expression, at least in this case) if subscribing to\nthe worldview helps users' understanding.\n\nIn my view \"refs/remotes/origin/devel\" is a reference we use to keep\ntrack of (or \"a reference that corresponds to\") the reference they\nhave called \"refs/heads/devel\" at the remote, and these are two\nseparate entities, so it's not like \"this single thing is called\ndifferently by us and them\".\n\nStepping back a bit; here is how the description begins.\n\n    upstream::\n            The name of a local ref which can be considered ``upstream''\n            from the displayed ref.\n\nSo 'upstream' is like 'refs/remotes/origin/devel' in the example in\nthe message you are responding to.  Perhaps we can make it clear in\nthe description, and then add :remote* modifiers are about asking\nwhere that remote-tracking branch comes from.  For example, instead\nof these \"Also respects...\", something like:\n\n    For a %(upstream) that is a remote-tracking branch, the name of\n    the remote repository it is copied from can be obtained with\n    %(upstream:remotename).  Simiarly, the branch at the remote\n    repository whose tip is copioed to this remote-tracking branch\n    can be obtined with %(upstream:remoteref) as a full refname.\n\nmay reduce the chance of confusion?\n\n\n\n"},{"id":"330452","messageId":"alpine.DEB.2.21.1.1710161334291.40514@virtualbox","threadId":"46883","inReplyTo":"xmqqk1zvuahz.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v2 2/3] for-each-ref: let upstream/push optionally remote ref name","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-10-16T11:39:01Z","receivedAt":"2017-10-16T11:40:15Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Mon, 16 Oct 2017, Junio C Hamano wrote:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n> >> >> -Also respects `:remotename` to state the name of the *remote* instead of\n> >> >> -the ref.\n> >> >> +Also respects `:remotename` to state the name of the *remote* instead\n> >> >> +of the ref, and `:remoteref` to state the name of the *reference* as\n> >> >> +locally known by the remote.\n> >> >\n> >> > What does \"locally known by the remote\" mean in this sentence?\n> >> \n> >> Good question.  I cannot offhand offer a better and concise\n> >> phrasing, but I think can explain what it wants to describe ;-).\n> >\n> > Yep, described it well.\n> >\n> > Maybe \"and `:remoteref` to state the name by which the remote knows the\n> > *reference*\"?\n> \n> I dunno.  \n> \n> The original and your update both seem to come from a worldview\n> where there is a single conceptual thing called \"reference\" that is\n> shared between our repository and the remote repository we pull from\n> (or push to), and the name we call it is \"refs/remotes/origin/devel\"\n> while the name they use to call it is \"refs/heads/devel\".  If you\n> subscribe to that worldview, then the updated sentence might make it\n> clearer than the original.\n> \n> But I do not share that worldview, and I am not sure (note: I am\n> truly unsure---it's not like I am convinced it is a good idea but\n> sugarcoating my expression, at least in this case) if subscribing to\n> the worldview helps users' understanding.\n> \n> In my view \"refs/remotes/origin/devel\" is a reference we use to keep\n> track of (or \"a reference that corresponds to\") the reference they\n> have called \"refs/heads/devel\" at the remote, and these are two\n> separate entities, so it's not like \"this single thing is called\n> differently by us and them\".\n> \n> Stepping back a bit; here is how the description begins.\n> \n>     upstream::\n>             The name of a local ref which can be considered ``upstream''\n>             from the displayed ref.\n> \n> So 'upstream' is like 'refs/remotes/origin/devel' in the example in\n> the message you are responding to.  Perhaps we can make it clear in\n> the description, and then add :remote* modifiers are about asking\n> where that remote-tracking branch comes from.  For example, instead\n> of these \"Also respects...\", something like:\n> \n>     For a %(upstream) that is a remote-tracking branch, the name of\n>     the remote repository it is copied from can be obtained with\n>     %(upstream:remotename).  Simiarly, the branch at the remote\n>     repository whose tip is copioed to this remote-tracking branch\n>     can be obtined with %(upstream:remoteref) as a full refname.\n> \n> may reduce the chance of confusion?\n\nLet's take two more steps back.\n\nFirst, for-each-ref is a low-level command (I do not remember whether our\nnickname for \"low-level\" is \"plumbing\" or \"porcelain\" or anything, so I\nstick with \"low-level\" which I deem descriptive enough). That is, users of\nthis command (and therefore, readers of this man page) need to be quite\nfamiliar with Git's worldview.\n\nSecond, the main purpose of this patch series is to answer the question\n\"what is the default <remoteref> in `git push <remotename>\n<ref>:<remoteref>`?\" for *many* refs at once.\n\nMaybe it would be better to describe the functionality by describing the\nquestion it tries to answer.\n\nCiao,\nDscho\n"},{"id":"332012","messageId":"cover.1510072200.git.johannes.schindelin@gmx.de","threadId":"46883","inReplyTo":"cover.1507205895.git.johannes.schindelin@gmx.de","subject":"[PATCH v3 0/3] for-each-ref: add :remoteref and :remotename specifiers","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-11-07T16:30:52Z","receivedAt":"2017-11-07T16:31:06Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"This introduces support for\n\n\tgit for-each-ref \\\n\t\t--format=\"%(merge:remotename),%(merge:remoteref)\"\n\tgit for-each-ref \\\n\t\t--format=\"%(push:remotename),%(push:remoteref)\"\n\nto figure out the remote nickname as well as the name of the corresponding\nbranch on the remote.\n\nNote: the `%(push:remotename)` placeholder is only interpolated by the value\nof `branch.<name>.pushRemote`; unlike `git push`, it does not fall back to\n`branch.<name>.remote`. Likewise, `%(push:remoteref)` interpolates to the\nempty string unless `remote.<nick>.pushRefs` is configured.\n\nThis is useful for third-party tools that need to know this type of information\nfor tons of branches.\n\nChanges since v2:\n\n- fixed the commit message of 1/3 to no longer talk about :remote.\n\n- used the push atom in 2/3, made the code look more as suggested by Junio.\n\n- fixed the oneline of 2/3 to use a verb (\"report\").\n\n- butchered Junio's proposed documentation update for 2/3 to hopefully make\n  the description of :remotename and :remoteref a lot clearer.\n\n\nJ Wyman (1):\n  for-each-ref: let upstream/push report the remote ref name\n\nJohannes Schindelin (2):\n  for-each-ref: let upstream/push optionally report the remote name\n  for-each-ref: test :remotename and :remoteref\n\n Documentation/git-for-each-ref.txt | 23 +++++++++++-------\n ref-filter.c                       | 48 ++++++++++++++++++++++++++++++++------\n remote.c                           | 30 ++++++++++++++++++++++++\n remote.h                           |  2 ++\n t/t6300-for-each-ref.sh            | 32 +++++++++++++++++++++++++\n 5 files changed, 120 insertions(+), 15 deletions(-)\n\n\nbase-commit: 7668cbc60578f99a4c048f8f8f38787930b8147b\nPublished-As: https://github.com/dscho/git/releases/tag/ref-filter-remote-name-v3\nFetch-It-Via: git fetch https://github.com/dscho/git ref-filter-remote-name-v3\n\nInterdiff vs v2:\n diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt\n index aff44c064a4..dffa14a7950 100644\n --- a/Documentation/git-for-each-ref.txt\n +++ b/Documentation/git-for-each-ref.txt\n @@ -147,9 +147,12 @@ upstream::\n  \tencountered. Append `:track,nobracket` to show tracking\n  \tinformation without brackets (i.e \"ahead N, behind M\").\n  +\n -Also respects `:remotename` to state the name of the *remote* instead\n -of the ref, and `:remoteref` to state the name of the *reference* as\n -locally known by the remote.\n +For any remote-tracking branch `%(upstream)`, `%(upstream:remotename)`\n +and `%(upstream:remoteref)` refer to the name of the remote and the\n +name of the tracked remote ref, respectively. In other words, the\n +remote-tracking branch can be updated explicitly and individually by\n +using the refspec `%(upstream:remoteref):%(upstream)` to fetch from\n +`%(upstream:remotename)`.\n  +\n  Has no effect if the ref does not have tracking information associated\n  with it.  All the options apart from `nobracket` are mutually exclusive,\n diff --git a/ref-filter.c b/ref-filter.c\n index bf078657d91..3f9161707e6 100644\n --- a/ref-filter.c\n +++ b/ref-filter.c\n @@ -1289,9 +1289,11 @@ static void fill_remote_ref_details(struct used_atom *atom, const char *refname,\n  \t\telse\n  \t\t\t*s = \"\";\n  \t} else if (atom->u.remote_ref.option == RR_REMOTE_REF) {\n -\t\tint explicit, for_push = starts_with(atom->name, \"push\");\n -\t\tconst char *merge = remote_ref_for_branch(branch, for_push,\n -\t\t\t\t\t\t\t  &explicit);\n +\t\tint explicit;\n +\t\tconst char *merge;\n +\n +\t\tmerge = remote_ref_for_branch(branch, atom->u.remote_ref.push,\n +\t\t\t\t\t      &explicit);\n  \t\tif (explicit)\n  \t\t\t*s = xstrdup(merge);\n  \t\telse\n-- \n2.15.0.windows.1\n\n"},{"id":"332013","messageId":"9fac9476c73f83f2e688d3e12abc175f40f67c3e.1510072200.git.johannes.schindelin@gmx.de","threadId":"46883","inReplyTo":"cover.1510072200.git.johannes.schindelin@gmx.de","subject":"[PATCH v3 1/3] for-each-ref: let upstream/push optionally report the remote name","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-11-07T16:30:58Z","receivedAt":"2017-11-07T16:31:12Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"There are times when e.g. scripts want to know not only the name of the\nupstream branch on the remote repository, but also the name of the\nremote.\n\nThis patch offers the new suffix :remotename for the upstream and for\nthe push atoms, allowing to show exactly that. Example:\n\n\t$ cat .git/config\n\t...\n\t[remote \"origin\"]\n\t\turl = https://where.do.we.come/from\n\t\tfetch = refs/heads/*:refs/remote/origin/*\n\t[remote \"hello-world\"]\n\t\turl = https://hello.world/git\n\t\tfetch = refs/heads/*:refs/remote/origin/*\n\t\tpushURL = hello.world:git\n\t\tpush = refs/heads/*:refs/heads/*\n\t[branch \"master\"]\n\t\tremote = origin\n\t\tpushRemote = hello-world\n\t...\n\n\t$ git for-each-ref \\\n\t  --format='%(upstream) %(upstream:remotename) %(push:remotename)' \\\n\t  refs/heads/master\n\trefs/remotes/origin/master origin hello-world\n\nThe implementation chooses *not* to DWIM the push remote if no explicit\npush remote was configured; The reason is that it is possible to DWIM this\nby using\n\n\t%(if)%(push:remotename)%(then)\n\t\t%(push:remotename)\n\t%(else)\n\t\t%(upstream:remotename)\n\t%(end)\n\nwhile it would be impossible to \"un-DWIM\" the information in case the\ncaller is really only interested in explicit push remotes.\n\nWhile `:remote` would be shorter, it would also be a bit more ambiguous,\nand it would also shut the door e.g. for `:remoteref` (which would\nobviously refer to the corresponding ref in the remote repository).\n\nNote: the dashless, non-CamelCased form `:remotename` follows the\nexample of the `:trackshort` example.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n Documentation/git-for-each-ref.txt | 17 ++++++++++-------\n ref-filter.c                       | 35 ++++++++++++++++++++++++++++-------\n 2 files changed, 38 insertions(+), 14 deletions(-)\n\ndiff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt\nindex 1d420e4cde8..288b11aaeed 100644\n--- a/Documentation/git-for-each-ref.txt\n+++ b/Documentation/git-for-each-ref.txt\n@@ -145,17 +145,20 @@ upstream::\n \t(behind), \"<>\" (ahead and behind), or \"=\" (in sync). `:track`\n \talso prints \"[gone]\" whenever unknown upstream ref is\n \tencountered. Append `:track,nobracket` to show tracking\n-\tinformation without brackets (i.e \"ahead N, behind M\").  Has\n-\tno effect if the ref does not have tracking information\n-\tassociated with it.  All the options apart from `nobracket`\n-\tare mutually exclusive, but if used together the last option\n-\tis selected.\n+\tinformation without brackets (i.e \"ahead N, behind M\").\n++\n+Also respects `:remotename` to state the name of the *remote* instead of\n+the ref.\n++\n+Has no effect if the ref does not have tracking information associated\n+with it.  All the options apart from `nobracket` are mutually exclusive,\n+but if used together the last option is selected.\n \n push::\n \tThe name of a local ref which represents the `@{push}`\n \tlocation for the displayed ref. Respects `:short`, `:lstrip`,\n-\t`:rstrip`, `:track`, and `:trackshort` options as `upstream`\n-\tdoes. Produces an empty string if no `@{push}` ref is\n+\t`:rstrip`, `:track`, `:trackshort` and `:remotename` options as\n+\t`upstream` does. Produces an empty string if no `@{push}` ref is\n \tconfigured.\n \n HEAD::\ndiff --git a/ref-filter.c b/ref-filter.c\nindex e728b15b3ae..cde8b97dcb0 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -76,9 +76,11 @@ static struct used_atom {\n \t\tchar color[COLOR_MAXLEN];\n \t\tstruct align align;\n \t\tstruct {\n-\t\t\tenum { RR_REF, RR_TRACK, RR_TRACKSHORT } option;\n+\t\t\tenum {\n+\t\t\t\tRR_REF, RR_TRACK, RR_TRACKSHORT, RR_REMOTE_NAME\n+\t\t\t} option;\n \t\t\tstruct refname_atom refname;\n-\t\t\tunsigned int nobracket : 1;\n+\t\t\tunsigned int nobracket : 1, push : 1, push_remote : 1;\n \t\t} remote_ref;\n \t\tstruct {\n \t\t\tenum { C_BARE, C_BODY, C_BODY_DEP, C_LINES, C_SIG, C_SUB, C_TRAILERS } option;\n@@ -138,6 +140,9 @@ static void remote_ref_atom_parser(const struct ref_format *format, struct used_\n \tstruct string_list params = STRING_LIST_INIT_DUP;\n \tint i;\n \n+\tif (!strcmp(atom->name, \"push\") || starts_with(atom->name, \"push:\"))\n+\t\tatom->u.remote_ref.push = 1;\n+\n \tif (!arg) {\n \t\tatom->u.remote_ref.option = RR_REF;\n \t\trefname_atom_parser_internal(&atom->u.remote_ref.refname,\n@@ -157,7 +162,10 @@ static void remote_ref_atom_parser(const struct ref_format *format, struct used_\n \t\t\tatom->u.remote_ref.option = RR_TRACKSHORT;\n \t\telse if (!strcmp(s, \"nobracket\"))\n \t\t\tatom->u.remote_ref.nobracket = 1;\n-\t\telse {\n+\t\telse if (!strcmp(s, \"remotename\")) {\n+\t\t\tatom->u.remote_ref.option = RR_REMOTE_NAME;\n+\t\t\tatom->u.remote_ref.push_remote = 1;\n+\t\t} else {\n \t\t\tatom->u.remote_ref.option = RR_REF;\n \t\t\trefname_atom_parser_internal(&atom->u.remote_ref.refname,\n \t\t\t\t\t\t     arg, atom->name);\n@@ -1268,6 +1276,15 @@ static void fill_remote_ref_details(struct used_atom *atom, const char *refname,\n \t\t\t*s = \">\";\n \t\telse\n \t\t\t*s = \"<>\";\n+\t} else if (atom->u.remote_ref.option == RR_REMOTE_NAME) {\n+\t\tint explicit;\n+\t\tconst char *remote = atom->u.remote_ref.push ?\n+\t\t\tpushremote_for_branch(branch, &explicit) :\n+\t\t\tremote_for_branch(branch, &explicit);\n+\t\tif (explicit)\n+\t\t\t*s = xstrdup(remote);\n+\t\telse\n+\t\t\t*s = \"\";\n \t} else\n \t\tdie(\"BUG: unhandled RR_* enum\");\n }\n@@ -1377,16 +1394,20 @@ static void populate_value(struct ref_array_item *ref)\n \t\t\tif (refname)\n \t\t\t\tfill_remote_ref_details(atom, refname, branch, &v->s);\n \t\t\tcontinue;\n-\t\t} else if (starts_with(name, \"push\")) {\n+\t\t} else if (atom->u.remote_ref.push) {\n \t\t\tconst char *branch_name;\n \t\t\tif (!skip_prefix(ref->refname, \"refs/heads/\",\n \t\t\t\t\t &branch_name))\n \t\t\t\tcontinue;\n \t\t\tbranch = branch_get(branch_name);\n \n-\t\t\trefname = branch_get_push(branch, NULL);\n-\t\t\tif (!refname)\n-\t\t\t\tcontinue;\n+\t\t\tif (atom->u.remote_ref.push_remote)\n+\t\t\t\trefname = NULL;\n+\t\t\telse {\n+\t\t\t\trefname = branch_get_push(branch, NULL);\n+\t\t\t\tif (!refname)\n+\t\t\t\t\tcontinue;\n+\t\t\t}\n \t\t\tfill_remote_ref_details(atom, refname, branch, &v->s);\n \t\t\tcontinue;\n \t\t} else if (starts_with(name, \"color:\")) {\n-- \n2.15.0.windows.1\n\n\n"},{"id":"332014","messageId":"00a24074edbb6ac09344b1685bf7664cc2e10bd6.1510072200.git.johannes.schindelin@gmx.de","threadId":"46883","inReplyTo":"cover.1510072200.git.johannes.schindelin@gmx.de","subject":"[PATCH v3 2/3] for-each-ref: let upstream/push report the remote ref name","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-11-07T16:31:08Z","receivedAt":"2017-11-07T16:31:22Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: J Wyman <jwyman@microsoft.com>\n\nThere are times when scripts want to know not only the name of the\npush branch on the remote, but also the name of the branch as known\nby the remote repository.\n\nAn example of this is when a tool wants to push to the very same branch\nfrom which it would pull automatically, i.e. the `<remote>` and the `<to>`\nin `git push <remote> <from>:<to>` would be provided by\n`%(upstream:remotename)` and `%(upstream:remoteref)`, respectively.\n\nThis patch offers the new suffix :remoteref for the `upstream` and `push`\natoms, allowing to show exactly that. Example:\n\n\t$ cat .git/config\n\t...\n\t[remote \"origin\"]\n\t\turl = https://where.do.we.come/from\n\t\tfetch = refs/heads/*:refs/remote/origin/*\n\t[branch \"master\"]\n\t\tremote = origin\n\t\tmerge = refs/heads/master\n\t[branch \"develop/with/topics\"]\n\t\tremote = origin\n\t\tmerge = refs/heads/develop/with/topics\n\t...\n\n\t$ git for-each-ref \\\n\t\t--format='%(push) %(push:remoteref)' \\\n\t\trefs/heads\n\trefs/remotes/origin/master refs/heads/master\n\trefs/remotes/origin/develop/with/topics refs/heads/develop/with/topics\n\nSigned-off-by: J Wyman <jwyman@microsoft.com>\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n Documentation/git-for-each-ref.txt | 14 +++++++++-----\n ref-filter.c                       | 15 ++++++++++++++-\n remote.c                           | 30 ++++++++++++++++++++++++++++++\n remote.h                           |  2 ++\n 4 files changed, 55 insertions(+), 6 deletions(-)\n\ndiff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt\nindex 288b11aaeed..dffa14a7950 100644\n--- a/Documentation/git-for-each-ref.txt\n+++ b/Documentation/git-for-each-ref.txt\n@@ -147,8 +147,12 @@ upstream::\n \tencountered. Append `:track,nobracket` to show tracking\n \tinformation without brackets (i.e \"ahead N, behind M\").\n +\n-Also respects `:remotename` to state the name of the *remote* instead of\n-the ref.\n+For any remote-tracking branch `%(upstream)`, `%(upstream:remotename)`\n+and `%(upstream:remoteref)` refer to the name of the remote and the\n+name of the tracked remote ref, respectively. In other words, the\n+remote-tracking branch can be updated explicitly and individually by\n+using the refspec `%(upstream:remoteref):%(upstream)` to fetch from\n+`%(upstream:remotename)`.\n +\n Has no effect if the ref does not have tracking information associated\n with it.  All the options apart from `nobracket` are mutually exclusive,\n@@ -157,9 +161,9 @@ but if used together the last option is selected.\n push::\n \tThe name of a local ref which represents the `@{push}`\n \tlocation for the displayed ref. Respects `:short`, `:lstrip`,\n-\t`:rstrip`, `:track`, `:trackshort` and `:remotename` options as\n-\t`upstream` does. Produces an empty string if no `@{push}` ref is\n-\tconfigured.\n+\t`:rstrip`, `:track`, `:trackshort`, `:remotename`, and `:remoteref`\n+\toptions as `upstream` does. Produces an empty string if no `@{push}`\n+\tref is configured.\n \n HEAD::\n \t'*' if HEAD matches current ref (the checked out branch), ' '\ndiff --git a/ref-filter.c b/ref-filter.c\nindex cde8b97dcb0..3f9161707e6 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -77,7 +77,7 @@ static struct used_atom {\n \t\tstruct align align;\n \t\tstruct {\n \t\t\tenum {\n-\t\t\t\tRR_REF, RR_TRACK, RR_TRACKSHORT, RR_REMOTE_NAME\n+\t\t\t\tRR_REF, RR_TRACK, RR_TRACKSHORT, RR_REMOTE_NAME, RR_REMOTE_REF\n \t\t\t} option;\n \t\t\tstruct refname_atom refname;\n \t\t\tunsigned int nobracket : 1, push : 1, push_remote : 1;\n@@ -165,6 +165,9 @@ static void remote_ref_atom_parser(const struct ref_format *format, struct used_\n \t\telse if (!strcmp(s, \"remotename\")) {\n \t\t\tatom->u.remote_ref.option = RR_REMOTE_NAME;\n \t\t\tatom->u.remote_ref.push_remote = 1;\n+\t\t} else if (!strcmp(s, \"remoteref\")) {\n+\t\t\tatom->u.remote_ref.option = RR_REMOTE_REF;\n+\t\t\tatom->u.remote_ref.push_remote = 1;\n \t\t} else {\n \t\t\tatom->u.remote_ref.option = RR_REF;\n \t\t\trefname_atom_parser_internal(&atom->u.remote_ref.refname,\n@@ -1285,6 +1288,16 @@ static void fill_remote_ref_details(struct used_atom *atom, const char *refname,\n \t\t\t*s = xstrdup(remote);\n \t\telse\n \t\t\t*s = \"\";\n+\t} else if (atom->u.remote_ref.option == RR_REMOTE_REF) {\n+\t\tint explicit;\n+\t\tconst char *merge;\n+\n+\t\tmerge = remote_ref_for_branch(branch, atom->u.remote_ref.push,\n+\t\t\t\t\t      &explicit);\n+\t\tif (explicit)\n+\t\t\t*s = xstrdup(merge);\n+\t\telse\n+\t\t\t*s = \"\";\n \t} else\n \t\tdie(\"BUG: unhandled RR_* enum\");\n }\ndiff --git a/remote.c b/remote.c\nindex 685e776a65e..4e93753e198 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -675,6 +675,36 @@ const char *pushremote_for_branch(struct branch *branch, int *explicit)\n \treturn remote_for_branch(branch, explicit);\n }\n \n+const char *remote_ref_for_branch(struct branch *branch, int for_push,\n+\t\t\t\t  int *explicit)\n+{\n+\tif (branch) {\n+\t\tif (!for_push) {\n+\t\t\tif (branch->merge_nr) {\n+\t\t\t\tif (explicit)\n+\t\t\t\t\t*explicit = 1;\n+\t\t\t\treturn branch->merge_name[0];\n+\t\t\t}\n+\t\t} else {\n+\t\t\tconst char *dst, *remote_name =\n+\t\t\t\tpushremote_for_branch(branch, NULL);\n+\t\t\tstruct remote *remote = remote_get(remote_name);\n+\n+\t\t\tif (remote && remote->push_refspec_nr &&\n+\t\t\t    (dst = apply_refspecs(remote->push,\n+\t\t\t\t\t\t  remote->push_refspec_nr,\n+\t\t\t\t\t\t  branch->refname))) {\n+\t\t\t\tif (explicit)\n+\t\t\t\t\t*explicit = 1;\n+\t\t\t\treturn dst;\n+\t\t\t}\n+\t\t}\n+\t}\n+\tif (explicit)\n+\t\t*explicit = 0;\n+\treturn \"\";\n+}\n+\n static struct remote *remote_get_1(const char *name,\n \t\t\t\t   const char *(*get_default)(struct branch *, int *))\n {\ndiff --git a/remote.h b/remote.h\nindex 2ecf4c8c74c..1f6611be214 100644\n--- a/remote.h\n+++ b/remote.h\n@@ -223,6 +223,8 @@ struct branch {\n struct branch *branch_get(const char *name);\n const char *remote_for_branch(struct branch *branch, int *explicit);\n const char *pushremote_for_branch(struct branch *branch, int *explicit);\n+const char *remote_ref_for_branch(struct branch *branch, int for_push,\n+\t\t\t\t  int *explicit);\n \n int branch_has_merge_config(struct branch *branch);\n int branch_merge_matches(struct branch *, int n, const char *);\n-- \n2.15.0.windows.1\n\n\n"},{"id":"332015","messageId":"bf51292cfefd495ff813fdf638c51f6b7acfe646.1510072200.git.johannes.schindelin@gmx.de","threadId":"46883","inReplyTo":"cover.1510072200.git.johannes.schindelin@gmx.de","subject":"[PATCH v3 3/3] for-each-ref: test :remotename and :remoteref","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-11-07T16:31:14Z","receivedAt":"2017-11-07T16:31:24Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"This not only prevents regressions, but also serves as documentation\nwhat this new feature is expected to do.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n t/t6300-for-each-ref.sh | 32 ++++++++++++++++++++++++++++++++\n 1 file changed, 32 insertions(+)\n\ndiff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh\nindex 3aa534933e0..c128dfc5790 100755\n--- a/t/t6300-for-each-ref.sh\n+++ b/t/t6300-for-each-ref.sh\n@@ -766,4 +766,36 @@ test_expect_success 'Verify usage of %(symref:rstrip) atom' '\n \ttest_cmp expected actual\n '\n \n+test_expect_success ':remotename and :remoteref' '\n+\tgit init remote-tests &&\n+\t(\n+\t\tcd remote-tests &&\n+\t\ttest_commit initial &&\n+\t\tgit remote add from fifth.coffee:blub &&\n+\t\tgit config branch.master.remote from &&\n+\t\tgit config branch.master.merge refs/heads/stable &&\n+\t\tgit remote add to southridge.audio:repo &&\n+\t\tgit config remote.to.push \"refs/heads/*:refs/heads/pushed/*\" &&\n+\t\tgit config branch.master.pushRemote to &&\n+\t\tfor pair in \"%(upstream)=refs/remotes/from/stable\" \\\n+\t\t\t\"%(upstream:remotename)=from\" \\\n+\t\t\t\"%(upstream:remoteref)=refs/heads/stable\" \\\n+\t\t\t\"%(push)=refs/remotes/to/pushed/master\" \\\n+\t\t\t\"%(push:remotename)=to\" \\\n+\t\t\t\"%(push:remoteref)=refs/heads/pushed/master\"\n+\t\tdo\n+\t\t\techo \"${pair#*=}\" >expect &&\n+\t\t\tgit for-each-ref --format=\"${pair%=*}\" \\\n+\t\t\t\trefs/heads/master >actual &&\n+\t\t\ttest_cmp expect actual\n+\t\tdone &&\n+\t\tgit branch push-simple &&\n+\t\tgit config branch.push-simple.pushRemote from &&\n+\t\tactual=\"$(git for-each-ref \\\n+\t\t\t--format=\"%(push:remotename),%(push:remoteref)\" \\\n+\t\t\trefs/heads/push-simple)\" &&\n+\t\ttest from, = \"$actual\"\n+\t)\n+'\n+\n test_done\n-- \n2.15.0.windows.1\n"},{"id":"332056","messageId":"xmqqwp31mtzf.fsf@gitster.mtv.corp.google.com","threadId":"46883","inReplyTo":"cover.1510072200.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH v3 0/3] for-each-ref: add :remoteref and :remotename specifiers","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-11-08T01:36:52Z","receivedAt":"2017-11-08T01:37:00Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n\n> Changes since v2:\n>\n> - fixed the commit message of 1/3 to no longer talk about :remote.\n\nOK.  It now matches what we have had since October 5th in my tree.\n\n> - used the push atom in 2/3, made the code look more as suggested by Junio.\n\nI am pleasantly surprised (mostly because I didn't realize that the\ncode has already prepared all the info necessary to do this in the\natom enumeration phase) that this change was quite easy and doably\nvery cleanly.\n\n> - fixed the oneline of 2/3 to use a verb (\"report\").\n>\n> - butchered Junio's proposed documentation update for 2/3 to hopefully make\n>   the description of :remotename and :remoteref a lot clearer.\n\nWell I wasn't attempting to propose anything---as I said, I couldn't\nconcisely phrase what the description in v2 wanted to say in clearer\nterms, so I gave a lengthy and fuller description.\n\nIt feels a bit out-of-place to see \"can be updated\" in the\ndescription of a read-only operation for-each-ref, as we see below:\n\n>  -Also respects `:remotename` to state the name of the *remote* instead\n>  -of the ref, and `:remoteref` to state the name of the *reference* as\n>  -locally known by the remote.\n>  +For any remote-tracking branch `%(upstream)`, `%(upstream:remotename)`\n>  +and `%(upstream:remoteref)` refer to the name of the remote and the\n>  +name of the tracked remote ref, respectively. In other words, the\n>  +remote-tracking branch can be updated explicitly and individually by\n>  +using the refspec `%(upstream:remoteref):%(upstream)` to fetch from\n>  +`%(upstream:remotename)`.\n\nbut I think this should do for now.  It certainly is much clearer\nthan the previous round.\n\nWill queue, and merge to 'next' soonish.\n\nThanks.\n"}]}