Skip to content

Commit 24876eb

Browse files
dschogitster
authored andcommitted
commit-reach(repo_in_merge_bases_many): report missing commits
Some functions in Git's source code follow the convention that returning a negative value indicates a fatal error, e.g. repository corruption. Let's use this convention in `repo_in_merge_bases()` to report when one of the specified commits is missing (i.e. when `repo_parse_commit()` reports an error). Also adjust the callers of `repo_in_merge_bases()` to handle such negative return values. Note: As of this patch, errors are returned only if any of the specified merge heads is missing. Over the course of the next patches, missing commits will also be reported by the `paint_down_to_common()` function, which is called by `repo_in_merge_bases_many()`, and those errors will be properly propagated back to the caller at that stage. Signed-off-by: Johannes Schindelin <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 207c40e commit 24876eb

File tree

12 files changed

+173
-36
lines changed

12 files changed

+173
-36
lines changed

builtin/branch.c

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,8 @@ static int branch_merged(int kind, const char *name,
158158

159159
merged = reference_rev ? repo_in_merge_bases(the_repository, rev,
160160
reference_rev) : 0;
161+
if (merged < 0)
162+
exit(128);
161163

162164
/*
163165
* After the safety valve is fully redefined to "check with
@@ -166,9 +168,13 @@ static int branch_merged(int kind, const char *name,
166168
* any of the following code, but during the transition period,
167169
* a gentle reminder is in order.
168170
*/
169-
if ((head_rev != reference_rev) &&
170-
(head_rev ? repo_in_merge_bases(the_repository, rev, head_rev) : 0) != merged) {
171-
if (merged)
171+
if (head_rev != reference_rev) {
172+
int expect = head_rev ? repo_in_merge_bases(the_repository, rev, head_rev) : 0;
173+
if (expect < 0)
174+
exit(128);
175+
if (expect == merged)
176+
; /* okay */
177+
else if (merged)
172178
warning(_("deleting branch '%s' that has been merged to\n"
173179
" '%s', but not yet merged to HEAD"),
174180
name, reference_name);

builtin/fast-import.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1625,6 +1625,7 @@ static int update_branch(struct branch *b)
16251625
oidclr(&old_oid);
16261626
if (!force_update && !is_null_oid(&old_oid)) {
16271627
struct commit *old_cmit, *new_cmit;
1628+
int ret;
16281629

16291630
old_cmit = lookup_commit_reference_gently(the_repository,
16301631
&old_oid, 0);
@@ -1633,7 +1634,10 @@ static int update_branch(struct branch *b)
16331634
if (!old_cmit || !new_cmit)
16341635
return error("Branch %s is missing commits.", b->name);
16351636

1636-
if (!repo_in_merge_bases(the_repository, old_cmit, new_cmit)) {
1637+
ret = repo_in_merge_bases(the_repository, old_cmit, new_cmit);
1638+
if (ret < 0)
1639+
exit(128);
1640+
if (!ret) {
16371641
warning("Not updating %s"
16381642
" (new tip %s does not contain %s)",
16391643
b->name, oid_to_hex(&b->oid),

builtin/fetch.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -982,6 +982,8 @@ static int update_local_ref(struct ref *ref,
982982
uint64_t t_before = getnanotime();
983983
fast_forward = repo_in_merge_bases(the_repository, current,
984984
updated);
985+
if (fast_forward < 0)
986+
exit(128);
985987
forced_updates_ms += (getnanotime() - t_before) / 1000000;
986988
} else {
987989
fast_forward = 1;

builtin/log.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1625,7 +1625,7 @@ static struct commit *get_base_commit(const char *base_commit,
16251625
{
16261626
struct commit *base = NULL;
16271627
struct commit **rev;
1628-
int i = 0, rev_nr = 0, auto_select, die_on_failure;
1628+
int i = 0, rev_nr = 0, auto_select, die_on_failure, ret;
16291629

16301630
switch (auto_base) {
16311631
case AUTO_BASE_NEVER:
@@ -1725,7 +1725,10 @@ static struct commit *get_base_commit(const char *base_commit,
17251725
rev_nr = DIV_ROUND_UP(rev_nr, 2);
17261726
}
17271727

1728-
if (!repo_in_merge_bases(the_repository, base, rev[0])) {
1728+
ret = repo_in_merge_bases(the_repository, base, rev[0]);
1729+
if (ret < 0)
1730+
exit(128);
1731+
if (!ret) {
17291732
if (die_on_failure) {
17301733
die(_("base commit should be the ancestor of revision list"));
17311734
} else {

builtin/merge-base.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,12 +100,16 @@ static int handle_octopus(int count, const char **args, int show_all)
100100
static int handle_is_ancestor(int argc, const char **argv)
101101
{
102102
struct commit *one, *two;
103+
int ret;
103104

104105
if (argc != 2)
105106
die("--is-ancestor takes exactly two commits");
106107
one = get_commit_reference(argv[0]);
107108
two = get_commit_reference(argv[1]);
108-
if (repo_in_merge_bases(the_repository, one, two))
109+
ret = repo_in_merge_bases(the_repository, one, two);
110+
if (ret < 0)
111+
exit(128);
112+
if (ret)
109113
return 0;
110114
else
111115
return 1;

builtin/pull.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -926,6 +926,8 @@ static int get_can_ff(struct object_id *orig_head,
926926
merge_head = lookup_commit_reference(the_repository, orig_merge_head);
927927
ret = repo_is_descendant_of(the_repository, merge_head, list);
928928
free_commit_list(list);
929+
if (ret < 0)
930+
exit(128);
929931
return ret;
930932
}
931933

@@ -950,6 +952,8 @@ static int already_up_to_date(struct object_id *orig_head,
950952
commit_list_insert(theirs, &list);
951953
ok = repo_is_descendant_of(the_repository, ours, list);
952954
free_commit_list(list);
955+
if (ok < 0)
956+
exit(128);
953957
if (!ok)
954958
return 0;
955959
}

builtin/receive-pack.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1526,6 +1526,7 @@ static const char *update(struct command *cmd, struct shallow_info *si)
15261526
starts_with(name, "refs/heads/")) {
15271527
struct object *old_object, *new_object;
15281528
struct commit *old_commit, *new_commit;
1529+
int ret2;
15291530

15301531
old_object = parse_object(the_repository, old_oid);
15311532
new_object = parse_object(the_repository, new_oid);
@@ -1539,7 +1540,10 @@ static const char *update(struct command *cmd, struct shallow_info *si)
15391540
}
15401541
old_commit = (struct commit *)old_object;
15411542
new_commit = (struct commit *)new_object;
1542-
if (!repo_in_merge_bases(the_repository, old_commit, new_commit)) {
1543+
ret2 = repo_in_merge_bases(the_repository, old_commit, new_commit);
1544+
if (ret2 < 0)
1545+
exit(128);
1546+
if (!ret2) {
15431547
rp_error("denying non-fast-forward %s"
15441548
" (you should pull first)", name);
15451549
ret = "non-fast-forward";

commit-reach.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -463,11 +463,13 @@ int repo_is_descendant_of(struct repository *r,
463463
} else {
464464
while (with_commit) {
465465
struct commit *other;
466+
int ret;
466467

467468
other = with_commit->item;
468469
with_commit = with_commit->next;
469-
if (repo_in_merge_bases_many(r, other, 1, &commit, 0))
470-
return 1;
470+
ret = repo_in_merge_bases_many(r, other, 1, &commit, 0);
471+
if (ret)
472+
return ret;
471473
}
472474
return 0;
473475
}
@@ -597,6 +599,8 @@ int ref_newer(const struct object_id *new_oid, const struct object_id *old_oid)
597599
commit_list_insert(old_commit, &old_commit_list);
598600
ret = repo_is_descendant_of(the_repository,
599601
new_commit, old_commit_list);
602+
if (ret < 0)
603+
exit(128);
600604
free_commit_list(old_commit_list);
601605
return ret;
602606
}

http-push.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1575,8 +1575,11 @@ static int verify_merge_base(struct object_id *head_oid, struct ref *remote)
15751575
struct commit *head = lookup_commit_or_die(head_oid, "HEAD");
15761576
struct commit *branch = lookup_commit_or_die(&remote->old_oid,
15771577
remote->name);
1578+
int ret = repo_in_merge_bases(the_repository, branch, head);
15781579

1579-
return repo_in_merge_bases(the_repository, branch, head);
1580+
if (ret < 0)
1581+
exit(128);
1582+
return ret;
15801583
}
15811584

15821585
static int delete_remote_branch(const char *pattern, int force)

merge-ort.c

Lines changed: 71 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -542,6 +542,7 @@ enum conflict_and_info_types {
542542
CONFLICT_SUBMODULE_HISTORY_NOT_AVAILABLE,
543543
CONFLICT_SUBMODULE_MAY_HAVE_REWINDS,
544544
CONFLICT_SUBMODULE_NULL_MERGE_BASE,
545+
CONFLICT_SUBMODULE_CORRUPT,
545546

546547
/* Keep this entry _last_ in the list */
547548
NB_CONFLICT_TYPES,
@@ -594,7 +595,9 @@ static const char *type_short_descriptions[] = {
594595
[CONFLICT_SUBMODULE_MAY_HAVE_REWINDS] =
595596
"CONFLICT (submodule may have rewinds)",
596597
[CONFLICT_SUBMODULE_NULL_MERGE_BASE] =
597-
"CONFLICT (submodule lacks merge base)"
598+
"CONFLICT (submodule lacks merge base)",
599+
[CONFLICT_SUBMODULE_CORRUPT] =
600+
"CONFLICT (submodule corrupt)"
598601
};
599602

600603
struct logical_conflict_info {
@@ -1708,7 +1711,14 @@ static int find_first_merges(struct repository *repo,
17081711
die("revision walk setup failed");
17091712
while ((commit = get_revision(&revs)) != NULL) {
17101713
struct object *o = &(commit->object);
1711-
if (repo_in_merge_bases(repo, b, commit))
1714+
int ret = repo_in_merge_bases(repo, b, commit);
1715+
1716+
if (ret < 0) {
1717+
object_array_clear(&merges);
1718+
release_revisions(&revs);
1719+
return ret;
1720+
}
1721+
if (ret > 0)
17121722
add_object_array(o, NULL, &merges);
17131723
}
17141724
reset_revision_walk();
@@ -1723,9 +1733,17 @@ static int find_first_merges(struct repository *repo,
17231733
contains_another = 0;
17241734
for (j = 0; j < merges.nr; j++) {
17251735
struct commit *m2 = (struct commit *) merges.objects[j].item;
1726-
if (i != j && repo_in_merge_bases(repo, m2, m1)) {
1727-
contains_another = 1;
1728-
break;
1736+
if (i != j) {
1737+
int ret = repo_in_merge_bases(repo, m2, m1);
1738+
if (ret < 0) {
1739+
object_array_clear(&merges);
1740+
release_revisions(&revs);
1741+
return ret;
1742+
}
1743+
if (ret > 0) {
1744+
contains_another = 1;
1745+
break;
1746+
}
17291747
}
17301748
}
17311749

@@ -1747,7 +1765,7 @@ static int merge_submodule(struct merge_options *opt,
17471765
{
17481766
struct repository subrepo;
17491767
struct strbuf sb = STRBUF_INIT;
1750-
int ret = 0;
1768+
int ret = 0, ret2;
17511769
struct commit *commit_o, *commit_a, *commit_b;
17521770
int parent_count;
17531771
struct object_array merges;
@@ -1794,8 +1812,26 @@ static int merge_submodule(struct merge_options *opt,
17941812
}
17951813

17961814
/* check whether both changes are forward */
1797-
if (!repo_in_merge_bases(&subrepo, commit_o, commit_a) ||
1798-
!repo_in_merge_bases(&subrepo, commit_o, commit_b)) {
1815+
ret2 = repo_in_merge_bases(&subrepo, commit_o, commit_a);
1816+
if (ret2 < 0) {
1817+
path_msg(opt, CONFLICT_SUBMODULE_CORRUPT, 0,
1818+
path, NULL, NULL, NULL,
1819+
_("Failed to merge submodule %s "
1820+
"(repository corrupt)"),
1821+
path);
1822+
goto cleanup;
1823+
}
1824+
if (ret2 > 0)
1825+
ret2 = repo_in_merge_bases(&subrepo, commit_o, commit_b);
1826+
if (ret2 < 0) {
1827+
path_msg(opt, CONFLICT_SUBMODULE_CORRUPT, 0,
1828+
path, NULL, NULL, NULL,
1829+
_("Failed to merge submodule %s "
1830+
"(repository corrupt)"),
1831+
path);
1832+
goto cleanup;
1833+
}
1834+
if (!ret2) {
17991835
path_msg(opt, CONFLICT_SUBMODULE_MAY_HAVE_REWINDS, 0,
18001836
path, NULL, NULL, NULL,
18011837
_("Failed to merge submodule %s "
@@ -1805,7 +1841,16 @@ static int merge_submodule(struct merge_options *opt,
18051841
}
18061842

18071843
/* Case #1: a is contained in b or vice versa */
1808-
if (repo_in_merge_bases(&subrepo, commit_a, commit_b)) {
1844+
ret2 = repo_in_merge_bases(&subrepo, commit_a, commit_b);
1845+
if (ret2 < 0) {
1846+
path_msg(opt, CONFLICT_SUBMODULE_CORRUPT, 0,
1847+
path, NULL, NULL, NULL,
1848+
_("Failed to merge submodule %s "
1849+
"(repository corrupt)"),
1850+
path);
1851+
goto cleanup;
1852+
}
1853+
if (ret2 > 0) {
18091854
oidcpy(result, b);
18101855
path_msg(opt, INFO_SUBMODULE_FAST_FORWARDING, 1,
18111856
path, NULL, NULL, NULL,
@@ -1814,7 +1859,16 @@ static int merge_submodule(struct merge_options *opt,
18141859
ret = 1;
18151860
goto cleanup;
18161861
}
1817-
if (repo_in_merge_bases(&subrepo, commit_b, commit_a)) {
1862+
ret2 = repo_in_merge_bases(&subrepo, commit_b, commit_a);
1863+
if (ret2 < 0) {
1864+
path_msg(opt, CONFLICT_SUBMODULE_CORRUPT, 0,
1865+
path, NULL, NULL, NULL,
1866+
_("Failed to merge submodule %s "
1867+
"(repository corrupt)"),
1868+
path);
1869+
goto cleanup;
1870+
}
1871+
if (ret2 > 0) {
18181872
oidcpy(result, a);
18191873
path_msg(opt, INFO_SUBMODULE_FAST_FORWARDING, 1,
18201874
path, NULL, NULL, NULL,
@@ -1839,6 +1893,13 @@ static int merge_submodule(struct merge_options *opt,
18391893
parent_count = find_first_merges(&subrepo, path, commit_a, commit_b,
18401894
&merges);
18411895
switch (parent_count) {
1896+
case -1:
1897+
path_msg(opt, CONFLICT_SUBMODULE_CORRUPT, 0,
1898+
path, NULL, NULL, NULL,
1899+
_("Failed to merge submodule %s "
1900+
"(repository corrupt)"),
1901+
path);
1902+
break;
18421903
case 0:
18431904
path_msg(opt, CONFLICT_SUBMODULE_FAILED_TO_MERGE, 0,
18441905
path, NULL, NULL, NULL,

0 commit comments

Comments
 (0)