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