]> git.ipfire.org Git - thirdparty/git.git/commitdiff
Merge branch 'js/merge-base-with-missing-commit'
authorJunio C Hamano <gitster@pobox.com>
Mon, 11 Mar 2024 21:12:30 +0000 (14:12 -0700)
committerJunio C Hamano <gitster@pobox.com>
Mon, 11 Mar 2024 21:12:30 +0000 (14:12 -0700)
Make sure failure return from merge_bases_many() is properly caught.

* js/merge-base-with-missing-commit:
  merge-ort/merge-recursive: do report errors in `merge_submodule()`
  merge-recursive: prepare for `merge_submodule()` to report errors
  commit-reach(repo_get_merge_bases_many_dirty): pass on errors
  commit-reach(repo_get_merge_bases_many): pass on "missing commits" errors
  commit-reach(get_octopus_merge_bases): pass on "missing commits" errors
  commit-reach(repo_get_merge_bases): pass on "missing commits" errors
  commit-reach(get_merge_bases_many_0): pass on "missing commits" errors
  commit-reach(merge_bases_many): pass on "missing commits" errors
  commit-reach(paint_down_to_common): start reporting errors
  commit-reach(paint_down_to_common): prepare for handling shallow commits
  commit-reach(repo_in_merge_bases_many): report missing commits
  commit-reach(repo_in_merge_bases_many): optionally expect missing commits
  commit-reach(paint_down_to_common): plug two memory leaks

29 files changed:
bisect.c
builtin/branch.c
builtin/fast-import.c
builtin/fetch.c
builtin/log.c
builtin/merge-base.c
builtin/merge-tree.c
builtin/merge.c
builtin/pull.c
builtin/rebase.c
builtin/receive-pack.c
builtin/rev-parse.c
commit-reach.c
commit-reach.h
commit.c
diff-lib.c
http-push.c
log-tree.c
merge-ort.c
merge-recursive.c
notes-merge.c
object-name.c
remote.c
revision.c
sequencer.c
shallow.c
submodule.c
t/helper/test-reach.c
t/t4301-merge-tree-write-tree.sh

