Thread (38 messages) 38 messages, 5 authors, 2021-02-05

Re: git fails with a broken pipe when one quits the pager

flat view

From: Ævar Arnfjörð Bjarmason <hidden>
Date: 2021-02-01 12:11:20

On Mon, Feb 01 2021, Vincent Lefevre wrote:
On 2021-01-31 21:49:49 +0100, �var Arnfj�r� Bjarmason wrote:
quoted
On Sun, Jan 31 2021, Vincent Lefevre wrote:
quoted
FYI, I already have the exit status already in my prompt (the above
commands were just for the example). Still, the git behavior is
disturbing.

Moreover, this doesn't solve the issue when doing something like

  git log && some_other_command
What issue? That we're returning an exit code per getting a SIGHUP here
is a feature. Consider:

    git -c core.pager=/bin/false log && echo showed you the output
If the pager exists with a non-zero exit status, it is normal to
return a non-zero exit status. This was not the bug I reported.
Is it normal? Isn't this subject to the same race noted in
https://lore.kernel.org/git/20191115040909.GA21654@sigill.intra.peff.net/ (local)

I.e. we start the /bin/false process, then start spewing output to it,
so maybe we'll get a SIGPIPE first because it's not being consumed, or
maybe /bin/false (or whatever else exits with non-zero) will exit first.

Unrelated to that there's at least a bug in wait_for_pager_signal() in
how we log the pager's exit. We just rely on "ret" in
finish_command_in_signal() before calling trace2_child_exit(), but
should probably log -1 there or something and defer.
quoted
quoted
No! I want to be warned about real SIGPIPEs.
Not being able to write "git log" output is a real SIGPIPE.
Which is not the case here, because the full output has never been
requested by the user.
They requested it by running "git log", which e.g. for git.git is ~1
million lines. Then presumably paged down just a few pages and issued
"q" in their pager. At which point we'll fail on the write() in git-log.

The pager's exit status is usually/always 0 in those cases
(e.g. https://pubs.opengroup.org/onlinepubs/9699919799/utilities/more.html). So
we've got the SIGPIPE to indicate the output wasn't fully consumed.
quoted
Is it because in your mind it's got something to do with the "|" shell
piping construct? The SIGPIPE is sent by the kernel, so it's no less
expected in cases like:

    git log && echo foo

Than:

    git log | cat
See the difference (without the patch) between

$ git log && echo foo; echo $?
141

and

$ git log | head; echo $?
[...]
0
Presumably that first command is one where you exited your pager before
the output wasn't fully consumed, see above.
[...]
quoted
Maybe we have users who'd like to work around zsh's "setopt
PRINT_EXIT_VALUE" mode (would you want this patch if you could make zsh
ignore 141?).
zsh is working as expected, and as I've already said, I ***WANT***
SIGPIPE to be reported by the shell, as it may indicate a real failure
in a script. BTW, I even have a script using git that relies on that:

{ git rev-list --author "$@[-1]" HEAD &&
  git rev-list --grep   "$@[-1]" HEAD } | \
  git "${@[1,-2]:-lv}" --no-walk --stdin

return $((pipestatus[2] ? pipestatus[2] : pipestatus[1]))

Here it is important not to lose any information. No pager is
involved, the full output is needed. If for some reason, the
LHS of the pipe fails due to a SIGPIPE but the right hand side
succeeds, the error will be reported.
Sorry, I really don't see how this is different. I think this goes back
to my "'|' shell piping construct[...]" question in the E-Mail you're
replying to.

in both the "git log &&" case and potentially here you'll get a program
writing to a pipe getting a SIGPIPE, which is then reflected in the exit
code.
The fact is that with a pager, the SIGPIPE with a pager is normal.
Thus with a pager, git is reporting a spurious SIGPIPE, and this
is disturbing.
I don't get what you're trying to say here, sorry.

Maybe this helps. So first, I don't know if your report came out of
reading the recent "set -o pipefail" traffic on-list. As you can see in
[1] I'm not some zealot for PIPEFAIL always being returned no matter
what.

The difference between that though and what you're proposing is there
you have the shell getting an exit code and opting to ignore it, as
opposed to the program itself sweeping it under the rug.

I don't think either that just because you run a pager you're obligated
to ferry down a SIGPIPE if you get it. E.g. mysql and postgresql both
have interactive shells where you can open pagers. I didn't bother to
check, but you can imagine doing a "show tables" or whatever and only
viewing the first page, then quitting in the pager.

If that's part of a long interactive SQL session it would make no sense
for the eventual exit code of mysql(1) or psql(1) to reflect that.

But with git we're (mostly) executing one-shot commands, e.g. with "git
log" you give it some params, and it spews all the output at you, maybe
with the help of a pager.

So then if we fail on the write() I don't see how it doesn't make sense
to return the appropriate exit code for that failure downstream.

1. https://lore.kernel.org/git/20210116153554.12604-12-avarab@gmail.com/ (local)
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help