Merge branch 'nd/completion-negation'
[git] / builtin / show-branch.c
1 #include "cache.h"
2 #include "config.h"
3 #include "pretty.h"
4 #include "refs.h"
5 #include "builtin.h"
6 #include "color.h"
7 #include "argv-array.h"
8 #include "parse-options.h"
9 #include "dir.h"
10 #include "commit-slab.h"
11
12 static const char* show_branch_usage[] = {
13     N_("git show-branch [-a | --all] [-r | --remotes] [--topo-order | --date-order]\n"
14        "                [--current] [--color[=<when>] | --no-color] [--sparse]\n"
15        "                [--more=<n> | --list | --independent | --merge-base]\n"
16        "                [--no-name | --sha1-name] [--topics] [(<rev> | <glob>)...]"),
17     N_("git show-branch (-g | --reflog)[=<n>[,<base>]] [--list] [<ref>]"),
18     NULL
19 };
20
21 static int showbranch_use_color = -1;
22
23 static struct argv_array default_args = ARGV_ARRAY_INIT;
24
25 /*
26  * TODO: convert this use of commit->object.flags to commit-slab
27  * instead to store a pointer to ref name directly. Then use the same
28  * UNINTERESTING definition from revision.h here.
29  */
30 #define UNINTERESTING   01
31
32 #define REV_SHIFT        2
33 #define MAX_REVS        (FLAG_BITS - REV_SHIFT) /* should not exceed bits_per_int - REV_SHIFT */
34
35 #define DEFAULT_REFLOG  4
36
37 static const char *get_color_code(int idx)
38 {
39         if (want_color(showbranch_use_color))
40                 return column_colors_ansi[idx % column_colors_ansi_max];
41         return "";
42 }
43
44 static const char *get_color_reset_code(void)
45 {
46         if (want_color(showbranch_use_color))
47                 return GIT_COLOR_RESET;
48         return "";
49 }
50
51 static struct commit *interesting(struct commit_list *list)
52 {
53         while (list) {
54                 struct commit *commit = list->item;
55                 list = list->next;
56                 if (commit->object.flags & UNINTERESTING)
57                         continue;
58                 return commit;
59         }
60         return NULL;
61 }
62
63 struct commit_name {
64         const char *head_name; /* which head's ancestor? */
65         int generation; /* how many parents away from head_name */
66 };
67
68 define_commit_slab(commit_name_slab, struct commit_name *);
69 static struct commit_name_slab name_slab;
70
71 static struct commit_name *commit_to_name(struct commit *commit)
72 {
73         return *commit_name_slab_at(&name_slab, commit);
74 }
75
76
77 /* Name the commit as nth generation ancestor of head_name;
78  * we count only the first-parent relationship for naming purposes.
79  */
80 static void name_commit(struct commit *commit, const char *head_name, int nth)
81 {
82         struct commit_name *name;
83
84         name = *commit_name_slab_at(&name_slab, commit);
85         if (!name) {
86                 name = xmalloc(sizeof(*name));
87                 *commit_name_slab_at(&name_slab, commit) = name;
88         }
89         name->head_name = head_name;
90         name->generation = nth;
91 }
92
93 /* Parent is the first parent of the commit.  We may name it
94  * as (n+1)th generation ancestor of the same head_name as
95  * commit is nth generation ancestor of, if that generation
96  * number is better than the name it already has.
97  */
98 static void name_parent(struct commit *commit, struct commit *parent)
99 {
100         struct commit_name *commit_name = commit_to_name(commit);
101         struct commit_name *parent_name = commit_to_name(parent);
102         if (!commit_name)
103                 return;
104         if (!parent_name ||
105             commit_name->generation + 1 < parent_name->generation)
106                 name_commit(parent, commit_name->head_name,
107                             commit_name->generation + 1);
108 }
109
110 static int name_first_parent_chain(struct commit *c)
111 {
112         int i = 0;
113         while (c) {
114                 struct commit *p;
115                 if (!commit_to_name(c))
116                         break;
117                 if (!c->parents)
118                         break;
119                 p = c->parents->item;
120                 if (!commit_to_name(p)) {
121                         name_parent(c, p);
122                         i++;
123                 }
124                 else
125                         break;
126                 c = p;
127         }
128         return i;
129 }
130
131 static void name_commits(struct commit_list *list,
132                          struct commit **rev,
133                          char **ref_name,
134                          int num_rev)
135 {
136         struct commit_list *cl;
137         struct commit *c;
138         int i;
139
140         /* First give names to the given heads */
141         for (cl = list; cl; cl = cl->next) {
142                 c = cl->item;
143                 if (commit_to_name(c))
144                         continue;
145                 for (i = 0; i < num_rev; i++) {
146                         if (rev[i] == c) {
147                                 name_commit(c, ref_name[i], 0);
148                                 break;
149                         }
150                 }
151         }
152
153         /* Then commits on the first parent ancestry chain */
154         do {
155                 i = 0;
156                 for (cl = list; cl; cl = cl->next) {
157                         i += name_first_parent_chain(cl->item);
158                 }
159         } while (i);
160
161         /* Finally, any unnamed commits */
162         do {
163                 i = 0;
164                 for (cl = list; cl; cl = cl->next) {
165                         struct commit_list *parents;
166                         struct commit_name *n;
167                         int nth;
168                         c = cl->item;
169                         if (!commit_to_name(c))
170                                 continue;
171                         n = commit_to_name(c);
172                         parents = c->parents;
173                         nth = 0;
174                         while (parents) {
175                                 struct commit *p = parents->item;
176                                 struct strbuf newname = STRBUF_INIT;
177                                 parents = parents->next;
178                                 nth++;
179                                 if (commit_to_name(p))
180                                         continue;
181                                 switch (n->generation) {
182                                 case 0:
183                                         strbuf_addstr(&newname, n->head_name);
184                                         break;
185                                 case 1:
186                                         strbuf_addf(&newname, "%s^", n->head_name);
187                                         break;
188                                 default:
189                                         strbuf_addf(&newname, "%s~%d",
190                                                     n->head_name, n->generation);
191                                         break;
192                                 }
193                                 if (nth == 1)
194                                         strbuf_addch(&newname, '^');
195                                 else
196                                         strbuf_addf(&newname, "^%d", nth);
197                                 name_commit(p, strbuf_detach(&newname, NULL), 0);
198                                 i++;
199                                 name_first_parent_chain(p);
200                         }
201                 }
202         } while (i);
203 }
204
205 static int mark_seen(struct commit *commit, struct commit_list **seen_p)
206 {
207         if (!commit->object.flags) {
208                 commit_list_insert(commit, seen_p);
209                 return 1;
210         }
211         return 0;
212 }
213
214 static void join_revs(struct commit_list **list_p,
215                       struct commit_list **seen_p,
216                       int num_rev, int extra)
217 {
218         int all_mask = ((1u << (REV_SHIFT + num_rev)) - 1);
219         int all_revs = all_mask & ~((1u << REV_SHIFT) - 1);
220
221         while (*list_p) {
222                 struct commit_list *parents;
223                 int still_interesting = !!interesting(*list_p);
224                 struct commit *commit = pop_commit(list_p);
225                 int flags = commit->object.flags & all_mask;
226
227                 if (!still_interesting && extra <= 0)
228                         break;
229
230                 mark_seen(commit, seen_p);
231                 if ((flags & all_revs) == all_revs)
232                         flags |= UNINTERESTING;
233                 parents = commit->parents;
234
235                 while (parents) {
236                         struct commit *p = parents->item;
237                         int this_flag = p->object.flags;
238                         parents = parents->next;
239                         if ((this_flag & flags) == flags)
240                                 continue;
241                         parse_commit(p);
242                         if (mark_seen(p, seen_p) && !still_interesting)
243                                 extra--;
244                         p->object.flags |= flags;
245                         commit_list_insert_by_date(p, list_p);
246                 }
247         }
248
249         /*
250          * Postprocess to complete well-poisoning.
251          *
252          * At this point we have all the commits we have seen in
253          * seen_p list.  Mark anything that can be reached from
254          * uninteresting commits not interesting.
255          */
256         for (;;) {
257                 int changed = 0;
258                 struct commit_list *s;
259                 for (s = *seen_p; s; s = s->next) {
260                         struct commit *c = s->item;
261                         struct commit_list *parents;
262
263                         if (((c->object.flags & all_revs) != all_revs) &&
264                             !(c->object.flags & UNINTERESTING))
265                                 continue;
266
267                         /* The current commit is either a merge base or
268                          * already uninteresting one.  Mark its parents
269                          * as uninteresting commits _only_ if they are
270                          * already parsed.  No reason to find new ones
271                          * here.
272                          */
273                         parents = c->parents;
274                         while (parents) {
275                                 struct commit *p = parents->item;
276                                 parents = parents->next;
277                                 if (!(p->object.flags & UNINTERESTING)) {
278                                         p->object.flags |= UNINTERESTING;
279                                         changed = 1;
280                                 }
281                         }
282                 }
283                 if (!changed)
284                         break;
285         }
286 }
287
288 static void show_one_commit(struct commit *commit, int no_name)
289 {
290         struct strbuf pretty = STRBUF_INIT;
291         const char *pretty_str = "(unavailable)";
292         struct commit_name *name = commit_to_name(commit);
293
294         if (commit->object.parsed) {
295                 pp_commit_easy(CMIT_FMT_ONELINE, commit, &pretty);
296                 pretty_str = pretty.buf;
297         }
298         skip_prefix(pretty_str, "[PATCH] ", &pretty_str);
299
300         if (!no_name) {
301                 if (name && name->head_name) {
302                         printf("[%s", name->head_name);
303                         if (name->generation) {
304                                 if (name->generation == 1)
305                                         printf("^");
306                                 else
307                                         printf("~%d", name->generation);
308                         }
309                         printf("] ");
310                 }
311                 else
312                         printf("[%s] ",
313                                find_unique_abbrev(&commit->object.oid,
314                                                   DEFAULT_ABBREV));
315         }
316         puts(pretty_str);
317         strbuf_release(&pretty);
318 }
319
320 static char *ref_name[MAX_REVS + 1];
321 static int ref_name_cnt;
322
323 static const char *find_digit_prefix(const char *s, int *v)
324 {
325         const char *p;
326         int ver;
327         char ch;
328
329         for (p = s, ver = 0;
330              '0' <= (ch = *p) && ch <= '9';
331              p++)
332                 ver = ver * 10 + ch - '0';
333         *v = ver;
334         return p;
335 }
336
337
338 static int version_cmp(const char *a, const char *b)
339 {
340         while (1) {
341                 int va, vb;
342
343                 a = find_digit_prefix(a, &va);
344                 b = find_digit_prefix(b, &vb);
345                 if (va != vb)
346                         return va - vb;
347
348                 while (1) {
349                         int ca = *a;
350                         int cb = *b;
351                         if ('0' <= ca && ca <= '9')
352                                 ca = 0;
353                         if ('0' <= cb && cb <= '9')
354                                 cb = 0;
355                         if (ca != cb)
356                                 return ca - cb;
357                         if (!ca)
358                                 break;
359                         a++;
360                         b++;
361                 }
362                 if (!*a && !*b)
363                         return 0;
364         }
365 }
366
367 static int compare_ref_name(const void *a_, const void *b_)
368 {
369         const char * const*a = a_, * const*b = b_;
370         return version_cmp(*a, *b);
371 }
372
373 static void sort_ref_range(int bottom, int top)
374 {
375         QSORT(ref_name + bottom, top - bottom, compare_ref_name);
376 }
377
378 static int append_ref(const char *refname, const struct object_id *oid,
379                       int allow_dups)
380 {
381         struct commit *commit = lookup_commit_reference_gently(oid, 1);
382         int i;
383
384         if (!commit)
385                 return 0;
386
387         if (!allow_dups) {
388                 /* Avoid adding the same thing twice */
389                 for (i = 0; i < ref_name_cnt; i++)
390                         if (!strcmp(refname, ref_name[i]))
391                                 return 0;
392         }
393         if (MAX_REVS <= ref_name_cnt) {
394                 warning(Q_("ignoring %s; cannot handle more than %d ref",
395                            "ignoring %s; cannot handle more than %d refs",
396                            MAX_REVS), refname, MAX_REVS);
397                 return 0;
398         }
399         ref_name[ref_name_cnt++] = xstrdup(refname);
400         ref_name[ref_name_cnt] = NULL;
401         return 0;
402 }
403
404 static int append_head_ref(const char *refname, const struct object_id *oid,
405                            int flag, void *cb_data)
406 {
407         struct object_id tmp;
408         int ofs = 11;
409         if (!starts_with(refname, "refs/heads/"))
410                 return 0;
411         /* If both heads/foo and tags/foo exists, get_sha1 would
412          * get confused.
413          */
414         if (get_oid(refname + ofs, &tmp) || oidcmp(&tmp, oid))
415                 ofs = 5;
416         return append_ref(refname + ofs, oid, 0);
417 }
418
419 static int append_remote_ref(const char *refname, const struct object_id *oid,
420                              int flag, void *cb_data)
421 {
422         struct object_id tmp;
423         int ofs = 13;
424         if (!starts_with(refname, "refs/remotes/"))
425                 return 0;
426         /* If both heads/foo and tags/foo exists, get_sha1 would
427          * get confused.
428          */
429         if (get_oid(refname + ofs, &tmp) || oidcmp(&tmp, oid))
430                 ofs = 5;
431         return append_ref(refname + ofs, oid, 0);
432 }
433
434 static int append_tag_ref(const char *refname, const struct object_id *oid,
435                           int flag, void *cb_data)
436 {
437         if (!starts_with(refname, "refs/tags/"))
438                 return 0;
439         return append_ref(refname + 5, oid, 0);
440 }
441
442 static const char *match_ref_pattern = NULL;
443 static int match_ref_slash = 0;
444
445 static int append_matching_ref(const char *refname, const struct object_id *oid,
446                                int flag, void *cb_data)
447 {
448         /* we want to allow pattern hold/<asterisk> to show all
449          * branches under refs/heads/hold/, and v0.99.9? to show
450          * refs/tags/v0.99.9a and friends.
451          */
452         const char *tail;
453         int slash = count_slashes(refname);
454         for (tail = refname; *tail && match_ref_slash < slash; )
455                 if (*tail++ == '/')
456                         slash--;
457         if (!*tail)
458                 return 0;
459         if (wildmatch(match_ref_pattern, tail, 0))
460                 return 0;
461         if (starts_with(refname, "refs/heads/"))
462                 return append_head_ref(refname, oid, flag, cb_data);
463         if (starts_with(refname, "refs/tags/"))
464                 return append_tag_ref(refname, oid, flag, cb_data);
465         return append_ref(refname, oid, 0);
466 }
467
468 static void snarf_refs(int head, int remotes)
469 {
470         if (head) {
471                 int orig_cnt = ref_name_cnt;
472
473                 for_each_ref(append_head_ref, NULL);
474                 sort_ref_range(orig_cnt, ref_name_cnt);
475         }
476         if (remotes) {
477                 int orig_cnt = ref_name_cnt;
478
479                 for_each_ref(append_remote_ref, NULL);
480                 sort_ref_range(orig_cnt, ref_name_cnt);
481         }
482 }
483
484 static int rev_is_head(const char *head, const char *name,
485                        unsigned char *head_sha1, unsigned char *sha1)
486 {
487         if (!head || (head_sha1 && sha1 && hashcmp(head_sha1, sha1)))
488                 return 0;
489         skip_prefix(head, "refs/heads/", &head);
490         if (!skip_prefix(name, "refs/heads/", &name))
491                 skip_prefix(name, "heads/", &name);
492         return !strcmp(head, name);
493 }
494
495 static int show_merge_base(struct commit_list *seen, int num_rev)
496 {
497         int all_mask = ((1u << (REV_SHIFT + num_rev)) - 1);
498         int all_revs = all_mask & ~((1u << REV_SHIFT) - 1);
499         int exit_status = 1;
500
501         while (seen) {
502                 struct commit *commit = pop_commit(&seen);
503                 int flags = commit->object.flags & all_mask;
504                 if (!(flags & UNINTERESTING) &&
505                     ((flags & all_revs) == all_revs)) {
506                         puts(oid_to_hex(&commit->object.oid));
507                         exit_status = 0;
508                         commit->object.flags |= UNINTERESTING;
509                 }
510         }
511         return exit_status;
512 }
513
514 static int show_independent(struct commit **rev,
515                             int num_rev,
516                             char **ref_name,
517                             unsigned int *rev_mask)
518 {
519         int i;
520
521         for (i = 0; i < num_rev; i++) {
522                 struct commit *commit = rev[i];
523                 unsigned int flag = rev_mask[i];
524
525                 if (commit->object.flags == flag)
526                         puts(oid_to_hex(&commit->object.oid));
527                 commit->object.flags |= UNINTERESTING;
528         }
529         return 0;
530 }
531
532 static void append_one_rev(const char *av)
533 {
534         struct object_id revkey;
535         if (!get_oid(av, &revkey)) {
536                 append_ref(av, &revkey, 0);
537                 return;
538         }
539         if (strchr(av, '*') || strchr(av, '?') || strchr(av, '[')) {
540                 /* glob style match */
541                 int saved_matches = ref_name_cnt;
542
543                 match_ref_pattern = av;
544                 match_ref_slash = count_slashes(av);
545                 for_each_ref(append_matching_ref, NULL);
546                 if (saved_matches == ref_name_cnt &&
547                     ref_name_cnt < MAX_REVS)
548                         error(_("no matching refs with %s"), av);
549                 sort_ref_range(saved_matches, ref_name_cnt);
550                 return;
551         }
552         die("bad sha1 reference %s", av);
553 }
554
555 static int git_show_branch_config(const char *var, const char *value, void *cb)
556 {
557         if (!strcmp(var, "showbranch.default")) {
558                 if (!value)
559                         return config_error_nonbool(var);
560                 /*
561                  * default_arg is now passed to parse_options(), so we need to
562                  * mimic the real argv a bit better.
563                  */
564                 if (!default_args.argc)
565                         argv_array_push(&default_args, "show-branch");
566                 argv_array_push(&default_args, value);
567                 return 0;
568         }
569
570         if (!strcmp(var, "color.showbranch")) {
571                 showbranch_use_color = git_config_colorbool(var, value);
572                 return 0;
573         }
574
575         return git_color_default_config(var, value, cb);
576 }
577
578 static int omit_in_dense(struct commit *commit, struct commit **rev, int n)
579 {
580         /* If the commit is tip of the named branches, do not
581          * omit it.
582          * Otherwise, if it is a merge that is reachable from only one
583          * tip, it is not that interesting.
584          */
585         int i, flag, count;
586         for (i = 0; i < n; i++)
587                 if (rev[i] == commit)
588                         return 0;
589         flag = commit->object.flags;
590         for (i = count = 0; i < n; i++) {
591                 if (flag & (1u << (i + REV_SHIFT)))
592                         count++;
593         }
594         if (count == 1)
595                 return 1;
596         return 0;
597 }
598
599 static int reflog = 0;
600
601 static int parse_reflog_param(const struct option *opt, const char *arg,
602                               int unset)
603 {
604         char *ep;
605         const char **base = (const char **)opt->value;
606         if (!arg)
607                 arg = "";
608         reflog = strtoul(arg, &ep, 10);
609         if (*ep == ',')
610                 *base = ep + 1;
611         else if (*ep)
612                 return error("unrecognized reflog param '%s'", arg);
613         else
614                 *base = NULL;
615         if (reflog <= 0)
616                 reflog = DEFAULT_REFLOG;
617         return 0;
618 }
619
620 int cmd_show_branch(int ac, const char **av, const char *prefix)
621 {
622         struct commit *rev[MAX_REVS], *commit;
623         char *reflog_msg[MAX_REVS];
624         struct commit_list *list = NULL, *seen = NULL;
625         unsigned int rev_mask[MAX_REVS];
626         int num_rev, i, extra = 0;
627         int all_heads = 0, all_remotes = 0;
628         int all_mask, all_revs;
629         enum rev_sort_order sort_order = REV_SORT_IN_GRAPH_ORDER;
630         char *head;
631         struct object_id head_oid;
632         int merge_base = 0;
633         int independent = 0;
634         int no_name = 0;
635         int sha1_name = 0;
636         int shown_merge_point = 0;
637         int with_current_branch = 0;
638         int head_at = -1;
639         int topics = 0;
640         int dense = 1;
641         const char *reflog_base = NULL;
642         struct option builtin_show_branch_options[] = {
643                 OPT_BOOL('a', "all", &all_heads,
644                          N_("show remote-tracking and local branches")),
645                 OPT_BOOL('r', "remotes", &all_remotes,
646                          N_("show remote-tracking branches")),
647                 OPT__COLOR(&showbranch_use_color,
648                             N_("color '*!+-' corresponding to the branch")),
649                 { OPTION_INTEGER, 0, "more", &extra, N_("n"),
650                             N_("show <n> more commits after the common ancestor"),
651                             PARSE_OPT_OPTARG, NULL, (intptr_t)1 },
652                 OPT_SET_INT(0, "list", &extra, N_("synonym to more=-1"), -1),
653                 OPT_BOOL(0, "no-name", &no_name, N_("suppress naming strings")),
654                 OPT_BOOL(0, "current", &with_current_branch,
655                          N_("include the current branch")),
656                 OPT_BOOL(0, "sha1-name", &sha1_name,
657                          N_("name commits with their object names")),
658                 OPT_BOOL(0, "merge-base", &merge_base,
659                          N_("show possible merge bases")),
660                 OPT_BOOL(0, "independent", &independent,
661                             N_("show refs unreachable from any other ref")),
662                 OPT_SET_INT(0, "topo-order", &sort_order,
663                             N_("show commits in topological order"),
664                             REV_SORT_IN_GRAPH_ORDER),
665                 OPT_BOOL(0, "topics", &topics,
666                          N_("show only commits not on the first branch")),
667                 OPT_SET_INT(0, "sparse", &dense,
668                             N_("show merges reachable from only one tip"), 0),
669                 OPT_SET_INT(0, "date-order", &sort_order,
670                             N_("topologically sort, maintaining date order "
671                                "where possible"),
672                             REV_SORT_BY_COMMIT_DATE),
673                 { OPTION_CALLBACK, 'g', "reflog", &reflog_base, N_("<n>[,<base>]"),
674                             N_("show <n> most recent ref-log entries starting at "
675                                "base"),
676                             PARSE_OPT_OPTARG | PARSE_OPT_LITERAL_ARGHELP,
677                             parse_reflog_param },
678                 OPT_END()
679         };
680
681         init_commit_name_slab(&name_slab);
682
683         git_config(git_show_branch_config, NULL);
684
685         /* If nothing is specified, try the default first */
686         if (ac == 1 && default_args.argc) {
687                 ac = default_args.argc;
688                 av = default_args.argv;
689         }
690
691         ac = parse_options(ac, av, prefix, builtin_show_branch_options,
692                            show_branch_usage, PARSE_OPT_STOP_AT_NON_OPTION);
693         if (all_heads)
694                 all_remotes = 1;
695
696         if (extra || reflog) {
697                 /* "listing" mode is incompatible with
698                  * independent nor merge-base modes.
699                  */
700                 if (independent || merge_base)
701                         usage_with_options(show_branch_usage,
702                                            builtin_show_branch_options);
703                 if (reflog && ((0 < extra) || all_heads || all_remotes))
704                         /*
705                          * Asking for --more in reflog mode does not
706                          * make sense.  --list is Ok.
707                          *
708                          * Also --all and --remotes do not make sense either.
709                          */
710                         die(_("--reflog is incompatible with --all, --remotes, "
711                               "--independent or --merge-base"));
712         }
713
714         /* If nothing is specified, show all branches by default */
715         if (ac <= topics && all_heads + all_remotes == 0)
716                 all_heads = 1;
717
718         if (reflog) {
719                 struct object_id oid;
720                 char *ref;
721                 int base = 0;
722                 unsigned int flags = 0;
723
724                 if (ac == 0) {
725                         static const char *fake_av[2];
726
727                         fake_av[0] = resolve_refdup("HEAD",
728                                                     RESOLVE_REF_READING, &oid,
729                                                     NULL);
730                         fake_av[1] = NULL;
731                         av = fake_av;
732                         ac = 1;
733                         if (!*av)
734                                 die(_("no branches given, and HEAD is not valid"));
735                 }
736                 if (ac != 1)
737                         die(_("--reflog option needs one branch name"));
738
739                 if (MAX_REVS < reflog)
740                         die(Q_("only %d entry can be shown at one time.",
741                                "only %d entries can be shown at one time.",
742                                MAX_REVS), MAX_REVS);
743                 if (!dwim_ref(*av, strlen(*av), &oid, &ref))
744                         die(_("no such ref %s"), *av);
745
746                 /* Has the base been specified? */
747                 if (reflog_base) {
748                         char *ep;
749                         base = strtoul(reflog_base, &ep, 10);
750                         if (*ep) {
751                                 /* Ah, that is a date spec... */
752                                 timestamp_t at;
753                                 at = approxidate(reflog_base);
754                                 read_ref_at(ref, flags, at, -1, &oid, NULL,
755                                             NULL, NULL, &base);
756                         }
757                 }
758
759                 for (i = 0; i < reflog; i++) {
760                         char *logmsg;
761                         char *nth_desc;
762                         const char *msg;
763                         timestamp_t timestamp;
764                         int tz;
765
766                         if (read_ref_at(ref, flags, 0, base + i, &oid, &logmsg,
767                                         &timestamp, &tz, NULL)) {
768                                 reflog = i;
769                                 break;
770                         }
771                         msg = strchr(logmsg, '\t');
772                         if (!msg)
773                                 msg = "(none)";
774                         else
775                                 msg++;
776                         reflog_msg[i] = xstrfmt("(%s) %s",
777                                                 show_date(timestamp, tz,
778                                                           DATE_MODE(RELATIVE)),
779                                                 msg);
780                         free(logmsg);
781
782                         nth_desc = xstrfmt("%s@{%d}", *av, base+i);
783                         append_ref(nth_desc, &oid, 1);
784                         free(nth_desc);
785                 }
786                 free(ref);
787         }
788         else {
789                 while (0 < ac) {
790                         append_one_rev(*av);
791                         ac--; av++;
792                 }
793                 if (all_heads + all_remotes)
794                         snarf_refs(all_heads, all_remotes);
795         }
796
797         head = resolve_refdup("HEAD", RESOLVE_REF_READING,
798                               &head_oid, NULL);
799
800         if (with_current_branch && head) {
801                 int has_head = 0;
802                 for (i = 0; !has_head && i < ref_name_cnt; i++) {
803                         /* We are only interested in adding the branch
804                          * HEAD points at.
805                          */
806                         if (rev_is_head(head,
807                                         ref_name[i],
808                                         head_oid.hash, NULL))
809                                 has_head++;
810                 }
811                 if (!has_head) {
812                         const char *name = head;
813                         skip_prefix(name, "refs/heads/", &name);
814                         append_one_rev(name);
815                 }
816         }
817
818         if (!ref_name_cnt) {
819                 fprintf(stderr, "No revs to be shown.\n");
820                 exit(0);
821         }
822
823         for (num_rev = 0; ref_name[num_rev]; num_rev++) {
824                 struct object_id revkey;
825                 unsigned int flag = 1u << (num_rev + REV_SHIFT);
826
827                 if (MAX_REVS <= num_rev)
828                         die(Q_("cannot handle more than %d rev.",
829                                "cannot handle more than %d revs.",
830                                MAX_REVS), MAX_REVS);
831                 if (get_oid(ref_name[num_rev], &revkey))
832                         die(_("'%s' is not a valid ref."), ref_name[num_rev]);
833                 commit = lookup_commit_reference(&revkey);
834                 if (!commit)
835                         die(_("cannot find commit %s (%s)"),
836                             ref_name[num_rev], oid_to_hex(&revkey));
837                 parse_commit(commit);
838                 mark_seen(commit, &seen);
839
840                 /* rev#0 uses bit REV_SHIFT, rev#1 uses bit REV_SHIFT+1,
841                  * and so on.  REV_SHIFT bits from bit 0 are used for
842                  * internal bookkeeping.
843                  */
844                 commit->object.flags |= flag;
845                 if (commit->object.flags == flag)
846                         commit_list_insert_by_date(commit, &list);
847                 rev[num_rev] = commit;
848         }
849         for (i = 0; i < num_rev; i++)
850                 rev_mask[i] = rev[i]->object.flags;
851
852         if (0 <= extra)
853                 join_revs(&list, &seen, num_rev, extra);
854
855         commit_list_sort_by_date(&seen);
856
857         if (merge_base)
858                 return show_merge_base(seen, num_rev);
859
860         if (independent)
861                 return show_independent(rev, num_rev, ref_name, rev_mask);
862
863         /* Show list; --more=-1 means list-only */
864         if (1 < num_rev || extra < 0) {
865                 for (i = 0; i < num_rev; i++) {
866                         int j;
867                         int is_head = rev_is_head(head,
868                                                   ref_name[i],
869                                                   head_oid.hash,
870                                                   rev[i]->object.oid.hash);
871                         if (extra < 0)
872                                 printf("%c [%s] ",
873                                        is_head ? '*' : ' ', ref_name[i]);
874                         else {
875                                 for (j = 0; j < i; j++)
876                                         putchar(' ');
877                                 printf("%s%c%s [%s] ",
878                                        get_color_code(i),
879                                        is_head ? '*' : '!',
880                                        get_color_reset_code(), ref_name[i]);
881                         }
882
883                         if (!reflog) {
884                                 /* header lines never need name */
885                                 show_one_commit(rev[i], 1);
886                         }
887                         else
888                                 puts(reflog_msg[i]);
889
890                         if (is_head)
891                                 head_at = i;
892                 }
893                 if (0 <= extra) {
894                         for (i = 0; i < num_rev; i++)
895                                 putchar('-');
896                         putchar('\n');
897                 }
898         }
899         if (extra < 0)
900                 exit(0);
901
902         /* Sort topologically */
903         sort_in_topological_order(&seen, sort_order);
904
905         /* Give names to commits */
906         if (!sha1_name && !no_name)
907                 name_commits(seen, rev, ref_name, num_rev);
908
909         all_mask = ((1u << (REV_SHIFT + num_rev)) - 1);
910         all_revs = all_mask & ~((1u << REV_SHIFT) - 1);
911
912         while (seen) {
913                 struct commit *commit = pop_commit(&seen);
914                 int this_flag = commit->object.flags;
915                 int is_merge_point = ((this_flag & all_revs) == all_revs);
916
917                 shown_merge_point |= is_merge_point;
918
919                 if (1 < num_rev) {
920                         int is_merge = !!(commit->parents &&
921                                           commit->parents->next);
922                         if (topics &&
923                             !is_merge_point &&
924                             (this_flag & (1u << REV_SHIFT)))
925                                 continue;
926                         if (dense && is_merge &&
927                             omit_in_dense(commit, rev, num_rev))
928                                 continue;
929                         for (i = 0; i < num_rev; i++) {
930                                 int mark;
931                                 if (!(this_flag & (1u << (i + REV_SHIFT))))
932                                         mark = ' ';
933                                 else if (is_merge)
934                                         mark = '-';
935                                 else if (i == head_at)
936                                         mark = '*';
937                                 else
938                                         mark = '+';
939                                 printf("%s%c%s",
940                                        get_color_code(i),
941                                        mark, get_color_reset_code());
942                         }
943                         putchar(' ');
944                 }
945                 show_one_commit(commit, no_name);
946
947                 if (shown_merge_point && --extra < 0)
948                         break;
949         }
950         return 0;
951 }