mirror of
https://github.com/git/git.git
synced 2024-05-04 13:36:14 +02:00
Merge branch 'js/merge-base-with-missing-commit' into HEAD
Make sure failure return from merge_bases_many() is properly caught. * js/merge-base-with-missing-commit: 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
This commit is contained in:
commit
3e3eabaee9
7
bisect.c
7
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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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);
|
||||
|
|
209
commit-reach.c
209
commit-reach.c
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
7
commit.c
7
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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
87
merge-ort.c
87
merge-ort.c
|
@ -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,26 @@ 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);
|
||||
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);
|
||||
goto cleanup;
|
||||
}
|
||||
if (!ret2) {
|
||||
path_msg(opt, CONFLICT_SUBMODULE_MAY_HAVE_REWINDS, 0,
|
||||
path, NULL, NULL, NULL,
|
||||
_("Failed to merge submodule %s "
|
||||
|
@ -1807,7 +1843,16 @@ 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);
|
||||
goto cleanup;
|
||||
}
|
||||
if (ret2 > 0) {
|
||||
oidcpy(result, b);
|
||||
path_msg(opt, INFO_SUBMODULE_FAST_FORWARDING, 1,
|
||||
path, NULL, NULL, NULL,
|
||||
|
@ -1816,7 +1861,16 @@ 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);
|
||||
goto cleanup;
|
||||
}
|
||||
if (ret2 > 0) {
|
||||
oidcpy(result, a);
|
||||
path_msg(opt, INFO_SUBMODULE_FAST_FORWARDING, 1,
|
||||
path, NULL, NULL, NULL,
|
||||
|
@ -1841,6 +1895,13 @@ 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);
|
||||
break;
|
||||
case 0:
|
||||
path_msg(opt, CONFLICT_SUBMODULE_FAILED_TO_MERGE, 0,
|
||||
path, NULL, NULL, NULL,
|
||||
|
@ -5014,7 +5075,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);
|
||||
}
|
||||
|
|
|
@ -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,29 @@ 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);
|
||||
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);
|
||||
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);
|
||||
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 +1279,12 @@ 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);
|
||||
goto cleanup;
|
||||
}
|
||||
if (ret2) {
|
||||
oidcpy(result, a);
|
||||
if (show(opt, 3)) {
|
||||
output(opt, 3, _("Fast-forwarding submodule %s to the following commit:"), path);
|
||||
|
@ -1398,6 +1432,8 @@ static int merge_mode_and_contents(struct merge_options *opt,
|
|||
&o->oid,
|
||||
&a->oid,
|
||||
&b->oid);
|
||||
if (result->clean < 0)
|
||||
return -1;
|
||||
} else if (S_ISLNK(a->mode)) {
|
||||
switch (opt->recursive_variant) {
|
||||
case MERGE_VARIANT_NORMAL:
|
||||
|
@ -3598,7 +3634,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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
2
remote.c
2
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;
|
||||
}
|
||||
|
||||
|
|
12
revision.c
12
revision.c
|
@ -1991,7 +1991,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;
|
||||
|
@ -2006,7 +2006,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);
|
||||
|
@ -2094,14 +2095,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);
|
||||
|
|
|
@ -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;
|
||||
|
|
21
shallow.c
21
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];
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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")) {
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue