{"thread":{"id":"40156","subject":"[PATCH v3 1/8] branch: refactor width computation","startedAt":"2015-08-22T06:51:41Z","lastAt":"2015-08-24T18:10:37Z","messageCount":13,"participants":["Karthik Nayak","Christian Couder","Junio C Hamano"],"isPatch":true,"patchVersion":3,"patchTotal":8},"messages":[{"id":"268499","messageId":"1440226309-25415-1-git-send-email-Karthik.188@gmail.com","threadId":"40156","inReplyTo":null,"subject":"[PATCH v3 0/8] port the filtering part of ref-filter to branch.c","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-08-22T06:51:41Z","receivedAt":"2015-08-22T06:51:41Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"This is a follow up to porting tag.c to use ref-fitler APIs.\n\nv2 of this patch series can be found here:\nhttp://thread.gmane.org/gmane.comp.version-control.git/276147\n\nChanges made in this series:\n* Improve comment in 3/8 and fix grammar in 5/8.\n* Fix the test in t1430 to check stderr for the broken ref warning.\n* Instead of showing the detached head, reducing the no of array elements\nand displaying all of the other refs and then free'ing all of the refs. We\nnow free the detached head ref immediately after displaying so we don't have\nto bother about decrementing and incrementing the no of array elements.\n* \n\nKarthik Nayak (8):\n  branch: refactor width computation\n  branch: bump get_head_description() to the top\n  branch: roll show_detached HEAD into regular ref_list\n  branch: move 'current' check down to the presentation layer\n  branch: drop non-commit error reporting\n  branch.c: use 'ref-filter' data structures\n  branch.c: use 'ref-filter' APIs\n  branch: add '--points-at' option\n\n Documentation/git-branch.txt |  13 +-\n builtin/branch.c             | 506 +++++++++++++------------------------------\n ref-filter.c                 |   4 +-\n ref-filter.h                 |   8 +-\n t/t1430-bad-ref-name.sh      |   2 +-\n t/t3203-branch-output.sh     |  20 ++\n 6 files changed, 197 insertions(+), 356 deletions(-)\n\nInterdiff:\n\ndiff --git a/builtin/branch.c b/builtin/branch.c\nindex dd2fdbe..32a0d11 100644\n--- a/builtin/branch.c\n+++ b/builtin/branch.c\n@@ -475,7 +475,7 @@ static int calc_maxwidth(struct ref_array *refs, int remote_bonus)\n \n static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sorting)\n {\n-\tint i, index;\n+\tint i;\n \tstruct ref_array array;\n \tint maxwidth = 0;\n \tconst char *remote_prefix = \"\";\n@@ -493,17 +493,16 @@ static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sortin\n \tmemset(&array, 0, sizeof(array));\n \n \tverify_ref_format(\"%(refname)%(symref)\");\n-\tfilter_refs(&array, filter, filter->kind);\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-\tindex = array.nr;\n-\n \t/* Print detached HEAD before sorting and printing the rest */\n \tif (filter->kind & FILTER_REFS_DETACHED_HEAD) {\n-\t\tformat_and_print_ref_item(array.items[index - 1], maxwidth, filter, remote_prefix);\n-\t\tarray.nr -= 1;\n+\t\tformat_and_print_ref_item(array.items[array.nr - 1], maxwidth, filter, remote_prefix);\n+\t\tfree_array_item(array.items[array.nr - 1]);\n+\t\tarray.nr--;\n \t}\n \n \tif (!sorting) {\n@@ -517,7 +516,6 @@ static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sortin\n \tfor (i = 0; i < array.nr; i++)\n \t\tformat_and_print_ref_item(array.items[i], maxwidth, filter, remote_prefix);\n \n-\tarray.nr = index;\n \tref_array_clear(&array);\n }\n \ndiff --git a/ref-filter.c b/ref-filter.c\nindex 112feaa..3cd0c00 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -1251,7 +1251,7 @@ static int ref_filter_handler(const char *refname, const struct object_id *oid,\n }\n \n /*  Free memory allocated for a ref_array_item */\n-static void free_array_item(struct ref_array_item *item)\n+void free_array_item(struct ref_array_item *item)\n {\n \tfree((char *)item->symref);\n \tfree(item);\ndiff --git a/ref-filter.h b/ref-filter.h\nindex 3e29e5d..3e25d84 100644\n--- a/ref-filter.h\n+++ b/ref-filter.h\n@@ -89,6 +89,8 @@ struct ref_filter_cbdata {\n  * filtered refs in the ref_array structure.\n  */\n int filter_refs(struct ref_array *array, struct ref_filter *filter, unsigned int type);\n+/*  Clear memory allocated to a ref_array_item */\n+void free_array_item(struct ref_array_item *item);\n /*  Clear all memory allocated to ref_array */\n void ref_array_clear(struct ref_array *array);\n /*  Parse format string and sort specifiers */\ndiff --git a/t/t1430-bad-ref-name.sh b/t/t1430-bad-ref-name.sh\nindex dcf2931..db3627e 100755\n--- a/t/t1430-bad-ref-name.sh\n+++ b/t/t1430-bad-ref-name.sh\n@@ -38,11 +38,11 @@ test_expect_success 'fast-import: fail on invalid branch name \"bad[branch]name\"'\n \ttest_must_fail git fast-import <input\n '\n \n-test_expect_failure 'git branch shows badly named ref' '\n-       cp .git/refs/heads/master .git/refs/heads/broken...ref &&\n-       test_when_finished \"rm -f .git/refs/heads/broken...ref\" &&\n-       git branch >output &&\n-       grep -e \"broken\\.\\.\\.ref\" output\n+test_expect_success 'git branch shows badly named ref as warning' '\n+\tcp .git/refs/heads/master .git/refs/heads/broken...ref &&\n+\ttest_when_finished \"rm -f .git/refs/heads/broken...ref\" &&\n+\tgit branch 2>output &&\n+\tgrep -e \"broken\\.\\.\\.ref\" output\n '\n \n test_expect_success 'branch -d can delete badly named ref' '\ndiff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh\nindex 1deb7cb..c819f3e 100755\n--- a/t/t3203-branch-output.sh\n+++ b/t/t3203-branch-output.sh\n@@ -144,21 +144,21 @@ EOF\n '\n \n test_expect_success 'git branch `--sort` option' '\n-\tcat >expect <<EOF &&\n-* (HEAD detached from fromtag)\n-  branch-two\n-  branch-one\n-  master\n-EOF\n+\tcat >expect <<-\\EOF &&\n+\t* (HEAD detached from fromtag)\n+\t  branch-two\n+\t  branch-one\n+\t  master\n+\tEOF\n \tgit branch --sort=objectsize >actual &&\n \ttest_i18ncmp expect actual\n '\n \n test_expect_success 'git branch --points-at option' '\n-\tcat >expect <<EOF &&\n-  master\n-  branch-one\n-EOF\n+\tcat >expect <<-\\EOF &&\n+\t  master\n+\t  branch-one\n+\tEOF\n \tgit branch --points-at=branch-one >actual &&\n \ttest_cmp expect actual\n '\n\n\n-- \n2.5.0\n"},{"id":"268498","messageId":"1440226309-25415-2-git-send-email-Karthik.188@gmail.com","threadId":"40156","inReplyTo":"1440226309-25415-1-git-send-email-Karthik.188@gmail.com","subject":"[PATCH v3 1/8] branch: refactor width computation","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-08-22T06:51:42Z","receivedAt":"2015-08-22T06:51:42Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"From: Karthik Nayak <karthik.188@gmail.com>\n\nRemove unnecessary variables from ref_list and ref_item which were\nused for width computation. This is to make ref_item similar to\nref-filter's ref_array_item. This will ensure a smooth port of\nbranch.c to use ref-filter APIs in further patches.\n\nPreviously the maxwidth was computed when inserting the refs into the\nref_list. Now, we obtain the entire ref_list and then compute\nmaxwidth.\n\nBased-on-patch-by: Jeff King <peff@peff.net>\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 | 64 ++++++++++++++++++++++++++++++--------------------------\n 1 file changed, 34 insertions(+), 30 deletions(-)\n\ndiff --git a/builtin/branch.c b/builtin/branch.c\nindex 4fc8beb..28a10d6 100644\n--- a/builtin/branch.c\n+++ b/builtin/branch.c\n@@ -282,14 +282,14 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,\n struct ref_item {\n \tchar *name;\n \tchar *dest;\n-\tunsigned int kind, width;\n+\tunsigned int kind;\n \tstruct commit *commit;\n \tint ignore;\n };\n \n struct ref_list {\n \tstruct rev_info revs;\n-\tint index, alloc, maxwidth, verbose, abbrev;\n+\tint index, alloc, verbose, abbrev;\n \tstruct ref_item *list;\n \tstruct commit_list *with_commit;\n \tint kinds;\n@@ -386,15 +386,8 @@ static int append_ref(const char *refname, const struct object_id *oid, int flag\n \tnewitem->name = xstrdup(refname);\n \tnewitem->kind = kind;\n \tnewitem->commit = commit;\n-\tnewitem->width = utf8_strwidth(refname);\n \tnewitem->dest = resolve_symref(orig_refname, prefix);\n \tnewitem->ignore = 0;\n-\t/* adjust for \"remotes/\" */\n-\tif (newitem->kind == REF_REMOTE_BRANCH &&\n-\t    ref_list->kinds != REF_REMOTE_BRANCH)\n-\t\tnewitem->width += 8;\n-\tif (newitem->width > ref_list->maxwidth)\n-\t\tref_list->maxwidth = newitem->width;\n \n \treturn 0;\n }\n@@ -505,11 +498,12 @@ static void add_verbose_info(struct strbuf *out, struct ref_item *item,\n }\n \n static void print_ref_item(struct ref_item *item, int maxwidth, int verbose,\n-\t\t\t   int abbrev, int current, char *prefix)\n+\t\t\t   int abbrev, int current, const char *remote_prefix)\n {\n \tchar c;\n \tint color;\n \tstruct strbuf out = STRBUF_INIT, name = STRBUF_INIT;\n+\tconst char *prefix = \"\";\n \n \tif (item->ignore)\n \t\treturn;\n@@ -520,6 +514,7 @@ static void print_ref_item(struct ref_item *item, int maxwidth, int verbose,\n \t\tbreak;\n \tcase REF_REMOTE_BRANCH:\n \t\tcolor = BRANCH_COLOR_REMOTE;\n+\t\tprefix = remote_prefix;\n \t\tbreak;\n \tdefault:\n \t\tcolor = BRANCH_COLOR_PLAIN;\n@@ -557,16 +552,22 @@ static void print_ref_item(struct ref_item *item, int maxwidth, int verbose,\n \tstrbuf_release(&out);\n }\n \n-static int calc_maxwidth(struct ref_list *refs)\n+static int calc_maxwidth(struct ref_list *refs, int remote_bonus)\n {\n-\tint i, w = 0;\n+\tint i, max = 0;\n \tfor (i = 0; i < refs->index; i++) {\n-\t\tif (refs->list[i].ignore)\n+\t\tstruct ref_item *it = &refs->list[i];\n+\t\tint w;\n+\n+\t\tif (it->ignore)\n \t\t\tcontinue;\n-\t\tif (refs->list[i].width > w)\n-\t\t\tw = refs->list[i].width;\n+\t\tw = utf8_strwidth(it->name);\n+\t\tif (it->kind == REF_REMOTE_BRANCH)\n+\t\t\tw += remote_bonus;\n+\t\tif (w > max)\n+\t\t\tmax = w;\n \t}\n-\treturn w;\n+\treturn max;\n }\n \n static char *get_head_description(void)\n@@ -600,21 +601,18 @@ static char *get_head_description(void)\n \treturn strbuf_detach(&desc, NULL);\n }\n \n-static void show_detached(struct ref_list *ref_list)\n+static void show_detached(struct ref_list *ref_list, int maxwidth)\n {\n \tstruct commit *head_commit = lookup_commit_reference_gently(head_sha1, 1);\n \n \tif (head_commit && is_descendant_of(head_commit, ref_list->with_commit)) {\n \t\tstruct ref_item item;\n \t\titem.name = get_head_description();\n-\t\titem.width = utf8_strwidth(item.name);\n \t\titem.kind = REF_LOCAL_BRANCH;\n \t\titem.dest = NULL;\n \t\titem.commit = head_commit;\n \t\titem.ignore = 0;\n-\t\tif (item.width > ref_list->maxwidth)\n-\t\t\tref_list->maxwidth = item.width;\n-\t\tprint_ref_item(&item, ref_list->maxwidth, ref_list->verbose, ref_list->abbrev, 1, \"\");\n+\t\tprint_ref_item(&item, maxwidth, ref_list->verbose, ref_list->abbrev, 1, \"\");\n \t\tfree(item.name);\n \t}\n }\n@@ -624,6 +622,16 @@ static int print_ref_list(int kinds, int detached, int verbose, int abbrev, stru\n \tint i;\n \tstruct append_ref_cb cb;\n \tstruct ref_list ref_list;\n+\tint maxwidth = 0;\n+\tconst char *remote_prefix = \"\";\n+\n+\t/*\n+\t * If we are listing more than just remote branches,\n+\t * then remote branches will have a \"remotes/\" prefix.\n+\t * We need to account for this in the width.\n+\t */\n+\tif (kinds != REF_REMOTE_BRANCH)\n+\t\tremote_prefix = \"remotes/\";\n \n \tmemset(&ref_list, 0, sizeof(ref_list));\n \tref_list.kinds = kinds;\n@@ -667,26 +675,22 @@ static int print_ref_list(int kinds, int detached, int verbose, int abbrev, stru\n \t\t\tclear_commit_marks(item->commit, ALL_REV_FLAGS);\n \t\t}\n \t\tclear_commit_marks(filter, ALL_REV_FLAGS);\n-\n-\t\tif (verbose)\n-\t\t\tref_list.maxwidth = calc_maxwidth(&ref_list);\n \t}\n+\tif (verbose)\n+\t\tmaxwidth = calc_maxwidth(&ref_list, strlen(remote_prefix));\n \n \tqsort(ref_list.list, ref_list.index, sizeof(struct ref_item), ref_cmp);\n \n \tdetached = (detached && (kinds & REF_LOCAL_BRANCH));\n \tif (detached && match_patterns(pattern, \"HEAD\"))\n-\t\tshow_detached(&ref_list);\n+\t\tshow_detached(&ref_list, maxwidth);\n \n \tfor (i = 0; i < ref_list.index; i++) {\n \t\tint current = !detached &&\n \t\t\t(ref_list.list[i].kind == REF_LOCAL_BRANCH) &&\n \t\t\t!strcmp(ref_list.list[i].name, head);\n-\t\tchar *prefix = (kinds != REF_REMOTE_BRANCH &&\n-\t\t\t\tref_list.list[i].kind == REF_REMOTE_BRANCH)\n-\t\t\t\t? \"remotes/\" : \"\";\n-\t\tprint_ref_item(&ref_list.list[i], ref_list.maxwidth, verbose,\n-\t\t\t       abbrev, current, prefix);\n+\t\tprint_ref_item(&ref_list.list[i], maxwidth, verbose,\n+\t\t\t       abbrev, current, remote_prefix);\n \t}\n \n \tfree_ref_list(&ref_list);\n-- \n2.5.0\n"},{"id":"268502","messageId":"1440226309-25415-3-git-send-email-Karthik.188@gmail.com","threadId":"40156","inReplyTo":"1440226309-25415-1-git-send-email-Karthik.188@gmail.com","subject":"[PATCH v3 2/8] branch: bump get_head_description() to the top","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-08-22T06:51:43Z","receivedAt":"2015-08-22T06:51:43Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"This is a preperatory patch for 'roll show_detached HEAD into regular\nref_list'. This patch moves get_head_description() to the top so that\nit can be used in print_ref_item().\n\nBased-on-patch-by: Jeff King <peff@peff.net>\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 | 62 ++++++++++++++++++++++++++++----------------------------\n 1 file changed, 31 insertions(+), 31 deletions(-)\n\ndiff --git a/builtin/branch.c b/builtin/branch.c\nindex 28a10d6..193296a 100644\n--- a/builtin/branch.c\n+++ b/builtin/branch.c\n@@ -497,6 +497,37 @@ static void add_verbose_info(struct strbuf *out, struct ref_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 print_ref_item(struct ref_item *item, int maxwidth, int verbose,\n \t\t\t   int abbrev, int current, const char *remote_prefix)\n {\n@@ -570,37 +601,6 @@ static int calc_maxwidth(struct ref_list *refs, int remote_bonus)\n \treturn max;\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 show_detached(struct ref_list *ref_list, int maxwidth)\n {\n \tstruct commit *head_commit = lookup_commit_reference_gently(head_sha1, 1);\n-- \n2.5.0\n"},{"id":"268501","messageId":"1440226309-25415-4-git-send-email-Karthik.188@gmail.com","threadId":"40156","inReplyTo":"1440226309-25415-1-git-send-email-Karthik.188@gmail.com","subject":"[PATCH v3 3/8] branch: roll show_detached HEAD into regular ref_list","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-08-22T06:51:44Z","receivedAt":"2015-08-22T06:51:44Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"Remove show_detached() and make detached HEAD to be rolled into\nregular ref_list by adding REF_DETACHED_HEAD as a kind of branch and\nsupporting the same in append_ref(). This eliminates the need for an\nextra function and helps in easier porting of branch.c to use\nref-filter APIs.\n\nBefore show_detached() used to check if the HEAD branch satisfies the\n'--contains' option, now that is taken care by append_ref().\n\nBased-on-patch-by: Jeff King <peff@peff.net>\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 | 68 +++++++++++++++++++++++++++++++++-----------------------\n 1 file changed, 40 insertions(+), 28 deletions(-)\n\ndiff --git a/builtin/branch.c b/builtin/branch.c\nindex 193296a..6ba7a3f 100644\n--- a/builtin/branch.c\n+++ b/builtin/branch.c\n@@ -30,6 +30,7 @@ static const char * const builtin_branch_usage[] = {\n \n #define REF_LOCAL_BRANCH    0x01\n #define REF_REMOTE_BRANCH   0x02\n+#define REF_DETACHED_HEAD   0x04\n \n static const char *head;\n static unsigned char head_sha1[20];\n@@ -352,8 +353,12 @@ static int append_ref(const char *refname, const struct object_id *oid, int flag\n \t\t\tbreak;\n \t\t}\n \t}\n-\tif (ARRAY_SIZE(ref_kind) <= i)\n-\t\treturn 0;\n+\tif (ARRAY_SIZE(ref_kind) <= i) {\n+\t\tif (!strcmp(refname, \"HEAD\"))\n+\t\t\tkind = REF_DETACHED_HEAD;\n+\t\telse\n+\t\t\treturn 0;\n+\t}\n \n \t/* Don't add types the caller doesn't want */\n \tif ((kind & ref_list->kinds) == 0)\n@@ -535,6 +540,8 @@ static void print_ref_item(struct ref_item *item, int maxwidth, int verbose,\n \tint color;\n \tstruct strbuf out = STRBUF_INIT, name = STRBUF_INIT;\n \tconst char *prefix = \"\";\n+\tconst char *desc = item->name;\n+\tchar *to_free = NULL;\n \n \tif (item->ignore)\n \t\treturn;\n@@ -547,6 +554,10 @@ static void print_ref_item(struct ref_item *item, int maxwidth, int verbose,\n \t\tcolor = BRANCH_COLOR_REMOTE;\n \t\tprefix = remote_prefix;\n \t\tbreak;\n+\tcase REF_DETACHED_HEAD:\n+\t\tcolor = BRANCH_COLOR_CURRENT;\n+\t\tdesc = to_free = get_head_description();\n+\t\tbreak;\n \tdefault:\n \t\tcolor = BRANCH_COLOR_PLAIN;\n \t\tbreak;\n@@ -558,7 +569,7 @@ static void print_ref_item(struct ref_item *item, int maxwidth, int verbose,\n \t\tcolor = BRANCH_COLOR_CURRENT;\n \t}\n \n-\tstrbuf_addf(&name, \"%s%s\", prefix, item->name);\n+\tstrbuf_addf(&name, \"%s%s\", prefix, desc);\n \tif (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@@ -581,6 +592,7 @@ static void print_ref_item(struct ref_item *item, int maxwidth, int verbose,\n \t}\n \tstrbuf_release(&name);\n \tstrbuf_release(&out);\n+\tfree(to_free);\n }\n \n static int calc_maxwidth(struct ref_list *refs, int remote_bonus)\n@@ -601,25 +613,9 @@ static int calc_maxwidth(struct ref_list *refs, int remote_bonus)\n \treturn max;\n }\n \n-static void show_detached(struct ref_list *ref_list, int maxwidth)\n-{\n-\tstruct commit *head_commit = lookup_commit_reference_gently(head_sha1, 1);\n-\n-\tif (head_commit && is_descendant_of(head_commit, ref_list->with_commit)) {\n-\t\tstruct ref_item item;\n-\t\titem.name = get_head_description();\n-\t\titem.kind = REF_LOCAL_BRANCH;\n-\t\titem.dest = NULL;\n-\t\titem.commit = head_commit;\n-\t\titem.ignore = 0;\n-\t\tprint_ref_item(&item, maxwidth, ref_list->verbose, ref_list->abbrev, 1, \"\");\n-\t\tfree(item.name);\n-\t}\n-}\n-\n static int print_ref_list(int kinds, int detached, int verbose, int abbrev, struct commit_list *with_commit, const char **pattern)\n {\n-\tint i;\n+\tint i, index;\n \tstruct append_ref_cb cb;\n \tstruct ref_list ref_list;\n \tint maxwidth = 0;\n@@ -643,7 +639,14 @@ static int print_ref_list(int kinds, int detached, int verbose, int abbrev, stru\n \tcb.ref_list = &ref_list;\n \tcb.pattern = pattern;\n \tcb.ret = 0;\n+\t/*\n+\t * First we obtain all regular branch refs and if the HEAD is\n+\t * detached then we insert that ref to the end of the ref_fist\n+\t * so that it can be printed and removed first.\n+\t */\n \tfor_each_rawref(append_ref, &cb);\n+\tif (detached)\n+\t\thead_ref(append_ref, &cb);\n \t/*\n \t * The following implementation is currently duplicated in ref-filter. It\n \t * will eventually be removed when we port branch.c to use ref-filter APIs.\n@@ -679,15 +682,20 @@ static int print_ref_list(int kinds, int detached, int verbose, int abbrev, stru\n \tif (verbose)\n \t\tmaxwidth = calc_maxwidth(&ref_list, strlen(remote_prefix));\n \n-\tqsort(ref_list.list, ref_list.index, sizeof(struct ref_item), ref_cmp);\n+\tindex = ref_list.index;\n+\n+\t/* Print detached HEAD before sorting and printing the rest */\n+\tif (detached && (ref_list.list[index - 1].kind == REF_DETACHED_HEAD) &&\n+\t    !strcmp(ref_list.list[index - 1].name, head)) {\n+\t\tprint_ref_item(&ref_list.list[index - 1], maxwidth, verbose, abbrev,\n+\t\t\t       1, remote_prefix);\n+\t\tindex -= 1;\n+\t}\n \n-\tdetached = (detached && (kinds & REF_LOCAL_BRANCH));\n-\tif (detached && match_patterns(pattern, \"HEAD\"))\n-\t\tshow_detached(&ref_list, maxwidth);\n+\tqsort(ref_list.list, index, sizeof(struct ref_item), ref_cmp);\n \n-\tfor (i = 0; i < ref_list.index; i++) {\n-\t\tint current = !detached &&\n-\t\t\t(ref_list.list[i].kind == REF_LOCAL_BRANCH) &&\n+\tfor (i = 0; i < index; i++) {\n+\t\tint current = !detached && (ref_list.list[i].kind == REF_LOCAL_BRANCH) &&\n \t\t\t!strcmp(ref_list.list[i].name, head);\n \t\tprint_ref_item(&ref_list.list[i], maxwidth, verbose,\n \t\t\t       abbrev, current, remote_prefix);\n@@ -914,7 +922,11 @@ int cmd_branch(int argc, const char **argv, const char *prefix)\n \t\t\tdie(_(\"branch name required\"));\n \t\treturn delete_branches(argc, argv, delete > 1, kinds, quiet);\n \t} else if (list) {\n-\t\tint ret = print_ref_list(kinds, detached, verbose, abbrev,\n+\t\tint ret;\n+\t\t/*  git branch --local also shows HEAD when it is detached */\n+\t\tif (kinds & REF_LOCAL_BRANCH)\n+\t\t\tkinds |= REF_DETACHED_HEAD;\n+\t\tret = print_ref_list(kinds, detached, verbose, abbrev,\n \t\t\t\t\t with_commit, argv);\n \t\tprint_columns(&output, colopts, NULL);\n \t\tstring_list_clear(&output, 0);\n-- \n2.5.0\n"},{"id":"268504","messageId":"1440226309-25415-5-git-send-email-Karthik.188@gmail.com","threadId":"40156","inReplyTo":"1440226309-25415-1-git-send-email-Karthik.188@gmail.com","subject":"[PATCH v3 4/8] branch: move 'current' check down to the presentation layer","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-08-22T06:51:45Z","receivedAt":"2015-08-22T06:51:45Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"We check if given ref is the current branch in print_ref_list(). Move\nthis check to print_ref_item() where it is checked right before\nprinting.\n\nBased-on-patch-by: Jeff King <peff@peff.net>\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 | 22 +++++++++++-----------\n 1 file changed, 11 insertions(+), 11 deletions(-)\n\ndiff --git a/builtin/branch.c b/builtin/branch.c\nindex 6ba7a3f..4d9e4d0 100644\n--- a/builtin/branch.c\n+++ b/builtin/branch.c\n@@ -534,9 +534,10 @@ static char *get_head_description(void)\n }\n \n static void print_ref_item(struct ref_item *item, int maxwidth, int verbose,\n-\t\t\t   int abbrev, int current, const char *remote_prefix)\n+\t\t\t   int abbrev, int detached, 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@@ -548,15 +549,18 @@ static void print_ref_item(struct ref_item *item, int maxwidth, int verbose,\n \n \tswitch (item->kind) {\n \tcase REF_LOCAL_BRANCH:\n-\t\tcolor = BRANCH_COLOR_LOCAL;\n+\t\tif (!detached && !strcmp(item->name, head))\n+\t\t\tcurrent = 1;\n+\t\telse\n+\t\t\tcolor = BRANCH_COLOR_LOCAL;\n \t\tbreak;\n \tcase REF_REMOTE_BRANCH:\n \t\tcolor = BRANCH_COLOR_REMOTE;\n \t\tprefix = remote_prefix;\n \t\tbreak;\n \tcase REF_DETACHED_HEAD:\n-\t\tcolor = BRANCH_COLOR_CURRENT;\n \t\tdesc = to_free = get_head_description();\n+\t\tcurrent = 1;\n \t\tbreak;\n \tdefault:\n \t\tcolor = BRANCH_COLOR_PLAIN;\n@@ -685,21 +689,17 @@ static int print_ref_list(int kinds, int detached, int verbose, int abbrev, stru\n \tindex = ref_list.index;\n \n \t/* Print detached HEAD before sorting and printing the rest */\n-\tif (detached && (ref_list.list[index - 1].kind == REF_DETACHED_HEAD) &&\n-\t    !strcmp(ref_list.list[index - 1].name, head)) {\n+\tif (detached) {\n \t\tprint_ref_item(&ref_list.list[index - 1], maxwidth, verbose, abbrev,\n-\t\t\t       1, remote_prefix);\n+\t\t\t       detached, remote_prefix);\n \t\tindex -= 1;\n \t}\n \n \tqsort(ref_list.list, index, sizeof(struct ref_item), ref_cmp);\n \n-\tfor (i = 0; i < index; i++) {\n-\t\tint current = !detached && (ref_list.list[i].kind == REF_LOCAL_BRANCH) &&\n-\t\t\t!strcmp(ref_list.list[i].name, head);\n+\tfor (i = 0; i < index; i++)\n \t\tprint_ref_item(&ref_list.list[i], maxwidth, verbose,\n-\t\t\t       abbrev, current, remote_prefix);\n-\t}\n+\t\t\t       abbrev, detached, remote_prefix);\n \n \tfree_ref_list(&ref_list);\n \n-- \n2.5.0\n"},{"id":"268500","messageId":"1440226309-25415-6-git-send-email-Karthik.188@gmail.com","threadId":"40156","inReplyTo":"1440226309-25415-1-git-send-email-Karthik.188@gmail.com","subject":"[PATCH v3 5/8] branch: drop non-commit error reporting","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-08-22T06:51:46Z","receivedAt":"2015-08-22T06:51:46Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"Remove the error reporting variable to make the code easier to port\nover to using ref-filter APIs. This variable is not required as in\nref-filter we already check for possible errors and report them.\n\nBased-on-patch-by: Jeff King <peff@peff.net>\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 | 18 ++++--------------\n 1 file changed, 4 insertions(+), 14 deletions(-)\n\ndiff --git a/builtin/branch.c b/builtin/branch.c\nindex 4d9e4d0..8b9da60 100644\n--- a/builtin/branch.c\n+++ b/builtin/branch.c\n@@ -313,7 +313,6 @@ static char *resolve_symref(const char *src, const char *prefix)\n struct append_ref_cb {\n \tstruct ref_list *ref_list;\n \tconst char **pattern;\n-\tint ret;\n };\n \n static int match_patterns(const char **pattern, const char *refname)\n@@ -370,10 +369,8 @@ static int append_ref(const char *refname, const struct object_id *oid, int flag\n \tcommit = NULL;\n \tif (ref_list->verbose || ref_list->with_commit || merge_filter != NO_FILTER) {\n \t\tcommit = lookup_commit_reference_gently(oid->hash, 1);\n-\t\tif (!commit) {\n-\t\t\tcb->ret = error(_(\"branch '%s' does not point at a commit\"), refname);\n+\t\tif (!commit)\n \t\t\treturn 0;\n-\t\t}\n \n \t\t/* Filter with with_commit if specified */\n \t\tif (!is_descendant_of(commit, ref_list->with_commit))\n@@ -617,7 +614,7 @@ static int calc_maxwidth(struct ref_list *refs, int remote_bonus)\n \treturn max;\n }\n \n-static int print_ref_list(int kinds, int detached, int verbose, int abbrev, struct commit_list *with_commit, const char **pattern)\n+static void print_ref_list(int kinds, int detached, int verbose, int abbrev, struct commit_list *with_commit, const char **pattern)\n {\n \tint i, index;\n \tstruct append_ref_cb cb;\n@@ -642,7 +639,6 @@ static int print_ref_list(int kinds, int detached, int verbose, int abbrev, stru\n \t\tinit_revisions(&ref_list.revs, NULL);\n \tcb.ref_list = &ref_list;\n \tcb.pattern = pattern;\n-\tcb.ret = 0;\n \t/*\n \t * First we obtain all regular branch refs and if the HEAD is\n \t * detached then we insert that ref to the end of the ref_fist\n@@ -702,11 +698,6 @@ static int print_ref_list(int kinds, int detached, int verbose, int abbrev, stru\n \t\t\t       abbrev, detached, remote_prefix);\n \n \tfree_ref_list(&ref_list);\n-\n-\tif (cb.ret)\n-\t\terror(_(\"some refs could not be read\"));\n-\n-\treturn cb.ret;\n }\n \n static void rename_branch(const char *oldname, const char *newname, int force)\n@@ -922,15 +913,14 @@ int cmd_branch(int argc, const char **argv, const char *prefix)\n \t\t\tdie(_(\"branch name required\"));\n \t\treturn delete_branches(argc, argv, delete > 1, kinds, quiet);\n \t} else if (list) {\n-\t\tint ret;\n \t\t/*  git branch --local also shows HEAD when it is detached */\n \t\tif (kinds & REF_LOCAL_BRANCH)\n \t\t\tkinds |= REF_DETACHED_HEAD;\n-\t\tret = print_ref_list(kinds, detached, verbose, abbrev,\n+\t\tprint_ref_list(kinds, detached, verbose, abbrev,\n \t\t\t\t\t with_commit, argv);\n \t\tprint_columns(&output, colopts, NULL);\n \t\tstring_list_clear(&output, 0);\n-\t\treturn ret;\n+\t\treturn 0;\n \t}\n \telse if (edit_description) {\n \t\tconst char *branch_name;\n-- \n2.5.0\n"},{"id":"268505","messageId":"1440226309-25415-7-git-send-email-Karthik.188@gmail.com","threadId":"40156","inReplyTo":"1440226309-25415-1-git-send-email-Karthik.188@gmail.com","subject":"[PATCH v3 6/8] branch.c: use 'ref-filter' data structures","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-08-22T06:51:47Z","receivedAt":"2015-08-22T06:51:47Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"Make 'branch.c' use 'ref-filter' data structures and make changes to\nsupport the new data structures. This is a part of the process of\nporting 'branch.c' to use 'ref-filter' APIs.\n\nThis is a temporary step before porting 'branch.c' to use 'ref-filter'\ncompletely. As this is a temporary step, most of the code introduced\nhere will be removed when 'branch.c' is ported over to use\n'ref-filter' APIs.\n\nMake 'free_array_item()' of ref-filter.c a non static function. This\nis used to free memory allocated to a detached head ref, before we\nprint other refs.\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 | 328 ++++++++++++++++++++++---------------------------------\n ref-filter.c     |   2 +-\n ref-filter.h     |   9 +-\n 3 files changed, 141 insertions(+), 198 deletions(-)\n\ndiff --git a/builtin/branch.c b/builtin/branch.c\nindex 8b9da60..5cb7ef0 100644\n--- a/builtin/branch.c\n+++ b/builtin/branch.c\n@@ -19,6 +19,7 @@\n #include \"column.h\"\n #include \"utf8.h\"\n #include \"wt-status.h\"\n+#include \"ref-filter.h\"\n \n static const char * const builtin_branch_usage[] = {\n \tN_(\"git branch [<options>] [-r | -a] [--merged | --no-merged]\"),\n@@ -28,10 +29,6 @@ static const char * const builtin_branch_usage[] = {\n \tNULL\n };\n \n-#define REF_LOCAL_BRANCH    0x01\n-#define REF_REMOTE_BRANCH   0x02\n-#define REF_DETACHED_HEAD   0x04\n-\n static const char *head;\n static unsigned char head_sha1[20];\n \n@@ -53,13 +50,6 @@ enum color_branch {\n \tBRANCH_COLOR_UPSTREAM = 5\n };\n \n-static enum merge_filter {\n-\tNO_FILTER = 0,\n-\tSHOW_NOT_MERGED,\n-\tSHOW_MERGED\n-} merge_filter;\n-static unsigned char merge_filter_ref[20];\n-\n static struct string_list output = STRING_LIST_INIT_DUP;\n static unsigned int colopts;\n \n@@ -122,7 +112,7 @@ static int branch_merged(int kind, const char *name,\n \tvoid *reference_name_to_free = NULL;\n \tint merged;\n \n-\tif (kind == REF_LOCAL_BRANCH) {\n+\tif (kind == FILTER_REFS_BRANCHES) {\n \t\tstruct branch *branch = branch_get(name);\n \t\tconst char *upstream = branch_get_upstream(branch, NULL);\n \t\tunsigned char sha1[20];\n@@ -200,14 +190,14 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,\n \tstruct strbuf bname = STRBUF_INIT;\n \n \tswitch (kinds) {\n-\tcase REF_REMOTE_BRANCH:\n+\tcase FILTER_REFS_REMOTES:\n \t\tfmt = \"refs/remotes/%s\";\n \t\t/* For subsequent UI messages */\n \t\tremote_branch = 1;\n \n \t\tforce = 1;\n \t\tbreak;\n-\tcase REF_LOCAL_BRANCH:\n+\tcase FILTER_REFS_BRANCHES:\n \t\tfmt = \"refs/heads/%s\";\n \t\tbreak;\n \tdefault:\n@@ -224,7 +214,7 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,\n \t\tint flags = 0;\n \n \t\tstrbuf_branchname(&bname, argv[i]);\n-\t\tif (kinds == REF_LOCAL_BRANCH && !strcmp(head, bname.buf)) {\n+\t\tif (kinds == FILTER_REFS_BRANCHES && !strcmp(head, bname.buf)) {\n \t\t\terror(_(\"Cannot delete the branch '%s' \"\n \t\t\t      \"which you are currently on.\"), bname.buf);\n \t\t\tret = 1;\n@@ -280,22 +270,6 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,\n \treturn(ret);\n }\n \n-struct ref_item {\n-\tchar *name;\n-\tchar *dest;\n-\tunsigned int kind;\n-\tstruct commit *commit;\n-\tint ignore;\n-};\n-\n-struct ref_list {\n-\tstruct rev_info revs;\n-\tint index, alloc, verbose, abbrev;\n-\tstruct ref_item *list;\n-\tstruct commit_list *with_commit;\n-\tint kinds;\n-};\n-\n static char *resolve_symref(const char *src, const char *prefix)\n {\n \tunsigned char sha1[20];\n@@ -310,11 +284,6 @@ static char *resolve_symref(const char *src, const char *prefix)\n \treturn xstrdup(dst);\n }\n \n-struct append_ref_cb {\n-\tstruct ref_list *ref_list;\n-\tconst char **pattern;\n-};\n-\n static int match_patterns(const char **pattern, const char *refname)\n {\n \tif (!*pattern)\n@@ -327,11 +296,29 @@ static int match_patterns(const char **pattern, const char *refname)\n \treturn 0;\n }\n \n+/*\n+ * Allocate memory for a new ref_array_item and insert that into the\n+ * given ref_array. Doesn't take the objectname unlike\n+ * new_ref_array_item(). This is a temporary function which will be\n+ * removed when we port branch.c to use ref-filter APIs.\n+ */\n+static struct ref_array_item *ref_array_append(struct ref_array *array, const char *refname)\n+{\n+\tsize_t len = strlen(refname);\n+\tstruct ref_array_item *ref = xcalloc(1, sizeof(struct ref_array_item) + len + 1);\n+\tmemcpy(ref->refname, refname, len);\n+\tref->refname[len] = '\\0';\n+\tREALLOC_ARRAY(array->items, array->nr + 1);\n+\tarray->items[array->nr++] = ref;\n+\treturn ref;\n+}\n+\n static int append_ref(const char *refname, const struct object_id *oid, int flags, void *cb_data)\n {\n-\tstruct append_ref_cb *cb = (struct append_ref_cb *)(cb_data);\n-\tstruct ref_list *ref_list = cb->ref_list;\n-\tstruct ref_item *newitem;\n+\tstruct ref_filter_cbdata *cb = (struct ref_filter_cbdata *)(cb_data);\n+\tstruct ref_filter *filter = cb->filter;\n+\tstruct ref_array *array = cb->array;\n+\tstruct ref_array_item *item;\n \tstruct commit *commit;\n \tint kind, i;\n \tconst char *prefix, *orig_refname = refname;\n@@ -340,8 +327,8 @@ static int append_ref(const char *refname, const struct object_id *oid, int flag\n \t\tint kind;\n \t\tconst char *prefix;\n \t} ref_kind[] = {\n-\t\t{ REF_LOCAL_BRANCH, \"refs/heads/\" },\n-\t\t{ REF_REMOTE_BRANCH, \"refs/remotes/\" },\n+\t\t{ FILTER_REFS_BRANCHES, \"refs/heads/\" },\n+\t\t{ FILTER_REFS_REMOTES, \"refs/remotes/\" },\n \t};\n \n \t/* Detect kind */\n@@ -354,65 +341,52 @@ static int append_ref(const char *refname, const struct object_id *oid, int flag\n \t}\n \tif (ARRAY_SIZE(ref_kind) <= i) {\n \t\tif (!strcmp(refname, \"HEAD\"))\n-\t\t\tkind = REF_DETACHED_HEAD;\n+\t\t\tkind = FILTER_REFS_DETACHED_HEAD;\n \t\telse\n \t\t\treturn 0;\n \t}\n \n \t/* Don't add types the caller doesn't want */\n-\tif ((kind & ref_list->kinds) == 0)\n+\tif ((kind & filter->kind) == 0)\n \t\treturn 0;\n \n-\tif (!match_patterns(cb->pattern, refname))\n+\tif (!match_patterns(filter->name_patterns, refname))\n \t\treturn 0;\n \n \tcommit = NULL;\n-\tif (ref_list->verbose || ref_list->with_commit || merge_filter != NO_FILTER) {\n+\tif (filter->verbose || filter->with_commit || filter->merge != REF_FILTER_MERGED_NONE) {\n \t\tcommit = lookup_commit_reference_gently(oid->hash, 1);\n \t\tif (!commit)\n \t\t\treturn 0;\n \n \t\t/* Filter with with_commit if specified */\n-\t\tif (!is_descendant_of(commit, ref_list->with_commit))\n+\t\tif (!is_descendant_of(commit, filter->with_commit))\n \t\t\treturn 0;\n \n-\t\tif (merge_filter != NO_FILTER)\n-\t\t\tadd_pending_object(&ref_list->revs,\n+\t\tif (filter->merge != REF_FILTER_MERGED_NONE)\n+\t\t\tadd_pending_object(array->revs,\n \t\t\t\t\t   (struct object *)commit, refname);\n \t}\n \n-\tALLOC_GROW(ref_list->list, ref_list->index + 1, ref_list->alloc);\n+\titem = ref_array_append(array, refname);\n \n \t/* Record the new item */\n-\tnewitem = &(ref_list->list[ref_list->index++]);\n-\tnewitem->name = xstrdup(refname);\n-\tnewitem->kind = kind;\n-\tnewitem->commit = commit;\n-\tnewitem->dest = resolve_symref(orig_refname, prefix);\n-\tnewitem->ignore = 0;\n+\titem->kind = kind;\n+\titem->commit = commit;\n+\titem->symref = resolve_symref(orig_refname, prefix);\n+\titem->ignore = 0;\n \n \treturn 0;\n }\n \n-static void free_ref_list(struct ref_list *ref_list)\n-{\n-\tint i;\n-\n-\tfor (i = 0; i < ref_list->index; i++) {\n-\t\tfree(ref_list->list[i].name);\n-\t\tfree(ref_list->list[i].dest);\n-\t}\n-\tfree(ref_list->list);\n-}\n-\n static int ref_cmp(const void *r1, const void *r2)\n {\n-\tstruct ref_item *c1 = (struct ref_item *)(r1);\n-\tstruct ref_item *c2 = (struct ref_item *)(r2);\n+\tstruct ref_array_item *c1 = *((struct ref_array_item **)r1);\n+\tstruct ref_array_item *c2 = *((struct ref_array_item **)r2);\n \n \tif (c1->kind != c2->kind)\n \t\treturn c1->kind - c2->kind;\n-\treturn strcmp(c1->name, c2->name);\n+\treturn strcmp(c1->refname, c2->refname);\n }\n \n static void fill_tracking_info(struct strbuf *stat, const char *branch_name,\n@@ -477,8 +451,8 @@ static void fill_tracking_info(struct strbuf *stat, const char *branch_name,\n \tfree(ref);\n }\n \n-static void add_verbose_info(struct strbuf *out, struct ref_item *item,\n-\t\t\t     int verbose, int abbrev)\n+static void add_verbose_info(struct strbuf *out, struct ref_array_item *item,\n+\t\t\t     struct ref_filter *filter)\n {\n \tstruct strbuf subject = STRBUF_INIT, stat = STRBUF_INIT;\n \tconst char *sub = _(\" **** invalid ref ****\");\n@@ -489,11 +463,11 @@ static void add_verbose_info(struct strbuf *out, struct ref_item *item,\n \t\tsub = subject.buf;\n \t}\n \n-\tif (item->kind == REF_LOCAL_BRANCH)\n-\t\tfill_tracking_info(&stat, item->name, verbose > 1);\n+\tif (item->kind == FILTER_REFS_BRANCHES)\n+\t\tfill_tracking_info(&stat, item->refname, filter->verbose > 1);\n \n \tstrbuf_addf(out, \" %s %s%s\",\n-\t\tfind_unique_abbrev(item->commit->object.sha1, abbrev),\n+\t\tfind_unique_abbrev(item->commit->object.sha1, filter->abbrev),\n \t\tstat.buf, sub);\n \tstrbuf_release(&stat);\n \tstrbuf_release(&subject);\n@@ -530,32 +504,32 @@ static char *get_head_description(void)\n \treturn strbuf_detach(&desc, NULL);\n }\n \n-static void print_ref_item(struct ref_item *item, int maxwidth, int verbose,\n-\t\t\t   int abbrev, int detached, const char *remote_prefix)\n+static void print_ref_item(struct ref_array_item *item, int maxwidth,\n+\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->name;\n+\tconst char *desc = item->refname;\n \tchar *to_free = NULL;\n \n \tif (item->ignore)\n \t\treturn;\n \n \tswitch (item->kind) {\n-\tcase REF_LOCAL_BRANCH:\n-\t\tif (!detached && !strcmp(item->name, head))\n+\tcase FILTER_REFS_BRANCHES:\n+\t\tif (!filter->detached && !strcmp(item->refname, head))\n \t\t\tcurrent = 1;\n \t\telse\n \t\t\tcolor = BRANCH_COLOR_LOCAL;\n \t\tbreak;\n-\tcase REF_REMOTE_BRANCH:\n+\tcase FILTER_REFS_REMOTES:\n \t\tcolor = BRANCH_COLOR_REMOTE;\n \t\tprefix = remote_prefix;\n \t\tbreak;\n-\tcase REF_DETACHED_HEAD:\n+\tcase FILTER_REFS_DETACHED_HEAD:\n \t\tdesc = to_free = get_head_description();\n \t\tcurrent = 1;\n \t\tbreak;\n@@ -571,7 +545,7 @@ static void print_ref_item(struct ref_item *item, int maxwidth, int verbose,\n \t}\n \n \tstrbuf_addf(&name, \"%s%s\", prefix, desc);\n-\tif (verbose) {\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@@ -580,13 +554,13 @@ static void print_ref_item(struct ref_item *item, int maxwidth, int verbose,\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->dest)\n-\t\tstrbuf_addf(&out, \" -> %s\", item->dest);\n-\telse if (verbose)\n+\tif (item->symref)\n+\t\tstrbuf_addf(&out, \" -> %s\", item->symref);\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, verbose, abbrev);\n+\t\tadd_verbose_info(&out, item, filter);\n \tif (column_active(colopts)) {\n-\t\tassert(!verbose && \"--column and --verbose are incompatible\");\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@@ -596,17 +570,17 @@ static void print_ref_item(struct ref_item *item, int maxwidth, int verbose,\n \tfree(to_free);\n }\n \n-static int calc_maxwidth(struct ref_list *refs, int remote_bonus)\n+static int calc_maxwidth(struct ref_array *refs, int remote_bonus)\n {\n \tint i, max = 0;\n-\tfor (i = 0; i < refs->index; i++) {\n-\t\tstruct ref_item *it = &refs->list[i];\n+\tfor (i = 0; i < refs->nr; i++) {\n+\t\tstruct ref_array_item *it = refs->items[i];\n \t\tint w;\n \n \t\tif (it->ignore)\n \t\t\tcontinue;\n-\t\tw = utf8_strwidth(it->name);\n-\t\tif (it->kind == REF_REMOTE_BRANCH)\n+\t\tw = utf8_strwidth(it->refname);\n+\t\tif (it->kind == FILTER_REFS_REMOTES)\n \t\t\tw += remote_bonus;\n \t\tif (w > max)\n \t\t\tmax = w;\n@@ -614,90 +588,80 @@ static int calc_maxwidth(struct ref_list *refs, int remote_bonus)\n \treturn max;\n }\n \n-static void print_ref_list(int kinds, int detached, int verbose, int abbrev, struct commit_list *with_commit, const char **pattern)\n+static void print_ref_list(struct ref_filter *filter)\n {\n-\tint i, index;\n-\tstruct append_ref_cb cb;\n-\tstruct ref_list ref_list;\n+\tint i;\n+\tstruct ref_array array;\n+\tstruct ref_filter_cbdata data;\n \tint maxwidth = 0;\n \tconst char *remote_prefix = \"\";\n+\tstruct rev_info revs;\n \n \t/*\n \t * If we are listing more than just remote branches,\n \t * then remote branches will have a \"remotes/\" prefix.\n \t * We need to account for this in the width.\n \t */\n-\tif (kinds != REF_REMOTE_BRANCH)\n+\tif (filter->kind != FILTER_REFS_REMOTES)\n \t\tremote_prefix = \"remotes/\";\n \n-\tmemset(&ref_list, 0, sizeof(ref_list));\n-\tref_list.kinds = kinds;\n-\tref_list.verbose = verbose;\n-\tref_list.abbrev = abbrev;\n-\tref_list.with_commit = with_commit;\n-\tif (merge_filter != NO_FILTER)\n-\t\tinit_revisions(&ref_list.revs, NULL);\n-\tcb.ref_list = &ref_list;\n-\tcb.pattern = pattern;\n+\tmemset(&array, 0, sizeof(array));\n+\tif (filter->merge != REF_FILTER_MERGED_NONE)\n+\t\tinit_revisions(&revs, NULL);\n+\n+\tdata.array = &array;\n+\tdata.filter = filter;\n+\tarray.revs = &revs;\n+\n \t/*\n \t * First we obtain all regular branch refs and if the HEAD is\n \t * detached then we insert that ref to the end of the ref_fist\n \t * so that it can be printed and removed first.\n \t */\n-\tfor_each_rawref(append_ref, &cb);\n-\tif (detached)\n-\t\thead_ref(append_ref, &cb);\n+\tfor_each_rawref(append_ref, &data);\n+\tif (filter->detached)\n+\t\thead_ref(append_ref, &data);\n \t/*\n \t * The following implementation is currently duplicated in ref-filter. It\n \t * will eventually be removed when we port branch.c to use ref-filter APIs.\n \t */\n-\tif (merge_filter != NO_FILTER) {\n-\t\tstruct commit *filter;\n-\t\tfilter = lookup_commit_reference_gently(merge_filter_ref, 0);\n-\t\tif (!filter)\n-\t\t\tdie(_(\"object '%s' does not point to a commit\"),\n-\t\t\t    sha1_to_hex(merge_filter_ref));\n-\n-\t\tfilter->object.flags |= UNINTERESTING;\n-\t\tadd_pending_object(&ref_list.revs,\n-\t\t\t\t   (struct object *) filter, \"\");\n-\t\tref_list.revs.limited = 1;\n-\n-\t\tif (prepare_revision_walk(&ref_list.revs))\n+\tif (filter->merge != REF_FILTER_MERGED_NONE) {\n+\t\tfilter->merge_commit->object.flags |= UNINTERESTING;\n+\t\tadd_pending_object(&revs, &filter->merge_commit->object, \"\");\n+\t\trevs.limited = 1;\n+\n+\t\tif (prepare_revision_walk(&revs))\n \t\t\tdie(_(\"revision walk setup failed\"));\n \n-\t\tfor (i = 0; i < ref_list.index; i++) {\n-\t\t\tstruct ref_item *item = &ref_list.list[i];\n+\t\tfor (i = 0; i < array.nr; i++) {\n+\t\t\tstruct ref_array_item *item = array.items[i];\n \t\t\tstruct commit *commit = item->commit;\n \t\t\tint is_merged = !!(commit->object.flags & UNINTERESTING);\n-\t\t\titem->ignore = is_merged != (merge_filter == SHOW_MERGED);\n+\t\t\titem->ignore = is_merged != (filter->merge == REF_FILTER_MERGED_INCLUDE);\n \t\t}\n \n-\t\tfor (i = 0; i < ref_list.index; i++) {\n-\t\t\tstruct ref_item *item = &ref_list.list[i];\n+\t\tfor (i = 0; i < array.nr; i++) {\n+\t\t\tstruct ref_array_item *item = array.items[i];\n \t\t\tclear_commit_marks(item->commit, ALL_REV_FLAGS);\n \t\t}\n-\t\tclear_commit_marks(filter, ALL_REV_FLAGS);\n+\t\tclear_commit_marks(filter->merge_commit, ALL_REV_FLAGS);\n \t}\n-\tif (verbose)\n-\t\tmaxwidth = calc_maxwidth(&ref_list, strlen(remote_prefix));\n-\n-\tindex = ref_list.index;\n+\tif (filter->verbose)\n+\t\tmaxwidth = calc_maxwidth(&array, strlen(remote_prefix));\n \n \t/* Print detached HEAD before sorting and printing the rest */\n-\tif (detached) {\n-\t\tprint_ref_item(&ref_list.list[index - 1], maxwidth, verbose, abbrev,\n-\t\t\t       detached, remote_prefix);\n-\t\tindex -= 1;\n+\tif (filter->kind & FILTER_REFS_DETACHED_HEAD) {\n+\t\tprint_ref_item(array.items[array.nr - 1], maxwidth, filter, remote_prefix);\n+\t\tfree_array_item(array.items[array.nr - 1]);\n+\t\tarray.nr--;\n \t}\n \n-\tqsort(ref_list.list, index, sizeof(struct ref_item), ref_cmp);\n+\tqsort(array.items, array.nr, sizeof(struct ref_array_item *), ref_cmp);\n \n-\tfor (i = 0; i < index; i++)\n-\t\tprint_ref_item(&ref_list.list[i], maxwidth, verbose,\n-\t\t\t       abbrev, detached, remote_prefix);\n+\tfor (i = 0; i < array.nr; i++)\n+\t\tprint_ref_item(array.items[i], maxwidth, filter, remote_prefix);\n \n-\tfree_ref_list(&ref_list);\n+\tref_array_clear(&array);\n }\n \n static void rename_branch(const char *oldname, const char *newname, int force)\n@@ -753,24 +717,6 @@ static void rename_branch(const char *oldname, const char *newname, int force)\n \tstrbuf_release(&newsection);\n }\n \n-/*\n- * This function is duplicated in ref-filter. It will eventually be removed\n- * when we port branch.c to use ref-filter APIs.\n- */\n-static int opt_parse_merge_filter(const struct option *opt, const char *arg, int unset)\n-{\n-\tmerge_filter = ((opt->long_name[0] == 'n')\n-\t\t\t? SHOW_NOT_MERGED\n-\t\t\t: SHOW_MERGED);\n-\tif (unset)\n-\t\tmerge_filter = SHOW_NOT_MERGED; /* b/c for --no-merged */\n-\tif (!arg)\n-\t\targ = \"HEAD\";\n-\tif (get_sha1(arg, merge_filter_ref))\n-\t\tdie(_(\"malformed object name %s\"), arg);\n-\treturn 0;\n-}\n-\n static const char edit_description[] = \"BRANCH_DESCRIPTION\";\n \n static int edit_branch_description(const char *branch_name)\n@@ -810,17 +756,15 @@ static int edit_branch_description(const char *branch_name)\n int cmd_branch(int argc, const char **argv, const char *prefix)\n {\n \tint delete = 0, rename = 0, force = 0, list = 0;\n-\tint verbose = 0, abbrev = -1, detached = 0;\n \tint reflog = 0, edit_description = 0;\n \tint quiet = 0, unset_upstream = 0;\n \tconst char *new_upstream = NULL;\n \tenum branch_track track;\n-\tint kinds = REF_LOCAL_BRANCH;\n-\tstruct commit_list *with_commit = NULL;\n+\tstruct ref_filter filter;\n \n \tstruct option options[] = {\n \t\tOPT_GROUP(N_(\"Generic options\")),\n-\t\tOPT__VERBOSE(&verbose,\n+\t\tOPT__VERBOSE(&filter.verbose,\n \t\t\tN_(\"show hash and subject, give twice for upstream branch\")),\n \t\tOPT__QUIET(&quiet, N_(\"suppress informational messages\")),\n \t\tOPT_SET_INT('t', \"track\",  &track, N_(\"set up tracking mode (see git-pull(1))\"),\n@@ -830,15 +774,15 @@ int cmd_branch(int argc, const char **argv, const char *prefix)\n \t\tOPT_STRING('u', \"set-upstream-to\", &new_upstream, \"upstream\", \"change the upstream info\"),\n \t\tOPT_BOOL(0, \"unset-upstream\", &unset_upstream, \"Unset the upstream info\"),\n \t\tOPT__COLOR(&branch_use_color, N_(\"use colored output\")),\n-\t\tOPT_SET_INT('r', \"remotes\",     &kinds, N_(\"act on remote-tracking branches\"),\n-\t\t\tREF_REMOTE_BRANCH),\n-\t\tOPT_CONTAINS(&with_commit, N_(\"print only branches that contain the commit\")),\n-\t\tOPT_WITH(&with_commit, N_(\"print only branches that contain the commit\")),\n-\t\tOPT__ABBREV(&abbrev),\n+\t\tOPT_SET_INT('r', \"remotes\",     &filter.kind, N_(\"act on remote-tracking branches\"),\n+\t\t\tFILTER_REFS_REMOTES),\n+\t\tOPT_CONTAINS(&filter.with_commit, N_(\"print only branches that contain the commit\")),\n+\t\tOPT_WITH(&filter.with_commit, N_(\"print only branches that contain the commit\")),\n+\t\tOPT__ABBREV(&filter.abbrev),\n \n \t\tOPT_GROUP(N_(\"Specific git-branch actions:\")),\n-\t\tOPT_SET_INT('a', \"all\", &kinds, N_(\"list both remote-tracking and local branches\"),\n-\t\t\tREF_REMOTE_BRANCH | REF_LOCAL_BRANCH),\n+\t\tOPT_SET_INT('a', \"all\", &filter.kind, N_(\"list both remote-tracking and local branches\"),\n+\t\t\tFILTER_REFS_REMOTES | FILTER_REFS_BRANCHES),\n \t\tOPT_BIT('d', \"delete\", &delete, N_(\"delete fully merged branch\"), 1),\n \t\tOPT_BIT('D', NULL, &delete, N_(\"delete branch (even if not merged)\"), 2),\n \t\tOPT_BIT('m', \"move\", &rename, N_(\"move/rename a branch and its reflog\"), 1),\n@@ -848,22 +792,16 @@ int cmd_branch(int argc, const char **argv, const char *prefix)\n \t\tOPT_BOOL(0, \"edit-description\", &edit_description,\n \t\t\t N_(\"edit the description for the branch\")),\n \t\tOPT__FORCE(&force, N_(\"force creation, move/rename, deletion\")),\n-\t\t{\n-\t\t\tOPTION_CALLBACK, 0, \"no-merged\", &merge_filter_ref,\n-\t\t\tN_(\"commit\"), N_(\"print only not merged branches\"),\n-\t\t\tPARSE_OPT_LASTARG_DEFAULT | PARSE_OPT_NONEG,\n-\t\t\topt_parse_merge_filter, (intptr_t) \"HEAD\",\n-\t\t},\n-\t\t{\n-\t\t\tOPTION_CALLBACK, 0, \"merged\", &merge_filter_ref,\n-\t\t\tN_(\"commit\"), N_(\"print only merged branches\"),\n-\t\t\tPARSE_OPT_LASTARG_DEFAULT | PARSE_OPT_NONEG,\n-\t\t\topt_parse_merge_filter, (intptr_t) \"HEAD\",\n-\t\t},\n+\t\tOPT_MERGED(&filter, N_(\"print only branches that are merged\")),\n+\t\tOPT_NO_MERGED(&filter, N_(\"print only branches that are not merged\")),\n \t\tOPT_COLUMN(0, \"column\", &colopts, N_(\"list branches in columns\")),\n \t\tOPT_END(),\n \t};\n \n+\tmemset(&filter, 0, sizeof(filter));\n+\tfilter.kind = FILTER_REFS_BRANCHES;\n+\tfilter.abbrev = -1;\n+\n \tif (argc == 2 && !strcmp(argv[1], \"-h\"))\n \t\tusage_with_options(builtin_branch_usage, options);\n \n@@ -875,11 +813,9 @@ int cmd_branch(int argc, const char **argv, const char *prefix)\n \tif (!head)\n \t\tdie(_(\"Failed to resolve HEAD as a valid ref.\"));\n \tif (!strcmp(head, \"HEAD\"))\n-\t\tdetached = 1;\n+\t\tfilter.detached = 1;\n \telse if (!skip_prefix(head, \"refs/heads/\", &head))\n \t\tdie(_(\"HEAD not found below refs/heads!\"));\n-\thashcpy(merge_filter_ref, head_sha1);\n-\n \n \targc = parse_options(argc, argv, prefix, options, builtin_branch_usage,\n \t\t\t     0);\n@@ -887,17 +823,17 @@ int cmd_branch(int argc, const char **argv, const char *prefix)\n \tif (!delete && !rename && !edit_description && !new_upstream && !unset_upstream && argc == 0)\n \t\tlist = 1;\n \n-\tif (with_commit || merge_filter != NO_FILTER)\n+\tif (filter.with_commit || filter.merge != REF_FILTER_MERGED_NONE)\n \t\tlist = 1;\n \n \tif (!!delete + !!rename + !!new_upstream +\n \t    list + unset_upstream > 1)\n \t\tusage_with_options(builtin_branch_usage, options);\n \n-\tif (abbrev == -1)\n-\t\tabbrev = DEFAULT_ABBREV;\n+\tif (filter.abbrev == -1)\n+\t\tfilter.abbrev = DEFAULT_ABBREV;\n \tfinalize_colopts(&colopts, -1);\n-\tif (verbose) {\n+\tif (filter.verbose) {\n \t\tif (explicitly_enable_column(colopts))\n \t\t\tdie(_(\"--column and --verbose are incompatible\"));\n \t\tcolopts = 0;\n@@ -911,13 +847,13 @@ int cmd_branch(int argc, const char **argv, const char *prefix)\n \tif (delete) {\n \t\tif (!argc)\n \t\t\tdie(_(\"branch name required\"));\n-\t\treturn delete_branches(argc, argv, delete > 1, kinds, quiet);\n+\t\treturn delete_branches(argc, argv, delete > 1, filter.kind, quiet);\n \t} else if (list) {\n \t\t/*  git branch --local also shows HEAD when it is detached */\n-\t\tif (kinds & REF_LOCAL_BRANCH)\n-\t\t\tkinds |= REF_DETACHED_HEAD;\n-\t\tprint_ref_list(kinds, detached, verbose, abbrev,\n-\t\t\t\t\t with_commit, argv);\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);\n \t\tprint_columns(&output, colopts, NULL);\n \t\tstring_list_clear(&output, 0);\n \t\treturn 0;\n@@ -927,7 +863,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)\n \t\tstruct strbuf branch_ref = STRBUF_INIT;\n \n \t\tif (!argc) {\n-\t\t\tif (detached)\n+\t\t\tif (filter.detached)\n \t\t\t\tdie(_(\"Cannot give description to detached HEAD\"));\n \t\t\tbranch_name = head;\n \t\t} else if (argc == 1)\n@@ -1015,7 +951,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)\n \t\tif (!branch)\n \t\t\tdie(_(\"no such branch '%s'\"), argv[0]);\n \n-\t\tif (kinds != REF_LOCAL_BRANCH)\n+\t\tif (filter.kind != FILTER_REFS_BRANCHES)\n \t\t\tdie(_(\"-a and -r options to 'git branch' do not make sense with a branch name\"));\n \n \t\tif (track == BRANCH_TRACK_OVERRIDE)\ndiff --git a/ref-filter.c b/ref-filter.c\nindex f8b8fb7..bbf5648 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -1251,7 +1251,7 @@ static int ref_filter_handler(const char *refname, const struct object_id *oid,\n }\n \n /*  Free memory allocated for a ref_array_item */\n-static void free_array_item(struct ref_array_item *item)\n+void free_array_item(struct ref_array_item *item)\n {\n \tfree((char *)item->symref);\n \tfree(item);\ndiff --git a/ref-filter.h b/ref-filter.h\nindex 8241066..ae409b7 100644\n--- a/ref-filter.h\n+++ b/ref-filter.h\n@@ -35,6 +35,7 @@ struct ref_array_item {\n \tunsigned char objectname[20];\n \tint flag;\n \tunsigned int kind;\n+\tint ignore : 1; /* To be removed in the next patch */\n \tconst char *symref;\n \tstruct commit *commit;\n \tstruct atom_value *value;\n@@ -44,6 +45,7 @@ struct ref_array_item {\n struct ref_array {\n \tint nr, alloc;\n \tstruct ref_array_item **items;\n+\tstruct rev_info *revs;\n };\n \n struct ref_filter {\n@@ -59,9 +61,12 @@ struct ref_filter {\n \tstruct commit *merge_commit;\n \n \tunsigned int with_commit_tag_algo : 1,\n-\t\tmatch_as_path : 1;\n+\t\tmatch_as_path : 1,\n+\t\tdetached : 1;\n \tunsigned int kind,\n \t\tlines;\n+\tint abbrev,\n+\t\tverbose;\n };\n \n struct ref_filter_cbdata {\n@@ -85,6 +90,8 @@ struct ref_filter_cbdata {\n  * filtered refs in the ref_array structure.\n  */\n int filter_refs(struct ref_array *array, struct ref_filter *filter, unsigned int type);\n+/*  Clear memory allocated to a ref_array_item */\n+void free_array_item(struct ref_array_item *item);\n /*  Clear all memory allocated to ref_array */\n void ref_array_clear(struct ref_array *array);\n /*  Parse format string and sort specifiers */\n-- \n2.5.0\n"},{"id":"268503","messageId":"1440226309-25415-8-git-send-email-Karthik.188@gmail.com","threadId":"40156","inReplyTo":"1440226309-25415-1-git-send-email-Karthik.188@gmail.com","subject":"[PATCH v3 7/8] branch.c: use 'ref-filter' APIs","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-08-22T06:51:48Z","receivedAt":"2015-08-22T06:51:48Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"Make 'branch.c' use 'ref-filter' APIs for iterating through refs\nsorting. This removes most of the code used in 'branch.c' replacing it\nwith calls to the 'ref-filter' library.\n\nMake 'branch.c' use the 'filter_refs()' function provided by 'ref-filter'\nto filter out tags based on the options set.\n\nWe provide a sorting option provided for 'branch.c' by using the sorting\noptions provided by 'ref-filter'.\n\nAlso remove the 'ignore' variable from ref_array_item as it was\npreviously used for the '--merged' option and now that is handled by\nref-filter.\n\nThe test t1430 'git branch shows badly named ref' has been changed to\ncheck the stderr for the warning regarding the broken ref. This is\ndone as ref-filter throws a warning for broken refs rather than\ndirectly printing them.\n\nModify documentation and add tests 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 |   9 +-\n builtin/branch.c             | 213 +++++++------------------------------------\n ref-filter.c                 |   2 +-\n ref-filter.h                 |   1 -\n t/t1430-bad-ref-name.sh      |   2 +-\n t/t3203-branch-output.sh     |  11 +++\n 6 files changed, 56 insertions(+), 182 deletions(-)\n\ndiff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt\nindex a67138a..897cd81 100644\n--- a/Documentation/git-branch.txt\n+++ b/Documentation/git-branch.txt\n@@ -11,7 +11,7 @@ SYNOPSIS\n 'git branch' [--color[=<when>] | --no-color] [-r | -a]\n \t[--list] [-v [--abbrev=<length> | --no-abbrev]]\n \t[--column[=<options>] | --no-column]\n-\t[(--merged | --no-merged | --contains) [<commit>]] [<pattern>...]\n+\t[(--merged | --no-merged | --contains) [<commit>]] [--sort=<key>] [<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@@ -229,6 +229,13 @@ start-point is either a local or remote-tracking branch.\n \tThe new name for an existing branch. The same restrictions as for\n \t<branchname> apply.\n \n+--sort=<key>::\n+\tSort based on the key given. Prefix `-` to sort in descending\n+\torder of the value. You may use the --sort=<key> option\n+\tmultiple times, in which case the last key becomes the primary\n+\tkey. The keys supported are the same as those in `git\n+\tfor-each-ref`. Sort order defaults to sorting based on branch\n+\ttype.\n \n Examples\n --------\ndiff --git a/builtin/branch.c b/builtin/branch.c\nindex 5cb7ef0..e0aa44c 100644\n--- a/builtin/branch.c\n+++ b/builtin/branch.c\n@@ -270,125 +270,6 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,\n \treturn(ret);\n }\n \n-static char *resolve_symref(const char *src, const char *prefix)\n-{\n-\tunsigned char sha1[20];\n-\tint flag;\n-\tconst char *dst;\n-\n-\tdst = resolve_ref_unsafe(src, 0, sha1, &flag);\n-\tif (!(dst && (flag & REF_ISSYMREF)))\n-\t\treturn NULL;\n-\tif (prefix)\n-\t\tskip_prefix(dst, prefix, &dst);\n-\treturn xstrdup(dst);\n-}\n-\n-static int match_patterns(const char **pattern, const char *refname)\n-{\n-\tif (!*pattern)\n-\t\treturn 1; /* no pattern always matches */\n-\twhile (*pattern) {\n-\t\tif (!wildmatch(*pattern, refname, 0, NULL))\n-\t\t\treturn 1;\n-\t\tpattern++;\n-\t}\n-\treturn 0;\n-}\n-\n-/*\n- * Allocate memory for a new ref_array_item and insert that into the\n- * given ref_array. Doesn't take the objectname unlike\n- * new_ref_array_item(). This is a temporary function which will be\n- * removed when we port branch.c to use ref-filter APIs.\n- */\n-static struct ref_array_item *ref_array_append(struct ref_array *array, const char *refname)\n-{\n-\tsize_t len = strlen(refname);\n-\tstruct ref_array_item *ref = xcalloc(1, sizeof(struct ref_array_item) + len + 1);\n-\tmemcpy(ref->refname, refname, len);\n-\tref->refname[len] = '\\0';\n-\tREALLOC_ARRAY(array->items, array->nr + 1);\n-\tarray->items[array->nr++] = ref;\n-\treturn ref;\n-}\n-\n-static int append_ref(const char *refname, const struct object_id *oid, int flags, void *cb_data)\n-{\n-\tstruct ref_filter_cbdata *cb = (struct ref_filter_cbdata *)(cb_data);\n-\tstruct ref_filter *filter = cb->filter;\n-\tstruct ref_array *array = cb->array;\n-\tstruct ref_array_item *item;\n-\tstruct commit *commit;\n-\tint kind, i;\n-\tconst char *prefix, *orig_refname = refname;\n-\n-\tstatic struct {\n-\t\tint kind;\n-\t\tconst char *prefix;\n-\t} ref_kind[] = {\n-\t\t{ FILTER_REFS_BRANCHES, \"refs/heads/\" },\n-\t\t{ FILTER_REFS_REMOTES, \"refs/remotes/\" },\n-\t};\n-\n-\t/* Detect kind */\n-\tfor (i = 0; i < ARRAY_SIZE(ref_kind); i++) {\n-\t\tprefix = ref_kind[i].prefix;\n-\t\tif (skip_prefix(refname, prefix, &refname)) {\n-\t\t\tkind = ref_kind[i].kind;\n-\t\t\tbreak;\n-\t\t}\n-\t}\n-\tif (ARRAY_SIZE(ref_kind) <= i) {\n-\t\tif (!strcmp(refname, \"HEAD\"))\n-\t\t\tkind = FILTER_REFS_DETACHED_HEAD;\n-\t\telse\n-\t\t\treturn 0;\n-\t}\n-\n-\t/* Don't add types the caller doesn't want */\n-\tif ((kind & filter->kind) == 0)\n-\t\treturn 0;\n-\n-\tif (!match_patterns(filter->name_patterns, refname))\n-\t\treturn 0;\n-\n-\tcommit = NULL;\n-\tif (filter->verbose || filter->with_commit || filter->merge != REF_FILTER_MERGED_NONE) {\n-\t\tcommit = lookup_commit_reference_gently(oid->hash, 1);\n-\t\tif (!commit)\n-\t\t\treturn 0;\n-\n-\t\t/* Filter with with_commit if specified */\n-\t\tif (!is_descendant_of(commit, filter->with_commit))\n-\t\t\treturn 0;\n-\n-\t\tif (filter->merge != REF_FILTER_MERGED_NONE)\n-\t\t\tadd_pending_object(array->revs,\n-\t\t\t\t\t   (struct object *)commit, refname);\n-\t}\n-\n-\titem = ref_array_append(array, refname);\n-\n-\t/* Record the new item */\n-\titem->kind = kind;\n-\titem->commit = commit;\n-\titem->symref = resolve_symref(orig_refname, prefix);\n-\titem->ignore = 0;\n-\n-\treturn 0;\n-}\n-\n-static int ref_cmp(const void *r1, const void *r2)\n-{\n-\tstruct ref_array_item *c1 = *((struct ref_array_item **)r1);\n-\tstruct ref_array_item *c2 = *((struct ref_array_item **)r2);\n-\n-\tif (c1->kind != c2->kind)\n-\t\treturn c1->kind - c2->kind;\n-\treturn strcmp(c1->refname, c2->refname);\n-}\n-\n static void fill_tracking_info(struct strbuf *stat, const char *branch_name,\n \t\tint show_upstream_ref)\n {\n@@ -452,7 +333,7 @@ static void fill_tracking_info(struct strbuf *stat, const char *branch_name,\n }\n \n static void add_verbose_info(struct strbuf *out, struct ref_array_item *item,\n-\t\t\t     struct ref_filter *filter)\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@@ -464,7 +345,7 @@ static void add_verbose_info(struct strbuf *out, struct ref_array_item *item,\n \t}\n \n \tif (item->kind == FILTER_REFS_BRANCHES)\n-\t\tfill_tracking_info(&stat, item->refname, filter->verbose > 1);\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.sha1, filter->abbrev),\n@@ -504,8 +385,8 @@ static char *get_head_description(void)\n \treturn strbuf_detach(&desc, NULL);\n }\n \n-static void print_ref_item(struct ref_array_item *item, int maxwidth,\n-\t\t\t   struct ref_filter *filter, const char *remote_prefix)\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@@ -515,17 +396,16 @@ static void print_ref_item(struct ref_array_item *item, int maxwidth,\n \tconst char *desc = item->refname;\n \tchar *to_free = NULL;\n \n-\tif (item->ignore)\n-\t\treturn;\n-\n \tswitch (item->kind) {\n \tcase FILTER_REFS_BRANCHES:\n-\t\tif (!filter->detached && !strcmp(item->refname, head))\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@@ -554,11 +434,13 @@ static void print_ref_item(struct ref_array_item *item, int maxwidth,\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\tstrbuf_addf(&out, \" -> %s\", item->symref);\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);\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@@ -575,11 +457,13 @@ static int calc_maxwidth(struct ref_array *refs, int remote_bonus)\n \tint i, max = 0;\n \tfor (i = 0; i < refs->nr; i++) {\n \t\tstruct ref_array_item *it = refs->items[i];\n+\t\tconst char *desc = it->refname;\n \t\tint w;\n \n-\t\tif (it->ignore)\n-\t\t\tcontinue;\n-\t\tw = utf8_strwidth(it->refname);\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+\n \t\tif (it->kind == FILTER_REFS_REMOTES)\n \t\t\tw += remote_bonus;\n \t\tif (w > max)\n@@ -588,14 +472,14 @@ static int calc_maxwidth(struct ref_array *refs, int remote_bonus)\n \treturn max;\n }\n \n-static void print_ref_list(struct ref_filter *filter)\n+static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sorting)\n {\n \tint i;\n \tstruct ref_array array;\n-\tstruct ref_filter_cbdata data;\n \tint maxwidth = 0;\n \tconst char *remote_prefix = \"\";\n-\tstruct rev_info revs;\n+\tstruct ref_sorting def_sorting;\n+\tconst char *sort_type = \"type\";\n \n \t/*\n \t * If we are listing more than just remote branches,\n@@ -606,60 +490,30 @@ static void print_ref_list(struct ref_filter *filter)\n \t\tremote_prefix = \"remotes/\";\n \n \tmemset(&array, 0, sizeof(array));\n-\tif (filter->merge != REF_FILTER_MERGED_NONE)\n-\t\tinit_revisions(&revs, NULL);\n-\n-\tdata.array = &array;\n-\tdata.filter = filter;\n-\tarray.revs = &revs;\n \n-\t/*\n-\t * First we obtain all regular branch refs and if the HEAD is\n-\t * detached then we insert that ref to the end of the ref_fist\n-\t * so that it can be printed and removed first.\n-\t */\n-\tfor_each_rawref(append_ref, &data);\n-\tif (filter->detached)\n-\t\thead_ref(append_ref, &data);\n-\t/*\n-\t * The following implementation is currently duplicated in ref-filter. It\n-\t * will eventually be removed when we port branch.c to use ref-filter APIs.\n-\t */\n-\tif (filter->merge != REF_FILTER_MERGED_NONE) {\n-\t\tfilter->merge_commit->object.flags |= UNINTERESTING;\n-\t\tadd_pending_object(&revs, &filter->merge_commit->object, \"\");\n-\t\trevs.limited = 1;\n-\n-\t\tif (prepare_revision_walk(&revs))\n-\t\t\tdie(_(\"revision walk setup failed\"));\n-\n-\t\tfor (i = 0; i < array.nr; i++) {\n-\t\t\tstruct ref_array_item *item = array.items[i];\n-\t\t\tstruct commit *commit = item->commit;\n-\t\t\tint is_merged = !!(commit->object.flags & UNINTERESTING);\n-\t\t\titem->ignore = is_merged != (filter->merge == REF_FILTER_MERGED_INCLUDE);\n-\t\t}\n+\tverify_ref_format(\"%(refname)%(symref)\");\n+\tfilter_refs(&array, filter, filter->kind | FILTER_REFS_INCLUDE_BROKEN);\n \n-\t\tfor (i = 0; i < array.nr; i++) {\n-\t\t\tstruct ref_array_item *item = array.items[i];\n-\t\t\tclear_commit_marks(item->commit, ALL_REV_FLAGS);\n-\t\t}\n-\t\tclear_commit_marks(filter->merge_commit, ALL_REV_FLAGS);\n-\t}\n \tif (filter->verbose)\n \t\tmaxwidth = calc_maxwidth(&array, strlen(remote_prefix));\n \n \t/* Print detached HEAD before sorting and printing the rest */\n \tif (filter->kind & FILTER_REFS_DETACHED_HEAD) {\n-\t\tprint_ref_item(array.items[array.nr - 1], maxwidth, filter, remote_prefix);\n+\t\tformat_and_print_ref_item(array.items[array.nr - 1], maxwidth, filter, remote_prefix);\n \t\tfree_array_item(array.items[array.nr - 1]);\n \t\tarray.nr--;\n \t}\n \n-\tqsort(array.items, array.nr, sizeof(struct ref_array_item *), ref_cmp);\n+\tif (!sorting) {\n+\t\tdef_sorting.next = NULL;\n+\t\tdef_sorting.atom = parse_ref_filter_atom(sort_type,\n+\t\t\t\t\t\t\t sort_type + strlen(sort_type));\n+\t\tsorting = &def_sorting;\n+\t}\n+\tref_array_sort(sorting, &array);\n \n \tfor (i = 0; i < array.nr; i++)\n-\t\tprint_ref_item(array.items[i], maxwidth, filter, remote_prefix);\n+\t\tformat_and_print_ref_item(array.items[i], maxwidth, filter, remote_prefix);\n \n \tref_array_clear(&array);\n }\n@@ -761,6 +615,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)\n \tconst char *new_upstream = NULL;\n \tenum branch_track track;\n \tstruct ref_filter filter;\n+\tstatic struct ref_sorting *sorting = NULL, **sorting_tail = &sorting;\n \n \tstruct option options[] = {\n \t\tOPT_GROUP(N_(\"Generic options\")),\n@@ -795,6 +650,8 @@ int cmd_branch(int argc, const char **argv, const char *prefix)\n \t\tOPT_MERGED(&filter, N_(\"print only branches that are merged\")),\n \t\tOPT_NO_MERGED(&filter, N_(\"print only branches that are not merged\")),\n \t\tOPT_COLUMN(0, \"column\", &colopts, N_(\"list branches in columns\")),\n+\t\tOPT_CALLBACK(0 , \"sort\", sorting_tail, N_(\"key\"),\n+\t\t\t     N_(\"field name to sort on\"), &parse_opt_ref_sorting),\n \t\tOPT_END(),\n \t};\n \n@@ -853,7 +710,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);\n+\t\tprint_ref_list(&filter, sorting);\n \t\tprint_columns(&output, colopts, NULL);\n \t\tstring_list_clear(&output, 0);\n \t\treturn 0;\ndiff --git a/ref-filter.c b/ref-filter.c\nindex bbf5648..3cd0c00 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -1226,7 +1226,7 @@ static int ref_filter_handler(const char *refname, const struct object_id *oid,\n \t * obtain the commit using the 'oid' available and discard all\n \t * non-commits early. The actual filtering is done later.\n \t */\n-\tif (filter->merge_commit || filter->with_commit) {\n+\tif (filter->merge_commit || filter->with_commit || filter->verbose) {\n \t\tcommit = lookup_commit_reference_gently(oid->hash, 1);\n \t\tif (!commit)\n \t\t\treturn 0;\ndiff --git a/ref-filter.h b/ref-filter.h\nindex ae409b7..3e25d84 100644\n--- a/ref-filter.h\n+++ b/ref-filter.h\n@@ -35,7 +35,6 @@ struct ref_array_item {\n \tunsigned char objectname[20];\n \tint flag;\n \tunsigned int kind;\n-\tint ignore : 1; /* To be removed in the next patch */\n \tconst char *symref;\n \tstruct commit *commit;\n \tstruct atom_value *value;\ndiff --git a/t/t1430-bad-ref-name.sh b/t/t1430-bad-ref-name.sh\nindex 16d0b8b..db3627e 100755\n--- a/t/t1430-bad-ref-name.sh\n+++ b/t/t1430-bad-ref-name.sh\n@@ -41,7 +41,7 @@ test_expect_success 'fast-import: fail on invalid branch name \"bad[branch]name\"'\n test_expect_success 'git branch shows badly named ref' '\n \tcp .git/refs/heads/master .git/refs/heads/broken...ref &&\n \ttest_when_finished \"rm -f .git/refs/heads/broken...ref\" &&\n-\tgit branch >output &&\n+\tgit branch 2>output &&\n \tgrep -e \"broken\\.\\.\\.ref\" output\n '\n \ndiff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh\nindex f51d0f3..53d166d 100755\n--- a/t/t3203-branch-output.sh\n+++ b/t/t3203-branch-output.sh\n@@ -143,4 +143,15 @@ EOF\n \ttest_i18ncmp expect actual\n '\n \n+test_expect_success 'git branch `--sort` option' '\n+\tcat >expect <<-\\EOF &&\n+\t* (HEAD detached from fromtag)\n+\t  branch-two\n+\t  branch-one\n+\t  master\n+\tEOF\n+\tgit branch --sort=objectsize >actual &&\n+\ttest_i18ncmp expect actual\n+'\n+\n test_done\n-- \n2.5.0\n"},{"id":"268506","messageId":"1440226309-25415-9-git-send-email-Karthik.188@gmail.com","threadId":"40156","inReplyTo":"1440226309-25415-1-git-send-email-Karthik.188@gmail.com","subject":"[PATCH v3 8/8] branch: add '--points-at' option","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-08-22T06:51:49Z","receivedAt":"2015-08-22T06:51:49Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"Add the '--points-at' option provided by 'ref-filter'. The option lets\nthe user to list only branches which points at the given object.\n\nAdd documentation and tests 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 | 6 +++++-\n builtin/branch.c             | 7 ++++++-\n t/t3203-branch-output.sh     | 9 +++++++++\n 3 files changed, 20 insertions(+), 2 deletions(-)\n\ndiff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt\nindex 897cd81..211cfc3 100644\n--- a/Documentation/git-branch.txt\n+++ b/Documentation/git-branch.txt\n@@ -11,7 +11,8 @@ SYNOPSIS\n 'git branch' [--color[=<when>] | --no-color] [-r | -a]\n \t[--list] [-v [--abbrev=<length> | --no-abbrev]]\n \t[--column[=<options>] | --no-column]\n-\t[(--merged | --no-merged | --contains) [<commit>]] [--sort=<key>] [<pattern>...]\n+\t[(--merged | --no-merged | --contains) [<commit>]] [--sort=<key>]\n+\t[--points-at <object>] [<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@@ -237,6 +238,9 @@ start-point is either a local or remote-tracking branch.\n \tfor-each-ref`. Sort order defaults to sorting based on branch\n \ttype.\n \n+--points-at <object>::\n+\tOnly list branches of the given object.\n+\n Examples\n --------\n \ndiff --git a/builtin/branch.c b/builtin/branch.c\nindex e0aa44c..32a0d11 100644\n--- a/builtin/branch.c\n+++ b/builtin/branch.c\n@@ -26,6 +26,7 @@ static const char * const builtin_branch_usage[] = {\n \tN_(\"git branch [<options>] [-l] [-f] <branch-name> [<start-point>]\"),\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 \tNULL\n };\n \n@@ -652,6 +653,10 @@ int cmd_branch(int argc, const char **argv, const char *prefix)\n \t\tOPT_COLUMN(0, \"column\", &colopts, N_(\"list branches in columns\")),\n \t\tOPT_CALLBACK(0 , \"sort\", sorting_tail, N_(\"key\"),\n \t\t\t     N_(\"field name to sort on\"), &parse_opt_ref_sorting),\n+\t\t{\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_END(),\n \t};\n \n@@ -680,7 +685,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)\n \tif (!delete && !rename && !edit_description && !new_upstream && !unset_upstream && argc == 0)\n \t\tlist = 1;\n \n-\tif (filter.with_commit || filter.merge != REF_FILTER_MERGED_NONE)\n+\tif (filter.with_commit || filter.merge != REF_FILTER_MERGED_NONE || filter.points_at.nr)\n \t\tlist = 1;\n \n \tif (!!delete + !!rename + !!new_upstream +\ndiff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh\nindex 53d166d..c819f3e 100755\n--- a/t/t3203-branch-output.sh\n+++ b/t/t3203-branch-output.sh\n@@ -154,4 +154,13 @@ test_expect_success 'git branch `--sort` option' '\n \ttest_i18ncmp expect actual\n '\n \n+test_expect_success 'git branch --points-at option' '\n+\tcat >expect <<-\\EOF &&\n+\t  master\n+\t  branch-one\n+\tEOF\n+\tgit branch --points-at=branch-one >actual &&\n+\ttest_cmp expect actual\n+'\n+\n test_done\n-- \n2.5.0\n"},{"id":"268512","messageId":"CAP8UFD3rXJqB1DEz5LfdM8xxanzoJp6J=weED+FygeZmufG4Sw@mail.gmail.com","threadId":"40156","inReplyTo":"1440226309-25415-8-git-send-email-Karthik.188@gmail.com","subject":"Re: [PATCH v3 7/8] branch.c: use 'ref-filter' APIs","fromName":"Christian Couder","fromEmail":"christian.couder@gmail.com","sentAt":"2015-08-22T15:51:42Z","receivedAt":"2015-08-22T15:51:42Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"On Sat, Aug 22, 2015 at 8:51 AM, Karthik Nayak <karthik.188@gmail.com> wrote:\n>\n> The test t1430 'git branch shows badly named ref' has been changed to\n> check the stderr for the warning regarding the broken ref. This is\n> done as ref-filter throws a warning for broken refs rather than\n> directly printing them.\n\n[...]\n\n> diff --git a/t/t1430-bad-ref-name.sh b/t/t1430-bad-ref-name.sh\n> index 16d0b8b..db3627e 100755\n> --- a/t/t1430-bad-ref-name.sh\n> +++ b/t/t1430-bad-ref-name.sh\n> @@ -41,7 +41,7 @@ test_expect_success 'fast-import: fail on invalid branch name \"bad[branch]name\"'\n>  test_expect_success 'git branch shows badly named ref' '\n>         cp .git/refs/heads/master .git/refs/heads/broken...ref &&\n>         test_when_finished \"rm -f .git/refs/heads/broken...ref\" &&\n> -       git branch >output &&\n> +       git branch 2>output &&\n>         grep -e \"broken\\.\\.\\.ref\" output\n>  '\n\nMaybe the test could be renamed to 'git branch warns about badly named\nref' and maybe you could also check that \"broken\\.\\.\\.ref\" is not\nprinted on stdout.\n\nThanks,\nChristian.\n"},{"id":"268514","messageId":"CAOLa=ZSwU94-JgAdw-xoL5mDNVL8nsbuBCD-MhN3H+m1gFD9gQ@mail.gmail.com","threadId":"40156","inReplyTo":"CAP8UFD3rXJqB1DEz5LfdM8xxanzoJp6J=weED+FygeZmufG4Sw@mail.gmail.com","subject":"Re: [PATCH v3 7/8] branch.c: use 'ref-filter' APIs","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-08-22T17:50:32Z","receivedAt":"2015-08-22T17:50:32Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"On Sat, Aug 22, 2015 at 9:21 PM, Christian Couder\n<christian.couder@gmail.com> wrote:\n> On Sat, Aug 22, 2015 at 8:51 AM, Karthik Nayak <karthik.188@gmail.com> wrote:\n>>\n>> The test t1430 'git branch shows badly named ref' has been changed to\n>> check the stderr for the warning regarding the broken ref. This is\n>> done as ref-filter throws a warning for broken refs rather than\n>> directly printing them.\n>\n> [...]\n>\n>> diff --git a/t/t1430-bad-ref-name.sh b/t/t1430-bad-ref-name.sh\n>> index 16d0b8b..db3627e 100755\n>> --- a/t/t1430-bad-ref-name.sh\n>> +++ b/t/t1430-bad-ref-name.sh\n>> @@ -41,7 +41,7 @@ test_expect_success 'fast-import: fail on invalid branch name \"bad[branch]name\"'\n>>  test_expect_success 'git branch shows badly named ref' '\n>>         cp .git/refs/heads/master .git/refs/heads/broken...ref &&\n>>         test_when_finished \"rm -f .git/refs/heads/broken...ref\" &&\n>> -       git branch >output &&\n>> +       git branch 2>output &&\n>>         grep -e \"broken\\.\\.\\.ref\" output\n>>  '\n>\n> Maybe the test could be renamed to 'git branch warns about badly named\n> ref' and maybe you could also check that \"broken\\.\\.\\.ref\" is not\n> printed on stdout.\n>\n\nThe name change sounds reasonable, do we really need to check for it in the\nstdout?\n\n-- \nRegards,\nKarthik Nayak\n"},{"id":"268588","messageId":"xmqqtwro4mpu.fsf@gitster.dls.corp.google.com","threadId":"40156","inReplyTo":"CAOLa=ZSwU94-JgAdw-xoL5mDNVL8nsbuBCD-MhN3H+m1gFD9gQ@mail.gmail.com","subject":"Re: [PATCH v3 7/8] branch.c: use 'ref-filter' APIs","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-08-24T17:31:41Z","receivedAt":"2015-08-24T17:31:41Z","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>>>  test_expect_success 'git branch shows badly named ref' '\n>>>         cp .git/refs/heads/master .git/refs/heads/broken...ref &&\n>>>         test_when_finished \"rm -f .git/refs/heads/broken...ref\" &&\n>>> -       git branch >output &&\n>>> +       git branch 2>output &&\n>>>         grep -e \"broken\\.\\.\\.ref\" output\n>>>  '\n>>\n>> Maybe the test could be renamed to 'git branch warns about badly named\n>> ref' and maybe you could also check that \"broken\\.\\.\\.ref\" is not\n>> printed on stdout.\n>\n> The name change sounds reasonable, do we really need to check for it in the\n> stdout?\n\nI think Christian meant \"we should check in both\", i.e.\n\n\tgit branch >output 2>error &&\n        grep \"broken\\.\\.\\.ref\" error &&\n        ! grep \"broken\\.\\.\\.ref\" output\n\nor something like that.  That way, you are effectively specifying in\nthe test that badly named refs must not be included in the output,\nso somebody who changes that in the future needs to justify why\nincluding them in the output is a good idea when updating the test.\n"},{"id":"268593","messageId":"CAOLa=ZQzV5NB78593r+qXMvS249OBOkRK+ofU30AFzcf97+hsw@mail.gmail.com","threadId":"40156","inReplyTo":"xmqqtwro4mpu.fsf@gitster.dls.corp.google.com","subject":"Re: [PATCH v3 7/8] branch.c: use 'ref-filter' APIs","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-08-24T18:10:37Z","receivedAt":"2015-08-24T18:10:37Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"On Mon, Aug 24, 2015 at 11:01 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> Karthik Nayak <karthik.188@gmail.com> writes:\n>\n>>>>  test_expect_success 'git branch shows badly named ref' '\n>>>>         cp .git/refs/heads/master .git/refs/heads/broken...ref &&\n>>>>         test_when_finished \"rm -f .git/refs/heads/broken...ref\" &&\n>>>> -       git branch >output &&\n>>>> +       git branch 2>output &&\n>>>>         grep -e \"broken\\.\\.\\.ref\" output\n>>>>  '\n>>>\n>>> Maybe the test could be renamed to 'git branch warns about badly named\n>>> ref' and maybe you could also check that \"broken\\.\\.\\.ref\" is not\n>>> printed on stdout.\n>>\n>> The name change sounds reasonable, do we really need to check for it in the\n>> stdout?\n>\n> I think Christian meant \"we should check in both\", i.e.\n>\n>         git branch >output 2>error &&\n>         grep \"broken\\.\\.\\.ref\" error &&\n>         ! grep \"broken\\.\\.\\.ref\" output\n>\n> or something like that.  That way, you are effectively specifying in\n> the test that badly named refs must not be included in the output,\n> so somebody who changes that in the future needs to justify why\n> including them in the output is a good idea when updating the test.\n>\n\nAh! okay, I get what you're saying. Should I reroll it? Or a squash in?\n\n-- \nRegards,\nKarthik Nayak\n"}]}