Message ID | patch-v4-1.1-0caa9a89a86-20210831T135212Z-avarab@gmail.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | [v4] pull, fetch: fix segfault in --set-upstream option | expand |
Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes: >> Testing the new behaviour is a good idea. I also agree with you >> that die() would be more appropriate and does not risk regression, >> if the original behaviour was to segfault. > > Indeed. I changed it due to your upthread > <xmqqsg0anxix.fsf@gitster.g>. > > I think doing s/warning/die/ here makes sense, but similarly to the > above comment: Let's punt on that and do it separately from this > narrow segfault fix. If and when we change that we should change > various other "warning()" around this codepath to "die()" as well. I do not think that can be thrown into the same bin as "should UI give irrelevant details?" issue. If you make it not to segfault and give just a warning(), it becomes impossible to make it die() later. If we all agree that die() is a better action, that must be done now, or it will become never once the change is released to the field.
On Tue, Aug 31 2021, Junio C Hamano wrote: > Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes: > >>> Testing the new behaviour is a good idea. I also agree with you >>> that die() would be more appropriate and does not risk regression, >>> if the original behaviour was to segfault. >> >> Indeed. I changed it due to your upthread >> <xmqqsg0anxix.fsf@gitster.g>. >> >> I think doing s/warning/die/ here makes sense, but similarly to the >> above comment: Let's punt on that and do it separately from this >> narrow segfault fix. If and when we change that we should change >> various other "warning()" around this codepath to "die()" as well. > > I do not think that can be thrown into the same bin as "should UI > give irrelevant details?" issue. If you make it not to segfault and > give just a warning(), it becomes impossible to make it die() later. > > If we all agree that die() is a better action, that must be done > now, or it will become never once the change is released to the > field. Because someone might have been relying on the current behavior of segfaulting to stop their script? And a mere warning() would break things for them by having the script "work" if this patch were to make it into a release? I think it's unlikely that anyone's running into this in the wild as anything but a one-off, and in any case whether or not we segfault, warn or die the behavior of fetch at this point is to have already finished the fetch itself. We're merely doing some post-fetch work of setting config etc. Both before and after this patch we won't be setting the upstream config. But yes, the exit code will change from a segfault to successful exit. I think the first priority should be to just narrowly fix the segfault & leave refactoring of e.g. having fetch do sanity checking on all options before doing work for later, especially as we're almost 2 months into no fix for the segfault landing on "master" after the first working patch to fix it, so if we have that all wait on agreeing on the perfect behavior for fetch error handling...
Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes: >> If we all agree that die() is a better action, that must be done >> now, or it will become never once the change is released to the >> field. > > Because someone might have been relying on the current behavior of > segfaulting to stop their script? And a mere warning() would break > things for them by having the script "work" if this patch were to make > it into a release? No, because someone WILL start rely on the warning() behaviour, expecting that the "fixed" command will now run to completion without exiting with non-zero status. Once that happens, it will become impossible to flip it to die().
diff --git a/builtin/fetch.c b/builtin/fetch.c index e064687dbdc..28fa168133a 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -1625,6 +1625,16 @@ static int do_fetch(struct transport *transport, } } if (source_ref) { + if (!branch) { + const char *shortname = source_ref->name; + skip_prefix(shortname, "refs/heads/", &shortname); + + warning(_("could not set upstream of HEAD to '%s' from '%s' when " + "it does not point to any branch."), + shortname, transport->remote->name); + goto skip; + } + if (!strcmp(source_ref->name, "HEAD") || starts_with(source_ref->name, "refs/heads/")) install_branch_config(0, diff --git a/t/t5553-set-upstream.sh b/t/t5553-set-upstream.sh index 9c12c0f8c32..48050162c27 100755 --- a/t/t5553-set-upstream.sh +++ b/t/t5553-set-upstream.sh @@ -91,6 +91,17 @@ test_expect_success 'fetch --set-upstream with valid URL sets upstream to URL' ' check_config_missing other2 ' +test_expect_success 'fetch --set-upstream with a detached HEAD' ' + git checkout HEAD^0 && + test_when_finished "git checkout -" && + cat >expect <<-\EOF && + warning: could not set upstream of HEAD to '"'"'main'"'"' from '"'"'upstream'"'"' when it does not point to any branch. + EOF + git fetch --set-upstream upstream main 2>actual.raw && + grep ^warning: actual.raw >actual && + test_cmp expect actual +' + # tests for pull --set-upstream test_expect_success 'setup bare parent pull' ' @@ -178,4 +189,15 @@ test_expect_success 'pull --set-upstream with valid URL and branch sets branch' check_config_missing other2 ' +test_expect_success 'pull --set-upstream with a detached HEAD' ' + git checkout HEAD^0 && + test_when_finished "git checkout -" && + cat >expect <<-\EOF && + warning: could not set upstream of HEAD to '"'"'main'"'"' from '"'"'upstream'"'"' when it does not point to any branch. + EOF + git pull --no-rebase --set-upstream upstream main 2>actual.raw && + grep ^warning: actual.raw >actual && + test_cmp expect actual +' + test_done