commit-reach.con commit Merge branch 'sb/string-list-remove-unused' (f8649f8)
   1#include "cache.h"
   2#include "commit.h"
   3#include "commit-graph.h"
   4#include "decorate.h"
   5#include "prio-queue.h"
   6#include "tree.h"
   7#include "ref-filter.h"
   8#include "revision.h"
   9#include "tag.h"
  10#include "commit-reach.h"
  11
  12/* Remember to update object flag allocation in object.h */
  13#define REACHABLE       (1u<<15)
  14#define PARENT1         (1u<<16)
  15#define PARENT2         (1u<<17)
  16#define STALE           (1u<<18)
  17#define RESULT          (1u<<19)
  18
  19static const unsigned all_flags = (PARENT1 | PARENT2 | STALE | RESULT);
  20
  21static int queue_has_nonstale(struct prio_queue *queue)
  22{
  23        int i;
  24        for (i = 0; i < queue->nr; i++) {
  25                struct commit *commit = queue->array[i].data;
  26                if (!(commit->object.flags & STALE))
  27                        return 1;
  28        }
  29        return 0;
  30}
  31
  32/* all input commits in one and twos[] must have been parsed! */
  33static struct commit_list *paint_down_to_common(struct commit *one, int n,
  34                                                struct commit **twos,
  35                                                int min_generation)
  36{
  37        struct prio_queue queue = { compare_commits_by_gen_then_commit_date };
  38        struct commit_list *result = NULL;
  39        int i;
  40        uint32_t last_gen = GENERATION_NUMBER_INFINITY;
  41
  42        if (!min_generation)
  43                queue.compare = compare_commits_by_commit_date;
  44
  45        one->object.flags |= PARENT1;
  46        if (!n) {
  47                commit_list_append(one, &result);
  48                return result;
  49        }
  50        prio_queue_put(&queue, one);
  51
  52        for (i = 0; i < n; i++) {
  53                twos[i]->object.flags |= PARENT2;
  54                prio_queue_put(&queue, twos[i]);
  55        }
  56
  57        while (queue_has_nonstale(&queue)) {
  58                struct commit *commit = prio_queue_get(&queue);
  59                struct commit_list *parents;
  60                int flags;
  61
  62                if (min_generation && commit->generation > last_gen)
  63                        BUG("bad generation skip %8x > %8x at %s",
  64                            commit->generation, last_gen,
  65                            oid_to_hex(&commit->object.oid));
  66                last_gen = commit->generation;
  67
  68                if (commit->generation < min_generation)
  69                        break;
  70
  71                flags = commit->object.flags & (PARENT1 | PARENT2 | STALE);
  72                if (flags == (PARENT1 | PARENT2)) {
  73                        if (!(commit->object.flags & RESULT)) {
  74                                commit->object.flags |= RESULT;
  75                                commit_list_insert_by_date(commit, &result);
  76                        }
  77                        /* Mark parents of a found merge stale */
  78                        flags |= STALE;
  79                }
  80                parents = commit->parents;
  81                while (parents) {
  82                        struct commit *p = parents->item;
  83                        parents = parents->next;
  84                        if ((p->object.flags & flags) == flags)
  85                                continue;
  86                        if (parse_commit(p))
  87                                return NULL;
  88                        p->object.flags |= flags;
  89                        prio_queue_put(&queue, p);
  90                }
  91        }
  92
  93        clear_prio_queue(&queue);
  94        return result;
  95}
  96
  97static struct commit_list *merge_bases_many(struct commit *one, int n, struct commit **twos)
  98{
  99        struct commit_list *list = NULL;
 100        struct commit_list *result = NULL;
 101        int i;
 102
 103        for (i = 0; i < n; i++) {
 104                if (one == twos[i])
 105                        /*
 106                         * We do not mark this even with RESULT so we do not
 107                         * have to clean it up.
 108                         */
 109                        return commit_list_insert(one, &result);
 110        }
 111
 112        if (parse_commit(one))
 113                return NULL;
 114        for (i = 0; i < n; i++) {
 115                if (parse_commit(twos[i]))
 116                        return NULL;
 117        }
 118
 119        list = paint_down_to_common(one, n, twos, 0);
 120
 121        while (list) {
 122                struct commit *commit = pop_commit(&list);
 123                if (!(commit->object.flags & STALE))
 124                        commit_list_insert_by_date(commit, &result);
 125        }
 126        return result;
 127}
 128
 129struct commit_list *get_octopus_merge_bases(struct commit_list *in)
 130{
 131        struct commit_list *i, *j, *k, *ret = NULL;
 132
 133        if (!in)
 134                return ret;
 135
 136        commit_list_insert(in->item, &ret);
 137
 138        for (i = in->next; i; i = i->next) {
 139                struct commit_list *new_commits = NULL, *end = NULL;
 140
 141                for (j = ret; j; j = j->next) {
 142                        struct commit_list *bases;
 143                        bases = get_merge_bases(i->item, j->item);
 144                        if (!new_commits)
 145                                new_commits = bases;
 146                        else
 147                                end->next = bases;
 148                        for (k = bases; k; k = k->next)
 149                                end = k;
 150                }
 151                ret = new_commits;
 152        }
 153        return ret;
 154}
 155
 156static int remove_redundant(struct commit **array, int cnt)
 157{
 158        /*
 159         * Some commit in the array may be an ancestor of
 160         * another commit.  Move such commit to the end of
 161         * the array, and return the number of commits that
 162         * are independent from each other.
 163         */
 164        struct commit **work;
 165        unsigned char *redundant;
 166        int *filled_index;
 167        int i, j, filled;
 168
 169        work = xcalloc(cnt, sizeof(*work));
 170        redundant = xcalloc(cnt, 1);
 171        ALLOC_ARRAY(filled_index, cnt - 1);
 172
 173        for (i = 0; i < cnt; i++)
 174                parse_commit(array[i]);
 175        for (i = 0; i < cnt; i++) {
 176                struct commit_list *common;
 177                uint32_t min_generation = array[i]->generation;
 178
 179                if (redundant[i])
 180                        continue;
 181                for (j = filled = 0; j < cnt; j++) {
 182                        if (i == j || redundant[j])
 183                                continue;
 184                        filled_index[filled] = j;
 185                        work[filled++] = array[j];
 186
 187                        if (array[j]->generation < min_generation)
 188                                min_generation = array[j]->generation;
 189                }
 190                common = paint_down_to_common(array[i], filled, work,
 191                                              min_generation);
 192                if (array[i]->object.flags & PARENT2)
 193                        redundant[i] = 1;
 194                for (j = 0; j < filled; j++)
 195                        if (work[j]->object.flags & PARENT1)
 196                                redundant[filled_index[j]] = 1;
 197                clear_commit_marks(array[i], all_flags);
 198                clear_commit_marks_many(filled, work, all_flags);
 199                free_commit_list(common);
 200        }
 201
 202        /* Now collect the result */
 203        COPY_ARRAY(work, array, cnt);
 204        for (i = filled = 0; i < cnt; i++)
 205                if (!redundant[i])
 206                        array[filled++] = work[i];
 207        for (j = filled, i = 0; i < cnt; i++)
 208                if (redundant[i])
 209                        array[j++] = work[i];
 210        free(work);
 211        free(redundant);
 212        free(filled_index);
 213        return filled;
 214}
 215
 216static struct commit_list *get_merge_bases_many_0(struct commit *one,
 217                                                  int n,
 218                                                  struct commit **twos,
 219                                                  int cleanup)
 220{
 221        struct commit_list *list;
 222        struct commit **rslt;
 223        struct commit_list *result;
 224        int cnt, i;
 225
 226        result = merge_bases_many(one, n, twos);
 227        for (i = 0; i < n; i++) {
 228                if (one == twos[i])
 229                        return result;
 230        }
 231        if (!result || !result->next) {
 232                if (cleanup) {
 233                        clear_commit_marks(one, all_flags);
 234                        clear_commit_marks_many(n, twos, all_flags);
 235                }
 236                return result;
 237        }
 238
 239        /* There are more than one */
 240        cnt = commit_list_count(result);
 241        rslt = xcalloc(cnt, sizeof(*rslt));
 242        for (list = result, i = 0; list; list = list->next)
 243                rslt[i++] = list->item;
 244        free_commit_list(result);
 245
 246        clear_commit_marks(one, all_flags);
 247        clear_commit_marks_many(n, twos, all_flags);
 248
 249        cnt = remove_redundant(rslt, cnt);
 250        result = NULL;
 251        for (i = 0; i < cnt; i++)
 252                commit_list_insert_by_date(rslt[i], &result);
 253        free(rslt);
 254        return result;
 255}
 256
 257struct commit_list *get_merge_bases_many(struct commit *one,
 258                                         int n,
 259                                         struct commit **twos)
 260{
 261        return get_merge_bases_many_0(one, n, twos, 1);
 262}
 263
 264struct commit_list *get_merge_bases_many_dirty(struct commit *one,
 265                                               int n,
 266                                               struct commit **twos)
 267{
 268        return get_merge_bases_many_0(one, n, twos, 0);
 269}
 270
 271struct commit_list *get_merge_bases(struct commit *one, struct commit *two)
 272{
 273        return get_merge_bases_many_0(one, 1, &two, 1);
 274}
 275
 276/*
 277 * Is "commit" a descendant of one of the elements on the "with_commit" list?
 278 */
 279int is_descendant_of(struct commit *commit, struct commit_list *with_commit)
 280{
 281        if (!with_commit)
 282                return 1;
 283
 284        if (generation_numbers_enabled(the_repository)) {
 285                struct commit_list *from_list = NULL;
 286                int result;
 287                commit_list_insert(commit, &from_list);
 288                result = can_all_from_reach(from_list, with_commit, 0);
 289                free_commit_list(from_list);
 290                return result;
 291        } else {
 292                while (with_commit) {
 293                        struct commit *other;
 294
 295                        other = with_commit->item;
 296                        with_commit = with_commit->next;
 297                        if (in_merge_bases(other, commit))
 298                                return 1;
 299                }
 300                return 0;
 301        }
 302}
 303
 304/*
 305 * Is "commit" an ancestor of one of the "references"?
 306 */
 307int in_merge_bases_many(struct commit *commit, int nr_reference, struct commit **reference)
 308{
 309        struct commit_list *bases;
 310        int ret = 0, i;
 311        uint32_t min_generation = GENERATION_NUMBER_INFINITY;
 312
 313        if (parse_commit(commit))
 314                return ret;
 315        for (i = 0; i < nr_reference; i++) {
 316                if (parse_commit(reference[i]))
 317                        return ret;
 318                if (reference[i]->generation < min_generation)
 319                        min_generation = reference[i]->generation;
 320        }
 321
 322        if (commit->generation > min_generation)
 323                return ret;
 324
 325        bases = paint_down_to_common(commit, nr_reference, reference, commit->generation);
 326        if (commit->object.flags & PARENT2)
 327                ret = 1;
 328        clear_commit_marks(commit, all_flags);
 329        clear_commit_marks_many(nr_reference, reference, all_flags);
 330        free_commit_list(bases);
 331        return ret;
 332}
 333
 334/*
 335 * Is "commit" an ancestor of (i.e. reachable from) the "reference"?
 336 */
 337int in_merge_bases(struct commit *commit, struct commit *reference)
 338{
 339        return in_merge_bases_many(commit, 1, &reference);
 340}
 341
 342struct commit_list *reduce_heads(struct commit_list *heads)
 343{
 344        struct commit_list *p;
 345        struct commit_list *result = NULL, **tail = &result;
 346        struct commit **array;
 347        int num_head, i;
 348
 349        if (!heads)
 350                return NULL;
 351
 352        /* Uniquify */
 353        for (p = heads; p; p = p->next)
 354                p->item->object.flags &= ~STALE;
 355        for (p = heads, num_head = 0; p; p = p->next) {
 356                if (p->item->object.flags & STALE)
 357                        continue;
 358                p->item->object.flags |= STALE;
 359                num_head++;
 360        }
 361        array = xcalloc(num_head, sizeof(*array));
 362        for (p = heads, i = 0; p; p = p->next) {
 363                if (p->item->object.flags & STALE) {
 364                        array[i++] = p->item;
 365                        p->item->object.flags &= ~STALE;
 366                }
 367        }
 368        num_head = remove_redundant(array, num_head);
 369        for (i = 0; i < num_head; i++)
 370                tail = &commit_list_insert(array[i], tail)->next;
 371        free(array);
 372        return result;
 373}
 374
 375void reduce_heads_replace(struct commit_list **heads)
 376{
 377        struct commit_list *result = reduce_heads(*heads);
 378        free_commit_list(*heads);
 379        *heads = result;
 380}
 381
 382int ref_newer(const struct object_id *new_oid, const struct object_id *old_oid)
 383{
 384        struct object *o;
 385        struct commit *old_commit, *new_commit;
 386        struct commit_list *old_commit_list = NULL;
 387
 388        /*
 389         * Both new_commit and old_commit must be commit-ish and new_commit is descendant of
 390         * old_commit.  Otherwise we require --force.
 391         */
 392        o = deref_tag(the_repository, parse_object(the_repository, old_oid),
 393                      NULL, 0);
 394        if (!o || o->type != OBJ_COMMIT)
 395                return 0;
 396        old_commit = (struct commit *) o;
 397
 398        o = deref_tag(the_repository, parse_object(the_repository, new_oid),
 399                      NULL, 0);
 400        if (!o || o->type != OBJ_COMMIT)
 401                return 0;
 402        new_commit = (struct commit *) o;
 403
 404        if (parse_commit(new_commit) < 0)
 405                return 0;
 406
 407        commit_list_insert(old_commit, &old_commit_list);
 408        return is_descendant_of(new_commit, old_commit_list);
 409}
 410
 411/*
 412 * Mimicking the real stack, this stack lives on the heap, avoiding stack
 413 * overflows.
 414 *
 415 * At each recursion step, the stack items points to the commits whose
 416 * ancestors are to be inspected.
 417 */
 418struct contains_stack {
 419        int nr, alloc;
 420        struct contains_stack_entry {
 421                struct commit *commit;
 422                struct commit_list *parents;
 423        } *contains_stack;
 424};
 425
 426static int in_commit_list(const struct commit_list *want, struct commit *c)
 427{
 428        for (; want; want = want->next)
 429                if (!oidcmp(&want->item->object.oid, &c->object.oid))
 430                        return 1;
 431        return 0;
 432}
 433
 434/*
 435 * Test whether the candidate is contained in the list.
 436 * Do not recurse to find out, though, but return -1 if inconclusive.
 437 */
 438static enum contains_result contains_test(struct commit *candidate,
 439                                          const struct commit_list *want,
 440                                          struct contains_cache *cache,
 441                                          uint32_t cutoff)
 442{
 443        enum contains_result *cached = contains_cache_at(cache, candidate);
 444
 445        /* If we already have the answer cached, return that. */
 446        if (*cached)
 447                return *cached;
 448
 449        /* or are we it? */
 450        if (in_commit_list(want, candidate)) {
 451                *cached = CONTAINS_YES;
 452                return CONTAINS_YES;
 453        }
 454
 455        /* Otherwise, we don't know; prepare to recurse */
 456        parse_commit_or_die(candidate);
 457
 458        if (candidate->generation < cutoff)
 459                return CONTAINS_NO;
 460
 461        return CONTAINS_UNKNOWN;
 462}
 463
 464static void push_to_contains_stack(struct commit *candidate, struct contains_stack *contains_stack)
 465{
 466        ALLOC_GROW(contains_stack->contains_stack, contains_stack->nr + 1, contains_stack->alloc);
 467        contains_stack->contains_stack[contains_stack->nr].commit = candidate;
 468        contains_stack->contains_stack[contains_stack->nr++].parents = candidate->parents;
 469}
 470
 471static enum contains_result contains_tag_algo(struct commit *candidate,
 472                                              const struct commit_list *want,
 473                                              struct contains_cache *cache)
 474{
 475        struct contains_stack contains_stack = { 0, 0, NULL };
 476        enum contains_result result;
 477        uint32_t cutoff = GENERATION_NUMBER_INFINITY;
 478        const struct commit_list *p;
 479
 480        for (p = want; p; p = p->next) {
 481                struct commit *c = p->item;
 482                load_commit_graph_info(the_repository, c);
 483                if (c->generation < cutoff)
 484                        cutoff = c->generation;
 485        }
 486
 487        result = contains_test(candidate, want, cache, cutoff);
 488        if (result != CONTAINS_UNKNOWN)
 489                return result;
 490
 491        push_to_contains_stack(candidate, &contains_stack);
 492        while (contains_stack.nr) {
 493                struct contains_stack_entry *entry = &contains_stack.contains_stack[contains_stack.nr - 1];
 494                struct commit *commit = entry->commit;
 495                struct commit_list *parents = entry->parents;
 496
 497                if (!parents) {
 498                        *contains_cache_at(cache, commit) = CONTAINS_NO;
 499                        contains_stack.nr--;
 500                }
 501                /*
 502                 * If we just popped the stack, parents->item has been marked,
 503                 * therefore contains_test will return a meaningful yes/no.
 504                 */
 505                else switch (contains_test(parents->item, want, cache, cutoff)) {
 506                case CONTAINS_YES:
 507                        *contains_cache_at(cache, commit) = CONTAINS_YES;
 508                        contains_stack.nr--;
 509                        break;
 510                case CONTAINS_NO:
 511                        entry->parents = parents->next;
 512                        break;
 513                case CONTAINS_UNKNOWN:
 514                        push_to_contains_stack(parents->item, &contains_stack);
 515                        break;
 516                }
 517        }
 518        free(contains_stack.contains_stack);
 519        return contains_test(candidate, want, cache, cutoff);
 520}
 521
 522int commit_contains(struct ref_filter *filter, struct commit *commit,
 523                    struct commit_list *list, struct contains_cache *cache)
 524{
 525        if (filter->with_commit_tag_algo)
 526                return contains_tag_algo(commit, list, cache) == CONTAINS_YES;
 527        return is_descendant_of(commit, list);
 528}
 529
 530static int compare_commits_by_gen(const void *_a, const void *_b)
 531{
 532        const struct commit *a = (const struct commit *)_a;
 533        const struct commit *b = (const struct commit *)_b;
 534
 535        if (a->generation < b->generation)
 536                return -1;
 537        if (a->generation > b->generation)
 538                return 1;
 539        return 0;
 540}
 541
 542int can_all_from_reach_with_flag(struct object_array *from,
 543                                 unsigned int with_flag,
 544                                 unsigned int assign_flag,
 545                                 time_t min_commit_date,
 546                                 uint32_t min_generation)
 547{
 548        struct commit **list = NULL;
 549        int i;
 550        int result = 1;
 551
 552        ALLOC_ARRAY(list, from->nr);
 553        for (i = 0; i < from->nr; i++) {
 554                list[i] = (struct commit *)from->objects[i].item;
 555
 556                if (parse_commit(list[i]) ||
 557                    list[i]->generation < min_generation)
 558                        return 0;
 559        }
 560
 561        QSORT(list, from->nr, compare_commits_by_gen);
 562
 563        for (i = 0; i < from->nr; i++) {
 564                /* DFS from list[i] */
 565                struct commit_list *stack = NULL;
 566
 567                list[i]->object.flags |= assign_flag;
 568                commit_list_insert(list[i], &stack);
 569
 570                while (stack) {
 571                        struct commit_list *parent;
 572
 573                        if (stack->item->object.flags & with_flag) {
 574                                pop_commit(&stack);
 575                                continue;
 576                        }
 577
 578                        for (parent = stack->item->parents; parent; parent = parent->next) {
 579                                if (parent->item->object.flags & (with_flag | RESULT))
 580                                        stack->item->object.flags |= RESULT;
 581
 582                                if (!(parent->item->object.flags & assign_flag)) {
 583                                        parent->item->object.flags |= assign_flag;
 584
 585                                        if (parse_commit(parent->item) ||
 586                                            parent->item->date < min_commit_date ||
 587                                            parent->item->generation < min_generation)
 588                                                continue;
 589
 590                                        commit_list_insert(parent->item, &stack);
 591                                        break;
 592                                }
 593                        }
 594
 595                        if (!parent)
 596                                pop_commit(&stack);
 597                }
 598
 599                if (!(list[i]->object.flags & (with_flag | RESULT))) {
 600                        result = 0;
 601                        goto cleanup;
 602                }
 603        }
 604
 605cleanup:
 606        for (i = 0; i < from->nr; i++) {
 607                clear_commit_marks(list[i], RESULT);
 608                clear_commit_marks(list[i], assign_flag);
 609        }
 610        return result;
 611}
 612
 613int can_all_from_reach(struct commit_list *from, struct commit_list *to,
 614                       int cutoff_by_min_date)
 615{
 616        struct object_array from_objs = OBJECT_ARRAY_INIT;
 617        time_t min_commit_date = cutoff_by_min_date ? from->item->date : 0;
 618        struct commit_list *from_iter = from, *to_iter = to;
 619        int result;
 620        uint32_t min_generation = GENERATION_NUMBER_INFINITY;
 621
 622        while (from_iter) {
 623                add_object_array(&from_iter->item->object, NULL, &from_objs);
 624
 625                if (!parse_commit(from_iter->item)) {
 626                        if (from_iter->item->date < min_commit_date)
 627                                min_commit_date = from_iter->item->date;
 628
 629                        if (from_iter->item->generation < min_generation)
 630                                min_generation = from_iter->item->generation;
 631                }
 632
 633                from_iter = from_iter->next;
 634        }
 635
 636        while (to_iter) {
 637                if (!parse_commit(to_iter->item)) {
 638                        if (to_iter->item->date < min_commit_date)
 639                                min_commit_date = to_iter->item->date;
 640
 641                        if (to_iter->item->generation < min_generation)
 642                                min_generation = to_iter->item->generation;
 643                }
 644
 645                to_iter->item->object.flags |= PARENT2;
 646
 647                to_iter = to_iter->next;
 648        }
 649
 650        result = can_all_from_reach_with_flag(&from_objs, PARENT2, PARENT1,
 651                                              min_commit_date, min_generation);
 652
 653        while (from) {
 654                clear_commit_marks(from->item, PARENT1);
 655                from = from->next;
 656        }
 657
 658        while (to) {
 659                clear_commit_marks(to->item, PARENT2);
 660                to = to->next;
 661        }
 662
 663        object_array_clear(&from_objs);
 664        return result;
 665}