blame: move scoreboard setup to libgit

Signed-off-by: Jeff Smith <whydoubt@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Jeff Smith committed May 24, 2017 at 00:15 UTC 09002f1b31482dfbd0f471cd3614d542ea7a77a4
3 files changed +281 -284
blame.c
+275 -4
@@ -4,6 +4,7 @@
4 #include "mergesort.h"
5 #include "diff.h"
6 #include "diffcore.h"
7 +#include "tag.h"
8 #include "blame.h"
9
10 void blame_origin_decref(struct blame_origin *o)
@@ -49,7 +50,7 @@ static struct blame_origin *make_origin(struct commit *commit, const char *path)
50 * Locate an existing origin or create a new one.
51 * This moves the origin to front position in the commit util list.
52 */
52 -struct blame_origin *get_origin(struct commit *commit, const char *path)
53 +static struct blame_origin *get_origin(struct commit *commit, const char *path)
54 {
55 struct blame_origin *o, *l;
56
@@ -142,9 +143,9 @@ static void set_commit_buffer_from_strbuf(struct commit *c, struct strbuf *sb)
143 * Prepare a dummy commit that represents the work tree (or staged) item.
144 * Note that annotating work tree item never works in the reverse.
145 */
145 -struct commit *fake_working_tree_commit(struct diff_options *opt,
146 - const char *path,
147 - const char *contents_from)
146 +static struct commit *fake_working_tree_commit(struct diff_options *opt,
147 + const char *path,
148 + const char *contents_from)
149 {
150 struct commit *commit;
151 struct blame_origin *origin;
@@ -410,6 +411,13 @@ void blame_sort_final(struct blame_scoreboard *sb)
411 compare_blame_final);
412 }
413
414 +static int compare_commits_by_reverse_commit_date(const void *a,
415 + const void *b,
416 + void *c)
417 +{
418 + return -compare_commits_by_commit_date(a, b, c);
419 +}
420 +
421 /*
422 * For debugging -- origin is refcounted, and this asserts that
423 * we do not underflow.
@@ -482,6 +490,32 @@ static void queue_blames(struct blame_scoreboard *sb, struct blame_origin *porig
490 }
491 }
492
493 +/*
494 + * Fill the blob_sha1 field of an origin if it hasn't, so that later
495 + * call to fill_origin_blob() can use it to locate the data. blob_sha1
496 + * for an origin is also used to pass the blame for the entire file to
497 + * the parent to detect the case where a child's blob is identical to
498 + * that of its parent's.
499 + *
500 + * This also fills origin->mode for corresponding tree path.
501 + */
502 +static int fill_blob_sha1_and_mode(struct blame_origin *origin)
503 +{
504 + if (!is_null_oid(&origin->blob_oid))
505 + return 0;
506 + if (get_tree_entry(origin->commit->object.oid.hash,
507 + origin->path,
508 + origin->blob_oid.hash, &origin->mode))
509 + goto error_out;
510 + if (sha1_object_info(origin->blob_oid.hash, NULL) != OBJ_BLOB)
511 + goto error_out;
512 + return 0;
513 + error_out:
514 + oidclr(&origin->blob_oid);
515 + origin->mode = S_IFINVALID;
516 + return -1;
517 +}
518 +
519 /*
520 * We have an origin -- check if the same path exists in the
521 * parent and return an origin structure to represent it.
@@ -1574,3 +1608,240 @@ void assign_blame(struct blame_scoreboard *sb, int opt)
1608 sanity_check_refcnt(sb);
1609 }
1610 }
1611 +
1612 +static const char *get_next_line(const char *start, const char *end)
1613 +{
1614 + const char *nl = memchr(start, '\n', end - start);
1615 + return nl ? nl + 1 : end;
1616 +}
1617 +
1618 +/*
1619 + * To allow quick access to the contents of nth line in the
1620 + * final image, prepare an index in the scoreboard.
1621 + */
1622 +static int prepare_lines(struct blame_scoreboard *sb)
1623 +{
1624 + const char *buf = sb->final_buf;
1625 + unsigned long len = sb->final_buf_size;
1626 + const char *end = buf + len;
1627 + const char *p;
1628 + int *lineno;
1629 + int num = 0;
1630 +
1631 + for (p = buf; p < end; p = get_next_line(p, end))
1632 + num++;
1633 +
1634 + ALLOC_ARRAY(sb->lineno, num + 1);
1635 + lineno = sb->lineno;
1636 +
1637 + for (p = buf; p < end; p = get_next_line(p, end))
1638 + *lineno++ = p - buf;
1639 +
1640 + *lineno = len;
1641 +
1642 + sb->num_lines = num;
1643 + return sb->num_lines;
1644 +}
1645 +
1646 +static struct commit *find_single_final(struct rev_info *revs,
1647 + const char **name_p)
1648 +{
1649 + int i;
1650 + struct commit *found = NULL;
1651 + const char *name = NULL;
1652 +
1653 + for (i = 0; i < revs->pending.nr; i++) {
1654 + struct object *obj = revs->pending.objects[i].item;
1655 + if (obj->flags & UNINTERESTING)
1656 + continue;
1657 + obj = deref_tag(obj, NULL, 0);
1658 + if (obj->type != OBJ_COMMIT)
1659 + die("Non commit %s?", revs->pending.objects[i].name);
1660 + if (found)
1661 + die("More than one commit to dig from %s and %s?",
1662 + revs->pending.objects[i].name, name);
1663 + found = (struct commit *)obj;
1664 + name = revs->pending.objects[i].name;
1665 + }
1666 + if (name_p)
1667 + *name_p = name;
1668 + return found;
1669 +}
1670 +
1671 +static struct commit *dwim_reverse_initial(struct rev_info *revs,
1672 + const char **name_p)
1673 +{
1674 + /*
1675 + * DWIM "git blame --reverse ONE -- PATH" as
1676 + * "git blame --reverse ONE..HEAD -- PATH" but only do so
1677 + * when it makes sense.
1678 + */
1679 + struct object *obj;
1680 + struct commit *head_commit;
1681 + unsigned char head_sha1[20];
1682 +
1683 + if (revs->pending.nr != 1)
1684 + return NULL;
1685 +
1686 + /* Is that sole rev a committish? */
1687 + obj = revs->pending.objects[0].item;
1688 + obj = deref_tag(obj, NULL, 0);
1689 + if (obj->type != OBJ_COMMIT)
1690 + return NULL;
1691 +
1692 + /* Do we have HEAD? */
1693 + if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, head_sha1, NULL))
1694 + return NULL;
1695 + head_commit = lookup_commit_reference_gently(head_sha1, 1);
1696 + if (!head_commit)
1697 + return NULL;
1698 +
1699 + /* Turn "ONE" into "ONE..HEAD" then */
1700 + obj->flags |= UNINTERESTING;
1701 + add_pending_object(revs, &head_commit->object, "HEAD");
1702 +
1703 + if (name_p)
1704 + *name_p = revs->pending.objects[0].name;
1705 + return (struct commit *)obj;
1706 +}
1707 +
1708 +static struct commit *find_single_initial(struct rev_info *revs,
1709 + const char **name_p)
1710 +{
1711 + int i;
1712 + struct commit *found = NULL;
1713 + const char *name = NULL;
1714 +
1715 + /*
1716 + * There must be one and only one negative commit, and it must be
1717 + * the boundary.
1718 + */
1719 + for (i = 0; i < revs->pending.nr; i++) {
1720 + struct object *obj = revs->pending.objects[i].item;
1721 + if (!(obj->flags & UNINTERESTING))
1722 + continue;
1723 + obj = deref_tag(obj, NULL, 0);
1724 + if (obj->type != OBJ_COMMIT)
1725 + die("Non commit %s?", revs->pending.objects[i].name);
1726 + if (found)
1727 + die("More than one commit to dig up from, %s and %s?",
1728 + revs->pending.objects[i].name, name);
1729 + found = (struct commit *) obj;
1730 + name = revs->pending.objects[i].name;
1731 + }
1732 +
1733 + if (!name)
1734 + found = dwim_reverse_initial(revs, &name);
1735 + if (!name)
1736 + die("No commit to dig up from?");
1737 +
1738 + if (name_p)
1739 + *name_p = name;
1740 + return found;
1741 +}
1742 +
1743 +void init_scoreboard(struct blame_scoreboard *sb)
1744 +{
1745 + memset(sb, 0, sizeof(struct blame_scoreboard));
1746 + sb->move_score = BLAME_DEFAULT_MOVE_SCORE;
1747 + sb->copy_score = BLAME_DEFAULT_COPY_SCORE;
1748 +}
1749 +
1750 +void setup_scoreboard(struct blame_scoreboard *sb, const char *path, struct blame_origin **orig)
1751 +{
1752 + const char *final_commit_name = NULL;
1753 + struct blame_origin *o;
1754 + struct commit *final_commit = NULL;
1755 + enum object_type type;
1756 +
1757 + if (sb->reverse && sb->contents_from)
1758 + die(_("--contents and --reverse do not blend well."));
1759 +
1760 + if (!sb->reverse) {
1761 + sb->final = find_single_final(sb->revs, &final_commit_name);
1762 + sb->commits.compare = compare_commits_by_commit_date;
1763 + } else {
1764 + sb->final = find_single_initial(sb->revs, &final_commit_name);
1765 + sb->commits.compare = compare_commits_by_reverse_commit_date;
1766 + }
1767 +
1768 + if (sb->final && sb->contents_from)
1769 + die(_("cannot use --contents with final commit object name"));
1770 +
1771 + if (sb->reverse && sb->revs->first_parent_only)
1772 + sb->revs->children.name = NULL;
1773 +
1774 + if (!sb->final) {
1775 + /*
1776 + * "--not A B -- path" without anything positive;
1777 + * do not default to HEAD, but use the working tree
1778 + * or "--contents".
1779 + */
1780 + setup_work_tree();
1781 + sb->final = fake_working_tree_commit(&sb->revs->diffopt,
1782 + path, sb->contents_from);
1783 + add_pending_object(sb->revs, &(sb->final->object), ":");
1784 + }
1785 +
1786 + if (sb->reverse && sb->revs->first_parent_only) {
1787 + final_commit = find_single_final(sb->revs, NULL);
1788 + if (!final_commit)
1789 + die(_("--reverse and --first-parent together require specified latest commit"));
1790 + }
1791 +
1792 + /*
1793 + * If we have bottom, this will mark the ancestors of the
1794 + * bottom commits we would reach while traversing as
1795 + * uninteresting.
1796 + */
1797 + if (prepare_revision_walk(sb->revs))
1798 + die(_("revision walk setup failed"));
1799 +
1800 + if (sb->reverse && sb->revs->first_parent_only) {
1801 + struct commit *c = final_commit;
1802 +
1803 + sb->revs->children.name = "children";
1804 + while (c->parents &&
1805 + oidcmp(&c->object.oid, &sb->final->object.oid)) {
1806 + struct commit_list *l = xcalloc(1, sizeof(*l));
1807 +
1808 + l->item = c;
1809 + if (add_decoration(&sb->revs->children,
1810 + &c->parents->item->object, l))
1811 + die("BUG: not unique item in first-parent chain");
1812 + c = c->parents->item;
1813 + }
1814 +
1815 + if (oidcmp(&c->object.oid, &sb->final->object.oid))
1816 + die(_("--reverse --first-parent together require range along first-parent chain"));
1817 + }
1818 +
1819 + if (is_null_oid(&sb->final->object.oid)) {
1820 + o = sb->final->util;
1821 + sb->final_buf = xmemdupz(o->file.ptr, o->file.size);
1822 + sb->final_buf_size = o->file.size;
1823 + }
1824 + else {
1825 + o = get_origin(sb->final, path);
1826 + if (fill_blob_sha1_and_mode(o))
1827 + die(_("no such path %s in %s"), path, final_commit_name);
1828 +
1829 + if (DIFF_OPT_TST(&sb->revs->diffopt, ALLOW_TEXTCONV) &&
1830 + textconv_object(path, o->mode, &o->blob_oid, 1, (char **) &sb->final_buf,
1831 + &sb->final_buf_size))
1832 + ;
1833 + else
1834 + sb->final_buf = read_sha1_file(o->blob_oid.hash, &type,
1835 + &sb->final_buf_size);
1836 +
1837 + if (!sb->final_buf)
1838 + die(_("cannot read blob %s for path %s"),
1839 + oid_to_hex(&o->blob_oid),
1840 + path);
1841 + }
1842 + sb->num_read_blob++;
1843 + prepare_lines(sb);
1844 +
1845 + if (orig)
1846 + *orig = o;
1847 +}
blame.h
+6 -4
@@ -13,6 +13,9 @@
13 #define PICKAXE_BLAME_COPY_HARDER 04
14 #define PICKAXE_BLAME_COPY_HARDEST 010
15
16 +#define BLAME_DEFAULT_MOVE_SCORE 20
17 +#define BLAME_DEFAULT_COPY_SCORE 40
18 +
19 /*
20 * One blob in a commit that is being suspected
21 */
@@ -158,14 +161,13 @@ static inline struct blame_origin *blame_origin_incref(struct blame_origin *o)
161 }
162 extern void blame_origin_decref(struct blame_origin *o);
163
161 -extern struct blame_origin *get_origin(struct commit *commit, const char *path);
162 -
163 -extern struct commit *fake_working_tree_commit(struct diff_options *opt, const char *path, const char *contents_from);
164 -
164 extern void blame_coalesce(struct blame_scoreboard *sb);
165 extern void blame_sort_final(struct blame_scoreboard *sb);
166 extern unsigned blame_entry_score(struct blame_scoreboard *sb, struct blame_entry *e);
167 extern void assign_blame(struct blame_scoreboard *sb, int opt);
168 extern const char *blame_nth_line(struct blame_scoreboard *sb, long lno);
169
170 +extern void init_scoreboard(struct blame_scoreboard *sb);
171 +extern void setup_scoreboard(struct blame_scoreboard *sb, const char *path, struct blame_origin **orig);
172 +
173 #endif /* BLAME_H */
builtin/blame.c
-276
@@ -6,11 +6,8 @@
6 */
7
8 #include "cache.h"
9 -#include "refs.h"
9 #include "builtin.h"
10 #include "commit.h"
12 -#include "tag.h"
13 -#include "tree-walk.h"
11 #include "diff.h"
12 #include "revision.h"
13 #include "quote.h"
@@ -60,8 +57,6 @@ static struct string_list mailmap = STRING_LIST_INIT_NODUP;
57
58 static unsigned blame_move_score;
59 static unsigned blame_copy_score;
63 -#define BLAME_DEFAULT_MOVE_SCORE 20
64 -#define BLAME_DEFAULT_COPY_SCORE 40
60
61 /* Remember to update object flag allocation in object.h */
62 #define METAINFO_SHOWN (1u<<12)
@@ -72,39 +67,6 @@ struct progress_info {
67 int blamed_lines;
68 };
69
75 -static int compare_commits_by_reverse_commit_date(const void *a,
76 - const void *b,
77 - void *c)
78 -{
79 - return -compare_commits_by_commit_date(a, b, c);
80 -}
81 -
82 -/*
83 - * Fill the blob_sha1 field of an origin if it hasn't, so that later
84 - * call to fill_origin_blob() can use it to locate the data. blob_sha1
85 - * for an origin is also used to pass the blame for the entire file to
86 - * the parent to detect the case where a child's blob is identical to
87 - * that of its parent's.
88 - *
89 - * This also fills origin->mode for corresponding tree path.
90 - */
91 -static int fill_blob_sha1_and_mode(struct blame_origin *origin)
92 -{
93 - if (!is_null_oid(&origin->blob_oid))
94 - return 0;
95 - if (get_tree_entry(origin->commit->object.oid.hash,
96 - origin->path,
97 - origin->blob_oid.hash, &origin->mode))
98 - goto error_out;
99 - if (sha1_object_info(origin->blob_oid.hash, NULL) != OBJ_BLOB)
100 - goto error_out;
101 - return 0;
102 - error_out:
103 - oidclr(&origin->blob_oid);
104 - origin->mode = S_IFINVALID;
105 - return -1;
106 -}
107 -
70 static const char *nth_line_cb(void *data, long lno)
71 {
72 return blame_nth_line((struct blame_scoreboard *)data, lno);
@@ -512,40 +474,6 @@ static void output(struct blame_scoreboard *sb, int option)
474 }
475 }
476
515 -static const char *get_next_line(const char *start, const char *end)
516 -{
517 - const char *nl = memchr(start, '\n', end - start);
518 - return nl ? nl + 1 : end;
519 -}
520 -
521 -/*
522 - * To allow quick access to the contents of nth line in the
523 - * final image, prepare an index in the scoreboard.
524 - */
525 -static int prepare_lines(struct blame_scoreboard *sb)
526 -{
527 - const char *buf = sb->final_buf;
528 - unsigned long len = sb->final_buf_size;
529 - const char *end = buf + len;
530 - const char *p;
531 - int *lineno;
532 - int num = 0;
533 -
534 - for (p = buf; p < end; p = get_next_line(p, end))
535 - num++;
536 -
537 - ALLOC_ARRAY(sb->lineno, num + 1);
538 - lineno = sb->lineno;
539 -
540 - for (p = buf; p < end; p = get_next_line(p, end))
541 - *lineno++ = p - buf;
542 -
543 - *lineno = len;
544 -
545 - sb->num_lines = num;
546 - return sb->num_lines;
547 -}
548 -
477 /*
478 * Add phony grafts for use with -S; this is primarily to
479 * support git's cvsserver that wants to give a linear history
@@ -687,104 +615,6 @@ static int git_blame_config(const char *var, const char *value, void *cb)
615 return git_default_config(var, value, cb);
616 }
617
690 -static struct commit *find_single_final(struct rev_info *revs,
691 - const char **name_p)
692 -{
693 - int i;
694 - struct commit *found = NULL;
695 - const char *name = NULL;
696 -
697 - for (i = 0; i < revs->pending.nr; i++) {
698 - struct object *obj = revs->pending.objects[i].item;
699 - if (obj->flags & UNINTERESTING)
700 - continue;
701 - obj = deref_tag(obj, NULL, 0);
702 - if (obj->type != OBJ_COMMIT)
703 - die("Non commit %s?", revs->pending.objects[i].name);
704 - if (found)
705 - die("More than one commit to dig from %s and %s?",
706 - revs->pending.objects[i].name, name);
707 - found = (struct commit *)obj;
708 - name = revs->pending.objects[i].name;
709 - }
710 - if (name_p)
711 - *name_p = name;
712 - return found;
713 -}
714 -
715 -static struct commit *dwim_reverse_initial(struct rev_info *revs,
716 - const char **name_p)
717 -{
718 - /*
719 - * DWIM "git blame --reverse ONE -- PATH" as
720 - * "git blame --reverse ONE..HEAD -- PATH" but only do so
721 - * when it makes sense.
722 - */
723 - struct object *obj;
724 - struct commit *head_commit;
725 - unsigned char head_sha1[20];
726 -
727 - if (revs->pending.nr != 1)
728 - return NULL;
729 -
730 - /* Is that sole rev a committish? */
731 - obj = revs->pending.objects[0].item;
732 - obj = deref_tag(obj, NULL, 0);
733 - if (obj->type != OBJ_COMMIT)
734 - return NULL;
735 -
736 - /* Do we have HEAD? */
737 - if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, head_sha1, NULL))
738 - return NULL;
739 - head_commit = lookup_commit_reference_gently(head_sha1, 1);
740 - if (!head_commit)
741 - return NULL;
742 -
743 - /* Turn "ONE" into "ONE..HEAD" then */
744 - obj->flags |= UNINTERESTING;
745 - add_pending_object(revs, &head_commit->object, "HEAD");
746 -
747 - if (name_p)
748 - *name_p = revs->pending.objects[0].name;
749 - return (struct commit *)obj;
750 -}
751 -
752 -static struct commit *find_single_initial(struct rev_info *revs,
753 - const char **name_p)
754 -{
755 - int i;
756 - const char *final_commit_name = NULL;
757 - struct commit *found = NULL;
758 -
759 - /*
760 - * There must be one and only one negative commit, and it must be
761 - * the boundary.
762 - */
763 - for (i = 0; i < revs->pending.nr; i++) {
764 - struct object *obj = revs->pending.objects[i].item;
765 - if (!(obj->flags & UNINTERESTING))
766 - continue;
767 - obj = deref_tag(obj, NULL, 0);
768 - if (obj->type != OBJ_COMMIT)
769 - die("Non commit %s?", revs->pending.objects[i].name);
770 - if (found)
771 - die("More than one commit to dig up from, %s and %s?",
772 - revs->pending.objects[i].name,
773 - final_commit_name);
774 - found = (struct commit *) obj;
775 - final_commit_name = revs->pending.objects[i].name;
776 - }
777 -
778 - if (!final_commit_name)
779 - found = dwim_reverse_initial(revs, &final_commit_name);
780 - if (!final_commit_name)
781 - die("No commit to dig up from?");
782 -
783 - if (name_p)
784 - *name_p = final_commit_name;
785 - return found;
786 -}
787 -
618 static int blame_copy_callback(const struct option *option, const char *arg, int unset)
619 {
620 int *opt = option->value;
@@ -818,112 +648,6 @@ static int blame_move_callback(const struct option *option, const char *arg, int
648 return 0;
649 }
650
821 -void init_scoreboard(struct blame_scoreboard *sb)
822 -{
823 - memset(sb, 0, sizeof(struct blame_scoreboard));
824 - sb->move_score = BLAME_DEFAULT_MOVE_SCORE;
825 - sb->copy_score = BLAME_DEFAULT_COPY_SCORE;
826 -}
827 -
828 -void setup_scoreboard(struct blame_scoreboard *sb, const char *path, struct blame_origin **orig)
829 -{
830 - const char *final_commit_name = NULL;
831 - struct blame_origin *o;
832 - struct commit *final_commit = NULL;
833 - enum object_type type;
834 -
835 - if (sb->reverse && sb->contents_from)
836 - die(_("--contents and --reverse do not blend well."));
837 -
838 - if (!sb->reverse) {
839 - sb->final = find_single_final(sb->revs, &final_commit_name);
840 - sb->commits.compare = compare_commits_by_commit_date;
841 - } else {
842 - sb->final = find_single_initial(sb->revs, &final_commit_name);
843 - sb->commits.compare = compare_commits_by_reverse_commit_date;
844 - }
845 -
846 - if (sb->final && sb->contents_from)
847 - die(_("cannot use --contents with final commit object name"));
848 -
849 - if (sb->reverse && sb->revs->first_parent_only)
850 - sb->revs->children.name = NULL;
851 -
852 - if (!sb->final) {
853 - /*
854 - * "--not A B -- path" without anything positive;
855 - * do not default to HEAD, but use the working tree
856 - * or "--contents".
857 - */
858 - setup_work_tree();
859 - sb->final = fake_working_tree_commit(&sb->revs->diffopt,
860 - path, sb->contents_from);
861 - add_pending_object(sb->revs, &(sb->final->object), ":");
862 - }
863 -
864 - if (sb->reverse && sb->revs->first_parent_only) {
865 - final_commit = find_single_final(sb->revs, NULL);
866 - if (!final_commit)
867 - die(_("--reverse and --first-parent together require specified latest commit"));
868 - }
869 -
870 - /*
871 - * If we have bottom, this will mark the ancestors of the
872 - * bottom commits we would reach while traversing as
873 - * uninteresting.
874 - */
875 - if (prepare_revision_walk(sb->revs))
876 - die(_("revision walk setup failed"));
877 -
878 - if (sb->reverse && sb->revs->first_parent_only) {
879 - struct commit *c = final_commit;
880 -
881 - sb->revs->children.name = "children";
882 - while (c->parents &&
883 - oidcmp(&c->object.oid, &sb->final->object.oid)) {
884 - struct commit_list *l = xcalloc(1, sizeof(*l));
885 -
886 - l->item = c;
887 - if (add_decoration(&sb->revs->children,
888 - &c->parents->item->object, l))
889 - die("BUG: not unique item in first-parent chain");
890 - c = c->parents->item;
891 - }
892 -
893 - if (oidcmp(&c->object.oid, &sb->final->object.oid))
894 - die(_("--reverse --first-parent together require range along first-parent chain"));
895 - }
896 -
897 - if (is_null_oid(&sb->final->object.oid)) {
898 - o = sb->final->util;
899 - sb->final_buf = xmemdupz(o->file.ptr, o->file.size);
900 - sb->final_buf_size = o->file.size;
901 - }
902 - else {
903 - o = get_origin(sb->final, path);
904 - if (fill_blob_sha1_and_mode(o))
905 - die(_("no such path %s in %s"), path, final_commit_name);
906 -
907 - if (DIFF_OPT_TST(&sb->revs->diffopt, ALLOW_TEXTCONV) &&
908 - textconv_object(path, o->mode, &o->blob_oid, 1, (char **) &sb->final_buf,
909 - &sb->final_buf_size))
910 - ;
911 - else
912 - sb->final_buf = read_sha1_file(o->blob_oid.hash, &type,
913 - &sb->final_buf_size);
914 -
915 - if (!sb->final_buf)
916 - die(_("cannot read blob %s for path %s"),
917 - oid_to_hex(&o->blob_oid),
918 - path);
919 - }
920 - sb->num_read_blob++;
921 - prepare_lines(sb);
922 -
923 - if (orig)
924 - *orig = o;
925 -}
926 -
651 struct blame_entry *blame_entry_prepend(struct blame_entry *head,
652 long start, long end,
653 struct blame_origin *o)