]>
Commit | Line | Data |
---|---|---|
f345b0a0 JH |
1 | /* |
2 | * Copyright (C) 2005 Junio C Hamano | |
3 | */ | |
4 | #include "cache.h" | |
5 | #include "diff.h" | |
6 | #include "diffcore.h" | |
7 | #include "delta.h" | |
8 | #include "count-delta.h" | |
9 | ||
10 | static int very_different(struct diff_filespec *src, | |
11 | struct diff_filespec *dst, | |
12 | int min_score) | |
13 | { | |
14 | /* dst is recorded as a modification of src. Are they so | |
15 | * different that we are better off recording this as a pair | |
16 | * of delete and create? min_score is the minimum amount of | |
17 | * new material that must exist in the dst and not in src for | |
18 | * the pair to be considered a complete rewrite, and recommended | |
19 | * to be set to a very high value, 99% or so. | |
20 | * | |
21 | * The value we return represents the amount of new material | |
22 | * that is in dst and not in src. We return 0 when we do not | |
23 | * want to get the filepair broken. | |
24 | */ | |
25 | void *delta; | |
355e76a4 | 26 | unsigned long delta_size, base_size, src_copied, literal_added; |
f345b0a0 JH |
27 | |
28 | if (!S_ISREG(src->mode) || !S_ISREG(dst->mode)) | |
29 | return 0; /* leave symlink rename alone */ | |
30 | ||
31 | if (diff_populate_filespec(src, 1) || diff_populate_filespec(dst, 1)) | |
32 | return 0; /* error but caught downstream */ | |
33 | ||
34 | delta_size = ((src->size < dst->size) ? | |
35 | (dst->size - src->size) : (src->size - dst->size)); | |
36 | ||
37 | /* Notice that we use max of src and dst as the base size, | |
38 | * unlike rename similarity detection. This is so that we do | |
39 | * not mistake a large addition as a complete rewrite. | |
40 | */ | |
41 | base_size = ((src->size < dst->size) ? dst->size : src->size); | |
42 | ||
43 | /* | |
44 | * If file size difference is too big compared to the | |
45 | * base_size, we declare this a complete rewrite. | |
46 | */ | |
47 | if (base_size * min_score < delta_size * MAX_SCORE) | |
48 | return MAX_SCORE; | |
49 | ||
50 | if (diff_populate_filespec(src, 0) || diff_populate_filespec(dst, 0)) | |
51 | return 0; /* error but caught downstream */ | |
52 | ||
53 | delta = diff_delta(src->data, src->size, | |
54 | dst->data, dst->size, | |
55 | &delta_size); | |
56 | ||
57 | /* A delta that has a lot of literal additions would have | |
58 | * big delta_size no matter what else it does. | |
59 | */ | |
60 | if (base_size * min_score < delta_size * MAX_SCORE) | |
61 | return MAX_SCORE; | |
62 | ||
63 | /* Estimate the edit size by interpreting delta. */ | |
355e76a4 JH |
64 | if (count_delta(delta, delta_size, &src_copied, &literal_added)) { |
65 | free(delta); | |
66 | return 0; | |
67 | } | |
f345b0a0 | 68 | free(delta); |
355e76a4 JH |
69 | |
70 | /* Extent of damage */ | |
71 | if (src->size + literal_added < src_copied) | |
72 | delta_size = 0; | |
73 | else | |
74 | delta_size = (src->size - src_copied) + literal_added; | |
f345b0a0 JH |
75 | |
76 | if (base_size < delta_size) | |
77 | return MAX_SCORE; | |
78 | ||
79 | return delta_size * MAX_SCORE / base_size; | |
80 | } | |
81 | ||
82 | void diffcore_break(int min_score) | |
83 | { | |
84 | struct diff_queue_struct *q = &diff_queued_diff; | |
85 | struct diff_queue_struct outq; | |
86 | int i; | |
87 | ||
88 | if (!min_score) | |
89 | min_score = DEFAULT_BREAK_SCORE; | |
90 | ||
91 | outq.nr = outq.alloc = 0; | |
92 | outq.queue = NULL; | |
93 | ||
94 | for (i = 0; i < q->nr; i++) { | |
95 | struct diff_filepair *p = q->queue[i]; | |
96 | int score; | |
97 | ||
98 | /* We deal only with in-place edit of non directory. | |
99 | * We do not break anything else. | |
100 | */ | |
101 | if (DIFF_FILE_VALID(p->one) && DIFF_FILE_VALID(p->two) && | |
102 | !S_ISDIR(p->one->mode) && !S_ISDIR(p->two->mode) && | |
103 | !strcmp(p->one->path, p->two->path)) { | |
104 | score = very_different(p->one, p->two, min_score); | |
105 | if (min_score <= score) { | |
106 | /* Split this into delete and create */ | |
107 | struct diff_filespec *null_one, *null_two; | |
108 | struct diff_filepair *dp; | |
109 | ||
110 | /* deletion of one */ | |
111 | null_one = alloc_filespec(p->one->path); | |
112 | dp = diff_queue(&outq, p->one, null_one); | |
113 | dp->score = score; | |
114 | dp->broken_pair = 1; | |
115 | ||
116 | /* creation of two */ | |
117 | null_two = alloc_filespec(p->two->path); | |
118 | dp = diff_queue(&outq, null_two, p->two); | |
119 | dp->score = score; | |
120 | dp->broken_pair = 1; | |
121 | ||
122 | free(p); /* not diff_free_filepair(), we are | |
123 | * reusing one and two here. | |
124 | */ | |
125 | continue; | |
126 | } | |
127 | } | |
128 | diff_q(&outq, p); | |
129 | } | |
130 | free(q->queue); | |
131 | *q = outq; | |
132 | ||
133 | return; | |
134 | } |