Your program, in this case mydiff
, and the pager (less
, or whatever you have selected as core.pager
) are connected through a pipe. The OS has some limit on the amount of data that can be written into a pipe before the reader must clean some out, and the pager doesn't read the entire pipe before pausing, so at some amount of output, the pipe has filled up and your program is blocked in its write
system call.
If the read end of the pipe goes away (by having the pager exit), two things happen at this point: the OS delivers a SIGPIPE
signal to your program, and the OS has the write
system call fail with an EPIPE
error. Normally the first—the signal—kills your program before the second even occurs, but if your program were to catch or ignore SIGPIPE
, the second would occur.
Here's an example in a job-control shell of SIGPIPE
killing a process:
> cat book.pdf | : &
>
[1] Broken pipe cat book.pdf |
Done :
(Incidentally :
here is the built in colon command, which is a no-op; it's a leftover from, I think, the Mashey shell that had goto
as an external program.) Running this as a regular foreground process, the sequence is silent:
> cat book.pdf | :
>
This is because the shell does not complain about the died-of-SIGPIPE
process, since "died of SIGPIPE
" is quite normal.
For whatever reason, the git
front end is noisier about this died-of-SIGPIPE
case. If you don't use exec
, it is the shell that sees the died-of-SIGPIPE
. The shell absorbs that quietly and exits cleanly and git does not complain. If you do use exec
, the shell is replaced with your program, and the git
front end command sees the died-of-SIGPIPE
status and complains.
One obvious cure is to leave the shell around. Another approach is to get the shell to ignore (not catch) SIGPIPE
, then do the exec
:
trap "" PIPE
As you noted in a comment-reply, catching SIGPIPE
is no good: since exec
replaces the current occupant of the address space, the OS resets all caught signals to their default disposition (which for SIGPIPE
is "die of signal"). However, ignored signals remain ignored.
Depending on your program, this may be as bad or worse. For instance, when cat
dies of SIGPIPE
the shell is silent, but when cat
sees write
fail with EPIPE
it complains:
$ cat book.pdf | :
$ trap "" PIPE
$ cat book.pdf | :
cat: stdout: Broken pipe
(this is on FreeBSD; different OSes vary slightly, depending on how careful and clever their utilities are).