Merge branch 'maint'
authorJunio C Hamano <junkio@cox.net>
Sun, 6 May 2007 07:21:03 +0000 (00:21 -0700)
committerJunio C Hamano <junkio@cox.net>
Sun, 6 May 2007 07:21:03 +0000 (00:21 -0700)
* maint:
Small correction in reading of commit headers
Documentation: fix typo in git-remote.txt
Add test for blame corner cases.
blame: -C -C -C
blame: Notice a wholesale incorporation of an existing file.
Fix --boundary output
diff format documentation: describe raw combined diff format
Mention version 1.5.1 in tutorial and user-manual
Add --no-rebase option to git-svn dcommit
Fix markup in git-svn man page

1  2 
builtin-blame.c
commit.c
log-tree.c
diff --combined builtin-blame.c
index 6d6a577d684df82870c3b4e916c8e3d21abdeb3b,65d029a773691f994711478bc2475681093e0088..35471fc2615992451c8c5b51a346fe171029b572
  #include "quote.h"
  #include "xdiff-interface.h"
  #include "cache-tree.h"
 +#include "path-list.h"
 +#include "mailmap.h"
  
  static char blame_usage[] =
 -"git-blame [-c] [-l] [-t] [-f] [-n] [-p] [-L n,m] [-S <revs-file>] [-M] [-C] [-C] [--contents <filename>] [--incremental] [commit] [--] file\n"
 +"git-blame [-c] [-b] [-l] [--root] [-t] [-f] [-n] [-s] [-p] [-L n,m] [-S <revs-file>] [-M] [-C] [-C] [--contents <filename>] [--incremental] [commit] [--] file\n"
  "  -c                  Use the same output mode as git-annotate (Default: off)\n"
  "  -b                  Show blank SHA-1 for boundary commits (Default: off)\n"
  "  -l                  Show long commit SHA1 (Default: off)\n"
@@@ -28,7 -26,6 +28,7 @@@
  "  -t                  Show raw timestamp (Default: off)\n"
  "  -f, --show-name     Show original filename (Default: auto)\n"
  "  -n, --show-number   Show original linenumber (Default: off)\n"
 +"  -s                  Suppress author name and timestamp (Default: off)\n"
  "  -p, --porcelain     Show in a format designed for machine consumption\n"
  "  -L n,m              Process only line range n,m, counting from 1\n"
  "  -M, -C              Find line movements within and across files\n"
@@@ -45,7 -42,6 +45,7 @@@ static int show_root
  static int blank_boundary;
  static int incremental;
  static int cmd_is_annotate;
 +static struct path_list mailmap;
  
  #ifndef DEBUG
  #define DEBUG 0
@@@ -59,6 -55,7 +59,7 @@@ static int num_commits
  #define PICKAXE_BLAME_MOVE            01
  #define PICKAXE_BLAME_COPY            02
  #define PICKAXE_BLAME_COPY_HARDER     04
