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: Vincent Lefevre <hidden>
Date: 2021-02-01 12:37:42

On 2021-02-01 03:33:54 -0800, Chris Torek wrote:
quoted
On 2021-01-31 21:49:49 +0100, Ævar Arnfjörð Bjarmason wrote:
quoted
... 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
This example has a minor flaw: it should use `git -c core.pager=/bin/true`,
probably.
In this case, since /bin/true doesn't read anything on purpose,
I would not expect any non-zero exit status.

And note that

  git -c core.pager="sh -c 'cat; /bin/false'" log

exits with a zero exit status, which is unexpected since the
pager failed. For instance, in practice, the pager could be
killed by the system, but the user would not necessarily notice
this as the pager may be configured to quit automatically when
reaching the end of the output (there are some "less" options
to do that: -E, -F). So, the user would think that he got the
full output while he didn't.

[...]
quoted
quoted
Not being able to write "git log" output is a real SIGPIPE.
Worth noting: Linux has a pretty large pipe buffer.  POSIX requires
at least 4k here, as I recall, but Linux will buffer 64k or more, so that
if `git log` is able to write the entire log text (will be the case for small
repositories) *before* the program on the right side of the pager pipe
exits (this depends on many things), the pager's exit *won't* cause
a SIGPIPE.  You'll get the SIGPIPE if either the pager exits very
quickly, so that `git log` is unable to write much before the exit, or
if the repository is sufficiently large so that the pipe blocks first.
In general, repositories have more than 64k log.
quoted
Which is not the case here, because the full output has never been
requested by the user.
The `git log` command *did* request the full output.
No, because the output is sent to a pager. As long as the user
does not look at more than what he looks for, no more "git log"
output is requested (such output can happen internally, but it
is not requested by the user).
The problem that has come up is, if I understand correctly, that
some Linux distributions have come with misconfigured pagers
that don't bother reading their input, and silently exit zero.
They are not misconfigured. This is how they work. Actually I don't
see why they should read more than needed: this would be a useless
waste of memory.
This causes all kinds of Git commands to *seem* to fail. The Git
commands are just fine; the bug is that the pager doesn't read or
write anything.

Unfortunately, the way that pipes work -- asynchronously -- means
that Git really *can't* catch all problems here.  But catching a SIGPIPE,
whether Git itself spawned the pager or not, does indicate that
something has gone wrong ... *unless* Git was piping to, e.g., less,
and the user read enough, and the user typed `q` at less, and less
exited without bothering to read the rest of the input.

There's no good way for Git to be able to tell which of these was
the case.
In the case git spawns a pager, it knows that this is a pager
(as per documentation).

-- 
Vincent Lefèvre [off-list ref] - Web: <https://www.vinc17.net/>
100% accessible validated (X)HTML - Blog: <https://www.vinc17.net/blog/>
Work: CR INRIA - computer arithmetic / AriC project (LIP, ENS-Lyon)
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help