fixup tr/stash-format merge
authorJunio C Hamano <gitster@pobox.com>
Sat, 31 Oct 2009 03:18:31 +0000 (20:18 -0700)
committerJunio C Hamano <gitster@pobox.com>
Sat, 31 Oct 2009 03:18:31 +0000 (20:18 -0700)
1  2 
builtin-checkout.c
builtin-commit.c
commit.h
pretty.c
submodule.c
diff --combined builtin-checkout.c
index da04eed39104446c7c82dd846f8ddfd785d761e2,075a49f1a02fcdfb614a8482286cffe4100921c8..64f3a11ae1d415c466def8eccefe9dbc5b6b3926
@@@ -302,8 -302,9 +302,9 @@@ static void show_local_changes(struct o
  static void describe_detached_head(char *msg, struct commit *commit)
  {
        struct strbuf sb = STRBUF_INIT;
+       struct pretty_print_context ctx = {0};
        parse_commit(commit);
-       pretty_print_commit(CMIT_FMT_ONELINE, commit, &sb, 0, NULL, NULL, 0, 0);
+       pretty_print_commit(CMIT_FMT_ONELINE, commit, &sb, &ctx);
        fprintf(stderr, "%s %s... %s\n", msg,
                find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV), sb.buf);
        strbuf_release(&sb);
@@@ -572,40 -573,6 +573,40 @@@ static int interactive_checkout(const c
        return run_add_interactive(revision, "--patch=checkout", pathspec);
  }
  
 +struct tracking_name_data {
 +      const char *name;
 +      char *remote;
 +      int unique;
 +};
 +
 +static int check_tracking_name(const char *refname, const unsigned char *sha1,
 +                             int flags, void *cb_data)
 +{
 +      struct tracking_name_data *cb = cb_data;
 +      const char *slash;
 +
 +      if (prefixcmp(refname, "refs/remotes/"))
 +              return 0;
 +      slash = strchr(refname + 13, '/');
 +      if (!slash || strcmp(slash + 1, cb->name))
 +              return 0;
 +      if (cb->remote) {
 +              cb->unique = 0;
 +              return 0;
 +      }
 +      cb->remote = xstrdup(refname);
 +      return 0;
 +}
 +
 +static const char *unique_tracking_name(const char *name)
 +{
 +      struct tracking_name_data cb_data = { name, NULL, 1 };
 +      for_each_ref(check_tracking_name, &cb_data);
 +      if (cb_data.unique)
 +              return cb_data.remote;
 +      free(cb_data.remote);
 +      return NULL;
 +}
  
  int cmd_checkout(int argc, const char **argv, const char *prefix)
  {
        struct tree *source_tree = NULL;
        char *conflict_style = NULL;
        int patch_mode = 0;
 +      int dwim_new_local_branch = 1;
        struct option options[] = {
                OPT__QUIET(&opts.quiet),
                OPT_STRING('b', NULL, &opts.new_branch, "new branch", "branch"),
                OPT_STRING(0, "conflict", &conflict_style, "style",
                           "conflict style (merge or diff3)"),
                OPT_BOOLEAN('p', "patch", &patch_mode, "select hunks interactively"),
 +              { OPTION_BOOLEAN, 0, "guess", &dwim_new_local_branch, NULL,
 +                "second guess 'git checkout no-such-branch'",
 +                PARSE_OPT_NOARG | PARSE_OPT_HIDDEN },
                OPT_END(),
        };
        int has_dash_dash;
                opts.new_branch = argv0 + 1;
        }
  
 -      if (opts.track == BRANCH_TRACK_UNSPECIFIED)
 -              opts.track = git_branch_track;
        if (conflict_style) {
                opts.merge = 1; /* implied */
                git_xmerge_config("merge.conflictstyle", conflict_style, NULL);
         *   With no paths, if <something> is a commit, that is to
         *   switch to the branch or detach HEAD at it.
         *
 +       *   With no paths, if <something> is _not_ a commit, no -t nor -b
 +       *   was given, and there is a tracking branch whose name is
 +       *   <something> in one and only one remote, then this is a short-hand
 +       *   to fork local <something> from that remote tracking branch.
 +       *
         *   Otherwise <something> shall not be ambiguous.
         *   - If it's *only* a reference, treat it like case (1).
         *   - If it's only a path, treat it like case (2).
                if (get_sha1(arg, rev)) {
                        if (has_dash_dash)          /* case (1) */
                                die("invalid reference: %s", arg);
 -                      goto no_reference;          /* case (3 -> 2) */
 +                      if (!patch_mode &&
 +                          dwim_new_local_branch &&
 +                          opts.track == BRANCH_TRACK_UNSPECIFIED &&
 +                          !opts.new_branch &&
 +                          !check_filename(NULL, arg) &&
 +                          argc == 1) {
 +                              const char *remote = unique_tracking_name(arg);
 +                              if (!remote || get_sha1(remote, rev))
 +                                      goto no_reference;
 +                              opts.new_branch = arg;
 +                              arg = remote;
 +                              /* DWIMmed to create local branch */
 +                      }
 +                      else
 +                              goto no_reference;
                }
  
                /* we can't end up being in (2) anymore, eat the argument */
        }
  
  no_reference:
 +
 +      if (opts.track == BRANCH_TRACK_UNSPECIFIED)
 +              opts.track = git_branch_track;
 +
        if (argc) {
                const char **pathspec = get_pathspec(prefix, argv);
  
diff --combined builtin-commit.c
index c395cbf14f7e99880f39a63939dc174ba494004c,13edeee575e73e31cb0512e6be0e7b387c035e20..beddf01dd37e6644db7eb33b1b3aea2a74272783
@@@ -414,47 -414,6 +414,47 @@@ static void determine_author_info(void
        author_date = date;
  }
  
 +static int ends_rfc2822_footer(struct strbuf *sb)
 +{
 +      int ch;
 +      int hit = 0;
 +      int i, j, k;
 +      int len = sb->len;
 +      int first = 1;
 +      const char *buf = sb->buf;
 +
 +      for (i = len - 1; i > 0; i--) {
 +              if (hit && buf[i] == '\n')
 +                      break;
 +              hit = (buf[i] == '\n');
 +      }
 +
 +      while (i < len - 1 && buf[i] == '\n')
 +              i++;
 +
 +      for (; i < len; i = k) {
 +              for (k = i; k < len && buf[k] != '\n'; k++)
 +                      ; /* do nothing */
 +              k++;
 +
 +              if ((buf[k] == ' ' || buf[k] == '\t') && !first)
 +                      continue;
 +
 +              first = 0;
 +
 +              for (j = 0; i + j < len; j++) {
 +                      ch = buf[i + j];
 +                      if (ch == ':')
 +                              break;
 +                      if (isalnum(ch) ||
 +                          (ch == '-'))
 +                              continue;
 +                      return 0;
 +              }
 +      }
 +      return 1;
 +}
 +
  static int prepare_to_commit(const char *index_file, const char *prefix,
                             struct wt_status *s)
  {
                for (i = sb.len - 1; i > 0 && sb.buf[i - 1] != '\n'; i--)
                        ; /* do nothing */
                if (prefixcmp(sb.buf + i, sob.buf)) {
 -                      if (prefixcmp(sb.buf + i, sign_off_header))
 +                      if (!ends_rfc2822_footer(&sb))
                                strbuf_addch(&sb, '\n');
                        strbuf_addbuf(&sb, &sob);
                }
@@@ -725,8 -684,10 +725,10 @@@ static const char *find_author_by_nickn
        prepare_revision_walk(&revs);
        commit = get_revision(&revs);
        if (commit) {
+               struct pretty_print_context ctx = {0};
+               ctx.date_mode = DATE_NORMAL;
                strbuf_release(&buf);
-               format_commit_message(commit, "%an <%ae>", &buf, DATE_NORMAL);
+               format_commit_message(commit, "%an <%ae>", &buf, &ctx);
                return strbuf_detach(&buf, NULL);
        }
        die("No existing author found with '%s'", name);
@@@ -983,8 -944,10 +985,10 @@@ static void print_summary(const char *p
                initial_commit ? " (root-commit)" : "");
  
        if (!log_tree_commit(&rev, commit)) {
+               struct pretty_print_context ctx = {0};
                struct strbuf buf = STRBUF_INIT;
-               format_commit_message(commit, format + 7, &buf, DATE_NORMAL);
+               ctx.date_mode = DATE_NORMAL;
+               format_commit_message(commit, format + 7, &buf, &ctx);
                printf("%s\n", buf.buf);
                strbuf_release(&buf);
        }
diff --combined commit.h
index 95f981a1a93989d89edb0c5b850fa86db2071b50,15cb64920cda9cb03d1309ea4201a0fe89b3ddae..422f778f3f5b997ea1a3d8569cf6fa573481fff1
+++ b/commit.h
@@@ -63,6 -63,16 +63,16 @@@ enum cmit_fmt 
        CMIT_FMT_UNSPECIFIED,
  };
  
+ struct pretty_print_context
+ {
+       int abbrev;
+       const char *subject;
+       const char *after_subject;
+       enum date_mode date_mode;
+       int need_8bit_cte;
+       struct reflog_walk_info *reflog_info;
+ };
  extern int non_ascii(int);
  extern int has_non_ascii(const char *text);
  struct rev_info; /* in revision.h, it circularly uses enum cmit_fmt */
@@@ -70,13 -80,11 +80,11 @@@ extern char *reencode_commit_message(co
                                     const char **encoding_p);
  extern void get_commit_format(const char *arg, struct rev_info *);
  extern void format_commit_message(const struct commit *commit,
 -                                const void *format, struct strbuf *sb,
 +                                const char *format, struct strbuf *sb,
-                                 enum date_mode dmode);
- extern void pretty_print_commit(enum cmit_fmt fmt, const struct commit*,
-                                 struct strbuf *,
-                                 int abbrev, const char *subject,
-                                 const char *after_subject, enum date_mode,
-                               int need_8bit_cte);
+                                 const struct pretty_print_context *context);
+ extern void pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit,
+                               struct strbuf *sb,
+                               const struct pretty_print_context *context);
  void pp_user_info(const char *what, enum cmit_fmt fmt, struct strbuf *sb,
                   const char *line, enum date_mode dmode,
                   const char *encoding);
