diff options
author | Karthik Nayak <karthik.188@gmail.com> | 2015-09-23 23:41:12 +0530 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2015-09-25 08:54:54 -0700 |
commit | aedcb7dc75e5c260f20bebe14925f3ac4841b03d (patch) | |
tree | 7f2f9491b16883c75017c3c244b16114d2d1ab25 /builtin/branch.c | |
parent | 1511b22d40d102f397104858a617aa1662bb1c98 (diff) | |
download | git-aedcb7dc75e5c260f20bebe14925f3ac4841b03d.tar.gz |
branch.c: use 'ref-filter' APIs
Make 'branch.c' use 'ref-filter' APIs for iterating through refs
sorting. This removes most of the code used in 'branch.c' replacing it
with calls to the 'ref-filter' library.
Make 'branch.c' use the 'filter_refs()' function provided by 'ref-filter'
to filter out tags based on the options set.
We provide a sorting option provided for 'branch.c' by using the
sorting options provided by 'ref-filter'. Also by default, we sort by
'refname'. Since 'HEAD' is alphabatically before 'refs/...' we end up
with an array consisting of the 'HEAD' ref then the local branches and
finally the remote-tracking branches.
Also remove the 'ignore' variable from ref_array_item as it was
previously used for the '--merged' option and now that is handled by
ref-filter.
Modify some of the tests in t1430 to check the stderr for a warning
regarding the broken ref. This is done as ref-filter throws a warning
for broken refs rather than directly printing them.
Add tests and documentation for the same.
Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>
Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'builtin/branch.c')
-rw-r--r-- | builtin/branch.c | 213 |
1 files changed, 35 insertions, 178 deletions
diff --git a/builtin/branch.c b/builtin/branch.c index bfbba2f8d1..b83116a609 100644 --- a/builtin/branch.c +++ b/builtin/branch.c @@ -270,125 +270,6 @@ static int delete_branches(int argc, const char **argv, int force, int kinds, return(ret); } -static char *resolve_symref(const char *src, const char *prefix) -{ - unsigned char sha1[20]; - int flag; - const char *dst; - - dst = resolve_ref_unsafe(src, 0, sha1, &flag); - if (!(dst && (flag & REF_ISSYMREF))) - return NULL; - if (prefix) - skip_prefix(dst, prefix, &dst); - return xstrdup(dst); -} - -static int match_patterns(const char **pattern, const char *refname) -{ - if (!*pattern) - return 1; /* no pattern always matches */ - while (*pattern) { - if (!wildmatch(*pattern, refname, 0, NULL)) - return 1; - pattern++; - } - return 0; -} - -/* - * Allocate memory for a new ref_array_item and insert that into the - * given ref_array. Doesn't take the objectname unlike - * new_ref_array_item(). This is a temporary function which will be - * removed when we port branch.c to use ref-filter APIs. - */ -static struct ref_array_item *ref_array_append(struct ref_array *array, const char *refname) -{ - size_t len = strlen(refname); - struct ref_array_item *ref = xcalloc(1, sizeof(struct ref_array_item) + len + 1); - memcpy(ref->refname, refname, len); - ref->refname[len] = '\0'; - REALLOC_ARRAY(array->items, array->nr + 1); - array->items[array->nr++] = ref; - return ref; -} - -static int append_ref(const char *refname, const struct object_id *oid, int flags, void *cb_data) -{ - struct ref_filter_cbdata *cb = (struct ref_filter_cbdata *)(cb_data); - struct ref_filter *filter = cb->filter; - struct ref_array *array = cb->array; - struct ref_array_item *item; - struct commit *commit; - int kind, i; - const char *prefix, *orig_refname = refname; - - static struct { - int kind; - const char *prefix; - } ref_kind[] = { - { FILTER_REFS_BRANCHES, "refs/heads/" }, - { FILTER_REFS_REMOTES, "refs/remotes/" }, - }; - - /* Detect kind */ - for (i = 0; i < ARRAY_SIZE(ref_kind); i++) { - prefix = ref_kind[i].prefix; - if (skip_prefix(refname, prefix, &refname)) { - kind = ref_kind[i].kind; - break; - } - } - if (ARRAY_SIZE(ref_kind) <= i) { - if (!strcmp(refname, "HEAD")) - kind = FILTER_REFS_DETACHED_HEAD; - else - return 0; - } - - /* Don't add types the caller doesn't want */ - if ((kind & filter->kind) == 0) - return 0; - - if (!match_patterns(filter->name_patterns, refname)) - return 0; - - commit = NULL; - if (filter->verbose || filter->with_commit || filter->merge != REF_FILTER_MERGED_NONE) { - commit = lookup_commit_reference_gently(oid->hash, 1); - if (!commit) - return 0; - - /* Filter with with_commit if specified */ - if (!is_descendant_of(commit, filter->with_commit)) - return 0; - - if (filter->merge != REF_FILTER_MERGED_NONE) - add_pending_object(array->revs, - (struct object *)commit, refname); - } - - item = ref_array_append(array, refname); - - /* Record the new item */ - item->kind = kind; - item->commit = commit; - item->symref = resolve_symref(orig_refname, prefix); - item->ignore = 0; - - return 0; -} - -static int ref_cmp(const void *r1, const void *r2) -{ - struct ref_array_item *c1 = *((struct ref_array_item **)r1); - struct ref_array_item *c2 = *((struct ref_array_item **)r2); - - if (c1->kind != c2->kind) - return c1->kind - c2->kind; - return strcmp(c1->refname, c2->refname); -} - static void fill_tracking_info(struct strbuf *stat, const char *branch_name, int show_upstream_ref) { @@ -452,7 +333,7 @@ static void fill_tracking_info(struct strbuf *stat, const char *branch_name, } static void add_verbose_info(struct strbuf *out, struct ref_array_item *item, - struct ref_filter *filter) + struct ref_filter *filter, const char *refname) { struct strbuf subject = STRBUF_INIT, stat = STRBUF_INIT; const char *sub = _(" **** invalid ref ****"); @@ -464,7 +345,7 @@ static void add_verbose_info(struct strbuf *out, struct ref_array_item *item, } if (item->kind == FILTER_REFS_BRANCHES) - fill_tracking_info(&stat, item->refname, filter->verbose > 1); + fill_tracking_info(&stat, refname, filter->verbose > 1); strbuf_addf(out, " %s %s%s", find_unique_abbrev(item->commit->object.sha1, filter->abbrev), @@ -504,8 +385,8 @@ static char *get_head_description(void) return strbuf_detach(&desc, NULL); } -static void print_ref_item(struct ref_array_item *item, int maxwidth, - struct ref_filter *filter, const char *remote_prefix) +static void format_and_print_ref_item(struct ref_array_item *item, int maxwidth, + struct ref_filter *filter, const char *remote_prefix) { char c; int current = 0; @@ -515,17 +396,16 @@ static void print_ref_item(struct ref_array_item *item, int maxwidth, const char *desc = item->refname; char *to_free = NULL; - if (item->ignore) - return; - switch (item->kind) { case FILTER_REFS_BRANCHES: - if (!filter->detached && !strcmp(item->refname, head)) + skip_prefix(desc, "refs/heads/", &desc); + if (!filter->detached && !strcmp(desc, head)) current = 1; else color = BRANCH_COLOR_LOCAL; break; case FILTER_REFS_REMOTES: + skip_prefix(desc, "refs/remotes/", &desc); color = BRANCH_COLOR_REMOTE; prefix = remote_prefix; break; @@ -554,11 +434,13 @@ static void print_ref_item(struct ref_array_item *item, int maxwidth, strbuf_addf(&out, "%c %s%s%s", c, branch_get_color(color), name.buf, branch_get_color(BRANCH_COLOR_RESET)); - if (item->symref) - strbuf_addf(&out, " -> %s", item->symref); + if (item->symref) { + skip_prefix(item->symref, "refs/remotes/", &desc); + strbuf_addf(&out, " -> %s", desc); + } else if (filter->verbose) /* " f7c0c00 [ahead 58, behind 197] vcs-svn: drop obj_pool.h" */ - add_verbose_info(&out, item, filter); + add_verbose_info(&out, item, filter, desc); if (column_active(colopts)) { assert(!filter->verbose && "--column and --verbose are incompatible"); string_list_append(&output, out.buf); @@ -575,11 +457,13 @@ static int calc_maxwidth(struct ref_array *refs, int remote_bonus) int i, max = 0; for (i = 0; i < refs->nr; i++) { struct ref_array_item *it = refs->items[i]; + const char *desc = it->refname; int w; - if (it->ignore) - continue; - w = utf8_strwidth(it->refname); + skip_prefix(it->refname, "refs/heads/", &desc); + skip_prefix(it->refname, "refs/remotes/", &desc); + w = utf8_strwidth(desc); + if (it->kind == FILTER_REFS_REMOTES) w += remote_bonus; if (w > max) @@ -588,14 +472,12 @@ static int calc_maxwidth(struct ref_array *refs, int remote_bonus) return max; } -static void print_ref_list(struct ref_filter *filter) +static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sorting) { int i; struct ref_array array; - struct ref_filter_cbdata data; int maxwidth = 0; const char *remote_prefix = ""; - struct rev_info revs; /* * If we are listing more than just remote branches, @@ -606,54 +488,26 @@ static void print_ref_list(struct ref_filter *filter) remote_prefix = "remotes/"; memset(&array, 0, sizeof(array)); - if (filter->merge != REF_FILTER_MERGED_NONE) - init_revisions(&revs, NULL); - - data.array = &array; - data.filter = filter; - array.revs = &revs; - - /* - * First we obtain all regular branch refs and if the HEAD is - * detached then we insert that ref to the end of the ref_fist - * so that it can be printed and removed first. - */ - for_each_rawref(append_ref, &data); - if (filter->detached) - head_ref(append_ref, &data); - /* - * The following implementation is currently duplicated in ref-filter. It - * will eventually be removed when we port branch.c to use ref-filter APIs. - */ - if (filter->merge != REF_FILTER_MERGED_NONE) { - filter->merge_commit->object.flags |= UNINTERESTING; - add_pending_object(&revs, &filter->merge_commit->object, ""); - revs.limited = 1; - - if (prepare_revision_walk(&revs)) - die(_("revision walk setup failed")); - - for (i = 0; i < array.nr; i++) { - struct ref_array_item *item = array.items[i]; - struct commit *commit = item->commit; - int is_merged = !!(commit->object.flags & UNINTERESTING); - item->ignore = is_merged != (filter->merge == REF_FILTER_MERGED_INCLUDE); - } - for (i = 0; i < array.nr; i++) { - struct ref_array_item *item = array.items[i]; - clear_commit_marks(item->commit, ALL_REV_FLAGS); - } - clear_commit_marks(filter->merge_commit, ALL_REV_FLAGS); - } + verify_ref_format("%(refname)%(symref)"); + filter_refs(&array, filter, filter->kind | FILTER_REFS_INCLUDE_BROKEN); if (filter->verbose) maxwidth = calc_maxwidth(&array, strlen(remote_prefix)); - qsort(array.items, array.nr, sizeof(struct ref_array_item *), ref_cmp); + /* + * If no sorting parameter is given then we default to sorting + * by 'refname'. This would give us an alphabetically sorted + * array with the 'HEAD' ref at the beginning followed by + * local branches 'refs/heads/...' and finally remote-tacking + * branches 'refs/remotes/...'. + */ + if (!sorting) + sorting = ref_default_sorting(); + ref_array_sort(sorting, &array); for (i = 0; i < array.nr; i++) - print_ref_item(array.items[i], maxwidth, filter, remote_prefix); + format_and_print_ref_item(array.items[i], maxwidth, filter, remote_prefix); ref_array_clear(&array); } @@ -755,6 +609,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix) const char *new_upstream = NULL; enum branch_track track; struct ref_filter filter; + static struct ref_sorting *sorting = NULL, **sorting_tail = &sorting; struct option options[] = { OPT_GROUP(N_("Generic options")), @@ -789,6 +644,8 @@ int cmd_branch(int argc, const char **argv, const char *prefix) OPT_MERGED(&filter, N_("print only branches that are merged")), OPT_NO_MERGED(&filter, N_("print only branches that are not merged")), OPT_COLUMN(0, "column", &colopts, N_("list branches in columns")), + OPT_CALLBACK(0 , "sort", sorting_tail, N_("key"), + N_("field name to sort on"), &parse_opt_ref_sorting), OPT_END(), }; @@ -847,7 +704,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix) if ((filter.kind & FILTER_REFS_BRANCHES) && filter.detached) filter.kind |= FILTER_REFS_DETACHED_HEAD; filter.name_patterns = argv; - print_ref_list(&filter); + print_ref_list(&filter, sorting); print_columns(&output, colopts, NULL); string_list_clear(&output, 0); return 0; |