{"thread":{"id":"41875","subject":"[PATCH v3 02/16] ref-filter: include reference to 'used_atom' within 'atom_value'","startedAt":"2016-03-30T09:39:44Z","lastAt":"2016-04-04T16:12:40Z","messageCount":31,"participants":["Karthik Nayak","Junio C Hamano","Dennis Kaarsemaker","Ramsay Jones","Matthieu Moy"],"isPatch":true,"patchVersion":3,"patchTotal":16},"messages":[{"id":"282222","messageId":"1459330800-12525-1-git-send-email-Karthik.188@gmail.com","threadId":"41875","inReplyTo":null,"subject":"[PATCH v3 00/16] port branch.c to use ref-filter's printing options","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2016-03-30T09:39:44Z","receivedAt":"2016-03-30T09:39:44Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"I kinda waited before sending this, since there was lot of discussions\nhappening regarding to GSOC16, didn't want to clutter the mailing list.\n\nThis is part of unification of the commands 'git tag -l, git branch -l\nand git for-each-ref'. This ports over branch.c to use ref-filter's\nprinting options.\n\nInitially posted here: $(gmane/279226). It was decided that this series\nwould follow up after refactoring ref-filter parsing mechanism, which\nis now merged into master (9606218b32344c5c756f7c29349d3845ef60b80c).\n\nv1 can be found here: $(gmane/288342)\nv2 can be found here: $(gmane/288863)\n\nChanges in this version:\n1. Only Documentation and commit message changes as suggested by\nJacob in v2.\n\nThanks to Jacob for his suggestions on the previous iteration.\n\nKarthik Nayak (16):\n  ref-filter: implement %(if), %(then), and %(else) atoms\n  ref-filter: include reference to 'used_atom' within 'atom_value'\n  ref-filter: implement %(if:equals=<string>) and\n    %(if:notequals=<string>)\n  ref-filter: modify \"%(objectname:short)\" to take length\n  ref-filter: move get_head_description() from branch.c\n  ref-filter: introduce format_ref_array_item()\n  ref-filter: make %(upstream:track) prints \"[gone]\" for invalid\n    upstreams\n  ref-filter: add support for %(upstream:track,nobracket)\n  ref-filter: make \"%(symref)\" atom work with the ':short' modifier\n  ref-filter: introduce symref_atom_parser()\n  ref-filter: introduce refname_atom_parser()\n  ref-filter: add support for %(refname:dir) and %(refname:base)\n  ref-filter: allow porcelain to translate messages in the output\n  branch, tag: use porcelain output\n  branch: use ref-filter printing APIs\n  branch: implement '--format' option\n\n Documentation/git-branch.txt       |   7 +-\n Documentation/git-for-each-ref.txt |  63 +++++-\n builtin/branch.c                   | 267 ++++++----------------\n builtin/tag.c                      |   2 +\n ref-filter.c                       | 447 +++++++++++++++++++++++++++++++------\n ref-filter.h                       |   7 +\n t/t3203-branch-output.sh           |  12 +\n t/t6040-tracking-info.sh           |   2 +-\n t/t6300-for-each-ref.sh            |  40 +++-\n t/t6302-for-each-ref-filter.sh     |  88 ++++++++\n 10 files changed, 657 insertions(+), 278 deletions(-)\n\nInterdiff:\n\ndiff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt\nindex 0d7d80f..578bbd1 100644\n--- a/Documentation/git-for-each-ref.txt\n+++ b/Documentation/git-for-each-ref.txt\n@@ -109,10 +109,6 @@ objectsize::\n objectname::\n        The object name (aka SHA-1).\n        For a non-ambiguous abbreviation of the object name append `:short`.\n-       For an abbreviation of the object name with desired length append\n-       `:short=<length>`, where the minimum length is MINIMUM_ABBREV. The\n-       length may be exceeded to ensure unique object names.\n-\n \n upstream::\n        The name of a local ref which can be considered ``upstream''\n@@ -120,11 +116,12 @@ upstream::\n        `refname` above.  Additionally respects `:track` to show\n        \"[ahead N, behind M]\" and `:trackshort` to show the terse\n        version: \">\" (ahead), \"<\" (behind), \"<>\" (ahead and behind),\n-       or \"=\" (in sync). `:track` also prints \"[gone]\" whenever\n-       unknown upstream ref is encountered. Append `:track,nobracket`\n-       to show tracking information without brackets (i.e \"ahead N,\n-       behind M\").  Has no effect if the ref does not have tracking\n-       information associated with it.\n+       or \"=\" (in sync).  Has no effect if the ref does not have\n+       tracking information associated with it. `:track` also prints\n+       \"[gone]\" whenever unknown upstream ref is encountered. Append\n+       `:track,nobracket` to show tracking information without\n+       brackets (i.e \"ahead N, behind M\").  Has no effect if the ref\n+       does not have tracking information associated with it.\n \n push::\n        The name of a local ref which represents the `@{push}` location\n\n-- \n2.7.4\n"},{"id":"282208","messageId":"1459330800-12525-2-git-send-email-Karthik.188@gmail.com","threadId":"41875","inReplyTo":"1459330800-12525-1-git-send-email-Karthik.188@gmail.com","subject":"[PATCH v3 01/16] ref-filter: implement %(if), %(then), and %(else) atoms","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2016-03-30T09:39:45Z","receivedAt":"2016-03-30T09:39:45Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"Implement %(if), %(then) and %(else) atoms. Used as\n%(if)...%(then)...%(end) or %(if)...%(then)...%(else)...%(end). If the\nformat string between %(if) and %(then) expands to an empty string, or\nto only whitespaces, then the whole %(if)...%(end) expands to the string\nfollowing %(then). Otherwise, it expands to the string following\n%(else), if any. Nesting of this construct is possible.\n\nThis is in preparation for porting over `git branch -l` to use\nref-filter APIs for printing.\n\nAdd Documentation and tests regarding the same.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>\nSigned-off-by: Karthik Nayak <karthik.188@gmail.com>\n---\n Documentation/git-for-each-ref.txt |  45 +++++++++++--\n ref-filter.c                       | 133 +++++++++++++++++++++++++++++++++++--\n t/t6302-for-each-ref-filter.sh     |  70 +++++++++++++++++++\n 3 files changed, 237 insertions(+), 11 deletions(-)\n\ndiff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt\nindex 012e8f9..d048561 100644\n--- a/Documentation/git-for-each-ref.txt\n+++ b/Documentation/git-for-each-ref.txt\n@@ -141,10 +141,17 @@ align::\n \t\"width=\" and/or \"position=\" prefixes may be omitted, and bare\n \t<width> and <position> used instead.  For instance,\n \t`%(align:<width>,<position>)`. If the contents length is more\n-\tthan the width then no alignment is performed. If used with\n-\t'--quote' everything in between %(align:...) and %(end) is\n-\tquoted, but if nested then only the topmost level performs\n-\tquoting.\n+\tthan the width then no alignment is performed.\n+\n+if::\n+\tUsed as %(if)...%(then)...(%end) or\n+\t%(if)...%(then)...%(else)...%(end).  If there is an atom with\n+\tvalue or string literal after the %(if) then everything after\n+\tthe %(then) is printed, else if the %(else) atom is used, then\n+\teverything after %(else) is printed. We ignore space when\n+\tevaluating the string before %(then), this is useful when we\n+\tuse the %(HEAD) atom which prints either \"*\" or \" \" and we\n+\twant to apply the 'if' condition only on the 'HEAD' ref.\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@@ -181,6 +188,20 @@ As a special case for the date-type fields, you may specify a format for\n the date by adding `:` followed by date format name (see the\n values the `--date` option to linkgit::git-rev-list[1] takes).\n \n+Some atoms like %(align) and %(if) always require a matching %(end).\n+We call them \"opening atoms\" and sometimes denote them as %($open).\n+\n+When a scripting language specific quoting is in effect (i.e. one of\n+`--shell`, `--perl`, `--python`, `--tcl` is used), except for opening\n+atoms, replacement from every %(atom) is quoted when and only when it\n+appears at the top-level (that is, when it appears outside\n+%($open)...%(end)).\n+\n+When a scripting language specific quoting is in effect, everything\n+between a top-level opening atom and its matching %(end) is evaluated\n+according to the semantics of the opening atom and its result is\n+quoted.\n+\n \n EXAMPLES\n --------\n@@ -268,6 +289,22 @@ eval=`git for-each-ref --shell --format=\"$fmt\" \\\n eval \"$eval\"\n ------------\n \n+\n+An example to show the usage of %(if)...%(then)...%(else)...%(end).\n+This prefixes the current branch with a star.\n+\n+------------\n+git for-each-ref --format=\"%(if)%(HEAD)%(then)* %(else)  %(end)%(refname:short)\" refs/heads/\n+------------\n+\n+\n+An example to show the usage of %(if)...%(then)...%(end).\n+This prints the authorname, if present.\n+\n+------------\n+git for-each-ref --format=\"%(refname)%(if)%(authorname)%(then) %(color:red)Authored by: %(authorname)%(end)\"\n+------------\n+\n SEE ALSO\n --------\n linkgit:git-show-ref[1]\ndiff --git a/ref-filter.c b/ref-filter.c\nindex bc551a7..41e73f0 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -21,6 +21,12 @@ struct align {\n \tunsigned int width;\n };\n \n+struct if_then_else {\n+\tunsigned int then_atom_seen : 1,\n+\t\telse_atom_seen : 1,\n+\t\tcondition_satisfied : 1;\n+};\n+\n /*\n  * An atom is a valid field atom listed below, possibly prefixed with\n  * a \"*\" to denote deref_tag().\n@@ -203,6 +209,9 @@ static struct {\n \t{ \"color\", FIELD_STR, color_atom_parser },\n \t{ \"align\", FIELD_STR, align_atom_parser },\n \t{ \"end\" },\n+\t{ \"if\" },\n+\t{ \"then\" },\n+\t{ \"else\" },\n };\n \n #define REF_FORMATTING_STATE_INIT  { 0, NULL }\n@@ -210,7 +219,7 @@ static struct {\n struct ref_formatting_stack {\n \tstruct ref_formatting_stack *prev;\n \tstruct strbuf output;\n-\tvoid (*at_end)(struct ref_formatting_stack *stack);\n+\tvoid (*at_end)(struct ref_formatting_stack **stack);\n \tvoid *at_end_data;\n };\n \n@@ -343,13 +352,14 @@ static void pop_stack_element(struct ref_formatting_stack **stack)\n \t*stack = prev;\n }\n \n-static void end_align_handler(struct ref_formatting_stack *stack)\n+static void end_align_handler(struct ref_formatting_stack **stack)\n {\n-\tstruct align *align = (struct align *)stack->at_end_data;\n+\tstruct ref_formatting_stack *cur = *stack;\n+\tstruct align *align = (struct align *)cur->at_end_data;\n \tstruct strbuf s = STRBUF_INIT;\n \n-\tstrbuf_utf8_align(&s, align->position, align->width, stack->output.buf);\n-\tstrbuf_swap(&stack->output, &s);\n+\tstrbuf_utf8_align(&s, align->position, align->width, cur->output.buf);\n+\tstrbuf_swap(&cur->output, &s);\n \tstrbuf_release(&s);\n }\n \n@@ -363,6 +373,103 @@ static void align_atom_handler(struct atom_value *atomv, struct ref_formatting_s\n \tnew->at_end_data = &atomv->u.align;\n }\n \n+static void if_then_else_handler(struct ref_formatting_stack **stack)\n+{\n+\tstruct ref_formatting_stack *cur = *stack;\n+\tstruct ref_formatting_stack *prev = cur->prev;\n+\tstruct if_then_else *if_then_else = (struct if_then_else *)cur->at_end_data;\n+\n+\tif (!if_then_else->then_atom_seen)\n+\t\tdie(_(\"format: %%(if) atom used without a %%(then) atom\"));\n+\n+\tif (if_then_else->else_atom_seen) {\n+\t\t/*\n+\t\t * There is an %(else) atom: we need to drop one state from the\n+\t\t * stack, either the %(else) branch if the condition is satisfied, or\n+\t\t * the %(then) branch if it isn't.\n+\t\t */\n+\t\tif (if_then_else->condition_satisfied) {\n+\t\t\tstrbuf_reset(&cur->output);\n+\t\t\tpop_stack_element(&cur);\n+\t\t} else {\n+\t\t\tstrbuf_swap(&cur->output, &prev->output);\n+\t\t\tstrbuf_reset(&cur->output);\n+\t\t\tpop_stack_element(&cur);\n+\t\t}\n+\t} else if (!if_then_else->condition_satisfied)\n+\t\t/*\n+\t\t * No %(else) atom: just drop the %(then) branch if the\n+\t\t * condition is not satisfied.\n+\t\t */\n+\t\tstrbuf_reset(&cur->output);\n+\n+\t*stack = cur;\n+\tfree(if_then_else);\n+}\n+\n+static void if_atom_handler(struct atom_value *atomv, struct ref_formatting_state *state)\n+{\n+\tstruct ref_formatting_stack *new;\n+\tstruct if_then_else *if_then_else = xcalloc(sizeof(struct if_then_else), 1);\n+\n+\tpush_stack_element(&state->stack);\n+\tnew = state->stack;\n+\tnew->at_end = if_then_else_handler;\n+\tnew->at_end_data = if_then_else;\n+}\n+\n+static int is_empty(const char *s)\n+{\n+\twhile (*s != '\\0') {\n+\t\tif (!isspace(*s))\n+\t\t\treturn 0;\n+\t\ts++;\n+\t}\n+\treturn 1;\n+}\n+\n+static void then_atom_handler(struct atom_value *atomv, struct ref_formatting_state *state)\n+{\n+\tstruct ref_formatting_stack *cur = state->stack;\n+\tstruct if_then_else *if_then_else = NULL;\n+\n+\tif (cur->at_end == if_then_else_handler)\n+\t\tif_then_else = (struct if_then_else *)cur->at_end_data;\n+\tif (!if_then_else)\n+\t\tdie(_(\"format: %%(then) atom used without an %%(if) atom\"));\n+\tif (if_then_else->then_atom_seen)\n+\t\tdie(_(\"format: %%(then) atom used more than once\"));\n+\tif (if_then_else->else_atom_seen)\n+\t\tdie(_(\"format: %%(then) atom used after %%(else)\"));\n+\tif_then_else->then_atom_seen = 1;\n+\t/*\n+\t * If there exists non-empty string between the 'if' and\n+\t * 'then' atom then the 'if' condition is satisfied.\n+\t */\n+\tif (cur->output.len && !is_empty(cur->output.buf))\n+\t\tif_then_else->condition_satisfied = 1;\n+\tstrbuf_reset(&cur->output);\n+}\n+\n+static void else_atom_handler(struct atom_value *atomv, struct ref_formatting_state *state)\n+{\n+\tstruct ref_formatting_stack *prev = state->stack;\n+\tstruct if_then_else *if_then_else = NULL;\n+\n+\tif (prev->at_end == if_then_else_handler)\n+\t\tif_then_else = (struct if_then_else *)prev->at_end_data;\n+\tif (!if_then_else)\n+\t\tdie(_(\"format: %%(else) atom used without an %%(if) atom\"));\n+\tif (!if_then_else->then_atom_seen)\n+\t\tdie(_(\"format: %%(else) atom used without a %%(then) atom\"));\n+\tif (if_then_else->else_atom_seen)\n+\t\tdie(_(\"format: %%(else) atom used more than once\"));\n+\tif_then_else->else_atom_seen = 1;\n+\tpush_stack_element(&state->stack);\n+\tstate->stack->at_end_data = prev->at_end_data;\n+\tstate->stack->at_end = prev->at_end;\n+}\n+\n static void end_atom_handler(struct atom_value *atomv, struct ref_formatting_state *state)\n {\n \tstruct ref_formatting_stack *current = state->stack;\n@@ -370,14 +477,17 @@ static void end_atom_handler(struct atom_value *atomv, struct ref_formatting_sta\n \n \tif (!current->at_end)\n \t\tdie(_(\"format: %%(end) atom used without corresponding atom\"));\n-\tcurrent->at_end(current);\n+\tcurrent->at_end(&state->stack);\n+\n+\t/*  Stack may have been popped within at_end(), hence reset the current pointer */\n+\tcurrent = state->stack;\n \n \t/*\n \t * Perform quote formatting when the stack element is that of\n \t * a supporting atom. If nested then perform quote formatting\n \t * only on the topmost supporting atom.\n \t */\n-\tif (!state->stack->prev->prev) {\n+\tif (!current->prev->prev) {\n \t\tquote_formatting(&s, current->output.buf, state->quote_style);\n \t\tstrbuf_swap(&current->output, &s);\n \t}\n@@ -1029,6 +1139,15 @@ static void populate_value(struct ref_array_item *ref)\n \t\t} else if (!strcmp(name, \"end\")) {\n \t\t\tv->handler = end_atom_handler;\n \t\t\tcontinue;\n+\t\t} else if (!strcmp(name, \"if\")) {\n+\t\t\tv->handler = if_atom_handler;\n+\t\t\tcontinue;\n+\t\t} else if (!strcmp(name, \"then\")) {\n+\t\t\tv->handler = then_atom_handler;\n+\t\t\tcontinue;\n+\t\t} else if (!strcmp(name, \"else\")) {\n+\t\t\tv->handler = else_atom_handler;\n+\t\t\tcontinue;\n \t\t} else\n \t\t\tcontinue;\n \ndiff --git a/t/t6302-for-each-ref-filter.sh b/t/t6302-for-each-ref-filter.sh\nindex bcf472b..954b12a 100755\n--- a/t/t6302-for-each-ref-filter.sh\n+++ b/t/t6302-for-each-ref-filter.sh\n@@ -297,4 +297,74 @@ test_expect_success 'reverse version sort' '\n \ttest_cmp expect actual\n '\n \n+test_expect_success 'improper usage of %(if), %(then), %(else) and %(end) atoms' '\n+\ttest_must_fail git for-each-ref --format=\"%(if)\" &&\n+\ttest_must_fail git for-each-ref --format=\"%(then) %(end)\" &&\n+\ttest_must_fail git for-each-ref --format=\"%(else) %(end)\" &&\n+\ttest_must_fail git for-each-ref --format=\"%(if) %(else) %(end)\" &&\n+\ttest_must_fail git for-each-ref --format=\"%(if) %(then) %(then) %(end)\" &&\n+\ttest_must_fail git for-each-ref --format=\"%(then) %(else) %(end)\" &&\n+\ttest_must_fail git for-each-ref --format=\"%(if) %(else) %(end)\" &&\n+\ttest_must_fail git for-each-ref --format=\"%(if) %(then) %(else)\" &&\n+\ttest_must_fail git for-each-ref --format=\"%(if) %(else) %(then) %(end)\" &&\n+\ttest_must_fail git for-each-ref --format=\"%(if) %(then) %(else) %(else) %(end)\" &&\n+\ttest_must_fail git for-each-ref --format=\"%(if) %(end)\"\n+'\n+\n+test_expect_success 'check %(if)...%(then)...%(end) atoms' '\n+\tgit for-each-ref --format=\"%(if)%(authorname)%(then)%(authorname): %(refname)%(end)\" >actual &&\n+\tcat >expect <<-\\EOF &&\n+\tA U Thor: refs/heads/master\n+\tA U Thor: refs/heads/side\n+\tA U Thor: refs/odd/spot\n+\t\n+\tA U Thor: refs/tags/foo1.10\n+\tA U Thor: refs/tags/foo1.3\n+\tA U Thor: refs/tags/foo1.6\n+\tA U Thor: refs/tags/four\n+\tA U Thor: refs/tags/one\n+\t\n+\tA U Thor: refs/tags/three\n+\tA U Thor: refs/tags/two\n+\tEOF\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success 'check %(if)...%(then)...%(else)...%(end) atoms' '\n+\tgit for-each-ref --format=\"%(if)%(authorname)%(then)%(authorname)%(else)No author%(end): %(refname)\" >actual &&\n+\tcat >expect <<-\\EOF &&\n+\tA U Thor: refs/heads/master\n+\tA U Thor: refs/heads/side\n+\tA U Thor: refs/odd/spot\n+\tNo author: refs/tags/double-tag\n+\tA U Thor: refs/tags/foo1.10\n+\tA U Thor: refs/tags/foo1.3\n+\tA U Thor: refs/tags/foo1.6\n+\tA U Thor: refs/tags/four\n+\tA U Thor: refs/tags/one\n+\tNo author: refs/tags/signed-tag\n+\tA U Thor: refs/tags/three\n+\tA U Thor: refs/tags/two\n+\tEOF\n+\ttest_cmp expect actual\n+'\n+test_expect_success 'ignore spaces in %(if) atom usage' '\n+\tgit for-each-ref --format=\"%(refname:short): %(if)%(HEAD)%(then)Head ref%(else)Not Head ref%(end)\" >actual &&\n+\tcat >expect <<-\\EOF &&\n+\tmaster: Head ref\n+\tside: Not Head ref\n+\todd/spot: Not Head ref\n+\tdouble-tag: Not Head ref\n+\tfoo1.10: Not Head ref\n+\tfoo1.3: Not Head ref\n+\tfoo1.6: Not Head ref\n+\tfour: Not Head ref\n+\tone: Not Head ref\n+\tsigned-tag: Not Head ref\n+\tthree: Not Head ref\n+\ttwo: Not Head ref\n+\tEOF\n+\ttest_cmp expect actual\n+'\n+\n test_done\n-- \n2.7.4\n"},{"id":"282206","messageId":"1459330800-12525-3-git-send-email-Karthik.188@gmail.com","threadId":"41875","inReplyTo":"1459330800-12525-1-git-send-email-Karthik.188@gmail.com","subject":"[PATCH v3 02/16] ref-filter: include reference to 'used_atom' within 'atom_value'","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2016-03-30T09:39:46Z","receivedAt":"2016-03-30T09:39:46Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"Ensure that each 'atom_value' has a reference to its corresponding\n'used_atom'. This let's us use values within 'used_atom' in the\n'handler' function.\n\nHence we can get the %(align) atom's parameters directly from the\n'used_atom' therefore removing the necessity of passing %(align) atom's\nparameters to 'atom_value'.\n\nThis also acts as a preparatory patch for the upcoming patch where we\nintroduce %(if:equals=) and %(if:notequals=).\n\nSigned-off-by: Karthik Nayak <Karthik.188@gmail.com>\n---\n ref-filter.c | 8 +++-----\n 1 file changed, 3 insertions(+), 5 deletions(-)\n\ndiff --git a/ref-filter.c b/ref-filter.c\nindex 41e73f0..12e646c 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -230,11 +230,9 @@ struct ref_formatting_state {\n \n struct atom_value {\n \tconst char *s;\n-\tunion {\n-\t\tstruct align align;\n-\t} u;\n \tvoid (*handler)(struct atom_value *atomv, struct ref_formatting_state *state);\n \tunsigned long ul; /* used for sorting when not FIELD_STR */\n+\tstruct used_atom *atom;\n };\n \n /*\n@@ -370,7 +368,7 @@ static void align_atom_handler(struct atom_value *atomv, struct ref_formatting_s\n \tpush_stack_element(&state->stack);\n \tnew = state->stack;\n \tnew->at_end = end_align_handler;\n-\tnew->at_end_data = &atomv->u.align;\n+\tnew->at_end_data = &atomv->atom->u.align;\n }\n \n static void if_then_else_handler(struct ref_formatting_stack **stack)\n@@ -1069,6 +1067,7 @@ static void populate_value(struct ref_array_item *ref)\n \t\tstruct branch *branch = NULL;\n \n \t\tv->handler = append_atom;\n+\t\tv->atom = atom;\n \n \t\tif (*name == '*') {\n \t\t\tderef = 1;\n@@ -1133,7 +1132,6 @@ static void populate_value(struct ref_array_item *ref)\n \t\t\t\tv->s = \" \";\n \t\t\tcontinue;\n \t\t} else if (starts_with(name, \"align\")) {\n-\t\t\tv->u.align = atom->u.align;\n \t\t\tv->handler = align_atom_handler;\n \t\t\tcontinue;\n \t\t} else if (!strcmp(name, \"end\")) {\n-- \n2.7.4\n"},{"id":"282207","messageId":"1459330800-12525-4-git-send-email-Karthik.188@gmail.com","threadId":"41875","inReplyTo":"1459330800-12525-1-git-send-email-Karthik.188@gmail.com","subject":"[PATCH v3 03/16] ref-filter: implement %(if:equals=<string>) and %(if:notequals=<string>)","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2016-03-30T09:39:47Z","receivedAt":"2016-03-30T09:39:47Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"Implement %(if:equals=<string>) wherein the if condition is only\nsatisfied if the value obtained between the %(if:...) and %(then) atom\nis the same as the given '<string>'.\n\nSimilarly, implement (if:notequals=<string>) wherein the if condition\nis only satisfied if the value obtained between the %(if:...) and\n%(then) atom is differnt from the given '<string>'.\n\nThis is done by introducing 'if_atom_parser()' which parses the given\n%(if) atom and then stores the data in used_atom which is later passed\non to the used_atom of the %(then) atom, so that it can do the required\ncomparisons.\n\nAdd tests and Documentation for the same.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>\nSigned-off-by: Karthik Nayak <karthik.188@gmail.com>\n---\n Documentation/git-for-each-ref.txt |  3 +++\n ref-filter.c                       | 43 +++++++++++++++++++++++++++++++++-----\n t/t6302-for-each-ref-filter.sh     | 18 ++++++++++++++++\n 3 files changed, 59 insertions(+), 5 deletions(-)\n\ndiff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt\nindex d048561..e1b1a66 100644\n--- a/Documentation/git-for-each-ref.txt\n+++ b/Documentation/git-for-each-ref.txt\n@@ -152,6 +152,9 @@ if::\n \tevaluating the string before %(then), this is useful when we\n \tuse the %(HEAD) atom which prints either \"*\" or \" \" and we\n \twant to apply the 'if' condition only on the 'HEAD' ref.\n+\tAppend \":equals=<string>\" or \":notequals=<string>\" to compare\n+\tthe value between the %(if:...) and %(then) atoms with the\n+\tgiven string.\n \n In addition to the above, for commit and tag objects, the header\n field names (`tree`, `parent`, `object`, `type`, and `tag`) can\ndiff --git a/ref-filter.c b/ref-filter.c\nindex 12e646c..857a8b5 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -22,6 +22,8 @@ struct align {\n };\n \n struct if_then_else {\n+\tconst char *if_equals,\n+\t\t*not_equals;\n \tunsigned int then_atom_seen : 1,\n \t\telse_atom_seen : 1,\n \t\tcondition_satisfied : 1;\n@@ -49,6 +51,10 @@ static struct used_atom {\n \t\t\tenum { C_BARE, C_BODY, C_BODY_DEP, C_LINES, C_SIG, C_SUB } option;\n \t\t\tunsigned int nlines;\n \t\t} contents;\n+\t\tstruct {\n+\t\t\tconst char *if_equals,\n+\t\t\t\t*not_equals;\n+\t\t} if_then_else;\n \t\tenum { O_FULL, O_SHORT } objectname;\n \t} u;\n } *used_atom;\n@@ -169,6 +175,19 @@ static void align_atom_parser(struct used_atom *atom, const char *arg)\n \tstring_list_clear(&params, 0);\n }\n \n+static void if_atom_parser(struct used_atom *atom, const char *arg)\n+{\n+\tif (!arg)\n+\t\treturn;\n+\telse if (skip_prefix(arg, \"equals=\", &atom->u.if_then_else.if_equals))\n+\t\t ;\n+\telse if (skip_prefix(arg, \"notequals=\", &atom->u.if_then_else.not_equals))\n+\t\t;\n+\telse\n+\t\tdie(_(\"unrecognized %%(if) argument: %s\"), arg);\n+}\n+\n+\n static struct {\n \tconst char *name;\n \tcmp_type cmp_type;\n@@ -209,7 +228,7 @@ static struct {\n \t{ \"color\", FIELD_STR, color_atom_parser },\n \t{ \"align\", FIELD_STR, align_atom_parser },\n \t{ \"end\" },\n-\t{ \"if\" },\n+\t{ \"if\", FIELD_STR, if_atom_parser },\n \t{ \"then\" },\n \t{ \"else\" },\n };\n@@ -410,6 +429,9 @@ static void if_atom_handler(struct atom_value *atomv, struct ref_formatting_stat\n \tstruct ref_formatting_stack *new;\n \tstruct if_then_else *if_then_else = xcalloc(sizeof(struct if_then_else), 1);\n \n+\tif_then_else->if_equals = atomv->atom->u.if_then_else.if_equals;\n+\tif_then_else->not_equals = atomv->atom->u.if_then_else.not_equals;\n+\n \tpush_stack_element(&state->stack);\n \tnew = state->stack;\n \tnew->at_end = if_then_else_handler;\n@@ -441,10 +463,17 @@ static void then_atom_handler(struct atom_value *atomv, struct ref_formatting_st\n \t\tdie(_(\"format: %%(then) atom used after %%(else)\"));\n \tif_then_else->then_atom_seen = 1;\n \t/*\n-\t * If there exists non-empty string between the 'if' and\n-\t * 'then' atom then the 'if' condition is satisfied.\n+\t * If the 'equals' or 'notequals' attribute is used then\n+\t * perform the required comparison. If not, only non-empty\n+\t * strings satisfy the 'if' condition.\n \t */\n-\tif (cur->output.len && !is_empty(cur->output.buf))\n+\tif (if_then_else->if_equals) {\n+\t\tif (!strcmp(if_then_else->if_equals, cur->output.buf))\n+\t\t\tif_then_else->condition_satisfied = 1;\n+\t} else \tif (if_then_else->not_equals) {\n+\t\tif (strcmp(if_then_else->not_equals, cur->output.buf))\n+\t\t\tif_then_else->condition_satisfied = 1;\n+\t} else if (cur->output.len && !is_empty(cur->output.buf))\n \t\tif_then_else->condition_satisfied = 1;\n \tstrbuf_reset(&cur->output);\n }\n@@ -1137,7 +1166,11 @@ static void populate_value(struct ref_array_item *ref)\n \t\t} else if (!strcmp(name, \"end\")) {\n \t\t\tv->handler = end_atom_handler;\n \t\t\tcontinue;\n-\t\t} else if (!strcmp(name, \"if\")) {\n+\t\t} else if (starts_with(name, \"if\")) {\n+\t\t\tconst char *s;\n+\n+\t\t\tif (skip_prefix(name, \"if:\", &s))\n+\t\t\t\tv->s = xstrdup(s);\n \t\t\tv->handler = if_atom_handler;\n \t\t\tcontinue;\n \t\t} else if (!strcmp(name, \"then\")) {\ndiff --git a/t/t6302-for-each-ref-filter.sh b/t/t6302-for-each-ref-filter.sh\nindex 954b12a..83716e4 100755\n--- a/t/t6302-for-each-ref-filter.sh\n+++ b/t/t6302-for-each-ref-filter.sh\n@@ -367,4 +367,22 @@ test_expect_success 'ignore spaces in %(if) atom usage' '\n \ttest_cmp expect actual\n '\n \n+test_expect_success 'check %(if:equals=<string>)' '\n+\tgit for-each-ref --format=\"%(if:equals=master)%(refname:short)%(then)Found master%(else)Not master%(end)\" refs/heads/ >actual &&\n+\tcat >expect <<-\\EOF &&\n+\tFound master\n+\tNot master\n+\tEOF\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success 'check %(if:notequals=<string>)' '\n+\tgit for-each-ref --format=\"%(if:notequals=master)%(refname:short)%(then)Not master%(else)Found master%(end)\" refs/heads/ >actual &&\n+\tcat >expect <<-\\EOF &&\n+\tFound master\n+\tNot master\n+\tEOF\n+\ttest_cmp expect actual\n+'\n+\n test_done\n-- \n2.7.4\n"},{"id":"282211","messageId":"1459330800-12525-5-git-send-email-Karthik.188@gmail.com","threadId":"41875","inReplyTo":"1459330800-12525-1-git-send-email-Karthik.188@gmail.com","subject":"[PATCH v3 04/16] ref-filter: modify \"%(objectname:short)\" to take length","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2016-03-30T09:39:48Z","receivedAt":"2016-03-30T09:39:48Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"Add support for %(objectname:short=<length>) which would print the\nabbreviated unique objectname of given length. When no length is\nspecified, the length is 'DEFAULT_ABBREV'. The minimum length is\n'MINIMUM_ABBREV'. The length may be exceeded to ensure that the provided\nobject name is unique.\n\nAdd tests and documentation for the same.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>\nHelped-by: Jacob Keller <jacob.keller@gmail.com>\nSigned-off-by: Karthik Nayak <karthik.188@gmail.com>\n---\n Documentation/git-for-each-ref.txt |  4 ++++\n ref-filter.c                       | 25 +++++++++++++++++++------\n t/t6300-for-each-ref.sh            | 10 ++++++++++\n 3 files changed, 33 insertions(+), 6 deletions(-)\n\ndiff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt\nindex e1b1a66..d3223a2 100644\n--- a/Documentation/git-for-each-ref.txt\n+++ b/Documentation/git-for-each-ref.txt\n@@ -107,6 +107,10 @@ objectsize::\n objectname::\n \tThe object name (aka SHA-1).\n \tFor a non-ambiguous abbreviation of the object name append `:short`.\n+\tFor an abbreviation of the object name with desired length append\n+\t`:short=<length>`, where the minimum length is MINIMUM_ABBREV. The\n+\tlength may be exceeded to ensure unique object names.\n+\n \n upstream::\n \tThe name of a local ref which can be considered ``upstream''\ndiff --git a/ref-filter.c b/ref-filter.c\nindex 857a8b5..17f781d 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -55,7 +55,10 @@ static struct used_atom {\n \t\t\tconst char *if_equals,\n \t\t\t\t*not_equals;\n \t\t} if_then_else;\n-\t\tenum { O_FULL, O_SHORT } objectname;\n+\t\tstruct {\n+\t\t\tenum { O_FULL, O_LENGTH, O_SHORT } option;\n+\t\t\tunsigned int length;\n+\t\t} objectname;\n \t} u;\n } *used_atom;\n static int used_atom_cnt, need_tagged, need_symref;\n@@ -118,10 +121,17 @@ static void contents_atom_parser(struct used_atom *atom, const char *arg)\n static void objectname_atom_parser(struct used_atom *atom, const char *arg)\n {\n \tif (!arg)\n-\t\tatom->u.objectname = O_FULL;\n+\t\tatom->u.objectname.option = O_FULL;\n \telse if (!strcmp(arg, \"short\"))\n-\t\tatom->u.objectname = O_SHORT;\n-\telse\n+\t\tatom->u.objectname.option = O_SHORT;\n+\telse if (skip_prefix(arg, \"short=\", &arg)) {\n+\t\tatom->u.contents.option = O_LENGTH;\n+\t\tif (strtoul_ui(arg, 10, &atom->u.objectname.length) ||\n+\t\t    atom->u.objectname.length == 0)\n+\t\t\tdie(_(\"positive value expected objectname:short=%s\"), arg);\n+\t\tif (atom->u.objectname.length < MINIMUM_ABBREV)\n+\t\t\tatom->u.objectname.length = MINIMUM_ABBREV;\n+\t} else\n \t\tdie(_(\"unrecognized %%(objectname) argument: %s\"), arg);\n }\n \n@@ -591,12 +601,15 @@ static int grab_objectname(const char *name, const unsigned char *sha1,\n \t\t\t   struct atom_value *v, struct used_atom *atom)\n {\n \tif (starts_with(name, \"objectname\")) {\n-\t\tif (atom->u.objectname == O_SHORT) {\n+\t\tif (atom->u.objectname.option == O_SHORT) {\n \t\t\tv->s = xstrdup(find_unique_abbrev(sha1, DEFAULT_ABBREV));\n \t\t\treturn 1;\n-\t\t} else if (atom->u.objectname == O_FULL) {\n+\t\t} else if (atom->u.objectname.option == O_FULL) {\n \t\t\tv->s = xstrdup(sha1_to_hex(sha1));\n \t\t\treturn 1;\n+\t\t} else if (atom->u.objectname.option == O_LENGTH) {\n+\t\t\tv->s = xstrdup(find_unique_abbrev(sha1, atom->u.objectname.length));\n+\t\t\treturn 1;\n \t\t} else\n \t\t\tdie(\"BUG: unknown %%(objectname) option\");\n \t}\ndiff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh\nindex 19a2823..2be0a3f 100755\n--- a/t/t6300-for-each-ref.sh\n+++ b/t/t6300-for-each-ref.sh\n@@ -60,6 +60,8 @@ test_atom head objecttype commit\n test_atom head objectsize 171\n test_atom head objectname $(git rev-parse refs/heads/master)\n test_atom head objectname:short $(git rev-parse --short refs/heads/master)\n+test_atom head objectname:short=1 $(git rev-parse --short=1 refs/heads/master)\n+test_atom head objectname:short=10 $(git rev-parse --short=10 refs/heads/master)\n test_atom head tree $(git rev-parse refs/heads/master^{tree})\n test_atom head parent ''\n test_atom head numparent 0\n@@ -99,6 +101,8 @@ test_atom tag objecttype tag\n test_atom tag objectsize 154\n test_atom tag objectname $(git rev-parse refs/tags/testtag)\n test_atom tag objectname:short $(git rev-parse --short refs/tags/testtag)\n+test_atom head objectname:short=1 $(git rev-parse --short=1 refs/heads/master)\n+test_atom head objectname:short=10 $(git rev-parse --short=10 refs/heads/master)\n test_atom tag tree ''\n test_atom tag parent ''\n test_atom tag numparent ''\n@@ -164,6 +168,12 @@ test_expect_success 'Check invalid format specifiers are errors' '\n \ttest_must_fail git for-each-ref --format=\"%(authordate:INVALID)\" refs/heads\n '\n \n+test_expect_success 'arguments to %(objectname:short=) must be positive integers' '\n+\ttest_must_fail git for-each-ref --format=\"%(objectname:short=0)\" &&\n+\ttest_must_fail git for-each-ref --format=\"%(objectname:short=-1)\" &&\n+\ttest_must_fail git for-each-ref --format=\"%(objectname:short=foo)\"\n+'\n+\n test_date () {\n \tf=$1 &&\n \tcommitter_date=$2 &&\n-- \n2.7.4\n"},{"id":"282209","messageId":"1459330800-12525-6-git-send-email-Karthik.188@gmail.com","threadId":"41875","inReplyTo":"1459330800-12525-1-git-send-email-Karthik.188@gmail.com","subject":"[PATCH v3 05/16] ref-filter: move get_head_description() from branch.c","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2016-03-30T09:39:49Z","receivedAt":"2016-03-30T09:39:49Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"Move the implementation of get_head_description() from branch.c to\nref-filter.  This gives a description of the HEAD ref if called. This\nis used as the refname for the HEAD ref whenever the\nFILTER_REFS_DETACHED_HEAD option is used. Make it public because we\nneed it to calculate the length of the HEAD refs description in\nbranch.c:calc_maxwidth() when we port branch.c to use ref-filter\nAPIs.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>\nSigned-off-by: Karthik Nayak <karthik.188@gmail.com>\n---\n builtin/branch.c | 31 -------------------------------\n ref-filter.c     | 38 ++++++++++++++++++++++++++++++++++++--\n ref-filter.h     |  2 ++\n 3 files changed, 38 insertions(+), 33 deletions(-)\n\ndiff --git a/builtin/branch.c b/builtin/branch.c\nindex 7b45b6b..460f32f 100644\n--- a/builtin/branch.c\n+++ b/builtin/branch.c\n@@ -355,37 +355,6 @@ static void add_verbose_info(struct strbuf *out, struct ref_array_item *item,\n \tstrbuf_release(&subject);\n }\n \n-static char *get_head_description(void)\n-{\n-\tstruct strbuf desc = STRBUF_INIT;\n-\tstruct wt_status_state state;\n-\tmemset(&state, 0, sizeof(state));\n-\twt_status_get_state(&state, 1);\n-\tif (state.rebase_in_progress ||\n-\t    state.rebase_interactive_in_progress)\n-\t\tstrbuf_addf(&desc, _(\"(no branch, rebasing %s)\"),\n-\t\t\t    state.branch);\n-\telse if (state.bisect_in_progress)\n-\t\tstrbuf_addf(&desc, _(\"(no branch, bisect started on %s)\"),\n-\t\t\t    state.branch);\n-\telse if (state.detached_from) {\n-\t\t/* TRANSLATORS: make sure these match _(\"HEAD detached at \")\n-\t\t   and _(\"HEAD detached from \") in wt-status.c */\n-\t\tif (state.detached_at)\n-\t\t\tstrbuf_addf(&desc, _(\"(HEAD detached at %s)\"),\n-\t\t\t\tstate.detached_from);\n-\t\telse\n-\t\t\tstrbuf_addf(&desc, _(\"(HEAD detached from %s)\"),\n-\t\t\t\tstate.detached_from);\n-\t}\n-\telse\n-\t\tstrbuf_addstr(&desc, _(\"(no branch)\"));\n-\tfree(state.branch);\n-\tfree(state.onto);\n-\tfree(state.detached_from);\n-\treturn strbuf_detach(&desc, NULL);\n-}\n-\n static void format_and_print_ref_item(struct ref_array_item *item, int maxwidth,\n \t\t\t\t      struct ref_filter *filter, const char *remote_prefix)\n {\ndiff --git a/ref-filter.c b/ref-filter.c\nindex 17f781d..7004bf0 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -13,6 +13,7 @@\n #include \"utf8.h\"\n #include \"git-compat-util.h\"\n #include \"version.h\"\n+#include \"wt-status.h\"\n \n typedef enum { FIELD_STR, FIELD_ULONG, FIELD_TIME } cmp_type;\n \n@@ -1077,6 +1078,37 @@ static void fill_remote_ref_details(struct used_atom *atom, const char *refname,\n \t\t*s = refname;\n }\n \n+char *get_head_description(void)\n+{\n+\tstruct strbuf desc = STRBUF_INIT;\n+\tstruct wt_status_state state;\n+\tmemset(&state, 0, sizeof(state));\n+\twt_status_get_state(&state, 1);\n+\tif (state.rebase_in_progress ||\n+\t    state.rebase_interactive_in_progress)\n+\t\tstrbuf_addf(&desc, _(\"(no branch, rebasing %s)\"),\n+\t\t\t    state.branch);\n+\telse if (state.bisect_in_progress)\n+\t\tstrbuf_addf(&desc, _(\"(no branch, bisect started on %s)\"),\n+\t\t\t    state.branch);\n+\telse if (state.detached_from) {\n+\t\t/* TRANSLATORS: make sure these match _(\"HEAD detached at \")\n+\t\t   and _(\"HEAD detached from \") in wt-status.c */\n+\t\tif (state.detached_at)\n+\t\t\tstrbuf_addf(&desc, _(\"(HEAD detached at %s)\"),\n+\t\t\t\tstate.detached_from);\n+\t\telse\n+\t\t\tstrbuf_addf(&desc, _(\"(HEAD detached from %s)\"),\n+\t\t\t\tstate.detached_from);\n+\t}\n+\telse\n+\t\tstrbuf_addstr(&desc, _(\"(no branch)\"));\n+\tfree(state.branch);\n+\tfree(state.onto);\n+\tfree(state.detached_from);\n+\treturn strbuf_detach(&desc, NULL);\n+}\n+\n /*\n  * Parse the object referred by ref, and grab needed value.\n  */\n@@ -1116,9 +1148,11 @@ static void populate_value(struct ref_array_item *ref)\n \t\t\tname++;\n \t\t}\n \n-\t\tif (starts_with(name, \"refname\"))\n+\t\tif (starts_with(name, \"refname\")) {\n \t\t\trefname = ref->refname;\n-\t\telse if (starts_with(name, \"symref\"))\n+\t\t\tif (ref->kind & FILTER_REFS_DETACHED_HEAD)\n+\t\t\t\trefname = get_head_description();\n+\t\t} else if (starts_with(name, \"symref\"))\n \t\t\trefname = ref->symref ? ref->symref : \"\";\n \t\telse if (starts_with(name, \"upstream\")) {\n \t\t\tconst char *branch_name;\ndiff --git a/ref-filter.h b/ref-filter.h\nindex 14d435e..4aea594 100644\n--- a/ref-filter.h\n+++ b/ref-filter.h\n@@ -106,5 +106,7 @@ int parse_opt_ref_sorting(const struct option *opt, const char *arg, int unset);\n struct ref_sorting *ref_default_sorting(void);\n /*  Function to parse --merged and --no-merged options */\n int parse_opt_merge_filter(const struct option *opt, const char *arg, int unset);\n+/*  Get the current HEAD's description */\n+char *get_head_description(void);\n \n #endif /*  REF_FILTER_H  */\n-- \n2.7.4\n"},{"id":"282221","messageId":"1459330800-12525-7-git-send-email-Karthik.188@gmail.com","threadId":"41875","inReplyTo":"1459330800-12525-1-git-send-email-Karthik.188@gmail.com","subject":"[PATCH v3 06/16] ref-filter: introduce format_ref_array_item()","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2016-03-30T09:39:50Z","receivedAt":"2016-03-30T09:39:50Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"To allow column display, we will need to first render the output in a\nstring list to allow print_columns() to compute the proper size of\neach column before starting the actual output. Introduce the function\nformat_ref_array_item() that does the formatting of a ref_array_item\nto an strbuf.\n\nshow_ref_array_item() is kept as a convenience wrapper around it which\nobtains the strbuf and prints it the standard output.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>\nSigned-off-by: Karthik Nayak <karthik.188@gmail.com>\n---\n ref-filter.c | 16 ++++++++++++----\n ref-filter.h |  3 +++\n 2 files changed, 15 insertions(+), 4 deletions(-)\n\ndiff --git a/ref-filter.c b/ref-filter.c\nindex 7004bf0..3bb474f 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -1813,10 +1813,10 @@ static void append_literal(const char *cp, const char *ep, struct ref_formatting\n \t}\n }\n \n-void show_ref_array_item(struct ref_array_item *info, const char *format, int quote_style)\n+void format_ref_array_item(struct ref_array_item *info, const char *format,\n+\t\t\t   int quote_style, struct strbuf *final_buf)\n {\n \tconst char *cp, *sp, *ep;\n-\tstruct strbuf *final_buf;\n \tstruct ref_formatting_state state = REF_FORMATTING_STATE_INIT;\n \n \tstate.quote_style = quote_style;\n@@ -1846,9 +1846,17 @@ void show_ref_array_item(struct ref_array_item *info, const char *format, int qu\n \t}\n \tif (state.stack->prev)\n \t\tdie(_(\"format: %%(end) atom missing\"));\n-\tfinal_buf = &state.stack->output;\n-\tfwrite(final_buf->buf, 1, final_buf->len, stdout);\n+\tstrbuf_addbuf(final_buf, &state.stack->output);\n \tpop_stack_element(&state.stack);\n+}\n+\n+void show_ref_array_item(struct ref_array_item *info, const char *format, int quote_style)\n+{\n+\tstruct strbuf final_buf = STRBUF_INIT;\n+\n+\tformat_ref_array_item(info, format, quote_style, &final_buf);\n+\tfwrite(final_buf.buf, 1, final_buf.len, stdout);\n+\tstrbuf_release(&final_buf);\n \tputchar('\\n');\n }\n \ndiff --git a/ref-filter.h b/ref-filter.h\nindex 4aea594..0014b92 100644\n--- a/ref-filter.h\n+++ b/ref-filter.h\n@@ -98,6 +98,9 @@ int parse_ref_filter_atom(const char *atom, const char *ep);\n int verify_ref_format(const char *format);\n /*  Sort the given ref_array as per the ref_sorting provided */\n void ref_array_sort(struct ref_sorting *sort, struct ref_array *array);\n+/*  Based on the given format and quote_style, fill the strbuf */\n+void format_ref_array_item(struct ref_array_item *info, const char *format,\n+\t\t\t   int quote_style, struct strbuf *final_buf);\n /*  Print the ref using the given format and quote_style */\n void show_ref_array_item(struct ref_array_item *info, const char *format, int quote_style);\n /*  Callback function for parsing the sort option */\n-- \n2.7.4\n"},{"id":"282210","messageId":"1459330800-12525-8-git-send-email-Karthik.188@gmail.com","threadId":"41875","inReplyTo":"1459330800-12525-1-git-send-email-Karthik.188@gmail.com","subject":"[PATCH v3 07/16] ref-filter: make %(upstream:track) prints \"[gone]\" for invalid upstreams","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2016-03-30T09:39:51Z","receivedAt":"2016-03-30T09:39:51Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"Borrowing from branch.c's implementation print \"[gone]\" whenever an\nunknown upstream ref is encountered instead of just ignoring it.\n\nThis makes sure that when branch.c is ported over to using ref-filter\nAPIs for printing, this feature is not lost.\n\nMake changes to t/t6300-for-each-ref.sh and\nDocumentation/git-for-each-ref.txt to reflect this change.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>\nHelped-by : Jacob Keller <jacob.keller@gmail.com>\nSigned-off-by: Karthik Nayak <karthik.188@gmail.com>\n---\n Documentation/git-for-each-ref.txt | 3 ++-\n ref-filter.c                       | 4 +++-\n t/t6300-for-each-ref.sh            | 2 +-\n 3 files changed, 6 insertions(+), 3 deletions(-)\n\ndiff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt\nindex d3223a2..85ac2a8 100644\n--- a/Documentation/git-for-each-ref.txt\n+++ b/Documentation/git-for-each-ref.txt\n@@ -119,7 +119,8 @@ upstream::\n \t\"[ahead N, behind M]\" and `:trackshort` to show the terse\n \tversion: \">\" (ahead), \"<\" (behind), \"<>\" (ahead and behind),\n \tor \"=\" (in sync).  Has no effect if the ref does not have\n-\ttracking information associated with it.\n+\ttracking information associated with it. `:track` also prints\n+\t\"[gone]\" whenever unknown upstream ref is encountered.\n \n push::\n \tThe name of a local ref which represents the `@{push}` location\ndiff --git a/ref-filter.c b/ref-filter.c\nindex 3bb474f..4d7e0c0 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -1049,8 +1049,10 @@ static void fill_remote_ref_details(struct used_atom *atom, const char *refname,\n \t\t*s = shorten_unambiguous_ref(refname, warn_ambiguous_refs);\n \telse if (atom->u.remote_ref == RR_TRACK) {\n \t\tif (stat_tracking_info(branch, &num_ours,\n-\t\t\t\t       &num_theirs, NULL))\n+\t\t\t\t       &num_theirs, NULL)) {\n+\t\t\t*s = \"[gone]\";\n \t\t\treturn;\n+\t\t}\n \n \t\tif (!num_ours && !num_theirs)\n \t\t\t*s = \"\";\ndiff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh\nindex 2be0a3f..a92b36f 100755\n--- a/t/t6300-for-each-ref.sh\n+++ b/t/t6300-for-each-ref.sh\n@@ -382,7 +382,7 @@ test_expect_success 'Check that :track[short] cannot be used with other atoms' '\n \n test_expect_success 'Check that :track[short] works when upstream is invalid' '\n \tcat >expected <<-\\EOF &&\n-\n+\t[gone]\n \n \tEOF\n \ttest_when_finished \"git config branch.master.merge refs/heads/master\" &&\n-- \n2.7.4\n"},{"id":"282215","messageId":"1459330800-12525-9-git-send-email-Karthik.188@gmail.com","threadId":"41875","inReplyTo":"1459330800-12525-1-git-send-email-Karthik.188@gmail.com","subject":"[PATCH v3 08/16] ref-filter: add support for %(upstream:track,nobracket)","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2016-03-30T09:39:52Z","receivedAt":"2016-03-30T09:39:52Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"Add support for %(upstream:track,nobracket) which will print the\ntracking information without the brackets (i.e. \"ahead N, behind M\").\nThis is needed when we port branch.c to use ref-filter's printing APIs.\n\nAdd test and documentation for the same.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>\nSigned-off-by: Karthik Nayak <karthik.188@gmail.com>\n---\n Documentation/git-for-each-ref.txt |  8 +++--\n ref-filter.c                       | 67 +++++++++++++++++++++++++-------------\n t/t6300-for-each-ref.sh            |  2 ++\n 3 files changed, 51 insertions(+), 26 deletions(-)\n\ndiff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt\nindex 85ac2a8..be763c4 100644\n--- a/Documentation/git-for-each-ref.txt\n+++ b/Documentation/git-for-each-ref.txt\n@@ -118,9 +118,11 @@ upstream::\n \t`refname` above.  Additionally respects `:track` to show\n \t\"[ahead N, behind M]\" and `:trackshort` to show the terse\n \tversion: \">\" (ahead), \"<\" (behind), \"<>\" (ahead and behind),\n-\tor \"=\" (in sync).  Has no effect if the ref does not have\n-\ttracking information associated with it. `:track` also prints\n-\t\"[gone]\" whenever unknown upstream ref is encountered.\n+\tor \"=\" (in sync). `:track` also prints \"[gone]\" whenever\n+\tunknown upstream ref is encountered. Append `:track,nobracket`\n+\tto show tracking information without brackets (i.e \"ahead N,\n+\tbehind M\").  Has no effect if the ref does not have tracking\n+\tinformation associated with it.\n \n push::\n \tThe name of a local ref which represents the `@{push}` location\ndiff --git a/ref-filter.c b/ref-filter.c\nindex 4d7e0c0..8c97cdb 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -46,8 +46,10 @@ static struct used_atom {\n \tunion {\n \t\tchar color[COLOR_MAXLEN];\n \t\tstruct align align;\n-\t\tenum { RR_NORMAL, RR_SHORTEN, RR_TRACK, RR_TRACKSHORT }\n-\t\t\tremote_ref;\n+\t\tstruct {\n+\t\t\tenum { RR_NORMAL, RR_SHORTEN, RR_TRACK, RR_TRACKSHORT } option;\n+\t\t\tunsigned int nobracket: 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 } option;\n \t\t\tunsigned int nlines;\n@@ -75,16 +77,33 @@ static void color_atom_parser(struct used_atom *atom, const char *color_value)\n \n static void remote_ref_atom_parser(struct used_atom *atom, const char *arg)\n {\n-\tif (!arg)\n-\t\tatom->u.remote_ref = RR_NORMAL;\n-\telse if (!strcmp(arg, \"short\"))\n-\t\tatom->u.remote_ref = RR_SHORTEN;\n-\telse if (!strcmp(arg, \"track\"))\n-\t\tatom->u.remote_ref = RR_TRACK;\n-\telse if (!strcmp(arg, \"trackshort\"))\n-\t\tatom->u.remote_ref = RR_TRACKSHORT;\n-\telse\n-\t\tdie(_(\"unrecognized format: %%(%s)\"), atom->name);\n+\tstruct string_list params = STRING_LIST_INIT_DUP;\n+\tint i;\n+\n+\tif (!arg) {\n+\t\tatom->u.remote_ref.option = RR_NORMAL;\n+\t\treturn;\n+\t}\n+\n+\tatom->u.remote_ref.nobracket = 0;\n+\tstring_list_split(&params, arg, ',', -1);\n+\n+\tfor (i = 0; i < params.nr; i++) {\n+\t\tconst char *s = params.items[i].string;\n+\n+\t\tif (!strcmp(s, \"short\"))\n+\t\t\tatom->u.remote_ref.option = RR_SHORTEN;\n+\t\telse if (!strcmp(s, \"track\"))\n+\t\t\tatom->u.remote_ref.option = RR_TRACK;\n+\t\telse if (!strcmp(s, \"trackshort\"))\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\t\tdie(_(\"unrecognized format: %%(%s)\"), atom->name);\n+\t}\n+\n+\tstring_list_clear(&params, 0);\n }\n \n static void body_atom_parser(struct used_atom *atom, const char *arg)\n@@ -1045,25 +1064,27 @@ static void fill_remote_ref_details(struct used_atom *atom, const char *refname,\n \t\t\t\t    struct branch *branch, const char **s)\n {\n \tint num_ours, num_theirs;\n-\tif (atom->u.remote_ref == RR_SHORTEN)\n+\tif (atom->u.remote_ref.option == RR_SHORTEN)\n \t\t*s = shorten_unambiguous_ref(refname, warn_ambiguous_refs);\n-\telse if (atom->u.remote_ref == RR_TRACK) {\n+\telse if (atom->u.remote_ref.option == RR_TRACK) {\n \t\tif (stat_tracking_info(branch, &num_ours,\n \t\t\t\t       &num_theirs, NULL)) {\n-\t\t\t*s = \"[gone]\";\n-\t\t\treturn;\n-\t\t}\n-\n-\t\tif (!num_ours && !num_theirs)\n+\t\t\t*s = xstrdup(\"gone\");\n+\t\t} else if (!num_ours && !num_theirs)\n \t\t\t*s = \"\";\n \t\telse if (!num_ours)\n-\t\t\t*s = xstrfmt(\"[behind %d]\", num_theirs);\n+\t\t\t*s = xstrfmt(\"behind %d\", num_theirs);\n \t\telse if (!num_theirs)\n-\t\t\t*s = xstrfmt(\"[ahead %d]\", num_ours);\n+\t\t\t*s = xstrfmt(\"ahead %d\", num_ours);\n \t\telse\n-\t\t\t*s = xstrfmt(\"[ahead %d, behind %d]\",\n+\t\t\t*s = xstrfmt(\"ahead %d, behind %d\",\n \t\t\t\t     num_ours, num_theirs);\n-\t} else if (atom->u.remote_ref == RR_TRACKSHORT) {\n+\t\tif (!atom->u.remote_ref.nobracket && *s[0]) {\n+\t\t\tconst char *to_free = *s;\n+\t\t\t*s = xstrfmt(\"[%s]\", *s);\n+\t\t\tfree((void *)to_free);\n+\t\t}\n+\t} else if (atom->u.remote_ref.option == RR_TRACKSHORT) {\n \t\tif (stat_tracking_info(branch, &num_ours,\n \t\t\t\t       &num_theirs, NULL))\n \t\t\treturn;\ndiff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh\nindex a92b36f..2c5f177 100755\n--- a/t/t6300-for-each-ref.sh\n+++ b/t/t6300-for-each-ref.sh\n@@ -372,6 +372,8 @@ test_expect_success 'setup for upstream:track[short]' '\n \n test_atom head upstream:track '[ahead 1]'\n test_atom head upstream:trackshort '>'\n+test_atom head upstream:track,nobracket 'ahead 1'\n+test_atom head upstream:nobracket,track 'ahead 1'\n test_atom head push:track '[ahead 1]'\n test_atom head push:trackshort '>'\n \n-- \n2.7.4\n"},{"id":"282218","messageId":"1459330800-12525-10-git-send-email-Karthik.188@gmail.com","threadId":"41875","inReplyTo":"1459330800-12525-1-git-send-email-Karthik.188@gmail.com","subject":"[PATCH v3 09/16] ref-filter: make \"%(symref)\" atom work with the ':short' modifier","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2016-03-30T09:39:53Z","receivedAt":"2016-03-30T09:39:53Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"The \"%(symref)\" atom doesn't work when used with the ':short' modifier\nbecause we strictly match only 'symref' for setting the 'need_symref'\nindicator. Fix this by using comparing with valid_atom rather than used_atom.\n\nAdd tests for %(symref) and %(symref:short) while we're here.\n\nHelped-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Karthik Nayak <Karthik.188@gmail.com>\n---\n ref-filter.c            |  2 +-\n t/t6300-for-each-ref.sh | 24 ++++++++++++++++++++++++\n 2 files changed, 25 insertions(+), 1 deletion(-)\n\ndiff --git a/ref-filter.c b/ref-filter.c\nindex 8c97cdb..5c59b17 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -338,7 +338,7 @@ int parse_ref_filter_atom(const char *atom, const char *ep)\n \t\tvalid_atom[i].parser(&used_atom[at], arg);\n \tif (*atom == '*')\n \t\tneed_tagged = 1;\n-\tif (!strcmp(used_atom[at].name, \"symref\"))\n+\tif (!strcmp(valid_atom[i].name, \"symref\"))\n \t\tneed_symref = 1;\n \treturn at;\n }\ndiff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh\nindex 2c5f177..b06ea1c 100755\n--- a/t/t6300-for-each-ref.sh\n+++ b/t/t6300-for-each-ref.sh\n@@ -38,6 +38,7 @@ test_atom() {\n \tcase \"$1\" in\n \t\thead) ref=refs/heads/master ;;\n \t\t tag) ref=refs/tags/testtag ;;\n+\t\t sym) ref=refs/heads/sym ;;\n \t\t   *) ref=$1 ;;\n \tesac\n \tprintf '%s\\n' \"$3\" >expected\n@@ -565,4 +566,27 @@ test_expect_success 'Verify sort with multiple keys' '\n \t\trefs/tags/bogo refs/tags/master > actual &&\n \ttest_cmp expected actual\n '\n+\n+test_expect_success 'Add symbolic ref for the following tests' '\n+\tgit symbolic-ref refs/heads/sym refs/heads/master\n+'\n+\n+cat >expected <<EOF\n+refs/heads/master\n+EOF\n+\n+test_expect_success 'Verify usage of %(symref) atom' '\n+\tgit for-each-ref --format=\"%(symref)\" refs/heads/sym > actual &&\n+\ttest_cmp expected actual\n+'\n+\n+cat >expected <<EOF\n+heads/master\n+EOF\n+\n+test_expect_success 'Verify usage of %(symref:short) atom' '\n+\tgit for-each-ref --format=\"%(symref:short)\" refs/heads/sym > actual &&\n+\ttest_cmp expected actual\n+'\n+\n test_done\n-- \n2.7.4\n"},{"id":"282213","messageId":"1459330800-12525-11-git-send-email-Karthik.188@gmail.com","threadId":"41875","inReplyTo":"1459330800-12525-1-git-send-email-Karthik.188@gmail.com","subject":"[PATCH v3 10/16] ref-filter: introduce symref_atom_parser()","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2016-03-30T09:39:54Z","receivedAt":"2016-03-30T09:39:54Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"Introduce symref_atom_parser() which will parse the '%(symref)' atom and\nstore information into the 'used_atom' structure based on the modifiers\nused along with the atom.\n\nSigned-off-by: Karthik Nayak <Karthik.188@gmail.com>\n---\n ref-filter.c | 25 +++++++++++++++++++++++--\n 1 file changed, 23 insertions(+), 2 deletions(-)\n\ndiff --git a/ref-filter.c b/ref-filter.c\nindex 5c59b17..7b35e4f 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -62,6 +62,7 @@ static struct used_atom {\n \t\t\tenum { O_FULL, O_LENGTH, O_SHORT } option;\n \t\t\tunsigned int length;\n \t\t} objectname;\n+\t\tenum { S_FULL, S_SHORT } symref;\n \t} u;\n } *used_atom;\n static int used_atom_cnt, need_tagged, need_symref;\n@@ -217,6 +218,15 @@ static void if_atom_parser(struct used_atom *atom, const char *arg)\n \t\tdie(_(\"unrecognized %%(if) argument: %s\"), arg);\n }\n \n+static void symref_atom_parser(struct used_atom *atom, const char *arg)\n+{\n+\tif (!arg)\n+\t\tatom->u.symref = S_FULL;\n+\telse if (!strcmp(arg, \"short\"))\n+\t\tatom->u.symref = S_SHORT;\n+\telse\n+\t\tdie(_(\"unrecognized %%(symref) argument: %s\"), arg);\n+}\n \n static struct {\n \tconst char *name;\n@@ -252,7 +262,7 @@ static struct {\n \t{ \"contents\", FIELD_STR, contents_atom_parser },\n \t{ \"upstream\", FIELD_STR, remote_ref_atom_parser },\n \t{ \"push\", FIELD_STR, remote_ref_atom_parser },\n-\t{ \"symref\" },\n+\t{ \"symref\", FIELD_STR, symref_atom_parser },\n \t{ \"flag\" },\n \t{ \"HEAD\" },\n \t{ \"color\", FIELD_STR, color_atom_parser },\n@@ -1132,6 +1142,17 @@ char *get_head_description(void)\n \treturn strbuf_detach(&desc, NULL);\n }\n \n+static const char *get_symref(struct used_atom *atom, struct ref_array_item *ref)\n+{\n+\tif (!ref->symref)\n+\t\treturn \"\";\n+\telse if (atom->u.symref == S_SHORT)\n+\t\treturn shorten_unambiguous_ref(ref->symref,\n+\t\t\t\t\t       warn_ambiguous_refs);\n+\telse\n+\t\treturn ref->symref;\n+}\n+\n /*\n  * Parse the object referred by ref, and grab needed value.\n  */\n@@ -1176,7 +1197,7 @@ static void populate_value(struct ref_array_item *ref)\n \t\t\tif (ref->kind & FILTER_REFS_DETACHED_HEAD)\n \t\t\t\trefname = get_head_description();\n \t\t} else if (starts_with(name, \"symref\"))\n-\t\t\trefname = ref->symref ? ref->symref : \"\";\n+\t\t\trefname = get_symref(atom, ref);\n \t\telse if (starts_with(name, \"upstream\")) {\n \t\t\tconst char *branch_name;\n \t\t\t/* only local branches may have an upstream */\n-- \n2.7.4\n"},{"id":"282212","messageId":"1459330800-12525-12-git-send-email-Karthik.188@gmail.com","threadId":"41875","inReplyTo":"1459330800-12525-1-git-send-email-Karthik.188@gmail.com","subject":"[PATCH v3 11/16] ref-filter: introduce refname_atom_parser()","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2016-03-30T09:39:55Z","receivedAt":"2016-03-30T09:39:55Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"Introduce refname_atom_parser() which will parse the '%(refname)' atom\nand store information into the 'used_atom' structure based on the\nmodifiers used along with the atom.\n\nSigned-off-by: Karthik Nayak <Karthik.188@gmail.com>\n---\n ref-filter.c | 70 +++++++++++++++++++++++++++++++++---------------------------\n 1 file changed, 39 insertions(+), 31 deletions(-)\n\ndiff --git a/ref-filter.c b/ref-filter.c\nindex 7b35e4f..dc1e404 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -63,6 +63,10 @@ static struct used_atom {\n \t\t\tunsigned int length;\n \t\t} objectname;\n \t\tenum { S_FULL, S_SHORT } symref;\n+\t\tstruct {\n+\t\t\tenum { R_NORMAL, R_SHORT, R_STRIP } option;\n+\t\t\tunsigned int strip;\n+\t\t} refname;\n \t} u;\n } *used_atom;\n static int used_atom_cnt, need_tagged, need_symref;\n@@ -228,12 +232,27 @@ static void symref_atom_parser(struct used_atom *atom, const char *arg)\n \t\tdie(_(\"unrecognized %%(symref) argument: %s\"), arg);\n }\n \n+static void refname_atom_parser(struct used_atom *atom, const char *arg)\n+{\n+\tif (!arg)\n+\t\tatom->u.refname.option = R_NORMAL;\n+\telse if (!strcmp(arg, \"short\"))\n+\t\tatom->u.refname.option = R_SHORT;\n+\telse if (skip_prefix(arg, \"strip=\", &arg)) {\n+\t\tatom->u.contents.option = R_STRIP;\n+\t\tif (strtoul_ui(arg, 10, &atom->u.refname.strip) ||\n+\t\t\tatom->u.refname.strip <= 0)\n+\t\t\tdie(_(\"positive value expected refname:strip=%s\"), arg);\n+\t} else\n+\t\tdie(_(\"unrecognized %%(refname) argument: %s\"), arg);\n+}\n+\n static struct {\n \tconst char *name;\n \tcmp_type cmp_type;\n \tvoid (*parser)(struct used_atom *atom, const char *arg);\n } valid_atom[] = {\n-\t{ \"refname\" },\n+\t{ \"refname\", FIELD_STR, refname_atom_parser },\n \t{ \"objecttype\" },\n \t{ \"objectsize\", FIELD_ULONG },\n \t{ \"objectname\", FIELD_STR, objectname_atom_parser },\n@@ -1047,21 +1066,16 @@ static inline char *copy_advance(char *dst, const char *src)\n \treturn dst;\n }\n \n-static const char *strip_ref_components(const char *refname, const char *nr_arg)\n+static const char *strip_ref_components(const char *refname, unsigned int len)\n {\n-\tchar *end;\n-\tlong nr = strtol(nr_arg, &end, 10);\n-\tlong remaining = nr;\n+\tlong remaining = len;\n \tconst char *start = refname;\n \n-\tif (nr < 1 || *end != '\\0')\n-\t\tdie(_(\":strip= requires a positive integer argument\"));\n-\n \twhile (remaining) {\n \t\tswitch (*start++) {\n \t\tcase '\\0':\n-\t\t\tdie(_(\"ref '%s' does not have %ld components to :strip\"),\n-\t\t\t    refname, nr);\n+\t\t\tdie(\"ref '%s' does not have %ud components to :strip\",\n+\t\t\t    refname, len);\n \t\tcase '/':\n \t\t\tremaining--;\n \t\t\tbreak;\n@@ -1153,6 +1167,18 @@ static const char *get_symref(struct used_atom *atom, struct ref_array_item *ref\n \t\treturn ref->symref;\n }\n \n+static const char *get_refname(struct used_atom *atom, struct ref_array_item *ref)\n+{\n+\tif (ref->kind & FILTER_REFS_DETACHED_HEAD)\n+\t\treturn get_head_description();\n+\tif (atom->u.refname.option == R_SHORT)\n+\t\treturn shorten_unambiguous_ref(ref->refname, warn_ambiguous_refs);\n+\telse if (atom->u.refname.option == R_STRIP)\n+\t\treturn strip_ref_components(ref->refname, atom->u.refname.strip);\n+\telse\n+\t\treturn ref->refname;\n+}\n+\n /*\n  * Parse the object referred by ref, and grab needed value.\n  */\n@@ -1181,7 +1207,6 @@ static void populate_value(struct ref_array_item *ref)\n \t\tstruct atom_value *v = &ref->value[i];\n \t\tint deref = 0;\n \t\tconst char *refname;\n-\t\tconst char *formatp;\n \t\tstruct branch *branch = NULL;\n \n \t\tv->handler = append_atom;\n@@ -1192,11 +1217,9 @@ static void populate_value(struct ref_array_item *ref)\n \t\t\tname++;\n \t\t}\n \n-\t\tif (starts_with(name, \"refname\")) {\n-\t\t\trefname = ref->refname;\n-\t\t\tif (ref->kind & FILTER_REFS_DETACHED_HEAD)\n-\t\t\t\trefname = get_head_description();\n-\t\t} else if (starts_with(name, \"symref\"))\n+\t\tif (starts_with(name, \"refname\"))\n+\t\t\trefname = get_refname(atom, ref);\n+\t\telse if (starts_with(name, \"symref\"))\n \t\t\trefname = get_symref(atom, ref);\n \t\telse if (starts_with(name, \"upstream\")) {\n \t\t\tconst char *branch_name;\n@@ -1273,21 +1296,6 @@ static void populate_value(struct ref_array_item *ref)\n \t\t} else\n \t\t\tcontinue;\n \n-\t\tformatp = strchr(name, ':');\n-\t\tif (formatp) {\n-\t\t\tconst char *arg;\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 if (skip_prefix(formatp, \"strip=\", &arg))\n-\t\t\t\trefname = strip_ref_components(refname, arg);\n-\t\t\telse\n-\t\t\t\tdie(_(\"unknown %.*s format %s\"),\n-\t\t\t\t    (int)(formatp - name), name, formatp);\n-\t\t}\n-\n \t\tif (!deref)\n \t\t\tv->s = refname;\n \t\telse\n-- \n2.7.4\n"},{"id":"282214","messageId":"1459330800-12525-13-git-send-email-Karthik.188@gmail.com","threadId":"41875","inReplyTo":"1459330800-12525-1-git-send-email-Karthik.188@gmail.com","subject":"[PATCH v3 12/16] ref-filter: add support for %(refname:dir) and %(refname:base)","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2016-03-30T09:39:56Z","receivedAt":"2016-03-30T09:39:56Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"Add the options `:dir` and `:base` to the %(refname) atom. The `:dir`\noption gives the directory (the part after $GIT_DIR/) of the ref without\nthe refname. The `:base` option gives the base directory of the given\nref (i.e. the directory following $GIT_DIR/refs/).\n\nAdd tests and documentation for the same.\n\nSigned-off-by: Karthik Nayak <Karthik.188@gmail.com>\n---\n Documentation/git-for-each-ref.txt |  4 +++-\n ref-filter.c                       | 28 +++++++++++++++++++++++++---\n t/t6300-for-each-ref.sh            |  2 ++\n 3 files changed, 30 insertions(+), 4 deletions(-)\n\ndiff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt\nindex be763c4..0d7d80f 100644\n--- a/Documentation/git-for-each-ref.txt\n+++ b/Documentation/git-for-each-ref.txt\n@@ -96,7 +96,9 @@ refname::\n \tslash-separated path components from the front of the refname\n \t(e.g., `%(refname:strip=2)` turns `refs/tags/foo` into `foo`.\n \t`<N>` must be a positive integer.  If a displayed ref has fewer\n-\tcomponents than `<N>`, the command aborts with an error.\n+\tcomponents than `<N>`, the command aborts with an error. For the base\n+\tdirectory of the ref (i.e. foo in refs/foo/bar/boz) append\n+\t`:base`. For the entire directory path append `:dir`.\n \n objecttype::\n \tThe type of the object (`blob`, `tree`, `commit`, `tag`).\ndiff --git a/ref-filter.c b/ref-filter.c\nindex dc1e404..73e0a7f 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -64,7 +64,7 @@ static struct used_atom {\n \t\t} objectname;\n \t\tenum { S_FULL, S_SHORT } symref;\n \t\tstruct {\n-\t\t\tenum { R_NORMAL, R_SHORT, R_STRIP } option;\n+\t\t\tenum { R_BASE, R_DIR, R_NORMAL, R_SHORT, R_STRIP } option;\n \t\t\tunsigned int strip;\n \t\t} refname;\n \t} u;\n@@ -243,7 +243,11 @@ static void refname_atom_parser(struct used_atom *atom, const char *arg)\n \t\tif (strtoul_ui(arg, 10, &atom->u.refname.strip) ||\n \t\t\tatom->u.refname.strip <= 0)\n \t\t\tdie(_(\"positive value expected refname:strip=%s\"), arg);\n-\t} else\n+\t} else if (!strcmp(arg, \"dir\"))\n+\t\tatom->u.contents.option = R_DIR;\n+\telse if (!strcmp(arg, \"base\"))\n+\t\tatom->u.contents.option = R_BASE;\n+\telse\n \t\tdie(_(\"unrecognized %%(refname) argument: %s\"), arg);\n }\n \n@@ -1175,7 +1179,25 @@ static const char *get_refname(struct used_atom *atom, struct ref_array_item *re\n \t\treturn shorten_unambiguous_ref(ref->refname, warn_ambiguous_refs);\n \telse if (atom->u.refname.option == R_STRIP)\n \t\treturn strip_ref_components(ref->refname, atom->u.refname.strip);\n-\telse\n+\telse if (atom->u.refname.option == R_BASE) {\n+\t\tconst char *sp, *ep;\n+\n+\t\tif (skip_prefix(ref->refname, \"refs/\", &sp)) {\n+\t\t\tep = strchr(sp, '/');\n+\t\t\tif (!ep)\n+\t\t\t\treturn \"\";\n+\t\t\treturn xstrndup(sp, ep - sp);\n+\t\t}\n+\t\treturn \"\";\n+\t} else if (atom->u.refname.option == R_DIR) {\n+\t\tconst char *sp, *ep;\n+\n+\t\tsp = ref->refname;\n+\t\tep = strrchr(sp, '/');\n+\t\tif (!ep)\n+\t\t\treturn \"\";\n+\t\treturn xstrndup(sp, ep - sp);\n+\t} else\n \t\treturn ref->refname;\n }\n \ndiff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh\nindex b06ea1c..36d32d7 100755\n--- a/t/t6300-for-each-ref.sh\n+++ b/t/t6300-for-each-ref.sh\n@@ -53,6 +53,8 @@ test_atom head refname refs/heads/master\n test_atom head refname:short master\n test_atom head refname:strip=1 heads/master\n test_atom head refname:strip=2 master\n+test_atom head refname:dir refs/heads\n+test_atom head refname:base heads\n test_atom head upstream refs/remotes/origin/master\n test_atom head upstream:short origin/master\n test_atom head push refs/remotes/myfork/master\n-- \n2.7.4\n"},{"id":"282219","messageId":"1459330800-12525-14-git-send-email-Karthik.188@gmail.com","threadId":"41875","inReplyTo":"1459330800-12525-1-git-send-email-Karthik.188@gmail.com","subject":"[PATCH v3 13/16] ref-filter: allow porcelain to translate messages in the output","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2016-03-30T09:39:57Z","receivedAt":"2016-03-30T09:39:57Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"Introduce setup_ref_filter_porcelain_msg() so that the messages used in\nthe atom %(upstream:track) can be translated if needed. This is needed\nas we port branch.c to use ref-filter's printing API's.\n\nWritten-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>\nSigned-off-by: Karthik Nayak <karthik.188@gmail.com>\n---\n ref-filter.c | 28 ++++++++++++++++++++++++----\n ref-filter.h |  2 ++\n 2 files changed, 26 insertions(+), 4 deletions(-)\n\ndiff --git a/ref-filter.c b/ref-filter.c\nindex 73e0a7f..3435df1 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -15,6 +15,26 @@\n #include \"version.h\"\n #include \"wt-status.h\"\n \n+static struct ref_msg {\n+\tconst char *gone;\n+\tconst char *ahead;\n+\tconst char *behind;\n+\tconst char *ahead_behind;\n+} msgs = {\n+\t\"gone\",\n+\t\"ahead %d\",\n+\t\"behind %d\",\n+\t\"ahead %d, behind %d\"\n+};\n+\n+void setup_ref_filter_porcelain_msg(void)\n+{\n+\tmsgs.gone = _(\"gone\");\n+\tmsgs.ahead = _(\"ahead %d\");\n+\tmsgs.behind = _(\"behind %d\");\n+\tmsgs.ahead_behind = _(\"ahead %d, behind %d\");\n+}\n+\n typedef enum { FIELD_STR, FIELD_ULONG, FIELD_TIME } cmp_type;\n \n struct align {\n@@ -1097,15 +1117,15 @@ static void fill_remote_ref_details(struct used_atom *atom, const char *refname,\n \telse if (atom->u.remote_ref.option == RR_TRACK) {\n \t\tif (stat_tracking_info(branch, &num_ours,\n \t\t\t\t       &num_theirs, NULL)) {\n-\t\t\t*s = xstrdup(\"gone\");\n+\t\t\t*s = xstrdup(msgs.gone);\n \t\t} else if (!num_ours && !num_theirs)\n \t\t\t*s = \"\";\n \t\telse if (!num_ours)\n-\t\t\t*s = xstrfmt(\"behind %d\", num_theirs);\n+\t\t\t*s = xstrfmt(msgs.behind, num_theirs);\n \t\telse if (!num_theirs)\n-\t\t\t*s = xstrfmt(\"ahead %d\", num_ours);\n+\t\t\t*s = xstrfmt(msgs.ahead, num_ours);\n \t\telse\n-\t\t\t*s = xstrfmt(\"ahead %d, behind %d\",\n+\t\t\t*s = xstrfmt(msgs.ahead_behind,\n \t\t\t\t     num_ours, num_theirs);\n \t\tif (!atom->u.remote_ref.nobracket && *s[0]) {\n \t\t\tconst char *to_free = *s;\ndiff --git a/ref-filter.h b/ref-filter.h\nindex 0014b92..da17145 100644\n--- a/ref-filter.h\n+++ b/ref-filter.h\n@@ -111,5 +111,7 @@ struct ref_sorting *ref_default_sorting(void);\n int parse_opt_merge_filter(const struct option *opt, const char *arg, int unset);\n /*  Get the current HEAD's description */\n char *get_head_description(void);\n+/*  Set up translated strings in the output. */\n+void setup_ref_filter_porcelain_msg(void);\n \n #endif /*  REF_FILTER_H  */\n-- \n2.7.4\n"},{"id":"282216","messageId":"1459330800-12525-15-git-send-email-Karthik.188@gmail.com","threadId":"41875","inReplyTo":"1459330800-12525-1-git-send-email-Karthik.188@gmail.com","subject":"[PATCH v3 14/16] branch, tag: use porcelain output","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2016-03-30T09:39:58Z","receivedAt":"2016-03-30T09:39:58Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"Call ref-filter's setup_ref_filter_porcelain_msg() to enable\ntranslated messages for the %(upstream:tack) atom. Although branch.c\ndoesn't currently use ref-filter's printing API's, this will ensure\nthat when it does in the future patches, we do not need to worry about\ntranslation.\n\nWritten-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>\nSigned-off-by: Karthik Nayak <karthik.188@gmail.com>\n---\n builtin/branch.c | 2 ++\n builtin/tag.c    | 2 ++\n 2 files changed, 4 insertions(+)\n\ndiff --git a/builtin/branch.c b/builtin/branch.c\nindex 460f32f..8747d82 100644\n--- a/builtin/branch.c\n+++ b/builtin/branch.c\n@@ -622,6 +622,8 @@ int cmd_branch(int argc, const char **argv, const char *prefix)\n \t\tOPT_END(),\n \t};\n \n+\tsetup_ref_filter_porcelain_msg();\n+\n \tmemset(&filter, 0, sizeof(filter));\n \tfilter.kind = FILTER_REFS_BRANCHES;\n \tfilter.abbrev = -1;\ndiff --git a/builtin/tag.c b/builtin/tag.c\nindex 1705c94..82a04ed 100644\n--- a/builtin/tag.c\n+++ b/builtin/tag.c\n@@ -373,6 +373,8 @@ int cmd_tag(int argc, const char **argv, const char *prefix)\n \t\tOPT_END()\n \t};\n \n+\tsetup_ref_filter_porcelain_msg();\n+\n \tgit_config(git_tag_config, sorting_tail);\n \n \tmemset(&opt, 0, sizeof(opt));\n-- \n2.7.4\n"},{"id":"282220","messageId":"1459330800-12525-16-git-send-email-Karthik.188@gmail.com","threadId":"41875","inReplyTo":"1459330800-12525-1-git-send-email-Karthik.188@gmail.com","subject":"[PATCH v3 15/16] branch: use ref-filter printing APIs","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2016-03-30T09:39:59Z","receivedAt":"2016-03-30T09:39:59Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"Port branch.c to use ref-filter APIs for printing. This clears out\nmost of the code used in branch.c for printing and replaces them with\ncalls made to the ref-filter library.\n\nIntroduce build_format() which gets the format required for printing\nof refs. Make amendments to print_ref_list() to reflect these changes.\n\nChange calc_maxwidth() to also account for the length of HEAD ref, by\ncalling ref-filter:get_head_discription().\n\nAlso change the test in t6040 to reflect the changes.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>\nSigned-off-by: Karthik Nayak <karthik.188@gmail.com>\n---\n builtin/branch.c         | 226 ++++++++++++++---------------------------------\n t/t6040-tracking-info.sh |   2 +-\n 2 files changed, 66 insertions(+), 162 deletions(-)\n\ndiff --git a/builtin/branch.c b/builtin/branch.c\nindex 8747d82..29cd206 100644\n--- a/builtin/branch.c\n+++ b/builtin/branch.c\n@@ -35,12 +35,12 @@ static unsigned char head_sha1[20];\n \n static int branch_use_color = -1;\n static char branch_colors[][COLOR_MAXLEN] = {\n-\tGIT_COLOR_RESET,\n-\tGIT_COLOR_NORMAL,\t/* PLAIN */\n-\tGIT_COLOR_RED,\t\t/* REMOTE */\n-\tGIT_COLOR_NORMAL,\t/* LOCAL */\n-\tGIT_COLOR_GREEN,\t/* CURRENT */\n-\tGIT_COLOR_BLUE,\t\t/* UPSTREAM */\n+\t\"%(color:reset)\",\n+\t\"%(color:reset)\",\t/* PLAIN */\n+\t\"%(color:red)\",\t\t/* REMOTE */\n+\t\"%(color:reset)\",\t/* LOCAL */\n+\t\"%(color:green)\",\t/* CURRENT */\n+\t\"%(color:blue)\",\t/* UPSTREAM */\n };\n enum color_branch {\n \tBRANCH_COLOR_RESET = 0,\n@@ -271,157 +271,6 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,\n \treturn(ret);\n }\n \n-static void fill_tracking_info(struct strbuf *stat, const char *branch_name,\n-\t\tint show_upstream_ref)\n-{\n-\tint ours, theirs;\n-\tchar *ref = NULL;\n-\tstruct branch *branch = branch_get(branch_name);\n-\tconst char *upstream;\n-\tstruct strbuf fancy = STRBUF_INIT;\n-\tint upstream_is_gone = 0;\n-\tint added_decoration = 1;\n-\n-\tif (stat_tracking_info(branch, &ours, &theirs, &upstream) < 0) {\n-\t\tif (!upstream)\n-\t\t\treturn;\n-\t\tupstream_is_gone = 1;\n-\t}\n-\n-\tif (show_upstream_ref) {\n-\t\tref = shorten_unambiguous_ref(upstream, 0);\n-\t\tif (want_color(branch_use_color))\n-\t\t\tstrbuf_addf(&fancy, \"%s%s%s\",\n-\t\t\t\t\tbranch_get_color(BRANCH_COLOR_UPSTREAM),\n-\t\t\t\t\tref, branch_get_color(BRANCH_COLOR_RESET));\n-\t\telse\n-\t\t\tstrbuf_addstr(&fancy, ref);\n-\t}\n-\n-\tif (upstream_is_gone) {\n-\t\tif (show_upstream_ref)\n-\t\t\tstrbuf_addf(stat, _(\"[%s: gone]\"), fancy.buf);\n-\t\telse\n-\t\t\tadded_decoration = 0;\n-\t} else if (!ours && !theirs) {\n-\t\tif (show_upstream_ref)\n-\t\t\tstrbuf_addf(stat, _(\"[%s]\"), fancy.buf);\n-\t\telse\n-\t\t\tadded_decoration = 0;\n-\t} else if (!ours) {\n-\t\tif (show_upstream_ref)\n-\t\t\tstrbuf_addf(stat, _(\"[%s: behind %d]\"), fancy.buf, theirs);\n-\t\telse\n-\t\t\tstrbuf_addf(stat, _(\"[behind %d]\"), theirs);\n-\n-\t} else if (!theirs) {\n-\t\tif (show_upstream_ref)\n-\t\t\tstrbuf_addf(stat, _(\"[%s: ahead %d]\"), fancy.buf, ours);\n-\t\telse\n-\t\t\tstrbuf_addf(stat, _(\"[ahead %d]\"), ours);\n-\t} else {\n-\t\tif (show_upstream_ref)\n-\t\t\tstrbuf_addf(stat, _(\"[%s: ahead %d, behind %d]\"),\n-\t\t\t\t    fancy.buf, ours, theirs);\n-\t\telse\n-\t\t\tstrbuf_addf(stat, _(\"[ahead %d, behind %d]\"),\n-\t\t\t\t    ours, theirs);\n-\t}\n-\tstrbuf_release(&fancy);\n-\tif (added_decoration)\n-\t\tstrbuf_addch(stat, ' ');\n-\tfree(ref);\n-}\n-\n-static void add_verbose_info(struct strbuf *out, struct ref_array_item *item,\n-\t\t\t     struct ref_filter *filter, const char *refname)\n-{\n-\tstruct strbuf subject = STRBUF_INIT, stat = STRBUF_INIT;\n-\tconst char *sub = _(\" **** invalid ref ****\");\n-\tstruct commit *commit = item->commit;\n-\n-\tif (!parse_commit(commit)) {\n-\t\tpp_commit_easy(CMIT_FMT_ONELINE, commit, &subject);\n-\t\tsub = subject.buf;\n-\t}\n-\n-\tif (item->kind == FILTER_REFS_BRANCHES)\n-\t\tfill_tracking_info(&stat, refname, filter->verbose > 1);\n-\n-\tstrbuf_addf(out, \" %s %s%s\",\n-\t\tfind_unique_abbrev(item->commit->object.oid.hash, filter->abbrev),\n-\t\tstat.buf, sub);\n-\tstrbuf_release(&stat);\n-\tstrbuf_release(&subject);\n-}\n-\n-static void format_and_print_ref_item(struct ref_array_item *item, int maxwidth,\n-\t\t\t\t      struct ref_filter *filter, const char *remote_prefix)\n-{\n-\tchar c;\n-\tint current = 0;\n-\tint color;\n-\tstruct strbuf out = STRBUF_INIT, name = STRBUF_INIT;\n-\tconst char *prefix = \"\";\n-\tconst char *desc = item->refname;\n-\tchar *to_free = NULL;\n-\n-\tswitch (item->kind) {\n-\tcase FILTER_REFS_BRANCHES:\n-\t\tskip_prefix(desc, \"refs/heads/\", &desc);\n-\t\tif (!filter->detached && !strcmp(desc, head))\n-\t\t\tcurrent = 1;\n-\t\telse\n-\t\t\tcolor = BRANCH_COLOR_LOCAL;\n-\t\tbreak;\n-\tcase FILTER_REFS_REMOTES:\n-\t\tskip_prefix(desc, \"refs/remotes/\", &desc);\n-\t\tcolor = BRANCH_COLOR_REMOTE;\n-\t\tprefix = remote_prefix;\n-\t\tbreak;\n-\tcase FILTER_REFS_DETACHED_HEAD:\n-\t\tdesc = to_free = get_head_description();\n-\t\tcurrent = 1;\n-\t\tbreak;\n-\tdefault:\n-\t\tcolor = BRANCH_COLOR_PLAIN;\n-\t\tbreak;\n-\t}\n-\n-\tc = ' ';\n-\tif (current) {\n-\t\tc = '*';\n-\t\tcolor = BRANCH_COLOR_CURRENT;\n-\t}\n-\n-\tstrbuf_addf(&name, \"%s%s\", prefix, desc);\n-\tif (filter->verbose) {\n-\t\tint utf8_compensation = strlen(name.buf) - utf8_strwidth(name.buf);\n-\t\tstrbuf_addf(&out, \"%c %s%-*s%s\", c, branch_get_color(color),\n-\t\t\t    maxwidth + utf8_compensation, name.buf,\n-\t\t\t    branch_get_color(BRANCH_COLOR_RESET));\n-\t} else\n-\t\tstrbuf_addf(&out, \"%c %s%s%s\", c, branch_get_color(color),\n-\t\t\t    name.buf, branch_get_color(BRANCH_COLOR_RESET));\n-\n-\tif (item->symref) {\n-\t\tskip_prefix(item->symref, \"refs/remotes/\", &desc);\n-\t\tstrbuf_addf(&out, \" -> %s\", desc);\n-\t}\n-\telse if (filter->verbose)\n-\t\t/* \" f7c0c00 [ahead 58, behind 197] vcs-svn: drop obj_pool.h\" */\n-\t\tadd_verbose_info(&out, item, filter, desc);\n-\tif (column_active(colopts)) {\n-\t\tassert(!filter->verbose && \"--column and --verbose are incompatible\");\n-\t\tstring_list_append(&output, out.buf);\n-\t} else {\n-\t\tprintf(\"%s\\n\", out.buf);\n-\t}\n-\tstrbuf_release(&name);\n-\tstrbuf_release(&out);\n-\tfree(to_free);\n-}\n-\n static int calc_maxwidth(struct ref_array *refs, int remote_bonus)\n {\n \tint i, max = 0;\n@@ -432,7 +281,10 @@ static int calc_maxwidth(struct ref_array *refs, int remote_bonus)\n \n \t\tskip_prefix(it->refname, \"refs/heads/\", &desc);\n \t\tskip_prefix(it->refname, \"refs/remotes/\", &desc);\n-\t\tw = utf8_strwidth(desc);\n+\t\tif (it->kind == FILTER_REFS_DETACHED_HEAD)\n+\t\t\tw = strlen(get_head_description());\n+\t\telse\n+\t\t\tw = utf8_strwidth(desc);\n \n \t\tif (it->kind == FILTER_REFS_REMOTES)\n \t\t\tw += remote_bonus;\n@@ -442,12 +294,51 @@ static int calc_maxwidth(struct ref_array *refs, int remote_bonus)\n \treturn max;\n }\n \n+static char *build_format(struct ref_filter *filter, int maxwidth, const char *remote_prefix)\n+{\n+\tstruct strbuf fmt = STRBUF_INIT;\n+\tstruct strbuf local = STRBUF_INIT;\n+\tstruct strbuf remote = STRBUF_INIT;\n+\n+\tstrbuf_addf(&fmt, \"%%(if)%%(HEAD)%%(then)* %s%%(else)  %%(end)\", branch_get_color(BRANCH_COLOR_CURRENT));\n+\n+\tif (filter->verbose) {\n+\t\tstrbuf_addf(&local, \"%%(align:%d,left)%%(refname:strip=2)%%(end)\", maxwidth);\n+\t\tstrbuf_addf(&local, \"%s\", branch_get_color(BRANCH_COLOR_RESET));\n+\t\tstrbuf_addf(&local, \" %%(objectname:short=7) \");\n+\n+\t\tif (filter->verbose > 1)\n+\t\t\tstrbuf_addf(&local, \"%%(if)%%(upstream)%%(then)[%s%%(upstream:short)%s%%(if)%%(upstream:track)\"\n+\t\t\t\t    \"%%(then): %%(upstream:track,nobracket)%%(end)] %%(end)%%(contents:subject)\",\n+\t\t\t\t    branch_get_color(BRANCH_COLOR_UPSTREAM), branch_get_color(BRANCH_COLOR_RESET));\n+\t\telse\n+\t\t\tstrbuf_addf(&local, \"%%(if)%%(upstream:track)%%(then)%%(upstream:track) %%(end)%%(contents:subject)\");\n+\n+\t\tstrbuf_addf(&remote, \"%s%%(align:%d,left)%s%%(refname:strip=2)%%(end)%s%%(if)%%(symref)%%(then) -> %%(symref:short)\"\n+\t\t\t    \"%%(else) %%(objectname:short=7) %%(contents:subject)%%(end)\",\n+\t\t\t    branch_get_color(BRANCH_COLOR_REMOTE), maxwidth,\n+\t\t\t    remote_prefix, branch_get_color(BRANCH_COLOR_RESET));\n+\t} else {\n+\t\tstrbuf_addf(&local, \"%%(refname:strip=2)%s\", branch_get_color(BRANCH_COLOR_RESET));\n+\t\tstrbuf_addf(&remote, \"%s%s%%(refname:strip=2)%s%%(if)%%(symref)%%(then) -> %%(symref:short)%%(end)\",\n+\t\t\t    branch_get_color(BRANCH_COLOR_REMOTE), remote_prefix, branch_get_color(BRANCH_COLOR_RESET));\n+\t}\n+\n+\tstrbuf_addf(&fmt, \"%%(if:notequals=remotes)%%(refname:base)%%(then)%s%%(else)%s%%(end)\", local.buf, remote.buf);\n+\n+\tstrbuf_release(&local);\n+\tstrbuf_release(&remote);\n+\treturn strbuf_detach(&fmt, NULL);\n+}\n+\n static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sorting)\n {\n \tint i;\n \tstruct ref_array array;\n \tint maxwidth = 0;\n \tconst char *remote_prefix = \"\";\n+\tstruct strbuf out = STRBUF_INIT;\n+\tchar *format;\n \n \t/*\n \t * If we are listing more than just remote branches,\n@@ -459,12 +350,14 @@ static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sortin\n \n \tmemset(&array, 0, sizeof(array));\n \n-\tverify_ref_format(\"%(refname)%(symref)\");\n \tfilter_refs(&array, filter, filter->kind | FILTER_REFS_INCLUDE_BROKEN);\n \n \tif (filter->verbose)\n \t\tmaxwidth = calc_maxwidth(&array, strlen(remote_prefix));\n \n+\tformat = build_format(filter, maxwidth, remote_prefix);\n+\tverify_ref_format(format);\n+\n \t/*\n \t * If no sorting parameter is given then we default to sorting\n \t * by 'refname'. This would give us an alphabetically sorted\n@@ -476,10 +369,21 @@ static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sortin\n \t\tsorting = ref_default_sorting();\n \tref_array_sort(sorting, &array);\n \n-\tfor (i = 0; i < array.nr; i++)\n-\t\tformat_and_print_ref_item(array.items[i], maxwidth, filter, remote_prefix);\n+\tfor (i = 0; i < array.nr; i++) {\n+\t\tformat_ref_array_item(array.items[i], format, 0, &out);\n+\t\tif (column_active(colopts)) {\n+\t\t\tassert(!filter->verbose && \"--column and --verbose are incompatible\");\n+\t\t\t /* format to a string_list to let print_columns() do its job */\n+\t\t\tstring_list_append(&output, out.buf);\n+\t\t} else {\n+\t\t\tfwrite(out.buf, 1, out.len, stdout);\n+\t\t\tputchar('\\n');\n+\t\t}\n+\t\tstrbuf_release(&out);\n+\t}\n \n \tref_array_clear(&array);\n+\tfree(format);\n }\n \n static void rename_branch(const char *oldname, const char *newname, int force)\ndiff --git a/t/t6040-tracking-info.sh b/t/t6040-tracking-info.sh\nindex 3d5c238..97a0765 100755\n--- a/t/t6040-tracking-info.sh\n+++ b/t/t6040-tracking-info.sh\n@@ -44,7 +44,7 @@ b1 [ahead 1, behind 1] d\n b2 [ahead 1, behind 1] d\n b3 [behind 1] b\n b4 [ahead 2] f\n-b5 g\n+b5 [gone] g\n b6 c\n EOF\n \n-- \n2.7.4\n"},{"id":"282217","messageId":"1459330800-12525-17-git-send-email-Karthik.188@gmail.com","threadId":"41875","inReplyTo":"1459330800-12525-1-git-send-email-Karthik.188@gmail.com","subject":"[PATCH v3 16/16] branch: implement '--format' option","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2016-03-30T09:40:00Z","receivedAt":"2016-03-30T09:40:00Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"Implement the '--format' option provided by 'ref-filter'. This lets the\nuser list branches as per desired format similar to the implementation\nin 'git for-each-ref'.\n\nAdd tests and documentation for the same.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>\nSigned-off-by: Karthik Nayak <karthik.188@gmail.com>\n---\n Documentation/git-branch.txt |  7 ++++++-\n builtin/branch.c             | 14 +++++++++-----\n t/t3203-branch-output.sh     | 12 ++++++++++++\n 3 files changed, 27 insertions(+), 6 deletions(-)\n\ndiff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt\nindex 4a7037f..8af132f 100644\n--- a/Documentation/git-branch.txt\n+++ b/Documentation/git-branch.txt\n@@ -12,7 +12,7 @@ SYNOPSIS\n \t[--list] [-v [--abbrev=<length> | --no-abbrev]]\n \t[--column[=<options>] | --no-column]\n \t[(--merged | --no-merged | --contains) [<commit>]] [--sort=<key>]\n-\t[--points-at <object>] [<pattern>...]\n+\t[--points-at <object>] [--format=<format>] [<pattern>...]\n 'git branch' [--set-upstream | --track | --no-track] [-l] [-f] <branchname> [<start-point>]\n 'git branch' (--set-upstream-to=<upstream> | -u <upstream>) [<branchname>]\n 'git branch' --unset-upstream [<branchname>]\n@@ -246,6 +246,11 @@ start-point is either a local or remote-tracking branch.\n --points-at <object>::\n \tOnly list branches of the given object.\n \n+--format <format>::\n+\tA string that interpolates `%(fieldname)` from the object\n+\tpointed at by a ref being shown.  The format is the same as\n+\tthat of linkgit:git-for-each-ref[1].\n+\n Examples\n --------\n \ndiff --git a/builtin/branch.c b/builtin/branch.c\nindex 29cd206..fb05b39 100644\n--- a/builtin/branch.c\n+++ b/builtin/branch.c\n@@ -27,6 +27,7 @@ static const char * const builtin_branch_usage[] = {\n \tN_(\"git branch [<options>] [-r] (-d | -D) <branch-name>...\"),\n \tN_(\"git branch [<options>] (-m | -M) [<old-branch>] <new-branch>\"),\n \tN_(\"git branch [<options>] [-r | -a] [--points-at]\"),\n+\tN_(\"git branch [<options>] [-r | -a] [--format]\"),\n \tNULL\n };\n \n@@ -331,14 +332,14 @@ static char *build_format(struct ref_filter *filter, int maxwidth, const char *r\n \treturn strbuf_detach(&fmt, NULL);\n }\n \n-static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sorting)\n+static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sorting, const char *format)\n {\n \tint i;\n \tstruct ref_array array;\n \tint maxwidth = 0;\n \tconst char *remote_prefix = \"\";\n \tstruct strbuf out = STRBUF_INIT;\n-\tchar *format;\n+\tchar *to_free = NULL;\n \n \t/*\n \t * If we are listing more than just remote branches,\n@@ -355,7 +356,8 @@ static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sortin\n \tif (filter->verbose)\n \t\tmaxwidth = calc_maxwidth(&array, strlen(remote_prefix));\n \n-\tformat = build_format(filter, maxwidth, remote_prefix);\n+\tif (!format)\n+\t\tformat = to_free = build_format(filter, maxwidth, remote_prefix);\n \tverify_ref_format(format);\n \n \t/*\n@@ -383,7 +385,7 @@ static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sortin\n \t}\n \n \tref_array_clear(&array);\n-\tfree(format);\n+\tfree(to_free);\n }\n \n static void rename_branch(const char *oldname, const char *newname, int force)\n@@ -483,6 +485,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)\n \tenum branch_track track;\n \tstruct ref_filter filter;\n \tstatic struct ref_sorting *sorting = NULL, **sorting_tail = &sorting;\n+\tconst char *format = NULL;\n \n \tstruct option options[] = {\n \t\tOPT_GROUP(N_(\"Generic options\")),\n@@ -523,6 +526,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)\n \t\t\tOPTION_CALLBACK, 0, \"points-at\", &filter.points_at, N_(\"object\"),\n \t\t\tN_(\"print only branches of the object\"), 0, parse_opt_object_name\n \t\t},\n+\t\tOPT_STRING(  0 , \"format\", &format, N_(\"format\"), N_(\"format to use for the output\")),\n \t\tOPT_END(),\n \t};\n \n@@ -583,7 +587,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)\n \t\tif ((filter.kind & FILTER_REFS_BRANCHES) && filter.detached)\n \t\t\tfilter.kind |= FILTER_REFS_DETACHED_HEAD;\n \t\tfilter.name_patterns = argv;\n-\t\tprint_ref_list(&filter, sorting);\n+\t\tprint_ref_list(&filter, sorting, format);\n \t\tprint_columns(&output, colopts, NULL);\n \t\tstring_list_clear(&output, 0);\n \t\treturn 0;\ndiff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh\nindex 4261403..c33a3f3 100755\n--- a/t/t3203-branch-output.sh\n+++ b/t/t3203-branch-output.sh\n@@ -184,4 +184,16 @@ test_expect_success 'ambiguous branch/tag not marked' '\n \ttest_cmp expect actual\n '\n \n+test_expect_success 'git branch --format option' '\n+\tcat >expect <<-\\EOF &&\n+\tRefname is (HEAD detached from fromtag)\n+\tRefname is refs/heads/ambiguous\n+\tRefname is refs/heads/branch-one\n+\tRefname is refs/heads/branch-two\n+\tRefname is refs/heads/master\n+\tEOF\n+\tgit branch --format=\"Refname is %(refname)\" >actual &&\n+\ttest_cmp expect actual\n+'\n+\n test_done\n-- \n2.7.4\n"},{"id":"282273","messageId":"xmqqa8lfsk5e.fsf@gitster.mtv.corp.google.com","threadId":"41875","inReplyTo":"1459330800-12525-14-git-send-email-Karthik.188@gmail.com","subject":"Re: [PATCH v3 13/16] ref-filter: allow porcelain to translate messages in the output","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-03-30T21:58:21Z","receivedAt":"2016-03-30T21:58:21Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Karthik Nayak <karthik.188@gmail.com> writes:\n\n> +static struct ref_msg {\n> +\tconst char *gone;\n> +\tconst char *ahead;\n> +\tconst char *behind;\n> +\tconst char *ahead_behind;\n> +} msgs = {\n> +\t\"gone\",\n> +\t\"ahead %d\",\n> +\t\"behind %d\",\n> +\t\"ahead %d, behind %d\"\n> +};\n> +\n> +void setup_ref_filter_porcelain_msg(void)\n> +{\n> +\tmsgs.gone = _(\"gone\");\n> +\tmsgs.ahead = _(\"ahead %d\");\n> +\tmsgs.behind = _(\"behind %d\");\n> +\tmsgs.ahead_behind = _(\"ahead %d, behind %d\");\n> +}\n\nI do not think this patch is wrong, but I wonder if it would be\nsufficient to have a single bit in file-scope static variable and\nflip it in setup_ref_filter_porcelain_msg().  I.e.\n\n\tstatic int use_porcelain_msg; /* false by default */\n\n        void setup_ref_filter_porcelain_msg(void)\n        {\n        \tuse_porcelain_msg = 1;\n\t}        \n\n        static const char *P_(const char *msg)\n        {\n                return use_porcelain_msg ? _(msg) : msg;\n\t}\n\nand then mark the message up perhaps like so:\n\n\t-\t*s = xstrdup(\"gone\");\n        +\t*s = xstrdup(P_(\"gone\"));\n\nwhich may make things much simpler.\n\nWe'd need to update Makefile to recognize X_() as another keyword;\nI'd think something like this should do:\n\n         XGETTEXT_FLAGS_C = $(XGETTEXT_FLAGS) --language=C \\\n        -        --keyword=_ --keyword=N_ --keyword=\"Q_:1,2\"\n\t+        --keyword=_ --keyword=N_ --keyword=P_ --keyword=\"Q_:1,2\"\n\n\n>  typedef enum { FIELD_STR, FIELD_ULONG, FIELD_TIME } cmp_type;\n>  \n>  struct align {\n> @@ -1097,15 +1117,15 @@ static void fill_remote_ref_details(struct used_atom *atom, const char *refname,\n>  \telse if (atom->u.remote_ref.option == RR_TRACK) {\n>  \t\tif (stat_tracking_info(branch, &num_ours,\n>  \t\t\t\t       &num_theirs, NULL)) {\n> -\t\t\t*s = xstrdup(\"gone\");\n> +\t\t\t*s = xstrdup(msgs.gone);\n>  \t\t} else if (!num_ours && !num_theirs)\n>  \t\t\t*s = \"\";\n>  \t\telse if (!num_ours)\n> -\t\t\t*s = xstrfmt(\"behind %d\", num_theirs);\n> +\t\t\t*s = xstrfmt(msgs.behind, num_theirs);\n>  \t\telse if (!num_theirs)\n> -\t\t\t*s = xstrfmt(\"ahead %d\", num_ours);\n> +\t\t\t*s = xstrfmt(msgs.ahead, num_ours);\n>  \t\telse\n> -\t\t\t*s = xstrfmt(\"ahead %d, behind %d\",\n> +\t\t\t*s = xstrfmt(msgs.ahead_behind,\n>  \t\t\t\t     num_ours, num_theirs);\n>  \t\tif (!atom->u.remote_ref.nobracket && *s[0]) {\n>  \t\t\tconst char *to_free = *s;\n> diff --git a/ref-filter.h b/ref-filter.h\n> index 0014b92..da17145 100644\n> --- a/ref-filter.h\n> +++ b/ref-filter.h\n> @@ -111,5 +111,7 @@ struct ref_sorting *ref_default_sorting(void);\n>  int parse_opt_merge_filter(const struct option *opt, const char *arg, int unset);\n>  /*  Get the current HEAD's description */\n>  char *get_head_description(void);\n> +/*  Set up translated strings in the output. */\n> +void setup_ref_filter_porcelain_msg(void);\n>  \n>  #endif /*  REF_FILTER_H  */\n"},{"id":"282274","messageId":"xmqq37r7sjhx.fsf@gitster.mtv.corp.google.com","threadId":"41875","inReplyTo":"1459330800-12525-3-git-send-email-Karthik.188@gmail.com","subject":"Re: [PATCH v3 02/16] ref-filter: include reference to 'used_atom' within 'atom_value'","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-03-30T22:12:26Z","receivedAt":"2016-03-30T22:12:26Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Karthik Nayak <karthik.188@gmail.com> writes:\n\n> Ensure that each 'atom_value' has a reference to its corresponding\n> 'used_atom'. This let's us use values within 'used_atom' in the\n> 'handler' function.\n>\n> Hence we can get the %(align) atom's parameters directly from the\n> 'used_atom' therefore removing the necessity of passing %(align) atom's\n> parameters to 'atom_value'.\n>\n> This also acts as a preparatory patch for the upcoming patch where we\n> introduce %(if:equals=) and %(if:notequals=).\n>\n> Signed-off-by: Karthik Nayak <Karthik.188@gmail.com>\n> ---\n>  ref-filter.c | 8 +++-----\n>  1 file changed, 3 insertions(+), 5 deletions(-)\n>\n> diff --git a/ref-filter.c b/ref-filter.c\n> index 41e73f0..12e646c 100644\n> --- a/ref-filter.c\n> +++ b/ref-filter.c\n> @@ -230,11 +230,9 @@ struct ref_formatting_state {\n>  \n>  struct atom_value {\n>  \tconst char *s;\n> -\tunion {\n> -\t\tstruct align align;\n> -\t} u;\n>  \tvoid (*handler)(struct atom_value *atomv, struct ref_formatting_state *state);\n>  \tunsigned long ul; /* used for sorting when not FIELD_STR */\n> +\tstruct used_atom *atom;\n>  };\n\nMakes sense, as this would make what 04/16 does clearer.\n"},{"id":"282275","messageId":"xmqqy48zr4r6.fsf@gitster.mtv.corp.google.com","threadId":"41875","inReplyTo":"1459330800-12525-6-git-send-email-Karthik.188@gmail.com","subject":"Re: [PATCH v3 05/16] ref-filter: move get_head_description() from branch.c","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-03-30T22:16:13Z","receivedAt":"2016-03-30T22:16:13Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Karthik Nayak <karthik.188@gmail.com> writes:\n\n> -static char *get_head_description(void)\n> -{\n> -\tstruct strbuf desc = STRBUF_INIT;\n> -\tstruct wt_status_state state;\n> -\tmemset(&state, 0, sizeof(state));\n> -\twt_status_get_state(&state, 1);\n> -\tif (state.rebase_in_progress ||\n> -\t    state.rebase_interactive_in_progress)\n> -\t\tstrbuf_addf(&desc, _(\"(no branch, rebasing %s)\"),\n> -\t\t\t    state.branch);\n> -\telse if (state.bisect_in_progress)\n> -\t\tstrbuf_addf(&desc, _(\"(no branch, bisect started on %s)\"),\n> -\t\t\t    state.branch);\n> -\telse if (state.detached_from) {\n> -\t\t/* TRANSLATORS: make sure these match _(\"HEAD detached at \")\n> -\t\t   and _(\"HEAD detached from \") in wt-status.c */\n> -\t\tif (state.detached_at)\n> -\t\t\tstrbuf_addf(&desc, _(\"(HEAD detached at %s)\"),\n> -\t\t\t\tstate.detached_from);\n> -\t\telse\n> -\t\t\tstrbuf_addf(&desc, _(\"(HEAD detached from %s)\"),\n> -\t\t\t\tstate.detached_from);\n> -\t}\n> -\telse\n> -\t\tstrbuf_addstr(&desc, _(\"(no branch)\"));\n> -\tfree(state.branch);\n> -\tfree(state.onto);\n> -\tfree(state.detached_from);\n> -\treturn strbuf_detach(&desc, NULL);\n> -}\n> -\n\nHmph, the name used to be a good one within the context of\nimplementation of \"git branch\" command, but I have to wonder if it\nis a specific enough name in the global context of the entire\nproject.  I also wondered if this sits better in wt-status.c;\ndoesn't \"git status\" do something similar?\n\nFor now, this should do, as I do not think of anything better.  \n\nThanks.\n"},{"id":"282276","messageId":"xmqqtwjnr4od.fsf@gitster.mtv.corp.google.com","threadId":"41875","inReplyTo":"1459330800-12525-10-git-send-email-Karthik.188@gmail.com","subject":"Re: [PATCH v3 09/16] ref-filter: make \"%(symref)\" atom work with the ':short' modifier","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-03-30T22:17:54Z","receivedAt":"2016-03-30T22:17:54Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Karthik Nayak <karthik.188@gmail.com> writes:\n\n> The \"%(symref)\" atom doesn't work when used with the ':short' modifier\n> because we strictly match only 'symref' for setting the 'need_symref'\n> indicator. Fix this by using comparing with valid_atom rather than used_atom.\n>\n> Add tests for %(symref) and %(symref:short) while we're here.\n>\n> Helped-by: Junio C Hamano <gitster@pobox.com>\n> Signed-off-by: Karthik Nayak <Karthik.188@gmail.com>\n> ---\n>  ref-filter.c            |  2 +-\n>  t/t6300-for-each-ref.sh | 24 ++++++++++++++++++++++++\n>  2 files changed, 25 insertions(+), 1 deletion(-)\n>\n> diff --git a/ref-filter.c b/ref-filter.c\n> index 8c97cdb..5c59b17 100644\n> --- a/ref-filter.c\n> +++ b/ref-filter.c\n> @@ -338,7 +338,7 @@ int parse_ref_filter_atom(const char *atom, const char *ep)\n>  \t\tvalid_atom[i].parser(&used_atom[at], arg);\n>  \tif (*atom == '*')\n>  \t\tneed_tagged = 1;\n> -\tif (!strcmp(used_atom[at].name, \"symref\"))\n> +\tif (!strcmp(valid_atom[i].name, \"symref\"))\n>  \t\tneed_symref = 1;\n>  \treturn at;\n>  }\n\nMakes perfect sense.\n\n> diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh\n> index 2c5f177..b06ea1c 100755\n> --- a/t/t6300-for-each-ref.sh\n> +++ b/t/t6300-for-each-ref.sh\n> @@ -38,6 +38,7 @@ test_atom() {\n>  \tcase \"$1\" in\n>  \t\thead) ref=refs/heads/master ;;\n>  \t\t tag) ref=refs/tags/testtag ;;\n> +\t\t sym) ref=refs/heads/sym ;;\n>  \t\t   *) ref=$1 ;;\n>  \tesac\n\nAn earlier review may have missed this, but I just noticed that the\nbody of this case/esac is over-indented.  Something we can fix later\nafter the dust settles.\n\n>  \tprintf '%s\\n' \"$3\" >expected\n> @@ -565,4 +566,27 @@ test_expect_success 'Verify sort with multiple keys' '\n>  \t\trefs/tags/bogo refs/tags/master > actual &&\n>  \ttest_cmp expected actual\n>  '\n> +\n> +test_expect_success 'Add symbolic ref for the following tests' '\n> +\tgit symbolic-ref refs/heads/sym refs/heads/master\n> +'\n> +\n> +cat >expected <<EOF\n> +refs/heads/master\n> +EOF\n> +\n> +test_expect_success 'Verify usage of %(symref) atom' '\n> +\tgit for-each-ref --format=\"%(symref)\" refs/heads/sym > actual &&\n> +\ttest_cmp expected actual\n> +'\n> +\n> +cat >expected <<EOF\n> +heads/master\n> +EOF\n> +\n> +test_expect_success 'Verify usage of %(symref:short) atom' '\n> +\tgit for-each-ref --format=\"%(symref:short)\" refs/heads/sym > actual &&\n> +\ttest_cmp expected actual\n> +'\n> +\n>  test_done\n"},{"id":"282277","messageId":"xmqqpoubr4md.fsf@gitster.mtv.corp.google.com","threadId":"41875","inReplyTo":"1459330800-12525-1-git-send-email-Karthik.188@gmail.com","subject":"Re: [PATCH v3 00/16] port branch.c to use ref-filter's printing options","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-03-30T22:19:06Z","receivedAt":"2016-03-30T22:19:06Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Karthik Nayak <karthik.188@gmail.com> writes:\n\n> I kinda waited before sending this, since there was lot of discussions\n> happening regarding to GSOC16, didn't want to clutter the mailing list.\n>\n> This is part of unification of the commands 'git tag -l, git branch -l\n> and git for-each-ref'. This ports over branch.c to use ref-filter's\n> printing options.\n\nOverall this was a very pleasant read (I had a few comments but\nnothing that would make the whole idea of the topic invalidated).\n\nThanks.\n"},{"id":"282457","messageId":"1459517477.3493.5.camel@kaarsemaker.net","threadId":"41875","inReplyTo":"1459330800-12525-1-git-send-email-Karthik.188@gmail.com","subject":"Re: [PATCH v3 00/16] port branch.c to use ref-filter's printing options","fromName":"Dennis Kaarsemaker","fromEmail":"dennis@kaarsemaker.net","sentAt":"2016-04-01T13:31:17Z","receivedAt":"2016-04-01T13:31:17Z","isPatch":true,"sender":{"key":"dennis@kaarsemaker.net","avatar":"https://avatars.githubusercontent.com/u/200649?v=4"},"body":"On wo, 2016-03-30 at 15:09 +0530, Karthik Nayak wrote:\n> \n> This is part of unification of the commands 'git tag -l, git branch -l\n> and git for-each-ref'. This ports over branch.c to use ref-filter's\n> printing options.\n> \n> Initially posted here: $(gmane/279226). It was decided that this series\n> would follow up after refactoring ref-filter parsing mechanism, which\n> is now merged into master (9606218b32344c5c756f7c29349d3845ef60b80c).\n\nInteraction between this series and something I've not yet been able to\nidentify seems to break t6302. In f08f64b (the merge commit that merges\nthis with pu), that test fails. But neither of its parents show the\nsame failure.\n\nFull log of a failing 'make && make test':\nhttps://ci.kaarsemaker.net/git/refs/heads/pu/718c0b31e51ab07181954fb5147e3283793553f4/artefact/test/log\n\nVerbose output of the failing test:\n\nexpecting success: \n\tgit for-each-ref --format=\"%(if)%(authorname)%(then)%(authorname): %(refname)%(end)\" >actual &&\n\tcat >expect <<-\\EOF &&\n\tA U Thor: refs/heads/master\n\tA U Thor: refs/heads/side\n\tA U Thor: refs/odd/spot\n\n\tA U Thor: refs/tags/foo1.10\n\tA U Thor: refs/tags/foo1.3\n\tA U Thor: refs/tags/foo1.6\n\tA U Thor: refs/tags/four\n\tA U Thor: refs/tags/one\n\n\tA U Thor: refs/tags/three\n\tA U Thor: refs/tags/two\n\tEOF\n\ttest_cmp expect actual\n\n--- expect\t2016-04-01 13:28:14.157855026 +0000\n+++ actual\t2016-04-01 13:28:14.153855026 +0000\n@@ -2,6 +2,8 @@\n A U Thor: refs/heads/side\n A U Thor: refs/odd/spot\n \n+\n+\n A U Thor: refs/tags/foo1.10\n A U Thor: refs/tags/foo1.3\n A U Thor: refs/tags/foo1.6\nnot ok 34 - check %(if)...%(then)...%(end) atoms\n#\t\n#\t\tgit for-each-ref --format=\"%(if)%(authorname)%(then)%(authorname): %(refname)%(end)\" >actual &&\n#\t\tcat >expect <<-\\EOF &&\n#\t\tA U Thor: refs/heads/master\n#\t\tA U Thor: refs/heads/side\n#\t\tA U Thor: refs/odd/spot\n#\t\n#\t\tA U Thor: refs/tags/foo1.10\n#\t\tA U Thor: refs/tags/foo1.3\n#\t\tA U Thor: refs/tags/foo1.6\n#\t\tA U Thor: refs/tags/four\n#\t\tA U Thor: refs/tags/one\n#\t\n#\t\tA U Thor: refs/tags/three\n#\t\tA U Thor: refs/tags/two\n#\t\tEOF\n#\t\ttest_cmp expect actual\n#\t\n\nexpecting success: \n\tgit for-each-ref --format=\"%(if)%(authorname)%(then)%(authorname)%(else)No author%(end): %(refname)\" >actual &&\n\tcat >expect <<-\\EOF &&\n\tA U Thor: refs/heads/master\n\tA U Thor: refs/heads/side\n\tA U Thor: refs/odd/spot\n\tNo author: refs/tags/double-tag\n\tA U Thor: refs/tags/foo1.10\n\tA U Thor: refs/tags/foo1.3\n\tA U Thor: refs/tags/foo1.6\n\tA U Thor: refs/tags/four\n\tA U Thor: refs/tags/one\n\tNo author: refs/tags/signed-tag\n\tA U Thor: refs/tags/three\n\tA U Thor: refs/tags/two\n\tEOF\n\ttest_cmp expect actual\n\n--- expect\t2016-04-01 13:28:14.161855026 +0000\n+++ actual\t2016-04-01 13:28:14.161855026 +0000\n@@ -1,7 +1,9 @@\n A U Thor: refs/heads/master\n A U Thor: refs/heads/side\n A U Thor: refs/odd/spot\n-No author: refs/tags/double-tag\n+No author: refs/tags/annotated-tag\n+No author: refs/tags/doubly-annotated-tag\n+No author: refs/tags/doubly-signed-tag\n A U Thor: refs/tags/foo1.10\n A U Thor: refs/tags/foo1.3\n A U Thor: refs/tags/foo1.6\nnot ok 35 - check %(if)...%(then)...%(else)...%(end) atoms\n#\t\n#\t\tgit for-each-ref --format=\"%(if)%(authorname)%(then)%(authorname)%(else)No author%(end): %(refname)\" >actual &&\n#\t\tcat >expect <<-\\EOF &&\n#\t\tA U Thor: refs/heads/master\n#\t\tA U Thor: refs/heads/side\n#\t\tA U Thor: refs/odd/spot\n#\t\tNo author: refs/tags/double-tag\n#\t\tA U Thor: refs/tags/foo1.10\n#\t\tA U Thor: refs/tags/foo1.3\n#\t\tA U Thor: refs/tags/foo1.6\n#\t\tA U Thor: refs/tags/four\n#\t\tA U Thor: refs/tags/one\n#\t\tNo author: refs/tags/signed-tag\n#\t\tA U Thor: refs/tags/three\n#\t\tA U Thor: refs/tags/two\n#\t\tEOF\n#\t\ttest_cmp expect actual\n#\t\n\nexpecting success: \n\tgit for-each-ref --format=\"%(refname:short): %(if)%(HEAD)%(then)Head ref%(else)Not Head ref%(end)\" >actual &&\n\tcat >expect <<-\\EOF &&\n\tmaster: Head ref\n\tside: Not Head ref\n\todd/spot: Not Head ref\n\tdouble-tag: Not Head ref\n\tfoo1.10: Not Head ref\n\tfoo1.3: Not Head ref\n\tfoo1.6: Not Head ref\n\tfour: Not Head ref\n\tone: Not Head ref\n\tsigned-tag: Not Head ref\n\tthree: Not Head ref\n\ttwo: Not Head ref\n\tEOF\n\ttest_cmp expect actual\n\n--- expect\t2016-04-01 13:28:14.165855026 +0000\n+++ actual\t2016-04-01 13:28:14.165855026 +0000\n@@ -1,7 +1,9 @@\n master: Head ref\n side: Not Head ref\n odd/spot: Not Head ref\n-double-tag: Not Head ref\n+annotated-tag: Not Head ref\n+doubly-annotated-tag: Not Head ref\n+doubly-signed-tag: Not Head ref\n foo1.10: Not Head ref\n foo1.3: Not Head ref\n foo1.6: Not Head ref\nnot ok 36 - ignore spaces in %(if) atom usage\n#\t\n#\t\tgit for-each-ref --format=\"%(refname:short): %(if)%(HEAD)%(then)Head ref%(else)Not Head ref%(end)\" >actual &&\n#\t\tcat >expect <<-\\EOF &&\n#\t\tmaster: Head ref\n#\t\tside: Not Head ref\n#\t\todd/spot: Not Head ref\n#\t\tdouble-tag: Not Head ref\n#\t\tfoo1.10: Not Head ref\n#\t\tfoo1.3: Not Head ref\n#\t\tfoo1.6: Not Head ref\n#\t\tfour: Not Head ref\n#\t\tone: Not Head ref\n#\t\tsigned-tag: Not Head ref\n#\t\tthree: Not Head ref\n#\t\ttwo: Not Head ref\n#\t\tEOF\n#\t\ttest_cmp expect actual\n#\t\n\n\n# failed 3 among 38 test(s)\n1..38\n-- \nDennis Kaarsemaker\nwww.kaarsemaker.net\n"},{"id":"282459","messageId":"20160401134435.GA16027@spirit","threadId":"41875","inReplyTo":"1459517477.3493.5.camel@kaarsemaker.net","subject":"Re: [PATCH v3 00/16] port branch.c to use ref-filter's printing options","fromName":"Dennis Kaarsemaker","fromEmail":"dennis@kaarsemaker.net","sentAt":"2016-04-01T13:44:36Z","receivedAt":"2016-04-01T13:44:36Z","isPatch":true,"sender":{"key":"dennis@kaarsemaker.net","avatar":"https://avatars.githubusercontent.com/u/200649?v=4"},"body":"On Fri, Apr 01, 2016 at 03:31:17PM +0200, Dennis Kaarsemaker wrote:\n> On wo, 2016-03-30 at 15:09 +0530, Karthik Nayak wrote:\n> > \n> > This is part of unification of the commands 'git tag -l, git branch -l\n> > and git for-each-ref'. This ports over branch.c to use ref-filter's\n> > printing options.\n> > \n> > Initially posted here: $(gmane/279226). It was decided that this series\n> > would follow up after refactoring ref-filter parsing mechanism, which\n> > is now merged into master (9606218b32344c5c756f7c29349d3845ef60b80c).\n> \n> Interaction between this series and something I've not yet been able to\n> identify\n\nThat someting is es/test-gpg-tags. Karthik, can you maybe squash this\nfix in if you do another reroll?\n\ndiff --git a/t/t6302-for-each-ref-filter.sh b/t/t6302-for-each-ref-filter.sh\nindex 98a1c49..7420e48 100755\n--- a/t/t6302-for-each-ref-filter.sh\n+++ b/t/t6302-for-each-ref-filter.sh\n@@ -349,6 +349,8 @@ test_expect_success 'check %(if)...%(then)...%(end) atoms' '\n \tA U Thor: refs/heads/side\n \tA U Thor: refs/odd/spot\n \n+\n+\n \tA U Thor: refs/tags/foo1.10\n \tA U Thor: refs/tags/foo1.3\n \tA U Thor: refs/tags/foo1.6\n@@ -367,7 +369,9 @@ test_expect_success 'check %(if)...%(then)...%(else)...%(end) atoms' '\n \tA U Thor: refs/heads/master\n \tA U Thor: refs/heads/side\n \tA U Thor: refs/odd/spot\n-\tNo author: refs/tags/double-tag\n+\tNo author: refs/tags/annotated-tag\n+\tNo author: refs/tags/doubly-annotated-tag\n+\tNo author: refs/tags/doubly-signed-tag\n \tA U Thor: refs/tags/foo1.10\n \tA U Thor: refs/tags/foo1.3\n \tA U Thor: refs/tags/foo1.6\n@@ -385,7 +389,9 @@ test_expect_success 'ignore spaces in %(if) atom usage' '\n \tmaster: Head ref\n \tside: Not Head ref\n \todd/spot: Not Head ref\n-\tdouble-tag: Not Head ref\n+\tannotated-tag: Not Head ref\n+\tdoubly-annotated-tag: Not Head ref\n+\tdoubly-signed-tag: Not Head ref\n \tfoo1.10: Not Head ref\n \tfoo1.3: Not Head ref\n \tfoo1.6: Not Head ref\n\n\n-- \nDennis Kaarsemaker <dennis@kaarsemaker.net>\n"},{"id":"282467","messageId":"56FE9099.3030004@ramsayjones.plus.com","threadId":"41875","inReplyTo":"20160401134435.GA16027@spirit","subject":"Re: [PATCH v3 00/16] port branch.c to use ref-filter's printing options","fromName":"Ramsay Jones","fromEmail":"ramsay@ramsayjones.plus.com","sentAt":"2016-04-01T15:15:37Z","receivedAt":"2016-04-01T15:15:37Z","isPatch":true,"sender":{"key":"ramsay@ramsayjones.plus.com","avatar":"https://avatars.githubusercontent.com/u/33702710?v=4"},"body":"\n\nOn 01/04/16 14:44, Dennis Kaarsemaker wrote:\n> On Fri, Apr 01, 2016 at 03:31:17PM +0200, Dennis Kaarsemaker wrote:\n>> On wo, 2016-03-30 at 15:09 +0530, Karthik Nayak wrote:\n>>>\n>>> This is part of unification of the commands 'git tag -l, git branch -l\n>>> and git for-each-ref'. This ports over branch.c to use ref-filter's\n>>> printing options.\n>>>\n>>> Initially posted here: $(gmane/279226). It was decided that this series\n>>> would follow up after refactoring ref-filter parsing mechanism, which\n>>> is now merged into master (9606218b32344c5c756f7c29349d3845ef60b80c).\n>>\n>> Interaction between this series and something I've not yet been able to\n>> identify\n> \n> That someting is es/test-gpg-tags. Karthik, can you maybe squash this\n> fix in if you do another reroll?\n\nYes, I sent the same patch to Karthik yesterday. Unfortunately, I didn't\nsend it as a response to this email thread, so it may have been hard to\nspot on the mailing list. My bad. Sorry for wasting your time. :(\n\nATB,\nRamsay Jones\n\n\n> \n> diff --git a/t/t6302-for-each-ref-filter.sh b/t/t6302-for-each-ref-filter.sh\n> index 98a1c49..7420e48 100755\n> --- a/t/t6302-for-each-ref-filter.sh\n> +++ b/t/t6302-for-each-ref-filter.sh\n> @@ -349,6 +349,8 @@ test_expect_success 'check %(if)...%(then)...%(end) atoms' '\n>  \tA U Thor: refs/heads/side\n>  \tA U Thor: refs/odd/spot\n>  \n> +\n> +\n>  \tA U Thor: refs/tags/foo1.10\n>  \tA U Thor: refs/tags/foo1.3\n>  \tA U Thor: refs/tags/foo1.6\n> @@ -367,7 +369,9 @@ test_expect_success 'check %(if)...%(then)...%(else)...%(end) atoms' '\n>  \tA U Thor: refs/heads/master\n>  \tA U Thor: refs/heads/side\n>  \tA U Thor: refs/odd/spot\n> -\tNo author: refs/tags/double-tag\n> +\tNo author: refs/tags/annotated-tag\n> +\tNo author: refs/tags/doubly-annotated-tag\n> +\tNo author: refs/tags/doubly-signed-tag\n>  \tA U Thor: refs/tags/foo1.10\n>  \tA U Thor: refs/tags/foo1.3\n>  \tA U Thor: refs/tags/foo1.6\n> @@ -385,7 +389,9 @@ test_expect_success 'ignore spaces in %(if) atom usage' '\n>  \tmaster: Head ref\n>  \tside: Not Head ref\n>  \todd/spot: Not Head ref\n> -\tdouble-tag: Not Head ref\n> +\tannotated-tag: Not Head ref\n> +\tdoubly-annotated-tag: Not Head ref\n> +\tdoubly-signed-tag: Not Head ref\n>  \tfoo1.10: Not Head ref\n>  \tfoo1.3: Not Head ref\n>  \tfoo1.6: Not Head ref\n> \n> \n"},{"id":"282494","messageId":"CAOLa=ZSCFt-HMR6B9S5-ci=79_uDXu92+k_Nd+6zrSW11KTXCw@mail.gmail.com","threadId":"41875","inReplyTo":"xmqqtwjnr4od.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v3 09/16] ref-filter: make \"%(symref)\" atom work with the ':short' modifier","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2016-04-01T18:13:41Z","receivedAt":"2016-04-01T18:13:41Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"On Thu, Mar 31, 2016 at 3:47 AM, Junio C Hamano <gitster@pobox.com> wrote:\n> Karthik Nayak <karthik.188@gmail.com> writes:\n>\n>> The \"%(symref)\" atom doesn't work when used with the ':short' modifier\n>> because we strictly match only 'symref' for setting the 'need_symref'\n>> indicator. Fix this by using comparing with valid_atom rather than used_atom.\n>>\n>> Add tests for %(symref) and %(symref:short) while we're here.\n>>\n>> Helped-by: Junio C Hamano <gitster@pobox.com>\n>> Signed-off-by: Karthik Nayak <Karthik.188@gmail.com>\n>> ---\n>>  ref-filter.c            |  2 +-\n>>  t/t6300-for-each-ref.sh | 24 ++++++++++++++++++++++++\n>>  2 files changed, 25 insertions(+), 1 deletion(-)\n>>\n>> diff --git a/ref-filter.c b/ref-filter.c\n>> index 8c97cdb..5c59b17 100644\n>> --- a/ref-filter.c\n>> +++ b/ref-filter.c\n>> @@ -338,7 +338,7 @@ int parse_ref_filter_atom(const char *atom, const char *ep)\n>>               valid_atom[i].parser(&used_atom[at], arg);\n>>       if (*atom == '*')\n>>               need_tagged = 1;\n>> -     if (!strcmp(used_atom[at].name, \"symref\"))\n>> +     if (!strcmp(valid_atom[i].name, \"symref\"))\n>>               need_symref = 1;\n>>       return at;\n>>  }\n>\n> Makes perfect sense.\n>\n>> diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh\n>> index 2c5f177..b06ea1c 100755\n>> --- a/t/t6300-for-each-ref.sh\n>> +++ b/t/t6300-for-each-ref.sh\n>> @@ -38,6 +38,7 @@ test_atom() {\n>>       case \"$1\" in\n>>               head) ref=refs/heads/master ;;\n>>                tag) ref=refs/tags/testtag ;;\n>> +              sym) ref=refs/heads/sym ;;\n>>                  *) ref=$1 ;;\n>>       esac\n>\n> An earlier review may have missed this, but I just noticed that the\n> body of this case/esac is over-indented.  Something we can fix later\n> after the dust settles.\n>\n\nSince I'll be re-rolling, I'll fix it :)\n\n-- \nRegards,\nKarthik Nayak\n"},{"id":"282495","messageId":"CAOLa=ZSs3ZUysusArNK8oXSe7jqqquJyx4=ZtNyqmDsm_iAguQ@mail.gmail.com","threadId":"41875","inReplyTo":"xmqqy48zr4r6.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v3 05/16] ref-filter: move get_head_description() from branch.c","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2016-04-01T18:41:55Z","receivedAt":"2016-04-01T18:41:55Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"On Thu, Mar 31, 2016 at 3:46 AM, Junio C Hamano <gitster@pobox.com> wrote:\n> Karthik Nayak <karthik.188@gmail.com> writes:\n>\n>> -static char *get_head_description(void)\n>> -{\n>> -     struct strbuf desc = STRBUF_INIT;\n>> -     struct wt_status_state state;\n>> -     memset(&state, 0, sizeof(state));\n>> -     wt_status_get_state(&state, 1);\n>> -     if (state.rebase_in_progress ||\n>> -         state.rebase_interactive_in_progress)\n>> -             strbuf_addf(&desc, _(\"(no branch, rebasing %s)\"),\n>> -                         state.branch);\n>> -     else if (state.bisect_in_progress)\n>> -             strbuf_addf(&desc, _(\"(no branch, bisect started on %s)\"),\n>> -                         state.branch);\n>> -     else if (state.detached_from) {\n>> -             /* TRANSLATORS: make sure these match _(\"HEAD detached at \")\n>> -                and _(\"HEAD detached from \") in wt-status.c */\n>> -             if (state.detached_at)\n>> -                     strbuf_addf(&desc, _(\"(HEAD detached at %s)\"),\n>> -                             state.detached_from);\n>> -             else\n>> -                     strbuf_addf(&desc, _(\"(HEAD detached from %s)\"),\n>> -                             state.detached_from);\n>> -     }\n>> -     else\n>> -             strbuf_addstr(&desc, _(\"(no branch)\"));\n>> -     free(state.branch);\n>> -     free(state.onto);\n>> -     free(state.detached_from);\n>> -     return strbuf_detach(&desc, NULL);\n>> -}\n>> -\n>\n> Hmph, the name used to be a good one within the context of\n> implementation of \"git branch\" command, but I have to wonder if it\n> is a specific enough name in the global context of the entire\n> project.  I also wondered if this sits better in wt-status.c;\n> doesn't \"git status\" do something similar?\n>\n\nYes, `wt_status_print(struct wt_status *s)` pretty much does the same, maybe\nwe can eventually lose this in favor of using that.\n\n> For now, this should do, as I do not think of anything better.\n>\n> Thanks.\n\nSure.\n\n-- \nRegards,\nKarthik Nayak\n"},{"id":"282496","messageId":"CAOLa=ZQjxmVHuXc0fZioe9OLi9vjNwgHQq-8vf1opWxbuedM9Q@mail.gmail.com","threadId":"41875","inReplyTo":"xmqqa8lfsk5e.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v3 13/16] ref-filter: allow porcelain to translate messages in the output","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2016-04-01T19:00:27Z","receivedAt":"2016-04-01T19:00:27Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"cc'ing Matthieu since this patch was initially written by him.\n\nOn Thu, Mar 31, 2016 at 3:28 AM, Junio C Hamano <gitster@pobox.com> wrote:\n> Karthik Nayak <karthik.188@gmail.com> writes:\n>\n>> +static struct ref_msg {\n>> +     const char *gone;\n>> +     const char *ahead;\n>> +     const char *behind;\n>> +     const char *ahead_behind;\n>> +} msgs = {\n>> +     \"gone\",\n>> +     \"ahead %d\",\n>> +     \"behind %d\",\n>> +     \"ahead %d, behind %d\"\n>> +};\n>> +\n>> +void setup_ref_filter_porcelain_msg(void)\n>> +{\n>> +     msgs.gone = _(\"gone\");\n>> +     msgs.ahead = _(\"ahead %d\");\n>> +     msgs.behind = _(\"behind %d\");\n>> +     msgs.ahead_behind = _(\"ahead %d, behind %d\");\n>> +}\n>\n> I do not think this patch is wrong, but I wonder if it would be\n> sufficient to have a single bit in file-scope static variable and\n> flip it in setup_ref_filter_porcelain_msg().  I.e.\n>\n>         static int use_porcelain_msg; /* false by default */\n>\n>         void setup_ref_filter_porcelain_msg(void)\n>         {\n>                 use_porcelain_msg = 1;\n>         }\n>\n>         static const char *P_(const char *msg)\n>         {\n>                 return use_porcelain_msg ? _(msg) : msg;\n>         }\n>\n> and then mark the message up perhaps like so:\n>\n>         -       *s = xstrdup(\"gone\");\n>         +       *s = xstrdup(P_(\"gone\"));\n>\n> which may make things much simpler.\n>\n> We'd need to update Makefile to recognize X_() as another keyword;\n> I'd think something like this should do:\n>\n>          XGETTEXT_FLAGS_C = $(XGETTEXT_FLAGS) --language=C \\\n>         -        --keyword=_ --keyword=N_ --keyword=\"Q_:1,2\"\n>         +        --keyword=_ --keyword=N_ --keyword=P_ --keyword=\"Q_:1,2\"\n>\n>\n>>  typedef enum { FIELD_STR, FIELD_ULONG, FIELD_TIME } cmp_type;\n>>\n>>  struct align {\n>> @@ -1097,15 +1117,15 @@ static void fill_remote_ref_details(struct used_atom *atom, const char *refname,\n>>       else if (atom->u.remote_ref.option == RR_TRACK) {\n>>               if (stat_tracking_info(branch, &num_ours,\n>>                                      &num_theirs, NULL)) {\n>> -                     *s = xstrdup(\"gone\");\n>> +                     *s = xstrdup(msgs.gone);\n>>               } else if (!num_ours && !num_theirs)\n>>                       *s = \"\";\n>>               else if (!num_ours)\n>> -                     *s = xstrfmt(\"behind %d\", num_theirs);\n>> +                     *s = xstrfmt(msgs.behind, num_theirs);\n>>               else if (!num_theirs)\n>> -                     *s = xstrfmt(\"ahead %d\", num_ours);\n>> +                     *s = xstrfmt(msgs.ahead, num_ours);\n>>               else\n>> -                     *s = xstrfmt(\"ahead %d, behind %d\",\n>> +                     *s = xstrfmt(msgs.ahead_behind,\n>>                                    num_ours, num_theirs);\n>>               if (!atom->u.remote_ref.nobracket && *s[0]) {\n>>                       const char *to_free = *s;\n>> diff --git a/ref-filter.h b/ref-filter.h\n>> index 0014b92..da17145 100644\n>> --- a/ref-filter.h\n>> +++ b/ref-filter.h\n>> @@ -111,5 +111,7 @@ struct ref_sorting *ref_default_sorting(void);\n>>  int parse_opt_merge_filter(const struct option *opt, const char *arg, int unset);\n>>  /*  Get the current HEAD's description */\n>>  char *get_head_description(void);\n>> +/*  Set up translated strings in the output. */\n>> +void setup_ref_filter_porcelain_msg(void);\n>>\n>>  #endif /*  REF_FILTER_H  */\n\nI'm not totally knowledgeable  about how porcelain works, although\nMatthieu did give me a\nbrief explanation. I guess it'd better to hear his thoughts on this.\nFor me both the current patch\nand your suggestion, seem good to go.\n\n-- \nRegards,\nKarthik Nayak\n"},{"id":"282501","messageId":"CAOLa=ZRHap6C016zKvnWGy7A4OPx2zcSAeT+KYjytetQocPx-w@mail.gmail.com","threadId":"41875","inReplyTo":"56FE9099.3030004@ramsayjones.plus.com","subject":"Re: [PATCH v3 00/16] port branch.c to use ref-filter's printing options","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2016-04-01T19:42:46Z","receivedAt":"2016-04-01T19:42:46Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"On Fri, Apr 1, 2016 at 8:45 PM, Ramsay Jones\n<ramsay@ramsayjones.plus.com> wrote:\n>\n>\n> On 01/04/16 14:44, Dennis Kaarsemaker wrote:\n>> On Fri, Apr 01, 2016 at 03:31:17PM +0200, Dennis Kaarsemaker wrote:\n>>> On wo, 2016-03-30 at 15:09 +0530, Karthik Nayak wrote:\n>>>>\n>>>> This is part of unification of the commands 'git tag -l, git branch -l\n>>>> and git for-each-ref'. This ports over branch.c to use ref-filter's\n>>>> printing options.\n>>>>\n>>>> Initially posted here: $(gmane/279226). It was decided that this series\n>>>> would follow up after refactoring ref-filter parsing mechanism, which\n>>>> is now merged into master (9606218b32344c5c756f7c29349d3845ef60b80c).\n>>>\n>>> Interaction between this series and something I've not yet been able to\n>>> identify\n>>\n>> That someting is es/test-gpg-tags. Karthik, can you maybe squash this\n>> fix in if you do another reroll?\n>\n> Yes, I sent the same patch to Karthik yesterday. Unfortunately, I didn't\n> send it as a response to this email thread, so it may have been hard to\n> spot on the mailing list. My bad. Sorry for wasting your time. :(\n>\n> ATB,\n> Ramsay Jones\n>\n\nThanks to both of you, it seems that I hadn't rebased my work on Eric's patches\n($gmane/288371). Thanks for reporting, I'll fix and reroll.\n\n-- \nRegards,\nKarthik Nayak\n"},{"id":"282605","messageId":"vpqa8l9ztmd.fsf@anie.imag.fr","threadId":"41875","inReplyTo":"CAOLa=ZQjxmVHuXc0fZioe9OLi9vjNwgHQq-8vf1opWxbuedM9Q@mail.gmail.com","subject":"Re: [PATCH v3 13/16] ref-filter: allow porcelain to translate messages in the output","fromName":"Matthieu Moy","fromEmail":"matthieu.moy@grenoble-inp.fr","sentAt":"2016-04-04T08:05:30Z","receivedAt":"2016-04-04T08:05:30Z","isPatch":true,"sender":{"key":"matthieu.moy@grenoble-inp.fr","avatar":"https://gravatar.com/avatar/72c8a2705971a25dfaff23cece15130d405685845d911aedd5667ace277f3fc5?d=mp&s=160"},"body":"Karthik Nayak <karthik.188@gmail.com> writes:\n\n> cc'ing Matthieu since this patch was initially written by him.\n>\n> On Thu, Mar 31, 2016 at 3:28 AM, Junio C Hamano <gitster@pobox.com> wrote:\n>> Karthik Nayak <karthik.188@gmail.com> writes:\n>>\n>>> +static struct ref_msg {\n>>> +     const char *gone;\n>>> +     const char *ahead;\n>>> +     const char *behind;\n>>> +     const char *ahead_behind;\n>>> +} msgs = {\n>>> +     \"gone\",\n>>> +     \"ahead %d\",\n>>> +     \"behind %d\",\n>>> +     \"ahead %d, behind %d\"\n>>> +};\n>>> +\n>>> +void setup_ref_filter_porcelain_msg(void)\n>>> +{\n>>> +     msgs.gone = _(\"gone\");\n>>> +     msgs.ahead = _(\"ahead %d\");\n>>> +     msgs.behind = _(\"behind %d\");\n>>> +     msgs.ahead_behind = _(\"ahead %d, behind %d\");\n>>> +}\n>>\n>> I do not think this patch is wrong, but I wonder if it would be\n>> sufficient to have a single bit in file-scope static variable and\n>> flip it in setup_ref_filter_porcelain_msg().  I.e.\n>>\n>>         static int use_porcelain_msg; /* false by default */\n>>\n>>         void setup_ref_filter_porcelain_msg(void)\n>>         {\n>>                 use_porcelain_msg = 1;\n>>         }\n>>\n>>         static const char *P_(const char *msg)\n>>         {\n>>                 return use_porcelain_msg ? _(msg) : msg;\n>>         }\n>>\n>> and then mark the message up perhaps like so:\n>>\n>>         -       *s = xstrdup(\"gone\");\n>>         +       *s = xstrdup(P_(\"gone\"));\n>>\n>> which may make things much simpler.\n\n... but less evolutive. The non-translatable strings also need to be\ncast in stone, while the translatable ones may be subject to future\nimprovements/tweaks. If they are already duplicated in the code, then\nupdating one won't change the other, but factoring them means that the\nporcelain message can't easily be changed without modifying the plumbing\none.\n\nI'm not sure how important it is in this case, but it was in the case of\nsetup_unpack_trees_porcelain which I took inspiration from when we\ndiscussed this (actually, in setup_unpack_trees_porcelain, there's isn't\nany translation even in porcelain).\n\nNote that this can be worked around later by adding another function like\n\n        static const char *get_message(const char *porcelain, const char *plumbing)\n        {\n                return use_porcelain_msg ? porcelain : plumbing;\n        }\n\nto be called with get_message(_(\"this ref was gone\"), \"gone\") or so.\n\n>> We'd need to update Makefile to recognize X_() as another keyword;\n\n(I guess you meant P_, not X_)\n\n>> I'd think something like this should do:\n>>\n>>          XGETTEXT_FLAGS_C = $(XGETTEXT_FLAGS) --language=C \\\n>>         -        --keyword=_ --keyword=N_ --keyword=\"Q_:1,2\"\n>>         +        --keyword=_ --keyword=N_ --keyword=P_ --keyword=\"Q_:1,2\"\n\nI'm a bit reluctant to modifying the Makefile for something not really\nbuild-related.\n\n> I'm not totally knowledgeable  about how porcelain works, although\n> Matthieu did give me a\n> brief explanation. I guess it'd better to hear his thoughts on this.\n\nIn summary: both would work. No strong opinion from me, but I slightly\nprefer the version in the patch (i.e. the one I suggested IIRC) to\nJunio's version.\n\n-- \nMatthieu Moy\nhttp://www-verimag.imag.fr/~moy/\n"},{"id":"282617","messageId":"xmqq7fgd73pj.fsf@gitster.mtv.corp.google.com","threadId":"41875","inReplyTo":"vpqa8l9ztmd.fsf@anie.imag.fr","subject":"Re: [PATCH v3 13/16] ref-filter: allow porcelain to translate messages in the output","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-04-04T16:12:40Z","receivedAt":"2016-04-04T16:12:40Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Matthieu Moy <Matthieu.Moy@grenoble-inp.fr> writes:\n\n> I'm not sure how important it is in this case, but it was in the case of\n> setup_unpack_trees_porcelain which I took inspiration from when we\n> discussed this (actually, in setup_unpack_trees_porcelain, there's isn't\n> any translation even in porcelain).\n\nOK, so paraphrase:\n\nIn the most general case, we might want to have one code to issue\ndifferent messages between plumbing and Porcelain; further, for\nPorcelain messages may or may not want to be translated.\n\nBut I suspect that all Porcelain messages should be translatable\nin general, so there probably is a room for simplification.\n\nThe single macro P_() approach was done without knowing that this\ncodepath wanted the distinction between the plumbing and Porcelain.\n\n> Note that this can be worked around later by adding another function like\n>\n>         static const char *get_message(const char *porcelain, const char *plumbing)\n>         {\n>                 return use_porcelain_msg ? porcelain : plumbing;\n>         }\n>\n> to be called with get_message(_(\"this ref was gone\"), \"gone\") or so.\n\nYes, I think that would be a way to do this properly.  And we do not\nhave a separate \"here is the list of all translatable messages\"\ntable, which is a big plus.\n\n> In summary: both would work. No strong opinion from me, but I slightly\n> prefer the version in the patch (i.e. the one I suggested IIRC) to\n> Junio's version.\n\nYup.\n"}]}