diff --combined pretty.c
index 587101f846b945d7de219f468699e75565a7e9c0,fc65fca58a8403aa6080d827f5013b46ecb18921..da15cf2a80d08e38b4b0bb279e378b72dbe49cc7
+++ b/pretty.c
@@@ -7,6 -7,7 +7,7 @@@
  #include "mailmap.h"
  #include "log-tree.h"
  #include "color.h"
+ #include "reflog-walk.h"
  
  static char *user_format;
  
@@@ -442,7 -443,7 +443,7 @@@ struct chunk 
  
  struct format_commit_context {
        const struct commit *commit;
-       enum date_mode dmode;
+       const struct pretty_print_context *pretty_ctx;
        unsigned commit_header_parsed:1;
        unsigned commit_message_parsed:1;
  
@@@ -701,6 -702,22 +702,22 @@@ static size_t format_commit_item(struc
        case 'd':
                format_decoration(sb, commit);
                return 1;
+       case 'g':               /* reflog info */
+               switch(placeholder[1]) {
+               case 'd':       /* reflog selector */
+               case 'D':
+                       if (c->pretty_ctx->reflog_info)
+                               get_reflog_selector(sb,
+                                                   c->pretty_ctx->reflog_info,
+                                                   c->pretty_ctx->date_mode,
+                                                   (placeholder[1] == 'd'));
+                       return 2;
+               case 's':       /* reflog message */
+                       if (c->pretty_ctx->reflog_info)
+                               get_reflog_message(sb, c->pretty_ctx->reflog_info);
+                       return 2;
+               }
+               return 0;       /* unknown %g placeholder */
        }
  
        /* For the rest we have to parse the commit header. */
        case 'a':       /* author ... */
                return format_person_part(sb, placeholder[1],
                                   msg + c->author.off, c->author.len,
-                                  c->dmode);
+                                  c->pretty_ctx->date_mode);
        case 'c':       /* committer ... */
                return format_person_part(sb, placeholder[1],
                                   msg + c->committer.off, c->committer.len,
-                                  c->dmode);
+                                  c->pretty_ctx->date_mode);
        case 'e':       /* encoding */
                strbuf_add(sb, msg + c->encoding.off, c->encoding.len);
                return 1;
  }
  
  void format_commit_message(const struct commit *commit,
 -                         const void *format, struct strbuf *sb,
 +                         const char *format, struct strbuf *sb,
-                          enum date_mode dmode)
+                          const struct pretty_print_context *pretty_ctx)
  {
        struct format_commit_context context;
  
        memset(&context, 0, sizeof(context));
        context.commit = commit;
-       context.dmode = dmode;
+       context.pretty_ctx = pretty_ctx;
        strbuf_expand(sb, format, format_commit_item, &context);
  }
  
