Merge branch 'nd/stop-setenv-work-tree'
[gitweb.git] / builtin / blame.c
index eaa2c4260375370cb5fb15bf2ea600b39d4d8cf7..1df13cf7f4b501ed82dcbffdf4620706591a245e 100644 (file)
@@ -6,6 +6,7 @@
  */
 
 #include "cache.h"
+#include "refs.h"
 #include "builtin.h"
 #include "blob.h"
 #include "commit.h"
@@ -50,7 +51,7 @@ static int xdl_opts;
 static int abbrev = -1;
 static int no_whole_file_rename;
 
-static enum date_mode blame_date_mode = DATE_ISO8601;
+static struct date_mode blame_date_mode = { DATE_ISO8601 };
 static size_t blame_date_width;
 
 static struct string_list mailmap;
@@ -458,12 +459,13 @@ static void queue_blames(struct scoreboard *sb, struct origin *porigin,
 static struct origin *make_origin(struct commit *commit, const char *path)
 {
        struct origin *o;
-       o = xcalloc(1, sizeof(*o) + strlen(path) + 1);
+       size_t pathlen = strlen(path) + 1;
+       o = xcalloc(1, sizeof(*o) + pathlen);
        o->commit = commit;
        o->refcnt = 1;
        o->next = commit->util;
        commit->util = o;
-       strcpy(o->path, path);
+       memcpy(o->path, path, pathlen); /* includes NUL */
        return o;
 }
 
@@ -504,7 +506,7 @@ static int fill_blob_sha1_and_mode(struct origin *origin)
 {
        if (!is_null_sha1(origin->blob_sha1))
                return 0;
-       if (get_tree_entry(origin->commit->object.sha1,
+       if (get_tree_entry(origin->commit->object.oid.hash,
                           origin->path,
                           origin->blob_sha1, &origin->mode))
                goto error_out;
@@ -555,11 +557,11 @@ static struct origin *find_origin(struct scoreboard *sb,
                       PATHSPEC_LITERAL_PATH, "", paths);
        diff_setup_done(&diff_opts);
 
-       if (is_null_sha1(origin->commit->object.sha1))
-               do_diff_cache(parent->tree->object.sha1, &diff_opts);
+       if (is_null_oid(&origin->commit->object.oid))
+               do_diff_cache(parent->tree->object.oid.hash, &diff_opts);
        else
-               diff_tree_sha1(parent->tree->object.sha1,
-                              origin->commit->tree->object.sha1,
+               diff_tree_sha1(parent->tree->object.oid.hash,
+                              origin->commit->tree->object.oid.hash,
                               "", &diff_opts);
        diffcore_std(&diff_opts);
 
@@ -625,11 +627,11 @@ static struct origin *find_rename(struct scoreboard *sb,
        diff_opts.single_follow = origin->path;
        diff_setup_done(&diff_opts);
 
-       if (is_null_sha1(origin->commit->object.sha1))
-               do_diff_cache(parent->tree->object.sha1, &diff_opts);
+       if (is_null_oid(&origin->commit->object.oid))
+               do_diff_cache(parent->tree->object.oid.hash, &diff_opts);
        else
-               diff_tree_sha1(parent->tree->object.sha1,
-                              origin->commit->tree->object.sha1,
+               diff_tree_sha1(parent->tree->object.oid.hash,
+                              origin->commit->tree->object.oid.hash,
                               "", &diff_opts);
        diffcore_std(&diff_opts);
 
@@ -973,7 +975,10 @@ static void pass_blame_to_parent(struct scoreboard *sb,
        fill_origin_blob(&sb->revs->diffopt, target, &file_o);
        num_get_patch++;
 
-       diff_hunks(&file_p, &file_o, 0, blame_chunk_cb, &d);
+       if (diff_hunks(&file_p, &file_o, 0, blame_chunk_cb, &d))
+               die("unable to generate diff (%s -> %s)",
+                   oid_to_hex(&parent->commit->object.oid),
+                   oid_to_hex(&target->commit->object.oid));
        /* The rest are the same as the parent */
        blame_chunk(&d.dstq, &d.srcq, INT_MAX, d.offset, INT_MAX, parent);
        *d.dstq = NULL;
@@ -1119,7 +1124,9 @@ static void find_copy_in_blob(struct scoreboard *sb,
         * file_p partially may match that image.
         */
        memset(split, 0, sizeof(struct blame_entry [3]));
-       diff_hunks(file_p, &file_o, 1, handle_split_cb, &d);
+       if (diff_hunks(file_p, &file_o, 1, handle_split_cb, &d))
+               die("unable to generate diff (%s)",
+                   oid_to_hex(&parent->commit->object.oid));
        /* remainder, if any, all match the preimage */
        handle_split(sb, ent, d.tlno, d.plno, ent->num_lines, parent, split);
 }
@@ -1268,11 +1275,11 @@ static void find_copy_in_parent(struct scoreboard *sb,
                && (!porigin || strcmp(target->path, porigin->path))))
                DIFF_OPT_SET(&diff_opts, FIND_COPIES_HARDER);
 
-       if (is_null_sha1(target->commit->object.sha1))
-               do_diff_cache(parent->tree->object.sha1, &diff_opts);
+       if (is_null_oid(&target->commit->object.oid))
+               do_diff_cache(parent->tree->object.oid.hash, &diff_opts);
        else
-               diff_tree_sha1(parent->tree->object.sha1,
-                              target->commit->tree->object.sha1,
+               diff_tree_sha1(parent->tree->object.oid.hash,
+                              target->commit->tree->object.oid.hash,
                               "", &diff_opts);
 
        if (!DIFF_OPT_TST(&diff_opts, FIND_COPIES_HARDER))
@@ -1683,7 +1690,7 @@ static void get_commit_info(struct commit *commit,
        if (len)
                strbuf_add(&ret->summary, subject, len);
        else
-               strbuf_addf(&ret->summary, "(%s)", sha1_to_hex(commit->object.sha1));
+               strbuf_addf(&ret->summary, "(%s)", oid_to_hex(&commit->object.oid));
 
        unuse_commit_buffer(commit, message);
 }
@@ -1726,7 +1733,7 @@ static int emit_one_suspect_detail(struct origin *suspect, int repeat)
                printf("boundary\n");
        if (suspect->previous) {
                struct origin *prev = suspect->previous;
-               printf("previous %s ", sha1_to_hex(prev->commit->object.sha1));
+               printf("previous %s ", oid_to_hex(&prev->commit->object.oid));
                write_name_quoted(prev->path, stdout, '\n');
        }
 
@@ -1745,7 +1752,7 @@ static void found_guilty_entry(struct blame_entry *ent)
                struct origin *suspect = ent->suspect;
 
                printf("%s %d %d %d\n",
-                      sha1_to_hex(suspect->commit->object.sha1),
+                      oid_to_hex(&suspect->commit->object.oid),
                       ent->s_lno + 1, ent->lno + 1, ent->num_lines);
                emit_one_suspect_detail(suspect, 0);
                write_filename_info(suspect->path);
@@ -1834,7 +1841,7 @@ static const char *format_time(unsigned long time, const char *tz_str,
                size_t time_width;
                int tz;
                tz = atoi(tz_str);
-               time_str = show_date(time, tz, blame_date_mode);
+               time_str = show_date(time, tz, &blame_date_mode);
                strbuf_addstr(&time_buf, time_str);
                /*
                 * Add space paddings to time_buf to display a fixed width
@@ -1873,9 +1880,9 @@ static void emit_porcelain(struct scoreboard *sb, struct blame_entry *ent,
        int cnt;
        const char *cp;
        struct origin *suspect = ent->suspect;
-       char hex[41];
+       char hex[GIT_SHA1_HEXSZ + 1];
 
-       strcpy(hex, sha1_to_hex(suspect->commit->object.sha1));
+       sha1_to_hex_r(hex, suspect->commit->object.oid.hash);
        printf("%s %d %d %d\n",
               hex,
               ent->s_lno + 1,
@@ -1911,11 +1918,11 @@ static void emit_other(struct scoreboard *sb, struct blame_entry *ent, int opt)
        const char *cp;
        struct origin *suspect = ent->suspect;
        struct commit_info ci;
-       char hex[41];
+       char hex[GIT_SHA1_HEXSZ + 1];
        int show_raw_time = !!(opt & OUTPUT_RAW_TIMESTAMP);
 
        get_commit_info(suspect->commit, &ci, 1);
-       strcpy(hex, sha1_to_hex(suspect->commit->object.sha1));
+       sha1_to_hex_r(hex, suspect->commit->object.oid.hash);
 
        cp = nth_line(sb, ent->lno);
        for (cnt = 0; cnt < ent->num_lines; cnt++) {
@@ -2070,7 +2077,7 @@ static int read_ancestry(const char *graft_file)
 
 static int update_auto_abbrev(int auto_abbrev, struct origin *suspect)
 {
-       const char *uniq = find_unique_abbrev(suspect->commit->object.sha1,
+       const char *uniq = find_unique_abbrev(suspect->commit->object.oid.hash,
                                              auto_abbrev);
        int len = strlen(uniq);
        if (auto_abbrev < len)
@@ -2146,7 +2153,7 @@ static void sanity_check_refcnt(struct scoreboard *sb)
                if (ent->suspect->refcnt <= 0) {
                        fprintf(stderr, "%s in %s has negative refcnt %d\n",
                                ent->suspect->path,
-                               sha1_to_hex(ent->suspect->commit->object.sha1),
+                               oid_to_hex(&ent->suspect->commit->object.oid),
                                ent->suspect->refcnt);
                        baa = 1;
                }
@@ -2194,7 +2201,7 @@ static int git_blame_config(const char *var, const char *value, void *cb)
        if (!strcmp(var, "blame.date")) {
                if (!value)
                        return config_error_nonbool(var);
-               blame_date_mode = parse_date_format(value);
+               parse_date_format(value, &blame_date_mode);
                return 0;
        }
 
@@ -2209,7 +2216,7 @@ static void verify_working_tree_path(struct commit *work_tree, const char *path)
        struct commit_list *parents;
 
        for (parents = work_tree->parents; parents; parents = parents->next) {
-               const unsigned char *commit_sha1 = parents->item->object.sha1;
+               const unsigned char *commit_sha1 = parents->item->object.oid.hash;
                unsigned char blob_sha1[20];
                unsigned mode;
 
@@ -2233,20 +2240,19 @@ static struct commit_list **append_parent(struct commit_list **tail, const unsig
 static void append_merge_parents(struct commit_list **tail)
 {
        int merge_head;
-       const char *merge_head_file = git_path("MERGE_HEAD");
        struct strbuf line = STRBUF_INIT;
 
-       merge_head = open(merge_head_file, O_RDONLY);
+       merge_head = open(git_path_merge_head(), O_RDONLY);
        if (merge_head < 0) {
                if (errno == ENOENT)
                        return;
-               die("cannot open '%s' for reading", merge_head_file);
+               die("cannot open '%s' for reading", git_path_merge_head());
        }
 
        while (!strbuf_getwholeline_fd(&line, merge_head, '\n')) {
                unsigned char sha1[20];
                if (line.len < 40 || get_sha1_hex(line.buf, sha1))
-                       die("unknown line in '%s': %s", merge_head_file, line.buf);
+                       die("unknown line in '%s': %s", git_path_merge_head(), line.buf);
                tail = append_parent(tail, sha1);
        }
        close(merge_head);
@@ -2304,7 +2310,7 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt,
        strbuf_addstr(&msg, "tree 0000000000000000000000000000000000000000\n");
        for (parent = commit->parents; parent; parent = parent->next)
                strbuf_addf(&msg, "parent %s\n",
-                           sha1_to_hex(parent->item->object.sha1));
+                           oid_to_hex(&parent->item->object.oid));
        strbuf_addf(&msg,
                    "author %s\n"
                    "committer %s\n\n"
@@ -2582,13 +2588,13 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
 
        if (cmd_is_annotate) {
                output_option |= OUTPUT_ANNOTATE_COMPAT;
-               blame_date_mode = DATE_ISO8601;
+               blame_date_mode.type = DATE_ISO8601;
        } else {
                blame_date_mode = revs.date_mode;
        }
 
        /* The maximum width used to show the dates */
-       switch (blame_date_mode) {
+       switch (blame_date_mode.type) {
        case DATE_RFC2822:
                blame_date_width = sizeof("Thu, 19 Oct 2006 16:00:04 -0700");
                break;
@@ -2613,10 +2619,12 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
                   fewer display columns. */
                blame_date_width = utf8_strwidth(_("4 years, 11 months ago")) + 1; /* add the null */
                break;
-       case DATE_LOCAL:
        case DATE_NORMAL:
                blame_date_width = sizeof("Thu Oct 19 16:00:04 2006 -0700");
                break;
+       case DATE_STRFTIME:
+               blame_date_width = strlen(show_date(0, 0, &blame_date_mode)) + 1; /* add the null */
+               break;
        }
        blame_date_width -= 1; /* strip the null */
 
@@ -2689,7 +2697,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
                sb.commits.compare = compare_commits_by_commit_date;
        }
        else if (contents_from)
-               die("--contents and --children do not blend well.");
+               die("--contents and --reverse do not blend well.");
        else {
                final_commit_name = prepare_initial(&sb);
                sb.commits.compare = compare_commits_by_reverse_commit_date;
@@ -2730,7 +2738,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
 
                sb.revs->children.name = "children";
                while (c->parents &&
-                      hashcmp(c->object.sha1, sb.final->object.sha1)) {
+                      oidcmp(&c->object.oid, &sb.final->object.oid)) {
                        struct commit_list *l = xcalloc(1, sizeof(*l));
 
                        l->item = c;
@@ -2740,11 +2748,11 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
                        c = c->parents->item;
                }
 
-               if (hashcmp(c->object.sha1, sb.final->object.sha1))
+               if (oidcmp(&c->object.oid, &sb.final->object.oid))
                        die("--reverse --first-parent together require range along first-parent chain");
        }
 
-       if (is_null_sha1(sb.final->object.sha1)) {
+       if (is_null_oid(&sb.final->object.oid)) {
                o = sb.final->util;
                sb.final_buf = xmemdupz(o->file.ptr, o->file.size);
                sb.final_buf_size = o->file.size;