commit-reach(repo_get_merge_bases): pass on "missing commits" errors

The `merge_bases_many()` function was just taught to indicate parsing
errors, and now the `repo_get_merge_bases()` function (which is also
surfaced via the `repo_get_merge_bases()` macro) is aware of that, too.

Naturally, there are a lot of callers that need to be adjusted now, too.

Next step: adjust the callers of `get_octopus_merge_bases()`.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
maint
Johannes Schindelin 2024-02-28 09:44:14 +00:00 committed by Junio C Hamano
parent 8226e157a9
commit 76e2a09999
17 changed files with 96 additions and 51 deletions

View File

@ -1704,11 +1704,11 @@ static struct commit *get_base_commit(const char *base_commit,
*/ */
while (rev_nr > 1) { while (rev_nr > 1) {
for (i = 0; i < rev_nr / 2; i++) { for (i = 0; i < rev_nr / 2; i++) {
struct commit_list *merge_base; struct commit_list *merge_base = NULL;
merge_base = repo_get_merge_bases(the_repository, if (repo_get_merge_bases(the_repository,
rev[2 * i], rev[2 * i],
rev[2 * i + 1]); rev[2 * i + 1], &merge_base) < 0 ||
if (!merge_base || merge_base->next) { !merge_base || merge_base->next) {
if (die_on_failure) { if (die_on_failure) {
die(_("failed to find exact merge base")); die(_("failed to find exact merge base"));
} else { } else {

View File

@ -462,8 +462,9 @@ static int real_merge(struct merge_tree_options *o,
* Get the merge bases, in reverse order; see comment above * Get the merge bases, in reverse order; see comment above
* merge_incore_recursive in merge-ort.h * merge_incore_recursive in merge-ort.h
*/ */
merge_bases = repo_get_merge_bases(the_repository, parent1, if (repo_get_merge_bases(the_repository, parent1,
parent2); parent2, &merge_bases) < 0)
exit(128);
if (!merge_bases && !o->allow_unrelated_histories) if (!merge_bases && !o->allow_unrelated_histories)
die(_("refusing to merge unrelated histories")); die(_("refusing to merge unrelated histories"));
merge_bases = reverse_commit_list(merge_bases); merge_bases = reverse_commit_list(merge_bases);

View File

@ -1514,10 +1514,13 @@ int cmd_merge(int argc, const char **argv, const char *prefix)


if (!remoteheads) if (!remoteheads)
; /* already up-to-date */ ; /* already up-to-date */
else if (!remoteheads->next) else if (!remoteheads->next) {
common = repo_get_merge_bases(the_repository, head_commit, if (repo_get_merge_bases(the_repository, head_commit,
remoteheads->item); remoteheads->item, &common) < 0) {
else { ret = 2;
goto done;
}
} else {
struct commit_list *list = remoteheads; struct commit_list *list = remoteheads;
commit_list_insert(head_commit, &list); commit_list_insert(head_commit, &list);
common = get_octopus_merge_bases(list); common = get_octopus_merge_bases(list);
@ -1627,7 +1630,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
struct commit_list *j; struct commit_list *j;


for (j = remoteheads; j; j = j->next) { for (j = remoteheads; j; j = j->next) {
struct commit_list *common_one; struct commit_list *common_one = NULL;
struct commit *common_item; struct commit *common_item;


/* /*
@ -1635,9 +1638,10 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
* merge_bases again, otherwise "git merge HEAD^ * merge_bases again, otherwise "git merge HEAD^
* HEAD^^" would be missed. * HEAD^^" would be missed.
*/ */
common_one = repo_get_merge_bases(the_repository, if (repo_get_merge_bases(the_repository, head_commit,
head_commit, j->item, &common_one) < 0)
j->item); exit(128);

common_item = common_one->item; common_item = common_one->item;
free_commit_list(common_one); free_commit_list(common_one);
if (!oideq(&common_item->object.oid, &j->item->object.oid)) { if (!oideq(&common_item->object.oid, &j->item->object.oid)) {

View File

@ -867,7 +867,8 @@ static int can_fast_forward(struct commit *onto, struct commit *upstream,
if (!upstream) if (!upstream)
goto done; 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) if (!merge_bases || merge_bases->next)
goto done; goto done;


@ -886,8 +887,9 @@ static void fill_branch_base(struct rebase_options *options,
{ {
struct commit_list *merge_bases = NULL; struct commit_list *merge_bases = NULL;


merge_bases = repo_get_merge_bases(the_repository, options->onto, if (repo_get_merge_bases(the_repository, options->onto,
options->orig_head); options->orig_head, &merge_bases) < 0)
exit(128);
if (!merge_bases || merge_bases->next) if (!merge_bases || merge_bases->next)
oidcpy(branch_base, null_oid()); oidcpy(branch_base, null_oid());
else else

View File

@ -297,7 +297,7 @@ static int try_difference(const char *arg)
show_rev(NORMAL, &end_oid, end); show_rev(NORMAL, &end_oid, end);
show_rev(symmetric ? NORMAL : REVERSED, &start_oid, start); show_rev(symmetric ? NORMAL : REVERSED, &start_oid, start);
if (symmetric) { if (symmetric) {
struct commit_list *exclude; struct commit_list *exclude = NULL;
struct commit *a, *b; struct commit *a, *b;
a = lookup_commit_reference(the_repository, &start_oid); a = lookup_commit_reference(the_repository, &start_oid);
b = lookup_commit_reference(the_repository, &end_oid); b = lookup_commit_reference(the_repository, &end_oid);
@ -305,7 +305,8 @@ static int try_difference(const char *arg)
*dotdot = '.'; *dotdot = '.';
return 0; 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) { while (exclude) {
struct commit *commit = pop_commit(&exclude); struct commit *commit = pop_commit(&exclude);
show_rev(REVERSED, &commit->object.oid, NULL); show_rev(REVERSED, &commit->object.oid, NULL);

View File

@ -188,9 +188,12 @@ struct commit_list *get_octopus_merge_bases(struct commit_list *in)
struct commit_list *new_commits = NULL, *end = NULL; struct commit_list *new_commits = NULL, *end = NULL;


for (j = ret; j; j = j->next) { for (j = ret; j; j = j->next) {
struct commit_list *bases; struct commit_list *bases = NULL;
bases = repo_get_merge_bases(the_repository, i->item, if (repo_get_merge_bases(the_repository, i->item,
j->item); j->item, &bases) < 0) {
free_commit_list(bases);
return NULL;
}
if (!new_commits) if (!new_commits)
new_commits = bases; new_commits = bases;
else else
@ -482,16 +485,12 @@ struct commit_list *repo_get_merge_bases_many_dirty(struct repository *r,
return result; return result;
} }


struct commit_list *repo_get_merge_bases(struct repository *r, int repo_get_merge_bases(struct repository *r,
struct commit *one, struct commit *one,
struct commit *two) struct commit *two,
struct commit_list **result)
{ {
struct commit_list *result = NULL; return get_merge_bases_many_0(r, one, 1, &two, 1, result);
if (get_merge_bases_many_0(r, one, 1, &two, 1, &result) < 0) {
free_commit_list(result);
return NULL;
}
return result;
} }


/* /*

View File

@ -9,9 +9,10 @@ struct ref_filter;
struct object_id; struct object_id;
struct object_array; struct object_array;


struct commit_list *repo_get_merge_bases(struct repository *r, int repo_get_merge_bases(struct repository *r,
struct commit *rev1, struct commit *rev1,
struct commit *rev2); struct commit *rev2,
struct commit_list **result);
struct commit_list *repo_get_merge_bases_many(struct repository *r, struct commit_list *repo_get_merge_bases_many(struct repository *r,
struct commit *one, int n, struct commit *one, int n,
struct commit **twos); struct commit **twos);

View File

@ -570,7 +570,7 @@ void diff_get_merge_base(const struct rev_info *revs, struct object_id *mb)
{ {
int i; int i;
struct commit *mb_child[2] = {0}; 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++) { for (i = 0; i < revs->pending.nr; i++) {
struct object *obj = revs->pending.objects[i].item; 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); 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) if (!merge_bases)
die(_("no merge base found")); die(_("no merge base found"));
if (merge_bases->next) if (merge_bases->next)

View File

@ -1011,7 +1011,7 @@ static int do_remerge_diff(struct rev_info *opt,
struct object_id *oid) struct object_id *oid)
{ {
struct merge_options o; struct merge_options o;
struct commit_list *bases; struct commit_list *bases = NULL;
struct merge_result res = {0}; struct merge_result res = {0};
struct pretty_print_context ctx = {0}; struct pretty_print_context ctx = {0};
struct commit *parent1 = parents->item; 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 the relevant commits and get the merge bases */
parse_commit_or_die(parent1); parse_commit_or_die(parent1);
parse_commit_or_die(parent2); 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 */ /* Re-merge the parents */
merge_incore_recursive(&o, bases, parent1, parent2, &res); merge_incore_recursive(&o, bases, parent1, parent2, &res);

View File

@ -5068,7 +5068,11 @@ static void merge_ort_internal(struct merge_options *opt,
struct strbuf merge_base_abbrev = STRBUF_INIT; struct strbuf merge_base_abbrev = STRBUF_INIT;


if (!merge_bases) { 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 */ /* See merge-ort.h:merge_incore_recursive() declaration NOTE */
merge_bases = reverse_commit_list(merge_bases); merge_bases = reverse_commit_list(merge_bases);
} }

View File

@ -3633,7 +3633,9 @@ static int merge_recursive_internal(struct merge_options *opt,
} }


if (!merge_bases) { 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); merge_bases = reverse_commit_list(merge_bases);
} }



View File

@ -607,7 +607,8 @@ int notes_merge(struct notes_merge_options *o,
assert(local && remote); assert(local && remote);


/* Find merge bases */ /* 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) { if (!bases) {
base_oid = null_oid(); base_oid = null_oid();
base_tree_oid = the_hash_algo->empty_tree; base_tree_oid = the_hash_algo->empty_tree;

View File

@ -1479,7 +1479,7 @@ int repo_get_oid_mb(struct repository *r,
struct object_id *oid) struct object_id *oid)
{ {
struct commit *one, *two; struct commit *one, *two;
struct commit_list *mbs; struct commit_list *mbs = NULL;
struct object_id oid_tmp; struct object_id oid_tmp;
const char *dots; const char *dots;
int st; int st;
@ -1507,7 +1507,10 @@ int repo_get_oid_mb(struct repository *r,
two = lookup_commit_reference_gently(r, &oid_tmp, 0); two = lookup_commit_reference_gently(r, &oid_tmp, 0);
if (!two) if (!two)
return -1; 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) if (!mbs || mbs->next)
st = -1; st = -1;
else { else {

View File

@ -1963,7 +1963,7 @@ static void add_pending_commit_list(struct rev_info *revs,


static void prepare_show_merge(struct rev_info *revs) static void prepare_show_merge(struct rev_info *revs)
{ {
struct commit_list *bases; struct commit_list *bases = NULL;
struct commit *head, *other; struct commit *head, *other;
struct object_id oid; struct object_id oid;
const char **prune = NULL; const char **prune = NULL;
@ -1978,7 +1978,8 @@ static void prepare_show_merge(struct rev_info *revs)
other = lookup_commit_or_die(&oid, "MERGE_HEAD"); other = lookup_commit_or_die(&oid, "MERGE_HEAD");
add_pending_object(revs, &head->object, "HEAD"); add_pending_object(revs, &head->object, "HEAD");
add_pending_object(revs, &other->object, "MERGE_HEAD"); add_pending_object(revs, &other->object, "MERGE_HEAD");
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_rev_cmdline_list(revs, bases, REV_CMD_MERGE_BASE, UNINTERESTING | BOTTOM);
add_pending_commit_list(revs, bases, UNINTERESTING | BOTTOM); add_pending_commit_list(revs, bases, UNINTERESTING | BOTTOM);
free_commit_list(bases); free_commit_list(bases);
@ -2066,14 +2067,17 @@ static int handle_dotdot_1(const char *arg, char *dotdot,
} else { } else {
/* A...B -- find merge bases between the two */ /* A...B -- find merge bases between the two */
struct commit *a, *b; struct commit *a, *b;
struct commit_list *exclude; struct commit_list *exclude = NULL;


a = lookup_commit_reference(revs->repo, &a_obj->oid); a = lookup_commit_reference(revs->repo, &a_obj->oid);
b = lookup_commit_reference(revs->repo, &b_obj->oid); b = lookup_commit_reference(revs->repo, &b_obj->oid);
if (!a || !b) if (!a || !b)
return dotdot_missing(arg, dotdot, revs, symmetric); 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, add_rev_cmdline_list(revs, exclude, REV_CMD_MERGE_BASE,
flags_exclude); flags_exclude);
add_pending_commit_list(revs, exclude, flags_exclude); add_pending_commit_list(revs, exclude, flags_exclude);

View File

@ -3908,7 +3908,7 @@ static int do_merge(struct repository *r,
int run_commit_flags = 0; int run_commit_flags = 0;
struct strbuf ref_name = STRBUF_INIT; struct strbuf ref_name = STRBUF_INIT;
struct commit *head_commit, *merge_commit, *i; 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; struct commit_list *to_merge = NULL, **tail = &to_merge;
const char *strategy = !opts->xopts.nr && const char *strategy = !opts->xopts.nr &&
(!opts->strategy || (!opts->strategy ||
@ -4134,7 +4134,11 @@ static int do_merge(struct repository *r,
} }


merge_commit = to_merge->item; 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, if (bases && oideq(&merge_commit->object.oid,
&bases->item->object.oid)) { &bases->item->object.oid)) {
ret = 0; ret = 0;

View File

@ -592,7 +592,12 @@ static void show_submodule_header(struct diff_options *o,
(!is_null_oid(two) && !*right)) (!is_null_oid(two) && !*right))
message = "(commits not present)"; 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) {
if ((*merge_bases)->item == *left) if ((*merge_bases)->item == *left)
fast_forward = 1; fast_forward = 1;

View File

@ -945,4 +945,16 @@ test_expect_success 'check the input format when --stdin is passed' '
test_cmp expect actual test_cmp expect 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 test_done