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 <christian.couder@gmail.com> Mentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr> Helped-by: Junio C Hamano <gitster@pobox.com> Helped-by: Jeff King <peff@peff.net> Helped-by: Ramsay Jones <ramsay@ramsayjones.plus.com> Signed-off-by: Karthik Nayak <karthik.188@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
parent
56b43607f9
commit
949af0684c
253
builtin/branch.c
253
builtin/branch.c
@ -37,11 +37,11 @@ static unsigned char head_sha1[20];
|
|||||||
static int branch_use_color = -1;
|
static int branch_use_color = -1;
|
||||||
static char branch_colors[][COLOR_MAXLEN] = {
|
static char branch_colors[][COLOR_MAXLEN] = {
|
||||||
GIT_COLOR_RESET,
|
GIT_COLOR_RESET,
|
||||||
GIT_COLOR_NORMAL, /* PLAIN */
|
GIT_COLOR_NORMAL, /* PLAIN */
|
||||||
GIT_COLOR_RED, /* REMOTE */
|
GIT_COLOR_RED, /* REMOTE */
|
||||||
GIT_COLOR_NORMAL, /* LOCAL */
|
GIT_COLOR_NORMAL, /* LOCAL */
|
||||||
GIT_COLOR_GREEN, /* CURRENT */
|
GIT_COLOR_GREEN, /* CURRENT */
|
||||||
GIT_COLOR_BLUE, /* UPSTREAM */
|
GIT_COLOR_BLUE, /* UPSTREAM */
|
||||||
};
|
};
|
||||||
enum color_branch {
|
enum color_branch {
|
||||||
BRANCH_COLOR_RESET = 0,
|
BRANCH_COLOR_RESET = 0,
|
||||||
@ -280,162 +280,6 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
|
|||||||
return(ret);
|
return(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fill_tracking_info(struct strbuf *stat, const char *branch_name,
|
|
||||||
int show_upstream_ref)
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
} 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);
|
|
||||||
}
|
|
||||||
strbuf_release(&fancy);
|
|
||||||
if (added_decoration)
|
|
||||||
strbuf_addch(stat, ' ');
|
|
||||||
free(ref);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void add_verbose_info(struct strbuf *out, struct ref_array_item *item,
|
|
||||||
struct ref_filter *filter, const char *refname)
|
|
||||||
{
|
|
||||||
struct strbuf subject = STRBUF_INIT, stat = STRBUF_INIT;
|
|
||||||
const char *sub = _(" **** invalid ref ****");
|
|
||||||
struct commit *commit = item->commit;
|
|
||||||
|
|
||||||
if (!parse_commit(commit)) {
|
|
||||||
pp_commit_easy(CMIT_FMT_ONELINE, commit, &subject);
|
|
||||||
sub = subject.buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
c = ' ';
|
|
||||||
if (current) {
|
|
||||||
c = '*';
|
|
||||||
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,
|
|
||||||
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_release(&name);
|
|
||||||
strbuf_release(&out);
|
|
||||||
free(to_free);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int calc_maxwidth(struct ref_array *refs, int remote_bonus)
|
static int calc_maxwidth(struct ref_array *refs, int remote_bonus)
|
||||||
{
|
{
|
||||||
int i, max = 0;
|
int i, max = 0;
|
||||||
@ -446,7 +290,12 @@ static int calc_maxwidth(struct ref_array *refs, int remote_bonus)
|
|||||||
|
|
||||||
skip_prefix(it->refname, "refs/heads/", &desc);
|
skip_prefix(it->refname, "refs/heads/", &desc);
|
||||||
skip_prefix(it->refname, "refs/remotes/", &desc);
|
skip_prefix(it->refname, "refs/remotes/", &desc);
|
||||||
w = utf8_strwidth(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);
|
||||||
|
|
||||||
if (it->kind == FILTER_REFS_REMOTES)
|
if (it->kind == FILTER_REFS_REMOTES)
|
||||||
w += remote_bonus;
|
w += remote_bonus;
|
||||||
@ -456,12 +305,73 @@ static int calc_maxwidth(struct ref_array *refs, int remote_bonus)
|
|||||||
return max;
|
return max;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char *quote_literal_for_format(const char *s)
|
||||||
|
{
|
||||||
|
static struct strbuf buf = STRBUF_INIT;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return buf.buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *build_format(struct ref_filter *filter, int maxwidth, const char *remote_prefix)
|
||||||
|
{
|
||||||
|
struct strbuf fmt = STRBUF_INIT;
|
||||||
|
struct strbuf local = STRBUF_INIT;
|
||||||
|
struct strbuf remote = STRBUF_INIT;
|
||||||
|
|
||||||
|
strbuf_addf(&fmt, "%%(if)%%(HEAD)%%(then)* %s%%(else) %%(end)",
|
||||||
|
branch_get_color(BRANCH_COLOR_CURRENT));
|
||||||
|
|
||||||
|
if (filter->verbose) {
|
||||||
|
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(&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_addf(&fmt, "%%(if:notequals=refs/remotes)%%(refname:rstrip=-2)%%(then)%s%%(else)%s%%(end)", local.buf, remote.buf);
|
||||||
|
|
||||||
|
strbuf_release(&local);
|
||||||
|
strbuf_release(&remote);
|
||||||
|
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)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
struct ref_array array;
|
struct ref_array array;
|
||||||
int maxwidth = 0;
|
int maxwidth = 0;
|
||||||
const char *remote_prefix = "";
|
const char *remote_prefix = "";
|
||||||
|
struct strbuf out = STRBUF_INIT;
|
||||||
|
char *format;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we are listing more than just remote branches,
|
* 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));
|
memset(&array, 0, sizeof(array));
|
||||||
|
|
||||||
verify_ref_format("%(refname)%(symref)");
|
|
||||||
filter_refs(&array, filter, filter->kind | FILTER_REFS_INCLUDE_BROKEN);
|
filter_refs(&array, filter, filter->kind | FILTER_REFS_INCLUDE_BROKEN);
|
||||||
|
|
||||||
if (filter->verbose)
|
if (filter->verbose)
|
||||||
maxwidth = calc_maxwidth(&array, strlen(remote_prefix));
|
maxwidth = calc_maxwidth(&array, strlen(remote_prefix));
|
||||||
|
|
||||||
|
format = build_format(filter, maxwidth, remote_prefix);
|
||||||
|
verify_ref_format(format);
|
||||||
|
|
||||||
ref_array_sort(sorting, &array);
|
ref_array_sort(sorting, &array);
|
||||||
|
|
||||||
for (i = 0; i < array.nr; i++)
|
for (i = 0; i < array.nr; i++) {
|
||||||
format_and_print_ref_item(array.items[i], maxwidth, filter, remote_prefix);
|
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);
|
ref_array_clear(&array);
|
||||||
|
free(format);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void reject_rebase_or_bisect_branch(const char *target)
|
static void reject_rebase_or_bisect_branch(const char *target)
|
||||||
|
@ -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 &&
|
git symbolic-ref refs/heads/ref-to-remote refs/remotes/origin/branch-one &&
|
||||||
cat >expect <<-\EOF &&
|
cat >expect <<-\EOF &&
|
||||||
ref-to-branch -> branch-one
|
ref-to-branch -> branch-one
|
||||||
ref-to-remote -> refs/remotes/origin/branch-one
|
ref-to-remote -> origin/branch-one
|
||||||
EOF
|
EOF
|
||||||
git branch >actual.raw &&
|
git branch >actual.raw &&
|
||||||
grep ref-to <actual.raw >actual &&
|
grep ref-to <actual.raw >actual &&
|
||||||
|
@ -44,7 +44,7 @@ b1 [ahead 1, behind 1] d
|
|||||||
b2 [ahead 1, behind 1] d
|
b2 [ahead 1, behind 1] d
|
||||||
b3 [behind 1] b
|
b3 [behind 1] b
|
||||||
b4 [ahead 2] f
|
b4 [ahead 2] f
|
||||||
b5 g
|
b5 [gone] g
|
||||||
b6 c
|
b6 c
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user