Skip to content

Commit 949af06

Browse files
KarthikNayakgitster
authored andcommitted
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 <[email protected]> Mentored-by: Matthieu Moy <[email protected]> Helped-by: Junio C Hamano <[email protected]> Helped-by: Jeff King <[email protected]> Helped-by: Ramsay Jones <[email protected]> Signed-off-by: Karthik Nayak <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 56b4360 commit 949af06

File tree

3 files changed

+87
-164
lines changed

3 files changed

+87
-164
lines changed

builtin/branch.c

Lines changed: 85 additions & 162 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,11 @@ static unsigned char head_sha1[20];
3737
static int branch_use_color = -1;
3838
static char branch_colors[][COLOR_MAXLEN] = {
3939
GIT_COLOR_RESET,
40-
GIT_COLOR_NORMAL, /* PLAIN */
41-
GIT_COLOR_RED, /* REMOTE */
42-
GIT_COLOR_NORMAL, /* LOCAL */
43-
GIT_COLOR_GREEN, /* CURRENT */
44-
GIT_COLOR_BLUE, /* UPSTREAM */
40+
GIT_COLOR_NORMAL, /* PLAIN */
41+
GIT_COLOR_RED, /* REMOTE */
42+
GIT_COLOR_NORMAL, /* LOCAL */
43+
GIT_COLOR_GREEN, /* CURRENT */
44+
GIT_COLOR_BLUE, /* UPSTREAM */
4545
};
4646
enum color_branch {
4747
BRANCH_COLOR_RESET = 0,
@@ -280,180 +280,88 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
280280
return(ret);
281281
}
282282

