commit-reach: move ref_newer from remote.c
[git/raj.git] / commit-reach.c
bloba6bc4781a63d118d989599241057ec95fa39da5b
1 #include "cache.h"
2 #include "commit.h"
3 #include "decorate.h"
4 #include "prio-queue.h"
5 #include "tree.h"
6 #include "revision.h"
7 #include "tag.h"
8 #include "commit-reach.h"
10 /* Remember to update object flag allocation in object.h */
11 #define PARENT1 (1u<<16)
12 #define PARENT2 (1u<<17)
13 #define STALE (1u<<18)
14 #define RESULT (1u<<19)
16 static const unsigned all_flags = (PARENT1 | PARENT2 | STALE | RESULT);
18 static int queue_has_nonstale(struct prio_queue *queue)
20 int i;
21 for (i = 0; i < queue->nr; i++) {
22 struct commit *commit = queue->array[i].data;
23 if (!(commit->object.flags & STALE))
24 return 1;
26 return 0;
29 /* all input commits in one and twos[] must have been parsed! */
30 static struct commit_list *paint_down_to_common(struct commit *one, int n,
31 struct commit **twos,
32 int min_generation)
34 struct prio_queue queue = { compare_commits_by_gen_then_commit_date };
35 struct commit_list *result = NULL;
36 int i;
37 uint32_t last_gen = GENERATION_NUMBER_INFINITY;
39 one->object.flags |= PARENT1;
40 if (!n) {
41 commit_list_append(one, &result);
42 return result;
44 prio_queue_put(&queue, one);
46 for (i = 0; i < n; i++) {
47 twos[i]->object.flags |= PARENT2;
48 prio_queue_put(&queue, twos[i]);
51 while (queue_has_nonstale(&queue)) {
52 struct commit *commit = prio_queue_get(&queue);
53 struct commit_list *parents;
54 int flags;
56 if (commit->generation > last_gen)
57 BUG("bad generation skip %8x > %8x at %s",
58 commit->generation, last_gen,
59 oid_to_hex(&commit->object.oid));
60 last_gen = commit->generation;
62 if (commit->generation < min_generation)
63 break;
65 flags = commit->object.flags & (PARENT1 | PARENT2 | STALE);
66 if (flags == (PARENT1 | PARENT2)) {
67 if (!(commit->object.flags & RESULT)) {
68 commit->object.flags |= RESULT;
69 commit_list_insert_by_date(commit, &result);
71 /* Mark parents of a found merge stale */
72 flags |= STALE;
74 parents = commit->parents;
75 while (parents) {
76 struct commit *p = parents->item;
77 parents = parents->next;
78 if ((p->object.flags & flags) == flags)
79 continue;
80 if (parse_commit(p))
81 return NULL;
82 p->object.flags |= flags;
83 prio_queue_put(&queue, p);
87 clear_prio_queue(&queue);
88 return result;
91 static struct commit_list *merge_bases_many(struct commit *one, int n, struct commit **twos)
93 struct commit_list *list = NULL;
94 struct commit_list *result = NULL;
95 int i;
97 for (i = 0; i < n; i++) {
98 if (one == twos[i])
100 * We do not mark this even with RESULT so we do not
101 * have to clean it up.
103 return commit_list_insert(one, &result);
106 if (parse_commit(one))
107 return NULL;
108 for (i = 0; i < n; i++) {
109 if (parse_commit(twos[i]))
110 return NULL;
113 list = paint_down_to_common(one, n, twos, 0);
115 while (list) {
116 struct commit *commit = pop_commit(&list);
117 if (!(commit->object.flags & STALE))
118 commit_list_insert_by_date(commit, &result);
120 return result;
123 struct commit_list *get_octopus_merge_bases(struct commit_list *in)
125 struct commit_list *i, *j, *k, *ret = NULL;
127 if (!in)
128 return ret;
130 commit_list_insert(in->item, &ret);
132 for (i = in->next; i; i = i->next) {
133 struct commit_list *new_commits = NULL, *end = NULL;
135 for (j = ret; j; j = j->next) {
136 struct commit_list *bases;
137 bases = get_merge_bases(i->item, j->item);
138 if (!new_commits)
139 new_commits = bases;
140 else
141 end->next = bases;
142 for (k = bases; k; k = k->next)
143 end = k;
145 ret = new_commits;
147 return ret;
150 static int remove_redundant(struct commit **array, int cnt)
153 * Some commit in the array may be an ancestor of
154 * another commit. Move such commit to the end of
155 * the array, and return the number of commits that
156 * are independent from each other.
158 struct commit **work;
159 unsigned char *redundant;
160 int *filled_index;
161 int i, j, filled;
163 work = xcalloc(cnt, sizeof(*work));
164 redundant = xcalloc(cnt, 1);
165 ALLOC_ARRAY(filled_index, cnt - 1);
167 for (i = 0; i < cnt; i++)
168 parse_commit(array[i]);
169 for (i = 0; i < cnt; i++) {
170 struct commit_list *common;
171 uint32_t min_generation = array[i]->generation;
173 if (redundant[i])
174 continue;
175 for (j = filled = 0; j < cnt; j++) {
176 if (i == j || redundant[j])
177 continue;
178 filled_index[filled] = j;
179 work[filled++] = array[j];
181 if (array[j]->generation < min_generation)
182 min_generation = array[j]->generation;
184 common = paint_down_to_common(array[i], filled, work,
185 min_generation);
186 if (array[i]->object.flags & PARENT2)
187 redundant[i] = 1;
188 for (j = 0; j < filled; j++)
189 if (work[j]->object.flags & PARENT1)
190 redundant[filled_index[j]] = 1;
191 clear_commit_marks(array[i], all_flags);
192 clear_commit_marks_many(filled, work, all_flags);
193 free_commit_list(common);
196 /* Now collect the result */
197 COPY_ARRAY(work, array, cnt);
198 for (i = filled = 0; i < cnt; i++)
199 if (!redundant[i])
200 array[filled++] = work[i];
201 for (j = filled, i = 0; i < cnt; i++)
202 if (redundant[i])
203 array[j++] = work[i];
204 free(work);
205 free(redundant);
206 free(filled_index);
207 return filled;
210 static struct commit_list *get_merge_bases_many_0(struct commit *one,
211 int n,
212 struct commit **twos,
213 int cleanup)
215 struct commit_list *list;
216 struct commit **rslt;
217 struct commit_list *result;
218 int cnt, i;
220 result = merge_bases_many(one, n, twos);
221 for (i = 0; i < n; i++) {
222 if (one == twos[i])
223 return result;
225 if (!result || !result->next) {
226 if (cleanup) {
227 clear_commit_marks(one, all_flags);
228 clear_commit_marks_many(n, twos, all_flags);
230 return result;
233 /* There are more than one */
234 cnt = commit_list_count(result);
235 rslt = xcalloc(cnt, sizeof(*rslt));
236 for (list = result, i = 0; list; list = list->next)
237 rslt[i++] = list->item;
238 free_commit_list(result);
240 clear_commit_marks(one, all_flags);
241 clear_commit_marks_many(n, twos, all_flags);
243 cnt = remove_redundant(rslt, cnt);
244 result = NULL;
245 for (i = 0; i < cnt; i++)
246 commit_list_insert_by_date(rslt[i], &result);
247 free(rslt);
248 return result;
251 struct commit_list *get_merge_bases_many(struct commit *one,
252 int n,
253 struct commit **twos)
255 return get_merge_bases_many_0(one, n, twos, 1);
258 struct commit_list *get_merge_bases_many_dirty(struct commit *one,
259 int n,
260 struct commit **twos)
262 return get_merge_bases_many_0(one, n, twos, 0);
265 struct commit_list *get_merge_bases(struct commit *one, struct commit *two)
267 return get_merge_bases_many_0(one, 1, &two, 1);
271 * Is "commit" a descendant of one of the elements on the "with_commit" list?
273 int is_descendant_of(struct commit *commit, struct commit_list *with_commit)
275 if (!with_commit)
276 return 1;
277 while (with_commit) {
278 struct commit *other;
280 other = with_commit->item;
281 with_commit = with_commit->next;
282 if (in_merge_bases(other, commit))
283 return 1;
285 return 0;
289 * Is "commit" an ancestor of one of the "references"?
291 int in_merge_bases_many(struct commit *commit, int nr_reference, struct commit **reference)
293 struct commit_list *bases;
294 int ret = 0, i;
295 uint32_t min_generation = GENERATION_NUMBER_INFINITY;
297 if (parse_commit(commit))
298 return ret;
299 for (i = 0; i < nr_reference; i++) {
300 if (parse_commit(reference[i]))
301 return ret;
302 if (reference[i]->generation < min_generation)
303 min_generation = reference[i]->generation;
306 if (commit->generation > min_generation)
307 return ret;
309 bases = paint_down_to_common(commit, nr_reference, reference, commit->generation);
310 if (commit->object.flags & PARENT2)
311 ret = 1;
312 clear_commit_marks(commit, all_flags);
313 clear_commit_marks_many(nr_reference, reference, all_flags);
314 free_commit_list(bases);
315 return ret;
319 * Is "commit" an ancestor of (i.e. reachable from) the "reference"?
321 int in_merge_bases(struct commit *commit, struct commit *reference)
323 return in_merge_bases_many(commit, 1, &reference);
326 struct commit_list *reduce_heads(struct commit_list *heads)
328 struct commit_list *p;
329 struct commit_list *result = NULL, **tail = &result;
330 struct commit **array;
331 int num_head, i;
333 if (!heads)
334 return NULL;
336 /* Uniquify */
337 for (p = heads; p; p = p->next)
338 p->item->object.flags &= ~STALE;
339 for (p = heads, num_head = 0; p; p = p->next) {
340 if (p->item->object.flags & STALE)
341 continue;
342 p->item->object.flags |= STALE;
343 num_head++;
345 array = xcalloc(num_head, sizeof(*array));
346 for (p = heads, i = 0; p; p = p->next) {
347 if (p->item->object.flags & STALE) {
348 array[i++] = p->item;
349 p->item->object.flags &= ~STALE;
352 num_head = remove_redundant(array, num_head);
353 for (i = 0; i < num_head; i++)
354 tail = &commit_list_insert(array[i], tail)->next;
355 free(array);
356 return result;
359 void reduce_heads_replace(struct commit_list **heads)
361 struct commit_list *result = reduce_heads(*heads);
362 free_commit_list(*heads);
363 *heads = result;
366 static void unmark_and_free(struct commit_list *list, unsigned int mark)
368 while (list) {
369 struct commit *commit = pop_commit(&list);
370 commit->object.flags &= ~mark;
374 int ref_newer(const struct object_id *new_oid, const struct object_id *old_oid)
376 struct object *o;
377 struct commit *old_commit, *new_commit;
378 struct commit_list *list, *used;
379 int found = 0;
382 * Both new_commit and old_commit must be commit-ish and new_commit is descendant of
383 * old_commit. Otherwise we require --force.
385 o = deref_tag(the_repository, parse_object(the_repository, old_oid),
386 NULL, 0);
387 if (!o || o->type != OBJ_COMMIT)
388 return 0;
389 old_commit = (struct commit *) o;
391 o = deref_tag(the_repository, parse_object(the_repository, new_oid),
392 NULL, 0);
393 if (!o || o->type != OBJ_COMMIT)
394 return 0;
395 new_commit = (struct commit *) o;
397 if (parse_commit(new_commit) < 0)
398 return 0;
400 used = list = NULL;
401 commit_list_insert(new_commit, &list);
402 while (list) {
403 new_commit = pop_most_recent_commit(&list, TMP_MARK);
404 commit_list_insert(new_commit, &used);
405 if (new_commit == old_commit) {
406 found = 1;
407 break;
410 unmark_and_free(list, TMP_MARK);
411 unmark_and_free(used, TMP_MARK);
412 return found;