The merge-base logic vs missing commit objects (follow-up)
cover The merge-base logic vs missing commit objects (follow-up)
Jeff King reported that Coverity pointed out a problem in the patch series "The merge-base logic vs missing commit objects" (which made it into the next branch already): The return value of merge_submodules() is assigned to an unsigned, single-bit variable, which as a consequence is not able to hold a negative value indicating a non-recoverable error.
I looked into this issue and am happy to report that there are no other instances of the same issue in that patch series. The first patch in this here patch series addresses that issue.
While looking into this issue I also noticed that the merge_submodule() function did not even return negative values! This was an oversight on my part (which I attribute with a large amount of self-compassion to my utter lack of enthusiasm for submodules as a Git feature), and the second patch in this here patch series addresses that.
This is a follow-up for
https://lore.kernel.org/git/[email protected]/,
based on the js/merge-base-with-missing-commit branch.
Johannes Schindelin (2):
merge-recursive: prepare for merge_submodule() to report errors merge-ort/merge-recursive: do report errors in merge_submodule()
merge-ort.c | 5 +++++ merge-recursive.c | 21 +++++++++++++++------ 2 files changed, 20 insertions(+), 6 deletions(-)
base-commit: caaf1a2942c25c1f1a15818b718c9f641e52beef
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-1686%2Fdscho%2Fmerge-base-and-missing-objects-followup-v1
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1686/dscho/merge-base-and-missing-objects-followup-v1
Pull-Request: https://github.com/gitgitgadget/git/pull/1686
Signature · 1 line
gitgitgadget
PATCH 1/2 merge-recursive: prepare for `merge_submodule()` to report errors
From: Johannes Schindelin <[email protected]>
The merge_submodule() function returns an integer that indicates whether the merge was clean (returning 1) or unclean (returning 0).
Like the version in merge-ort.c, the version in merge-recursive.c does not report any errors (such as repository corruption) by returning -1 as of time of writing, even if the callers in merge-ort.c are prepared for exactly such errors.
However, we want to teach (both variants of) the merge_submodule() function that trick: to report errors by returning -1. Therefore, prepare the caller in merge-recursive.c to handle that scenario.
--- merge-recursive.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-)
merge-recursive.c +7 -6
@@ -1426,13 +1426,14 @@ static int merge_mode_and_contents(struct merge_options *opt,/* FIXME: bug, what if modes didn't match? */ result->clean = (merge_status ==0 ); }else if (S_ISGITLINK (a->mode)) { - result->clean =merge_submodule (opt, &result->blob.oid, - o->path, - &o->oid, - &a->oid, - &b->oid); -if (result->clean <0 ) +int clean =merge_submodule (opt, &result->blob.oid, + o->path, + &o->oid, + &a->oid, + &b->oid); +if (clean <0 )return -1 ; + result->clean = clean; }else if (S_ISLNK (a->mode)) {switch (opt->recursive_variant) {case MERGE_VARIANT_NORMAL :
Signature · 1 line
gitgitgadget
PATCH 2/2 merge-ort/merge-recursive: do report errors in `merge_submodule()`
In reply to Johannes Schindelin via GitGitGadgetFrom: Johannes Schindelin <[email protected]>
In 24876ebf68b (commit-reach(repo_in_merge_bases_many): report missing commits, 2024-02-28), I taught merge_submodule() to handle errors reported by repo_in_merge_bases_many().
However, those errors were not passed through to the callers. That was unintentional, and this commit remedies that.
Note that find_first_merges() can now also return -1 (because it passes through that return value from repo_in_merge_bases()), and this commit also adds the forgotten handling for that scenario.
--- merge-ort.c | 5 +++++ merge-recursive.c | 8 ++++++++ 2 files changed, 13 insertions(+)
merge-ort.c +5 -0
@@ -1819,6 +1819,7 @@ static int merge_submodule(struct merge_options *opt,_ ("Failed to merge submodule %s " "(repository corrupt)" ), path); + ret =-1 ; goto cleanup; }if (ret2 >0 )
@@ -1829,6 +1830,7 @@ static int merge_submodule(struct merge_options *opt,_ ("Failed to merge submodule %s " "(repository corrupt)" ), path); + ret =-1 ; goto cleanup; }if (!ret2) {
@@ -1848,6 +1850,7 @@ static int merge_submodule(struct merge_options *opt,_ ("Failed to merge submodule %s " "(repository corrupt)" ), path); + ret =-1 ; goto cleanup; }if (ret2 >0 ) {
@@ -1866,6 +1869,7 @@ static int merge_submodule(struct merge_options *opt,_ ("Failed to merge submodule %s " "(repository corrupt)" ), path); + ret =-1 ; goto cleanup; }if (ret2 >0 ) {
@@ -1899,6 +1903,7 @@ static int merge_submodule(struct merge_options *opt,_ ("Failed to merge submodule %s " "(repository corrupt)" ), path); + ret =-1 ;break ;case 0 : path_msg(opt, CONFLICT_SUBMODULE_FAILED_TO_MERGE, 0,
merge-recursive.c +8 -0
@@ -1246,12 +1246,14 @@ static int merge_submodule(struct merge_options *opt, ret2 =repo_in_merge_bases (&subrepo, commit_base, commit_a);if (ret2 <0 ) {output (opt,1 ,_ ("Failed to merge submodule %s (repository corrupt)" ), path); + ret =-1 ; 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); + ret =-1 ; goto cleanup; }if (!ret2) {
@@ -1263,6 +1265,7 @@ static int merge_submodule(struct merge_options *opt, ret2 =repo_in_merge_bases (&subrepo, commit_a, commit_b);if (ret2 <0 ) {output (opt,1 ,_ ("Failed to merge submodule %s (repository corrupt)" ), path); + ret =-1 ; goto cleanup; }if (ret2) {
@@ -1281,6 +1284,7 @@ static int merge_submodule(struct merge_options *opt, ret2 =repo_in_merge_bases (&subrepo, commit_b, commit_a);if (ret2 <0 ) {output (opt,1 ,_ ("Failed to merge submodule %s (repository corrupt)" ), path); + ret =-1 ; goto cleanup; }if (ret2) {
@@ -1312,6 +1316,10 @@ static int merge_submodule(struct merge_options *opt, parent_count =find_first_merges (&subrepo, &merges, path, commit_a, commit_b);switch (parent_count) { +case -1 : +output (opt,1 ,_ ("Failed to merge submodule %s (repository corrupt)" ), path); + ret =-1 ; +break ;case 0 :output (opt,1 ,_ ("Failed to merge submodule %s (merge following commits not found)" ), path);break ;
Signature · 1 line
gitgitgadget
Quoted 17 lines · Johannes Schindelin via GitGitGadget
Jeff King reported that Coverity pointed out a problem in the patch series "The merge-base logic vs missing commit objects" (which made it into the next branch already): The return value of
merge_submodules()is assigned to an unsigned, single-bit variable, which as a consequence is not able to hold a negative value indicating a non-recoverable error.I looked into this issue and am happy to report that there are no other instances of the same issue in that patch series. The first patch in this here patch series addresses that issue.
While looking into this issue I also noticed that the
merge_submodule()function did not even return negative values! This was an oversight on my part (which I attribute with a large amount of self-compassion to my utter lack of enthusiasm for submodules as a Git feature), and the second patch in this here patch series addresses that.
Quoted 3 lines
This is a follow-up for
https://lore.kernel.org/git/[email protected]/,
based on the js/merge-base-with-missing-commit branch.
This series looks good to me; thanks.
"Johannes Schindelin via GitGitGadget" <[email protected]>
Quoted 16 lines · writes:
Jeff King reported that Coverity pointed out a problem in the patch series "The merge-base logic vs missing commit objects" (which made it into the next branch already): The return value of
merge_submodules()is assigned to an unsigned, single-bit variable, which as a consequence is not able to hold a negative value indicating a non-recoverable error.I looked into this issue and am happy to report that there are no other instances of the same issue in that patch series. The first patch in this here patch series addresses that issue.
While looking into this issue I also noticed that the
merge_submodule()function did not even return negative values! This was an oversight on my part (which I attribute with a large amount of self-compassion to my utter lack of enthusiasm for submodules as a Git feature), and the second patch in this here patch series addresses that.
Quoted 3 lines
This is a follow-up for
https://lore.kernel.org/git/[email protected]/,
based on the js/merge-base-with-missing-commit branch.
Thanks.
Quoted 14 lines
Johannes Schindelin (2):
merge-recursive: prepare formerge_submodule()to report errors merge-ort/merge-recursive: do report errors inmerge_submodule()merge-ort.c | 5 +++++ merge-recursive.c | 21 +++++++++++++++------ 2 files changed, 20 insertions(+), 6 deletions(-)base-commit:
caaf1a2942c25c1f1a15818b718c9f641e52beef
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-1686%2Fdscho%2Fmerge-base-and-missing-objects-followup-v1
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1686/dscho/merge-base-and-missing-objects-followup-v1
Pull-Request: https://github.com/gitgitgadget/git/pull/1686
Re: [PATCH 2/2] merge-ort/merge-recursive: do report errors in `merge_submodule()`
In reply to Johannes Schindelin via GitGitGadget"Johannes Schindelin via GitGitGadget" <[email protected]>
Quoted 6 lines · writes:
From: Johannes Schindelin <[email protected]>
In
24876ebf68b(commit-reach(repo_in_merge_bases_many): report missing commits, 2024-02-28), I taughtmerge_submodule()to handle errors reported byrepo_in_merge_bases_many().
Quoted 6 lines
However, those errors were not passed through to the callers. That was unintentional, and this commit remedies that.
Note that
find_first_merges()can now also return -1 (because it passes through that return value fromrepo_in_merge_bases()), and this commit also adds the forgotten handling for that scenario.
Good clean-up. But this "oops, we did not check for errors" makes me wonder if we are better off adopting "by default we assume an error, until we are sure we are good" pattern, i.e.
func()
{
int ret = -1; /* assume worst */
do stuff;
if (...) {
error(_("this is bad"));
goto cleanup;
}
do stuff;
if (...) {
error(_("this is bad, too"));
goto cleanup;
}
/* ok we are happy */
ret = 0;
cleanup:
release resources;
return ret;
}The patch to both functions do make it appear that they are good candidates for application of the pattern to me.
Thanks.
Quoted 96 lines
Signed-off-by Johannes Schindelin <[email protected]>--- merge-ort.c | 5 +++++ merge-recursive.c | 8 ++++++++ 2 files changed, 13 insertions(+)merge-ort.c +5
-0@@ -1819,6 +1819,7 @@ static int merge_submodule(struct merge_options *opt,_ ("Failed to merge submodule %s " "(repository corrupt)" ), path); + ret =-1 ; goto cleanup; }if (ret2 >0 )@@ -1829,6 +1830,7 @@ static int merge_submodule(struct merge_options *opt,_ ("Failed to merge submodule %s " "(repository corrupt)" ), path); + ret =-1 ; goto cleanup; }if (!ret2) {@@ -1848,6 +1850,7 @@ static int merge_submodule(struct merge_options *opt,_ ("Failed to merge submodule %s " "(repository corrupt)" ), path); + ret =-1 ; goto cleanup; }if (ret2 >0 ) {@@ -1866,6 +1869,7 @@ static int merge_submodule(struct merge_options *opt,_ ("Failed to merge submodule %s " "(repository corrupt)" ), path); + ret =-1 ; goto cleanup; }if (ret2 >0 ) {@@ -1899,6 +1903,7 @@ static int merge_submodule(struct merge_options *opt,_ ("Failed to merge submodule %s " "(repository corrupt)" ), path); + ret =-1 ;break ;case 0 : path_msg(opt, CONFLICT_SUBMODULE_FAILED_TO_MERGE, 0,merge-recursive.c +8
-0@@ -1246,12 +1246,14 @@ static int merge_submodule(struct merge_options *opt, ret2 =repo_in_merge_bases (&subrepo, commit_base, commit_a);if (ret2 <0 ) {output (opt,1 ,_ ("Failed to merge submodule %s (repository corrupt)" ), path); + ret =-1 ; 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); + ret =-1 ; goto cleanup; }if (!ret2) {@@ -1263,6 +1265,7 @@ static int merge_submodule(struct merge_options *opt, ret2 =repo_in_merge_bases (&subrepo, commit_a, commit_b);if (ret2 <0 ) {output (opt,1 ,_ ("Failed to merge submodule %s (repository corrupt)" ), path); + ret =-1 ; goto cleanup; }if (ret2) {@@ -1281,6 +1284,7 @@ static int merge_submodule(struct merge_options *opt, ret2 =repo_in_merge_bases (&subrepo, commit_b, commit_a);if (ret2 <0 ) {output (opt,1 ,_ ("Failed to merge submodule %s (repository corrupt)" ), path); + ret =-1 ; goto cleanup; }if (ret2) {@@ -1312,6 +1316,10 @@ static int merge_submodule(struct merge_options *opt, parent_count =find_first_merges (&subrepo, &merges, path, commit_a, commit_b);switch (parent_count) { +case -1 : +output (opt,1 ,_ ("Failed to merge submodule %s (repository corrupt)" ), path); + ret =-1 ; +break ;case 0 :output (opt,1 ,_ ("Failed to merge submodule %s (merge following commits not found)" ), path);break ;
Quoted 5 lines · Elijah Newren
Quoted 3 lines
This is a follow-up for
https://lore.kernel.org/git/[email protected]/,
based on the js/merge-base-with-missing-commit branch.This series looks good to me; thanks.
Thanks, both.
Re: [PATCH 2/2] merge-ort/merge-recursive: do report errors in `merge_submodule()`
In reply to Junio C HamanoHi Junio,
Quoted 43 lines · Junio C Hamano
"Johannes Schindelin via GitGitGadget" <[email protected]>
Quoted 6 lines · writes:
From: Johannes Schindelin <[email protected]>
In
24876ebf68b(commit-reach(repo_in_merge_bases_many): report missing commits, 2024-02-28), I taughtmerge_submodule()to handle errors reported byrepo_in_merge_bases_many().Quoted 6 lines
However, those errors were not passed through to the callers. That was unintentional, and this commit remedies that.
Note that
find_first_merges()can now also return -1 (because it passes through that return value fromrepo_in_merge_bases()), and this commit also adds the forgotten handling for that scenario.Good clean-up. But this "oops, we did not check for errors" makes me wonder if we are better off adopting "by default we assume an error, until we are sure we are good" pattern, i.e.
func() { int ret = -1; /* assume worst */ do stuff; if (...) { error(_("this is bad")); goto cleanup; } do stuff; if (...) { error(_("this is bad, too")); goto cleanup; } /* ok we are happy */ ret = 0; cleanup: release resources; return ret; }
Quoted 2 lines
The patch to both functions do make it appear that they are good candidates for application of the pattern to me.
This is a very fitting pattern here, and it is in fact used already! It is used with ret = 0, though, to indicate unclean merges.
This makes sense, as most of the specifically-handled cases have that outcome. By my counting, 5 of the handled cases result in ret = -1, i.e. non-recoverable errors, but 8 of the cases result in ret = 0, i.e. unclean merges, whereas only 2 cases return 1, i.e. clean merges.
Those numbers are for the merge_submodule() variant in merge-ort.c. In merge-recursive.c, by my counting there are 10 instead of 8 ret = 0 cases, the other two numbers are the same.
Ciao,
Johannes
Re: [PATCH 2/2] merge-ort/merge-recursive: do report errors in `merge_submodule()`
Quoted 4 lines · Johannes Schindelin
By my counting, 5 of the handled cases result in ret = -1, i.e. non-recoverable errors, but 8 of the cases result in ret = 0, i.e. unclean merges, whereas only 2 cases return 1, i.e. clean merges.
Sounds good. Thanks.