]> git.ipfire.org Git - thirdparty/git.git/blame - commit-reach.c
commit.h: remove method declarations
[thirdparty/git.git] / commit-reach.c
CommitLineData
5227c385
DS
1#include "cache.h"
2#include "prio-queue.h"
3#include "commit.h"
4#include "commit-reach.h"
5
6/* Remember to update object flag allocation in object.h */
7#define PARENT1 (1u<<16)
8#define PARENT2 (1u<<17)
9#define STALE (1u<<18)
10#define RESULT (1u<<19)
11
12static const unsigned all_flags = (PARENT1 | PARENT2 | STALE | RESULT);
13
14static int queue_has_nonstale(struct prio_queue *queue)
15{
16 int i;
17 for (i = 0; i < queue->nr; i++) {
18 struct commit *commit = queue->array[i].data;
19 if (!(commit->object.flags & STALE))
20 return 1;
21 }
22 return 0;
23}
24
25/* all input commits in one and twos[] must have been parsed! */
26static struct commit_list *paint_down_to_common(struct commit *one, int n,
27 struct commit **twos,
28 int min_generation)
29{
30 struct prio_queue queue = { compare_commits_by_gen_then_commit_date };
31 struct commit_list *result = NULL;
32 int i;
33 uint32_t last_gen = GENERATION_NUMBER_INFINITY;
34
35 one->object.flags |= PARENT1;
36 if (!n) {
37 commit_list_append(one, &result);
38 return result;
39 }
40 prio_queue_put(&queue, one);
41
42 for (i = 0; i < n; i++) {
43 twos[i]->object.flags |= PARENT2;
44 prio_queue_put(&queue, twos[i]);
45 }
46
47 while (queue_has_nonstale(&queue)) {
48 struct commit *commit = prio_queue_get(&queue);
49 struct commit_list *parents;
50 int flags;
51
52 if (commit->generation > last_gen)
53 BUG("bad generation skip %8x > %8x at %s",
54 commit->generation, last_gen,
55 oid_to_hex(&commit->object.oid));
56 last_gen = commit->generation;
57
58 if (commit->generation < min_generation)
59 break;
60
61 flags = commit->object.flags & (PARENT1 | PARENT2 | STALE);
62 if (flags == (PARENT1 | PARENT2)) {
63 if (!(commit->object.flags & RESULT)) {
64 commit->object.flags |= RESULT;
65 commit_list_insert_by_date(commit, &result);
66 }
67 /* Mark parents of a found merge stale */
68 flags |= STALE;
69 }
70 parents = commit->parents;
71 while (parents) {
72 struct commit *p = parents->item;
73 parents = parents->next;
74 if ((p->object.flags & flags) == flags)
75 continue;
76 if (parse_commit(p))
77 return NULL;
78 p->object.flags |= flags;
79 prio_queue_put(&queue, p);
80 }
81 }
82
83 clear_prio_queue(&queue);
84 return result;
85}
86
87static struct commit_list *merge_bases_many(struct commit *one, int n, struct commit **twos)
88{
89 struct commit_list *list = NULL;
90 struct commit_list *result = NULL;
91 int i;
92
93 for (i = 0; i < n; i++) {
94 if (one == twos[i])
95 /*
96 * We do not mark this even with RESULT so we do not
97 * have to clean it up.
98 */
99 return commit_list_insert(one, &result);
100 }
101
102 if (parse_commit(one))
103 return NULL;
104 for (i = 0; i < n; i++) {
105 if (parse_commit(twos[i]))
106 return NULL;
107 }
108
109 list = paint_down_to_common(one, n, twos, 0);
110
111 while (list) {
112 struct commit *commit = pop_commit(&list);
113 if (!(commit->object.flags & STALE))
114 commit_list_insert_by_date(commit, &result);
115 }
116 return result;
117}
118
119struct commit_list *get_octopus_merge_bases(struct commit_list *in)
120{
121 struct commit_list *i, *j, *k, *ret = NULL;
122
123 if (!in)
124 return ret;
125
126 commit_list_insert(in->item, &ret);
127
128 for (i = in->next; i; i = i->next) {
129 struct commit_list *new_commits = NULL, *end = NULL;
130
131 for (j = ret; j; j = j->next) {
132 struct commit_list *bases;
133 bases = get_merge_bases(i->item, j->item);
134 if (!new_commits)
135 new_commits = bases;
136 else
137 end->next = bases;
138 for (k = bases; k; k = k->next)
139 end = k;
140 }
141 ret = new_commits;
142 }
143 return ret;
144}
145
146static int remove_redundant(struct commit **array, int cnt)
147{
148 /*
149 * Some commit in the array may be an ancestor of
150 * another commit. Move such commit to the end of
151 * the array, and return the number of commits that
152 * are independent from each other.
153 */
154 struct commit **work;
155 unsigned char *redundant;
156 int *filled_index;
157 int i, j, filled;
158
159 work = xcalloc(cnt, sizeof(*work));
160 redundant = xcalloc(cnt, 1);
161 ALLOC_ARRAY(filled_index, cnt - 1);
162
163 for (i = 0; i < cnt; i++)
164 parse_commit(array[i]);
165 for (i = 0; i < cnt; i++) {
166 struct commit_list *common;
167 uint32_t min_generation = array[i]->generation;
168
169 if (redundant[i])
170 continue;
171 for (j = filled = 0; j < cnt; j++) {
172 if (i == j || redundant[j])
173 continue;
174 filled_index[filled] = j;
175 work[filled++] = array[j];
176
177 if (array[j]->generation < min_generation)
178 min_generation = array[j]->generation;
179 }
180 common = paint_down_to_common(array[i], filled, work,
181 min_generation);
182 if (array[i]->object.flags & PARENT2)
183 redundant[i] = 1;
184 for (j = 0; j < filled; j++)
185 if (work[j]->object.flags & PARENT1)
186 redundant[filled_index[j]] = 1;
187 clear_commit_marks(array[i], all_flags);
188 clear_commit_marks_many(filled, work, all_flags);
189 free_commit_list(common);
190 }
191
192 /* Now collect the result */
193 COPY_ARRAY(work, array, cnt);
194 for (i = filled = 0; i < cnt; i++)
195 if (!redundant[i])
196 array[filled++] = work[i];
197 for (j = filled, i = 0; i < cnt; i++)
198 if (redundant[i])
199 array[j++] = work[i];
200 free(work);
201 free(redundant);
202 free(filled_index);
203 return filled;
204}
205
206static struct commit_list *get_merge_bases_many_0(struct commit *one,
207 int n,
208 struct commit **twos,
209 int cleanup)
210{
211 struct commit_list *list;
212 struct commit **rslt;
213 struct commit_list *result;
214 int cnt, i;
215
216 result = merge_bases_many(one, n, twos);
217 for (i = 0; i < n; i++) {
218 if (one == twos[i])
219 return result;
220 }
221 if (!result || !result->next) {
222 if (cleanup) {
223 clear_commit_marks(one, all_flags);
224 clear_commit_marks_many(n, twos, all_flags);
225 }
226 return result;
227 }
228
229 /* There are more than one */
230 cnt = commit_list_count(result);
231 rslt = xcalloc(cnt, sizeof(*rslt));
232 for (list = result, i = 0; list; list = list->next)
233 rslt[i++] = list->item;
234 free_commit_list(result);
235
236 clear_commit_marks(one, all_flags);
237 clear_commit_marks_many(n, twos, all_flags);
238
239 cnt = remove_redundant(rslt, cnt);
240 result = NULL;
241 for (i = 0; i < cnt; i++)
242 commit_list_insert_by_date(rslt[i], &result);
243 free(rslt);
244 return result;
245}
246
247struct commit_list *get_merge_bases_many(struct commit *one,
248 int n,
249 struct commit **twos)
250{
251 return get_merge_bases_many_0(one, n, twos, 1);
252}
253
254struct commit_list *get_merge_bases_many_dirty(struct commit *one,
255 int n,
256 struct commit **twos)
257{
258 return get_merge_bases_many_0(one, n, twos, 0);
259}
260
261struct commit_list *get_merge_bases(struct commit *one, struct commit *two)
262{
263 return get_merge_bases_many_0(one, 1, &two, 1);
264}
265
266/*
267 * Is "commit" a descendant of one of the elements on the "with_commit" list?
268 */
269int is_descendant_of(struct commit *commit, struct commit_list *with_commit)
270{
271 if (!with_commit)
272 return 1;
273 while (with_commit) {
274 struct commit *other;
275
276 other = with_commit->item;
277 with_commit = with_commit->next;
278 if (in_merge_bases(other, commit))
279 return 1;
280 }
281 return 0;
282}
283
284/*
285 * Is "commit" an ancestor of one of the "references"?
286 */
287int in_merge_bases_many(struct commit *commit, int nr_reference, struct commit **reference)
288{
289 struct commit_list *bases;
290 int ret = 0, i;
291 uint32_t min_generation = GENERATION_NUMBER_INFINITY;
292
293 if (parse_commit(commit))
294 return ret;
295 for (i = 0; i < nr_reference; i++) {
296 if (parse_commit(reference[i]))
297 return ret;
298 if (reference[i]->generation < min_generation)
299 min_generation = reference[i]->generation;
300 }
301
302 if (commit->generation > min_generation)
303 return ret;
304
305 bases = paint_down_to_common(commit, nr_reference, reference, commit->generation);
306 if (commit->object.flags & PARENT2)
307 ret = 1;
308 clear_commit_marks(commit, all_flags);
309 clear_commit_marks_many(nr_reference, reference, all_flags);
310 free_commit_list(bases);
311 return ret;
312}
313
314/*
315 * Is "commit" an ancestor of (i.e. reachable from) the "reference"?
316 */
317int in_merge_bases(struct commit *commit, struct commit *reference)
318{
319 return in_merge_bases_many(commit, 1, &reference);
320}
321
322struct commit_list *reduce_heads(struct commit_list *heads)
323{
324 struct commit_list *p;
325 struct commit_list *result = NULL, **tail = &result;
326 struct commit **array;
327 int num_head, i;
328
329 if (!heads)
330 return NULL;
331
332 /* Uniquify */
333 for (p = heads; p; p = p->next)
334 p->item->object.flags &= ~STALE;
335 for (p = heads, num_head = 0; p; p = p->next) {
336 if (p->item->object.flags & STALE)
337 continue;
338 p->item->object.flags |= STALE;
339 num_head++;
340 }
341 array = xcalloc(num_head, sizeof(*array));
342 for (p = heads, i = 0; p; p = p->next) {
343 if (p->item->object.flags & STALE) {
344 array[i++] = p->item;
345 p->item->object.flags &= ~STALE;
346 }
347 }
348 num_head = remove_redundant(array, num_head);
349 for (i = 0; i < num_head; i++)
350 tail = &commit_list_insert(array[i], tail)->next;
351 free(array);
352 return result;
353}
354
355void reduce_heads_replace(struct commit_list **heads)
356{
357 struct commit_list *result = reduce_heads(*heads);
358 free_commit_list(*heads);
359 *heads = result;
360}