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>
This commit is contained in:
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) {
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 {

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
* 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);

View File

@ -1514,10 +1514,13 @@ 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);
@ -1627,7 +1630,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;
/*
@ -1635,9 +1638,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)) {

View 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

View 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);

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

View File

@ -9,9 +9,10 @@ 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);
int repo_get_merge_bases(struct repository *r,
struct commit *rev1,
struct commit *rev2,
struct commit_list **result);
struct commit_list *repo_get_merge_bases_many(struct repository *r,
struct commit *one, int n,
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;
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)

View 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);

View File

@ -5068,7 +5068,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);
}

View File

@ -3633,7 +3633,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);
}

View 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;

View File

@ -1479,7 +1479,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;
@ -1507,7 +1507,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 {

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)
{
struct commit_list *bases;
struct commit_list *bases = NULL;
struct commit *head, *other;
struct object_id oid;
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");
add_pending_object(revs, &head->object, "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_pending_commit_list(revs, bases, UNINTERESTING | BOTTOM);
free_commit_list(bases);
@ -2066,14 +2067,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);

View File

@ -3908,7 +3908,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 ||
@ -4134,7 +4134,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;

View 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;

View File

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