Merge branch 'js/log-show-children'
authorJunio C Hamano <gitster@pobox.com>
Wed, 19 Oct 2011 04:59:12 +0000 (21:59 -0700)
committerJunio C Hamano <gitster@pobox.com>
Wed, 19 Oct 2011 04:59:12 +0000 (21:59 -0700)
* js/log-show-children:
  log --children

1  2 
log-tree.c

diff --combined log-tree.c
  #include "reflog-walk.h"
  #include "refs.h"
  #include "string-list.h"
 +#include "color.h"
  
  struct decoration name_decoration = { "object names" };
  
 -static void add_name_decoration(const char *prefix, const char *name, struct object *obj)
 +enum decoration_type {
 +      DECORATION_NONE = 0,
 +      DECORATION_REF_LOCAL,
 +      DECORATION_REF_REMOTE,
 +      DECORATION_REF_TAG,
 +      DECORATION_REF_STASH,
 +      DECORATION_REF_HEAD,
 +      DECORATION_GRAFTED,
 +};
 +
 +static char decoration_colors[][COLOR_MAXLEN] = {
 +      GIT_COLOR_RESET,
 +      GIT_COLOR_BOLD_GREEN,   /* REF_LOCAL */
 +      GIT_COLOR_BOLD_RED,     /* REF_REMOTE */
 +      GIT_COLOR_BOLD_YELLOW,  /* REF_TAG */
 +      GIT_COLOR_BOLD_MAGENTA, /* REF_STASH */
 +      GIT_COLOR_BOLD_CYAN,    /* REF_HEAD */
 +      GIT_COLOR_BOLD_BLUE,    /* GRAFTED */
 +};
 +
 +static const char *decorate_get_color(int decorate_use_color, enum decoration_type ix)
 +{
 +      if (want_color(decorate_use_color))
 +              return decoration_colors[ix];
 +      return "";
 +}
 +
 +static int parse_decorate_color_slot(const char *slot)
 +{
 +      /*
 +       * We're comparing with 'ignore-case' on
 +       * (because config.c sets them all tolower),
 +       * but let's match the letters in the literal
 +       * string values here with how they are
 +       * documented in Documentation/config.txt, for
 +       * consistency.
 +       *
 +       * We love being consistent, don't we?
 +       */
 +      if (!strcasecmp(slot, "branch"))
 +              return DECORATION_REF_LOCAL;
 +      if (!strcasecmp(slot, "remoteBranch"))
 +              return DECORATION_REF_REMOTE;
 +      if (!strcasecmp(slot, "tag"))
 +              return DECORATION_REF_TAG;
 +      if (!strcasecmp(slot, "stash"))
 +              return DECORATION_REF_STASH;
 +      if (!strcasecmp(slot, "HEAD"))
 +              return DECORATION_REF_HEAD;
 +      return -1;
 +}
 +
 +int parse_decorate_color_config(const char *var, const int ofs, const char *value)
 +{
 +      int slot = parse_decorate_color_slot(var + ofs);
 +      if (slot < 0)
 +              return 0;
 +      if (!value)
 +              return config_error_nonbool(var);
 +      color_parse(value, var, decoration_colors[slot]);
 +      return 0;
 +}
 +
 +/*
 + * log-tree.c uses DIFF_OPT_TST for determining whether to use color
 + * for showing the commit sha1, use the same check for --decorate
 + */
 +#define decorate_get_color_opt(o, ix) \
 +      decorate_get_color((o)->use_color, ix)
 +
 +static void add_name_decoration(enum decoration_type type, const char *name, struct object *obj)
  {
 -      int plen = strlen(prefix);
        int nlen = strlen(name);
 -      struct name_decoration *res = xmalloc(sizeof(struct name_decoration) + plen + nlen);
 -      memcpy(res->name, prefix, plen);
 -      memcpy(res->name + plen, name, nlen + 1);
 +      struct name_decoration *res = xmalloc(sizeof(struct name_decoration) + nlen);
 +      memcpy(res->name, name, nlen + 1);
 +      res->type = type;
        res->next = add_decoration(&name_decoration, obj, res);
  }
  
  static int add_ref_decoration(const char *refname, const unsigned char *sha1, int flags, void *cb_data)
  {
 -      struct object *obj = parse_object(sha1);
 +      struct object *obj;
 +      enum decoration_type type = DECORATION_NONE;
 +
 +      if (!prefixcmp(refname, "refs/replace/")) {
 +              unsigned char original_sha1[20];
 +              if (!read_replace_refs)
 +                      return 0;
 +              if (get_sha1_hex(refname + 13, original_sha1)) {
 +                      warning("invalid replace ref %s", refname);
 +                      return 0;
 +              }
 +              obj = parse_object(original_sha1);
 +              if (obj)
 +                      add_name_decoration(DECORATION_GRAFTED, "replaced", obj);
 +              return 0;
 +      }
 +
 +      obj = parse_object(sha1);
        if (!obj)
                return 0;
 +
 +      if (!prefixcmp(refname, "refs/heads/"))
 +              type = DECORATION_REF_LOCAL;
 +      else if (!prefixcmp(refname, "refs/remotes/"))
 +              type = DECORATION_REF_REMOTE;
 +      else if (!prefixcmp(refname, "refs/tags/"))
 +              type = DECORATION_REF_TAG;
 +      else if (!prefixcmp(refname, "refs/stash"))
 +              type = DECORATION_REF_STASH;
 +      else if (!prefixcmp(refname, "HEAD"))
 +              type = DECORATION_REF_HEAD;
 +
        if (!cb_data || *(int *)cb_data == DECORATE_SHORT_REFS)
                refname = prettify_refname(refname);
 -      add_name_decoration("", refname, obj);
 +      add_name_decoration(type, refname, obj);
        while (obj->type == OBJ_TAG) {
                obj = ((struct tag *)obj)->tagged;
                if (!obj)
                        break;
 -              add_name_decoration("tag: ", refname, obj);
 +              add_name_decoration(DECORATION_REF_TAG, refname, obj);
        }
        return 0;
  }
  
 +static int add_graft_decoration(const struct commit_graft *graft, void *cb_data)
 +{
 +      struct commit *commit = lookup_commit(graft->sha1);
 +      if (!commit)
 +              return 0;
 +      add_name_decoration(DECORATION_GRAFTED, "grafted", &commit->object);
 +      return 0;
 +}
 +
  void load_ref_decorations(int flags)
  {
        static int loaded;
                loaded = 1;
                for_each_ref(add_ref_decoration, &flags);
                head_ref(add_ref_decoration, &flags);
 +              for_each_commit_graft(add_graft_decoration, NULL);
        }
  }
  
