{"thread":{"id":"35037","subject":"[PATCH v2 0/3] Juggling between hot branches","startedAt":"2013-09-28T02:59:18Z","lastAt":"2013-09-28T02:59:21Z","messageCount":4,"participants":["Ramkumar Ramachandra"],"isPatch":true,"patchVersion":2,"patchTotal":3},"messages":[{"id":"228340","messageId":"1380337161-803-1-git-send-email-artagnon@gmail.com","threadId":"35037","inReplyTo":null,"subject":"[PATCH v2 0/3] Juggling between hot branches","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2013-09-28T02:59:18Z","receivedAt":"2013-09-28T02:59:18Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Hi,\n\nThis iteration incorporates the suggestions made by Phil Hord.\n\nThanks.\n\nRamkumar Ramachandra (3):\n  for-each-ref: introduce %C(...) for color\n  for-each-ref: introduce %(HEAD) asterisk marker\n  for-each-ref: introduce %(upstream:track[short])\n\n Documentation/git-for-each-ref.txt | 14 ++++++-\n builtin/for-each-ref.c             | 75 ++++++++++++++++++++++++++++++++++----\n 2 files changed, 79 insertions(+), 10 deletions(-)\n\n-- \n1.8.4.477.g4cae6f5\n"},{"id":"228342","messageId":"1380337161-803-2-git-send-email-artagnon@gmail.com","threadId":"35037","inReplyTo":"1380337161-803-1-git-send-email-artagnon@gmail.com","subject":"[PATCH v2 1/3] for-each-ref: introduce %C(...) for color","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2013-09-28T02:59:19Z","receivedAt":"2013-09-28T02:59:19Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Enhance 'git for-each-ref' with color formatting options.  You can now\nuse the following format in for-each-ref:\n\n  %C(green)%(refname:short)%C(reset)\n\nSigned-off-by: Ramkumar Ramachandra <artagnon@gmail.com>\n---\n Documentation/git-for-each-ref.txt |  4 +++-\n builtin/for-each-ref.c             | 23 +++++++++++++++++++----\n 2 files changed, 22 insertions(+), 5 deletions(-)\n\ndiff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt\nindex f2e08d1..6fa4464 100644\n--- a/Documentation/git-for-each-ref.txt\n+++ b/Documentation/git-for-each-ref.txt\n@@ -45,7 +45,9 @@ OPTIONS\n \tIt also interpolates `%%` to `%`, and `%xx` where `xx`\n \tare hex digits interpolates to character with hex code\n \t`xx`; for example `%00` interpolates to `\\0` (NUL),\n-\t`%09` to `\\t` (TAB) and `%0a` to `\\n` (LF).\n+\t`%09` to `\\t` (TAB) and `%0a` to `\\n` (LF). Additionally,\n+\tcolors can be specified using `%C(...)`, with names\n+\tdescribed in color.branch.*.\n \n <pattern>...::\n \tIf one or more patterns are given, only refs are shown that\ndiff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c\nindex 1d4083c..6da2903 100644\n--- a/builtin/for-each-ref.c\n+++ b/builtin/for-each-ref.c\n@@ -9,6 +9,7 @@\n #include \"quote.h\"\n #include \"parse-options.h\"\n #include \"remote.h\"\n+#include \"color.h\"\n \n /* Quoting styles */\n #define QUOTE_NONE 0\n@@ -155,10 +156,13 @@ static const char *find_next(const char *cp)\n \twhile (*cp) {\n \t\tif (*cp == '%') {\n \t\t\t/*\n+\t\t\t * %C( is the start of a color;\n \t\t\t * %( is the start of an atom;\n \t\t\t * %% is a quoted per-cent.\n \t\t\t */\n-\t\t\tif (cp[1] == '(')\n+\t\t\tif (cp[1] == 'C' && cp[2] == '(')\n+\t\t\t\treturn cp;\n+\t\t\telse if (cp[1] == '(')\n \t\t\t\treturn cp;\n \t\t\telse if (cp[1] == '%')\n \t\t\t\tcp++; /* skip over two % */\n@@ -180,8 +184,11 @@ static int verify_format(const char *format)\n \t\tconst char *ep = strchr(sp, ')');\n \t\tif (!ep)\n \t\t\treturn error(\"malformed format string %s\", sp);\n-\t\t/* sp points at \"%(\" and ep points at the closing \")\" */\n-\t\tparse_atom(sp + 2, ep);\n+\t\t/* Ignore color specifications: %C(\n+\t\t * sp points at \"%(\" and ep points at the closing \")\"\n+\t\t */\n+\t\tif (prefixcmp(sp, \"%C(\"))\n+\t\t\tparse_atom(sp + 2, ep);\n \t\tcp = ep + 1;\n \t}\n \treturn 0;\n@@ -933,12 +940,20 @@ static void emit(const char *cp, const char *ep)\n static void show_ref(struct refinfo *info, const char *format, int quote_style)\n {\n \tconst char *cp, *sp, *ep;\n+\tchar color[COLOR_MAXLEN] = \"\";\n \n \tfor (cp = format; *cp && (sp = find_next(cp)); cp = ep + 1) {\n \t\tep = strchr(sp, ')');\n \t\tif (cp < sp)\n \t\t\temit(cp, sp);\n-\t\tprint_value(info, parse_atom(sp + 2, ep), quote_style);\n+\n+\t\t/* Do we have a color specification? */\n+\t\tif (!prefixcmp(sp, \"%C(\"))\n+\t\t\tcolor_parse_mem(sp + 3, ep - sp - 3, \"--format\", color);\n+\t\telse {\n+\t\t\tprintf(\"%s\", color);\n+\t\t\tprint_value(info, parse_atom(sp + 2, ep), quote_style);\n+\t\t}\n \t}\n \tif (*cp) {\n \t\tsp = cp + strlen(cp);\n-- \n1.8.4.477.g4cae6f5\n"},{"id":"228341","messageId":"1380337161-803-3-git-send-email-artagnon@gmail.com","threadId":"35037","inReplyTo":"1380337161-803-1-git-send-email-artagnon@gmail.com","subject":"[PATCH v2 2/3] for-each-ref: introduce %(HEAD) asterisk marker","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2013-09-28T02:59:20Z","receivedAt":"2013-09-28T02:59:20Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"'git branch' shows which branch you are currently on with an '*', but\n'git for-each-ref' misses this feature.  So, extend its format with\n%(HEAD) for the same effect.\n\nNow you can use the following format in for-each-ref:\n\n  %C(red)%(HEAD)%C(reset) %(refname:short)\n\nto display a red asterisk next to the current ref.\n\nSigned-off-by: Ramkumar Ramachandra <artagnon@gmail.com>\n---\n Documentation/git-for-each-ref.txt |  4 ++++\n builtin/for-each-ref.c             | 13 +++++++++++--\n 2 files changed, 15 insertions(+), 2 deletions(-)\n\ndiff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt\nindex 6fa4464..bb9c4c1 100644\n--- a/Documentation/git-for-each-ref.txt\n+++ b/Documentation/git-for-each-ref.txt\n@@ -95,6 +95,10 @@ upstream::\n \tfrom the displayed ref. Respects `:short` in the same way as\n \t`refname` above.\n \n+HEAD::\n+\tUsed to indicate the currently checked out branch.  Is '*' if\n+\tHEAD points to the current ref, and ' ' otherwise.\n+\n In addition to the above, for commit and tag objects, the header\n field names (`tree`, `parent`, `object`, `type`, and `tag`) can\n be used to specify the value in the header field.\ndiff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c\nindex 6da2903..b841545 100644\n--- a/builtin/for-each-ref.c\n+++ b/builtin/for-each-ref.c\n@@ -76,6 +76,7 @@ static struct {\n \t{ \"upstream\" },\n \t{ \"symref\" },\n \t{ \"flag\" },\n+\t{ \"HEAD\" },\n };\n \n /*\n@@ -682,8 +683,16 @@ static void populate_value(struct refinfo *ref)\n \t\t\t\tv->s = xstrdup(buf + 1);\n \t\t\t}\n \t\t\tcontinue;\n-\t\t}\n-\t\telse\n+\t\t} else if (!strcmp(name, \"HEAD\")) {\n+\t\t\tconst char *head;\n+\t\t\tunsigned char sha1[20];\n+\t\t\thead = resolve_ref_unsafe(\"HEAD\", sha1, 1, NULL);\n+\t\t\tif (!strcmp(ref->refname, head))\n+\t\t\t\tv->s = \"*\";\n+\t\t\telse\n+\t\t\t\tv->s = \" \";\n+\t\t\tcontinue;\n+\t\t} else\n \t\t\tcontinue;\n \n \t\tformatp = strchr(name, ':');\n-- \n1.8.4.477.g4cae6f5\n"},{"id":"228343","messageId":"1380337161-803-4-git-send-email-artagnon@gmail.com","threadId":"35037","inReplyTo":"1380337161-803-1-git-send-email-artagnon@gmail.com","subject":"[PATCH v2 3/3] for-each-ref: introduce %(upstream:track[short])","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2013-09-28T02:59:21Z","receivedAt":"2013-09-28T02:59:21Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Introduce %(upstream:track) to display \"[ahead M, behind N]\" and\n%(upstream:trackshort) to display \"=\", \">\", \"<\", or \"<>\"\nappropriately (inspired by contrib/completion/git-prompt.sh).\n\nNow you can use the following format in for-each-ref:\n\n  %C(green)%(refname:short)%C(reset)%(upstream:trackshort)\n\nto display refs with terse tracking information.\n\nNote that :track and :trackshort only work with \"upstream\", and error\nout when used with anything else.\n\nSigned-off-by: Ramkumar Ramachandra <artagnon@gmail.com>\n---\n Documentation/git-for-each-ref.txt |  6 +++++-\n builtin/for-each-ref.c             | 39 ++++++++++++++++++++++++++++++++++++--\n 2 files changed, 42 insertions(+), 3 deletions(-)\n\ndiff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt\nindex bb9c4c1..3ef6aa8 100644\n--- a/Documentation/git-for-each-ref.txt\n+++ b/Documentation/git-for-each-ref.txt\n@@ -93,7 +93,11 @@ objectname::\n upstream::\n \tThe name of a local ref which can be considered ``upstream''\n \tfrom the displayed ref. Respects `:short` in the same way as\n-\t`refname` above.\n+\t`refname` above.  Additionally respects `:track` to show\n+\t\"[ahead N, behind M]\" and `:trackshort` to show the terse\n+\tversion (like the prompt) \">\", \"<\", \"<>\", or \"=\".  Has no\n+\teffect if the ref does not have tracking information\n+\tassociated with it.\n \n HEAD::\n \tUsed to indicate the currently checked out branch.  Is '*' if\ndiff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c\nindex b841545..7d5c174 100644\n--- a/builtin/for-each-ref.c\n+++ b/builtin/for-each-ref.c\n@@ -648,6 +648,7 @@ static void populate_value(struct refinfo *ref)\n \t\tint deref = 0;\n \t\tconst char *refname;\n \t\tconst char *formatp;\n+\t\tstruct branch *branch;\n \n \t\tif (*name == '*') {\n \t\t\tderef = 1;\n@@ -659,7 +660,6 @@ static void populate_value(struct refinfo *ref)\n \t\telse if (!prefixcmp(name, \"symref\"))\n \t\t\trefname = ref->symref ? ref->symref : \"\";\n \t\telse if (!prefixcmp(name, \"upstream\")) {\n-\t\t\tstruct branch *branch;\n \t\t\t/* only local branches may have an upstream */\n \t\t\tif (prefixcmp(ref->refname, \"refs/heads/\"))\n \t\t\t\tcontinue;\n@@ -686,6 +686,7 @@ static void populate_value(struct refinfo *ref)\n \t\t} else if (!strcmp(name, \"HEAD\")) {\n \t\t\tconst char *head;\n \t\t\tunsigned char sha1[20];\n+\n \t\t\thead = resolve_ref_unsafe(\"HEAD\", sha1, 1, NULL);\n \t\t\tif (!strcmp(ref->refname, head))\n \t\t\t\tv->s = \"*\";\n@@ -698,11 +699,45 @@ static void populate_value(struct refinfo *ref)\n \t\tformatp = strchr(name, ':');\n \t\t/* look for \"short\" refname format */\n \t\tif (formatp) {\n+\t\t\tint num_ours, num_theirs;\n+\n \t\t\tformatp++;\n \t\t\tif (!strcmp(formatp, \"short\"))\n \t\t\t\trefname = shorten_unambiguous_ref(refname,\n \t\t\t\t\t\t      warn_ambiguous_refs);\n-\t\t\telse\n+\t\t\telse if (!strcmp(formatp, \"track\") &&\n+\t\t\t\t!prefixcmp(name, \"upstream\")) {\n+\t\t\t\tchar buf[40];\n+\n+\t\t\t\tstat_tracking_info(branch, &num_ours, &num_theirs);\n+\t\t\t\tif (!num_ours && !num_theirs)\n+\t\t\t\t\tv->s = \"\";\n+\t\t\t\telse if (!num_ours) {\n+\t\t\t\t\tsprintf(buf, \"[behind %d]\", num_theirs);\n+\t\t\t\t\tv->s = xstrdup(buf);\n+\t\t\t\t} else if (!num_theirs) {\n+\t\t\t\t\tsprintf(buf, \"[ahead %d]\", num_ours);\n+\t\t\t\t\tv->s = xstrdup(buf);\n+\t\t\t\t} else {\n+\t\t\t\t\tsprintf(buf, \"[ahead %d, behind %d]\",\n+\t\t\t\t\t\tnum_ours, num_theirs);\n+\t\t\t\t\tv->s = xstrdup(buf);\n+\t\t\t\t}\n+\t\t\t\tcontinue;\n+\t\t\t} else if (!strcmp(formatp, \"trackshort\") &&\n+\t\t\t\t!prefixcmp(name, \"upstream\")) {\n+\n+\t\t\t\tstat_tracking_info(branch, &num_ours, &num_theirs);\n+\t\t\t\tif (!num_ours && !num_theirs)\n+\t\t\t\t\tv->s = \"=\";\n+\t\t\t\telse if (!num_ours)\n+\t\t\t\t\tv->s = \"<\";\n+\t\t\t\telse if (!num_theirs)\n+\t\t\t\t\tv->s = \">\";\n+\t\t\t\telse\n+\t\t\t\t\tv->s = \"<>\";\n+\t\t\t\tcontinue;\n+\t\t\t} else\n \t\t\t\tdie(\"unknown %.*s format %s\",\n \t\t\t\t    (int)(formatp - name), name, formatp);\n \t\t}\n-- \n1.8.4.477.g4cae6f5\n"}]}