Skip to content

Commit

Permalink
Merge branch 'js/merge-base-with-missing-commit'
Browse files Browse the repository at this point in the history
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
  • Loading branch information
gitster committed Mar 11, 2024
2 parents e09f125 + 25fd20e commit 7745f92
Show file tree
Hide file tree
Showing 29 changed files with 460 additions and 188 deletions.
7 changes: 4 additions & 3 deletions bisect.c
Expand Up @@ -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;
Expand Down
12 changes: 9 additions & 3 deletions builtin/branch.c
Expand Up @@ -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
Expand All @@ -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);
Expand Down
6 changes: 5 additions & 1 deletion builtin/fast-import.c
Expand Up @@ -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);
Expand All @@ -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),
Expand Down
2 changes: 2 additions & 0 deletions builtin/fetch.c
Expand Up @@ -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;
Expand Down
30 changes: 17 additions & 13 deletions builtin/log.c
Expand Up @@ -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:
Expand Down Expand Up @@ -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;

Expand All @@ -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 {
Expand Down Expand Up @@ -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 {
Expand All @@ -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 {
Expand Down
23 changes: 17 additions & 6 deletions builtin/merge-base.c
Expand Up @@ -10,10 +10,13 @@

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;
Expand Down Expand Up @@ -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);

Expand All @@ -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;
Expand Down
5 changes: 3 additions & 2 deletions builtin/merge-tree.c
Expand Up @@ -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);
Expand Down
26 changes: 17 additions & 9 deletions builtin/merge.c
Expand Up @@ -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);
}

Expand Down Expand Up @@ -1626,17 +1633,18 @@ 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;

/*
* Here we *have* to calculate the individual
* 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)) {
Expand Down
9 changes: 7 additions & 2 deletions builtin/pull.c
Expand Up @@ -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);
Expand All @@ -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);

Expand Down Expand Up @@ -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;
}

Expand All @@ -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;
}
Expand Down
8 changes: 5 additions & 3 deletions builtin/rebase.c
Expand Up @@ -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;

Expand All @@ -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
Expand Down
6 changes: 5 additions & 1 deletion builtin/receive-pack.c
Expand Up @@ -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);
Expand All @@ -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";
Expand Down
5 changes: 3 additions & 2 deletions builtin/rev-parse.c
Expand Up @@ -297,15 +297,16 @@ 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);
if (!a || !b) {
*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);
Expand Down

0 comments on commit 7745f92

Please sign in to comment.