@@@ -165,14 -56,18 +165,22 @@@ static void show_parents(struct commit 
        }
  }
  
+ static void show_children(struct rev_info *opt, struct commit *commit, int abbrev)
+ {
+       struct commit_list *p = lookup_decoration(&opt->children, &commit->object);
+       for ( ; p; p = p->next) {
+               printf(" %s", find_unique_abbrev(p->item->object.sha1, abbrev));
+       }
+ }
  void show_decorations(struct rev_info *opt, struct commit *commit)
  {
        const char *prefix;
        struct name_decoration *decoration;
 +      const char *color_commit =
 +              diff_get_color_opt(&opt->diffopt, DIFF_COMMIT);
 +      const char *color_reset =
 +              decorate_get_color_opt(&opt->diffopt, DECORATION_NONE);
  
        if (opt->show_source && commit->util)
                printf("\t%s", (char *) commit->util);
                return;
        prefix = " (";
        while (decoration) {
 -              printf("%s%s", prefix, decoration->name);
 +              printf("%s", prefix);
 +              fputs(decorate_get_color_opt(&opt->diffopt, decoration->type),
 +                    stdout);
 +              if (decoration->type == DECORATION_REF_TAG)
 +                      fputs("tag: ", stdout);
 +              printf("%s", decoration->name);
 +              fputs(color_reset, stdout);
 +              fputs(color_commit, stdout);
                prefix = ", ";
                decoration = decoration->next;
        }
@@@ -322,9 -210,8 +330,9 @@@ void log_write_email_headers(struct rev
        if (opt->total > 0) {
                static char buffer[64];
                snprintf(buffer, sizeof(buffer),
 -                       "Subject: [%s %0*d/%d] ",
 +                       "Subject: [%s%s%0*d/%d] ",
                         opt->subject_prefix,
 +                       *opt->subject_prefix ? " " : "",
                         digits_in_number(opt->total),
                         opt->nr, opt->total);
                subject = buffer;
@@@ -409,11 -296,23 +417,13 @@@ void show_log(struct rev_info *opt
        if (!opt->verbose_header) {
                graph_show_commit(opt->graph);
  
 -              if (!opt->graph) {
 -                      if (commit->object.flags & BOUNDARY)
 -                              putchar('-');
 -                      else if (commit->object.flags & UNINTERESTING)
 -                              putchar('^');
 -                      else if (opt->left_right) {
 -                              if (commit->object.flags & SYMMETRIC_LEFT)
 -                                      putchar('<');
 -                              else
 -                                      putchar('>');
 -                      }
 -              }
 +              if (!opt->graph)
 +                      put_revision_mark(opt, commit);
                fputs(find_unique_abbrev(commit->object.sha1, abbrev_commit), stdout);
                if (opt->print_parents)
                        show_parents(commit, abbrev_commit);
+               if (opt->children.name)
+                       show_children(opt, commit, abbrev_commit);
                show_decorations(opt, commit);
                if (opt->graph && !graph_is_commit_finished(opt->graph)) {
                        putchar('\n');
                if (opt->commit_format != CMIT_FMT_ONELINE)
                        fputs("commit ", stdout);
  
 -              if (!opt->graph) {
 -                      if (commit->object.flags & BOUNDARY)
 -                              putchar('-');
 -                      else if (commit->object.flags & UNINTERESTING)
 -                              putchar('^');
 -                      else if (opt->left_right) {
 -                              if (commit->object.flags & SYMMETRIC_LEFT)
 -                                      putchar('<');
 -                              else
 -                                      putchar('>');
 -                      }
 -              }
 +              if (!opt->graph)
 +                      put_revision_mark(opt, commit);
                fputs(find_unique_abbrev(commit->object.sha1, abbrev_commit),
                      stdout);
                if (opt->print_parents)
                        show_parents(commit, abbrev_commit);
+               if (opt->children.name)
+                       show_children(opt, commit, abbrev_commit);
                if (parent)
                        printf(" (from %s)",
                               find_unique_abbrev(parent->object.sha1,
        ctx.date_mode = opt->date_mode;
        ctx.abbrev = opt->diffopt.abbrev;
        ctx.after_subject = extra_headers;
 +      ctx.preserve_subject = opt->preserve_subject;
        ctx.reflog_info = opt->reflog_info;
 -      pretty_print_commit(opt->commit_format, commit, &msgbuf, &ctx);
 +      ctx.fmt = opt->commit_format;
 +      pretty_print_commit(&ctx, commit, &msgbuf);
  
        if (opt->add_signoff)
                append_signoff(&msgbuf, opt->add_signoff);
@@@ -572,12 -481,6 +584,12 @@@ int log_tree_diff_flush(struct rev_inf
                        int pch = DIFF_FORMAT_DIFFSTAT | DIFF_FORMAT_PATCH;
                        if ((pch & opt->diffopt.output_format) == pch)
                                printf("---");
 +                      if (opt->diffopt.output_prefix) {
 +                              struct strbuf *msg = NULL;
 +                              msg = opt->diffopt.output_prefix(&opt->diffopt,
 +                                      opt->diffopt.output_prefix_data);
 +                              fwrite(msg->buf, msg->len, 1, stdout);
 +                      }
                        putchar('\n');
                }
        }
@@@ -623,16 -526,6 +635,16 @@@ static int log_tree_diff(struct rev_inf
                        return 0;
                else if (opt->combine_merges)
                        return do_diff_combined(opt, commit);
 +              else if (opt->first_parent_only) {
 +                      /*
 +                       * Generate merge log entry only for the first
 +                       * parent, showing summary diff of the others
 +                       * we merged _in_.
 +                       */
 +                      diff_tree_sha1(parents->item->object.sha1, sha1, "", &opt->diffopt);
 +                      log_tree_diff_flush(opt);
 +                      return !opt->loginfo;
 +              }
  
                /* If we show individual diffs, show the parent info */
                log->parent = parents->item;