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)