blame.con commit blame: Rename detection (take 2) (27e7304)
   1/*
   2 * Copyright (C) 2006, Fredrik Kuivinen <freku045@student.liu.se>
   3 */
   4
   5#include <assert.h>
   6#include <time.h>
   7#include <sys/time.h>
   8#include <math.h>
   9
  10#include "cache.h"
  11#include "refs.h"
  12#include "tag.h"
  13#include "commit.h"
  14#include "tree.h"
  15#include "blob.h"
  16#include "diff.h"
  17#include "diffcore.h"
  18#include "revision.h"
  19
  20#define DEBUG 0
  21
  22static const char blame_usage[] = "[-c] [-l] [--] file [commit]\n"
  23        "  -c, --compability Use the same output mode as git-annotate (Default: off)\n"
  24        "  -l, --long        Show long commit SHA1 (Default: off)\n"
  25        "  -h, --help        This message";
  26
  27static struct commit **blame_lines;
  28static int num_blame_lines;
  29static char* blame_contents;
  30static int blame_len;
  31
  32struct util_info {
  33        int *line_map;
  34        unsigned char sha1[20]; /* blob sha, not commit! */
  35        char *buf;
  36        unsigned long size;
  37        int num_lines;
  38        const char* pathname;
  39
  40        void* topo_data;
  41};
  42
  43struct chunk {
  44        int off1, len1; // ---
  45        int off2, len2; // +++
  46};
  47
  48struct patch {
  49        struct chunk *chunks;
  50        int num;
  51};
  52
  53static void get_blob(struct commit *commit);
  54
  55/* Only used for statistics */
  56static int num_get_patch = 0;
  57static int num_commits = 0;
  58static int patch_time = 0;
  59
  60#define TEMPFILE_PATH_LEN 60
  61static struct patch *get_patch(struct commit *commit, struct commit *other)
  62{
  63        struct patch *ret;
  64        struct util_info *info_c = (struct util_info *)commit->object.util;
  65        struct util_info *info_o = (struct util_info *)other->object.util;
  66        char tmp_path1[TEMPFILE_PATH_LEN], tmp_path2[TEMPFILE_PATH_LEN];
  67        char diff_cmd[TEMPFILE_PATH_LEN*2 + 20];
  68        struct timeval tv_start, tv_end;
  69        int fd;
  70        FILE *fin;
  71        char buf[1024];
  72
  73        ret = xmalloc(sizeof(struct patch));
  74        ret->chunks = NULL;
  75        ret->num = 0;
  76
  77        get_blob(commit);
  78        get_blob(other);
  79
  80        gettimeofday(&tv_start, NULL);
  81
  82        fd = git_mkstemp(tmp_path1, TEMPFILE_PATH_LEN, "git-blame-XXXXXX");
  83        if (fd < 0)
  84                die("unable to create temp-file: %s", strerror(errno));
  85
  86        if (xwrite(fd, info_c->buf, info_c->size) != info_c->size)
  87                die("write failed: %s", strerror(errno));
  88        close(fd);
  89
  90        fd = git_mkstemp(tmp_path2, TEMPFILE_PATH_LEN, "git-blame-XXXXXX");
  91        if (fd < 0)
  92                die("unable to create temp-file: %s", strerror(errno));
  93
  94        if (xwrite(fd, info_o->buf, info_o->size) != info_o->size)
  95                die("write failed: %s", strerror(errno));
  96        close(fd);
  97
  98        sprintf(diff_cmd, "diff -U 0 %s %s", tmp_path1, tmp_path2);
  99        fin = popen(diff_cmd, "r");
 100        if (!fin)
 101                die("popen failed: %s", strerror(errno));
 102
 103        while (fgets(buf, sizeof(buf), fin)) {
 104                struct chunk *chunk;
 105                char *start, *sp;
 106
 107                if (buf[0] != '@' || buf[1] != '@')
 108                        continue;
 109
 110                if (DEBUG)
 111                        printf("chunk line: %s", buf);
 112                ret->num++;
 113                ret->chunks = xrealloc(ret->chunks,
 114                                       sizeof(struct chunk) * ret->num);
 115                chunk = &ret->chunks[ret->num - 1];
 116
 117                assert(!strncmp(buf, "@@ -", 4));
 118
 119                start = buf + 4;
 120                sp = index(start, ' ');
 121                *sp = '\0';
 122                if (index(start, ',')) {
 123                        int ret =
 124                            sscanf(start, "%d,%d", &chunk->off1, &chunk->len1);
 125                        assert(ret == 2);
 126                } else {
 127                        int ret = sscanf(start, "%d", &chunk->off1);
 128                        assert(ret == 1);
 129                        chunk->len1 = 1;
 130                }
 131                *sp = ' ';
 132
 133                start = sp + 1;
 134                sp = index(start, ' ');
 135                *sp = '\0';
 136                if (index(start, ',')) {
 137                        int ret =
 138                            sscanf(start, "%d,%d", &chunk->off2, &chunk->len2);
 139                        assert(ret == 2);
 140                } else {
 141                        int ret = sscanf(start, "%d", &chunk->off2);
 142                        assert(ret == 1);
 143                        chunk->len2 = 1;
 144                }
 145                *sp = ' ';
 146
 147                if (chunk->len1 == 0)
 148                        chunk->off1++;
 149                if (chunk->len2 == 0)
 150                        chunk->off2++;
 151
 152                if (chunk->off1 > 0)
 153                        chunk->off1--;
 154                if (chunk->off2 > 0)
 155                        chunk->off2--;
 156
 157                assert(chunk->off1 >= 0);
 158                assert(chunk->off2 >= 0);
 159        }
 160        pclose(fin);
 161        unlink(tmp_path1);
 162        unlink(tmp_path2);
 163
 164        gettimeofday(&tv_end, NULL);
 165        patch_time += 1000000 * (tv_end.tv_sec - tv_start.tv_sec) +
 166                tv_end.tv_usec - tv_start.tv_usec;
 167
 168        num_get_patch++;
 169        return ret;
 170}
 171
 172static void free_patch(struct patch *p)
 173{
 174        free(p->chunks);
 175        free(p);
 176}
 177
 178static int get_blob_sha1_internal(unsigned char *sha1, const char *base,
 179                                  int baselen, const char *pathname,
 180                                  unsigned mode, int stage);
 181
 182static unsigned char blob_sha1[20];
 183static int get_blob_sha1(struct tree *t, const char *pathname,
 184                         unsigned char *sha1)
 185{
 186        int i;
 187        const char *pathspec[2];
 188        pathspec[0] = pathname;
 189        pathspec[1] = NULL;
 190        memset(blob_sha1, 0, sizeof(blob_sha1));
 191        read_tree_recursive(t, "", 0, 0, pathspec, get_blob_sha1_internal);
 192
 193        for (i = 0; i < 20; i++) {
 194                if (blob_sha1[i] != 0)
 195                        break;
 196        }
 197
 198        if (i == 20)
 199                return -1;
 200
 201        memcpy(sha1, blob_sha1, 20);
 202        return 0;
 203}
 204
 205static int get_blob_sha1_internal(unsigned char *sha1, const char *base,
 206                                  int baselen, const char *pathname,
 207                                  unsigned mode, int stage)
 208{
 209        if (S_ISDIR(mode))
 210                return READ_TREE_RECURSIVE;
 211
 212        memcpy(blob_sha1, sha1, 20);
 213        return -1;
 214}
 215
 216static void get_blob(struct commit *commit)
 217{
 218        struct util_info *info = commit->object.util;
 219        char type[20];
 220
 221        if (info->buf)
 222                return;
 223
 224        info->buf = read_sha1_file(info->sha1, type, &info->size);
 225
 226        assert(!strcmp(type, "blob"));
 227}
 228
 229/* For debugging only */
 230static void print_patch(struct patch *p)
 231{
 232        int i;
 233        printf("Num chunks: %d\n", p->num);
 234        for (i = 0; i < p->num; i++) {
 235                printf("%d,%d %d,%d\n", p->chunks[i].off1, p->chunks[i].len1,
 236                       p->chunks[i].off2, p->chunks[i].len2);
 237        }
 238}
 239
 240#if DEBUG
 241/* For debugging only */
 242static void print_map(struct commit *cmit, struct commit *other)
 243{
 244        struct util_info *util = cmit->object.util;
 245        struct util_info *util2 = other->object.util;
 246
 247        int i;
 248        int max =
 249            util->num_lines >
 250            util2->num_lines ? util->num_lines : util2->num_lines;
 251        int num;
 252
 253        for (i = 0; i < max; i++) {
 254                printf("i: %d ", i);
 255                num = -1;
 256
 257                if (i < util->num_lines) {
 258                        num = util->line_map[i];
 259                        printf("%d\t", num);
 260                } else
 261                        printf("\t");
 262
 263                if (i < util2->num_lines) {
 264                        int num2 = util2->line_map[i];
 265                        printf("%d\t", num2);
 266                        if (num != -1 && num2 != num)
 267                                printf("---");
 268                } else
 269                        printf("\t");
 270
 271                printf("\n");
 272        }
 273}
 274#endif
 275
 276// p is a patch from commit to other.
 277static void fill_line_map(struct commit *commit, struct commit *other,
 278                          struct patch *p)
 279{
 280        struct util_info *util = commit->object.util;
 281        struct util_info *util2 = other->object.util;
 282        int *map = util->line_map;
 283        int *map2 = util2->line_map;
 284        int cur_chunk = 0;
 285        int i1, i2;
 286
 287        if (p->num && DEBUG)
 288                print_patch(p);
 289
 290        if (DEBUG)
 291                printf("num lines 1: %d num lines 2: %d\n", util->num_lines,
 292                       util2->num_lines);
 293
 294        for (i1 = 0, i2 = 0; i1 < util->num_lines; i1++, i2++) {
 295                struct chunk *chunk = NULL;
 296                if (cur_chunk < p->num)
 297                        chunk = &p->chunks[cur_chunk];
 298
 299                if (chunk && chunk->off1 == i1) {
 300                        if (DEBUG && i2 != chunk->off2)
 301                                printf("i2: %d off2: %d\n", i2, chunk->off2);
 302
 303                        assert(i2 == chunk->off2);
 304
 305                        i1--;
 306                        i2--;
 307                        if (chunk->len1 > 0)
 308                                i1 += chunk->len1;
 309
 310                        if (chunk->len2 > 0)
 311                                i2 += chunk->len2;
 312
 313                        cur_chunk++;
 314                } else {
 315                        if (i2 >= util2->num_lines)
 316                                break;
 317
 318                        if (map[i1] != map2[i2] && map[i1] != -1) {
 319                                if (DEBUG)
 320                                        printf("map: i1: %d %d %p i2: %d %d %p\n",
 321                                               i1, map[i1],
 322                                               i1 != -1 ? blame_lines[map[i1]] : NULL,
 323                                               i2, map2[i2],
 324                                               i2 != -1 ? blame_lines[map2[i2]] : NULL);
 325                                if (map2[i2] != -1 &&
 326                                    blame_lines[map[i1]] &&
 327                                    !blame_lines[map2[i2]])
 328                                        map[i1] = map2[i2];
 329                        }
 330
 331                        if (map[i1] == -1 && map2[i2] != -1)
 332                                map[i1] = map2[i2];
 333                }
 334
 335                if (DEBUG > 1)
 336                        printf("l1: %d l2: %d i1: %d i2: %d\n",
 337                               map[i1], map2[i2], i1, i2);
 338        }
 339}
 340
 341static int map_line(struct commit *commit, int line)
 342{
 343        struct util_info *info = commit->object.util;
 344        assert(line >= 0 && line < info->num_lines);
 345        return info->line_map[line];
 346}
 347
 348static struct util_info* get_util(struct commit *commit)
 349{
 350        struct util_info *util = commit->object.util;
 351
 352        if (util)
 353                return util;
 354
 355        util = xmalloc(sizeof(struct util_info));
 356        util->buf = NULL;
 357        util->size = 0;
 358        util->line_map = NULL;
 359        util->num_lines = -1;
 360        util->pathname = NULL;
 361        commit->object.util = util;
 362        return util;
 363}
 364
 365static int fill_util_info(struct commit *commit)
 366{
 367        struct util_info *util = commit->object.util;
 368
 369        assert(util);
 370        assert(util->pathname);
 371
 372        if (get_blob_sha1(commit->tree, util->pathname, util->sha1))
 373                return 1;
 374        else
 375                return 0;
 376}
 377
 378static void alloc_line_map(struct commit *commit)
 379{
 380        struct util_info *util = commit->object.util;
 381        int i;
 382
 383        if (util->line_map)
 384                return;
 385
 386        get_blob(commit);
 387
 388        util->num_lines = 0;
 389        for (i = 0; i < util->size; i++) {
 390                if (util->buf[i] == '\n')
 391                        util->num_lines++;
 392        }
 393        if(util->buf[util->size - 1] != '\n')
 394                util->num_lines++;
 395
 396        util->line_map = xmalloc(sizeof(int) * util->num_lines);
 397
 398        for (i = 0; i < util->num_lines; i++)
 399                util->line_map[i] = -1;
 400}
 401
 402static void init_first_commit(struct commit* commit, const char* filename)
 403{
 404        struct util_info* util = commit->object.util;
 405        int i;
 406
 407        util->pathname = filename;
 408        if (fill_util_info(commit))
 409                die("fill_util_info failed");
 410
 411        alloc_line_map(commit);
 412
 413        util = commit->object.util;
 414
 415        for (i = 0; i < util->num_lines; i++)
 416                util->line_map[i] = i;
 417}
 418
 419
 420static void process_commits(struct rev_info *rev, const char *path,
 421                            struct commit** initial)
 422{
 423        int i;
 424        struct util_info* util;
 425        int lines_left;
 426        int *blame_p;
 427        int *new_lines;
 428        int new_lines_len;
 429
 430        struct commit* commit = get_revision(rev);
 431        assert(commit);
 432        init_first_commit(commit, path);
 433
 434        util = commit->object.util;
 435        num_blame_lines = util->num_lines;
 436        blame_lines = xmalloc(sizeof(struct commit *) * num_blame_lines);
 437        blame_contents = util->buf;
 438        blame_len = util->size;
 439
 440        for (i = 0; i < num_blame_lines; i++)
 441                blame_lines[i] = NULL;
 442
 443        lines_left = num_blame_lines;
 444        blame_p = xmalloc(sizeof(int) * num_blame_lines);
 445        new_lines = xmalloc(sizeof(int) * num_blame_lines);
 446        do {
 447                struct commit_list *parents;
 448                int num_parents;
 449                struct util_info *util;
 450
 451                if (DEBUG)
 452                        printf("\nProcessing commit: %d %s\n", num_commits,
 453                               sha1_to_hex(commit->object.sha1));
 454
 455                if (lines_left == 0)
 456                        return;
 457
 458                num_commits++;
 459                memset(blame_p, 0, sizeof(int) * num_blame_lines);
 460                new_lines_len = 0;
 461                num_parents = 0;
 462                for (parents = commit->parents;
 463                     parents != NULL; parents = parents->next)
 464                        num_parents++;
 465
 466                if(num_parents == 0)
 467                        *initial = commit;
 468
 469                if (fill_util_info(commit))
 470                        continue;
 471
 472                alloc_line_map(commit);
 473                util = commit->object.util;
 474
 475                for (parents = commit->parents;
 476                     parents != NULL; parents = parents->next) {
 477                        struct commit *parent = parents->item;
 478                        struct patch *patch;
 479
 480                        if (parse_commit(parent) < 0)
 481                                die("parse_commit error");
 482
 483                        if (DEBUG)
 484                                printf("parent: %s\n",
 485                                       sha1_to_hex(parent->object.sha1));
 486
 487                        if (fill_util_info(parent)) {
 488                                num_parents--;
 489                                continue;
 490                        }
 491
 492                        patch = get_patch(parent, commit);
 493                        alloc_line_map(parent);
 494                        fill_line_map(parent, commit, patch);
 495
 496                        for (i = 0; i < patch->num; i++) {
 497                            int l;
 498                            for (l = 0; l < patch->chunks[i].len2; l++) {
 499                                int mapped_line =
 500                                    map_line(commit, patch->chunks[i].off2 + l);
 501                                if (mapped_line != -1) {
 502                                    blame_p[mapped_line]++;
 503                                    if (blame_p[mapped_line] == num_parents)
 504                                        new_lines[new_lines_len++] = mapped_line;
 505                                }
 506                            }
 507                        }
 508                        free_patch(patch);
 509                }
 510
 511                if (DEBUG)
 512                        printf("parents: %d\n", num_parents);
 513
 514                for (i = 0; i < new_lines_len; i++) {
 515                        int mapped_line = new_lines[i];
 516                        if (blame_lines[mapped_line] == NULL) {
 517                                blame_lines[mapped_line] = commit;
 518                                lines_left--;
 519                                if (DEBUG)
 520                                        printf("blame: mapped: %d i: %d\n",
 521                                               mapped_line, i);
 522                        }
 523                }
 524        } while ((commit = get_revision(rev)) != NULL);
 525}
 526
 527
 528static int compare_tree_path(struct rev_info* revs,
 529                             struct commit* c1, struct commit* c2)
 530{
 531        const char* paths[2];
 532        struct util_info* util = c2->object.util;
 533        paths[0] = util->pathname;
 534        paths[1] = NULL;
 535
 536        diff_tree_setup_paths(get_pathspec(revs->prefix, paths));
 537        return rev_compare_tree(c1->tree, c2->tree);
 538}
 539
 540
 541static int same_tree_as_empty_path(struct rev_info *revs, struct tree* t1,
 542                                   const char* path)
 543{
 544        const char* paths[2];
 545        paths[0] = path;
 546        paths[1] = NULL;
 547
 548        diff_tree_setup_paths(get_pathspec(revs->prefix, paths));
 549        return rev_same_tree_as_empty(t1);
 550}
 551
 552static const char* find_rename(struct commit* commit, struct commit* parent)
 553{
 554        struct util_info* cutil = commit->object.util;
 555        struct diff_options diff_opts;
 556        const char *paths[1];
 557        int i;
 558
 559        if (DEBUG) {
 560                printf("find_rename commit: %s ",
 561                       sha1_to_hex(commit->object.sha1));
 562                puts(sha1_to_hex(parent->object.sha1));
 563        }
 564
 565        diff_setup(&diff_opts);
 566        diff_opts.recursive = 1;
 567        diff_opts.detect_rename = DIFF_DETECT_RENAME;
 568        paths[0] = NULL;
 569        diff_tree_setup_paths(paths);
 570        if (diff_setup_done(&diff_opts) < 0)
 571                die("diff_setup_done failed");
 572
 573        diff_tree_sha1(commit->tree->object.sha1, parent->tree->object.sha1,
 574                       "", &diff_opts);
 575        diffcore_std(&diff_opts);
 576
 577        for (i = 0; i < diff_queued_diff.nr; i++) {
 578                struct diff_filepair *p = diff_queued_diff.queue[i];
 579
 580                if (p->status == 'R' && !strcmp(p->one->path, cutil->pathname)) {
 581                        if (DEBUG)
 582                                printf("rename %s -> %s\n", p->one->path, p->two->path);
 583                        return p->two->path;
 584                }
 585        }
 586
 587        return 0;
 588}
 589
 590static void simplify_commit(struct rev_info *revs, struct commit *commit)
 591{
 592        struct commit_list **pp, *parent;
 593
 594        if (!commit->tree)
 595                return;
 596
 597        if (!commit->parents) {
 598                struct util_info* util = commit->object.util;
 599                if (!same_tree_as_empty_path(revs, commit->tree,
 600                                             util->pathname))
 601                        commit->object.flags |= TREECHANGE;
 602                return;
 603        }
 604
 605        pp = &commit->parents;
 606        while ((parent = *pp) != NULL) {
 607                struct commit *p = parent->item;
 608
 609                if (p->object.flags & UNINTERESTING) {
 610                        pp = &parent->next;
 611                        continue;
 612                }
 613
 614                parse_commit(p);
 615                switch (compare_tree_path(revs, p, commit)) {
 616                case REV_TREE_SAME:
 617                        parent->next = NULL;
 618                        commit->parents = parent;
 619                        get_util(p)->pathname = get_util(commit)->pathname;
 620                        return;
 621
 622                case REV_TREE_NEW:
 623                {
 624
 625                        struct util_info* util = commit->object.util;
 626                        if (revs->remove_empty_trees &&
 627                            same_tree_as_empty_path(revs, p->tree,
 628                                                    util->pathname)) {
 629                                const char* new_name = find_rename(commit, p);
 630                                if (new_name) {
 631                                        struct util_info* putil = get_util(p);
 632                                        if (!putil->pathname)
 633                                                putil->pathname = strdup(new_name);
 634                                } else {
 635                                        *pp = parent->next;
 636                                        continue;
 637                                }
 638                        }
 639                }
 640
 641                /* fallthrough */
 642                case REV_TREE_DIFFERENT:
 643                        pp = &parent->next;
 644                        if (!get_util(p)->pathname)
 645                                get_util(p)->pathname =
 646                                        get_util(commit)->pathname;
 647                        continue;
 648                }
 649                die("bad tree compare for commit %s",
 650                    sha1_to_hex(commit->object.sha1));
 651        }
 652        commit->object.flags |= TREECHANGE;
 653}
 654
 655
 656struct commit_info
 657{
 658        char* author;
 659        char* author_mail;
 660        unsigned long author_time;
 661        char* author_tz;
 662};
 663
 664static void get_commit_info(struct commit* commit, struct commit_info* ret)
 665{
 666        int len;
 667        char* tmp;
 668        static char author_buf[1024];
 669
 670        tmp = strstr(commit->buffer, "\nauthor ") + 8;
 671        len = index(tmp, '\n') - tmp;
 672        ret->author = author_buf;
 673        memcpy(ret->author, tmp, len);
 674
 675        tmp = ret->author;
 676        tmp += len;
 677        *tmp = 0;
 678        while(*tmp != ' ')
 679                tmp--;
 680        ret->author_tz = tmp+1;
 681
 682        *tmp = 0;
 683        while(*tmp != ' ')
 684                tmp--;
 685        ret->author_time = strtoul(tmp, NULL, 10);
 686
 687        *tmp = 0;
 688        while(*tmp != ' ')
 689                tmp--;
 690        ret->author_mail = tmp + 1;
 691
 692        *tmp = 0;
 693}
 694
 695static const char* format_time(unsigned long time, const char* tz_str)
 696{
 697        static char time_buf[128];
 698        time_t t = time;
 699        int minutes, tz;
 700        struct tm *tm;
 701
 702        tz = atoi(tz_str);
 703        minutes = tz < 0 ? -tz : tz;
 704        minutes = (minutes / 100)*60 + (minutes % 100);
 705        minutes = tz < 0 ? -minutes : minutes;
 706        t = time + minutes * 60;
 707        tm = gmtime(&t);
 708
 709        strftime(time_buf, sizeof(time_buf), "%Y-%m-%d %H:%M:%S ", tm);
 710        strcat(time_buf, tz_str);
 711        return time_buf;
 712}
 713
 714static void topo_setter(struct commit* c, void* data)
 715{
 716        struct util_info* util = c->object.util;
 717        util->topo_data = data;
 718}
 719
 720static void* topo_getter(struct commit* c)
 721{
 722        struct util_info* util = c->object.util;
 723        return util->topo_data;
 724}
 725
 726int main(int argc, const char **argv)
 727{
 728        int i;
 729        struct commit *initial = NULL;
 730        unsigned char sha1[20];
 731
 732        const char *filename = NULL, *commit = NULL;
 733        char filename_buf[256];
 734        int sha1_len = 8;
 735        int compability = 0;
 736        int options = 1;
 737        struct commit* start_commit;
 738
 739        const char* args[10];
 740        struct rev_info rev;
 741
 742        struct commit_info ci;
 743        const char *buf;
 744        int max_digits;
 745
 746        const char* prefix = setup_git_directory();
 747
 748        for(i = 1; i < argc; i++) {
 749                if(options) {
 750                        if(!strcmp(argv[i], "-h") ||
 751                           !strcmp(argv[i], "--help"))
 752                                usage(blame_usage);
 753                        else if(!strcmp(argv[i], "-l") ||
 754                                !strcmp(argv[i], "--long")) {
 755                                sha1_len = 40;
 756                                continue;
 757                        } else if(!strcmp(argv[i], "-c") ||
 758                                  !strcmp(argv[i], "--compability")) {
 759                                compability = 1;
 760                                continue;
 761                        } else if(!strcmp(argv[i], "--")) {
 762                                options = 0;
 763                                continue;
 764                        } else if(argv[i][0] == '-')
 765                                usage(blame_usage);
 766                        else
 767                                options = 0;
 768                }
 769
 770                if(!options) {
 771                        if(!filename)
 772                                filename = argv[i];
 773                        else if(!commit)
 774                                commit = argv[i];
 775                        else
 776                                usage(blame_usage);
 777                }
 778        }
 779
 780        if(!filename)
 781                usage(blame_usage);
 782        if(!commit)
 783                commit = "HEAD";
 784
 785        if(prefix)
 786                sprintf(filename_buf, "%s%s", prefix, filename);
 787        else
 788                strcpy(filename_buf, filename);
 789        filename = filename_buf;
 790
 791        if (get_sha1(commit, sha1))
 792                die("get_sha1 failed, commit '%s' not found", commit);
 793        start_commit = lookup_commit_reference(sha1);
 794        get_util(start_commit)->pathname = filename;
 795        if (fill_util_info(start_commit)) {
 796                printf("%s not found in %s\n", filename, commit);
 797                return 1;
 798        }
 799
 800
 801        init_revisions(&rev);
 802        rev.remove_empty_trees = 1;
 803        rev.topo_order = 1;
 804        rev.prune_fn = simplify_commit;
 805        rev.topo_setter = topo_setter;
 806        rev.topo_getter = topo_getter;
 807        rev.limited = 1;
 808
 809        commit_list_insert(start_commit, &rev.commits);
 810
 811        args[0] = filename;
 812        args[1] = NULL;
 813        diff_tree_setup_paths(args);
 814        prepare_revision_walk(&rev);
 815        process_commits(&rev, filename, &initial);
 816
 817        buf = blame_contents;
 818        for (max_digits = 1, i = 10; i <= num_blame_lines + 1; max_digits++)
 819                i *= 10;
 820
 821        for (i = 0; i < num_blame_lines; i++) {
 822                struct commit *c = blame_lines[i];
 823                struct util_info* u;
 824
 825                if (!c)
 826                        c = initial;
 827
 828                u = c->object.util;
 829                get_commit_info(c, &ci);
 830                fwrite(sha1_to_hex(c->object.sha1), sha1_len, 1, stdout);
 831                if(compability)
 832                        printf("\t(%10s\t%10s\t%d)", ci.author,
 833                               format_time(ci.author_time, ci.author_tz), i+1);
 834                else
 835                        printf(" %s (%-15.15s %10s %*d) ", u->pathname,
 836                               ci.author, format_time(ci.author_time,
 837                                                      ci.author_tz),
 838                               max_digits, i+1);
 839
 840                if(i == num_blame_lines - 1) {
 841                        fwrite(buf, blame_len - (buf - blame_contents),
 842                               1, stdout);
 843                        if(blame_contents[blame_len-1] != '\n')
 844                                putc('\n', stdout);
 845                } else {
 846                        char* next_buf = index(buf, '\n') + 1;
 847                        fwrite(buf, next_buf - buf, 1, stdout);
 848                        buf = next_buf;
 849                }
 850        }
 851
 852        if (DEBUG) {
 853                printf("num get patch: %d\n", num_get_patch);
 854                printf("num commits: %d\n", num_commits);
 855                printf("patch time: %f\n", patch_time / 1000000.0);
 856                printf("initial: %s\n", sha1_to_hex(initial->object.sha1));
 857        }
 858
 859        return 0;
 860}