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
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)
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,
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)