+ #define PICKAXE_BLAME_COPY_HARDEST    010
  
  /*
   * blame for a blame_entry with score lower than these thresholds
@@@ -894,6 -891,39 +895,39 @@@ static void copy_split_if_better(struc
        memcpy(best_so_far, this, sizeof(struct blame_entry [3]));
  }
  
+ /*
+  * We are looking at a part of the final image represented by
+  * ent (tlno and same are offset by ent->s_lno).
+  * tlno is where we are looking at in the final image.
+  * up to (but not including) same match preimage.
+  * plno is where we are looking at in the preimage.
+  *
+  * <-------------- final image ---------------------->
+  *       <------ent------>
+  *         ^tlno ^same
+  *    <---------preimage----->
+  *         ^plno
+  *
+  * All line numbers are 0-based.
+  */
+ static void handle_split(struct scoreboard *sb,
+                        struct blame_entry *ent,
+                        int tlno, int plno, int same,
+                        struct origin *parent,
+                        struct blame_entry *split)
+ {
+       if (ent->num_lines <= tlno)
+               return;
+       if (tlno < same) {
+               struct blame_entry this[3];
+               tlno += ent->s_lno;
+               same += ent->s_lno;
+               split_overlap(this, ent, tlno, plno, same, parent);
+               copy_split_if_better(sb, split, this);
+               decref_split(this);
+       }
+ }
  /*
   * Find the lines from parent that are the same as ent so that
   * we can pass blames to it.  file_p has the blob contents for
@@@ -926,26 -956,21 +960,21 @@@ static void find_copy_in_blob(struct sc
  
        patch = compare_buffer(file_p, &file_o, 1);
  
+       /*
+        * file_o is a part of final image we are annotating.
+        * file_p partially may match that image.
+        */
        memset(split, 0, sizeof(struct blame_entry [3]));
        plno = tlno = 0;
        for (i = 0; i < patch->num; i++) {
                struct chunk *chunk = &patch->chunks[i];
  
-               /* tlno to chunk->same are the same as ent */
-               if (ent->num_lines <= tlno)
-                       break;
-               if (tlno < chunk->same) {
-                       struct blame_entry this[3];
-                       split_overlap(this, ent,
-                                     tlno + ent->s_lno, plno,
-                                     chunk->same + ent->s_lno,
-                                     parent);
-                       copy_split_if_better(sb, split, this);
-                       decref_split(this);
-               }
+               handle_split(sb, ent, tlno, plno, chunk->same, parent, split);
                plno = chunk->p_next;
                tlno = chunk->t_next;
        }
+       /* remainder, if any, all match the preimage */
+       handle_split(sb, ent, tlno, plno, ent->num_lines, parent, split);
        free_patch(patch);
  }
  
