{"thread":{"id":"29382","subject":"[PATCH] branch: borrow --sort and --count from for-each-ref","startedAt":"2012-01-17T13:11:47Z","lastAt":"2012-02-04T16:19:05Z","messageCount":4,"participants":["Nguyễn Thái Ngọc Duy","Junio C Hamano","Nguyen Thai Ngoc Duy"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"182683","messageId":"1326805907-19416-1-git-send-email-pclouds@gmail.com","threadId":"29382","inReplyTo":null,"subject":"[PATCH] branch: borrow --sort and --count from for-each-ref","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2012-01-17T13:11:47Z","receivedAt":"2012-01-17T13:11:47Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Some time ago, I posted a patch that added date sort to git-branch\n and Peff pointed me to for-each-ref. I did not look at it closely.\n Now it does not seem hard to lend some code from for-each-ref to\n git-branch. I can list 10 most recently touched branches with\n\n  git branch --sort=-committerdate -v --count=10\n\n kind of cool. I don't think adding --format is necessary because\n git-branch already has its own formatting.\n\n Documentation/git-branch.txt |   13 +++++++++\n Makefile                     |    1 +\n builtin/branch.c             |   61 +++++++++++++++++++++++++++++++++--------\n builtin/for-each-ref.c       |   33 +++-------------------\n builtin/for-each-ref.h       |   32 ++++++++++++++++++++++\n 5 files changed, 100 insertions(+), 40 deletions(-)\n create mode 100644 builtin/for-each-ref.h\n\ndiff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt\nindex 0427e80..b6f2826 100644\n--- a/Documentation/git-branch.txt\n+++ b/Documentation/git-branch.txt\n@@ -10,6 +10,7 @@ SYNOPSIS\n [verse]\n 'git branch' [--color[=<when>] | --no-color] [-r | -a]\n \t[--list] [-v [--abbrev=<length> | --no-abbrev]]\n+\t[--count=<count>] [(--sort=<key>)...]\n \t[(--merged | --no-merged | --contains) [<commit>]] [<pattern>...]\n 'git branch' [--set-upstream | --track | --no-track] [-l] [-f] <branchname> [<start-point>]\n 'git branch' (-m | -M) [<oldbranch>] <newbranch>\n@@ -192,6 +193,18 @@ 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+<count>::\n+\tBy default the command shows all refs that match\n+\t`<pattern>`.  This option makes it stop after showing\n+\tthat many refs.\n+\n+<key>::\n+\tA field name to sort on.  Prefix `-` to sort in descending\n+\torder of the value.  When unspecified, `refname` is used.  You\n+\tmay use the --sort=<key> option multiple times, in which case\n+\tthe last key becomes the primary key. See\n+\tlinkgit:for-each-ref[1] for field name details.\n+\n \n Examples\n --------\ndiff --git a/Makefile b/Makefile\nindex a782409..daf3e46 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -2108,6 +2108,7 @@ builtin/log.o builtin/shortlog.o: shortlog.h\n builtin/prune.o builtin/reflog.o reachable.o: reachable.h\n builtin/commit.o builtin/revert.o wt-status.o: wt-status.h\n builtin/tar-tree.o archive-tar.o: tar.h\n+builtin/branch.o builtin/for-each-ref.o: builtin/for-each-ref.h\n connect.o transport.o url.o http-backend.o: url.h\n http-fetch.o http-walker.o remote-curl.o transport.o walker.o: walker.h\n http.o http-walker.o http-push.o http-fetch.o remote-curl.o: http.h url.h\ndiff --git a/builtin/branch.c b/builtin/branch.c\nindex 7095718..67bdbc7 100644\n--- a/builtin/branch.c\n+++ b/builtin/branch.c\n@@ -15,6 +15,7 @@\n #include \"branch.h\"\n #include \"diff.h\"\n #include \"revision.h\"\n+#include \"for-each-ref.h\"\n \n static const char * const builtin_branch_usage[] = {\n \t\"git branch [options] [-r | -a] [--merged | --no-merged]\",\n@@ -30,6 +31,9 @@ static const char * const builtin_branch_usage[] = {\n static const char *head;\n static unsigned char head_sha1[20];\n \n+static struct ref_sort *sort = NULL, **sort_tail = &sort;\n+static int maxcount;\n+\n static int branch_use_color = -1;\n static char branch_colors[][COLOR_MAXLEN] = {\n \tGIT_COLOR_RESET,\n@@ -312,7 +316,7 @@ static int append_ref(const char *refname, const unsigned char *sha1, int flags,\n \tif ((kind & ref_list->kinds) == 0)\n \t\treturn 0;\n \n-\tif (!match_patterns(cb->pattern, refname))\n+\tif (cb->pattern && !match_patterns(cb->pattern, refname))\n \t\treturn 0;\n \n \tcommit = NULL;\n@@ -510,10 +514,38 @@ static void show_detached(struct ref_list *ref_list)\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+static int fetch_branches(struct ref_list *ref_list,\n+\t\t\t\t const char **pattern)\n {\n-\tint i;\n \tstruct append_ref_cb cb;\n+\tcb.ref_list = ref_list;\n+\tcb.pattern = pattern;\n+\tcb.ret = 0;\n+\tif (sort) {\n+\t\tstruct grab_ref_cbdata cbdata;\n+\t\tint i;\n+\t\tmemset(&cbdata, 0, sizeof(cbdata));\n+\t\tcbdata.grab_pattern = pattern;\n+\t\tfor_each_rawref(grab_single_ref, &cbdata);\n+\t\tsort_refs(sort, cbdata.grab_array, cbdata.grab_cnt);\n+\t\tfor (i = 0; i < cbdata.grab_cnt; i++) {\n+\t\t\tstruct refinfo *ri = cbdata.grab_array[i];\n+\t\t\tappend_ref(ri->refname, ri->objectname, ri->flag, &cb);\n+\t\t}\n+\t}\n+\telse {\n+\t\tfor_each_rawref(append_ref, &cb);\n+\t\tqsort(ref_list->list, ref_list->index,\n+\t\t      sizeof(struct ref_item), ref_cmp);\n+\t}\n+\treturn cb.ret;\n+}\n+\n+static int print_ref_list(int kinds, int detached, int verbose, int abbrev,\n+\t\t\t  struct commit_list *with_commit,\n+\t\t\t  const char **pattern)\n+{\n+\tint i, ret;\n \tstruct ref_list ref_list;\n \n \tmemset(&ref_list, 0, sizeof(ref_list));\n@@ -523,10 +555,7 @@ static int print_ref_list(int kinds, int detached, int verbose, int abbrev, stru\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-\tcb.ret = 0;\n-\tfor_each_rawref(append_ref, &cb);\n+\tret = fetch_branches(&ref_list, pattern);\n \tif (merge_filter != NO_FILTER) {\n \t\tstruct commit *filter;\n \t\tfilter = lookup_commit_reference_gently(merge_filter_ref, 0);\n@@ -539,13 +568,13 @@ static int print_ref_list(int kinds, int detached, int verbose, int abbrev, stru\n \t\t\tref_list.maxwidth = calc_maxwidth(&ref_list);\n \t}\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 \n-\tfor (i = 0; i < ref_list.index; i++) {\n+\tif (!maxcount)\n+\t\tmaxcount = ref_list.index;\n+\tfor (i = 0; i < maxcount; 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@@ -558,10 +587,10 @@ static int print_ref_list(int kinds, int detached, int verbose, int abbrev, stru\n \n \tfree_ref_list(&ref_list);\n \n-\tif (cb.ret)\n+\tif (ret)\n \t\terror(_(\"some refs could not be read\"));\n \n-\treturn cb.ret;\n+\treturn ret;\n }\n \n static void rename_branch(const char *oldname, const char *newname, int force)\n@@ -702,6 +731,9 @@ int cmd_branch(int argc, const char **argv, const char *prefix)\n \t\t\tparse_opt_with_commit, (intptr_t) \"HEAD\",\n \t\t},\n \t\tOPT__ABBREV(&abbrev),\n+\t\tOPT_CALLBACK(0 , \"sort\", sort_tail, \"key\",\n+\t\t\t     \"field name to sort on\", &opt_parse_sort),\n+\t\tOPT_INTEGER( 0 , \"count\", &maxcount, \"show only <n> matched refs\"),\n \n \t\tOPT_GROUP(\"Specific git-branch actions:\"),\n \t\tOPT_SET_INT('a', \"all\", &kinds, \"list both remote-tracking and local branches\",\n@@ -752,6 +784,11 @@ int cmd_branch(int argc, const char **argv, const char *prefix)\n \targc = parse_options(argc, argv, prefix, options, builtin_branch_usage,\n \t\t\t     0);\n \n+\tif (maxcount < 0) {\n+\t\terror(\"invalid --count argument: `%d'\", maxcount);\n+\t\tusage_with_options(builtin_branch_usage, options);\n+\t}\n+\n \tif (!delete && !rename && !edit_description && argc == 0)\n \t\tlist = 1;\n \ndiff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c\nindex b01d76a..7b25c54 100644\n--- a/builtin/for-each-ref.c\n+++ b/builtin/for-each-ref.c\n@@ -9,6 +9,7 @@\n #include \"quote.h\"\n #include \"parse-options.h\"\n #include \"remote.h\"\n+#include \"for-each-ref.h\"\n \n /* Quoting styles */\n #define QUOTE_NONE 0\n@@ -19,25 +20,6 @@\n \n typedef enum { FIELD_STR, FIELD_ULONG, FIELD_TIME } cmp_type;\n \n-struct atom_value {\n-\tconst char *s;\n-\tunsigned long ul; /* used for sorting when not FIELD_STR */\n-};\n-\n-struct ref_sort {\n-\tstruct ref_sort *next;\n-\tint atom; /* index into used_atom array */\n-\tunsigned reverse : 1;\n-};\n-\n-struct refinfo {\n-\tchar *refname;\n-\tunsigned char objectname[20];\n-\tint flag;\n-\tconst char *symref;\n-\tstruct atom_value *value;\n-};\n-\n static struct {\n \tconst char *name;\n \tcmp_type cmp_type;\n@@ -765,17 +747,12 @@ static void get_value(struct refinfo *ref, int atom, struct atom_value **v)\n \t*v = &ref->value[atom];\n }\n \n-struct grab_ref_cbdata {\n-\tstruct refinfo **grab_array;\n-\tconst char **grab_pattern;\n-\tint grab_cnt;\n-};\n-\n /*\n  * A call-back given to for_each_ref().  Filter refs and keep them for\n  * later object processing.\n  */\n-static int grab_single_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)\n+int grab_single_ref(const char *refname, const unsigned char *sha1,\n+\t\t    int flag, void *cb_data)\n {\n \tstruct grab_ref_cbdata *cb = cb_data;\n \tstruct refinfo *ref;\n@@ -858,7 +835,7 @@ static int compare_refs(const void *a_, const void *b_)\n \treturn 0;\n }\n \n-static void sort_refs(struct ref_sort *sort, struct refinfo **refs, int num_refs)\n+void sort_refs(struct ref_sort *sort, struct refinfo **refs, int num_refs)\n {\n \tref_sort = sort;\n \tqsort(refs, num_refs, sizeof(struct refinfo *), compare_refs);\n@@ -953,7 +930,7 @@ static struct ref_sort *default_sort(void)\n \treturn sort;\n }\n \n-static int opt_parse_sort(const struct option *opt, const char *arg, int unset)\n+int opt_parse_sort(const struct option *opt, const char *arg, int unset)\n {\n \tstruct ref_sort **sort_tail = opt->value;\n \tstruct ref_sort *s;\ndiff --git a/builtin/for-each-ref.h b/builtin/for-each-ref.h\nnew file mode 100644\nindex 0000000..8542d66\n--- /dev/null\n+++ b/builtin/for-each-ref.h\n@@ -0,0 +1,32 @@\n+struct atom_value {\n+\tconst char *s;\n+\tunsigned long ul; /* used for sorting when not FIELD_STR */\n+};\n+\n+struct ref_sort {\n+\tstruct ref_sort *next;\n+\tint atom; /* index into used_atom array */\n+\tunsigned reverse : 1;\n+};\n+\n+struct refinfo {\n+\tchar *refname;\n+\tunsigned char objectname[20];\n+\tint flag;\n+\tconst char *symref;\n+\tstruct atom_value *value;\n+};\n+\n+struct grab_ref_cbdata {\n+\tstruct refinfo **grab_array;\n+\tconst char **grab_pattern;\n+\tint grab_cnt;\n+};\n+\n+extern int grab_single_ref(const char *refname,\n+\t\t\t   const unsigned char *sha1,\n+\t\t\t   int flag, void *cb_data);\n+extern int opt_parse_sort(const struct option *opt,\n+\t\t\t  const char *arg, int unset);\n+extern void sort_refs(struct ref_sort *sort,\n+\t\t      struct refinfo **refs, int num_refs);\n-- \n1.7.8.36.g69ee2\n"},{"id":"182697","messageId":"7vvcoaqe9h.fsf@alter.siamese.dyndns.org","threadId":"29382","inReplyTo":"1326805907-19416-1-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH] branch: borrow --sort and --count from for-each-ref","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-01-17T20:12:58Z","receivedAt":"2012-01-17T20:12:58Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:\n\n> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n> ---\n>  Some time ago, I posted a patch that added date sort to git-branch\n>  and Peff pointed me to for-each-ref. I did not look at it closely.\n>  Now it does not seem hard to lend some code from for-each-ref to\n>  git-branch. I can list 10 most recently touched branches with\n>\n>   git branch --sort=-committerdate -v --count=10\n>\n>  kind of cool. I don't think adding --format is necessary because\n>  git-branch already has its own formatting.\n\nWhy do we even need this for \"git branch\", when \"git for-each-ref\nrefs/heads\" already does this?\n"},{"id":"182711","messageId":"CACsJy8An5oYv_Ki2oFezykSDFXmprPq07G7G4xq+srhcpP+OHg@mail.gmail.com","threadId":"29382","inReplyTo":"7vvcoaqe9h.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH] branch: borrow --sort and --count from for-each-ref","fromName":"Nguyen Thai Ngoc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2012-01-18T01:20:05Z","receivedAt":"2012-01-18T01:20:05Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"2012/1/18 Junio C Hamano <gitster@pobox.com>:\n> Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:\n>\n>> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n>> ---\n>>  Some time ago, I posted a patch that added date sort to git-branch\n>>  and Peff pointed me to for-each-ref. I did not look at it closely.\n>>  Now it does not seem hard to lend some code from for-each-ref to\n>>  git-branch. I can list 10 most recently touched branches with\n>>\n>>   git branch --sort=-committerdate -v --count=10\n>>\n>>  kind of cool. I don't think adding --format is necessary because\n>>  git-branch already has its own formatting.\n>\n> Why do we even need this for \"git branch\", when \"git for-each-ref\n> refs/heads\" already does this?\n\ncoloring, current branch marking, \"branch -v\", more accessible command\n(I did not know about for-each-ref until Jeff told me)\n-- \nDuy\n"},{"id":"183845","messageId":"1328372345-16479-1-git-send-email-pclouds@gmail.com","threadId":"29382","inReplyTo":"1326805907-19416-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v2] branch: borrow --sort and --count from for-each-ref","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2012-02-04T16:19:05Z","receivedAt":"2012-02-04T16:19:05Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Fix sorted refs being fnmatch()'d twice.\n\n Documentation/git-branch.txt |   13 +++++++++\n Makefile                     |    1 +\n builtin/branch.c             |   60 +++++++++++++++++++++++++++++++++--------\n builtin/for-each-ref.c       |   33 +++-------------------\n builtin/for-each-ref.h       |   32 ++++++++++++++++++++++\n 5 files changed, 99 insertions(+), 40 deletions(-)\n create mode 100644 builtin/for-each-ref.h\n\ndiff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt\nindex 0427e80..b6f2826 100644\n--- a/Documentation/git-branch.txt\n+++ b/Documentation/git-branch.txt\n@@ -10,6 +10,7 @@ SYNOPSIS\n [verse]\n 'git branch' [--color[=<when>] | --no-color] [-r | -a]\n \t[--list] [-v [--abbrev=<length> | --no-abbrev]]\n+\t[--count=<count>] [(--sort=<key>)...]\n \t[(--merged | --no-merged | --contains) [<commit>]] [<pattern>...]\n 'git branch' [--set-upstream | --track | --no-track] [-l] [-f] <branchname> [<start-point>]\n 'git branch' (-m | -M) [<oldbranch>] <newbranch>\n@@ -192,6 +193,18 @@ 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+<count>::\n+\tBy default the command shows all refs that match\n+\t`<pattern>`.  This option makes it stop after showing\n+\tthat many refs.\n+\n+<key>::\n+\tA field name to sort on.  Prefix `-` to sort in descending\n+\torder of the value.  When unspecified, `refname` is used.  You\n+\tmay use the --sort=<key> option multiple times, in which case\n+\tthe last key becomes the primary key. See\n+\tlinkgit:for-each-ref[1] for field name details.\n+\n \n Examples\n --------\ndiff --git a/Makefile b/Makefile\nindex a782409..daf3e46 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -2108,6 +2108,7 @@ builtin/log.o builtin/shortlog.o: shortlog.h\n builtin/prune.o builtin/reflog.o reachable.o: reachable.h\n builtin/commit.o builtin/revert.o wt-status.o: wt-status.h\n builtin/tar-tree.o archive-tar.o: tar.h\n+builtin/branch.o builtin/for-each-ref.o: builtin/for-each-ref.h\n connect.o transport.o url.o http-backend.o: url.h\n http-fetch.o http-walker.o remote-curl.o transport.o walker.o: walker.h\n http.o http-walker.o http-push.o http-fetch.o remote-curl.o: http.h url.h\ndiff --git a/builtin/branch.c b/builtin/branch.c\nindex 7095718..97bf96c 100644\n--- a/builtin/branch.c\n+++ b/builtin/branch.c\n@@ -15,6 +15,7 @@\n #include \"branch.h\"\n #include \"diff.h\"\n #include \"revision.h\"\n+#include \"for-each-ref.h\"\n \n static const char * const builtin_branch_usage[] = {\n \t\"git branch [options] [-r | -a] [--merged | --no-merged]\",\n@@ -30,6 +31,9 @@ static const char * const builtin_branch_usage[] = {\n static const char *head;\n static unsigned char head_sha1[20];\n \n+static struct ref_sort *sort = NULL, **sort_tail = &sort;\n+static int maxcount;\n+\n static int branch_use_color = -1;\n static char branch_colors[][COLOR_MAXLEN] = {\n \tGIT_COLOR_RESET,\n@@ -312,7 +316,7 @@ static int append_ref(const char *refname, const unsigned char *sha1, int flags,\n \tif ((kind & ref_list->kinds) == 0)\n \t\treturn 0;\n \n-\tif (!match_patterns(cb->pattern, refname))\n+\tif (cb->pattern && !match_patterns(cb->pattern, refname))\n \t\treturn 0;\n \n \tcommit = NULL;\n@@ -510,10 +514,37 @@ static void show_detached(struct ref_list *ref_list)\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+static int fetch_branches(struct ref_list *ref_list,\n+\t\t\t\t const char **pattern)\n {\n-\tint i;\n \tstruct append_ref_cb cb;\n+\tmemset(&cb, 0, sizeof(cb));\n+\tcb.ref_list = ref_list;\n+\tif (sort) {\n+\t\tstruct grab_ref_cbdata cbdata;\n+\t\tint i;\n+\t\tmemset(&cbdata, 0, sizeof(cbdata));\n+\t\tcbdata.grab_pattern = pattern;\n+\t\tfor_each_rawref(grab_single_ref, &cbdata);\n+\t\tsort_refs(sort, cbdata.grab_array, cbdata.grab_cnt);\n+\t\tfor (i = 0; i < cbdata.grab_cnt; i++) {\n+\t\t\tstruct refinfo *ri = cbdata.grab_array[i];\n+\t\t\tappend_ref(ri->refname, ri->objectname, ri->flag, &cb);\n+\t\t}\n+\t} else {\n+\t\tcb.pattern = pattern;\n+\t\tfor_each_rawref(append_ref, &cb);\n+\t\tqsort(ref_list->list, ref_list->index,\n+\t\t      sizeof(struct ref_item), ref_cmp);\n+\t}\n+\treturn cb.ret;\n+}\n+\n+static int print_ref_list(int kinds, int detached, int verbose, int abbrev,\n+\t\t\t  struct commit_list *with_commit,\n+\t\t\t  const char **pattern)\n+{\n+\tint i, ret;\n \tstruct ref_list ref_list;\n \n \tmemset(&ref_list, 0, sizeof(ref_list));\n@@ -523,10 +554,7 @@ static int print_ref_list(int kinds, int detached, int verbose, int abbrev, stru\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-\tcb.ret = 0;\n-\tfor_each_rawref(append_ref, &cb);\n+\tret = fetch_branches(&ref_list, pattern);\n \tif (merge_filter != NO_FILTER) {\n \t\tstruct commit *filter;\n \t\tfilter = lookup_commit_reference_gently(merge_filter_ref, 0);\n@@ -539,13 +567,13 @@ static int print_ref_list(int kinds, int detached, int verbose, int abbrev, stru\n \t\t\tref_list.maxwidth = calc_maxwidth(&ref_list);\n \t}\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 \n-\tfor (i = 0; i < ref_list.index; i++) {\n+\tif (!maxcount)\n+\t\tmaxcount = ref_list.index;\n+\tfor (i = 0; i < maxcount; 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@@ -558,10 +586,10 @@ static int print_ref_list(int kinds, int detached, int verbose, int abbrev, stru\n \n \tfree_ref_list(&ref_list);\n \n-\tif (cb.ret)\n+\tif (ret)\n \t\terror(_(\"some refs could not be read\"));\n \n-\treturn cb.ret;\n+\treturn ret;\n }\n \n static void rename_branch(const char *oldname, const char *newname, int force)\n@@ -702,6 +730,9 @@ int cmd_branch(int argc, const char **argv, const char *prefix)\n \t\t\tparse_opt_with_commit, (intptr_t) \"HEAD\",\n \t\t},\n \t\tOPT__ABBREV(&abbrev),\n+\t\tOPT_CALLBACK(0 , \"sort\", sort_tail, \"key\",\n+\t\t\t     \"field name to sort on\", &opt_parse_sort),\n+\t\tOPT_INTEGER( 0 , \"count\", &maxcount, \"show only <n> matched refs\"),\n \n \t\tOPT_GROUP(\"Specific git-branch actions:\"),\n \t\tOPT_SET_INT('a', \"all\", &kinds, \"list both remote-tracking and local branches\",\n@@ -752,6 +783,11 @@ int cmd_branch(int argc, const char **argv, const char *prefix)\n \targc = parse_options(argc, argv, prefix, options, builtin_branch_usage,\n \t\t\t     0);\n \n+\tif (maxcount < 0) {\n+\t\terror(\"invalid --count argument: `%d'\", maxcount);\n+\t\tusage_with_options(builtin_branch_usage, options);\n+\t}\n+\n \tif (!delete && !rename && !edit_description && argc == 0)\n \t\tlist = 1;\n \ndiff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c\nindex b01d76a..7b25c54 100644\n--- a/builtin/for-each-ref.c\n+++ b/builtin/for-each-ref.c\n@@ -9,6 +9,7 @@\n #include \"quote.h\"\n #include \"parse-options.h\"\n #include \"remote.h\"\n+#include \"for-each-ref.h\"\n \n /* Quoting styles */\n #define QUOTE_NONE 0\n@@ -19,25 +20,6 @@\n \n typedef enum { FIELD_STR, FIELD_ULONG, FIELD_TIME } cmp_type;\n \n-struct atom_value {\n-\tconst char *s;\n-\tunsigned long ul; /* used for sorting when not FIELD_STR */\n-};\n-\n-struct ref_sort {\n-\tstruct ref_sort *next;\n-\tint atom; /* index into used_atom array */\n-\tunsigned reverse : 1;\n-};\n-\n-struct refinfo {\n-\tchar *refname;\n-\tunsigned char objectname[20];\n-\tint flag;\n-\tconst char *symref;\n-\tstruct atom_value *value;\n-};\n-\n static struct {\n \tconst char *name;\n \tcmp_type cmp_type;\n@@ -765,17 +747,12 @@ static void get_value(struct refinfo *ref, int atom, struct atom_value **v)\n \t*v = &ref->value[atom];\n }\n \n-struct grab_ref_cbdata {\n-\tstruct refinfo **grab_array;\n-\tconst char **grab_pattern;\n-\tint grab_cnt;\n-};\n-\n /*\n  * A call-back given to for_each_ref().  Filter refs and keep them for\n  * later object processing.\n  */\n-static int grab_single_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)\n+int grab_single_ref(const char *refname, const unsigned char *sha1,\n+\t\t    int flag, void *cb_data)\n {\n \tstruct grab_ref_cbdata *cb = cb_data;\n \tstruct refinfo *ref;\n@@ -858,7 +835,7 @@ static int compare_refs(const void *a_, const void *b_)\n \treturn 0;\n }\n \n-static void sort_refs(struct ref_sort *sort, struct refinfo **refs, int num_refs)\n+void sort_refs(struct ref_sort *sort, struct refinfo **refs, int num_refs)\n {\n \tref_sort = sort;\n \tqsort(refs, num_refs, sizeof(struct refinfo *), compare_refs);\n@@ -953,7 +930,7 @@ static struct ref_sort *default_sort(void)\n \treturn sort;\n }\n \n-static int opt_parse_sort(const struct option *opt, const char *arg, int unset)\n+int opt_parse_sort(const struct option *opt, const char *arg, int unset)\n {\n \tstruct ref_sort **sort_tail = opt->value;\n \tstruct ref_sort *s;\ndiff --git a/builtin/for-each-ref.h b/builtin/for-each-ref.h\nnew file mode 100644\nindex 0000000..8542d66\n--- /dev/null\n+++ b/builtin/for-each-ref.h\n@@ -0,0 +1,32 @@\n+struct atom_value {\n+\tconst char *s;\n+\tunsigned long ul; /* used for sorting when not FIELD_STR */\n+};\n+\n+struct ref_sort {\n+\tstruct ref_sort *next;\n+\tint atom; /* index into used_atom array */\n+\tunsigned reverse : 1;\n+};\n+\n+struct refinfo {\n+\tchar *refname;\n+\tunsigned char objectname[20];\n+\tint flag;\n+\tconst char *symref;\n+\tstruct atom_value *value;\n+};\n+\n+struct grab_ref_cbdata {\n+\tstruct refinfo **grab_array;\n+\tconst char **grab_pattern;\n+\tint grab_cnt;\n+};\n+\n+extern int grab_single_ref(const char *refname,\n+\t\t\t   const unsigned char *sha1,\n+\t\t\t   int flag, void *cb_data);\n+extern int opt_parse_sort(const struct option *opt,\n+\t\t\t  const char *arg, int unset);\n+extern void sort_refs(struct ref_sort *sort,\n+\t\t      struct refinfo **refs, int num_refs);\n-- \n1.7.8.36.g69ee2\n"}]}