{"thread":{"id":"40342","subject":"[PATCH v4 1/8] branch: refactor width computation","startedAt":"2015-09-13T07:23:47Z","lastAt":"2015-09-17T18:25:58Z","messageCount":38,"participants":["Karthik Nayak","Matthieu Moy","Eric Sunshine","Junio C Hamano"],"isPatch":true,"patchVersion":4,"patchTotal":8},"messages":[{"id":"269860","messageId":"1442129035-31386-1-git-send-email-Karthik.188@gmail.com","threadId":"40342","inReplyTo":null,"subject":"[PATCH v4 0/8] port the filtering part of branch.c to use ref-filter APIs","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-09-13T07:23:47Z","receivedAt":"2015-09-13T07:23:47Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"This makes branch.c use the ref-filter APIs for filtering of\nrefs for 'git branch -l'. This is part of the series of unification\nof code of 'git branch -l, git tag -l and git for-each-ref'.\n\nThe previous version can be found here:\nhttp://thread.gmane.org/gmane.comp.version-control.git/276377\n\nThe changes in this version are:\n[7/8]: Change the tests check for stdout and stderr. (check interdiff)\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      |  31 ++-\n t/t3203-branch-output.sh     |  20 ++\n 6 files changed, 216 insertions(+), 366 deletions(-)\n\ninterdiff:\n\ndiff --git a/t/t1430-bad-ref-name.sh b/t/t1430-bad-ref-name.sh\nindex db3627e..070cf06 100755\n--- a/t/t1430-bad-ref-name.sh\n+++ b/t/t1430-bad-ref-name.sh\n@@ -38,18 +38,20 @@ 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_success 'git branch shows badly named ref' '\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+\tgit branch >output 2>error &&\n+\tgrep -e \"broken\\.\\.\\.ref\" error &&\n+\t! grep -e \"broken\\.\\.\\.ref\" output\n '\n \n test_expect_success 'branch -d can delete 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 -d broken...ref &&\n-\tgit branch >output &&\n+\tgit branch >output 2>error &&\n+\t! grep -e \"broken\\.\\.\\.ref\" error &&\n \t! grep -e \"broken\\.\\.\\.ref\" output\n '\n \n@@ -57,7 +59,8 @@ test_expect_success 'branch -D can delete 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 -D broken...ref &&\n-\tngit branch >output &&\n+\tgit branch >output 2>error &&\n+\t! grep -e \"broken\\.\\.\\.ref\" error &&\n \t! grep -e \"broken\\.\\.\\.ref\" output\n '\n \n@@ -85,7 +88,8 @@ test_expect_success 'branch -D cannot delete absolute path' '\n test_expect_success 'git branch cannot create a badly named ref' '\n \ttest_when_finished \"rm -f .git/refs/heads/broken...ref\" &&\n \ttest_must_fail git branch broken...ref &&\n-\tgit branch >output &&\n+\tgit branch >output 2>error &&\n+\t! grep -e \"broken\\.\\.\\.ref\" error &&\n \t! grep -e \"broken\\.\\.\\.ref\" output\n '\n \n@@ -95,7 +99,8 @@ test_expect_success 'branch -m cannot rename to a bad ref name' '\n \tgit branch goodref &&\n \ttest_must_fail git branch -m goodref broken...ref &&\n \ttest_cmp_rev master goodref &&\n-\tgit branch >output &&\n+\tgit branch >output 2>error &&\n+\t! grep -e \"broken\\.\\.\\.ref\" error &&\n \t! grep -e \"broken\\.\\.\\.ref\" output\n '\n \n@@ -104,14 +109,16 @@ test_expect_failure 'branch -m can rename from a bad ref name' '\n \ttest_when_finished \"rm -f .git/refs/heads/broken...ref\" &&\n \tgit branch -m broken...ref renamed &&\n \ttest_cmp_rev master renamed &&\n-\tgit branch >output &&\n+\tgit branch >output 2>error &&\n+\t! grep -e \"broken\\.\\.\\.ref\" error &&\n \t! grep -e \"broken\\.\\.\\.ref\" output\n '\n \n test_expect_success 'push cannot create a badly named ref' '\n \ttest_when_finished \"rm -f .git/refs/heads/broken...ref\" &&\n \ttest_must_fail git push \"file://$(pwd)\" HEAD:refs/heads/broken...ref &&\n-\tgit branch >output &&\n+\tgit branch >output 2>error &&\n+\t! grep -e \"broken\\.\\.\\.ref\" error &&\n \t! grep -e \"broken\\.\\.\\.ref\" output\n '\n \n@@ -131,7 +138,8 @@ test_expect_failure 'push --mirror can delete badly named ref' '\n \t\tcp .git/refs/heads/master .git/refs/heads/broken...ref\n \t) &&\n \tgit -C src push --mirror \"file://$top/dest\" &&\n-\tgit -C dest branch >output &&\n+\tgit -C dest branch >output 2>error &&\n+\t! grep -e \"broken\\.\\.\\.ref\" error\n \t! grep -e \"broken\\.\\.\\.ref\" output\n '\n \n@@ -159,7 +167,8 @@ test_expect_success 'update-ref -d can delete broken name' '\n \tcp .git/refs/heads/master .git/refs/heads/broken...ref &&\n \ttest_when_finished \"rm -f .git/refs/heads/broken...ref\" &&\n \tgit update-ref -d refs/heads/broken...ref &&\n-\tgit branch >output &&\n+\tgit branch >output 2>error &&\n+\t! grep -e \"broken\\.\\.\\.ref\" error &&\n \t! grep -e \"broken\\.\\.\\.ref\" output\n '\n\n-- \n2.5.1\n"},{"id":"269859","messageId":"1442129035-31386-2-git-send-email-Karthik.188@gmail.com","threadId":"40342","inReplyTo":"1442129035-31386-1-git-send-email-Karthik.188@gmail.com","subject":"[PATCH v4 1/8] branch: refactor width computation","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-09-13T07:23:48Z","receivedAt":"2015-09-13T07:23:48Z","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.1\n"},{"id":"269861","messageId":"1442129035-31386-3-git-send-email-Karthik.188@gmail.com","threadId":"40342","inReplyTo":"1442129035-31386-1-git-send-email-Karthik.188@gmail.com","subject":"[PATCH v4 2/8] branch: bump get_head_description() to the top","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-09-13T07:23:49Z","receivedAt":"2015-09-13T07:23:49Z","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.1\n"},{"id":"269862","messageId":"1442129035-31386-4-git-send-email-Karthik.188@gmail.com","threadId":"40342","inReplyTo":"1442129035-31386-1-git-send-email-Karthik.188@gmail.com","subject":"[PATCH v4 3/8] branch: roll show_detached HEAD into regular ref_list","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-09-13T07:23:50Z","receivedAt":"2015-09-13T07:23:50Z","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.1\n"},{"id":"269863","messageId":"1442129035-31386-5-git-send-email-Karthik.188@gmail.com","threadId":"40342","inReplyTo":"1442129035-31386-1-git-send-email-Karthik.188@gmail.com","subject":"[PATCH v4 4/8] branch: move 'current' check down to the presentation layer","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-09-13T07:23:51Z","receivedAt":"2015-09-13T07:23:51Z","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.1\n"},{"id":"269864","messageId":"1442129035-31386-6-git-send-email-Karthik.188@gmail.com","threadId":"40342","inReplyTo":"1442129035-31386-1-git-send-email-Karthik.188@gmail.com","subject":"[PATCH v4 5/8] branch: drop non-commit error reporting","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-09-13T07:23:52Z","receivedAt":"2015-09-13T07:23:52Z","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.1\n"},{"id":"269865","messageId":"1442129035-31386-7-git-send-email-Karthik.188@gmail.com","threadId":"40342","inReplyTo":"1442129035-31386-1-git-send-email-Karthik.188@gmail.com","subject":"[PATCH v4 6/8] branch.c: use 'ref-filter' data structures","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-09-13T07:23:53Z","receivedAt":"2015-09-13T07:23:53Z","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 fd839ac..c059d87 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -1356,7 +1356,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 a5cfa5e..56980a3 100644\n--- a/ref-filter.h\n+++ b/ref-filter.h\n@@ -36,6 +36,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@@ -45,6 +46,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@@ -60,9 +62,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@@ -86,6 +91,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.1\n"},{"id":"269866","messageId":"1442129035-31386-8-git-send-email-Karthik.188@gmail.com","threadId":"40342","inReplyTo":"1442129035-31386-1-git-send-email-Karthik.188@gmail.com","subject":"[PATCH v4 6/8] branch.c: use 'ref-filter' data structures","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-09-13T07:23:54Z","receivedAt":"2015-09-13T07:23:54Z","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      |  19 ++--\n t/t3203-branch-output.sh     |  11 +++\n 6 files changed, 65 insertions(+), 190 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 c059d87..c536aea 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -1331,7 +1331,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 56980a3..9316031 100644\n--- a/ref-filter.h\n+++ b/ref-filter.h\n@@ -36,7 +36,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..dacc186 100755\n--- a/t/t1430-bad-ref-name.sh\n+++ b/t/t1430-bad-ref-name.sh\n@@ -38,11 +38,12 @@ 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_success 'git branch shows badly named ref' '\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 >output &&\n-\tgrep -e \"broken\\.\\.\\.ref\" output\n+\tgit branch >output 2>error &&\n+\tgrep -e \"broken\\.\\.\\.ref\" error &&\n+\t! grep -e \"broken\\.\\.\\.ref\" output\n '\n \n test_expect_success 'branch -d can delete badly named ref' '\n@@ -95,8 +96,8 @@ test_expect_success 'branch -m cannot rename to a bad ref name' '\n \tgit branch goodref &&\n \ttest_must_fail git branch -m goodref broken...ref &&\n \ttest_cmp_rev master goodref &&\n-\tgit branch >output &&\n-\t! grep -e \"broken\\.\\.\\.ref\" output\n+\tgit branch >output 2>error &&\n+\t! grep -e \"broken\\.\\.\\.ref\" error\n '\n \n test_expect_failure 'branch -m can rename from a bad ref name' '\n@@ -104,8 +105,8 @@ test_expect_failure 'branch -m can rename from a bad ref name' '\n \ttest_when_finished \"rm -f .git/refs/heads/broken...ref\" &&\n \tgit branch -m broken...ref renamed &&\n \ttest_cmp_rev master renamed &&\n-\tgit branch >output &&\n-\t! grep -e \"broken\\.\\.\\.ref\" output\n+\tgit branch >output 2>error &&\n+\t! grep -e \"broken\\.\\.\\.ref\" error\n '\n \n test_expect_success 'push cannot create a badly named ref' '\n@@ -131,8 +132,8 @@ test_expect_failure 'push --mirror can delete badly named ref' '\n \t\tcp .git/refs/heads/master .git/refs/heads/broken...ref\n \t) &&\n \tgit -C src push --mirror \"file://$top/dest\" &&\n-\tgit -C dest branch >output &&\n-\t! grep -e \"broken\\.\\.\\.ref\" output\n+\tgit -C dest branch >output 2>error &&\n+\t! grep -e \"broken\\.\\.\\.ref\" error\n '\n \n test_expect_success 'rev-parse skips symref pointing to broken name' '\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.1\n"},{"id":"269867","messageId":"1442129035-31386-9-git-send-email-Karthik.188@gmail.com","threadId":"40342","inReplyTo":"1442129035-31386-1-git-send-email-Karthik.188@gmail.com","subject":"[PATCH v4 8/8] branch: add '--points-at' option","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-09-13T07:23:55Z","receivedAt":"2015-09-13T07:23:55Z","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.1\n"},{"id":"269868","messageId":"1442129398-31799-1-git-send-email-Karthik.188@gmail.com","threadId":"40342","inReplyTo":"1442129035-31386-1-git-send-email-Karthik.188@gmail.com","subject":"[PATCH v4 7/8] branch.c: use 'ref-filter' APIs","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-09-13T07:29:58Z","receivedAt":"2015-09-13T07:29:58Z","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      |  19 ++--\n t/t3203-branch-output.sh     |  11 +++\n 6 files changed, 65 insertions(+), 190 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 c059d87..c536aea 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -1331,7 +1331,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 56980a3..9316031 100644\n--- a/ref-filter.h\n+++ b/ref-filter.h\n@@ -36,7 +36,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..dacc186 100755\n--- a/t/t1430-bad-ref-name.sh\n+++ b/t/t1430-bad-ref-name.sh\n@@ -38,11 +38,12 @@ 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_success 'git branch shows badly named ref' '\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 >output &&\n-\tgrep -e \"broken\\.\\.\\.ref\" output\n+\tgit branch >output 2>error &&\n+\tgrep -e \"broken\\.\\.\\.ref\" error &&\n+\t! grep -e \"broken\\.\\.\\.ref\" output\n '\n \n test_expect_success 'branch -d can delete badly named ref' '\n@@ -95,8 +96,8 @@ test_expect_success 'branch -m cannot rename to a bad ref name' '\n \tgit branch goodref &&\n \ttest_must_fail git branch -m goodref broken...ref &&\n \ttest_cmp_rev master goodref &&\n-\tgit branch >output &&\n-\t! grep -e \"broken\\.\\.\\.ref\" output\n+\tgit branch >output 2>error &&\n+\t! grep -e \"broken\\.\\.\\.ref\" error\n '\n \n test_expect_failure 'branch -m can rename from a bad ref name' '\n@@ -104,8 +105,8 @@ test_expect_failure 'branch -m can rename from a bad ref name' '\n \ttest_when_finished \"rm -f .git/refs/heads/broken...ref\" &&\n \tgit branch -m broken...ref renamed &&\n \ttest_cmp_rev master renamed &&\n-\tgit branch >output &&\n-\t! grep -e \"broken\\.\\.\\.ref\" output\n+\tgit branch >output 2>error &&\n+\t! grep -e \"broken\\.\\.\\.ref\" error\n '\n \n test_expect_success 'push cannot create a badly named ref' '\n@@ -131,8 +132,8 @@ test_expect_failure 'push --mirror can delete badly named ref' '\n \t\tcp .git/refs/heads/master .git/refs/heads/broken...ref\n \t) &&\n \tgit -C src push --mirror \"file://$top/dest\" &&\n-\tgit -C dest branch >output &&\n-\t! grep -e \"broken\\.\\.\\.ref\" output\n+\tgit -C dest branch >output 2>error &&\n+\t! grep -e \"broken\\.\\.\\.ref\" error\n '\n \n test_expect_success 'rev-parse skips symref pointing to broken name' '\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.1\n"},{"id":"269869","messageId":"CAOLa=ZR_vLzUikDbs_GOswpjadsMYw6innJ1wqdGBeqneNF+HA@mail.gmail.com","threadId":"40342","inReplyTo":"1442129035-31386-8-git-send-email-Karthik.188@gmail.com","subject":"Re: [PATCH v4 6/8] branch.c: use 'ref-filter' data structures","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-09-13T07:32:17Z","receivedAt":"2015-09-13T07:32:17Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"On Sun, Sep 13, 2015 at 12:53 PM, Karthik Nayak <karthik.188@gmail.com> wrote:\n> Make 'branch.c' use 'ref-filter' APIs for iterating through refs\n> sorting. This removes most of the code used in 'branch.c' replacing it\n> with calls to the 'ref-filter' library.\n>\n> Make 'branch.c' use the 'filter_refs()' function provided by 'ref-filter'\n> to filter out tags based on the options set.\n>\n> We provide a sorting option provided for 'branch.c' by using the sorting\n> options provided by 'ref-filter'.\n>\n> Also remove the 'ignore' variable from ref_array_item as it was\n> previously used for the '--merged' option and now that is handled by\n> ref-filter.\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> Modify documentation and add tests for the same.\n>\n> Mentored-by: Christian Couder <christian.couder@gmail.com>\n> Mentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>\n> Signed-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      |  19 ++--\n>  t/t3203-branch-output.sh     |  11 +++\n>  6 files changed, 65 insertions(+), 190 deletions(-)\n>\n> diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt\n> index 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>         [--list] [-v [--abbrev=<length> | --no-abbrev]]\n>         [--column[=<options>] | --no-column]\n> -       [(--merged | --no-merged | --contains) [<commit>]] [<pattern>...]\n> +       [(--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>         The new name for an existing branch. The same restrictions as for\n>         <branchname> apply.\n>\n> +--sort=<key>::\n> +       Sort based on the key given. Prefix `-` to sort in descending\n> +       order of the value. You may use the --sort=<key> option\n> +       multiple times, in which case the last key becomes the primary\n> +       key. The keys supported are the same as those in `git\n> +       for-each-ref`. Sort order defaults to sorting based on branch\n> +       type.\n>\n>  Examples\n>  --------\n> diff --git a/builtin/branch.c b/builtin/branch.c\n> index 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>         return(ret);\n>  }\n>\n> -static char *resolve_symref(const char *src, const char *prefix)\n> -{\n> -       unsigned char sha1[20];\n> -       int flag;\n> -       const char *dst;\n> -\n> -       dst = resolve_ref_unsafe(src, 0, sha1, &flag);\n> -       if (!(dst && (flag & REF_ISSYMREF)))\n> -               return NULL;\n> -       if (prefix)\n> -               skip_prefix(dst, prefix, &dst);\n> -       return xstrdup(dst);\n> -}\n> -\n> -static int match_patterns(const char **pattern, const char *refname)\n> -{\n> -       if (!*pattern)\n> -               return 1; /* no pattern always matches */\n> -       while (*pattern) {\n> -               if (!wildmatch(*pattern, refname, 0, NULL))\n> -                       return 1;\n> -               pattern++;\n> -       }\n> -       return 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> -       size_t len = strlen(refname);\n> -       struct ref_array_item *ref = xcalloc(1, sizeof(struct ref_array_item) + len + 1);\n> -       memcpy(ref->refname, refname, len);\n> -       ref->refname[len] = '\\0';\n> -       REALLOC_ARRAY(array->items, array->nr + 1);\n> -       array->items[array->nr++] = ref;\n> -       return ref;\n> -}\n> -\n> -static int append_ref(const char *refname, const struct object_id *oid, int flags, void *cb_data)\n> -{\n> -       struct ref_filter_cbdata *cb = (struct ref_filter_cbdata *)(cb_data);\n> -       struct ref_filter *filter = cb->filter;\n> -       struct ref_array *array = cb->array;\n> -       struct ref_array_item *item;\n> -       struct commit *commit;\n> -       int kind, i;\n> -       const char *prefix, *orig_refname = refname;\n> -\n> -       static struct {\n> -               int kind;\n> -               const char *prefix;\n> -       } ref_kind[] = {\n> -               { FILTER_REFS_BRANCHES, \"refs/heads/\" },\n> -               { FILTER_REFS_REMOTES, \"refs/remotes/\" },\n> -       };\n> -\n> -       /* Detect kind */\n> -       for (i = 0; i < ARRAY_SIZE(ref_kind); i++) {\n> -               prefix = ref_kind[i].prefix;\n> -               if (skip_prefix(refname, prefix, &refname)) {\n> -                       kind = ref_kind[i].kind;\n> -                       break;\n> -               }\n> -       }\n> -       if (ARRAY_SIZE(ref_kind) <= i) {\n> -               if (!strcmp(refname, \"HEAD\"))\n> -                       kind = FILTER_REFS_DETACHED_HEAD;\n> -               else\n> -                       return 0;\n> -       }\n> -\n> -       /* Don't add types the caller doesn't want */\n> -       if ((kind & filter->kind) == 0)\n> -               return 0;\n> -\n> -       if (!match_patterns(filter->name_patterns, refname))\n> -               return 0;\n> -\n> -       commit = NULL;\n> -       if (filter->verbose || filter->with_commit || filter->merge != REF_FILTER_MERGED_NONE) {\n> -               commit = lookup_commit_reference_gently(oid->hash, 1);\n> -               if (!commit)\n> -                       return 0;\n> -\n> -               /* Filter with with_commit if specified */\n> -               if (!is_descendant_of(commit, filter->with_commit))\n> -                       return 0;\n> -\n> -               if (filter->merge != REF_FILTER_MERGED_NONE)\n> -                       add_pending_object(array->revs,\n> -                                          (struct object *)commit, refname);\n> -       }\n> -\n> -       item = ref_array_append(array, refname);\n> -\n> -       /* Record the new item */\n> -       item->kind = kind;\n> -       item->commit = commit;\n> -       item->symref = resolve_symref(orig_refname, prefix);\n> -       item->ignore = 0;\n> -\n> -       return 0;\n> -}\n> -\n> -static int ref_cmp(const void *r1, const void *r2)\n> -{\n> -       struct ref_array_item *c1 = *((struct ref_array_item **)r1);\n> -       struct ref_array_item *c2 = *((struct ref_array_item **)r2);\n> -\n> -       if (c1->kind != c2->kind)\n> -               return c1->kind - c2->kind;\n> -       return strcmp(c1->refname, c2->refname);\n> -}\n> -\n>  static void fill_tracking_info(struct strbuf *stat, const char *branch_name,\n>                 int 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> -                            struct ref_filter *filter)\n> +                            struct ref_filter *filter, const char *refname)\n>  {\n>         struct strbuf subject = STRBUF_INIT, stat = STRBUF_INIT;\n>         const char *sub = _(\" **** invalid ref ****\");\n> @@ -464,7 +345,7 @@ static void add_verbose_info(struct strbuf *out, struct ref_array_item *item,\n>         }\n>\n>         if (item->kind == FILTER_REFS_BRANCHES)\n> -               fill_tracking_info(&stat, item->refname, filter->verbose > 1);\n> +               fill_tracking_info(&stat, refname, filter->verbose > 1);\n>\n>         strbuf_addf(out, \" %s %s%s\",\n>                 find_unique_abbrev(item->commit->object.sha1, filter->abbrev),\n> @@ -504,8 +385,8 @@ static char *get_head_description(void)\n>         return strbuf_detach(&desc, NULL);\n>  }\n>\n> -static void print_ref_item(struct ref_array_item *item, int maxwidth,\n> -                          struct ref_filter *filter, const char *remote_prefix)\n> +static void format_and_print_ref_item(struct ref_array_item *item, int maxwidth,\n> +                                     struct ref_filter *filter, const char *remote_prefix)\n>  {\n>         char c;\n>         int current = 0;\n> @@ -515,17 +396,16 @@ static void print_ref_item(struct ref_array_item *item, int maxwidth,\n>         const char *desc = item->refname;\n>         char *to_free = NULL;\n>\n> -       if (item->ignore)\n> -               return;\n> -\n>         switch (item->kind) {\n>         case FILTER_REFS_BRANCHES:\n> -               if (!filter->detached && !strcmp(item->refname, head))\n> +               skip_prefix(desc, \"refs/heads/\", &desc);\n> +               if (!filter->detached && !strcmp(desc, head))\n>                         current = 1;\n>                 else\n>                         color = BRANCH_COLOR_LOCAL;\n>                 break;\n>         case FILTER_REFS_REMOTES:\n> +               skip_prefix(desc, \"refs/remotes/\", &desc);\n>                 color = BRANCH_COLOR_REMOTE;\n>                 prefix = remote_prefix;\n>                 break;\n> @@ -554,11 +434,13 @@ static void print_ref_item(struct ref_array_item *item, int maxwidth,\n>                 strbuf_addf(&out, \"%c %s%s%s\", c, branch_get_color(color),\n>                             name.buf, branch_get_color(BRANCH_COLOR_RESET));\n>\n> -       if (item->symref)\n> -               strbuf_addf(&out, \" -> %s\", item->symref);\n> +       if (item->symref) {\n> +               skip_prefix(item->symref, \"refs/remotes/\", &desc);\n> +               strbuf_addf(&out, \" -> %s\", desc);\n> +       }\n>         else if (filter->verbose)\n>                 /* \" f7c0c00 [ahead 58, behind 197] vcs-svn: drop obj_pool.h\" */\n> -               add_verbose_info(&out, item, filter);\n> +               add_verbose_info(&out, item, filter, desc);\n>         if (column_active(colopts)) {\n>                 assert(!filter->verbose && \"--column and --verbose are incompatible\");\n>                 string_list_append(&output, out.buf);\n> @@ -575,11 +457,13 @@ static int calc_maxwidth(struct ref_array *refs, int remote_bonus)\n>         int i, max = 0;\n>         for (i = 0; i < refs->nr; i++) {\n>                 struct ref_array_item *it = refs->items[i];\n> +               const char *desc = it->refname;\n>                 int w;\n>\n> -               if (it->ignore)\n> -                       continue;\n> -               w = utf8_strwidth(it->refname);\n> +               skip_prefix(it->refname, \"refs/heads/\", &desc);\n> +               skip_prefix(it->refname, \"refs/remotes/\", &desc);\n> +               w = utf8_strwidth(desc);\n> +\n>                 if (it->kind == FILTER_REFS_REMOTES)\n>                         w += remote_bonus;\n>                 if (w > max)\n> @@ -588,14 +472,14 @@ static int calc_maxwidth(struct ref_array *refs, int remote_bonus)\n>         return 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>         int i;\n>         struct ref_array array;\n> -       struct ref_filter_cbdata data;\n>         int maxwidth = 0;\n>         const char *remote_prefix = \"\";\n> -       struct rev_info revs;\n> +       struct ref_sorting def_sorting;\n> +       const char *sort_type = \"type\";\n>\n>         /*\n>          * If we are listing more than just remote branches,\n> @@ -606,60 +490,30 @@ static void print_ref_list(struct ref_filter *filter)\n>                 remote_prefix = \"remotes/\";\n>\n>         memset(&array, 0, sizeof(array));\n> -       if (filter->merge != REF_FILTER_MERGED_NONE)\n> -               init_revisions(&revs, NULL);\n> -\n> -       data.array = &array;\n> -       data.filter = filter;\n> -       array.revs = &revs;\n>\n> -       /*\n> -        * First we obtain all regular branch refs and if the HEAD is\n> -        * detached then we insert that ref to the end of the ref_fist\n> -        * so that it can be printed and removed first.\n> -        */\n> -       for_each_rawref(append_ref, &data);\n> -       if (filter->detached)\n> -               head_ref(append_ref, &data);\n> -       /*\n> -        * The following implementation is currently duplicated in ref-filter. It\n> -        * will eventually be removed when we port branch.c to use ref-filter APIs.\n> -        */\n> -       if (filter->merge != REF_FILTER_MERGED_NONE) {\n> -               filter->merge_commit->object.flags |= UNINTERESTING;\n> -               add_pending_object(&revs, &filter->merge_commit->object, \"\");\n> -               revs.limited = 1;\n> -\n> -               if (prepare_revision_walk(&revs))\n> -                       die(_(\"revision walk setup failed\"));\n> -\n> -               for (i = 0; i < array.nr; i++) {\n> -                       struct ref_array_item *item = array.items[i];\n> -                       struct commit *commit = item->commit;\n> -                       int is_merged = !!(commit->object.flags & UNINTERESTING);\n> -                       item->ignore = is_merged != (filter->merge == REF_FILTER_MERGED_INCLUDE);\n> -               }\n> +       verify_ref_format(\"%(refname)%(symref)\");\n> +       filter_refs(&array, filter, filter->kind | FILTER_REFS_INCLUDE_BROKEN);\n>\n> -               for (i = 0; i < array.nr; i++) {\n> -                       struct ref_array_item *item = array.items[i];\n> -                       clear_commit_marks(item->commit, ALL_REV_FLAGS);\n> -               }\n> -               clear_commit_marks(filter->merge_commit, ALL_REV_FLAGS);\n> -       }\n>         if (filter->verbose)\n>                 maxwidth = calc_maxwidth(&array, strlen(remote_prefix));\n>\n>         /* Print detached HEAD before sorting and printing the rest */\n>         if (filter->kind & FILTER_REFS_DETACHED_HEAD) {\n> -               print_ref_item(array.items[array.nr - 1], maxwidth, filter, remote_prefix);\n> +               format_and_print_ref_item(array.items[array.nr - 1], maxwidth, filter, remote_prefix);\n>                 free_array_item(array.items[array.nr - 1]);\n>                 array.nr--;\n>         }\n>\n> -       qsort(array.items, array.nr, sizeof(struct ref_array_item *), ref_cmp);\n> +       if (!sorting) {\n> +               def_sorting.next = NULL;\n> +               def_sorting.atom = parse_ref_filter_atom(sort_type,\n> +                                                        sort_type + strlen(sort_type));\n> +               sorting = &def_sorting;\n> +       }\n> +       ref_array_sort(sorting, &array);\n>\n>         for (i = 0; i < array.nr; i++)\n> -               print_ref_item(array.items[i], maxwidth, filter, remote_prefix);\n> +               format_and_print_ref_item(array.items[i], maxwidth, filter, remote_prefix);\n>\n>         ref_array_clear(&array);\n>  }\n> @@ -761,6 +615,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)\n>         const char *new_upstream = NULL;\n>         enum branch_track track;\n>         struct ref_filter filter;\n> +       static struct ref_sorting *sorting = NULL, **sorting_tail = &sorting;\n>\n>         struct option options[] = {\n>                 OPT_GROUP(N_(\"Generic options\")),\n> @@ -795,6 +650,8 @@ int cmd_branch(int argc, const char **argv, const char *prefix)\n>                 OPT_MERGED(&filter, N_(\"print only branches that are merged\")),\n>                 OPT_NO_MERGED(&filter, N_(\"print only branches that are not merged\")),\n>                 OPT_COLUMN(0, \"column\", &colopts, N_(\"list branches in columns\")),\n> +               OPT_CALLBACK(0 , \"sort\", sorting_tail, N_(\"key\"),\n> +                            N_(\"field name to sort on\"), &parse_opt_ref_sorting),\n>                 OPT_END(),\n>         };\n>\n> @@ -853,7 +710,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)\n>                 if ((filter.kind & FILTER_REFS_BRANCHES) && filter.detached)\n>                         filter.kind |= FILTER_REFS_DETACHED_HEAD;\n>                 filter.name_patterns = argv;\n> -               print_ref_list(&filter);\n> +               print_ref_list(&filter, sorting);\n>                 print_columns(&output, colopts, NULL);\n>                 string_list_clear(&output, 0);\n>                 return 0;\n> diff --git a/ref-filter.c b/ref-filter.c\n> index c059d87..c536aea 100644\n> --- a/ref-filter.c\n> +++ b/ref-filter.c\n> @@ -1331,7 +1331,7 @@ static int ref_filter_handler(const char *refname, const struct object_id *oid,\n>          * obtain the commit using the 'oid' available and discard all\n>          * non-commits early. The actual filtering is done later.\n>          */\n> -       if (filter->merge_commit || filter->with_commit) {\n> +       if (filter->merge_commit || filter->with_commit || filter->verbose) {\n>                 commit = lookup_commit_reference_gently(oid->hash, 1);\n>                 if (!commit)\n>                         return 0;\n> diff --git a/ref-filter.h b/ref-filter.h\n> index 56980a3..9316031 100644\n> --- a/ref-filter.h\n> +++ b/ref-filter.h\n> @@ -36,7 +36,6 @@ struct ref_array_item {\n>         unsigned char objectname[20];\n>         int flag;\n>         unsigned int kind;\n> -       int ignore : 1; /* To be removed in the next patch */\n>         const char *symref;\n>         struct commit *commit;\n>         struct atom_value *value;\n> diff --git a/t/t1430-bad-ref-name.sh b/t/t1430-bad-ref-name.sh\n> index 16d0b8b..dacc186 100755\n> --- a/t/t1430-bad-ref-name.sh\n> +++ b/t/t1430-bad-ref-name.sh\n> @@ -38,11 +38,12 @@ test_expect_success 'fast-import: fail on invalid branch name \"bad[branch]name\"'\n>         test_must_fail git fast-import <input\n>  '\n>\n> -test_expect_success 'git branch shows badly named ref' '\n> +test_expect_success 'git branch shows badly named ref as warning' '\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> +       git branch >output 2>error &&\n> +       grep -e \"broken\\.\\.\\.ref\" error &&\n> +       ! grep -e \"broken\\.\\.\\.ref\" output\n>  '\n>\n>  test_expect_success 'branch -d can delete badly named ref' '\n> @@ -95,8 +96,8 @@ test_expect_success 'branch -m cannot rename to a bad ref name' '\n>         git branch goodref &&\n>         test_must_fail git branch -m goodref broken...ref &&\n>         test_cmp_rev master goodref &&\n> -       git branch >output &&\n> -       ! grep -e \"broken\\.\\.\\.ref\" output\n> +       git branch >output 2>error &&\n> +       ! grep -e \"broken\\.\\.\\.ref\" error\n>  '\n>\n>  test_expect_failure 'branch -m can rename from a bad ref name' '\n> @@ -104,8 +105,8 @@ test_expect_failure 'branch -m can rename from a bad ref name' '\n>         test_when_finished \"rm -f .git/refs/heads/broken...ref\" &&\n>         git branch -m broken...ref renamed &&\n>         test_cmp_rev master renamed &&\n> -       git branch >output &&\n> -       ! grep -e \"broken\\.\\.\\.ref\" output\n> +       git branch >output 2>error &&\n> +       ! grep -e \"broken\\.\\.\\.ref\" error\n>  '\n>\n>  test_expect_success 'push cannot create a badly named ref' '\n> @@ -131,8 +132,8 @@ test_expect_failure 'push --mirror can delete badly named ref' '\n>                 cp .git/refs/heads/master .git/refs/heads/broken...ref\n>         ) &&\n>         git -C src push --mirror \"file://$top/dest\" &&\n> -       git -C dest branch >output &&\n> -       ! grep -e \"broken\\.\\.\\.ref\" output\n> +       git -C dest branch >output 2>error &&\n> +       ! grep -e \"broken\\.\\.\\.ref\" error\n>  '\n>\n>  test_expect_success 'rev-parse skips symref pointing to broken name' '\n> diff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh\n> index f51d0f3..53d166d 100755\n> --- a/t/t3203-branch-output.sh\n> +++ b/t/t3203-branch-output.sh\n> @@ -143,4 +143,15 @@ EOF\n>         test_i18ncmp expect actual\n>  '\n>\n> +test_expect_success 'git branch `--sort` option' '\n> +       cat >expect <<-\\EOF &&\n> +       * (HEAD detached from fromtag)\n> +         branch-two\n> +         branch-one\n> +         master\n> +       EOF\n> +       git branch --sort=objectsize >actual &&\n> +       test_i18ncmp expect actual\n> +'\n> +\n>  test_done\n> --\n> 2.5.1\n>\n\nThis is [7/8] which is repeated, not sure why this happened, ignore this.\n\n-- \nRegards,\nKarthik Nayak\n"},{"id":"269872","messageId":"vpqio7ev8o6.fsf@anie.imag.fr","threadId":"40342","inReplyTo":"1442129035-31386-2-git-send-email-Karthik.188@gmail.com","subject":"Re: [PATCH v4 1/8] branch: refactor width computation","fromName":"Matthieu Moy","fromEmail":"matthieu.moy@grenoble-inp.fr","sentAt":"2015-09-13T11:51:53Z","receivedAt":"2015-09-13T11:51:53Z","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> @@ -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\nI don't understand this hunk. To give a bit more context, the closing\nbrace corresponds to:\n\n\tif (merge_filter != NO_FILTER) {\n\nHence this patch gets the two lines out of this \"if\". Actually, I don't\nunderstand how it could work previously. Wasn't this \"calc_maxwidth\"\nneeded regardless of merge_filter from the beginning?\n\nIn any case, that remark is not an objection on your patch, but I'd like\nto understand.\n\n-- \nMatthieu Moy\nhttp://www-verimag.imag.fr/~moy/\n"},{"id":"269873","messageId":"vpqa8sqv7p1.fsf@anie.imag.fr","threadId":"40342","inReplyTo":"1442129035-31386-4-git-send-email-Karthik.188@gmail.com","subject":"Re: [PATCH v4 3/8] branch: roll show_detached HEAD into regular ref_list","fromName":"Matthieu Moy","fromEmail":"matthieu.moy@grenoble-inp.fr","sentAt":"2015-09-13T12:12:58Z","receivedAt":"2015-09-13T12:12:58Z","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> @@ -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\nI think Eric already mentionned it, but I don't remember the conclusion\nand can't find it in the archives. Wouldn't it be cleaner to actually\nremove the detached head from the array (do \"ref_list.index -= 1\"\ninstead of \"index -= 1\", and possibly free() what needs to be freed?\n\nIf you did so, you wouldn't have any possible confusion between the\nlocal variable \"index\" and ref_list.index in the code below:\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\n-- \nMatthieu Moy\nhttp://www-verimag.imag.fr/~moy/\n"},{"id":"269874","messageId":"vpq4miyv7kn.fsf@anie.imag.fr","threadId":"40342","inReplyTo":"1442129035-31386-5-git-send-email-Karthik.188@gmail.com","subject":"Re: [PATCH v4 4/8] branch: move 'current' check down to the presentation layer","fromName":"Matthieu Moy","fromEmail":"matthieu.moy@grenoble-inp.fr","sentAt":"2015-09-13T12:15:36Z","receivedAt":"2015-09-13T12:15:36Z","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> We check if given ref is the current branch in print_ref_list(). Move\n> this check to print_ref_item() where it is checked right before\n> printing.\n\nYou may want to add a sentence saying why this is good. Given the\ncontext, it's relatively clear that this makes the code closer to the\nshape expected by ref-filter, but if you imagine someone bisecting or\nblaming and finding this commit in another context, that person may\nappreciate more explanation.\n\n-- \nMatthieu Moy\nhttp://www-verimag.imag.fr/~moy/\n"},{"id":"269875","messageId":"CAOLa=ZQoEsJ_pHZpsOWJaCVhku0Ai0Xkc=ON+LR+qGspDnszqQ@mail.gmail.com","threadId":"40342","inReplyTo":"vpqio7ev8o6.fsf@anie.imag.fr","subject":"Re: [PATCH v4 1/8] branch: refactor width computation","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-09-13T12:23:48Z","receivedAt":"2015-09-13T12:23:48Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"On Sun, Sep 13, 2015 at 5:21 PM, Matthieu Moy\n<Matthieu.Moy@grenoble-inp.fr> wrote:\n> Karthik Nayak <karthik.188@gmail.com> writes:\n>\n>> @@ -667,26 +675,22 @@ static int print_ref_list(int kinds, int detached, int verbose, int abbrev, stru\n>>                       clear_commit_marks(item->commit, ALL_REV_FLAGS);\n>>               }\n>>               clear_commit_marks(filter, ALL_REV_FLAGS);\n>> -\n>> -             if (verbose)\n>> -                     ref_list.maxwidth = calc_maxwidth(&ref_list);\n>>       }\n>> +     if (verbose)\n>> +             maxwidth = calc_maxwidth(&ref_list, strlen(remote_prefix));\n>\n> I don't understand this hunk. To give a bit more context, the closing\n> brace corresponds to:\n>\n>         if (merge_filter != NO_FILTER) {\n>\n> Hence this patch gets the two lines out of this \"if\". Actually, I don't\n> understand how it could work previously. Wasn't this \"calc_maxwidth\"\n> needed regardless of merge_filter from the beginning?\n\nPreviously, we used to compute and store each item's width in append_ref()\nand change the ref_list.maxwidth only if we find a new maxwidth (all\nwithin append_ref()).\nAlthough the maxwidth variable is only needed when we use the verbose\noption this is computed otherwise also (without the usage of calc_maxwidth()).\nWhen using the merge option with verbose the maxwidth would need to be\nrecalculated. Hence we compute the maxwidth again using\ncalc_maxwidth() within the\nif block.\n\nCurrently we only compute and store maxwidth if required, after\nobtaining required refs.\n\n>\n> In any case, that remark is not an objection on your patch, but I'd like\n> to understand.\n>\n\nHappy to explain.\n\n-- \nRegards,\nKarthik Nayak\n"},{"id":"269878","messageId":"vpqy4gatshr.fsf@anie.imag.fr","threadId":"40342","inReplyTo":"1442129035-31386-7-git-send-email-Karthik.188@gmail.com","subject":"Re: [PATCH v4 6/8] branch.c: use 'ref-filter' data structures","fromName":"Matthieu Moy","fromEmail":"matthieu.moy@grenoble-inp.fr","sentAt":"2015-09-13T12:26:40Z","receivedAt":"2015-09-13T12:26:40Z","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>  \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\nAh, this answers my previous remark: indeed, you are removing the\nelement from the array completely after this patch. You may want to\nmodify the previous patch to start doing it earlier, but I think it's\nnot worth the trouble: I agree with the final state, only the\nintermediate state is suboptimal (but still acceptable to me at least).\n\n-- \nMatthieu Moy\nhttp://www-verimag.imag.fr/~moy/\n"},{"id":"269879","messageId":"vpqlhcats6v.fsf@anie.imag.fr","threadId":"40342","inReplyTo":"CAOLa=ZQoEsJ_pHZpsOWJaCVhku0Ai0Xkc=ON+LR+qGspDnszqQ@mail.gmail.com","subject":"Re: [PATCH v4 1/8] branch: refactor width computation","fromName":"Matthieu Moy","fromEmail":"matthieu.moy@grenoble-inp.fr","sentAt":"2015-09-13T12:33:12Z","receivedAt":"2015-09-13T12:33:12Z","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> Happy to explain.\n\nThanks for the clarification.\n\n-- \nMatthieu Moy\nhttp://www-verimag.imag.fr/~moy/\n"},{"id":"269880","messageId":"CAOLa=ZQVwECZ=0oJdFcCWJwAUf7gYaF5pGweKDAFpfJujw-Q1A@mail.gmail.com","threadId":"40342","inReplyTo":"vpqy4gatshr.fsf@anie.imag.fr","subject":"Re: [PATCH v4 6/8] branch.c: use 'ref-filter' data structures","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-09-13T13:19:09Z","receivedAt":"2015-09-13T13:19:09Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"On Sun, Sep 13, 2015 at 5:56 PM, Matthieu Moy\n<Matthieu.Moy@grenoble-inp.fr> wrote:\n> Karthik Nayak <karthik.188@gmail.com> writes:\n>\n>>       /* Print detached HEAD before sorting and printing the rest */\n>> -     if (detached) {\n>> -             print_ref_item(&ref_list.list[index - 1], maxwidth, verbose, abbrev,\n>> -                            detached, remote_prefix);\n>> -             index -= 1;\n>> +     if (filter->kind & FILTER_REFS_DETACHED_HEAD) {\n>> +             print_ref_item(array.items[array.nr - 1], maxwidth, filter, remote_prefix);\n>> +             free_array_item(array.items[array.nr - 1]);\n>> +             array.nr--;\n>\n> Ah, this answers my previous remark: indeed, you are removing the\n> element from the array completely after this patch. You may want to\n> modify the previous patch to start doing it earlier, but I think it's\n> not worth the trouble: I agree with the final state, only the\n> intermediate state is suboptimal (but still acceptable to me at least).\n>\n\nYes! Eric suggested this. It doesn't make much sense in the previous\npatch, cause I'd have to introduce something along the lines of\nfree_array_item() only to be removed/replaced here.\n\n-- \nRegards,\nKarthik Nayak\n"},{"id":"269881","messageId":"CAOLa=ZTQjtEi4G7_T6gRzrmL=EocJxw69qR=n7vjLWCvbu2JMw@mail.gmail.com","threadId":"40342","inReplyTo":"vpq4miyv7kn.fsf@anie.imag.fr","subject":"Re: [PATCH v4 4/8] branch: move 'current' check down to the presentation layer","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-09-13T13:22:38Z","receivedAt":"2015-09-13T13:22:38Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"On Sun, Sep 13, 2015 at 5:45 PM, Matthieu Moy\n<Matthieu.Moy@grenoble-inp.fr> wrote:\n> Karthik Nayak <karthik.188@gmail.com> writes:\n>\n>> We check if given ref is the current branch in print_ref_list(). Move\n>> this check to print_ref_item() where it is checked right before\n>> printing.\n>\n> You may want to add a sentence saying why this is good. Given the\n> context, it's relatively clear that this makes the code closer to the\n> shape expected by ref-filter, but if you imagine someone bisecting or\n> blaming and finding this commit in another context, that person may\n> appreciate more explanation.\n>\n\nWill do.\n\n-- \nRegards,\nKarthik Nayak\n"},{"id":"269882","messageId":"CAOLa=ZTx7EpqfdYrq5RQPQOERjJZYZv837NOGZxmoP33oRNPew@mail.gmail.com","threadId":"40342","inReplyTo":"vpqa8sqv7p1.fsf@anie.imag.fr","subject":"Re: [PATCH v4 3/8] branch: roll show_detached HEAD into regular ref_list","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-09-13T13:24:04Z","receivedAt":"2015-09-13T13:24:04Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"On Sun, Sep 13, 2015 at 5:42 PM, Matthieu Moy\n<Matthieu.Moy@grenoble-inp.fr> wrote:\n> Karthik Nayak <karthik.188@gmail.com> writes:\n>\n>> @@ -679,15 +682,20 @@ static int print_ref_list(int kinds, int detached, int verbose, int abbrev, stru\n>>       if (verbose)\n>>               maxwidth = calc_maxwidth(&ref_list, strlen(remote_prefix));\n>>\n>> -     qsort(ref_list.list, ref_list.index, sizeof(struct ref_item), ref_cmp);\n>> +     index = ref_list.index;\n>> +\n>> +     /* Print detached HEAD before sorting and printing the rest */\n>> +     if (detached && (ref_list.list[index - 1].kind == REF_DETACHED_HEAD) &&\n>> +         !strcmp(ref_list.list[index - 1].name, head)) {\n>> +             print_ref_item(&ref_list.list[index - 1], maxwidth, verbose, abbrev,\n>> +                            1, remote_prefix);\n>> +             index -= 1;\n>> +     }\n>\n> I think Eric already mentionned it, but I don't remember the conclusion\n> and can't find it in the archives. Wouldn't it be cleaner to actually\n> remove the detached head from the array (do \"ref_list.index -= 1\"\n> instead of \"index -= 1\", and possibly free() what needs to be freed?\n>\n> If you did so, you wouldn't have any possible confusion between the\n> local variable \"index\" and ref_list.index in the code below:\n\nThis is cleared out in [PATCH 6/8].\n\n-- \nRegards,\nKarthik Nayak\n"},{"id":"269883","messageId":"1442158552-21552-1-git-send-email-Karthik.188@gmail.com","threadId":"40342","inReplyTo":"1442129035-31386-5-git-send-email-Karthik.188@gmail.com","subject":"[PATCH v4 4/8] branch: move 'current' check down to the presentation layer","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-09-13T15:35:52Z","receivedAt":"2015-09-13T15:35:52Z","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. This enables a smooth transition to using ref-filter APIs,\nas we can later replace the current check while printing to just check\nfor FILTER_REFS_DETACHED instead.\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\nChange the commit message to explain the need for this patch.\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.1\n"},{"id":"269884","messageId":"CAPig+cTzEQ=+FKa2j2RbfHv_NP35_vPDq1NZCeek8LX9fJF3aQ@mail.gmail.com","threadId":"40342","inReplyTo":"vpqa8sqv7p1.fsf@anie.imag.fr","subject":"Re: [PATCH v4 3/8] branch: roll show_detached HEAD into regular ref_list","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2015-09-13T16:46:48Z","receivedAt":"2015-09-13T16:46:48Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Sun, Sep 13, 2015 at 8:12 AM, Matthieu Moy\n<Matthieu.Moy@grenoble-inp.fr> wrote:\n> Karthik Nayak <karthik.188@gmail.com> writes:\n>\n>> @@ -679,15 +682,20 @@ static int print_ref_list(int kinds, int detached, int verbose, int abbrev, stru\n>>       if (verbose)\n>>               maxwidth = calc_maxwidth(&ref_list, strlen(remote_prefix));\n>>\n>> -     qsort(ref_list.list, ref_list.index, sizeof(struct ref_item), ref_cmp);\n>> +     index = ref_list.index;\n>> +\n>> +     /* Print detached HEAD before sorting and printing the rest */\n>> +     if (detached && (ref_list.list[index - 1].kind == REF_DETACHED_HEAD) &&\n>> +         !strcmp(ref_list.list[index - 1].name, head)) {\n>> +             print_ref_item(&ref_list.list[index - 1], maxwidth, verbose, abbrev,\n>> +                            1, remote_prefix);\n>> +             index -= 1;\n>> +     }\n>\n> I think Eric already mentionned it, but I don't remember the conclusion\n> and can't find it in the archives. Wouldn't it be cleaner to actually\n> remove the detached head from the array (do \"ref_list.index -= 1\"\n> instead of \"index -= 1\", and possibly free() what needs to be freed?\n\nI think Michael Haggerty mentioned something along those lines...\n"},{"id":"269886","messageId":"vpq7fnutdj9.fsf@anie.imag.fr","threadId":"40342","inReplyTo":"CAOLa=ZQVwECZ=0oJdFcCWJwAUf7gYaF5pGweKDAFpfJujw-Q1A@mail.gmail.com","subject":"Re: [PATCH v4 6/8] branch.c: use 'ref-filter' data structures","fromName":"Matthieu Moy","fromEmail":"matthieu.moy@grenoble-inp.fr","sentAt":"2015-09-13T17:49:46Z","receivedAt":"2015-09-13T17:49:46Z","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> On Sun, Sep 13, 2015 at 5:56 PM, Matthieu Moy\n> <Matthieu.Moy@grenoble-inp.fr> wrote:\n>> Karthik Nayak <karthik.188@gmail.com> writes:\n>>\n>>>       /* Print detached HEAD before sorting and printing the rest */\n>>> -     if (detached) {\n>>> -             print_ref_item(&ref_list.list[index - 1], maxwidth, verbose, abbrev,\n>>> -                            detached, remote_prefix);\n>>> -             index -= 1;\n>>> +     if (filter->kind & FILTER_REFS_DETACHED_HEAD) {\n>>> +             print_ref_item(array.items[array.nr - 1], maxwidth, filter, remote_prefix);\n>>> +             free_array_item(array.items[array.nr - 1]);\n>>> +             array.nr--;\n>>\n>> Ah, this answers my previous remark: indeed, you are removing the\n>> element from the array completely after this patch. You may want to\n>> modify the previous patch to start doing it earlier, but I think it's\n>> not worth the trouble: I agree with the final state, only the\n>> intermediate state is suboptimal (but still acceptable to me at least).\n>\n> Yes! Eric suggested this. It doesn't make much sense in the previous\n> patch, cause I'd have to introduce something along the lines of\n> free_array_item() only to be removed/replaced here.\n\nOK, it makes sense.\n\n-- \nMatthieu Moy\nhttp://www-verimag.imag.fr/~moy/\n"},{"id":"269887","messageId":"CAPig+cR42jzxeeqpVh2sMojSCVD7Xg4RF6TDfTeg0y10o-2TLQ@mail.gmail.com","threadId":"40342","inReplyTo":"CAPig+cTzEQ=+FKa2j2RbfHv_NP35_vPDq1NZCeek8LX9fJF3aQ@mail.gmail.com","subject":"Re: [PATCH v4 3/8] branch: roll show_detached HEAD into regular ref_list","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2015-09-13T18:31:21Z","receivedAt":"2015-09-13T18:31:21Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Sun, Sep 13, 2015 at 12:46 PM, Eric Sunshine <sunshine@sunshineco.com> wrote:\n> On Sun, Sep 13, 2015 at 8:12 AM, Matthieu Moy\n> <Matthieu.Moy@grenoble-inp.fr> wrote:\n>> Karthik Nayak <karthik.188@gmail.com> writes:\n>>\n>>> @@ -679,15 +682,20 @@ static int print_ref_list(int kinds, int detached, int verbose, int abbrev, stru\n>>>       if (verbose)\n>>>               maxwidth = calc_maxwidth(&ref_list, strlen(remote_prefix));\n>>>\n>>> -     qsort(ref_list.list, ref_list.index, sizeof(struct ref_item), ref_cmp);\n>>> +     index = ref_list.index;\n>>> +\n>>> +     /* Print detached HEAD before sorting and printing the rest */\n>>> +     if (detached && (ref_list.list[index - 1].kind == REF_DETACHED_HEAD) &&\n>>> +         !strcmp(ref_list.list[index - 1].name, head)) {\n>>> +             print_ref_item(&ref_list.list[index - 1], maxwidth, verbose, abbrev,\n>>> +                            1, remote_prefix);\n>>> +             index -= 1;\n>>> +     }\n>>\n>> I think Eric already mentionned it, but I don't remember the conclusion\n>> and can't find it in the archives. Wouldn't it be cleaner to actually\n>> remove the detached head from the array (do \"ref_list.index -= 1\"\n>> instead of \"index -= 1\", and possibly free() what needs to be freed?\n>\n> I think Michael Haggerty mentioned something along those lines...\n\nSpecifically, I think you're referring to [1] (?).\n\n[1]: http://thread.gmane.org/gmane.comp.version-control.git/276363/focus=276676\n"},{"id":"269927","messageId":"CAOLa=ZQR8dJH_tAJX1wFwgTgsA178C9Ok8CvKUixywTbsUK_Eg@mail.gmail.com","threadId":"40342","inReplyTo":"CAPig+cR42jzxeeqpVh2sMojSCVD7Xg4RF6TDfTeg0y10o-2TLQ@mail.gmail.com","subject":"Re: [PATCH v4 3/8] branch: roll show_detached HEAD into regular ref_list","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-09-14T14:48:52Z","receivedAt":"2015-09-14T14:48:52Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"On Mon, Sep 14, 2015 at 12:01 AM, Eric Sunshine <sunshine@sunshineco.com> wrote:\n> On Sun, Sep 13, 2015 at 12:46 PM, Eric Sunshine <sunshine@sunshineco.com> wrote:\n>> On Sun, Sep 13, 2015 at 8:12 AM, Matthieu Moy\n>> <Matthieu.Moy@grenoble-inp.fr> wrote:\n>>> Karthik Nayak <karthik.188@gmail.com> writes:\n>>>\n>>>> @@ -679,15 +682,20 @@ static int print_ref_list(int kinds, int detached, int verbose, int abbrev, stru\n>>>>       if (verbose)\n>>>>               maxwidth = calc_maxwidth(&ref_list, strlen(remote_prefix));\n>>>>\n>>>> -     qsort(ref_list.list, ref_list.index, sizeof(struct ref_item), ref_cmp);\n>>>> +     index = ref_list.index;\n>>>> +\n>>>> +     /* Print detached HEAD before sorting and printing the rest */\n>>>> +     if (detached && (ref_list.list[index - 1].kind == REF_DETACHED_HEAD) &&\n>>>> +         !strcmp(ref_list.list[index - 1].name, head)) {\n>>>> +             print_ref_item(&ref_list.list[index - 1], maxwidth, verbose, abbrev,\n>>>> +                            1, remote_prefix);\n>>>> +             index -= 1;\n>>>> +     }\n>>>\n>>> I think Eric already mentionned it, but I don't remember the conclusion\n>>> and can't find it in the archives. Wouldn't it be cleaner to actually\n>>> remove the detached head from the array (do \"ref_list.index -= 1\"\n>>> instead of \"index -= 1\", and possibly free() what needs to be freed?\n>>\n>> I think Michael Haggerty mentioned something along those lines...\n>\n> Specifically, I think you're referring to [1] (?).\n>\n> [1]: http://thread.gmane.org/gmane.comp.version-control.git/276363/focus=276676\n\nNo not that, that is handled in the previous patch series.\n\nI can't find the reference either, but the comment was along the lines of what\nMatthieu just mentioned above, But like I replied on [Patch 6/8] Its\ntaken care of\nin that particular patch. Here it doesn't seem to be needed.\n\n-- \nRegards,\nKarthik Nayak\n"},{"id":"269928","messageId":"vpqsi6hjbjx.fsf@anie.imag.fr","threadId":"40342","inReplyTo":"CAOLa=ZQR8dJH_tAJX1wFwgTgsA178C9Ok8CvKUixywTbsUK_Eg@mail.gmail.com","subject":"Re: [PATCH v4 3/8] branch: roll show_detached HEAD into regular ref_list","fromName":"Matthieu Moy","fromEmail":"matthieu.moy@grenoble-inp.fr","sentAt":"2015-09-14T14:54:58Z","receivedAt":"2015-09-14T14:54:58Z","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> On Mon, Sep 14, 2015 at 12:01 AM, Eric Sunshine <sunshine@sunshineco.com> wrote:\n>> Specifically, I think you're referring to [1] (?).\n>>\n>> [1]: http://thread.gmane.org/gmane.comp.version-control.git/276363/focus=276676\n>\n> No not that, that is handled in the previous patch series.\n>\n> I can't find the reference either, but the comment was along the lines of what\n> Matthieu just mentioned above,\n\nI had another message in mind too. Never mind, the comment is addressed,\nwe don't need to know if it was a real message or a collective\nhallucination ;-).\n\n-- \nMatthieu Moy\nhttp://www-verimag.imag.fr/~moy/\n"},{"id":"269957","messageId":"xmqqzj0ovlno.fsf@gitster.mtv.corp.google.com","threadId":"40342","inReplyTo":"1442129035-31386-4-git-send-email-Karthik.188@gmail.com","subject":"Re: [PATCH v4 3/8] branch: roll show_detached HEAD into regular ref_list","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-09-14T19:35:55Z","receivedAt":"2015-09-14T19:35:55Z","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> +\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> +\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> +\tqsort(ref_list.list, index, sizeof(struct ref_item), ref_cmp);\n\nThis looks somewhat strange.  Wouldn't it be more consistent to\nteach ref_cmp that HEAD sorts where in the collection of refs (I\npresume that kind is checked first and then name, so if you give\nREF_DETACHED_HEAD a low number than others, it would automatically\ngive you the ordering you want) without all of the above special\ncasing?\n"},{"id":"269958","messageId":"xmqqvbbcvl0v.fsf@gitster.mtv.corp.google.com","threadId":"40342","inReplyTo":"1442129035-31386-6-git-send-email-Karthik.188@gmail.com","subject":"Re: [PATCH v4 5/8] branch: drop non-commit error reporting","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-09-14T19:49:36Z","receivedAt":"2015-09-14T19:49:36Z","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> Remove the error reporting variable to make the code easier to port\n> over to using ref-filter APIs. This variable is not required as in\n> ref-filter we already check for possible errors and report them.\n\nHmmmm.  What do you exactly mean \"possible errors\" here?\n\nUnlike generic refs that can point at anything, refs/heads/* refs\nmust point at a commit [*1*], and that is why the error message says\n'does not point at a commit'.\n\nDoes ref-filter API have corresponding check to treat the local and\nremote branch hierarchies differently from tags and others?\n\n[Footnote]\n\n*1* Strictly speaking, use of lookup_commit_reference_gently() in\n    the existing code allows a committish to be there and does not\n    limit the tip objects to be commits, but I think it is a bug.\n    At least, even with deref_tag(), we reject non committish found\n    at the tip of branch refs and explain with the error message\n    this patch removes.\n\n> Based-on-patch-by: Jeff King <peff@peff.net>\n> Mentored-by: Christian Couder <christian.couder@gmail.com>\n> Mentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>\n> Signed-off-by: Karthik Nayak <karthik.188@gmail.com>\n> ---\n>  builtin/branch.c | 18 ++++--------------\n>  1 file changed, 4 insertions(+), 14 deletions(-)\n>\n> diff --git a/builtin/branch.c b/builtin/branch.c\n> index 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"},{"id":"270098","messageId":"CAOLa=ZQ+uAy6CfWqRgV_Wf8iQoyHdtYU=HEn748Vb=FRc36f_g@mail.gmail.com","threadId":"40342","inReplyTo":"xmqqvbbcvl0v.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v4 5/8] branch: drop non-commit error reporting","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-09-16T06:04:08Z","receivedAt":"2015-09-16T06:04:08Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"On Tue, Sep 15, 2015 at 1:19 AM, Junio C Hamano <gitster@pobox.com> wrote:\n> Karthik Nayak <karthik.188@gmail.com> writes:\n>\n>> Remove the error reporting variable to make the code easier to port\n>> over to using ref-filter APIs. This variable is not required as in\n>> ref-filter we already check for possible errors and report them.\n>\n> Hmmmm.  What do you exactly mean \"possible errors\" here?\n>\n\nThe checking if it points to a commit.\n\n> Unlike generic refs that can point at anything, refs/heads/* refs\n> must point at a commit [*1*], and that is why the error message says\n> 'does not point at a commit'.\n>\n> Does ref-filter API have corresponding check to treat the local and\n> remote branch hierarchies differently from tags and others?\n>\n\nThis check in the existing code is only done when one of these holds:\nref_list->verbose || ref_list->with_commit || merge_filter != NO_FILTER\n\nThere is a similar check in ref-filter when we filter and obtain refs.\n\n    if (filter->merge_commit || filter->with_commit || filter->verbose) {\n        commit = lookup_commit_reference_gently(oid->hash, 1);\n        if (!commit)\n            return 0;\n        /* We perform the filtering for the '--contains' option */\n        if (filter->with_commit &&\n            !commit_contains(filter, commit))\n            return 0;\n    }\n\n> [Footnote]\n>\n> *1* Strictly speaking, use of lookup_commit_reference_gently() in\n>     the existing code allows a committish to be there and does not\n>     limit the tip objects to be commits, but I think it is a bug.\n>     At least, even with deref_tag(), we reject non committish found\n>     at the tip of branch refs and explain with the error message\n>     this patch removes.\n\nAh, didn't go through this.\n\n-- \nRegards,\nKarthik Nayak\n"},{"id":"270100","messageId":"CAOLa=ZQ51+TKvOiJvWa-emmJJGirAqkr9m0a_7BrQ2UbiSJdjA@mail.gmail.com","threadId":"40342","inReplyTo":"xmqqzj0ovlno.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v4 3/8] branch: roll show_detached HEAD into regular ref_list","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-09-16T06:23:15Z","receivedAt":"2015-09-16T06:23:15Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"On Tue, Sep 15, 2015 at 1:05 AM, Junio C Hamano <gitster@pobox.com> wrote:\n> Karthik Nayak <karthik.188@gmail.com> writes:\n>\n>> +     /*\n>> +      * First we obtain all regular branch refs and if the HEAD is\n>> +      * detached then we insert that ref to the end of the ref_fist\n>> +      * so that it can be printed and removed first.\n>> +      */\n>>       for_each_rawref(append_ref, &cb);\n>> +     if (detached)\n>> +             head_ref(append_ref, &cb);\n>> +     index = ref_list.index;\n>> +\n>> +     /* Print detached HEAD before sorting and printing the rest */\n>> +     if (detached && (ref_list.list[index - 1].kind == REF_DETACHED_HEAD) &&\n>> +         !strcmp(ref_list.list[index - 1].name, head)) {\n>> +             print_ref_item(&ref_list.list[index - 1], maxwidth, verbose, abbrev,\n>> +                            1, remote_prefix);\n>> +             index -= 1;\n>> +     }\n>>\n>> +     qsort(ref_list.list, index, sizeof(struct ref_item), ref_cmp);\n>\n> This looks somewhat strange.  Wouldn't it be more consistent to\n> teach ref_cmp that HEAD sorts where in the collection of refs (I\n> presume that kind is checked first and then name, so if you give\n> REF_DETACHED_HEAD a low number than others, it would automatically\n> give you the ordering you want) without all of the above special\n> casing?\n\nThats nice, we could do that, something like this perhaps:\n\n    qsort(ref_list.list, ref_list.index, sizeof(struct ref_item), ref_cmp);\n\n    for (i = 0; i < ref_list.index; i++) {\n        int current = !detached && (ref_list.list[i].kind ==\nREF_LOCAL_BRANCH) &&\n            !strcmp(ref_list.list[i].name, head);\n        /*  If detached the first ref_item is the current ref */\n        if (detached && i == 0)\n            current = 1;\n        print_ref_item(&ref_list.list[i], maxwidth, verbose,\n                   abbrev, current, remote_prefix);\n    }\n\n-- \nRegards,\nKarthik Nayak\n"},{"id":"270199","messageId":"CAOLa=ZQxounTiJk0t+zB2-7=UQa8oL+uJ9EQpTkWL7kYFHjxwQ@mail.gmail.com","threadId":"40342","inReplyTo":"CAOLa=ZQ51+TKvOiJvWa-emmJJGirAqkr9m0a_7BrQ2UbiSJdjA@mail.gmail.com","subject":"Re: [PATCH v4 3/8] branch: roll show_detached HEAD into regular ref_list","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-09-17T09:47:06Z","receivedAt":"2015-09-17T09:47:06Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"On Wed, Sep 16, 2015 at 11:53 AM, Karthik Nayak <karthik.188@gmail.com> wrote:\n> On Tue, Sep 15, 2015 at 1:05 AM, Junio C Hamano <gitster@pobox.com> wrote:\n>> Karthik Nayak <karthik.188@gmail.com> writes:\n>>\n>>> +     /*\n>>> +      * First we obtain all regular branch refs and if the HEAD is\n>>> +      * detached then we insert that ref to the end of the ref_fist\n>>> +      * so that it can be printed and removed first.\n>>> +      */\n>>>       for_each_rawref(append_ref, &cb);\n>>> +     if (detached)\n>>> +             head_ref(append_ref, &cb);\n>>> +     index = ref_list.index;\n>>> +\n>>> +     /* Print detached HEAD before sorting and printing the rest */\n>>> +     if (detached && (ref_list.list[index - 1].kind == REF_DETACHED_HEAD) &&\n>>> +         !strcmp(ref_list.list[index - 1].name, head)) {\n>>> +             print_ref_item(&ref_list.list[index - 1], maxwidth, verbose, abbrev,\n>>> +                            1, remote_prefix);\n>>> +             index -= 1;\n>>> +     }\n>>>\n>>> +     qsort(ref_list.list, index, sizeof(struct ref_item), ref_cmp);\n>>\n>> This looks somewhat strange.  Wouldn't it be more consistent to\n>> teach ref_cmp that HEAD sorts where in the collection of refs (I\n>> presume that kind is checked first and then name, so if you give\n>> REF_DETACHED_HEAD a low number than others, it would automatically\n>> give you the ordering you want) without all of the above special\n>> casing?\n>\n> Thats nice, we could do that, something like this perhaps:\n>\n>     qsort(ref_list.list, ref_list.index, sizeof(struct ref_item), ref_cmp);\n>\n>     for (i = 0; i < ref_list.index; i++) {\n>         int current = !detached && (ref_list.list[i].kind ==\n> REF_LOCAL_BRANCH) &&\n>             !strcmp(ref_list.list[i].name, head);\n>         /*  If detached the first ref_item is the current ref */\n>         if (detached && i == 0)\n>             current = 1;\n>         print_ref_item(&ref_list.list[i], maxwidth, verbose,\n>                    abbrev, current, remote_prefix);\n>     }\n>\n\nAlthough this solves the problem here, we'd still need to do something\nsimilar when we use ref-filter APIs as in [PATCH 7/8].\n\nSo either we could introduce a new atom for sorting something like\n`branch_sort` which uses the FILTER_REFS_(DETACHED_HEAD | BRANCHES | REMOTES)\nto sort or we could sort after printing the detached head, as done in\nthis series.\nI'm ok with either.\n\n-- \nRegards,\nKarthik Nayak\n"},{"id":"270212","messageId":"vpqpp1hqgcd.fsf@anie.imag.fr","threadId":"40342","inReplyTo":"CAOLa=ZQxounTiJk0t+zB2-7=UQa8oL+uJ9EQpTkWL7kYFHjxwQ@mail.gmail.com","subject":"Re: [PATCH v4 3/8] branch: roll show_detached HEAD into regular ref_list","fromName":"Matthieu Moy","fromEmail":"matthieu.moy@grenoble-inp.fr","sentAt":"2015-09-17T14:18:42Z","receivedAt":"2015-09-17T14:18:42Z","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> So either we could introduce a new atom for sorting something like\n> `branch_sort` which uses the FILTER_REFS_(DETACHED_HEAD | BRANCHES |\n> REMOTES)\n\nI don't think you need a new atom. You can just change the sorting\nfunction to consider that detached HEAD is always first, and when\ncomparing two non-detached-HEAD branches, use the atom supplied by the\nuser.\n\nThat would mean the detached HEAD would be displayed first regardless of\n--sort (which is the case right now).\n\nIntroducing a new atom would mean that \"git branch --sort authorname\"\nwould not use this new atom, hence the HEAD would be sorted like the\nothers. I don't know if this is good or bad.\n\n-- \nMatthieu Moy\nhttp://www-verimag.imag.fr/~moy/\n"},{"id":"270216","messageId":"xmqqh9mtkrg0.fsf@gitster.mtv.corp.google.com","threadId":"40342","inReplyTo":"vpqpp1hqgcd.fsf@anie.imag.fr","subject":"Re: [PATCH v4 3/8] branch: roll show_detached HEAD into regular ref_list","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-09-17T15:15:27Z","receivedAt":"2015-09-17T15:15:27Z","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> Karthik Nayak <karthik.188@gmail.com> writes:\n>\n>> So either we could introduce a new atom for sorting something like\n>> `branch_sort` which uses the FILTER_REFS_(DETACHED_HEAD | BRANCHES |\n>> REMOTES)\n>\n> I don't think you need a new atom. You can just change the sorting\n> function to consider that detached HEAD is always first, and when\n> comparing two non-detached-HEAD branches, use the atom supplied by the\n> user.\n>\n> That would mean the detached HEAD would be displayed first regardless of\n> --sort (which is the case right now).\n\nI am a bit fuzzy about this.  I do not understand why Karthik thinks\na new atom is necessary in the first place, and I do agree that the\nbest way to go would be to teach the sort function to do \"the right\nthing\", but I am not sure why it has to be \"regardless of --sort\".\n\nIn the original for-each-ref (before it was butchered^W updated with\nref-filter), we grab refs and sort with default_sort() when \"--sort\"\nis not given.  When --sort is given, we just use atoms to compare.\n\nI do not think ref-filter broke that pattern, and as long as it kept\nthat pattern, I do not think the solution has to be more than just\n\"teach that default_sort() function, which sorts by refname, to\nalways show HEAD first\".  When you throw HEAD into the mix, instead\nof grabbing only from refs/*, you can still give that set to a\nsorting function, which by default puts \"HEAD\" before others (just\nlike the sorting function for \"branch -a\" by default puts local\nbefore remote-tracking), and you are done, no?\n\nWhen the user does give a custom --sort criteria, the logic in\ndefault_sort() would not kick in, so there is no need for special\ncasing for \"HEAD\" like the code I questioned in this thread.\n\nWhat am I missing?\n\n> Introducing a new atom would mean that \"git branch --sort authorname\"\n> would not use this new atom, hence the HEAD would be sorted like the\n> others.\n\nI think that is exactly what people would expect.\n\nPerhaps a slightly tricky would be \"git branch -a --sort refname\".\nIf you have HEAD, refs/heads/master, and refs/remotes/origin/master,\nI'd expect that it would sort these in that order purely because\nthat is the textual/ascii sort order of the FULL refname.\n\nAnd then at the presentation level you would strip refs/heads and\nrefs/remotes from local and remote-tracking branches, just like \"git\nbranch -a\" output has always done, from the sorted result when\nshowing.\n\n\"git branch -a --sort refname:short\" would sort using HEAD vs master\nvs origin/master in the above example and would end up mixing loal\nand remote-tracking together, but that is what the user is asking\nfor, and the user deserves to get what s/he asked for.\n\nSomewhat confused....\n"},{"id":"270220","messageId":"vpqio79oxva.fsf@anie.imag.fr","threadId":"40342","inReplyTo":"xmqqh9mtkrg0.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v4 3/8] branch: roll show_detached HEAD into regular ref_list","fromName":"Matthieu Moy","fromEmail":"matthieu.moy@grenoble-inp.fr","sentAt":"2015-09-17T15:43:05Z","receivedAt":"2015-09-17T15:43:05Z","isPatch":true,"sender":{"key":"matthieu.moy@grenoble-inp.fr","avatar":"https://gravatar.com/avatar/72c8a2705971a25dfaff23cece15130d405685845d911aedd5667ace277f3fc5?d=mp&s=160"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Matthieu Moy <Matthieu.Moy@grenoble-inp.fr> writes:\n>\n>> Karthik Nayak <karthik.188@gmail.com> writes:\n>>\n>>> So either we could introduce a new atom for sorting something like\n>>> `branch_sort` which uses the FILTER_REFS_(DETACHED_HEAD | BRANCHES |\n>>> REMOTES)\n>>\n>> I don't think you need a new atom. You can just change the sorting\n>> function to consider that detached HEAD is always first, and when\n>> comparing two non-detached-HEAD branches, use the atom supplied by the\n>> user.\n>>\n>> That would mean the detached HEAD would be displayed first regardless of\n>> --sort (which is the case right now).\n>\n> I am a bit fuzzy about this.  I do not understand why Karthik thinks\n> a new atom is necessary in the first place, and I do agree that the\n> best way to go would be to teach the sort function to do \"the right\n> thing\", but I am not sure why it has to be \"regardless of --sort\".\n\nI think Karthik meant that branch could default to\n\"--sort=my_magic_atom_that_does_the_right_thing\". In this case, the\ndefault would be to show HEAD first, but using \"--sort\" explicitly would\nchange the order and interleave HEAD within other branches.\n\nIOW, we have:\n\nstruct ref_sorting *ref_default_sorting(void)\n{\n\tstatic const char cstr_name[] = \"refname\";\n\n\tstruct ref_sorting *sorting = xcalloc(1, sizeof(*sorting));\n\n\tsorting->next = NULL;\n\tsorting->atom = parse_ref_filter_atom(cstr_name, cstr_name + strlen(cstr_name));\n\treturn sorting;\n}\n\nand we could\n\n-\tstatic const char cstr_name[] = \"refname\";\n+\tstatic const char cstr_name[] = \"some_magic_atom\";\n\nBut you convinced me that this is not a good idea.\n\n> When the user does give a custom --sort criteria, the logic in\n> default_sort()\n\nThe logic itself is not in ref_default_sorting() (I guess this is what\nyou meant by \"default_sort\"): this function just builds a struct\nref_sorting that is later used by the more general cmp_ref_sorting.\n\nBut that's still workable: struct ref_sorting could contain a flag\n\"head_first\" that would be set by ref_default_sorting() and only it, and\nthen read by cmp_ref_sorting.\n\n-- \nMatthieu Moy\nhttp://www-verimag.imag.fr/~moy/\n"},{"id":"270232","messageId":"xmqqeghxj8i1.fsf@gitster.mtv.corp.google.com","threadId":"40342","inReplyTo":"vpqio79oxva.fsf@anie.imag.fr","subject":"Re: [PATCH v4 3/8] branch: roll show_detached HEAD into regular ref_list","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-09-17T16:49:58Z","receivedAt":"2015-09-17T16:49:58Z","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> But that's still workable: struct ref_sorting could contain a flag\n> \"head_first\" that would be set by ref_default_sorting() and only it, and\n> then read by cmp_ref_sorting.\n\nHmm, I am still puzzled.  \"refname\" atom would expand to things like\n\"HEAD\", \"refs/heads/master\", etc., so I still do not see a need for\nhead_first option at all.  \"HEAD\" will sort before \"refs/anything\"\nalways, no?\n"},{"id":"270240","messageId":"vpqmvwlm0rt.fsf@anie.imag.fr","threadId":"40342","inReplyTo":"xmqqeghxj8i1.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v4 3/8] branch: roll show_detached HEAD into regular ref_list","fromName":"Matthieu Moy","fromEmail":"matthieu.moy@grenoble-inp.fr","sentAt":"2015-09-17T17:08:38Z","receivedAt":"2015-09-17T17:08:38Z","isPatch":true,"sender":{"key":"matthieu.moy@grenoble-inp.fr","avatar":"https://gravatar.com/avatar/72c8a2705971a25dfaff23cece15130d405685845d911aedd5667ace277f3fc5?d=mp&s=160"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Matthieu Moy <Matthieu.Moy@grenoble-inp.fr> writes:\n>\n>> But that's still workable: struct ref_sorting could contain a flag\n>> \"head_first\" that would be set by ref_default_sorting() and only it, and\n>> then read by cmp_ref_sorting.\n>\n> Hmm, I am still puzzled.  \"refname\" atom would expand to things like\n> \"HEAD\", \"refs/heads/master\", etc., so I still do not see a need for\n> head_first option at all.  \"HEAD\" will sort before \"refs/anything\"\n> always, no?\n\nAh, you mean, the alphabetic order on refname already sorts HEAD first\nbecause other refs will start with \"refs/\"? So, there's no need for any\nspecial case at all indeed. Nothing to teach compare_refs, it's already\ndoing it.\n\nHowever, just relying on this seems a bit fragile to me: if we ever\nallow listing e.g. FETCH_HEAD as a reference, then we would get\n\n  FETCH_HEAD\n* (HEAD detached at ...)\n  master\n\nwhich seems weird to me. But we can decide \"if sorting on refname, then\nHEAD always comes first anyway\".\n\n-- \nMatthieu Moy\nhttp://www-verimag.imag.fr/~moy/\n"},{"id":"270243","messageId":"xmqqwpvphsgz.fsf@gitster.mtv.corp.google.com","threadId":"40342","inReplyTo":"vpqmvwlm0rt.fsf@anie.imag.fr","subject":"Re: [PATCH v4 3/8] branch: roll show_detached HEAD into regular ref_list","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-09-17T17:21:32Z","receivedAt":"2015-09-17T17:21:32Z","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> ... But we can decide \"if sorting on refname, then\n> HEAD always comes first anyway\".\n\nSure.\n"},{"id":"270254","messageId":"CAOLa=ZTn+arYr1HHA3CH+E2Sd7z9-ry=7D-QRSUM98kSKKcXdg@mail.gmail.com","threadId":"40342","inReplyTo":"vpqmvwlm0rt.fsf@anie.imag.fr","subject":"Re: [PATCH v4 3/8] branch: roll show_detached HEAD into regular ref_list","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-09-17T18:25:58Z","receivedAt":"2015-09-17T18:25:58Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"On Thu, Sep 17, 2015 at 10:38 PM, Matthieu Moy\n<Matthieu.Moy@grenoble-inp.fr> wrote:\n> Junio C Hamano <gitster@pobox.com> writes:\n>\n>> Matthieu Moy <Matthieu.Moy@grenoble-inp.fr> writes:\n>>\n>>> But that's still workable: struct ref_sorting could contain a flag\n>>> \"head_first\" that would be set by ref_default_sorting() and only it, and\n>>> then read by cmp_ref_sorting.\n>>\n>> Hmm, I am still puzzled.  \"refname\" atom would expand to things like\n>> \"HEAD\", \"refs/heads/master\", etc., so I still do not see a need for\n>> head_first option at all.  \"HEAD\" will sort before \"refs/anything\"\n>> always, no?\n>\n> Ah, you mean, the alphabetic order on refname already sorts HEAD first\n> because other refs will start with \"refs/\"? So, there's no need for any\n> special case at all indeed. Nothing to teach compare_refs, it's already\n> doing it.\n>\n> However, just relying on this seems a bit fragile to me: if we ever\n> allow listing e.g. FETCH_HEAD as a reference, then we would get\n>\n>   FETCH_HEAD\n> * (HEAD detached at ...)\n>   master\n>\n> which seems weird to me. But we can decide \"if sorting on refname, then\n> HEAD always comes first anyway\".\n\nThanks for explaining what I had in mind, Seems like the confusion is sorted,\nI have nothing more to add to this discussion. Junio is right, sorting\nby \"refname\"\nwould indeed work, I was just thinking along the lines of what you're ;)\n\n-- \nRegards,\nKarthik Nayak\n"}]}