From d4919bb288e46c81b92d6fe02c4f4564b8477fd3 Mon Sep 17 00:00:00 2001 From: Karthik Nayak Date: Tue, 10 Jan 2017 14:19:38 +0530 Subject: ref-filter: move get_head_description() from branch.c Move the implementation of get_head_description() from branch.c to ref-filter. This gives a description of the HEAD ref if called. This is used as the refname for the HEAD ref whenever the FILTER_REFS_DETACHED_HEAD option is used. Make it public because we need it to calculate the length of the HEAD refs description in branch.c:calc_maxwidth() when we port branch.c to use ref-filter APIs. Mentored-by: Christian Couder Mentored-by: Matthieu Moy Signed-off-by: Karthik Nayak Signed-off-by: Junio C Hamano --- builtin/branch.c | 33 --------------------------------- 1 file changed, 33 deletions(-) (limited to 'builtin') diff --git a/builtin/branch.c b/builtin/branch.c index 9d30f55b0b..6423ebce5d 100644 --- a/builtin/branch.c +++ b/builtin/branch.c @@ -364,39 +364,6 @@ static void add_verbose_info(struct strbuf *out, struct ref_array_item *item, strbuf_release(&subject); } -static char *get_head_description(void) -{ - struct strbuf desc = STRBUF_INIT; - struct wt_status_state state; - memset(&state, 0, sizeof(state)); - wt_status_get_state(&state, 1); - if (state.rebase_in_progress || - state.rebase_interactive_in_progress) - strbuf_addf(&desc, _("(no branch, rebasing %s)"), - state.branch); - else if (state.bisect_in_progress) - strbuf_addf(&desc, _("(no branch, bisect started on %s)"), - state.branch); - else if (state.detached_from) { - if (state.detached_at) - /* TRANSLATORS: make sure this matches - "HEAD detached at " in wt-status.c */ - strbuf_addf(&desc, _("(HEAD detached at %s)"), - state.detached_from); - else - /* TRANSLATORS: make sure this matches - "HEAD detached from " in wt-status.c */ - strbuf_addf(&desc, _("(HEAD detached from %s)"), - state.detached_from); - } - else - strbuf_addstr(&desc, _("(no branch)")); - free(state.branch); - free(state.onto); - free(state.detached_from); - return strbuf_detach(&desc, NULL); -} - static void format_and_print_ref_item(struct ref_array_item *item, int maxwidth, struct ref_filter *filter, const char *remote_prefix) { -- cgit v1.3 From 17938f171f703c28696c7839a910565f0fb32121 Mon Sep 17 00:00:00 2001 From: Karthik Nayak Date: Tue, 10 Jan 2017 14:19:46 +0530 Subject: ref-filter: rename the 'strip' option to 'lstrip' In preparation for the upcoming patch, where we introduce the 'rstrip' option. Rename the 'strip' option to 'lstrip' to remove ambiguity. Signed-off-by: Karthik Nayak Signed-off-by: Junio C Hamano --- Documentation/git-for-each-ref.txt | 10 +++++----- builtin/tag.c | 4 ++-- ref-filter.c | 20 ++++++++++---------- t/t6300-for-each-ref.sh | 22 +++++++++++----------- 4 files changed, 28 insertions(+), 28 deletions(-) (limited to 'builtin') diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt index b18eabd699..b0d94deea6 100644 --- a/Documentation/git-for-each-ref.txt +++ b/Documentation/git-for-each-ref.txt @@ -95,9 +95,9 @@ refname:: The name of the ref (the part after $GIT_DIR/). For a non-ambiguous short name of the ref append `:short`. The option core.warnAmbiguousRefs is used to select the strict - abbreviation mode. If `strip=` is appended, strips `` + abbreviation mode. If `lstrip=` is appended, strips `` slash-separated path components from the front of the refname - (e.g., `%(refname:strip=2)` turns `refs/tags/foo` into `foo`. + (e.g., `%(refname:lstrip=2)` turns `refs/tags/foo` into `foo`. `` must be a positive integer. If a displayed ref has fewer components than ``, the command aborts with an error. @@ -116,7 +116,7 @@ objectname:: upstream:: The name of a local ref which can be considered ``upstream'' - from the displayed ref. Respects `:short` and `:strip` in the + from the displayed ref. Respects `:short` and `:lstrip` in the same way as `refname` above. Additionally respects `:track` to show "[ahead N, behind M]" and `:trackshort` to show the terse version: ">" (ahead), "<" (behind), "<>" (ahead and @@ -130,7 +130,7 @@ upstream:: push:: The name of a local ref which represents the `@{push}` - location for the displayed ref. Respects `:short`, `:strip`, + location for the displayed ref. Respects `:short`, `:lstrip`, `:track`, and `:trackshort` options as `upstream` does. Produces an empty string if no `@{push}` ref is configured. @@ -174,7 +174,7 @@ if:: symref:: The ref which the given symbolic ref refers to. If not a symbolic ref, nothing is printed. Respects the `:short` and - `:strip` options in the same way as `refname` above. + `:lstrip` options in the same way as `refname` above. In addition to the above, for commit and tag objects, the header field names (`tree`, `parent`, `object`, `type`, and `tag`) can diff --git a/builtin/tag.c b/builtin/tag.c index 73df728114..b4789cec45 100644 --- a/builtin/tag.c +++ b/builtin/tag.c @@ -45,11 +45,11 @@ static int list_tags(struct ref_filter *filter, struct ref_sorting *sorting, con if (!format) { if (filter->lines) { to_free = xstrfmt("%s %%(contents:lines=%d)", - "%(align:15)%(refname:strip=2)%(end)", + "%(align:15)%(refname:lstrip=2)%(end)", filter->lines); format = to_free; } else - format = "%(refname:strip=2)"; + format = "%(refname:lstrip=2)"; } verify_ref_format(format); diff --git a/ref-filter.c b/ref-filter.c index ffa29446cf..cccd86f574 100644 --- a/ref-filter.c +++ b/ref-filter.c @@ -33,8 +33,8 @@ struct if_then_else { }; struct refname_atom { - enum { R_NORMAL, R_SHORT, R_STRIP } option; - unsigned int strip; + enum { R_NORMAL, R_SHORT, R_LSTRIP } option; + unsigned int lstrip; }; /* @@ -91,10 +91,10 @@ static void refname_atom_parser_internal(struct refname_atom *atom, atom->option = R_NORMAL; else if (!strcmp(arg, "short")) atom->option = R_SHORT; - else if (skip_prefix(arg, "strip=", &arg)) { - atom->option = R_STRIP; - if (strtoul_ui(arg, 10, &atom->strip) || atom->strip <= 0) - die(_("positive value expected refname:strip=%s"), arg); + else if (skip_prefix(arg, "lstrip=", &arg)) { + atom->option = R_LSTRIP; + if (strtoul_ui(arg, 10, &atom->lstrip) || atom->lstrip <= 0) + die(_("positive value expected refname:lstrip=%s"), arg); } else die(_("unrecognized %%(%s) argument: %s"), name, arg); } @@ -1091,7 +1091,7 @@ static inline char *copy_advance(char *dst, const char *src) return dst; } -static const char *strip_ref_components(const char *refname, unsigned int len) +static const char *lstrip_ref_components(const char *refname, unsigned int len) { long remaining = len; const char *start = refname; @@ -1099,7 +1099,7 @@ static const char *strip_ref_components(const char *refname, unsigned int len) while (remaining) { switch (*start++) { case '\0': - die(_("ref '%s' does not have %ud components to :strip"), + die(_("ref '%s' does not have %ud components to :lstrip"), refname, len); case '/': remaining--; @@ -1113,8 +1113,8 @@ static const char *show_ref(struct refname_atom *atom, const char *refname) { if (atom->option == R_SHORT) return shorten_unambiguous_ref(refname, warn_ambiguous_refs); - else if (atom->option == R_STRIP) - return strip_ref_components(refname, atom->strip); + else if (atom->option == R_LSTRIP) + return lstrip_ref_components(refname, atom->lstrip); else return refname; } diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh index c538084245..5eb013ca21 100755 --- a/t/t6300-for-each-ref.sh +++ b/t/t6300-for-each-ref.sh @@ -51,14 +51,14 @@ test_atom() { test_atom head refname refs/heads/master test_atom head refname:short master -test_atom head refname:strip=1 heads/master -test_atom head refname:strip=2 master +test_atom head refname:lstrip=1 heads/master +test_atom head refname:lstrip=2 master test_atom head upstream refs/remotes/origin/master test_atom head upstream:short origin/master -test_atom head upstream:strip=2 origin/master +test_atom head upstream:lstrip=2 origin/master test_atom head push refs/remotes/myfork/master test_atom head push:short myfork/master -test_atom head push:strip=1 remotes/myfork/master +test_atom head push:lstrip=1 remotes/myfork/master test_atom head objecttype commit test_atom head objectsize 171 test_atom head objectname $(git rev-parse refs/heads/master) @@ -141,14 +141,14 @@ test_expect_success 'Check invalid atoms names are errors' ' test_must_fail git for-each-ref --format="%(INVALID)" refs/heads ' -test_expect_success 'arguments to :strip must be positive integers' ' - test_must_fail git for-each-ref --format="%(refname:strip=0)" && - test_must_fail git for-each-ref --format="%(refname:strip=-1)" && - test_must_fail git for-each-ref --format="%(refname:strip=foo)" +test_expect_success 'arguments to :lstrip must be positive integers' ' + test_must_fail git for-each-ref --format="%(refname:lstrip=0)" && + test_must_fail git for-each-ref --format="%(refname:lstrip=-1)" && + test_must_fail git for-each-ref --format="%(refname:lstrip=foo)" ' test_expect_success 'stripping refnames too far gives an error' ' - test_must_fail git for-each-ref --format="%(refname:strip=3)" + test_must_fail git for-each-ref --format="%(refname:lstrip=3)" ' test_expect_success 'Check format specifiers are ignored in naming date atoms' ' @@ -630,8 +630,8 @@ cat >expected < actual && +test_expect_success 'Verify usage of %(symref:lstrip) atom' ' + git for-each-ref --format="%(symref:lstrip=2)" refs/heads/sym > actual && test_cmp expected actual ' -- cgit v1.3 From 56b43607f975841e70203e55bba3c0b0228da6b0 Mon Sep 17 00:00:00 2001 From: Karthik Nayak Date: Tue, 10 Jan 2017 14:19:51 +0530 Subject: branch, tag: use porcelain output Call ref-filter's setup_ref_filter_porcelain_msg() to enable translated messages for the %(upstream:tack) atom. Although branch.c doesn't currently use ref-filter's printing API's, this will ensure that when it does in the future patches, we do not need to worry about translation. Written-by: Matthieu Moy Mentored-by: Christian Couder Mentored-by: Matthieu Moy Signed-off-by: Karthik Nayak Signed-off-by: Junio C Hamano --- builtin/branch.c | 2 ++ builtin/tag.c | 2 ++ 2 files changed, 4 insertions(+) (limited to 'builtin') diff --git a/builtin/branch.c b/builtin/branch.c index 6423ebce5d..34cd61cd90 100644 --- a/builtin/branch.c +++ b/builtin/branch.c @@ -649,6 +649,8 @@ int cmd_branch(int argc, const char **argv, const char *prefix) OPT_END(), }; + setup_ref_filter_porcelain_msg(); + memset(&filter, 0, sizeof(filter)); filter.kind = FILTER_REFS_BRANCHES; filter.abbrev = -1; diff --git a/builtin/tag.c b/builtin/tag.c index b4789cec45..8a1a476db7 100644 --- a/builtin/tag.c +++ b/builtin/tag.c @@ -375,6 +375,8 @@ int cmd_tag(int argc, const char **argv, const char *prefix) OPT_END() }; + setup_ref_filter_porcelain_msg(); + git_config(git_tag_config, sorting_tail); memset(&opt, 0, sizeof(opt)); -- cgit v1.3 From 949af0684c1f84587504e2143fca6f9bb8504e31 Mon Sep 17 00:00:00 2001 From: Karthik Nayak Date: Tue, 10 Jan 2017 14:19:52 +0530 Subject: branch: use ref-filter printing APIs Port branch.c to use ref-filter APIs for printing. This clears out most of the code used in branch.c for printing and replaces them with calls made to the ref-filter library. Introduce build_format() which gets the format required for printing of refs. Make amendments to print_ref_list() to reflect these changes. The strings included in build_format() may not be safely quoted for inclusion (i.e. it might contain '%' which needs to be escaped with an additional '%'). Introduce quote_literal_for_format() as a helper function which takes a string and returns a version of the string that is safely quoted to be used in the for-each-ref format which is built in build_format(). Change calc_maxwidth() to also account for the length of HEAD ref, by calling ref-filter:get_head_discription(). Also change the test in t6040 to reflect the changes. Before this patch, all cross-prefix symrefs weren't shortened. Since we're using ref-filter APIs, we shorten all symrefs by default. We also allow the user to change the format if needed with the introduction of the '--format' option in the next patch. Mentored-by: Christian Couder Mentored-by: Matthieu Moy Helped-by: Junio C Hamano Helped-by: Jeff King Helped-by: Ramsay Jones Signed-off-by: Karthik Nayak Signed-off-by: Junio C Hamano --- builtin/branch.c | 247 ++++++++++++++++------------------------------- t/t3203-branch-output.sh | 2 +- t/t6040-tracking-info.sh | 2 +- 3 files changed, 87 insertions(+), 164 deletions(-) (limited to 'builtin') diff --git a/builtin/branch.c b/builtin/branch.c index 34cd61cd90..f293ee5b0f 100644 --- a/builtin/branch.c +++ b/builtin/branch.c @@ -37,11 +37,11 @@ static unsigned char head_sha1[20]; static int branch_use_color = -1; static char branch_colors[][COLOR_MAXLEN] = { GIT_COLOR_RESET, - GIT_COLOR_NORMAL, /* PLAIN */ - GIT_COLOR_RED, /* REMOTE */ - GIT_COLOR_NORMAL, /* LOCAL */ - GIT_COLOR_GREEN, /* CURRENT */ - GIT_COLOR_BLUE, /* UPSTREAM */ + GIT_COLOR_NORMAL, /* PLAIN */ + GIT_COLOR_RED, /* REMOTE */ + GIT_COLOR_NORMAL, /* LOCAL */ + GIT_COLOR_GREEN, /* CURRENT */ + GIT_COLOR_BLUE, /* UPSTREAM */ }; enum color_branch { BRANCH_COLOR_RESET = 0, @@ -280,180 +280,88 @@ static int delete_branches(int argc, const char **argv, int force, int kinds, return(ret); } -static void fill_tracking_info(struct strbuf *stat, const char *branch_name, - int show_upstream_ref) +static int calc_maxwidth(struct ref_array *refs, int remote_bonus) { - int ours, theirs; - char *ref = NULL; - struct branch *branch = branch_get(branch_name); - const char *upstream; - struct strbuf fancy = STRBUF_INIT; - int upstream_is_gone = 0; - int added_decoration = 1; - - if (stat_tracking_info(branch, &ours, &theirs, &upstream) < 0) { - if (!upstream) - return; - upstream_is_gone = 1; - } - - if (show_upstream_ref) { - ref = shorten_unambiguous_ref(upstream, 0); - if (want_color(branch_use_color)) - strbuf_addf(&fancy, "%s%s%s", - branch_get_color(BRANCH_COLOR_UPSTREAM), - ref, branch_get_color(BRANCH_COLOR_RESET)); - else - strbuf_addstr(&fancy, ref); - } + 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 (upstream_is_gone) { - if (show_upstream_ref) - strbuf_addf(stat, _("[%s: gone]"), fancy.buf); - else - added_decoration = 0; - } else if (!ours && !theirs) { - if (show_upstream_ref) - strbuf_addf(stat, _("[%s]"), fancy.buf); - else - added_decoration = 0; - } else if (!ours) { - if (show_upstream_ref) - strbuf_addf(stat, _("[%s: behind %d]"), fancy.buf, theirs); - else - strbuf_addf(stat, _("[behind %d]"), theirs); + skip_prefix(it->refname, "refs/heads/", &desc); + skip_prefix(it->refname, "refs/remotes/", &desc); + if (it->kind == FILTER_REFS_DETACHED_HEAD) { + char *head_desc = get_head_description(); + w = utf8_strwidth(head_desc); + free(head_desc); + } else + w = utf8_strwidth(desc); - } else if (!theirs) { - if (show_upstream_ref) - strbuf_addf(stat, _("[%s: ahead %d]"), fancy.buf, ours); - else - strbuf_addf(stat, _("[ahead %d]"), ours); - } else { - if (show_upstream_ref) - strbuf_addf(stat, _("[%s: ahead %d, behind %d]"), - fancy.buf, ours, theirs); - else - strbuf_addf(stat, _("[ahead %d, behind %d]"), - ours, theirs); + if (it->kind == FILTER_REFS_REMOTES) + w += remote_bonus; + if (w > max) + max = w; } - strbuf_release(&fancy); - if (added_decoration) - strbuf_addch(stat, ' '); - free(ref); + return max; } -static void add_verbose_info(struct strbuf *out, struct ref_array_item *item, - struct ref_filter *filter, const char *refname) +static const char *quote_literal_for_format(const char *s) { - struct strbuf subject = STRBUF_INIT, stat = STRBUF_INIT; - const char *sub = _(" **** invalid ref ****"); - struct commit *commit = item->commit; + static struct strbuf buf = STRBUF_INIT; - if (!parse_commit(commit)) { - pp_commit_easy(CMIT_FMT_ONELINE, commit, &subject); - sub = subject.buf; + strbuf_reset(&buf); + while (*s) { + const char *ep = strchrnul(s, '%'); + if (s < ep) + strbuf_add(&buf, s, ep - s); + if (*ep == '%') { + strbuf_addstr(&buf, "%%"); + s = ep + 1; + } else { + s = ep; + } } - - if (item->kind == FILTER_REFS_BRANCHES) - fill_tracking_info(&stat, refname, filter->verbose > 1); - - strbuf_addf(out, " %s %s%s", - find_unique_abbrev(item->commit->object.oid.hash, filter->abbrev), - stat.buf, sub); - strbuf_release(&stat); - strbuf_release(&subject); + return buf.buf; } -static void format_and_print_ref_item(struct ref_array_item *item, int maxwidth, - struct ref_filter *filter, const char *remote_prefix) +static char *build_format(struct ref_filter *filter, int maxwidth, const char *remote_prefix) { - char c; - int current = 0; - int color; - struct strbuf out = STRBUF_INIT, name = STRBUF_INIT; - const char *prefix_to_show = ""; - const char *prefix_to_skip = NULL; - const char *desc = item->refname; - char *to_free = NULL; - - switch (item->kind) { - case FILTER_REFS_BRANCHES: - prefix_to_skip = "refs/heads/"; - skip_prefix(desc, prefix_to_skip, &desc); - if (!filter->detached && !strcmp(desc, head)) - current = 1; - else - color = BRANCH_COLOR_LOCAL; - break; - case FILTER_REFS_REMOTES: - prefix_to_skip = "refs/remotes/"; - skip_prefix(desc, prefix_to_skip, &desc); - color = BRANCH_COLOR_REMOTE; - prefix_to_show = remote_prefix; - break; - case FILTER_REFS_DETACHED_HEAD: - desc = to_free = get_head_description(); - current = 1; - break; - default: - color = BRANCH_COLOR_PLAIN; - break; - } + struct strbuf fmt = STRBUF_INIT; + struct strbuf local = STRBUF_INIT; + struct strbuf remote = STRBUF_INIT; - c = ' '; - if (current) { - c = '*'; - color = BRANCH_COLOR_CURRENT; - } + strbuf_addf(&fmt, "%%(if)%%(HEAD)%%(then)* %s%%(else) %%(end)", + branch_get_color(BRANCH_COLOR_CURRENT)); - strbuf_addf(&name, "%s%s", prefix_to_show, desc); if (filter->verbose) { - int utf8_compensation = strlen(name.buf) - utf8_strwidth(name.buf); - strbuf_addf(&out, "%c %s%-*s%s", c, branch_get_color(color), - maxwidth + utf8_compensation, name.buf, + strbuf_addf(&local, "%%(align:%d,left)%%(refname:lstrip=2)%%(end)", maxwidth); + strbuf_addf(&local, "%s", branch_get_color(BRANCH_COLOR_RESET)); + strbuf_addf(&local, " %%(objectname:short=7) "); + + if (filter->verbose > 1) + strbuf_addf(&local, "%%(if)%%(upstream)%%(then)[%s%%(upstream:short)%s%%(if)%%(upstream:track)" + "%%(then): %%(upstream:track,nobracket)%%(end)] %%(end)%%(contents:subject)", + branch_get_color(BRANCH_COLOR_UPSTREAM), branch_get_color(BRANCH_COLOR_RESET)); + else + strbuf_addf(&local, "%%(if)%%(upstream:track)%%(then)%%(upstream:track) %%(end)%%(contents:subject)"); + + strbuf_addf(&remote, "%s%%(align:%d,left)%s%%(refname:lstrip=2)%%(end)%s%%(if)%%(symref)%%(then) -> %%(symref:short)" + "%%(else) %%(objectname:short=7) %%(contents:subject)%%(end)", + branch_get_color(BRANCH_COLOR_REMOTE), maxwidth, quote_literal_for_format(remote_prefix), branch_get_color(BRANCH_COLOR_RESET)); - } else - strbuf_addf(&out, "%c %s%s%s", c, branch_get_color(color), - name.buf, branch_get_color(BRANCH_COLOR_RESET)); - - if (item->symref) { - const char *symref = item->symref; - if (prefix_to_skip) - skip_prefix(symref, prefix_to_skip, &symref); - strbuf_addf(&out, " -> %s", symref); - } - else if (filter->verbose) - /* " f7c0c00 [ahead 58, behind 197] vcs-svn: drop obj_pool.h" */ - 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); } else { - printf("%s\n", out.buf); + strbuf_addf(&local, "%%(refname:lstrip=2)%s%%(if)%%(symref)%%(then) -> %%(symref:short)%%(end)", + branch_get_color(BRANCH_COLOR_RESET)); + strbuf_addf(&remote, "%s%s%%(refname:lstrip=2)%s%%(if)%%(symref)%%(then) -> %%(symref:short)%%(end)", + branch_get_color(BRANCH_COLOR_REMOTE), quote_literal_for_format(remote_prefix), + branch_get_color(BRANCH_COLOR_RESET)); } - strbuf_release(&name); - strbuf_release(&out); - free(to_free); -} - -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; - skip_prefix(it->refname, "refs/heads/", &desc); - skip_prefix(it->refname, "refs/remotes/", &desc); - w = utf8_strwidth(desc); + strbuf_addf(&fmt, "%%(if:notequals=refs/remotes)%%(refname:rstrip=-2)%%(then)%s%%(else)%s%%(end)", local.buf, remote.buf); - if (it->kind == FILTER_REFS_REMOTES) - w += remote_bonus; - if (w > max) - max = w; - } - return max; + strbuf_release(&local); + strbuf_release(&remote); + return strbuf_detach(&fmt, NULL); } static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sorting) @@ -462,6 +370,8 @@ static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sortin struct ref_array array; int maxwidth = 0; const char *remote_prefix = ""; + struct strbuf out = STRBUF_INIT; + char *format; /* * If we are listing more than just remote branches, @@ -473,18 +383,31 @@ static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sortin memset(&array, 0, sizeof(array)); - 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)); + format = build_format(filter, maxwidth, remote_prefix); + verify_ref_format(format); + ref_array_sort(sorting, &array); - for (i = 0; i < array.nr; i++) - format_and_print_ref_item(array.items[i], maxwidth, filter, remote_prefix); + for (i = 0; i < array.nr; i++) { + format_ref_array_item(array.items[i], format, 0, &out); + if (column_active(colopts)) { + assert(!filter->verbose && "--column and --verbose are incompatible"); + /* format to a string_list to let print_columns() do its job */ + string_list_append(&output, out.buf); + } else { + fwrite(out.buf, 1, out.len, stdout); + putchar('\n'); + } + strbuf_release(&out); + } ref_array_clear(&array); + free(format); } static void reject_rebase_or_bisect_branch(const char *target) diff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh index 52283dfc8c..45213280a1 100755 --- a/t/t3203-branch-output.sh +++ b/t/t3203-branch-output.sh @@ -194,7 +194,7 @@ test_expect_success 'local-branch symrefs shortened properly' ' git symbolic-ref refs/heads/ref-to-remote refs/remotes/origin/branch-one && cat >expect <<-\EOF && ref-to-branch -> branch-one - ref-to-remote -> refs/remotes/origin/branch-one + ref-to-remote -> origin/branch-one EOF git branch >actual.raw && grep ref-to actual && diff --git a/t/t6040-tracking-info.sh b/t/t6040-tracking-info.sh index 3d5c238c81..97a07655a0 100755 --- a/t/t6040-tracking-info.sh +++ b/t/t6040-tracking-info.sh @@ -44,7 +44,7 @@ b1 [ahead 1, behind 1] d b2 [ahead 1, behind 1] d b3 [behind 1] b b4 [ahead 2] f -b5 g +b5 [gone] g b6 c EOF -- cgit v1.3 From 3d9e4ce3ebef4f5aa47dad49f730e085f32b98da Mon Sep 17 00:00:00 2001 From: Karthik Nayak Date: Tue, 10 Jan 2017 14:19:53 +0530 Subject: branch: implement '--format' option Implement the '--format' option provided by 'ref-filter'. This lets the user list branches as per desired format similar to the implementation in 'git for-each-ref'. Add tests and documentation for the same. Mentored-by: Christian Couder Mentored-by: Matthieu Moy Signed-off-by: Karthik Nayak Signed-off-by: Junio C Hamano --- Documentation/git-branch.txt | 7 ++++++- builtin/branch.c | 14 +++++++++----- t/t3203-branch-output.sh | 14 ++++++++++++++ 3 files changed, 29 insertions(+), 6 deletions(-) (limited to 'builtin') diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt index 5516a47b54..1fae4eeee3 100644 --- a/Documentation/git-branch.txt +++ b/Documentation/git-branch.txt @@ -12,7 +12,7 @@ SYNOPSIS [--list] [-v [--abbrev= | --no-abbrev]] [--column[=] | --no-column] [(--merged | --no-merged | --contains) []] [--sort=] - [--points-at ] [...] + [--points-at ] [--format=] [...] 'git branch' [--set-upstream | --track | --no-track] [-l] [-f] [] 'git branch' (--set-upstream-to= | -u ) [] 'git branch' --unset-upstream [] @@ -250,6 +250,11 @@ start-point is either a local or remote-tracking branch. --points-at :: Only list branches of the given object. +--format :: + A string that interpolates `%(fieldname)` from the object + pointed at by a ref being shown. The format is the same as + that of linkgit:git-for-each-ref[1]. + Examples -------- diff --git a/builtin/branch.c b/builtin/branch.c index f293ee5b0f..cbaa6d03c0 100644 --- a/builtin/branch.c +++ b/builtin/branch.c @@ -28,6 +28,7 @@ static const char * const builtin_branch_usage[] = { N_("git branch [] [-r] (-d | -D) ..."), N_("git branch [] (-m | -M) [] "), N_("git branch [] [-r | -a] [--points-at]"), + N_("git branch [] [-r | -a] [--format]"), NULL }; @@ -364,14 +365,14 @@ static char *build_format(struct ref_filter *filter, int maxwidth, const char *r return strbuf_detach(&fmt, NULL); } -static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sorting) +static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sorting, const char *format) { int i; struct ref_array array; int maxwidth = 0; const char *remote_prefix = ""; struct strbuf out = STRBUF_INIT; - char *format; + char *to_free = NULL; /* * If we are listing more than just remote branches, @@ -388,7 +389,8 @@ static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sortin if (filter->verbose) maxwidth = calc_maxwidth(&array, strlen(remote_prefix)); - format = build_format(filter, maxwidth, remote_prefix); + if (!format) + format = to_free = build_format(filter, maxwidth, remote_prefix); verify_ref_format(format); ref_array_sort(sorting, &array); @@ -407,7 +409,7 @@ static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sortin } ref_array_clear(&array); - free(format); + free(to_free); } static void reject_rebase_or_bisect_branch(const char *target) @@ -528,6 +530,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix) struct ref_filter filter; int icase = 0; static struct ref_sorting *sorting = NULL, **sorting_tail = &sorting; + const char *format = NULL; struct option options[] = { OPT_GROUP(N_("Generic options")), @@ -569,6 +572,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix) N_("print only branches of the object"), 0, parse_opt_object_name }, OPT_BOOL('i', "ignore-case", &icase, N_("sorting and filtering are case insensitive")), + OPT_STRING( 0 , "format", &format, N_("format"), N_("format to use for the output")), OPT_END(), }; @@ -641,7 +645,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix) if (!sorting) sorting = ref_default_sorting(); sorting->ignore_case = icase; - print_ref_list(&filter, sorting); + print_ref_list(&filter, sorting, format); print_columns(&output, colopts, NULL); string_list_clear(&output, 0); return 0; diff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh index 45213280a1..5778c0afe1 100755 --- a/t/t3203-branch-output.sh +++ b/t/t3203-branch-output.sh @@ -225,4 +225,18 @@ test_expect_success 'sort branches, ignore case' ' ) ' +test_expect_success 'git branch --format option' ' + cat >expect <<-\EOF && + Refname is (HEAD detached from fromtag) + Refname is refs/heads/ambiguous + Refname is refs/heads/branch-one + Refname is refs/heads/branch-two + Refname is refs/heads/master + Refname is refs/heads/ref-to-branch + Refname is refs/heads/ref-to-remote + EOF + git branch --format="Refname is %(refname)" >actual && + test_cmp expect actual +' + test_done -- cgit v1.3