283-
static void fill_tracking_info(struct strbuf *stat, const char *branch_name,
284-
int show_upstream_ref)
283+
static int calc_maxwidth(struct ref_array *refs, int remote_bonus)
285284
{
286-
int ours, theirs;
287-
char *ref = NULL;
288-
struct branch *branch = branch_get(branch_name);
289-
const char *upstream;
290-
struct strbuf fancy = STRBUF_INIT;
291-
int upstream_is_gone = 0;
292-
int added_decoration = 1;
293-
294-
if (stat_tracking_info(branch, &ours, &theirs, &upstream) < 0) {
295-
if (!upstream)
296-
return;
297-
upstream_is_gone = 1;
298-
}
299-
300-
if (show_upstream_ref) {
301-
ref = shorten_unambiguous_ref(upstream, 0);
302-
if (want_color(branch_use_color))
303-
strbuf_addf(&fancy, "%s%s%s",
304-
branch_get_color(BRANCH_COLOR_UPSTREAM),
305-
ref, branch_get_color(BRANCH_COLOR_RESET));
306-
else
307-
strbuf_addstr(&fancy, ref);
308-
}
285+
int i, max = 0;
286+
for (i = 0; i < refs->nr; i++) {
287+
struct ref_array_item *it = refs->items[i];
288+
const char *desc = it->refname;
289+
int w;
309290

310-
if (upstream_is_gone) {
311-
if (show_upstream_ref)
312-
strbuf_addf(stat, _("[%s: gone]"), fancy.buf);
313-
else
314-
added_decoration = 0;
315-
} else if (!ours && !theirs) {
316-
if (show_upstream_ref)
317-
strbuf_addf(stat, _("[%s]"), fancy.buf);
318-
else
319-
added_decoration = 0;
320-
} else if (!ours) {
321-
if (show_upstream_ref)
322-
strbuf_addf(stat, _("[%s: behind %d]"), fancy.buf, theirs);
323-
else
324-
strbuf_addf(stat, _("[behind %d]"), theirs);
291+
skip_prefix(it->refname, "refs/heads/", &desc);
292+
skip_prefix(it->refname, "refs/remotes/", &desc);
293+
if (it->kind == FILTER_REFS_DETACHED_HEAD) {
294+
char *head_desc = get_head_description();
295+
w = utf8_strwidth(head_desc);
296+
free(head_desc);
297+
} else
298+
w = utf8_strwidth(desc);
325299

326-
} else if (!theirs) {
327-
if (show_upstream_ref)
328-
strbuf_addf(stat, _("[%s: ahead %d]"), fancy.buf, ours);
329-
else
330-
strbuf_addf(stat, _("[ahead %d]"), ours);
331-
} else {
332-
if (show_upstream_ref)
333-
strbuf_addf(stat, _("[%s: ahead %d, behind %d]"),
334-
fancy.buf, ours, theirs);
335-
else
336-
strbuf_addf(stat, _("[ahead %d, behind %d]"),
337-
ours, theirs);
300+
if (it->kind == FILTER_REFS_REMOTES)
301+
w += remote_bonus;
302+
if (w > max)
303+
max = w;
338304
}
339-
strbuf_release(&fancy);
340-
if (added_decoration)
341-
strbuf_addch(stat, ' ');
342-
free(ref);
305+
return max;
343306
}
344307

345-
static void add_verbose_info(struct strbuf *out, struct ref_array_item *item,
346-
struct ref_filter *filter, const char *refname)
308+
static const char *quote_literal_for_format(const char *s)
347309
{
348-
struct strbuf subject = STRBUF_INIT, stat = STRBUF_INIT;
349-
const char *sub = _(" **** invalid ref ****");
350-
struct commit *commit = item->commit;
310+
static struct strbuf buf = STRBUF_INIT;
351311

352-
if (!parse_commit(commit)) {
353-
pp_commit_easy(CMIT_FMT_ONELINE, commit, &subject);
354-
sub = subject.buf;
312+
strbuf_reset(&buf);
313+
while (*s) {
314+
const char *ep = strchrnul(s, '%');
315+
if (s < ep)
316+
strbuf_add(&buf, s, ep - s);
317+
if (*ep == '%') {
318+
strbuf_addstr(&buf, "%%");
319+
s = ep + 1;
320+
} else {
321+
s = ep;
322+
}
355323
}
356-
357-
if (item->kind == FILTER_REFS_BRANCHES)
358-
fill_tracking_info(&stat, refname, filter->verbose > 1);
359-
360-
strbuf_addf(out, " %s %s%s",
361-
find_unique_abbrev(item->commit->object.oid.hash, filter->abbrev),
362-
stat.buf, sub);
363-
strbuf_release(&stat);
364-
strbuf_release(&subject);
324+
return buf.buf;
365325
}
366326

367-
static void format_and_print_ref_item(struct ref_array_item *item, int maxwidth,
368-
struct ref_filter *filter, const char *remote_prefix)
327+
static char *build_format(struct ref_filter *filter, int maxwidth, const char *remote_prefix)
369328
{
370-
char c;
371-
int current = 0;
372-
int color;
373-
struct strbuf out = STRBUF_INIT, name = STRBUF_INIT;
374-
const char *prefix_to_show = "";
375-
const char *prefix_to_skip = NULL;
376-
const char *desc = item->refname;
377-
char *to_free = NULL;
378-
379-
switch (item->kind) {
380-
case FILTER_REFS_BRANCHES:
381-
prefix_to_skip = "refs/heads/";
382-
skip_prefix(desc, prefix_to_skip, &desc);
383-
if (!filter->detached && !strcmp(desc, head))
384-
current = 1;
385-
else
386-
color = BRANCH_COLOR_LOCAL;
387-
break;
388-
case FILTER_REFS_REMOTES:
389-
prefix_to_skip = "refs/remotes/";
390-
skip_prefix(desc, prefix_to_skip, &desc);
391-
color = BRANCH_COLOR_REMOTE;
392-
prefix_to_show = remote_prefix;
393-
break;
394-
case FILTER_REFS_DETACHED_HEAD:
395-
desc = to_free = get_head_description();
396-
current = 1;
397-
break;
398-
default:
399-
color = BRANCH_COLOR_PLAIN;
400-
break;
401-
}
329+
struct strbuf fmt = STRBUF_INIT;
330+
struct strbuf local = STRBUF_INIT;
331+
struct strbuf remote = STRBUF_INIT;
402332

403-
c = ' ';
404-
if (current) {
405-
c = '*';
406-
color = BRANCH_COLOR_CURRENT;
407-
}
333+
strbuf_addf(&fmt, "%%(if)%%(HEAD)%%(then)* %s%%(else) %%(end)",
334+
branch_get_color(BRANCH_COLOR_CURRENT));
408335

409-
strbuf_addf(&name, "%s%s", prefix_to_show, desc);
410336
if (filter->verbose) {
411-
int utf8_compensation = strlen(name.buf) - utf8_strwidth(name.buf);
412-
strbuf_addf(&out, "%c %s%-*s%s", c, branch_get_color(color),
413-
maxwidth + utf8_compensation, name.buf,
337+
strbuf_addf(&local, "%%(align:%d,left)%%(refname:lstrip=2)%%(end)", maxwidth);
338+
strbuf_addf(&local, "%s", branch_get_color(BRANCH_COLOR_RESET));
339+
strbuf_addf(&local, " %%(objectname:short=7) ");
340+
341+
if (filter->verbose > 1)
342+
strbuf_addf(&local, "%%(if)%%(upstream)%%(then)[%s%%(upstream:short)%s%%(if)%%(upstream:track)"
343+
"%%(then): %%(upstream:track,nobracket)%%(end)] %%(end)%%(contents:subject)",
344+
branch_get_color(BRANCH_COLOR_UPSTREAM), branch_get_color(BRANCH_COLOR_RESET));
345+
else
346+
strbuf_addf(&local, "%%(if)%%(upstream:track)%%(then)%%(upstream:track) %%(end)%%(contents:subject)");
347+
348+
strbuf_addf(&remote, "%s%%(align:%d,left)%s%%(refname:lstrip=2)%%(end)%s%%(if)%%(symref)%%(then) -> %%(symref:short)"
349+
"%%(else) %%(objectname:short=7) %%(contents:subject)%%(end)",
350+
branch_get_color(BRANCH_COLOR_REMOTE), maxwidth, quote_literal_for_format(remote_prefix),
414351
branch_get_color(BRANCH_COLOR_RESET));
415-
} else
416-
strbuf_addf(&out, "%c %s%s%s", c, branch_get_color(color),
417-
name.buf, branch_get_color(BRANCH_COLOR_RESET));
418-
419-
if (item->symref) {
420-
const char *symref = item->symref;
421-
if (prefix_to_skip)
422-
skip_prefix(symref, prefix_to_skip, &symref);
423-
strbuf_addf(&out, " -> %s", symref);
424-
}
425-
else if (filter->verbose)
426-
/* " f7c0c00 [ahead 58, behind 197] vcs-svn: drop obj_pool.h" */
427-
add_verbose_info(&out, item, filter, desc);
428-
if (column_active(colopts)) {
429-
assert(!filter->verbose && "--column and --verbose are incompatible");
430-
string_list_append(&output, out.buf);
431352
} else {
432-
printf("%s\n", out.buf);
353+
strbuf_addf(&local, "%%(refname:lstrip=2)%s%%(if)%%(symref)%%(then) -> %%(symref:short)%%(end)",
354+
branch_get_color(BRANCH_COLOR_RESET));
355+
strbuf_addf(&remote, "%s%s%%(refname:lstrip=2)%s%%(if)%%(symref)%%(then) -> %%(symref:short)%%(end)",
356+
branch_get_color(BRANCH_COLOR_REMOTE), quote_literal_for_format(remote_prefix),
357+
branch_get_color(BRANCH_COLOR_RESET));
433358
}
434-
strbuf_release(&name);
435-
strbuf_release(&out);
436-
free(to_free);
437-
}
438-
439-
static int calc_maxwidth(struct ref_array *refs, int remote_bonus)
440-
{
441-
int i, max = 0;
442-
for (i = 0; i < refs->nr; i++) {
443-
struct ref_array_item *it = refs->items[i];
444-
const char *desc = it->refname;
445-
int w;
446359

447-
skip_prefix(it->refname, "refs/heads/", &desc);
448-
skip_prefix(it->refname, "refs/remotes/", &desc);
449-
w = utf8_strwidth(desc);
360+
strbuf_addf(&fmt, "%%(if:notequals=refs/remotes)%%(refname:rstrip=-2)%%(then)%s%%(else)%s%%(end)", local.buf, remote.buf);
450361

451-
if (it->kind == FILTER_REFS_REMOTES)
452-
w += remote_bonus;
453-
if (w > max)
454-
max = w;
455-
}
456-
return max;
362+
strbuf_release(&local);
363+
strbuf_release(&remote);
364+
return strbuf_detach(&fmt, NULL);
457365
}
458366

459367
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
462370
struct ref_array array;
463371
int maxwidth = 0;
464372
const char *remote_prefix = "";
373+
struct strbuf out = STRBUF_INIT;
374+
char *format;
465375

466376
/*
467377
* 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
473383

474384
memset(&array, 0, sizeof(array));
475385

476-
verify_ref_format("%(refname)%(symref)");
477386
filter_refs(&array, filter, filter->kind | FILTER_REFS_INCLUDE_BROKEN);
478387

479388
if (filter->verbose)
480389
maxwidth = calc_maxwidth(&array, strlen(remote_prefix));
481390

391+
format = build_format(filter, maxwidth, remote_prefix);
392+
verify_ref_format(format);
393+
482394
ref_array_sort(sorting, &array);
483395

484-
for (i = 0; i < array.nr; i++)
485-
format_and_print_ref_item(array.items[i], maxwidth, filter, remote_prefix);
396+
for (i = 0; i < array.nr; i++) {
397+
format_ref_array_item(array.items[i], format, 0, &out);
398+
if (column_active(colopts)) {
399+
assert(!filter->verbose && "--column and --verbose are incompatible");
400+
/* format to a string_list to let print_columns() do its job */
401+
string_list_append(&output, out.buf);
402+
} else {
403+
fwrite(out.buf, 1, out.len, stdout);
404+
putchar('\n');
405+
}
406+
strbuf_release(&out);
407+
}
486408

487409
ref_array_clear(&array);
410+
free(format);
488411
}
489412

490413
static void reject_rebase_or_bisect_branch(const char *target)

t/t3203-branch-output.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ test_expect_success 'local-branch symrefs shortened properly' '
194194
git symbolic-ref refs/heads/ref-to-remote refs/remotes/origin/branch-one &&
195195
cat >expect <<-\EOF &&
196196
ref-to-branch -> branch-one
197-
ref-to-remote -> refs/remotes/origin/branch-one
197+
ref-to-remote -> origin/branch-one
198198
EOF
199199
git branch >actual.raw &&
200200
grep ref-to <actual.raw >actual &&

t/t6040-tracking-info.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ b1 [ahead 1, behind 1] d
4444
b2 [ahead 1, behind 1] d
4545
b3 [behind 1] b
4646
b4 [ahead 2] f
47-
b5 g
47+
b5 [gone] g
4848
b6 c
4949
EOF
5050

0 commit comments

Comments
 (0)