index f75e50c339764db8a6b9f2266281541203d4e76f..60aae2fe50d4edaa520c9cf9f7e4a23ed6c60085 100644 (file)
--- a/bisect.c
+++ b/bisect.c
@@ -836,10 +836,11 @@ static void handle_skipped_merge_base(const struct object_id *mb)
 static enum bisect_error check_merge_bases(int rev_nr, struct commit **rev, int no_checkout)
 {
        enum bisect_error res = BISECT_OK;
-       struct commit_list *result;
+       struct commit_list *result = NULL;
 
-       result = repo_get_merge_bases_many(the_repository, rev[0], rev_nr - 1,
-                                          rev + 1);
+       if (repo_get_merge_bases_many(the_repository, rev[0], rev_nr - 1,
+                                     rev + 1, &result) < 0)
+               exit(128);
 
        for (; result; result = result->next) {
                const struct object_id *mb = &result->item->object.oid;
index cfb63cce5fb9dff64106907947d0df25a2c25489..b3cbb7fd440486300b14e76400ac58f927532995 100644 (file)
@@ -158,6 +158,8 @@ static int branch_merged(int kind, const char *name,
 
        merged = reference_rev ? repo_in_merge_bases(the_repository, rev,
                                                     reference_rev) : 0;
+       if (merged < 0)
+               exit(128);
 
        /*
         * After the safety valve is fully redefined to "check with
@@ -166,9 +168,13 @@ static int branch_merged(int kind, const char *name,
         * any of the following code, but during the transition period,
         * a gentle reminder is in order.
         */
-       if ((head_rev != reference_rev) &&
-           (head_rev ? repo_in_merge_bases(the_repository, rev, head_rev) : 0) != merged) {
-               if (merged)
+       if (head_rev != reference_rev) {
+               int expect = head_rev ? repo_in_merge_bases(the_repository, rev, head_rev) : 0;
+               if (expect < 0)
+                       exit(128);
+               if (expect == merged)
+                       ; /* okay */
+               else if (merged)
                        warning(_("deleting branch '%s' that has been merged to\n"
                                "         '%s', but not yet merged to HEAD"),
                                name, reference_name);
index 92eda20683ca2d07c24a03f5903d1e604ce54763..71a195ca227315d799c03dd766d4723f7ffbec46 100644 (file)
@@ -1625,6 +1625,7 @@ static int update_branch(struct branch *b)
                oidclr(&old_oid);
        if (!force_update && !is_null_oid(&old_oid)) {
                struct commit *old_cmit, *new_cmit;
+               int ret;
 
                old_cmit = lookup_commit_reference_gently(the_repository,
                                                          &old_oid, 0);
@@ -1633,7 +1634,10 @@ static int update_branch(struct branch *b)
                if (!old_cmit || !new_cmit)
                        return error("Branch %s is missing commits.", b->name);
 
-               if (!repo_in_merge_bases(the_repository, old_cmit, new_cmit)) {
+               ret = repo_in_merge_bases(the_repository, old_cmit, new_cmit);
+               if (ret < 0)
+                       exit(128);
+               if (!ret) {
                        warning("Not updating %s"
                                " (new tip %s does not contain %s)",
                                b->name, oid_to_hex(&b->oid),
index 0a7a1a34765483e9f207ec26c5ca408df88c9dfc..46a793411a437969b53c4f14d941df27358d00ed 100644 (file)
@@ -981,6 +981,8 @@ static int update_local_ref(struct ref *ref,
                uint64_t t_before = getnanotime();
                fast_forward = repo_in_merge_bases(the_repository, current,
                                                   updated);
+               if (fast_forward < 0)
+                       exit(128);
                forced_updates_ms += (getnanotime() - t_before) / 1000000;
        } else {
                fast_forward = 1;
index db1808d7c13dfd523e31d1da395122b52b6579ab..e5da0d10434dddc146ee00d9b035e76c28e3b214 100644 (file)
@@ -1625,7 +1625,7 @@ static struct commit *get_base_commit(const char *base_commit,
 {
        struct commit *base = NULL;
        struct commit **rev;
-       int i = 0, rev_nr = 0, auto_select, die_on_failure;
+       int i = 0, rev_nr = 0, auto_select, die_on_failure, ret;
 
        switch (auto_base) {
        case AUTO_BASE_NEVER:
@@ -1658,7 +1658,7 @@ static struct commit *get_base_commit(const char *base_commit,
                struct branch *curr_branch = branch_get(NULL);
                const char *upstream = branch_get_upstream(curr_branch, NULL);
                if (upstream) {
-                       struct commit_list *base_list;
+                       struct commit_list *base_list = NULL;
                        struct commit *commit;
                        struct object_id oid;
 
@@ -1669,11 +1669,12 @@ static struct commit *get_base_commit(const char *base_commit,
                                        return NULL;
                        }
                        commit = lookup_commit_or_die(&oid, "upstream base");
-                       base_list = repo_get_merge_bases_many(the_repository,
-                                                             commit, total,
-                                                             list);
-                       /* There should be one and only one merge base. */
-                       if (!base_list || base_list->next) {
+                       if (repo_get_merge_bases_many(the_repository,
+                                                     commit, total,
+                                                     list,
+                                                     &base_list) < 0 ||
+                           /* There should be one and only one merge base. */
+                           !base_list || base_list->next) {
                                if (die_on_failure) {
                                        die(_("could not find exact merge base"));
                                } else {
@@ -1704,11 +1705,11 @@ static struct commit *get_base_commit(const char *base_commit,
         */
        while (rev_nr > 1) {
                for (i = 0; i < rev_nr / 2; i++) {
-                       struct commit_list *merge_base;
-                       merge_base = repo_get_merge_bases(the_repository,
-                                                         rev[2 * i],
-                                                         rev[2 * i + 1]);
-                       if (!merge_base || merge_base->next) {
+                       struct commit_list *merge_base = NULL;
+                       if (repo_get_merge_bases(the_repository,
+                                                rev[2 * i],
+                                                rev[2 * i + 1], &merge_base) < 0 ||
+                           !merge_base || merge_base->next) {
                                if (die_on_failure) {
                                        die(_("failed to find exact merge base"));
                                } else {
@@ -1725,7 +1726,10 @@ static struct commit *get_base_commit(const char *base_commit,
                rev_nr = DIV_ROUND_UP(rev_nr, 2);
        }
 
-       if (!repo_in_merge_bases(the_repository, base, rev[0])) {
+       ret = repo_in_merge_bases(the_repository, base, rev[0]);
+       if (ret < 0)
+               exit(128);
+       if (!ret) {
                if (die_on_failure) {
                        die(_("base commit should be the ancestor of revision list"));
                } else {
index d26e8fbf6f75d9971762afdc0ea5c04e209db387..5a8e72950298c254d430664c6e931ca13c699590 100644 (file)
 
 static int show_merge_base(struct commit **rev, int rev_nr, int show_all)
 {
-       struct commit_list *result, *r;
+       struct commit_list *result = NULL, *r;
 
-       result = repo_get_merge_bases_many_dirty(the_repository, rev[0],
-                                                rev_nr - 1, rev + 1);
+       if (repo_get_merge_bases_many_dirty(the_repository, rev[0],
+                                           rev_nr - 1, rev + 1, &result) < 0) {
+               free_commit_list(result);
+               return -1;
+       }
 
        if (!result)
                return 1;
@@ -74,13 +77,17 @@ static int handle_independent(int count, const char **args)
 static int handle_octopus(int count, const char **args, int show_all)
 {
        struct commit_list *revs = NULL;
-       struct commit_list *result, *rev;
+       struct commit_list *result = NULL, *rev;
        int i;
 
        for (i = count - 1; i >= 0; i--)
                commit_list_insert(get_commit_reference(args[i]), &revs);
 
-       result = get_octopus_merge_bases(revs);
+       if (get_octopus_merge_bases(revs, &result) < 0) {
+               free_commit_list(revs);
+               free_commit_list(result);
+               return 128;
+       }
        free_commit_list(revs);
        reduce_heads_replace(&result);
 
@@ -100,12 +107,16 @@ static int handle_octopus(int count, const char **args, int show_all)
 static int handle_is_ancestor(int argc, const char **argv)
 {
        struct commit *one, *two;
+       int ret;
 
        if (argc != 2)
                die("--is-ancestor takes exactly two commits");
        one = get_commit_reference(argv[0]);
        two = get_commit_reference(argv[1]);
-       if (repo_in_merge_bases(the_repository, one, two))
+       ret = repo_in_merge_bases(the_repository, one, two);
+       if (ret < 0)
+               exit(128);
+       if (ret)
                return 0;
        else
                return 1;
index b57246da0c58c61f314cf11315a7358559650f81..05d0cad55438a90b72c8e001dfe71b05ad8203d3 100644 (file)
@@ -476,8 +476,9 @@ static int real_merge(struct merge_tree_options *o,
                 * Get the merge bases, in reverse order; see comment above
                 * merge_incore_recursive in merge-ort.h
                 */
-               merge_bases = repo_get_merge_bases(the_repository, parent1,
-                                                  parent2);
+               if (repo_get_merge_bases(the_repository, parent1,
+                                        parent2, &merge_bases) < 0)
+                       exit(128);
                if (!merge_bases && !o->allow_unrelated_histories)
                        die(_("refusing to merge unrelated histories"));
                merge_bases = reverse_commit_list(merge_bases);
index 935c8a57ddbcaa3b396bdcf633f34eb29d8860c1..a0ba1f9815d9f45a1525bab8932810c9f5919aff 100644 (file)
@@ -1513,13 +1513,20 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
 
        if (!remoteheads)
                ; /* already up-to-date */
-       else if (!remoteheads->next)
-               common = repo_get_merge_bases(the_repository, head_commit,
-                                             remoteheads->item);
-       else {
+       else if (!remoteheads->next) {
+               if (repo_get_merge_bases(the_repository, head_commit,
+                                        remoteheads->item, &common) < 0) {
+                       ret = 2;
+                       goto done;
+               }
+       } else {
                struct commit_list *list = remoteheads;
                commit_list_insert(head_commit, &list);
-               common = get_octopus_merge_bases(list);
+               if (get_octopus_merge_bases(list, &common) < 0) {
+                       free(list);
+                       ret = 2;
+                       goto done;
+               }
                free(list);
        }
 
@@ -1626,7 +1633,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                struct commit_list *j;
 
                for (j = remoteheads; j; j = j->next) {
-                       struct commit_list *common_one;
+                       struct commit_list *common_one = NULL;
                        struct commit *common_item;
 
                        /*
@@ -1634,9 +1641,10 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                         * merge_bases again, otherwise "git merge HEAD^
                         * HEAD^^" would be missed.
                         */
-                       common_one = repo_get_merge_bases(the_repository,
-                                                         head_commit,
-                                                         j->item);
+                       if (repo_get_merge_bases(the_repository, head_commit,
+                                                j->item, &common_one) < 0)
+                               exit(128);
+
                        common_item = common_one->item;
                        free_commit_list(common_one);
                        if (!oideq(&common_item->object.oid, &j->item->object.oid)) {
index 73a68b75b0672487013299f992d382d1957a02a4..72cbb76d520718cfc2f23093dd5ef76ea2d682bf 100644 (file)
@@ -815,7 +815,7 @@ static int get_octopus_merge_base(struct object_id *merge_base,
                const struct object_id *merge_head,
                const struct object_id *fork_point)
 {
-       struct commit_list *revs = NULL, *result;
+       struct commit_list *revs = NULL, *result = NULL;
 
        commit_list_insert(lookup_commit_reference(the_repository, curr_head),
                           &revs);
@@ -825,7 +825,8 @@ static int get_octopus_merge_base(struct object_id *merge_base,
                commit_list_insert(lookup_commit_reference(the_repository, fork_point),
                                   &revs);
 
-       result = get_octopus_merge_bases(revs);
+       if (get_octopus_merge_bases(revs, &result) < 0)
+               exit(128);
        free_commit_list(revs);
        reduce_heads_replace(&result);
 
@@ -926,6 +927,8 @@ static int get_can_ff(struct object_id *orig_head,
        merge_head = lookup_commit_reference(the_repository, orig_merge_head);
        ret = repo_is_descendant_of(the_repository, merge_head, list);
        free_commit_list(list);
+       if (ret < 0)
+               exit(128);
        return ret;
 }
 
@@ -950,6 +953,8 @@ static int already_up_to_date(struct object_id *orig_head,
                commit_list_insert(theirs, &list);
                ok = repo_is_descendant_of(the_repository, ours, list);
                free_commit_list(list);
+               if (ok < 0)
+                       exit(128);
                if (!ok)
                        return 0;
        }
index 6ead9465a42c6d3c6ff7a547bb42ed9dd919dd90..be787690bd7c2b6396784a1476314b8f757ab749 100644 (file)
@@ -867,7 +867,8 @@ static int can_fast_forward(struct commit *onto, struct commit *upstream,
        if (!upstream)
                goto done;
 
-       merge_bases = repo_get_merge_bases(the_repository, upstream, head);
+       if (repo_get_merge_bases(the_repository, upstream, head, &merge_bases) < 0)
+               exit(128);
        if (!merge_bases || merge_bases->next)
                goto done;
 
@@ -886,8 +887,9 @@ static void fill_branch_base(struct rebase_options *options,
 {
        struct commit_list *merge_bases = NULL;
 
-       merge_bases = repo_get_merge_bases(the_repository, options->onto,
-                                          options->orig_head);
+       if (repo_get_merge_bases(the_repository, options->onto,
+                                options->orig_head, &merge_bases) < 0)
+               exit(128);
        if (!merge_bases || merge_bases->next)
                oidcpy(branch_base, null_oid());
        else
index db656074857e765c8b5d5c91ab1b872de0bad66d..56d8a77ed75f65c1bcf47bd580e8e4e7cbbc32d9 100644 (file)
@@ -1526,6 +1526,7 @@ static const char *update(struct command *cmd, struct shallow_info *si)
            starts_with(name, "refs/heads/")) {
                struct object *old_object, *new_object;
                struct commit *old_commit, *new_commit;
+               int ret2;
 
                old_object = parse_object(the_repository, old_oid);
                new_object = parse_object(the_repository, new_oid);
@@ -1539,7 +1540,10 @@ static const char *update(struct command *cmd, struct shallow_info *si)
                }
                old_commit = (struct commit *)old_object;
                new_commit = (struct commit *)new_object;
-               if (!repo_in_merge_bases(the_repository, old_commit, new_commit)) {
+               ret2 = repo_in_merge_bases(the_repository, old_commit, new_commit);
+               if (ret2 < 0)
+                       exit(128);
+               if (!ret2) {
                        rp_error("denying non-fast-forward %s"
                                 " (you should pull first)", name);
                        ret = "non-fast-forward";
index d08987646a0a533ad81480ae4667b577a335f9f7..181c703d4c00bcce1f1715f1a8913fad0892828d 100644 (file)
@@ -297,7 +297,7 @@ static int try_difference(const char *arg)
                show_rev(NORMAL, &end_oid, end);
                show_rev(symmetric ? NORMAL : REVERSED, &start_oid, start);
                if (symmetric) {
-                       struct commit_list *exclude;
+                       struct commit_list *exclude = NULL;
                        struct commit *a, *b;
                        a = lookup_commit_reference(the_repository, &start_oid);
                        b = lookup_commit_reference(the_repository, &end_oid);
@@ -305,7 +305,8 @@ static int try_difference(const char *arg)
                                *dotdot = '.';
                                return 0;
                        }
-                       exclude = repo_get_merge_bases(the_repository, a, b);
+                       if (repo_get_merge_bases(the_repository, a, b, &exclude) < 0)
+                               exit(128);
                        while (exclude) {
                                struct commit *commit = pop_commit(&exclude);
                                show_rev(REVERSED, &commit->object.oid, NULL);
index ecc913fc99ba9e6b88df675462a2b8f912cbd0ce..8f9b008f876787abf12ca89af5541f0b3bdf6ba7 100644 (file)
@@ -49,13 +49,14 @@ static int queue_has_nonstale(struct prio_queue *queue)
 }
 
 /* all input commits in one and twos[] must have been parsed! */
-static struct commit_list *paint_down_to_common(struct repository *r,
-                                               struct commit *one, int n,
-                                               struct commit **twos,
-                                               timestamp_t min_generation)
+static int paint_down_to_common(struct repository *r,
+                               struct commit *one, int n,
+                               struct commit **twos,
+                               timestamp_t min_generation,
+                               int ignore_missing_commits,
+                               struct commit_list **result)
 {
        struct prio_queue queue = { compare_commits_by_gen_then_commit_date };
-       struct commit_list *result = NULL;
        int i;
        timestamp_t last_gen = GENERATION_NUMBER_INFINITY;
 
@@ -64,8 +65,8 @@ static struct commit_list *paint_down_to_common(struct repository *r,
 
        one->object.flags |= PARENT1;
        if (!n) {
-               commit_list_append(one, &result);
-               return result;
+               commit_list_append(one, result);
+               return 0;
        }
        prio_queue_put(&queue, one);
 
@@ -93,7 +94,7 @@ static struct commit_list *paint_down_to_common(struct repository *r,
                if (flags == (PARENT1 | PARENT2)) {
                        if (!(commit->object.flags & RESULT)) {
                                commit->object.flags |= RESULT;
-                               commit_list_insert_by_date(commit, &result);
+                               commit_list_insert_by_date(commit, result);
                        }
                        /* Mark parents of a found merge stale */
                        flags |= STALE;
@@ -104,67 +105,97 @@ static struct commit_list *paint_down_to_common(struct repository *r,
                        parents = parents->next;
                        if ((p->object.flags & flags) == flags)
                                continue;
-                       if (repo_parse_commit(r, p))
-                               return NULL;
+                       if (repo_parse_commit(r, p)) {
+                               clear_prio_queue(&queue);
+                               free_commit_list(*result);
+                               *result = NULL;
+                               /*
+                                * At this stage, we know that the commit is
+                                * missing: `repo_parse_commit()` uses
+                                * `OBJECT_INFO_DIE_IF_CORRUPT` and therefore
+                                * corrupt commits would already have been
+                                * dispatched with a `die()`.
+                                */
+                               if (ignore_missing_commits)
+                                       return 0;
+                               return error(_("could not parse commit %s"),
+                                            oid_to_hex(&p->object.oid));
+                       }
                        p->object.flags |= flags;
                        prio_queue_put(&queue, p);
                }
        }
 
        clear_prio_queue(&queue);
-       return result;
+       return 0;
 }
 
-static struct commit_list *merge_bases_many(struct repository *r,
-                                           struct commit *one, int n,
-                                           struct commit **twos)
+static int merge_bases_many(struct repository *r,
+                           struct commit *one, int n,
+                           struct commit **twos,
+                           struct commit_list **result)
 {
        struct commit_list *list = NULL;
-       struct commit_list *result = NULL;
        int i;
 
        for (i = 0; i < n; i++) {
-               if (one == twos[i])
+               if (one == twos[i]) {
                        /*
                         * We do not mark this even with RESULT so we do not
                         * have to clean it up.
                         */
-                       return commit_list_insert(one, &result);
+                       *result = commit_list_insert(one, result);
+                       return 0;
+               }
        }
 
+       if (!one)
+               return 0;
        if (repo_parse_commit(r, one))
-               return NULL;
+               return error(_("could not parse commit %s"),
+                            oid_to_hex(&one->object.oid));
        for (i = 0; i < n; i++) {
+               if (!twos[i])
+                       return 0;
                if (repo_parse_commit(r, twos[i]))
-                       return NULL;
+                       return error(_("could not parse commit %s"),
+                                    oid_to_hex(&twos[i]->object.oid));
        }
 
-       list = paint_down_to_common(r, one, n, twos, 0);
+       if (paint_down_to_common(r, one, n, twos, 0, 0, &list)) {
+               free_commit_list(list);
+               return -1;
+       }
 
        while (list) {
                struct commit *commit = pop_commit(&list);
                if (!(commit->object.flags & STALE))
-                       commit_list_insert_by_date(commit, &result);
+                       commit_list_insert_by_date(commit, result);
        }
-       return result;
+       return 0;
 }
 
-struct commit_list *get_octopus_merge_bases(struct commit_list *in)
+int get_octopus_merge_bases(struct commit_list *in, struct commit_list **result)
 {
-       struct commit_list *i, *j, *k, *ret = NULL;
+       struct commit_list *i, *j, *k;
 
        if (!in)
-               return ret;
+               return 0;
 
-       commit_list_insert(in->item, &ret);
+       commit_list_insert(in->item, result);
 
        for (i = in->next; i; i = i->next) {
                struct commit_list *new_commits = NULL, *end = NULL;
 
-               for (j = ret; j; j = j->next) {
-                       struct commit_list *bases;
-                       bases = repo_get_merge_bases(the_repository, i->item,
-                                                    j->item);
+               for (j = *result; j; j = j->next) {
+                       struct commit_list *bases = NULL;
+                       if (repo_get_merge_bases(the_repository, i->item,
+                                                j->item, &bases) < 0) {
+                               free_commit_list(bases);
+                               free_commit_list(*result);
+                               *result = NULL;
+                               return -1;
+                       }
                        if (!new_commits)
                                new_commits = bases;
                        else
@@ -172,10 +203,10 @@ struct commit_list *get_octopus_merge_bases(struct commit_list *in)
                        for (k = bases; k; k = k->next)
                                end = k;
                }
-               free_commit_list(ret);
-               ret = new_commits;
+               free_commit_list(*result);
+               *result = new_commits;
        }
-       return ret;
+       return 0;
 }
 
 static int remove_redundant_no_gen(struct repository *r,
@@ -193,7 +224,7 @@ static int remove_redundant_no_gen(struct repository *r,
        for (i = 0; i < cnt; i++)
                repo_parse_commit(r, array[i]);
        for (i = 0; i < cnt; i++) {
-               struct commit_list *common;
+               struct commit_list *common = NULL;
                timestamp_t min_generation = commit_graph_generation(array[i]);
 
                if (redundant[i])
@@ -209,8 +240,16 @@ static int remove_redundant_no_gen(struct repository *r,
                        if (curr_generation < min_generation)
                                min_generation = curr_generation;
                }
-               common = paint_down_to_common(r, array[i], filled,
-                                             work, min_generation);
+               if (paint_down_to_common(r, array[i], filled,
+                                        work, min_generation, 0, &common)) {
+                       clear_commit_marks(array[i], all_flags);
+                       clear_commit_marks_many(filled, work, all_flags);
+                       free_commit_list(common);
+                       free(work);
+                       free(redundant);
+                       free(filled_index);
+                       return -1;
+               }
                if (array[i]->object.flags & PARENT2)
                        redundant[i] = 1;
                for (j = 0; j < filled; j++)
@@ -375,69 +414,77 @@ static int remove_redundant(struct repository *r, struct commit **array, int cnt
        return remove_redundant_no_gen(r, array, cnt);
 }
 
-static struct commit_list *get_merge_bases_many_0(struct repository *r,
-                                                 struct commit *one,
-                                                 int n,
-                                                 struct commit **twos,
-                                                 int cleanup)
+static int get_merge_bases_many_0(struct repository *r,
+                                 struct commit *one,
+                                 int n,
+                                 struct commit **twos,
+                                 int cleanup,
+                                 struct commit_list **result)
 {
        struct commit_list *list;
        struct commit **rslt;
-       struct commit_list *result;
        int cnt, i;
 
-       result = merge_bases_many(r, one, n, twos);
+       if (merge_bases_many(r, one, n, twos, result) < 0)
+               return -1;
        for (i = 0; i < n; i++) {
                if (one == twos[i])
-                       return result;
+                       return 0;
        }
-       if (!result || !result->next) {
+       if (!*result || !(*result)->next) {
                if (cleanup) {
                        clear_commit_marks(one, all_flags);
                        clear_commit_marks_many(n, twos, all_flags);
                }
-               return result;
+               return 0;
        }
 
        /* There are more than one */
-       cnt = commit_list_count(result);
+       cnt = commit_list_count(*result);
        CALLOC_ARRAY(rslt, cnt);
-       for (list = result, i = 0; list; list = list->next)
+       for (list = *result, i = 0; list; list = list->next)
                rslt[i++] = list->item;
-       free_commit_list(result);
+       free_commit_list(*result);
+       *result = NULL;
 
        clear_commit_marks(one, all_flags);
        clear_commit_marks_many(n, twos, all_flags);
 
        cnt = remove_redundant(r, rslt, cnt);
-       result = NULL;
+       if (cnt < 0) {
+               free(rslt);
+               return -1;
+       }
        for (i = 0; i < cnt; i++)
-               commit_list_insert_by_date(rslt[i], &result);
+               commit_list_insert_by_date(rslt[i], result);
        free(rslt);
-       return result;
+       return 0;
 }
 
-struct commit_list *repo_get_merge_bases_many(struct repository *r,
-                                             struct commit *one,
-                                             int n,
-                                             struct commit **twos)
+int repo_get_merge_bases_many(struct repository *r,
+                             struct commit *one,
+                             int n,
+                             struct commit **twos,
+                             struct commit_list **result)
 {
-       return get_merge_bases_many_0(r, one, n, twos, 1);
+       return get_merge_bases_many_0(r, one, n, twos, 1, result);
 }
 
-struct commit_list *repo_get_merge_bases_many_dirty(struct repository *r,
-                                                   struct commit *one,
-                                                   int n,
-                                                   struct commit **twos)
+int repo_get_merge_bases_many_dirty(struct repository *r,
+                                   struct commit *one,
+                                   int n,
+                                   struct commit **twos,
+                                   struct commit_list **result)
 {
-       return get_merge_bases_many_0(r, one, n, twos, 0);
+       return get_merge_bases_many_0(r, one, n, twos, 0, result);
 }
 
-struct commit_list *repo_get_merge_bases(struct repository *r,
-                                        struct commit *one,
-                                        struct commit *two)
+int repo_get_merge_bases(struct repository *r,
+                        struct commit *one,
+                        struct commit *two,
+                        struct commit_list **result)
 {
-       return get_merge_bases_many_0(r, one, 1, &two, 1);
+       return get_merge_bases_many_0(r, one, 1, &two, 1, result);
 }
 
 /*
@@ -460,11 +507,13 @@ int repo_is_descendant_of(struct repository *r,
        } else {
                while (with_commit) {
                        struct commit *other;
+                       int ret;
 
                        other = with_commit->item;
                        with_commit = with_commit->next;
-                       if (repo_in_merge_bases_many(r, other, 1, &commit))
-                               return 1;
+                       ret = repo_in_merge_bases_many(r, other, 1, &commit, 0);
+                       if (ret)
+                               return ret;
                }
                return 0;
        }
@@ -474,17 +523,18 @@ int repo_is_descendant_of(struct repository *r,
  * Is "commit" an ancestor of one of the "references"?
  */
 int repo_in_merge_bases_many(struct repository *r, struct commit *commit,
-                            int nr_reference, struct commit **reference)
+                            int nr_reference, struct commit **reference,
+                            int ignore_missing_commits)
 {
-       struct commit_list *bases;
+       struct commit_list *bases = NULL;
        int ret = 0, i;
        timestamp_t generation, max_generation = GENERATION_NUMBER_ZERO;
 
        if (repo_parse_commit(r, commit))
-               return ret;
+               return ignore_missing_commits ? 0 : -1;
        for (i = 0; i < nr_reference; i++) {
                if (repo_parse_commit(r, reference[i]))
-                       return ret;
+                       return ignore_missing_commits ? 0 : -1;
 
                generation = commit_graph_generation(reference[i]);
                if (generation > max_generation)
@@ -495,10 +545,11 @@ int repo_in_merge_bases_many(struct repository *r, struct commit *commit,
        if (generation > max_generation)
                return ret;
 
-       bases = paint_down_to_common(r, commit,
-                                    nr_reference, reference,
-                                    generation);
-       if (commit->object.flags & PARENT2)
+       if (paint_down_to_common(r, commit,
+                                nr_reference, reference,
+                                generation, ignore_missing_commits, &bases))
+               ret = -1;
+       else if (commit->object.flags & PARENT2)
                ret = 1;
        clear_commit_marks(commit, all_flags);
        clear_commit_marks_many(nr_reference, reference, all_flags);
@@ -551,6 +602,10 @@ struct commit_list *reduce_heads(struct commit_list *heads)
                }
        }
        num_head = remove_redundant(the_repository, array, num_head);
+       if (num_head < 0) {
+               free(array);
+               return NULL;
+       }
        for (i = 0; i < num_head; i++)
                tail = &commit_list_insert(array[i], tail)->next;
        free(array);
@@ -593,6 +648,8 @@ int ref_newer(const struct object_id *new_oid, const struct object_id *old_oid)
        commit_list_insert(old_commit, &old_commit_list);
        ret = repo_is_descendant_of(the_repository,
                                    new_commit, old_commit_list);
+       if (ret < 0)
+               exit(128);
        free_commit_list(old_commit_list);
        return ret;
 }
index 35c4da4948122a6caea3a1757484b487db16b0fd..bf63cc468fd311a9ef658a23cec3db4fbbbac767 100644 (file)
@@ -9,18 +9,21 @@ struct ref_filter;
 struct object_id;
 struct object_array;
 
-struct commit_list *repo_get_merge_bases(struct repository *r,
-                                        struct commit *rev1,
-                                        struct commit *rev2);
-struct commit_list *repo_get_merge_bases_many(struct repository *r,
-                                             struct commit *one, int n,
-                                             struct commit **twos);
+int repo_get_merge_bases(struct repository *r,
+                        struct commit *rev1,
+                        struct commit *rev2,
+                        struct commit_list **result);
+int repo_get_merge_bases_many(struct repository *r,
+                             struct commit *one, int n,
+                             struct commit **twos,
+                             struct commit_list **result);
 /* To be used only when object flags after this call no longer matter */
-struct commit_list *repo_get_merge_bases_many_dirty(struct repository *r,
-                                                   struct commit *one, int n,
-                                                   struct commit **twos);
+int repo_get_merge_bases_many_dirty(struct repository *r,
+                                   struct commit *one, int n,
+                                   struct commit **twos,
+                                   struct commit_list **result);
 
-struct commit_list *get_octopus_merge_bases(struct commit_list *in);
+int get_octopus_merge_bases(struct commit_list *in, struct commit_list **result);
 
 int repo_is_descendant_of(struct repository *r,
                          struct commit *commit,
@@ -30,7 +33,8 @@ int repo_in_merge_bases(struct repository *r,
                        struct commit *reference);
 int repo_in_merge_bases_many(struct repository *r,
                             struct commit *commit,
-                            int nr_reference, struct commit **reference);
+                            int nr_reference, struct commit **reference,
+                            int ignore_missing_commits);
 
 /*
  * Takes a list of commits and returns a new list where those
index ef679a0b939046c4aac15567cdf3c0ae8c079d29..467be9f7f99408edbe1a34e2f21c491dd50e2813 100644 (file)
--- a/commit.c
+++ b/commit.c
@@ -1052,7 +1052,7 @@ struct commit *get_fork_point(const char *refname, struct commit *commit)
 {
        struct object_id oid;
        struct rev_collect revs;
-       struct commit_list *bases;
+       struct commit_list *bases = NULL;
        int i;
        struct commit *ret = NULL;
        char *full_refname;
@@ -1077,8 +1077,9 @@ struct commit *get_fork_point(const char *refname, struct commit *commit)
        for (i = 0; i < revs.nr; i++)
                revs.commit[i]->object.flags &= ~TMP_MARK;
 
-       bases = repo_get_merge_bases_many(the_repository, commit, revs.nr,
-                                         revs.commit);
+       if (repo_get_merge_bases_many(the_repository, commit, revs.nr,
+                                     revs.commit, &bases) < 0)
+               exit(128);
 
        /*
         * There should be one and only one merge base, when we found
index 6c8df04273702fa47215dffa263477df347900ee..5e8717c774eff4bb2364344c440a4efb4686e4f4 100644 (file)
@@ -570,7 +570,7 @@ void diff_get_merge_base(const struct rev_info *revs, struct object_id *mb)
 {
        int i;
        struct commit *mb_child[2] = {0};
-       struct commit_list *merge_bases;
+       struct commit_list *merge_bases = NULL;
 
        for (i = 0; i < revs->pending.nr; i++) {
                struct object *obj = revs->pending.objects[i].item;
@@ -597,7 +597,8 @@ void diff_get_merge_base(const struct rev_info *revs, struct object_id *mb)
                mb_child[1] = lookup_commit_reference(the_repository, &oid);
        }
 
-       merge_bases = repo_get_merge_bases(the_repository, mb_child[0], mb_child[1]);
+       if (repo_get_merge_bases(the_repository, mb_child[0], mb_child[1], &merge_bases) < 0)
+               exit(128);
        if (!merge_bases)
                die(_("no merge base found"));
        if (merge_bases->next)
index 12d111374107a7a071ac90d035c5172af2b63c79..33db41bfac5f977747ce7af864207df3f255e491 100644 (file)
@@ -1575,8 +1575,11 @@ static int verify_merge_base(struct object_id *head_oid, struct ref *remote)
        struct commit *head = lookup_commit_or_die(head_oid, "HEAD");
        struct commit *branch = lookup_commit_or_die(&remote->old_oid,
                                                     remote->name);
+       int ret = repo_in_merge_bases(the_repository, branch, head);
 
-       return repo_in_merge_bases(the_repository, branch, head);
+       if (ret < 0)
+               exit(128);
+       return ret;
 }
 
 static int delete_remote_branch(const char *pattern, int force)
index 337b9334cdbafe0d3ffd2bf2fd36898f6d112410..e5438b029d90f352f0c434ebc8088c01fce11f3a 100644 (file)
@@ -1011,7 +1011,7 @@ static int do_remerge_diff(struct rev_info *opt,
                           struct object_id *oid)
 {
        struct merge_options o;
-       struct commit_list *bases;
+       struct commit_list *bases = NULL;
        struct merge_result res = {0};
        struct pretty_print_context ctx = {0};
        struct commit *parent1 = parents->item;
@@ -1036,7 +1036,8 @@ static int do_remerge_diff(struct rev_info *opt,
        /* Parse the relevant commits and get the merge bases */
        parse_commit_or_die(parent1);
        parse_commit_or_die(parent2);
-       bases = repo_get_merge_bases(the_repository, parent1, parent2);
+       if (repo_get_merge_bases(the_repository, parent1, parent2, &bases) < 0)
+               exit(128);
 
        /* Re-merge the parents */
        merge_incore_recursive(&o, bases, parent1, parent2, &res);
index 817f7b57c7bee9db817b5c9c77532615aef3d160..201f8f77755b439ad1b91b5b692c16aaeba5d032 100644 (file)
@@ -543,6 +543,7 @@ enum conflict_and_info_types {
        CONFLICT_SUBMODULE_HISTORY_NOT_AVAILABLE,
        CONFLICT_SUBMODULE_MAY_HAVE_REWINDS,
        CONFLICT_SUBMODULE_NULL_MERGE_BASE,
+       CONFLICT_SUBMODULE_CORRUPT,
 
        /* Keep this entry _last_ in the list */
        NB_CONFLICT_TYPES,
@@ -595,7 +596,9 @@ static const char *type_short_descriptions[] = {
        [CONFLICT_SUBMODULE_MAY_HAVE_REWINDS] =
                "CONFLICT (submodule may have rewinds)",
        [CONFLICT_SUBMODULE_NULL_MERGE_BASE] =
-               "CONFLICT (submodule lacks merge base)"
+               "CONFLICT (submodule lacks merge base)",
+       [CONFLICT_SUBMODULE_CORRUPT] =
+               "CONFLICT (submodule corrupt)"
 };
 
 struct logical_conflict_info {
@@ -1710,7 +1713,14 @@ static int find_first_merges(struct repository *repo,
                die("revision walk setup failed");
        while ((commit = get_revision(&revs)) != NULL) {
                struct object *o = &(commit->object);
-               if (repo_in_merge_bases(repo, b, commit))
+               int ret = repo_in_merge_bases(repo, b, commit);
+
+               if (ret < 0) {
+                       object_array_clear(&merges);
+                       release_revisions(&revs);
+                       return ret;
+               }
+               if (ret > 0)
                        add_object_array(o, NULL, &merges);
        }
        reset_revision_walk();
@@ -1725,9 +1735,17 @@ static int find_first_merges(struct repository *repo,
                contains_another = 0;
                for (j = 0; j < merges.nr; j++) {
                        struct commit *m2 = (struct commit *) merges.objects[j].item;
-                       if (i != j && repo_in_merge_bases(repo, m2, m1)) {
-                               contains_another = 1;
-                               break;
+                       if (i != j) {
+                               int ret = repo_in_merge_bases(repo, m2, m1);
+                               if (ret < 0) {
+                                       object_array_clear(&merges);
+                                       release_revisions(&revs);
+                                       return ret;
+                               }
+                               if (ret > 0) {
+                                       contains_another = 1;
+                                       break;
+                               }
                        }
                }
 
@@ -1749,7 +1767,7 @@ static int merge_submodule(struct merge_options *opt,
 {
        struct repository subrepo;
        struct strbuf sb = STRBUF_INIT;
-       int ret = 0;
+       int ret = 0, ret2;
        struct commit *commit_o, *commit_a, *commit_b;
        int parent_count;
        struct object_array merges;
@@ -1796,8 +1814,28 @@ static int merge_submodule(struct merge_options *opt,
        }
 
        /* check whether both changes are forward */
-       if (!repo_in_merge_bases(&subrepo, commit_o, commit_a) ||
-           !repo_in_merge_bases(&subrepo, commit_o, commit_b)) {
+       ret2 = repo_in_merge_bases(&subrepo, commit_o, commit_a);
+       if (ret2 < 0) {
+               path_msg(opt, CONFLICT_SUBMODULE_CORRUPT, 0,
+                        path, NULL, NULL, NULL,
+                        _("Failed to merge submodule %s "
+                          "(repository corrupt)"),
+                        path);
+               ret = -1;
+               goto cleanup;
+       }
+       if (ret2 > 0)
+               ret2 = repo_in_merge_bases(&subrepo, commit_o, commit_b);
+       if (ret2 < 0) {
+               path_msg(opt, CONFLICT_SUBMODULE_CORRUPT, 0,
+                        path, NULL, NULL, NULL,
+                        _("Failed to merge submodule %s "
+                          "(repository corrupt)"),
+                        path);
+               ret = -1;
+               goto cleanup;
+       }
+       if (!ret2) {
                path_msg(opt, CONFLICT_SUBMODULE_MAY_HAVE_REWINDS, 0,
                         path, NULL, NULL, NULL,
                         _("Failed to merge submodule %s "
@@ -1807,7 +1845,17 @@ static int merge_submodule(struct merge_options *opt,
        }
 
        /* Case #1: a is contained in b or vice versa */
-       if (repo_in_merge_bases(&subrepo, commit_a, commit_b)) {
+       ret2 = repo_in_merge_bases(&subrepo, commit_a, commit_b);
+       if (ret2 < 0) {
+               path_msg(opt, CONFLICT_SUBMODULE_CORRUPT, 0,
+                        path, NULL, NULL, NULL,
+                        _("Failed to merge submodule %s "
+                          "(repository corrupt)"),
+                        path);
+               ret = -1;
+               goto cleanup;
+       }
+       if (ret2 > 0) {
                oidcpy(result, b);
                path_msg(opt, INFO_SUBMODULE_FAST_FORWARDING, 1,
                         path, NULL, NULL, NULL,
@@ -1816,7 +1864,17 @@ static int merge_submodule(struct merge_options *opt,
                ret = 1;
                goto cleanup;
        }
-       if (repo_in_merge_bases(&subrepo, commit_b, commit_a)) {
+       ret2 = repo_in_merge_bases(&subrepo, commit_b, commit_a);
+       if (ret2 < 0) {
+               path_msg(opt, CONFLICT_SUBMODULE_CORRUPT, 0,
+                        path, NULL, NULL, NULL,
+                        _("Failed to merge submodule %s "
+                          "(repository corrupt)"),
+                        path);
+               ret = -1;
+               goto cleanup;
+       }
+       if (ret2 > 0) {
                oidcpy(result, a);
                path_msg(opt, INFO_SUBMODULE_FAST_FORWARDING, 1,
                         path, NULL, NULL, NULL,
@@ -1841,6 +1899,14 @@ static int merge_submodule(struct merge_options *opt,
        parent_count = find_first_merges(&subrepo, path, commit_a, commit_b,
                                         &merges);
        switch (parent_count) {
+       case -1:
+               path_msg(opt, CONFLICT_SUBMODULE_CORRUPT, 0,
+                        path, NULL, NULL, NULL,
+                        _("Failed to merge submodule %s "
+                          "(repository corrupt)"),
+                        path);
+               ret = -1;
+               break;
        case 0:
                path_msg(opt, CONFLICT_SUBMODULE_FAILED_TO_MERGE, 0,
                         path, NULL, NULL, NULL,
@@ -5014,7 +5080,11 @@ static void merge_ort_internal(struct merge_options *opt,
        struct strbuf merge_base_abbrev = STRBUF_INIT;
 
        if (!merge_bases) {
-               merge_bases = repo_get_merge_bases(the_repository, h1, h2);
+               if (repo_get_merge_bases(the_repository, h1, h2,
+                                        &merge_bases) < 0) {
+                       result->clean = -1;
+                       return;
+               }
                /* See merge-ort.h:merge_incore_recursive() declaration NOTE */
                merge_bases = reverse_commit_list(merge_bases);
        }
index d58c05ad2ce847b9d41fecc01c42d8af4a90b9e1..103ee321aeb8cd8c169d35316bb20cfd9eea1693 100644 (file)
@@ -1140,7 +1140,13 @@ static int find_first_merges(struct repository *repo,
                die("revision walk setup failed");
        while ((commit = get_revision(&revs)) != NULL) {
                struct object *o = &(commit->object);
-               if (repo_in_merge_bases(repo, b, commit))
+               int ret = repo_in_merge_bases(repo, b, commit);
+               if (ret < 0) {
+                       object_array_clear(&merges);
+                       release_revisions(&revs);
+                       return ret;
+               }
+               if (ret)
                        add_object_array(o, NULL, &merges);
        }
        reset_revision_walk();
@@ -1155,9 +1161,17 @@ static int find_first_merges(struct repository *repo,
                contains_another = 0;
                for (j = 0; j < merges.nr; j++) {
                        struct commit *m2 = (struct commit *) merges.objects[j].item;
-                       if (i != j && repo_in_merge_bases(repo, m2, m1)) {
-                               contains_another = 1;
-                               break;
+                       if (i != j) {
+                               int ret = repo_in_merge_bases(repo, m2, m1);
+                               if (ret < 0) {
+                                       object_array_clear(&merges);
+                                       release_revisions(&revs);
+                                       return ret;
+                               }
+                               if (ret > 0) {
+                                       contains_another = 1;
+                                       break;
+                               }
                        }
                }
 
@@ -1193,7 +1207,7 @@ static int merge_submodule(struct merge_options *opt,
                           const struct object_id *b)
 {
        struct repository subrepo;
-       int ret = 0;
+       int ret = 0, ret2;
        struct commit *commit_base, *commit_a, *commit_b;
        int parent_count;
        struct object_array merges;
@@ -1230,14 +1244,32 @@ static int merge_submodule(struct merge_options *opt,
        }
 
        /* check whether both changes are forward */
-       if (!repo_in_merge_bases(&subrepo, commit_base, commit_a) ||
-           !repo_in_merge_bases(&subrepo, commit_base, commit_b)) {
+       ret2 = repo_in_merge_bases(&subrepo, commit_base, commit_a);
+       if (ret2 < 0) {
+               output(opt, 1, _("Failed to merge submodule %s (repository corrupt)"), path);
+               ret = -1;
+               goto cleanup;
+       }
+       if (ret2 > 0)
+               ret2 = repo_in_merge_bases(&subrepo, commit_base, commit_b);
+       if (ret2 < 0) {
+               output(opt, 1, _("Failed to merge submodule %s (repository corrupt)"), path);
+               ret = -1;
+               goto cleanup;
+       }
+       if (!ret2) {
                output(opt, 1, _("Failed to merge submodule %s (commits don't follow merge-base)"), path);
                goto cleanup;
        }
 
        /* Case #1: a is contained in b or vice versa */
-       if (repo_in_merge_bases(&subrepo, commit_a, commit_b)) {
+       ret2 = repo_in_merge_bases(&subrepo, commit_a, commit_b);
+       if (ret2 < 0) {
+               output(opt, 1, _("Failed to merge submodule %s (repository corrupt)"), path);
+               ret = -1;
+               goto cleanup;
+       }
+       if (ret2) {
                oidcpy(result, b);
                if (show(opt, 3)) {
                        output(opt, 3, _("Fast-forwarding submodule %s to the following commit:"), path);
@@ -1250,7 +1282,13 @@ static int merge_submodule(struct merge_options *opt,
                ret = 1;
                goto cleanup;
        }
-       if (repo_in_merge_bases(&subrepo, commit_b, commit_a)) {
+       ret2 = repo_in_merge_bases(&subrepo, commit_b, commit_a);
+       if (ret2 < 0) {
+               output(opt, 1, _("Failed to merge submodule %s (repository corrupt)"), path);
+               ret = -1;
+               goto cleanup;
+       }
+       if (ret2) {
                oidcpy(result, a);
                if (show(opt, 3)) {
                        output(opt, 3, _("Fast-forwarding submodule %s to the following commit:"), path);
@@ -1279,6 +1317,10 @@ static int merge_submodule(struct merge_options *opt,
        parent_count = find_first_merges(&subrepo, &merges, path,
                                         commit_a, commit_b);
        switch (parent_count) {
+       case -1:
+               output(opt, 1,_("Failed to merge submodule %s (repository corrupt)"), path);
+               ret = -1;
+               break;
        case 0:
                output(opt, 1, _("Failed to merge submodule %s (merge following commits not found)"), path);
                break;
@@ -1393,11 +1435,14 @@ static int merge_mode_and_contents(struct merge_options *opt,
                        /* FIXME: bug, what if modes didn't match? */
                        result->clean = (merge_status == 0);
                } else if (S_ISGITLINK(a->mode)) {
-                       result->clean = merge_submodule(opt, &result->blob.oid,
-                                                       o->path,
-                                                       &o->oid,
-                                                       &a->oid,
-                                                       &b->oid);
+                       int clean = merge_submodule(opt, &result->blob.oid,
+                                                   o->path,
+                                                   &o->oid,
+                                                   &a->oid,
+                                                   &b->oid);
+                       if (clean < 0)
+                               return -1;
+                       result->clean = clean;
                } else if (S_ISLNK(a->mode)) {
                        switch (opt->recursive_variant) {
                        case MERGE_VARIANT_NORMAL:
@@ -3598,7 +3643,9 @@ static int merge_recursive_internal(struct merge_options *opt,
        }
 
        if (!merge_bases) {
-               merge_bases = repo_get_merge_bases(the_repository, h1, h2);
+               if (repo_get_merge_bases(the_repository, h1, h2,
+                                        &merge_bases) < 0)
+                       return -1;
                merge_bases = reverse_commit_list(merge_bases);
        }
 
index 8799b522a55f31869dcc8cbfd7229cc8db65af4c..51282934ae62b8e7daefcf8202b98e006c416c07 100644 (file)
@@ -607,7 +607,8 @@ int notes_merge(struct notes_merge_options *o,
        assert(local && remote);
 
        /* Find merge bases */
-       bases = repo_get_merge_bases(the_repository, local, remote);
+       if (repo_get_merge_bases(the_repository, local, remote, &bases) < 0)
+               exit(128);
        if (!bases) {
                base_oid = null_oid();
                base_tree_oid = the_hash_algo->empty_tree;
index 511f09bc0fea75301433fe888efbe10d5227fdc0..bd77695d7eac539ff114c4b6a031cdd81931d7d8 100644 (file)
@@ -1488,7 +1488,7 @@ int repo_get_oid_mb(struct repository *r,
                    struct object_id *oid)
 {
        struct commit *one, *two;
-       struct commit_list *mbs;
+       struct commit_list *mbs = NULL;
        struct object_id oid_tmp;
        const char *dots;
        int st;
@@ -1516,7 +1516,10 @@ int repo_get_oid_mb(struct repository *r,
        two = lookup_commit_reference_gently(r, &oid_tmp, 0);
        if (!two)
                return -1;
-       mbs = repo_get_merge_bases(r, one, two);
+       if (repo_get_merge_bases(r, one, two, &mbs) < 0) {
+               free_commit_list(mbs);
+               return -1;
+       }
        if (!mbs || mbs->next)
                st = -1;
        else {
index 9090632e96daddfc1217bc64ae4e0dac11bdb993..2b650b813b741f722a5f6c69f359a1f53249bcb1 100644 (file)
--- a/remote.c
+++ b/remote.c
@@ -2679,7 +2679,7 @@ static int is_reachable_in_reflog(const char *local, const struct ref *remote)
                if (MERGE_BASES_BATCH_SIZE < size)
                        size = MERGE_BASES_BATCH_SIZE;
 
-               if ((ret = repo_in_merge_bases_many(the_repository, commit, size, chunk)))
+               if ((ret = repo_in_merge_bases_many(the_repository, commit, size, chunk, 0)))
                        break;
        }
 
index 6f8ebc762e8dcc214de6378d91c87529bf6f8bb0..45893651c22f2669da8d5fe38a0b809e650d6f6d 100644 (file)
@@ -1992,7 +1992,7 @@ static const char *lookup_other_head(struct object_id *oid)
 
 static void prepare_show_merge(struct rev_info *revs)
 {
-       struct commit_list *bases;
+       struct commit_list *bases = NULL;
        struct commit *head, *other;
        struct object_id oid;
        const char *other_name;
@@ -2007,7 +2007,8 @@ static void prepare_show_merge(struct rev_info *revs)
        other = lookup_commit_or_die(&oid, other_name);
        add_pending_object(revs, &head->object, "HEAD");
        add_pending_object(revs, &other->object, other_name);
-       bases = repo_get_merge_bases(the_repository, head, other);
+       if (repo_get_merge_bases(the_repository, head, other, &bases) < 0)
+               exit(128);
        add_rev_cmdline_list(revs, bases, REV_CMD_MERGE_BASE, UNINTERESTING | BOTTOM);
        add_pending_commit_list(revs, bases, UNINTERESTING | BOTTOM);
        free_commit_list(bases);
@@ -2095,14 +2096,17 @@ static int handle_dotdot_1(const char *arg, char *dotdot,
        } else {
                /* A...B -- find merge bases between the two */
                struct commit *a, *b;
-               struct commit_list *exclude;
+               struct commit_list *exclude = NULL;
 
                a = lookup_commit_reference(revs->repo, &a_obj->oid);
                b = lookup_commit_reference(revs->repo, &b_obj->oid);
                if (!a || !b)
                        return dotdot_missing(arg, dotdot, revs, symmetric);
 
-               exclude = repo_get_merge_bases(the_repository, a, b);
+               if (repo_get_merge_bases(the_repository, a, b, &exclude) < 0) {
+                       free_commit_list(exclude);
+                       return -1;
+               }
                add_rev_cmdline_list(revs, exclude, REV_CMD_MERGE_BASE,
                                     flags_exclude);
                add_pending_commit_list(revs, exclude, flags_exclude);
index 35dd7e561a60c56d2639068a6afde50099497d65..5c6f541126c74bb1c70adef36520213b31d3265b 100644 (file)
@@ -3912,7 +3912,7 @@ static int do_merge(struct repository *r,
        int run_commit_flags = 0;
        struct strbuf ref_name = STRBUF_INIT;
        struct commit *head_commit, *merge_commit, *i;
-       struct commit_list *bases, *j;
+       struct commit_list *bases = NULL, *j;
        struct commit_list *to_merge = NULL, **tail = &to_merge;
        const char *strategy = !opts->xopts.nr &&
                (!opts->strategy ||
@@ -4138,7 +4138,11 @@ static int do_merge(struct repository *r,
        }
 
        merge_commit = to_merge->item;
-       bases = repo_get_merge_bases(r, head_commit, merge_commit);
+       if (repo_get_merge_bases(r, head_commit, merge_commit, &bases) < 0) {
+               ret = -1;
+               goto leave_merge;
+       }
+
        if (bases && oideq(&merge_commit->object.oid,
                           &bases->item->object.oid)) {
                ret = 0;
index 7711798127e49efaa18b6403ecf103f05e92f7e7..7ff50dd0da45e00ac3de5e03af473ff361d33b02 100644 (file)
--- a/shallow.c
+++ b/shallow.c
@@ -794,12 +794,16 @@ static void post_assign_shallow(struct shallow_info *info,
                if (!*bitmap)
                        continue;
                for (j = 0; j < bitmap_nr; j++)
-                       if (bitmap[0][j] &&
-                           /* Step 7, reachability test at commit level */
-                           !repo_in_merge_bases_many(the_repository, c, ca.nr, ca.commits)) {
-                               update_refstatus(ref_status, info->ref->nr, *bitmap);
-                               dst++;
-                               break;
+                       if (bitmap[0][j]) {
+                               /* Step 7, reachability test at commit level */
+                               int ret = repo_in_merge_bases_many(the_repository, c, ca.nr, ca.commits, 1);
+                               if (ret < 0)
+                                       exit(128);
+                               if (!ret) {
+                                       update_refstatus(ref_status, info->ref->nr, *bitmap);
+                                       dst++;
+                                       break;
+                               }
                        }
        }
        info->nr_ours = dst;
@@ -827,7 +831,10 @@ int delayed_reachability_test(struct shallow_info *si, int c)
                si->reachable[c] = repo_in_merge_bases_many(the_repository,
                                                            commit,
                                                            si->nr_commits,
-                                                           si->commits);
+                                                           si->commits,
+                                                           1);
+               if (si->reachable[c] < 0)
+                       exit(128);
                si->need_reachability_test[c] = 0;
        }
        return si->reachable[c];
index 40f13a36857179c39d31891396c892c5b7e54f72..f0ddb31e8fb535264dded9fb0a7434fda1330f39 100644 (file)
@@ -592,7 +592,12 @@ static void show_submodule_header(struct diff_options *o,
             (!is_null_oid(two) && !*right))
                message = "(commits not present)";
 
-       *merge_bases = repo_get_merge_bases(sub, *left, *right);
+       *merge_bases = NULL;
+       if (repo_get_merge_bases(sub, *left, *right, merge_bases) < 0) {
+               message = "(corrupt repository)";
+               goto output_header;
+       }
+
        if (*merge_bases) {
                if ((*merge_bases)->item == *left)
                        fast_forward = 1;
index 1e159a754db6db5d02eaa81072b0ab19fa863004..1e3b431e3e72116df65e825bed1916d5ff7859e6 100644 (file)
@@ -111,13 +111,16 @@ int cmd__reach(int ac, const char **av)
                       repo_in_merge_bases(the_repository, A, B));
        else if (!strcmp(av[1], "in_merge_bases_many"))
                printf("%s(A,X):%d\n", av[1],
-                      repo_in_merge_bases_many(the_repository, A, X_nr, X_array));
+                      repo_in_merge_bases_many(the_repository, A, X_nr, X_array, 0));
        else if (!strcmp(av[1], "is_descendant_of"))
                printf("%s(A,X):%d\n", av[1], repo_is_descendant_of(r, A, X));
        else if (!strcmp(av[1], "get_merge_bases_many")) {
-               struct commit_list *list = repo_get_merge_bases_many(the_repository,
-                                                                    A, X_nr,
-                                                                    X_array);
+               struct commit_list *list = NULL;
+               if (repo_get_merge_bases_many(the_repository,
+                                             A, X_nr,
+                                             X_array,
+                                             &list) < 0)
+                       exit(128);
                printf("%s(A,X):\n", av[1]);
                print_sorted_commit_ids(list);
        } else if (!strcmp(av[1], "reduce_heads")) {
index d83c1d172dd2626578bb9b0918f6856f91d17ed4..29e9974cdfd421f6fb7dd17fa2bb12db8d5d6e04 100755 (executable)
@@ -978,4 +978,16 @@ test_expect_success 'error out on missing blob objects' '
        test_must_be_empty actual
 '
 
+test_expect_success 'error out on missing commits as well' '
+       git init --bare missing-commit.git &&
+       git rev-list --objects side1 side3 >list-including-initial &&
+       grep -v ^$(git rev-parse side1^) <list-including-initial >list &&
+       git pack-objects missing-commit.git/objects/pack/missing-initial <list &&
+       side1=$(git rev-parse side1) &&
+       side3=$(git rev-parse side3) &&
+       test_must_fail git --git-dir=missing-commit.git \
+               merge-tree --allow-unrelated-histories $side1 $side3 >actual &&
+       test_must_be_empty actual
+'
+
 test_done