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>

Karthik Nayak committed Jan 10, 2017 at 14:19 UTC 949af0684c1f84587504e2143fca6f9bb8504e31
3 files changed +87 -164
builtin/branch.c
+85 -162
@@ -37,11 +37,11 @@ static unsigned char head_sha1[20];
37 static int branch_use_color = -1;
38 static char branch_colors[][COLOR_MAXLEN] = {
39 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 */
45 };
46 enum color_branch {
47 BRANCH_COLOR_RESET = 0,
@@ -280,180 +280,88 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
280 return(ret);
281 }
282
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)
284 {
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;
290
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);
299
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;
304 }
339 - strbuf_release(&fancy);
340 - if (added_decoration)
341 - strbuf_addch(stat, ' ');
342 - free(ref);
305 + return max;
306 }
307
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)
309 {
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;
311
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 + }
323 }
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;
325 }
326
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)
328 {
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;
332
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));
335
409 - strbuf_addf(&name, "%s%s", prefix_to_show, desc);
336 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),
351 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);
352 } 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));
358 }
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;
359
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);
361
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);
365 }
366
367 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
370 struct ref_array array;
371 int maxwidth = 0;
372 const char *remote_prefix = "";
373 + struct strbuf out = STRBUF_INIT;
374 + char *format;
375
376 /*
377 * 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
383
384 memset(&array, 0, sizeof(array));
385
476 - verify_ref_format("%(refname)%(symref)");
386 filter_refs(&array, filter, filter->kind | FILTER_REFS_INCLUDE_BROKEN);
387
388 if (filter->verbose)
389 maxwidth = calc_maxwidth(&array, strlen(remote_prefix));
390
391 + format = build_format(filter, maxwidth, remote_prefix);
392 + verify_ref_format(format);
393 +
394 ref_array_sort(sorting, &array);
395
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 + }
408
409 ref_array_clear(&array);
410 + free(format);
411 }
412
413 static void reject_rebase_or_bisect_branch(const char *target)
t/t3203-branch-output.sh
+1 -1
@@ -194,7 +194,7 @@ test_expect_success 'local-branch symrefs shortened properly' '
194 git symbolic-ref refs/heads/ref-to-remote refs/remotes/origin/branch-one &&
195 cat >expect <<-\EOF &&
196 ref-to-branch -> branch-one
197 - ref-to-remote -> refs/remotes/origin/branch-one
197 + ref-to-remote -> origin/branch-one
198 EOF
199 git branch >actual.raw &&
200 grep ref-to <actual.raw >actual &&
t/t6040-tracking-info.sh
+1 -1
@@ -44,7 +44,7 @@ b1 [ahead 1, behind 1] d
44 b2 [ahead 1, behind 1] d
45 b3 [behind 1] b
46 b4 [ahead 2] f
47 -b5 g
47 +b5 [gone] g
48 b6 c
49 EOF
50