@@@ -1055,8 -1080,9 +1084,9 @@@ static int find_copy_in_parent(struct s
         * and this code needs to be after diff_setup_done(), which
         * usually makes find-copies-harder imply copy detection.
         */
-       if ((opt & PICKAXE_BLAME_COPY_HARDER) &&
-           (!porigin || strcmp(target->path, porigin->path)))
+       if ((opt & PICKAXE_BLAME_COPY_HARDEST)
+           || ((opt & PICKAXE_BLAME_COPY_HARDER)
+               && (!porigin || strcmp(target->path, porigin->path))))
                diff_opts.find_copies_harder = 1;
  
        if (is_null_sha1(target->commit->object.sha1))
@@@ -1268,8 -1294,8 +1298,8 @@@ static void get_ac_line(const char *inb
                        int bufsz, char *person, const char **mail,
                        unsigned long *time, const char **tz)
  {
 -      int len;
 -      char *tmp, *endp;
 +      int len, tzlen, maillen;
 +      char *tmp, *endp, *timepos;
  
        tmp = strstr(inbuf, what);
        if (!tmp)
        while (*tmp != ' ')
                tmp--;
        *tz = tmp+1;
 +      tzlen = (person+len)-(tmp+1);
  
        *tmp = 0;
        while (*tmp != ' ')
                tmp--;
        *time = strtoul(tmp, NULL, 10);
 +      timepos = tmp;
  
        *tmp = 0;
        while (*tmp != ' ')
                tmp--;
        *mail = tmp + 1;
        *tmp = 0;
 +      maillen = timepos - tmp;
 +
 +      if (!mailmap.nr)
 +              return;
 +
 +      /*
 +       * mailmap expansion may make the name longer.
 +       * make room by pushing stuff down.
 +       */
 +      tmp = person + bufsz - (tzlen + 1);
 +      memmove(tmp, *tz, tzlen);
 +      tmp[tzlen] = 0;
 +      *tz = tmp;
 +
 +      tmp = tmp - (maillen + 1);
 +      memmove(tmp, *mail, maillen);
 +      tmp[maillen] = 0;
 +      *mail = tmp;
 +
 +      /*
 +       * Now, convert e-mail using mailmap
 +       */
 +      map_email(&mailmap, tmp + 1, person, tmp-person-1);
  }
  
  static void get_commit_info(struct commit *commit,
@@@ -1512,7 -1513,6 +1542,7 @@@ static const char *format_time(unsigne
  #define OUTPUT_SHOW_NAME      020
  #define OUTPUT_SHOW_NUMBER    040
  #define OUTPUT_SHOW_SCORE      0100
 +#define OUTPUT_NO_AUTHOR       0200
  
  static void emit_porcelain(struct scoreboard *sb, struct blame_entry *ent)
  {
@@@ -1607,15 -1607,10 +1637,15 @@@ static void emit_other(struct scoreboar
                        if (opt & OUTPUT_SHOW_NUMBER)
                                printf(" %*d", max_orig_digits,
                                       ent->s_lno + 1 + cnt);
 -                      printf(" (%-*.*s %10s %*d) ",
 -                             longest_author, longest_author, ci.author,
 -                             format_time(ci.author_time, ci.author_tz,
 -                                         show_raw_time),
 +
 +                      if (!(opt & OUTPUT_NO_AUTHOR))
 +                              printf(" (%-*.*s %10s",
 +                                     longest_author, longest_author,
 +                                     ci.author,
 +                                     format_time(ci.author_time,
 +                                                 ci.author_tz,
 +                                                 show_raw_time));
 +                      printf(" %*d) ",
                               max_digits, ent->lno + 1 + cnt);
                }
                do {
@@@ -2127,8 -2122,6 +2157,8 @@@ int cmd_blame(int argc, const char **ar
                        output_option |= OUTPUT_RAW_TIMESTAMP;
                else if (!strcmp("-l", arg))
                        output_option |= OUTPUT_LONG_OBJECT_NAME;
 +              else if (!strcmp("-s", arg))
 +                      output_option |= OUTPUT_NO_AUTHOR;
                else if (!strcmp("-S", arg) && ++i < argc)
                        revs_file = argv[i];
                else if (!prefixcmp(arg, "-M")) {
                        blame_move_score = parse_score(arg+2);
                }
                else if (!prefixcmp(arg, "-C")) {
+                       /*
+                        * -C enables copy from removed files;
+                        * -C -C enables copy from existing files, but only
+                        *       when blaming a new file;
+                        * -C -C -C enables copy from existing files for
+                        *          everybody
+                        */
+                       if (opt & PICKAXE_BLAME_COPY_HARDER)
+                               opt |= PICKAXE_BLAME_COPY_HARDEST;
                        if (opt & PICKAXE_BLAME_COPY)
                                opt |= PICKAXE_BLAME_COPY_HARDER;
                        opt |= PICKAXE_BLAME_COPY | PICKAXE_BLAME_MOVE;
                die("reading graft file %s failed: %s",
                    revs_file, strerror(errno));
  
 +      read_mailmap(&mailmap, ".mailmap", NULL);
 +
        assign_blame(&sb, &revs, opt);
  
        if (incremental)
diff --combined commit.c
index aa7059c1c6dd7650aa0623443372cfa804a0787c,7d78e786e9a6a6a3566cb7aa6555a815d79f9e4b..d01833d8137ece2f4a1d95d8b85d8ed54ecbd16b
+++ b/commit.c
@@@ -4,8 -4,6 +4,8 @@@
  #include "pkt-line.h"
  #include "utf8.h"
  #include "interpolate.h"
 +#include "diff.h"
 +#include "revision.h"
  
  int save_commit_buffer = 1;
  
@@@ -98,8 -96,12 +98,8 @@@ struct commit *lookup_commit_reference(
  struct commit *lookup_commit(const unsigned char *sha1)
  {
        struct object *obj = lookup_object(sha1);
 -      if (!obj) {
 -              struct commit *ret = alloc_commit_node();
 -              created_object(sha1, &ret->object);
 -              ret->object.type = OBJ_COMMIT;
 -              return ret;
 -      }
 +      if (!obj)
 +              return create_object(sha1, OBJ_COMMIT, alloc_commit_node());
        if (!obj->type)
                obj->type = OBJ_COMMIT;
        return check_commit(obj, sha1, 0);
@@@ -526,7 -528,7 +526,7 @@@ static int add_rfc2047(char *buf, cons
  }
  
  static int add_user_info(const char *what, enum cmit_fmt fmt, char *buf,
 -                       const char *line, int relative_date,
 +                       const char *line, enum date_mode dmode,
                         const char *encoding)
  {
        char *date;
        switch (fmt) {
        case CMIT_FMT_MEDIUM:
                ret += sprintf(buf + ret, "Date:   %s\n",
 -                             show_date(time, tz, relative_date));
 +                             show_date(time, tz, dmode));
                break;
        case CMIT_FMT_EMAIL:
                ret += sprintf(buf + ret, "Date: %s\n",
                break;
        case CMIT_FMT_FULLER:
                ret += sprintf(buf + ret, "%sDate: %s\n", what,
 -                             show_date(time, tz, relative_date));
 +                             show_date(time, tz, dmode));
                break;
        default:
                /* notin' */
@@@ -638,7 -640,9 +638,9 @@@ static char *get_header(const struct co
                        next = NULL;
                } else
                        next = eol + 1;
-               if (!strncmp(line, key, key_len) && line[key_len] == ' ') {
+               if (eol - line > key_len &&
+                   !strncmp(line, key, key_len) &&
+                   line[key_len] == ' ') {
                        int len = eol - line - key_len;
                        char *ret = xmalloc(len);
                        memcpy(ret, line + key_len + 1, len - 1);
@@@ -798,8 -802,7 +800,8 @@@ static long format_commit_message(cons
                { "%Cgreen" },  /* green */
                { "%Cblue" },   /* blue */
                { "%Creset" },  /* reset color */
 -              { "%n" }        /* newline */
 +              { "%n" },       /* newline */
 +              { "%m" },       /* left/right/bottom */
        };
        enum interp_index {
                IHASH = 0, IHASH_ABBREV,
                ISUBJECT,
                IBODY,
                IRED, IGREEN, IBLUE, IRESET_COLOR,
 -              INEWLINE
 +              INEWLINE,
 +              ILEFT_RIGHT,
        };
        struct commit_list *p;
        char parents[1024];
        int i;
        enum { HEADER, SUBJECT, BODY } state;
  
 -      if (INEWLINE + 1 != ARRAY_SIZE(table))
 +      if (ILEFT_RIGHT + 1 != ARRAY_SIZE(table))
                die("invalid interp table!");
  
        /* these are independent of the commit */
        interp_set_entry(table, ITREE_ABBREV,
                        find_unique_abbrev(commit->tree->object.sha1,
                                DEFAULT_ABBREV));
 +      interp_set_entry(table, ILEFT_RIGHT,
 +                       (commit->object.flags & BOUNDARY)
 +                       ? "-"
 +                       : (commit->object.flags & SYMMETRIC_LEFT)
 +                       ? "<"
 +                       : ">");
  
        parents[1] = 0;
        for (i = 0, p = commit->parents;
@@@ -911,7 -907,7 +913,7 @@@ unsigned long pretty_print_commit(enum 
                                  char *buf, unsigned long space,
                                  int abbrev, const char *subject,
                                  const char *after_subject,
 -                                int relative_date)
 +                                enum date_mode dmode)
  {
        int hdr = 1, body = 0, seen_title = 0;
        unsigned long offset = 0;
                                offset += add_user_info("Author", fmt,
                                                        buf + offset,
                                                        line + 7,
 -                                                      relative_date,
 +                                                      dmode,
                                                        encoding);
                        if (!memcmp(line, "committer ", 10) &&
                            (fmt == CMIT_FMT_FULL || fmt == CMIT_FMT_FULLER))
                                offset += add_user_info("Commit", fmt,
                                                        buf + offset,
                                                        line + 10,
 -                                                      relative_date,
 +                                                      dmode,
                                                        encoding);
                        continue;
                }
diff --combined log-tree.c
index c679324c073b50a083daec568e4832e74a8bf4f3,dbd06490f97c735171974f068b48dbdbbb992723..4bef909144b2b5b402ee7cf0d959a0995c00ff0e
@@@ -4,8 -4,6 +4,8 @@@
  #include "log-tree.h"
  #include "reflog-walk.h"
  
 +struct decoration name_decoration = { "object names" };
 +
  static void show_parents(struct commit *commit, int abbrev)
  {
        struct commit_list *p;
        }
  }
  
 +static void show_decorations(struct commit *commit)
 +{
 +      const char *prefix;
 +      struct name_decoration *decoration;
 +
 +      decoration = lookup_decoration(&name_decoration, &commit->object);
 +      if (!decoration)
 +              return;
 +      prefix = " (";
 +      while (decoration) {
 +              printf("%s%s", prefix, decoration->name);
 +              prefix = ", ";
 +              decoration = decoration->next;
 +      }
 +      putchar(')');
 +}
 +
  /*
   * Search for "^[-A-Za-z]+: [^@]+@" pattern. It usually matches
   * Signed-off-by: and Acked-by: lines.
@@@ -155,7 -136,6 +155,7 @@@ void show_log(struct rev_info *opt, con
                fputs(diff_unique_abbrev(commit->object.sha1, abbrev_commit), stdout);
                if (opt->parents)
                        show_parents(commit, abbrev_commit);
 +              show_decorations(commit);
                putchar(opt->diffopt.line_termination);
                return;
        }
                if (opt->total > 0) {
                        static char buffer[64];
                        snprintf(buffer, sizeof(buffer),
 -                                      "Subject: [PATCH %0*d/%d] ",
 +                                      "Subject: [%s %0*d/%d] ",
 +                                      opt->subject_prefix,
                                        digits_in_number(opt->total),
                                        opt->nr, opt->total);
                        subject = buffer;
 -              } else if (opt->total == 0)
 -                      subject = "Subject: [PATCH] ";
 -              else
 +              } else if (opt->total == 0) {
 +                      static char buffer[256];
 +                      snprintf(buffer, sizeof(buffer),
 +                                      "Subject: [%s] ",
 +                                      opt->subject_prefix);
 +                      subject = buffer;
 +              } else {
                        subject = "Subject: ";
 +              }
  
                printf("From %s Mon Sep 17 00:00:00 2001\n", sha1);
                if (opt->message_id)
                      stdout);
                if (opt->commit_format != CMIT_FMT_ONELINE)
                        fputs("commit ", stdout);
-               if (opt->left_right) {
-                       if (commit->object.flags & BOUNDARY)
-                               putchar('-');
-                       else if (commit->object.flags & SYMMETRIC_LEFT)
+               if (commit->object.flags & BOUNDARY)
+                       putchar('-');
+               else if (opt->left_right) {
+                       if (commit->object.flags & SYMMETRIC_LEFT)
                                putchar('<');
                        else
                                putchar('>');
                        printf(" (from %s)",
                               diff_unique_abbrev(parent->object.sha1,
                                                  abbrev_commit));
 +              show_decorations(commit);
                printf("%s",
                       diff_get_color(opt->diffopt.color_diff, DIFF_RESET));
                putchar(opt->commit_format == CMIT_FMT_ONELINE ? ' ' : '\n');
                if (opt->reflog_info) {
                        show_reflog_message(opt->reflog_info,
                                    opt->commit_format == CMIT_FMT_ONELINE,
 -                                  opt->relative_date);
 +                                  opt->date_mode);
                        if (opt->commit_format == CMIT_FMT_ONELINE) {
                                printf("%s", sep);
                                return;
         */
        len = pretty_print_commit(opt->commit_format, commit, ~0u, this_header,
                                  sizeof(this_header), abbrev, subject,
 -                                extra_headers, opt->relative_date);
 +                                extra_headers, opt->date_mode);
  
        if (opt->add_signoff)
                len = append_signoff(this_header, sizeof(this_header), len,