@@@ -900,18 -917,18 +917,18 @@@ char *reencode_commit_message(const str
  }
  
  void pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit,
-                        struct strbuf *sb, int abbrev,
-                        const char *subject, const char *after_subject,
-                        enum date_mode dmode, int need_8bit_cte)
+                        struct strbuf *sb,
+                        const struct pretty_print_context *context)
  {
        unsigned long beginning_of_body;
        int indent = 4;
        const char *msg = commit->buffer;
        char *reencoded;
        const char *encoding;
+       int need_8bit_cte = context->need_8bit_cte;
  
        if (fmt == CMIT_FMT_USERFORMAT) {
-               format_commit_message(commit, user_format, sb, dmode);
+               format_commit_message(commit, user_format, sb, context);
                return;
        }
  
                }
        }
  
-       pp_header(fmt, abbrev, dmode, encoding, commit, &msg, sb);
-       if (fmt != CMIT_FMT_ONELINE && !subject) {
+       pp_header(fmt, context->abbrev, context->date_mode, encoding,
+                 commit, &msg, sb);
+       if (fmt != CMIT_FMT_ONELINE && !context->subject) {
                strbuf_addch(sb, '\n');
        }
  
  
        /* These formats treat the title line specially. */
        if (fmt == CMIT_FMT_ONELINE || fmt == CMIT_FMT_EMAIL)
-               pp_title_line(fmt, &msg, sb, subject,
-                             after_subject, encoding, need_8bit_cte);
+               pp_title_line(fmt, &msg, sb, context->subject,
+                             context->after_subject, encoding, need_8bit_cte);
  
        beginning_of_body = sb->len;
        if (fmt != CMIT_FMT_ONELINE)
diff --combined submodule.c
index d5fce7a882e14f6154d56f38531ba5d9000dabda,0000000000000000000000000000000000000000..461faf0e000ee14cdd0bb3d40121e1d21833e30d
mode 100644,000000..100644
--- /dev/null
@@@ -1,113 -1,0 +1,114 @@@
-                       format_commit_message(commit, format, &sb,
-                                       rev.date_mode);
 +#include "cache.h"
 +#include "submodule.h"
 +#include "dir.h"
 +#include "diff.h"
 +#include "commit.h"
 +#include "revision.h"
 +
 +int add_submodule_odb(const char *path)
 +{
 +      struct strbuf objects_directory = STRBUF_INIT;
 +      struct alternate_object_database *alt_odb;
 +
 +      strbuf_addf(&objects_directory, "%s/.git/objects/", path);
 +      if (!is_directory(objects_directory.buf))
 +              return -1;
 +
 +      /* avoid adding it twice */
 +      for (alt_odb = alt_odb_list; alt_odb; alt_odb = alt_odb->next)
 +              if (alt_odb->name - alt_odb->base == objects_directory.len &&
 +                              !strncmp(alt_odb->base, objects_directory.buf,
 +                                      objects_directory.len))
 +                      return 0;
 +
 +      alt_odb = xmalloc(objects_directory.len + 42 + sizeof(*alt_odb));
 +      alt_odb->next = alt_odb_list;
 +      strcpy(alt_odb->base, objects_directory.buf);
 +      alt_odb->name = alt_odb->base + objects_directory.len;
 +      alt_odb->name[2] = '/';
 +      alt_odb->name[40] = '\0';
 +      alt_odb->name[41] = '\0';
 +      alt_odb_list = alt_odb;
 +      prepare_alt_odb();
 +      return 0;
 +}
 +
 +void show_submodule_summary(FILE *f, const char *path,
 +              unsigned char one[20], unsigned char two[20],
 +              const char *del, const char *add, const char *reset)
 +{
 +      struct rev_info rev;
 +      struct commit *commit, *left = left, *right;
 +      struct commit_list *merge_bases, *list;
 +      const char *message = NULL;
 +      struct strbuf sb = STRBUF_INIT;
 +      static const char *format = "  %m %s";
 +      int fast_forward = 0, fast_backward = 0;
 +
 +      if (is_null_sha1(two))
 +              message = "(submodule deleted)";
 +      else if (add_submodule_odb(path))
 +              message = "(not checked out)";
 +      else if (is_null_sha1(one))
 +              message = "(new submodule)";
 +      else if (!(left = lookup_commit_reference(one)) ||
 +               !(right = lookup_commit_reference(two)))
 +              message = "(commits not present)";
 +
 +      if (!message) {
 +              init_revisions(&rev, NULL);
 +              setup_revisions(0, NULL, &rev, NULL);
 +              rev.left_right = 1;
 +              rev.first_parent_only = 1;
 +              left->object.flags |= SYMMETRIC_LEFT;
 +              add_pending_object(&rev, &left->object, path);
 +              add_pending_object(&rev, &right->object, path);
 +              merge_bases = get_merge_bases(left, right, 1);
 +              if (merge_bases) {
 +                      if (merge_bases->item == left)
 +                              fast_forward = 1;
 +                      else if (merge_bases->item == right)
 +                              fast_backward = 1;
 +              }
 +              for (list = merge_bases; list; list = list->next) {
 +                      list->item->object.flags |= UNINTERESTING;
 +                      add_pending_object(&rev, &list->item->object,
 +                              sha1_to_hex(list->item->object.sha1));
 +              }
 +              if (prepare_revision_walk(&rev))
 +                      message = "(revision walker failed)";
 +      }
 +
 +      strbuf_addf(&sb, "Submodule %s %s..", path,
 +                      find_unique_abbrev(one, DEFAULT_ABBREV));
 +      if (!fast_backward && !fast_forward)
 +              strbuf_addch(&sb, '.');
 +      strbuf_addf(&sb, "%s", find_unique_abbrev(two, DEFAULT_ABBREV));
 +      if (message)
 +              strbuf_addf(&sb, " %s\n", message);
 +      else
 +              strbuf_addf(&sb, "%s:\n", fast_backward ? " (rewind)" : "");
 +      fwrite(sb.buf, sb.len, 1, f);
 +
 +      if (!message) {
 +              while ((commit = get_revision(&rev))) {
++                      struct pretty_print_context ctx = {0};
++                      ctx.date_mode = rev.date_mode;
 +                      strbuf_setlen(&sb, 0);
 +                      if (commit->object.flags & SYMMETRIC_LEFT) {
 +                              if (del)
 +                                      strbuf_addstr(&sb, del);
 +                      }
 +                      else if (add)
 +                              strbuf_addstr(&sb, add);
++                      format_commit_message(commit, format, &sb, &ctx);
 +                      if (reset)
 +                              strbuf_addstr(&sb, reset);
 +                      strbuf_addch(&sb, '\n');
 +                      fprintf(f, "%s", sb.buf);
 +              }
 +              clear_commit_marks(left, ~0);
 +              clear_commit_marks(right, ~0);
 +      }
 +      strbuf_release(&sb);
 +}