Code

Make path in tree view look nicer
[git.git] / blame.c
diff --git a/blame.c b/blame.c
index 88bfec262f741a80ee4aac6ef19d7cf359559464..8cfd5d94c777770a2019e058f1140ecd5a5c9aa2 100644 (file)
--- a/blame.c
+++ b/blame.c
 
 #define DEBUG 0
 
-static const char blame_usage[] = "[-c] [-l] [--] file [commit]\n"
-       "  -c, --compability Use the same output mode as git-annotate (Default: off)\n"
-       "  -l, --long        Show long commit SHA1 (Default: off)\n"
-       "  -h, --help        This message";
+static const char blame_usage[] = "git-blame [-c] [-l] [-t] [-S <revs-file>] [--] file [commit]\n"
+       "  -c, --compatibility Use the same output mode as git-annotate (Default: off)\n"
+       "  -l, --long          Show long commit SHA1 (Default: off)\n"
+       "  -t, --time          Show raw timestamp (Default: off)\n"
+       "  -S, --revs-file     Use revisions from revs-file instead of calling git-rev-list\n"
+       "  -h, --help          This message";
 
 static struct commit **blame_lines;
 static int num_blame_lines;
@@ -42,8 +44,8 @@ struct util_info {
 };
 
 struct chunk {
-       int off1, len1; // ---
-       int off2, len2; // +++
+       int off1, len1; /* --- */
+       int off2, len2; /* +++ */
 };
 
 struct patch {
@@ -54,9 +56,9 @@ struct patch {
 static void get_blob(struct commit *commit);
 
 /* Only used for statistics */
-static int num_get_patch = 0;
-static int num_commits = 0;
-static int patch_time = 0;
+static int num_get_patch;
+static int num_commits;
+static int patch_time;
 
 struct blame_diff_state {
        struct xdiff_emit_state xm;
@@ -108,8 +110,8 @@ static struct patch *get_patch(struct commit *commit, struct commit *other)
        xdemitconf_t xecfg;
        mmfile_t file_c, file_o;
        xdemitcb_t ecb;
-       struct util_info *info_c = (struct util_info *)commit->object.util;
-       struct util_info *info_o = (struct util_info *)other->object.util;
+       struct util_info *info_c = (struct util_info *)commit->util;
+       struct util_info *info_o = (struct util_info *)other->util;
        struct timeval tv_start, tv_end;
 
        get_blob(commit);
@@ -163,7 +165,7 @@ static int get_blob_sha1(struct tree *t, const char *pathname,
        blame_file = pathname;
        pathspec[0] = pathname;
        pathspec[1] = NULL;
-       memset(blob_sha1, 0, sizeof(blob_sha1));
+       hashclr(blob_sha1);
        read_tree_recursive(t, "", 0, 0, pathspec, get_blob_sha1_internal);
 
        for (i = 0; i < 20; i++) {
@@ -174,7 +176,7 @@ static int get_blob_sha1(struct tree *t, const char *pathname,
        if (i == 20)
                return -1;
 
-       memcpy(sha1, blob_sha1, 20);
+       hashcpy(sha1, blob_sha1);
        return 0;
 }
 
@@ -189,13 +191,13 @@ static int get_blob_sha1_internal(const unsigned char *sha1, const char *base,
            strcmp(blame_file + baselen, pathname))
                return -1;
 
-       memcpy(blob_sha1, sha1, 20);
+       hashcpy(blob_sha1, sha1);
        return -1;
 }
 
 static void get_blob(struct commit *commit)
 {
-       struct util_info *info = commit->object.util;
+       struct util_info *info = commit->util;
        char type[20];
 
        if (info->buf)
@@ -221,8 +223,8 @@ static void print_patch(struct patch *p)
 /* For debugging only */
 static void print_map(struct commit *cmit, struct commit *other)
 {
-       struct util_info *util = cmit->object.util;
-       struct util_info *util2 = other->object.util;
+       struct util_info *util = cmit->util;
+       struct util_info *util2 = other->util;
 
        int i;
        int max =
@@ -253,12 +255,12 @@ static void print_map(struct commit *cmit, struct commit *other)
 }
 #endif
 
-// p is a patch from commit to other.
+/* p is a patch from commit to other. */
 static void fill_line_map(struct commit *commit, struct commit *other,
                          struct patch *p)
 {
-       struct util_info *util = commit->object.util;
-       struct util_info *util2 = other->object.util;
+       struct util_info *util = commit->util;
+       struct util_info *util2 = other->util;
        int *map = util->line_map;
        int *map2 = util2->line_map;
        int cur_chunk = 0;
@@ -299,9 +301,9 @@ static void fill_line_map(struct commit *commit, struct commit *other,
                                if (DEBUG)
                                        printf("map: i1: %d %d %p i2: %d %d %p\n",
                                               i1, map[i1],
-                                              i1 != -1 ? blame_lines[map[i1]] : NULL,
+                                              (void *) (i1 != -1 ? blame_lines[map[i1]] : NULL),
                                               i2, map2[i2],
-                                              i2 != -1 ? blame_lines[map2[i2]] : NULL);
+                                              (void *) (i2 != -1 ? blame_lines[map2[i2]] : NULL));
                                if (map2[i2] != -1 &&
                                    blame_lines[map[i1]] &&
                                    !blame_lines[map2[i2]])
@@ -320,14 +322,14 @@ static void fill_line_map(struct commit *commit, struct commit *other,
 
 static int map_line(struct commit *commit, int line)
 {
-       struct util_info *info = commit->object.util;
+       struct util_info *info = commit->util;
        assert(line >= 0 && line < info->num_lines);
        return info->line_map[line];
 }
 
 static struct util_info* get_util(struct commit *commit)
 {
-       struct util_info *util = commit->object.util;
+       struct util_info *util = commit->util;
 
        if (util)
                return util;
@@ -338,26 +340,23 @@ static struct util_info* get_util(struct commit *commit)
        util->line_map = NULL;
        util->num_lines = -1;
        util->pathname = NULL;
-       commit->object.util = util;
+       commit->util = util;
        return util;
 }
 
 static int fill_util_info(struct commit *commit)
 {
-       struct util_info *util = commit->object.util;
+       struct util_info *util = commit->util;
 
        assert(util);
        assert(util->pathname);
 
-       if (get_blob_sha1(commit->tree, util->pathname, util->sha1))
-               return 1;
-       else
-               return 0;
+       return !!get_blob_sha1(commit->tree, util->pathname, util->sha1);
 }
 
 static void alloc_line_map(struct commit *commit)
 {
-       struct util_info *util = commit->object.util;
+       struct util_info *util = commit->util;
        int i;
 
        if (util->line_map)
@@ -381,7 +380,7 @@ static void alloc_line_map(struct commit *commit)
 
 static void init_first_commit(struct commit* commit, const char* filename)
 {
-       struct util_info* util = commit->object.util;
+       struct util_info* util = commit->util;
        int i;
 
        util->pathname = filename;
@@ -390,7 +389,7 @@ static void init_first_commit(struct commit* commit, const char* filename)
 
        alloc_line_map(commit);
 
-       util = commit->object.util;
+       util = commit->util;
 
        for (i = 0; i < util->num_lines; i++)
                util->line_map[i] = i;
@@ -411,7 +410,7 @@ static void process_commits(struct rev_info *rev, const char *path,
        assert(commit);
        init_first_commit(commit, path);
 
-       util = commit->object.util;
+       util = commit->util;
        num_blame_lines = util->num_lines;
        blame_lines = xmalloc(sizeof(struct commit *) * num_blame_lines);
        blame_contents = util->buf;
@@ -450,7 +449,7 @@ static void process_commits(struct rev_info *rev, const char *path,
                        continue;
 
                alloc_line_map(commit);
-               util = commit->object.util;
+               util = commit->util;
 
                for (parents = commit->parents;
                     parents != NULL; parents = parents->next) {
@@ -510,7 +509,7 @@ static int compare_tree_path(struct rev_info* revs,
 {
        int ret;
        const char* paths[2];
-       struct util_info* util = c2->object.util;
+       struct util_info* util = c2->util;
        paths[0] = util->pathname;
        paths[1] = NULL;
 
@@ -539,7 +538,7 @@ static int same_tree_as_empty_path(struct rev_info *revs, struct tree* t1,
 
 static const char* find_rename(struct commit* commit, struct commit* parent)
 {
-       struct util_info* cutil = commit->object.util;
+       struct util_info* cutil = commit->util;
        struct diff_options diff_opts;
        const char *paths[1];
        int i;
@@ -583,7 +582,7 @@ static void simplify_commit(struct rev_info *revs, struct commit *commit)
                return;
 
        if (!commit->parents) {
-               struct util_info* util = commit->object.util;
+               struct util_info* util = commit->util;
                if (!same_tree_as_empty_path(revs, commit->tree,
                                             util->pathname))
                        commit->object.flags |= TREECHANGE;
@@ -610,7 +609,7 @@ static void simplify_commit(struct rev_info *revs, struct commit *commit)
                case REV_TREE_NEW:
                {
 
-                       struct util_info* util = commit->object.util;
+                       struct util_info* util = commit->util;
                        if (revs->remove_empty_trees &&
                            same_tree_as_empty_path(revs, p->tree,
                                                    util->pathname)) {
@@ -618,7 +617,7 @@ static void simplify_commit(struct rev_info *revs, struct commit *commit)
                                if (new_name) {
                                        struct util_info* putil = get_util(p);
                                        if (!putil->pathname)
-                                               putil->pathname = strdup(new_name);
+                                               putil->pathname = xstrdup(new_name);
                                } else {
                                        *pp = parent->next;
                                        continue;
@@ -680,13 +679,19 @@ static void get_commit_info(struct commit* commit, struct commit_info* ret)
        *tmp = 0;
 }
 
-static const char* format_time(unsigned long time, const char* tz_str)
+static const char* format_time(unsigned long time, const char* tz_str,
+                              int show_raw_time)
 {
        static char time_buf[128];
        time_t t = time;
        int minutes, tz;
        struct tm *tm;
 
+       if (show_raw_time) {
+               sprintf(time_buf, "%lu %s", time, tz_str);
+               return time_buf;
+       }
+
        tz = atoi(tz_str);
        minutes = tz < 0 ? -tz : tz;
        minutes = (minutes / 100)*60 + (minutes % 100);
@@ -701,13 +706,13 @@ static const char* format_time(unsigned long time, const char* tz_str)
 
 static void topo_setter(struct commit* c, void* data)
 {
-       struct util_info* util = c->object.util;
+       struct util_info* util = c->util;
        util->topo_data = data;
 }
 
 static void* topo_getter(struct commit* c)
 {
-       struct util_info* util = c->object.util;
+       struct util_info* util = c->util;
        return util->topo_data;
 }
 
@@ -739,7 +744,8 @@ int main(int argc, const char **argv)
        const char *filename = NULL, *commit = NULL;
        char filename_buf[256];
        int sha1_len = 8;
-       int compability = 0;
+       int compatibility = 0;
+       int show_raw_time = 0;
        int options = 1;
        struct commit* start_commit;
 
@@ -765,13 +771,17 @@ int main(int argc, const char **argv)
                                sha1_len = 40;
                                continue;
                        } else if(!strcmp(argv[i], "-c") ||
-                                 !strcmp(argv[i], "--compability")) {
-                               compability = 1;
+                                 !strcmp(argv[i], "--compatibility")) {
+                               compatibility = 1;
+                               continue;
+                       } else if(!strcmp(argv[i], "-t") ||
+                                 !strcmp(argv[i], "--time")) {
+                               show_raw_time = 1;
                                continue;
                        } else if(!strcmp(argv[i], "-S")) {
                                if (i + 1 < argc &&
                                    !read_ancestry(argv[i + 1], &sha1_p)) {
-                                       compability = 1;
+                                       compatibility = 1;
                                        i++;
                                        continue;
                                }
@@ -821,7 +831,7 @@ int main(int argc, const char **argv)
        }
 
 
-       init_revisions(&rev);
+       init_revisions(&rev, setup_git_directory());
        rev.remove_empty_trees = 1;
        rev.topo_order = 1;
        rev.prune_fn = simplify_commit;
@@ -850,7 +860,7 @@ int main(int argc, const char **argv)
                struct util_info* u;
                if (!c)
                        c = initial;
-               u = c->object.util;
+               u = c->util;
 
                if (!found_rename && strcmp(filename, u->pathname))
                        found_rename = 1;
@@ -868,19 +878,22 @@ int main(int argc, const char **argv)
                if (!c)
                        c = initial;
 
-               u = c->object.util;
+               u = c->util;
                get_commit_info(c, &ci);
                fwrite(sha1_to_hex(c->object.sha1), sha1_len, 1, stdout);
-               if(compability) {
+               if(compatibility) {
                        printf("\t(%10s\t%10s\t%d)", ci.author,
-                              format_time(ci.author_time, ci.author_tz), i+1);
+                              format_time(ci.author_time, ci.author_tz,
+                                          show_raw_time),
+                              i+1);
                } else {
                        if (found_rename)
                                printf(" %-*.*s", longest_file, longest_file,
                                       u->pathname);
                        printf(" (%-*.*s %10s %*d) ",
                               longest_author, longest_author, ci.author,
-                              format_time(ci.author_time, ci.author_tz),
+                              format_time(ci.author_time, ci.author_tz,
+                                          show_raw_time),
                               max_digits, i+1);
                }