{"thread":{"id":"33911","subject":"[PATCH 0/7] Let's get that @{push}!","startedAt":"2013-05-23T15:12:43Z","lastAt":"2013-05-24T19:12:40Z","messageCount":17,"participants":["Ramkumar Ramachandra","Felipe Contreras","Duy Nguyen","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":7},"messages":[{"id":"218269","messageId":"1369321970-7759-1-git-send-email-artagnon@gmail.com","threadId":"33911","inReplyTo":null,"subject":"[PATCH 0/7] Let's get that @{push}!","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2013-05-23T15:12:43Z","receivedAt":"2013-05-23T15:12:43Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"[7/7] is the meat.  Sorry it's in such a messy state: I was having a\nfield day tracing what push is actually doing.  Anyway, I wanted to\nsend out the series now to get early feedback.\n\nIn other news: why on earth is push doing _so_ much processing before\npushing?  Is it written very badly, or am I missing something?\n\nThanks.\n\n(based on rr/die-on-missing-upstream)\n\nRamkumar Ramachandra (7):\n  sha1_name: abstract upstream_mark() logic\n  sha1_name: factor out die_no_upstream()\n  sha1_name: remove upstream_mark()\n  remote: expose parse_push_refspec()\n  remote: expose get_ref_match()\n  sha1_name: prepare to introduce AT_KIND_PUSH\n  sha1_name: implement finding @{push}\n\n remote.c    |   4 +--\n remote.h    |   4 +++\n sha1_name.c | 111 ++++++++++++++++++++++++++++++++++++++++++++----------------\n 3 files changed, 88 insertions(+), 31 deletions(-)\n\n-- \n1.8.3.rc3.17.gd95ec6c.dirty\n"},{"id":"218273","messageId":"1369321970-7759-2-git-send-email-artagnon@gmail.com","threadId":"33911","inReplyTo":"1369321970-7759-1-git-send-email-artagnon@gmail.com","subject":"[PATCH 1/7] sha1_name: abstract upstream_mark() logic","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2013-05-23T15:12:44Z","receivedAt":"2013-05-23T15:12:44Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Currently, the only non-numerical @{...} expression we support is\n@{u[pstream]}.  Since we're slowly growing git to support triangular\nworkflows, it might make sense to have a @{p[ush]} and various other\nspecial @{...} expressions in the future.  To prepare for this, abstract\nout the upstream_mark() logic to accept any suffix, while preserving the\nupstream_mark() interface.\n\nSigned-off-by: Ramkumar Ramachandra <artagnon@gmail.com>\n---\n sha1_name.c | 40 +++++++++++++++++++++++++++++++---------\n 1 file changed, 31 insertions(+), 9 deletions(-)\n\ndiff --git a/sha1_name.c b/sha1_name.c\nindex 6928cc7..766e4e9 100644\n--- a/sha1_name.c\n+++ b/sha1_name.c\n@@ -23,6 +23,8 @@ struct disambiguate_state {\n \tunsigned always_call_fn:1;\n };\n \n+#define AT_KIND_UPSTREAM 0\n+\n static void update_candidates(struct disambiguate_state *ds, const unsigned char *current)\n {\n \tif (ds->always_call_fn) {\n@@ -416,20 +418,40 @@ static int ambiguous_path(const char *path, int len)\n \treturn slash;\n }\n \n-static inline int upstream_mark(const char *string, int len)\n+static inline int at_mark(const char *string, int len, int *kind)\n {\n-\tconst char *suffix[] = { \"@{upstream}\", \"@{u}\" };\n-\tint i;\n-\n-\tfor (i = 0; i < ARRAY_SIZE(suffix); i++) {\n-\t\tint suffix_len = strlen(suffix[i]);\n-\t\tif (suffix_len <= len\n-\t\t    && !memcmp(string, suffix[i], suffix_len))\n-\t\t\treturn suffix_len;\n+\tint i, j;\n+\n+\tstatic struct {\n+\t\tint kind;\n+\t\tconst char *suffix[2];\n+\t} at_form[] = {\n+\t\t{ AT_KIND_UPSTREAM, { \"@{upstream}\", \"@{u}\" } }\n+\t};\n+\n+\tfor (j = 0; j < ARRAY_SIZE(at_form); j++) {\n+\t\tfor (i = 0; i < ARRAY_SIZE(at_form[j].suffix); i++) {\n+\t\t\tint suffix_len = strlen(at_form[j].suffix[i]);\n+\t\t\tif (suffix_len <= len\n+\t\t\t\t&& !memcmp(string, at_form[j].suffix[i], suffix_len)) {\n+\t\t\t\tif (kind)\n+\t\t\t\t\t*kind = at_form[j].kind;\n+\t\t\t\treturn suffix_len;\n+\t\t\t}\n+\t\t}\n \t}\n \treturn 0;\n }\n \n+static inline int upstream_mark(const char *string, int len)\n+{\n+\tint suffix_len, kind;\n+\tsuffix_len = at_mark(string, len, &kind);\n+\tif (suffix_len && kind == AT_KIND_UPSTREAM)\n+\t\treturn suffix_len;\n+\treturn 0;\n+}\n+\n static int get_sha1_1(const char *name, int len, unsigned char *sha1, unsigned lookup_flags);\n \n static int get_sha1_basic(const char *str, int len, unsigned char *sha1)\n-- \n1.8.3.rc3.17.gd95ec6c.dirty\n"},{"id":"218271","messageId":"1369321970-7759-3-git-send-email-artagnon@gmail.com","threadId":"33911","inReplyTo":"1369321970-7759-1-git-send-email-artagnon@gmail.com","subject":"[PATCH 2/7] sha1_name: factor out die_no_upstream()","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2013-05-23T15:12:45Z","receivedAt":"2013-05-23T15:12:45Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Currently interpret_branch_name() tries to parse various things, and\nfinally falls back to parsing <branch>@{u[pstream]}.  It dies if the\ninput string contained an \"@{u[pstream]}\" but an upstream could not be\nfound.  The logic can be generalized to check for any branch property\nafter branch_get().  In preparation for introducing more special @{...}\nforms, factor out die_no_upstream().\n\nSigned-off-by: Ramkumar Ramachandra <artagnon@gmail.com>\n---\n sha1_name.c | 40 ++++++++++++++++++++++------------------\n 1 file changed, 22 insertions(+), 18 deletions(-)\n\ndiff --git a/sha1_name.c b/sha1_name.c\nindex 766e4e9..7aabd94 100644\n--- a/sha1_name.c\n+++ b/sha1_name.c\n@@ -998,6 +998,24 @@ int get_sha1_mb(const char *name, unsigned char *sha1)\n \treturn st;\n }\n \n+static void die_no_upstream(struct branch *upstream, char *name) {\n+\t/*\n+\t * Upstream can be NULL only if cp refers to HEAD and HEAD\n+\t * points to something different than a branch.\n+\t */\n+\tif (!upstream)\n+\t\tdie(_(\"HEAD does not point to a branch\"));\n+\tif (!upstream->merge || !upstream->merge[0]->dst) {\n+\t\tif (!ref_exists(upstream->refname))\n+\t\t\tdie(_(\"No such branch: '%s'\"), name);\n+\t\tif (!upstream->merge)\n+\t\t\tdie(_(\"No upstream configured for branch '%s'\"),\n+\t\t\t\tupstream->name);\n+\t\tdie(_(\"Upstream branch '%s' not stored as a remote-tracking branch\"),\n+\t\t\tupstream->merge[0]->src);\n+\t}\n+}\n+\n /*\n  * This reads short-hand syntax that not only evaluates to a commit\n  * object name, but also can act as if the end user spelled the name\n@@ -1022,7 +1040,7 @@ int get_sha1_mb(const char *name, unsigned char *sha1)\n int interpret_branch_name(const char *name, struct strbuf *buf)\n {\n \tchar *cp;\n-\tstruct branch *upstream;\n+\tstruct branch *branch;\n \tint namelen = strlen(name);\n \tint len = interpret_nth_prior_checkout(name, buf);\n \tint tmp_len;\n@@ -1059,24 +1077,10 @@ int interpret_branch_name(const char *name, struct strbuf *buf)\n \t\treturn -1;\n \tlen = cp + tmp_len - name;\n \tcp = xstrndup(name, cp - name);\n-\tupstream = branch_get(*cp ? cp : NULL);\n-\t/*\n-\t * Upstream can be NULL only if cp refers to HEAD and HEAD\n-\t * points to something different than a branch.\n-\t */\n-\tif (!upstream)\n-\t\tdie(_(\"HEAD does not point to a branch\"));\n-\tif (!upstream->merge || !upstream->merge[0]->dst) {\n-\t\tif (!ref_exists(upstream->refname))\n-\t\t\tdie(_(\"No such branch: '%s'\"), cp);\n-\t\tif (!upstream->merge)\n-\t\t\tdie(_(\"No upstream configured for branch '%s'\"),\n-\t\t\t\tupstream->name);\n-\t\tdie(_(\"Upstream branch '%s' not stored as a remote-tracking branch\"),\n-\t\t\tupstream->merge[0]->src);\n-\t}\n+\tbranch = branch_get(*cp ? cp : NULL);\n+\tdie_no_upstream(branch, cp);\n \tfree(cp);\n-\tcp = shorten_unambiguous_ref(upstream->merge[0]->dst, 0);\n+\tcp = shorten_unambiguous_ref(branch->merge[0]->dst, 0);\n \tstrbuf_reset(buf);\n \tstrbuf_addstr(buf, cp);\n \tfree(cp);\n-- \n1.8.3.rc3.17.gd95ec6c.dirty\n"},{"id":"218276","messageId":"1369321970-7759-4-git-send-email-artagnon@gmail.com","threadId":"33911","inReplyTo":"1369321970-7759-1-git-send-email-artagnon@gmail.com","subject":"[PATCH 3/7] sha1_name: remove upstream_mark()","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2013-05-23T15:12:46Z","receivedAt":"2013-05-23T15:12:46Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"The first caller get_sha1_basic() just wants to make sure that no\nnon-numerical @{...} form was matched, so that it can proceed with\nprocessing numerical @{...} forms.  Since we're going to introduce more\nnon-numerical @{...} forms, replace this upstream_mark() call with a\ncall to at_mark() passing NULL as the last argument; we don't care what\nthe kind is: all we need to know is if the return value is zero (parse\nfailure).\n\nThe second caller interpret_branch_name() will be expanded in the future\nto handle all possible AT_KIND_* values.  So, replace the\nupstream_mark() call with an upstream_mark() call capturing at_kind and\nusing it in a switch statement to perform the appropriate action.\n\nSigned-off-by: Ramkumar Ramachandra <artagnon@gmail.com>\n---\n sha1_name.c | 26 ++++++++++++--------------\n 1 file changed, 12 insertions(+), 14 deletions(-)\n\ndiff --git a/sha1_name.c b/sha1_name.c\nindex 7aabd94..106716e 100644\n--- a/sha1_name.c\n+++ b/sha1_name.c\n@@ -443,15 +443,6 @@ static inline int at_mark(const char *string, int len, int *kind)\n \treturn 0;\n }\n \n-static inline int upstream_mark(const char *string, int len)\n-{\n-\tint suffix_len, kind;\n-\tsuffix_len = at_mark(string, len, &kind);\n-\tif (suffix_len && kind == AT_KIND_UPSTREAM)\n-\t\treturn suffix_len;\n-\treturn 0;\n-}\n-\n static int get_sha1_1(const char *name, int len, unsigned char *sha1, unsigned lookup_flags);\n \n static int get_sha1_basic(const char *str, int len, unsigned char *sha1)\n@@ -469,7 +460,7 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1)\n \tif (len && str[len-1] == '}') {\n \t\tfor (at = len-2; at >= 0; at--) {\n \t\t\tif (str[at] == '@' && str[at+1] == '{') {\n-\t\t\t\tif (!upstream_mark(str + at, len - at)) {\n+\t\t\t\tif (!at_mark(str + at, len - at, NULL)) {\n \t\t\t\t\treflog_len = (len-1) - (at+2);\n \t\t\t\t\tlen = at;\n \t\t\t\t}\n@@ -1044,6 +1035,7 @@ int interpret_branch_name(const char *name, struct strbuf *buf)\n \tint namelen = strlen(name);\n \tint len = interpret_nth_prior_checkout(name, buf);\n \tint tmp_len;\n+\tint at_kind;\n \n \tif (!len)\n \t\treturn len; /* syntax Ok, not enough switches */\n@@ -1072,15 +1064,21 @@ int interpret_branch_name(const char *name, struct strbuf *buf)\n \tcp = strchr(name, '@');\n \tif (!cp)\n \t\treturn -1;\n-\ttmp_len = upstream_mark(cp, namelen - (cp - name));\n+\ttmp_len = at_mark(cp, namelen - (cp - name), &at_kind);\n \tif (!tmp_len)\n \t\treturn -1;\n \tlen = cp + tmp_len - name;\n \tcp = xstrndup(name, cp - name);\n \tbranch = branch_get(*cp ? cp : NULL);\n-\tdie_no_upstream(branch, cp);\n-\tfree(cp);\n-\tcp = shorten_unambiguous_ref(branch->merge[0]->dst, 0);\n+\n+\tswitch (at_kind) {\n+\tcase AT_KIND_UPSTREAM:\n+\t\tdie_no_upstream(branch, cp);\n+\t\tfree(cp);\n+\t\tcp = shorten_unambiguous_ref(branch->merge[0]->dst, 0);\n+\t\tbreak;\n+\t}\n+\n \tstrbuf_reset(buf);\n \tstrbuf_addstr(buf, cp);\n \tfree(cp);\n-- \n1.8.3.rc3.17.gd95ec6c.dirty\n"},{"id":"218270","messageId":"1369321970-7759-5-git-send-email-artagnon@gmail.com","threadId":"33911","inReplyTo":"1369321970-7759-1-git-send-email-artagnon@gmail.com","subject":"[PATCH 4/7] remote: expose parse_push_refspec()","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2013-05-23T15:12:47Z","receivedAt":"2013-05-23T15:12:47Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"parse_fetch_refspec() is already available to other callers via\nremote.h.  There's no reason why parse_push_refspec() shouldn't be.\n\nSigned-off-by: Ramkumar Ramachandra <artagnon@gmail.com>\n---\n remote.c | 2 +-\n remote.h | 1 +\n 2 files changed, 2 insertions(+), 1 deletion(-)\n\ndiff --git a/remote.c b/remote.c\nindex 68eb99b..99c44da 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -660,7 +660,7 @@ struct refspec *parse_fetch_refspec(int nr_refspec, const char **refspec)\n \treturn parse_refspec_internal(nr_refspec, refspec, 1, 0);\n }\n \n-static struct refspec *parse_push_refspec(int nr_refspec, const char **refspec)\n+struct refspec *parse_push_refspec(int nr_refspec, const char **refspec)\n {\n \treturn parse_refspec_internal(nr_refspec, refspec, 0, 0);\n }\ndiff --git a/remote.h b/remote.h\nindex cf56724..2497b93 100644\n--- a/remote.h\n+++ b/remote.h\n@@ -94,6 +94,7 @@ void ref_remove_duplicates(struct ref *ref_map);\n \n int valid_fetch_refspec(const char *refspec);\n struct refspec *parse_fetch_refspec(int nr_refspec, const char **refspec);\n+struct refspec *parse_push_refspec(int nr_refspec, const char **refspec);\n \n void free_refspec(int nr_refspec, struct refspec *refspec);\n \n-- \n1.8.3.rc3.17.gd95ec6c.dirty\n"},{"id":"218272","messageId":"1369321970-7759-6-git-send-email-artagnon@gmail.com","threadId":"33911","inReplyTo":"1369321970-7759-1-git-send-email-artagnon@gmail.com","subject":"[PATCH 5/7] remote: expose get_ref_match()","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2013-05-23T15:12:48Z","receivedAt":"2013-05-23T15:12:48Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"We need it.\n\nSigned-off-by: Ramkumar Ramachandra <artagnon@gmail.com>\n---\n remote.c | 2 +-\n remote.h | 3 +++\n 2 files changed, 4 insertions(+), 1 deletion(-)\n\ndiff --git a/remote.c b/remote.c\nindex 99c44da..9ae1fc5 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -1168,7 +1168,7 @@ static int match_explicit_refs(struct ref *src, struct ref *dst,\n \treturn errs;\n }\n \n-static char *get_ref_match(const struct refspec *rs, int rs_nr, const struct ref *ref,\n+char *get_ref_match(const struct refspec *rs, int rs_nr, const struct ref *ref,\n \t\tint send_mirror, int direction, const struct refspec **ret_pat)\n {\n \tconst struct refspec *pat;\ndiff --git a/remote.h b/remote.h\nindex 2497b93..5671fe0 100644\n--- a/remote.h\n+++ b/remote.h\n@@ -173,4 +173,7 @@ struct ref *guess_remote_head(const struct ref *head,\n /* Return refs which no longer exist on remote */\n struct ref *get_stale_heads(struct refspec *refs, int ref_count, struct ref *fetch_map);\n \n+char *get_ref_match(const struct refspec *rs, int rs_nr, const struct ref *ref,\n+\t\tint send_mirror, int direction, const struct refspec **ret_pat);\n+\n #endif\n-- \n1.8.3.rc3.17.gd95ec6c.dirty\n"},{"id":"218275","messageId":"1369321970-7759-7-git-send-email-artagnon@gmail.com","threadId":"33911","inReplyTo":"1369321970-7759-1-git-send-email-artagnon@gmail.com","subject":"[PATCH 6/7] sha1_name: prepare to introduce AT_KIND_PUSH","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2013-05-23T15:12:49Z","receivedAt":"2013-05-23T15:12:49Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Introduce an AT_KIND_PUSH to be represented as \"@{p[ush]}\".  Determine\nit using branch.remote.push_refspec.\n\nSigned-off-by: Ramkumar Ramachandra <artagnon@gmail.com>\n---\n sha1_name.c | 13 +++++++++++--\n 1 file changed, 11 insertions(+), 2 deletions(-)\n\ndiff --git a/sha1_name.c b/sha1_name.c\nindex 106716e..5f6958b 100644\n--- a/sha1_name.c\n+++ b/sha1_name.c\n@@ -23,7 +23,7 @@ struct disambiguate_state {\n \tunsigned always_call_fn:1;\n };\n \n-#define AT_KIND_UPSTREAM 0\n+enum at_kind { AT_KIND_UPSTREAM, AT_KIND_PUSH };\n \n static void update_candidates(struct disambiguate_state *ds, const unsigned char *current)\n {\n@@ -426,7 +426,8 @@ static inline int at_mark(const char *string, int len, int *kind)\n \t\tint kind;\n \t\tconst char *suffix[2];\n \t} at_form[] = {\n-\t\t{ AT_KIND_UPSTREAM, { \"@{upstream}\", \"@{u}\" } }\n+\t\t{ AT_KIND_UPSTREAM, { \"@{upstream}\", \"@{u}\" } },\n+\t\t{ AT_KIND_PUSH, { \"@{push}\", \"@{p}\" } }\n \t};\n \n \tfor (j = 0; j < ARRAY_SIZE(at_form); j++) {\n@@ -1022,6 +1023,12 @@ static void die_no_upstream(struct branch *upstream, char *name) {\n  *   given buf and returns the number of characters parsed if\n  *   successful.\n  *\n+ * - \"<branch>@{push}\" finds the name of the ref that\n+ *   <branch> is configured to push to (missing <branch> defaults\n+ *   to the current branch), and places the name of the branch in the\n+ *   given buf and returns the number of characters parsed if\n+ *   successful.\n+ *\n  * If the input is not of the accepted format, it returns a negative\n  * number to signal an error.\n  *\n@@ -1077,6 +1084,8 @@ int interpret_branch_name(const char *name, struct strbuf *buf)\n \t\tfree(cp);\n \t\tcp = shorten_unambiguous_ref(branch->merge[0]->dst, 0);\n \t\tbreak;\n+\tcase AT_KIND_PUSH:\n+\t\tbreak;\n \t}\n \n \tstrbuf_reset(buf);\n-- \n1.8.3.rc3.17.gd95ec6c.dirty\n"},{"id":"218274","messageId":"1369321970-7759-8-git-send-email-artagnon@gmail.com","threadId":"33911","inReplyTo":"1369321970-7759-1-git-send-email-artagnon@gmail.com","subject":"[PATCH 7/7] sha1_name: implement finding @{push}","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2013-05-23T15:12:50Z","receivedAt":"2013-05-23T15:12:50Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Try this now: configure your current branch's pushremote to push to\n\"refs/heads/*:refs/heads/rr/*\".  Now, type 'git show @{p}'.  Voila!\n\nIt currently only works when:\n\n1. remote.<name>.push is explicitly specified.\n2. There is a pattern to match (*).\n\nProof-of-concept only.\n\nSigned-off-by: Ramkumar Ramachandra <artagnon@gmail.com>\n---\n sha1_name.c | 20 ++++++++++++++++++++\n 1 file changed, 20 insertions(+)\n\ndiff --git a/sha1_name.c b/sha1_name.c\nindex 5f6958b..283d538 100644\n--- a/sha1_name.c\n+++ b/sha1_name.c\n@@ -1008,6 +1008,24 @@ static void die_no_upstream(struct branch *upstream, char *name) {\n \t}\n }\n \n+static void find_push_ref(struct branch *branch) {\n+\tstruct remote *remote = pushremote_get(NULL);\n+\tconst struct refspec *pat = NULL;\n+\tchar raw_ref[PATH_MAX];\n+\tstruct ref *this_ref;\n+\tchar *dst_name;\n+\tint len;\n+\n+\tsprintf(raw_ref, \"refs/heads/%s\", branch->name);\n+\tlen = strlen(raw_ref) + 1;\n+\tthis_ref = xcalloc(1, sizeof(*this_ref) + len);\n+\tmemcpy(this_ref->name, raw_ref, len);\n+\n+\tdst_name = get_ref_match(remote->push, remote->push_refspec_nr,\n+\t\t\t\tthis_ref, MATCH_REFS_ALL, 0, &pat);\n+\tprintf(\"dst_name = %s\\n\", dst_name);\n+}\n+\n /*\n  * This reads short-hand syntax that not only evaluates to a commit\n  * object name, but also can act as if the end user spelled the name\n@@ -1085,6 +1103,8 @@ int interpret_branch_name(const char *name, struct strbuf *buf)\n \t\tcp = shorten_unambiguous_ref(branch->merge[0]->dst, 0);\n \t\tbreak;\n \tcase AT_KIND_PUSH:\n+\t\tfind_push_ref(branch);\n+\t\tdie(\"Done!\");\n \t\tbreak;\n \t}\n \n-- \n1.8.3.rc3.17.gd95ec6c.dirty\n"},{"id":"218366","messageId":"CAMP44s2AxHkx54HzCCK5nUsexAhWy4J_oqg4wNu0=FzvEYtXAg@mail.gmail.com","threadId":"33911","inReplyTo":"1369321970-7759-7-git-send-email-artagnon@gmail.com","subject":"Re: [PATCH 6/7] sha1_name: prepare to introduce AT_KIND_PUSH","fromName":"Felipe Contreras","fromEmail":"felipe.contreras@gmail.com","sentAt":"2013-05-24T13:22:15Z","receivedAt":"2013-05-24T13:22:15Z","isPatch":true,"sender":{"key":"felipe.contreras@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8358?v=4"},"body":"On Thu, May 23, 2013 at 10:12 AM, Ramkumar Ramachandra\n<artagnon@gmail.com> wrote:\n> Introduce an AT_KIND_PUSH to be represented as \"@{p[ush]}\".  Determine\n> it using branch.remote.push_refspec.\n\nI think the semantics of this don't make any sense.\n\n  git push branch@{upstream}\n\nIs very clear: push upstream of branch.\n\n  git push branch@{push}\n\nIs not clear at all: push push of branch?\n\nIs it a noun, or a verb?\n\nI would expect branch@{X} to be 'the X of branch', and \"the push of\nbranch\" doesn't make sense. Whatever X ends up being, it should be a\nnoun.\n\n-- \nFelipe Contreras\n"},{"id":"218367","messageId":"CALkWK0m+PAeE1nk4a7PjXU2tymCQVXzGL1CFOgyd5AqJuVZ9Og@mail.gmail.com","threadId":"33911","inReplyTo":"CAMP44s2AxHkx54HzCCK5nUsexAhWy4J_oqg4wNu0=FzvEYtXAg@mail.gmail.com","subject":"Re: [PATCH 6/7] sha1_name: prepare to introduce AT_KIND_PUSH","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2013-05-24T13:27:05Z","receivedAt":"2013-05-24T13:27:05Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Felipe Contreras wrote:\n>   git push branch@{push}\n>\n> Is not clear at all: push push of branch?\n\nWe can pick the name later.  I had to pick a name to write code, and\nthat happens to be @{push}.\n"},{"id":"218385","messageId":"CACsJy8CV192WVW8u6YRnbf6Ue6tFbzyiCARwicwzapSZucaaMw@mail.gmail.com","threadId":"33911","inReplyTo":"1369321970-7759-8-git-send-email-artagnon@gmail.com","subject":"Re: [PATCH 7/7] sha1_name: implement finding @{push}","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2013-05-24T16:09:49Z","receivedAt":"2013-05-24T16:09:49Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"(I haven't caught up with git mails lately, but the @{special}\nrefactoring caught my eyes..)\n\nOn Thu, May 23, 2013 at 10:12 PM, Ramkumar Ramachandra\n<artagnon@gmail.com> wrote:\n> Try this now: configure your current branch's pushremote to push to\n> \"refs/heads/*:refs/heads/rr/*\".  Now, type 'git show @{p}'.  Voila!\n\nVoila what? Why not avoid guessing game and describe what the patch is for?\n\n> +static void find_push_ref(struct branch *branch) {\n> +       struct remote *remote = pushremote_get(NULL);\n> +       const struct refspec *pat = NULL;\n> +       char raw_ref[PATH_MAX];\n> +       struct ref *this_ref;\n> +       char *dst_name;\n> +       int len;\n> +\n> +       sprintf(raw_ref, \"refs/heads/%s\", branch->name);\n> +       len = strlen(raw_ref) + 1;\n> +       this_ref = xcalloc(1, sizeof(*this_ref) + len);\n> +       memcpy(this_ref->name, raw_ref, len);\n> +\n> +       dst_name = get_ref_match(remote->push, remote->push_refspec_nr,\n> +                               this_ref, MATCH_REFS_ALL, 0, &pat);\n> +       printf(\"dst_name = %s\\n\", dst_name);\n> +}\n> +\n\nIsn't this an abuse of extended sha-1 syntax? How can I combine this\nwith other @{}, ^, ~...?\n--\nDuy\n"},{"id":"218387","messageId":"CALkWK0=XufbcwObBq7_MWX3jL63Nv3YeSvTUpOfXD+XoKkvMag@mail.gmail.com","threadId":"33911","inReplyTo":"CACsJy8CV192WVW8u6YRnbf6Ue6tFbzyiCARwicwzapSZucaaMw@mail.gmail.com","subject":"Re: [PATCH 7/7] sha1_name: implement finding @{push}","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2013-05-24T16:15:52Z","receivedAt":"2013-05-24T16:15:52Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Duy Nguyen wrote:\n> On Thu, May 23, 2013 at 10:12 PM, Ramkumar Ramachandra\n> <artagnon@gmail.com> wrote:\n>> Try this now: configure your current branch's pushremote to push to\n>> \"refs/heads/*:refs/heads/rr/*\".  Now, type 'git show @{p}'.  Voila!\n>\n> Voila what? Why not avoid guessing game and describe what the patch is for?\n\nIf you're on branch master, it'll output refs/heads/rr/master.  The\ntopic is about having a @{push} corresponding to @{upstream}\n\n>> +static void find_push_ref(struct branch *branch) {\n>> +       struct remote *remote = pushremote_get(NULL);\n>> +       const struct refspec *pat = NULL;\n>> +       char raw_ref[PATH_MAX];\n>> +       struct ref *this_ref;\n>> +       char *dst_name;\n>> +       int len;\n>> +\n>> +       sprintf(raw_ref, \"refs/heads/%s\", branch->name);\n>> +       len = strlen(raw_ref) + 1;\n>> +       this_ref = xcalloc(1, sizeof(*this_ref) + len);\n>> +       memcpy(this_ref->name, raw_ref, len);\n>> +\n>> +       dst_name = get_ref_match(remote->push, remote->push_refspec_nr,\n>> +                               this_ref, MATCH_REFS_ALL, 0, &pat);\n>> +       printf(\"dst_name = %s\\n\", dst_name);\n>> +}\n>> +\n>\n> Isn't this an abuse of extended sha-1 syntax? How can I combine this\n> with other @{}, ^, ~...?\n\nI'm unsure what you mean.  How can I be on branch master^1?  Did you\nread the cover-letter?\n"},{"id":"218389","messageId":"CACsJy8AHX0181uON5Aa7oJzX8j3qAA26Ymh5G3YEGidD4O5zvA@mail.gmail.com","threadId":"33911","inReplyTo":"CALkWK0=XufbcwObBq7_MWX3jL63Nv3YeSvTUpOfXD+XoKkvMag@mail.gmail.com","subject":"Re: [PATCH 7/7] sha1_name: implement finding @{push}","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2013-05-24T16:21:34Z","receivedAt":"2013-05-24T16:21:34Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Fri, May 24, 2013 at 11:15 PM, Ramkumar Ramachandra\n<artagnon@gmail.com> wrote:\n> Duy Nguyen wrote:\n>> On Thu, May 23, 2013 at 10:12 PM, Ramkumar Ramachandra\n>> <artagnon@gmail.com> wrote:\n>>> Try this now: configure your current branch's pushremote to push to\n>>> \"refs/heads/*:refs/heads/rr/*\".  Now, type 'git show @{p}'.  Voila!\n>>\n>> Voila what? Why not avoid guessing game and describe what the patch is for?\n>\n> If you're on branch master, it'll output refs/heads/rr/master.  The\n> topic is about having a @{push} corresponding to @{upstream}\n\nThen \"show @{p}\" should show the tip commit of rr/master, not the ref\nname. rev-parse (with an option, maybe) may be a better place for\nthis.\n\n>>> +       dst_name = get_ref_match(remote->push, remote->push_refspec_nr,\n>>> +                               this_ref, MATCH_REFS_ALL, 0, &pat);\n>>> +       printf(\"dst_name = %s\\n\", dst_name);\n>>> +}\n>>> +\n>>\n>> Isn't this an abuse of extended sha-1 syntax? How can I combine this\n>> with other @{}, ^, ~...?\n>\n> I'm unsure what you mean.  How can I be on branch master^1?  Did you\n> read the cover-letter?\n\nI did not expect @{p} to printf(). If it's part of get_sha1(), how can\nit return an sha-1? And the cover letter said \"7/7 is the meat\". Not\nvery informative.\n--\nDuy\n"},{"id":"218392","messageId":"CALkWK0=LXNRaWz0vN_FwmJKbXT+W11mHABqzSJnbm_izQ0Ttrw@mail.gmail.com","threadId":"33911","inReplyTo":"CACsJy8AHX0181uON5Aa7oJzX8j3qAA26Ymh5G3YEGidD4O5zvA@mail.gmail.com","subject":"Re: [PATCH 7/7] sha1_name: implement finding @{push}","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2013-05-24T16:29:11Z","receivedAt":"2013-05-24T16:29:11Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Duy Nguyen wrote:\n> Then \"show @{p}\" should show the tip commit of rr/master, not the ref\n> name.\n\nYes, that is correct.\n\n> rev-parse (with an option, maybe) may be a better place for\n> this.\n\nEr, no.  I actually want things like diff @{p}..HEAD.  I want it to be\na first-class revision, just like @{u}.\n\n> I did not expect @{p} to printf(). If it's part of get_sha1(), how can\n> it return an sha-1? And the cover letter said \"7/7 is the meat\". Not\n> very informative.\n\nI also said sorry for the horrible mess ;)\nYes, it's obviously not supposed to print and die() with a \"Done!\":\nthis was a development session, and I hit send-email as soon as I got\nthe right output.  It's supposed to behave exactly like @{u} (failing\nto resolve occasionally).\n"},{"id":"218405","messageId":"7vehcw9s0k.fsf@alter.siamese.dyndns.org","threadId":"33911","inReplyTo":"CALkWK0=LXNRaWz0vN_FwmJKbXT+W11mHABqzSJnbm_izQ0Ttrw@mail.gmail.com","subject":"Re: [PATCH 7/7] sha1_name: implement finding @{push}","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-05-24T18:01:15Z","receivedAt":"2013-05-24T18:01:15Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ramkumar Ramachandra <artagnon@gmail.com> writes:\n\n> Duy Nguyen wrote:\n>> Then \"show @{p}\" should show the tip commit of rr/master, not the ref\n>> name.\n>\n> Yes, that is correct.\n>\n>> rev-parse (with an option, maybe) may be a better place for\n>> this.\n>\n> Er, no.  I actually want things like diff @{p}..HEAD.  I want it to be\n> a first-class revision, just like @{u}.\n\nI think Duy's suggestion makes perfect sense; rev-parse already has\na mechanism to expand @{u} to the full name, so if you are hooking\ninto the same codepath as @{u} to implement the \"I publish there\"\ninformation, which I think you should, you already should have it\nfor free.\n"},{"id":"218408","messageId":"CALkWK0mmJE3Q2WU3pmhWdcrxv=jFXb8oVhPCRW+Zc6yLdDmfUg@mail.gmail.com","threadId":"33911","inReplyTo":"7vehcw9s0k.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH 7/7] sha1_name: implement finding @{push}","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2013-05-24T18:21:32Z","receivedAt":"2013-05-24T18:21:32Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Junio C Hamano wrote:\n>>> rev-parse (with an option, maybe) may be a better place for\n>>> this.\n>>\n>> Er, no.  I actually want things like diff @{p}..HEAD.  I want it to be\n>> a first-class revision, just like @{u}.\n>\n> I think Duy's suggestion makes perfect sense; rev-parse already has\n> a mechanism to expand @{u} to the full name, so if you are hooking\n> into the same codepath as @{u} to implement the \"I publish there\"\n> information, which I think you should, you already should have it\n> for free.\n\n*scratches head*\n\nOkay, I'm not understanding this.  I've implemented @{push} as a\nrevision, so all callers who know how to get_sha1_basic() will be able\nto resolve this (including rev-parse).  Are you talking about\n--symbolic-full-name?  That just calls dwim_ref(), which calls\ninterpret_branch_name() anyway: except you get a symbolic name instead\nof the sha1.  Why do I have to think about rev-parse specifically in\nthis patch series?  rev-parse has no special logic for @{u} either.\n\nThe codepath that resolves @{u} is in interpret_branch_name(): it's\njust a matter of reading branch->merge[0]->dst; it's trivial to\ndetermine because read_config() just reads the configuration file and\nfills in these values when you get_branch().  How do I get \"I publish\nthere\" information for free?  Where is it contained?  In fact, it's so\ncomplicated to get that information that I had to break my head to\neven get this far (after mucking around in the transport layer);\nthat's what I'm trying to show in this series.  Unless I'm very badly\nmistaken, it's _impossible_ for any codepath in git to determine where\na push will go, except the one activated by invoking the builtin push.\n\nThe long-term impact of this series is not just @{push}, but that\nanyone else in git will be able to determine where a push is supposed\nto go.  Ultimately, it can lead to very heavy optimizations of the\ntransport_push() codepath (which is currently super-convoluted unless\nI'm missing something).\n"},{"id":"218411","messageId":"7vsj1c8a53.fsf@alter.siamese.dyndns.org","threadId":"33911","inReplyTo":"CALkWK0mmJE3Q2WU3pmhWdcrxv=jFXb8oVhPCRW+Zc6yLdDmfUg@mail.gmail.com","subject":"Re: [PATCH 7/7] sha1_name: implement finding @{push}","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-05-24T19:12:40Z","receivedAt":"2013-05-24T19:12:40Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ramkumar Ramachandra <artagnon@gmail.com> writes:\n\n> Junio C Hamano wrote:\n>>>> rev-parse (with an option, maybe) may be a better place for\n>>>> this.\n>>>\n>>> Er, no.  I actually want things like diff @{p}..HEAD.  I want it to be\n>>> a first-class revision, just like @{u}.\n>>\n>> I think Duy's suggestion makes perfect sense; rev-parse already has\n>> a mechanism to expand @{u} to the full name, so if you are hooking\n>> into the same codepath as @{u} to implement the \"I publish there\"\n>> information, which I think you should, you already should have it\n>> for free.\n>\n> *scratches head*\n>\n> Okay, I'm not understanding this.\n> ...  How do I get \"I publish\n> there\" information for free?\n\nThat is not what I said.\n\nLet's step back a bit and think what it means that @{u} can be used\nto name \"The latest, as best of my knowledge, of the possibly moving\nref that my work is based on\".  You can do so by\n\n (1) having a ref that points at such commit and having a mechanism\n     to keep the ref up to date;\n\n (2) having a mechansim to turn @{u} to such a ref; and\n\n (3) letting get_sha1() machinery to read from that ref when an\n     object name is needed for @{u}.\n\nNone of the above is what rev-parse does, but because you have (2),\nrev-parse --symbolic-full-name can just ask (2) for a refname.\n\nThat is what I meant by \"for free\", and \"which I think you should\"\nrefers to all of these three things you would do to keep track of\n\"The latest, as best of my knowledge, of the possibly moving ref\nthat points at the commit I pushed the last time\" for your @{p} in a\nway similar to how @{u} works.\n\nIf I understand correctly the discussion so far, for a given branch\nB, \"git push\" (no arguments to specify to which repository to push\nnor what branch to update) would decide what the user did not say by\nlooking at:\n\n    - branch.B.pushremote (and using remote.pushdefault and\n      branch.B.remote as fallbacks) to find what repository R to\n      push to;\n\n    - branch.B.push (or mapping B through remote.R.push refspecs as\n      a fallback logic) to find what destination branch D at R is\n      updated by B.\n\nThen after \"git push\" succeeds, it would look at remote.R.fetch\nrefspecs to pretend as if we fetched immediately from R, which is\nhow we keep track of the \"last pushed\" state, which is (1) of the\nnecessary three.\n\nIt follows that for B@{p} to be \"The last pushed\" for B, it has to\nresolve to a remote tracking branch for D from R.  That (i.e. find R\nand D and then map it through R's fetch refspec) is the logic we\nneed for (2).  That is very similar for B@{u}, which should be to\nfind the repository O it comes from by looking at branch.B.remote\n(or 'origin'), and then where branch.B.merge from O is stored in our\nref namespace (e.g. refs/remotes/origin/topic) by mapping it through\nthe remote.O.fetch refspec.\n\nOnce you have (2), the implementation of (3) is quite obvious.  We\nknow where in the codeflow @{u} is turned into a ref; we can do the\nsame for @{p} by calling the logic (2) from the same place to turn\n@{p} into a ref.\n\nIt is worth noting that @{p} has one error case that @{u} does not,\nwhose only error case is essentially that the branch you are asking\nfor @{u} does not have \"upstream\" configured.\n\nFor \"git push\" to work, you only need to be able to compute R and D\nfor B.  But R does not necessarily need to have fetch refspec for a\ntriangular pushing to work, hence we may not be recording what we\npushed the last time, violating (1), which in turn means (2) may not\nhave an answer.\n"}]}