270
return(ret);
271
}
272
273
-static char *resolve_symref(const char *src, const char *prefix)
274
-{
275
- unsigned char sha1[20];
276
- int flag;
277
- const char *dst;
278
-
279
- dst = resolve_ref_unsafe(src, 0, sha1, &flag);
280
- if (!(dst && (flag & REF_ISSYMREF)))
281
- return NULL;
282
- if (prefix)
283
- skip_prefix(dst, prefix, &dst);
284
- return xstrdup(dst);
285
-}
286
-
287
-static int match_patterns(const char **pattern, const char *refname)
288
-{
289
- if (!*pattern)
290
- return 1; /* no pattern always matches */
291
- while (*pattern) {
292
- if (!wildmatch(*pattern, refname, 0, NULL))
293
- return 1;
294
- pattern++;
295
- }
296
- return 0;
297
-}
298
-
299
-/*
300
- * Allocate memory for a new ref_array_item and insert that into the
301
- * given ref_array. Doesn't take the objectname unlike
302
- * new_ref_array_item(). This is a temporary function which will be
303
- * removed when we port branch.c to use ref-filter APIs.
304
- */
305
-static struct ref_array_item *ref_array_append(struct ref_array *array, const char *refname)
306
-{
307
- size_t len = strlen(refname);
308
- struct ref_array_item *ref = xcalloc(1, sizeof(struct ref_array_item) + len + 1);
309
- memcpy(ref->refname, refname, len);
310
- ref->refname[len] = '\0';
311
- REALLOC_ARRAY(array->items, array->nr + 1);
312
- array->items[array->nr++] = ref;
313
- return ref;
314
-}
315
-
316
-static int append_ref(const char *refname, const struct object_id *oid, int flags, void *cb_data)
317
-{
318
- struct ref_filter_cbdata *cb = (struct ref_filter_cbdata *)(cb_data);
319
- struct ref_filter *filter = cb->filter;
320
- struct ref_array *array = cb->array;
321
- struct ref_array_item *item;
322
- struct commit *commit;
323
- int kind, i;
324
- const char *prefix, *orig_refname = refname;
325
-
326
- static struct {
327
- int kind;
328
- const char *prefix;
329
- } ref_kind[] = {
330
- { FILTER_REFS_BRANCHES, "refs/heads/" },
331
- { FILTER_REFS_REMOTES, "refs/remotes/" },
332
- };
333
-
334
- /* Detect kind */
335
- for (i = 0; i < ARRAY_SIZE(ref_kind); i++) {
336
- prefix = ref_kind[i].prefix;
337
- if (skip_prefix(refname, prefix, &refname)) {
338
- kind = ref_kind[i].kind;
339
- break;
340
- }
341
- }
342
- if (ARRAY_SIZE(ref_kind) <= i) {
343
- if (!strcmp(refname, "HEAD"))
344
- kind = FILTER_REFS_DETACHED_HEAD;
345
- else
346
- return 0;
347
- }
348
-
349
- /* Don't add types the caller doesn't want */
350
- if ((kind & filter->kind) == 0)
351
- return 0;
352
-
353
- if (!match_patterns(filter->name_patterns, refname))
354
- return 0;
355
-
356
- commit = NULL;
357
- if (filter->verbose || filter->with_commit || filter->merge != REF_FILTER_MERGED_NONE) {
358
- commit = lookup_commit_reference_gently(oid->hash, 1);
359
- if (!commit)
360
- return 0;
361
-
362
- /* Filter with with_commit if specified */
363
- if (!is_descendant_of(commit, filter->with_commit))
364
- return 0;
365
-
366
- if (filter->merge != REF_FILTER_MERGED_NONE)
367
- add_pending_object(array->revs,
368
- (struct object *)commit, refname);
369
- }
370
-
371
- item = ref_array_append(array, refname);
372
-
373
- /* Record the new item */
374
- item->kind = kind;
375
- item->commit = commit;
376
- item->symref = resolve_symref(orig_refname, prefix);
377
- item->ignore = 0;
378
-
379
- return 0;
380
-}
381
-
382
-static int ref_cmp(const void *r1, const void *r2)
383
-{
384
- struct ref_array_item *c1 = *((struct ref_array_item **)r1);
385
- struct ref_array_item *c2 = *((struct ref_array_item **)r2);
386
-
387
- if (c1->kind != c2->kind)
388
- return c1->kind - c2->kind;
389
- return strcmp(c1->refname, c2->refname);
390
-}
391
-
273
static void fill_tracking_info(struct strbuf *stat, const char *branch_name,
274
int show_upstream_ref)
275
{
333
}
334
335
static void add_verbose_info(struct strbuf *out, struct ref_array_item *item,
455
- struct ref_filter *filter)
336
+ struct ref_filter *filter, const char *refname)
337
{
338
struct strbuf subject = STRBUF_INIT, stat = STRBUF_INIT;
339
const char *sub = _(" **** invalid ref ****");
345
}
346
347
if (item->kind == FILTER_REFS_BRANCHES)
467
- fill_tracking_info(&stat, item->refname, filter->verbose > 1);
348
+ fill_tracking_info(&stat, refname, filter->verbose > 1);
349
350
strbuf_addf(out, " %s %s%s",
351
find_unique_abbrev(item->commit->object.sha1, filter->abbrev),
385
return strbuf_detach(&desc, NULL);
386
}
387
507
-static void print_ref_item(struct ref_array_item *item, int maxwidth,
508
- struct ref_filter *filter, const char *remote_prefix)
388
+static void format_and_print_ref_item(struct ref_array_item *item, int maxwidth,
389
+ struct ref_filter *filter, const char *remote_prefix)
390
{
391
char c;
392
int current = 0;
396
const char *desc = item->refname;
397
char *to_free = NULL;
398
518
- if (item->ignore)
519
- return;
520
-
399
switch (item->kind) {
400
case FILTER_REFS_BRANCHES:
523
- if (!filter->detached && !strcmp(item->refname, head))
401
+ skip_prefix(desc, "refs/heads/", &desc);
402
+ if (!filter->detached && !strcmp(desc, head))
403
current = 1;
404
else
405
color = BRANCH_COLOR_LOCAL;
406
break;
407
case FILTER_REFS_REMOTES:
408
+ skip_prefix(desc, "refs/remotes/", &desc);
409
color = BRANCH_COLOR_REMOTE;
410
prefix = remote_prefix;
411
break;
434
strbuf_addf(&out, "%c %s%s%s", c, branch_get_color(color),
435
name.buf, branch_get_color(BRANCH_COLOR_RESET));
436
557
- if (item->symref)
558
- strbuf_addf(&out, " -> %s", item->symref);
437
+ if (item->symref) {
438
+ skip_prefix(item->symref, "refs/remotes/", &desc);
439
+ strbuf_addf(&out, " -> %s", desc);
440
+ }
441
else if (filter->verbose)
442
/* " f7c0c00 [ahead 58, behind 197] vcs-svn: drop obj_pool.h" */
561
- add_verbose_info(&out, item, filter);
443
+ add_verbose_info(&out, item, filter, desc);
444
if (column_active(colopts)) {
445
assert(!filter->verbose && "--column and --verbose are incompatible");
446
string_list_append(&output, out.buf);
457
int i, max = 0;
458
for (i = 0; i < refs->nr; i++) {
459
struct ref_array_item *it = refs->items[i];
460
+ const char *desc = it->refname;
461
int w;
462
580
- if (it->ignore)
581
- continue;
582
- w = utf8_strwidth(it->refname);
463
+ skip_prefix(it->refname, "refs/heads/", &desc);
464
+ skip_prefix(it->refname, "refs/remotes/", &desc);
465
+ w = utf8_strwidth(desc);
466
+
467
if (it->kind == FILTER_REFS_REMOTES)
468
w += remote_bonus;
469
if (w > max)
472
return max;
473
}
474
591
-static void print_ref_list(struct ref_filter *filter)
475
+static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sorting)
476
{
477
int i;
478
struct ref_array array;
595
- struct ref_filter_cbdata data;
479
int maxwidth = 0;
480
const char *remote_prefix = "";
598
- struct rev_info revs;
481
482
/*
483
* If we are listing more than just remote branches,
488
remote_prefix = "remotes/";
489
490
memset(&array, 0, sizeof(array));
609
- if (filter->merge != REF_FILTER_MERGED_NONE)
610
- init_revisions(&revs, NULL);
611
-
612
- data.array = &array;
613
- data.filter = filter;
614
- array.revs = &revs;
615
-
616
- /*
617
- * First we obtain all regular branch refs and if the HEAD is
618
- * detached then we insert that ref to the end of the ref_fist
619
- * so that it can be printed and removed first.
620
- */
621
- for_each_rawref(append_ref, &data);
622
- if (filter->detached)
623
- head_ref(append_ref, &data);
624
- /*
625
- * The following implementation is currently duplicated in ref-filter. It
626
- * will eventually be removed when we port branch.c to use ref-filter APIs.
627
- */
628
- if (filter->merge != REF_FILTER_MERGED_NONE) {
629
- filter->merge_commit->object.flags |= UNINTERESTING;
630
- add_pending_object(&revs, &filter->merge_commit->object, "");
631
- revs.limited = 1;
632
-
633
- if (prepare_revision_walk(&revs))
634
- die(_("revision walk setup failed"));
635
-
636
- for (i = 0; i < array.nr; i++) {
637
- struct ref_array_item *item = array.items[i];
638
- struct commit *commit = item->commit;
639
- int is_merged = !!(commit->object.flags & UNINTERESTING);
640
- item->ignore = is_merged != (filter->merge == REF_FILTER_MERGED_INCLUDE);
641
- }
491
643
- for (i = 0; i < array.nr; i++) {
644
- struct ref_array_item *item = array.items[i];
645
- clear_commit_marks(item->commit, ALL_REV_FLAGS);
646
- }
647
- clear_commit_marks(filter->merge_commit, ALL_REV_FLAGS);
648
- }
492
+ verify_ref_format("%(refname)%(symref)");
493
+ filter_refs(&array, filter, filter->kind | FILTER_REFS_INCLUDE_BROKEN);
494
495
if (filter->verbose)
496
maxwidth = calc_maxwidth(&array, strlen(remote_prefix));
497
653
- qsort(array.items, array.nr, sizeof(struct ref_array_item *), ref_cmp);
498
+ /*
499
+ * If no sorting parameter is given then we default to sorting
500
+ * by 'refname'. This would give us an alphabetically sorted
501
+ * array with the 'HEAD' ref at the beginning followed by
502
+ * local branches 'refs/heads/...' and finally remote-tacking
503
+ * branches 'refs/remotes/...'.
504
+ */
505
+ if (!sorting)
506
+ sorting = ref_default_sorting();
507
+ ref_array_sort(sorting, &array);
508
509
for (i = 0; i < array.nr; i++)
656
- print_ref_item(array.items[i], maxwidth, filter, remote_prefix);
510
+ format_and_print_ref_item(array.items[i], maxwidth, filter, remote_prefix);
511
512
ref_array_clear(&array);
513
}
609
const char *new_upstream = NULL;
610
enum branch_track track;
611
struct ref_filter filter;
612
+ static struct ref_sorting *sorting = NULL, **sorting_tail = &sorting;
613
614
struct option options[] = {
615
OPT_GROUP(N_("Generic options")),
644
OPT_MERGED(&filter, N_("print only branches that are merged")),
645
OPT_NO_MERGED(&filter, N_("print only branches that are not merged")),
646
OPT_COLUMN(0, "column", &colopts, N_("list branches in columns")),
647
+ OPT_CALLBACK(0 , "sort", sorting_tail, N_("key"),
648
+ N_("field name to sort on"), &parse_opt_ref_sorting),
649
OPT_END(),
650
};
651
704
if ((filter.kind & FILTER_REFS_BRANCHES) && filter.detached)
705
filter.kind |= FILTER_REFS_DETACHED_HEAD;
706
filter.name_patterns = argv;
850
- print_ref_list(&filter);
707
+ print_ref_list(&filter, sorting);
708
print_columns(&output, colopts, NULL);
709
string_list_clear(&output, 0);
710
return 0;