{"thread":{"id":"25031","subject":"[PATCH] sha1_name: allow to add @{...} alias via config","startedAt":"2010-09-08T04:04:01Z","lastAt":"2010-09-08T10:12:49Z","messageCount":5,"participants":["Nguyễn Thái Ngọc Duy","Santi Béjar","Nguyen Thai Ngoc Duy"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"150274","messageId":"1283918641-3662-1-git-send-email-pclouds@gmail.com","threadId":"25031","inReplyTo":null,"subject":"[PATCH] sha1_name: allow to add @{...} alias via config","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2010-09-08T04:04:01Z","receivedAt":"2010-09-08T04:04:01Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This allows users to add new @{..} alias via ref-at.* config\nvariables. The rewrite rule is printf-alike.\n\nMy itch is I usually work on a topic and only want to see commits in\nthat topic. So I make a tag to the topic's base, then do\n\ngit log base/my-topic..\n\nThat is a lot of keystrokes, and my mind is small enough sometimes I\ndon't even remember the topic name, stucking at \"base/  what?\"\n\nNow I have \"ref-at.base = base/%(tip)\" in my gitconfig and I only need\nto do \"git log @{base}..\".\n\nThis is probably not the best way to do though. Any advice?\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n cache.h     |    3 ++\n config.c    |    3 ++\n sha1_name.c |  100 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++---\n 3 files changed, 101 insertions(+), 5 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex be02a42..bad577d 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1112,4 +1112,7 @@ extern struct startup_info *startup_info;\n /* builtin/merge.c */\n int checkout_fast_forward(const unsigned char *from, const unsigned char *to);\n \n+/* sha1_name.c */\n+extern int git_ref_at_config(const char *var, const char *value);\n+\n #endif /* CACHE_H */\ndiff --git a/config.c b/config.c\nindex cdcf583..b560f51 100644\n--- a/config.c\n+++ b/config.c\n@@ -720,6 +720,9 @@ int git_default_config(const char *var, const char *value, void *dummy)\n \tif (!prefixcmp(var, \"advice.\"))\n \t\treturn git_default_advice_config(var, value);\n \n+\tif (!strncmp(var, \"ref-at.\", 7))\n+\t\treturn git_ref_at_config(var, value);\n+\n \tif (!strcmp(var, \"pager.color\") || !strcmp(var, \"color.pager\")) {\n \t\tpager_use_color = git_config_bool(var,value);\n \t\treturn 0;\ndiff --git a/sha1_name.c b/sha1_name.c\nindex 7b7e617..c9987f4 100644\n--- a/sha1_name.c\n+++ b/sha1_name.c\n@@ -7,6 +7,84 @@\n #include \"refs.h\"\n #include \"remote.h\"\n \n+struct ref_at {\n+\tconst char *mark;\n+\tconst char *format;\n+};\n+\n+static struct ref_at *ref_at;\n+static int ref_at_nr;\n+\n+int git_ref_at_config(const char *var, const char *value)\n+{\n+\tref_at_nr++;\n+\tref_at = xrealloc(ref_at, sizeof(*ref_at)*ref_at_nr);\n+\tref_at[ref_at_nr-1].mark = xstrdup(var+7); /* ref-at. */\n+\tref_at[ref_at_nr-1].format = xstrdup(value);\n+\treturn 0;\n+}\n+\n+static int substitute_ref_at(struct strbuf *sb, const char *name)\n+{\n+\tint i;\n+\tconst char *at = strchr(name, '@');\n+\tconst char *p, *p2;\n+\n+\tif (!at || at[1] != '{')\n+\t\treturn -1;\n+\tfor (i = 0; i < ref_at_nr; i++) {\n+\t\tint len = strlen(ref_at[i].mark);\n+\t\tif (!(at[len+2] == '}' && !strncmp(at+2, ref_at[i].mark, len)))\n+\t\t\tcontinue;\n+\n+\t\tp = ref_at[i].format;\n+\t\twhile (*p) {\n+\t\t\tif (*p != '%') {\n+\t\t\t\tstrbuf_addch(sb, *p);\n+\t\t\t\tp++;\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\t\t\tif (p[1] == '%') {\n+\t\t\t\tstrbuf_addch(sb, '%');\n+\t\t\t\tp += 2;\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\t\t\tif (p[1] != '(') {\n+\t\t\t\terror(\"ref-at.%s: '%%%c' not supported\", ref_at[i].mark, p[1]);\n+\t\t\t\treturn -1;\n+\t\t\t}\n+\t\t\tp += 2;\n+\t\t\tp2 = strchr(p, ')');\n+\t\t\tif (!p2)\n+\t\t\t\treturn -1;\n+\t\t\tif (!strncmp(p, \"branch\", p2-p)) {\n+\t\t\t\tstrbuf_add(sb, name, at-name);\n+\t\t\t\tp = p2+1;\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\t\t\tif (!strncmp(p, \"tip\", p2-p)) {\n+\t\t\t\tif (at == name || !strncmp(name, \"HEAD\", at-name)) {\n+\t\t\t\t\tunsigned char sha1[20];\n+\t\t\t\t\tint flag;\n+\t\t\t\t\tconst char *real_ref = resolve_ref(\"HEAD\", sha1, 0, &flag);\n+\t\t\t\t\tif (!strncmp(real_ref, \"refs/heads/\", 11))\n+\t\t\t\t\t\tstrbuf_addstr(sb, real_ref+11);\n+\t\t\t\t\telse\n+\t\t\t\t\t\tstrbuf_addstr(sb, real_ref);\n+\t\t\t\t}\n+\t\t\t\telse\n+\t\t\t\t\tstrbuf_add(sb, name, p2-p);\n+\t\t\t\tp = p2+1;\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\t\t\terror(\"ref-at.%s: '%%(%.*s)' is not supported\", ref_at[i].mark, p2-p, p);\n+\t\t\treturn -1;\n+\t\t}\n+\t\treturn 1;\n+\t}\n+\treturn 0;\n+}\n+\n static int find_short_object_filename(int len, const char *name, unsigned char *sha1)\n {\n \tstruct alternate_object_database *alt;\n@@ -346,6 +424,7 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1)\n \tchar *real_ref = NULL;\n \tint refs_found = 0;\n \tint at, reflog_len;\n+\tstruct strbuf new_str = STRBUF_INIT;\n \n \tif (len == 40 && !get_sha1_hex(str, sha1))\n \t\treturn 0;\n@@ -355,6 +434,11 @@ 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 (substitute_ref_at(&new_str, str) >= 0) {\n+\t\t\t\t\tstr = new_str.buf;\n+\t\t\t\t\tlen = new_str.len;\n+\t\t\t\t\tbreak;\n+\t\t\t\t}\n \t\t\t\tif (!upstream_mark(str + at, len - at)) {\n \t\t\t\t\treflog_len = (len-1) - (at+2);\n \t\t\t\t\tlen = at;\n@@ -366,7 +450,7 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1)\n \n \t/* Accept only unambiguous ref paths. */\n \tif (len && ambiguous_path(str, len))\n-\t\treturn -1;\n+\t\tgoto failed;\n \n \tif (!len && reflog_len) {\n \t\tstruct strbuf buf = STRBUF_INIT;\n@@ -374,10 +458,11 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1)\n \t\t/* try the @{-N} syntax for n-th checkout */\n \t\tret = interpret_branch_name(str+at, &buf);\n \t\tif (ret > 0) {\n+\t\t\tstrbuf_release(&new_str);\n \t\t\t/* substitute this branch name and restart */\n \t\t\treturn get_sha1_1(buf.buf, buf.len, sha1);\n \t\t} else if (ret == 0) {\n-\t\t\treturn -1;\n+\t\t\tgoto failed;\n \t\t}\n \t\t/* allow \"@{...}\" to mean the current branch reflog */\n \t\trefs_found = dwim_ref(\"HEAD\", 4, sha1, &real_ref);\n@@ -387,7 +472,7 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1)\n \t\trefs_found = dwim_ref(str, len, sha1, &real_ref);\n \n \tif (!refs_found)\n-\t\treturn -1;\n+\t\tgoto failed;\n \n \tif (warn_ambiguous_refs && refs_found > 1)\n \t\twarning(warn_msg, len, str);\n@@ -400,7 +485,7 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1)\n \n \t\t/* a @{-N} placed anywhere except the start is an error */\n \t\tif (str[at+2] == '-')\n-\t\t\treturn -1;\n+\t\t\tgoto failed;\n \n \t\t/* Is it asking for N-th entry, or approxidate? */\n \t\tfor (i = nth = 0; 0 <= nth && i < reflog_len; i++) {\n@@ -421,7 +506,7 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1)\n \t\t\tat_time = approxidate_careful(tmp, &errors);\n \t\t\tfree(tmp);\n \t\t\tif (errors)\n-\t\t\t\treturn -1;\n+\t\t\t\tgoto failed;\n \t\t}\n \t\tif (read_ref_at(real_ref, at_time, nth, sha1, NULL,\n \t\t\t\t&co_time, &co_tz, &co_cnt)) {\n@@ -438,7 +523,12 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1)\n \t}\n \n \tfree(real_ref);\n+\tstrbuf_release(&new_str);\n \treturn 0;\n+\n+failed:\n+\tstrbuf_release(&new_str);\n+\treturn -1;\n }\n \n static int get_parent(const char *name, int len,\n-- \n1.7.1.rc1.69.g24c2f7\n"},{"id":"150286","messageId":"AANLkTimK6MwJHYafAAYNn+h3HD1f0H-BHsQYph4qbCrJ@mail.gmail.com","threadId":"25031","inReplyTo":"1283918641-3662-1-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH] sha1_name: allow to add @{...} alias via config","fromName":"Santi Béjar","fromEmail":"santi@agolina.net","sentAt":"2010-09-08T09:45:29Z","receivedAt":"2010-09-08T09:45:29Z","isPatch":true,"sender":{"key":"santi@agolina.net","avatar":null},"body":"2010/9/8 Nguyễn Thái Ngọc Duy <pclouds@gmail.com>:\n> This allows users to add new @{..} alias via ref-at.* config\n> variables. The rewrite rule is printf-alike.\n>\n> My itch is I usually work on a topic and only want to see commits in\n> that topic. So I make a tag to the topic's base, then do\n>\n> git log base/my-topic..\n>\n> That is a lot of keystrokes, and my mind is small enough sometimes I\n> don't even remember the topic name, stucking at \"base/  what?\"\n>\n> Now I have \"ref-at.base = base/%(tip)\" in my gitconfig and I only need\n> to do \"git log @{base}..\".\n\nI like the idea, but I would like something more generic, a ref\ntransformation or expression (ref-exp?). Currently you can't say\n%(tip)@{1}, neither %(tip)^, nor origin/master..origin/%(tip).\n\nAnother issue is that it can shadow builtin @{}s, like @{upstream}.\n\nWhy %(tip) and not %(branchname), in line with other %() modifiers.\n\nIn particular I have a use case for this @{name}. I would like something like:\n\nref-exp.last = %(tip)@{1}..%(tip)@{0}\n\nso I could do:\n\ngit log @{last}\ngit log origin/master@{last}\n\nAlthough another way to get it could be:\n\ngit log @{1..0}\ngit log origin/master@{1..0}\n\nThanks,\nSanti\n"},{"id":"150287","messageId":"AANLkTin83BQ0YhWHuDqkY4HYWP9+bUso1BDNbFtRskDp@mail.gmail.com","threadId":"25031","inReplyTo":"AANLkTimK6MwJHYafAAYNn+h3HD1f0H-BHsQYph4qbCrJ@mail.gmail.com","subject":"Re: [PATCH] sha1_name: allow to add @{...} alias via config","fromName":"Santi Béjar","fromEmail":"santi@agolina.net","sentAt":"2010-09-08T09:53:53Z","receivedAt":"2010-09-08T09:53:53Z","isPatch":true,"sender":{"key":"santi@agolina.net","avatar":null},"body":"2010/9/8 Santi Béjar <santi@agolina.net>:\n> 2010/9/8 Nguyễn Thái Ngọc Duy <pclouds@gmail.com>:\n>> This allows users to add new @{..} alias via ref-at.* config\n>> variables. The rewrite rule is printf-alike.\n>\n> Another issue is that it can shadow builtin @{}s, like @{upstream}.\n\nIn fact this patch breaks @{upstream}.\n\nSanti\n"},{"id":"150289","messageId":"AANLkTiknnbijQuL4RzPR7R9O6ra079eH6N_KOM-UHRKE@mail.gmail.com","threadId":"25031","inReplyTo":"AANLkTimK6MwJHYafAAYNn+h3HD1f0H-BHsQYph4qbCrJ@mail.gmail.com","subject":"Re: [PATCH] sha1_name: allow to add @{...} alias via config","fromName":"Nguyen Thai Ngoc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2010-09-08T10:11:19Z","receivedAt":"2010-09-08T10:11:19Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"2010/9/8 Santi Béjar <santi@agolina.net>:\n> 2010/9/8 Nguyễn Thái Ngọc Duy <pclouds@gmail.com>:\n>> This allows users to add new @{..} alias via ref-at.* config\n>> variables. The rewrite rule is printf-alike.\n>>\n>> My itch is I usually work on a topic and only want to see commits in\n>> that topic. So I make a tag to the topic's base, then do\n>>\n>> git log base/my-topic..\n>>\n>> That is a lot of keystrokes, and my mind is small enough sometimes I\n>> don't even remember the topic name, stucking at \"base/  what?\"\n>>\n>> Now I have \"ref-at.base = base/%(tip)\" in my gitconfig and I only need\n>> to do \"git log @{base}..\".\n>\n> I like the idea, but I would like something more generic, a ref\n> transformation or expression (ref-exp?). Currently you can't say\n> %(tip)@{1}, neither %(tip)^, nor origin/master..origin/%(tip).\n\nThe idea is to nail down what kind of expression that should be used.\nThen implement it. My first thought was to use a hook, but I thought\nit was overkill for ref transformation.\n\nSomething like bash variable substitution is probably enough.\n\n> Another issue is that it can shadow builtin @{}s, like @{upstream}.\n\nYes. I think @{upstream} can be put in to ref-transformation list at\nstartup. That way it always gets precedence.\n\n> Why %(tip) and not %(branchname), in line with other %() modifiers.\n\nOh.. I picked whatever name I had in my mind. @(branchname) of @(branch)\nsounds good.\n\n> In particular I have a use case for this @{name}. I would like something like:\n>\n> ref-exp.last = %(tip)@{1}..%(tip)@{0}\n\nYeah I was tempted too after writing the patch. It's a revision range,\nnot a reference anymore. But from user perspective it's pretty much\nthe same. And transformation rule would be the same. Hmm.. tempting.\n-- \nDuy\n"},{"id":"150290","messageId":"AANLkTimR35gKwXg9Ve5y2SqaxyxcM410h3p=eM9cHWY2@mail.gmail.com","threadId":"25031","inReplyTo":"AANLkTin83BQ0YhWHuDqkY4HYWP9+bUso1BDNbFtRskDp@mail.gmail.com","subject":"Re: [PATCH] sha1_name: allow to add @{...} alias via config","fromName":"Nguyen Thai Ngoc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2010-09-08T10:12:49Z","receivedAt":"2010-09-08T10:12:49Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"2010/9/8 Santi Béjar <santi@agolina.net>:\n> 2010/9/8 Santi Béjar <santi@agolina.net>:\n>> 2010/9/8 Nguyễn Thái Ngọc Duy <pclouds@gmail.com>:\n>>> This allows users to add new @{..} alias via ref-at.* config\n>>> variables. The rewrite rule is printf-alike.\n>>\n>> Another issue is that it can shadow builtin @{}s, like @{upstream}.\n>\n> In fact this patch breaks @{upstream}.\n\nMy fault. There should not be an equal in\n\nif (substitute_ref_at(&new_str, str) >= 0)\n-- \nDuy\n"}]}