8ab6044414a127e358f0f4abb6977f2aba347882
   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}