{"thread":{"id":"66268","subject":"[PATCH] git-gui: drain the cat-file pipe before closing it","startedAt":"2026-09-03T16:17:45Z","lastAt":"2026-09-03T18:36:46Z","messageCount":2,"participants":["chib via GitGitGadget","Johannes Sixt"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"551884","messageId":"pull.2216.git.1788452262806.gitgitgadget@gmail.com","threadId":"66268","inReplyTo":null,"subject":"[PATCH] git-gui: drain the cat-file pipe before closing it","fromName":"chib via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-09-03T16:17:42Z","receivedAt":"2026-09-03T16:17:45Z","isPatch":true,"body":"From: chib <chib@foxmail.com>\n\ncommit_committree opens \"git cat-file commit <parent>\" to read the tree\nline for the empty-commit check, reads only the first line, and then\ncloses the pipe while the rest of the commit object (often several\nkilobytes of commit message) is still unread.\n\nOn Linux this is harmless: the child process dies of SIGPIPE when it\nkeeps writing, and that is not reported as an error when the pipe is\nclosed. On Windows there is no SIGPIPE: the native git.exe gets a\nbroken-pipe error when writing and exits with a non-zero status. Tcl's\n[close] then surfaces that as \"child process exited abnormally\", the\ncommit is aborted, and the index lock is released with nothing\ncommitted. The failure only shows up once the parent commit's object is\nlarger than the pipe buffer: in testing with Git for Windows 2.52,\nobjects up to ~6.5 KiB always succeed while objects of ~9 KiB and up\nfail 10 out of 10 times (the threshold is around the 8 KiB pipe\nbuffer). Amending a commit with a long message therefore triggers it\nreliably while short commits slip through. Reading the pipe to EOF\nbefore closing fixes it 10 out of 10 times, and is harmless on POSIX\nplatforms where the same test succeeds either way.\n\nRead the rest of the pipe before closing it, mirroring what the amend\npath already does when loading the parent commit's message.\n\nSigned-off-by: chib <chib@foxmail.com>\n---\n    git-gui: drain the cat-file pipe before closing it\n    \n    commit_committree opens \"git cat-file commit \" to read the tree line for\n    the empty-commit check, reads only the first line, and then closes the\n    pipe while the rest of the commit object (often several kilobytes of\n    commit message) is still unread.\n    \n    On Linux this is harmless: the child process dies of SIGPIPE when it\n    keeps writing, and that is not reported as an error when the pipe is\n    closed. On Windows there is no SIGPIPE: the native git.exe gets a\n    broken-pipe error when writing and exits with a non-zero status. Tcl's\n    [close] then surfaces that as \"child process exited abnormally\", the\n    commit is aborted, and the index lock is released with nothing\n    committed. The failure only shows up once the parent commit's object is\n    larger than the pipe buffer: in testing with Git for Windows 2.52,\n    objects up to ~6.5 KiB always succeed while objects of ~9 KiB and up\n    fail 10 out of 10 times (the threshold is around the 8 KiB pipe buffer).\n    Amending a commit with a long message therefore triggers it reliably\n    while short commits slip through. Reading the pipe to EOF before closing\n    fixes it 10 out of 10 times, and is harmless on POSIX platforms where\n    the same test succeeds either way.\n    \n    Read the rest of the pipe before closing it, mirroring what the amend\n    path already does when loading the parent commit's message.\n\nPublished-As: https://github.com/gitgitgadget/git/releases/tag/pr-2216%2F1dao%2Fgui-drain-catfile-pipe-v1\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-2216/1dao/gui-drain-catfile-pipe-v1\nPull-Request: https://github.com/gitgitgadget/git/pull/2216\n\n lib/commit.tcl | 4 ++++\n 1 file changed, 4 insertions(+)\n\ndiff --git a/lib/commit.tcl b/lib/commit.tcl\nindex 89eb8c7b73..5e5f879f0e 100644\n--- a/lib/commit.tcl\n+++ b/lib/commit.tcl\n@@ -386,6 +386,10 @@ proc commit_committree {fd_wt curHEAD msg_p} {\n \t\tset fd_ot [git_read [list cat-file commit $PARENT]]\n \t\tfconfigure $fd_ot -encoding iso8859-1\n \t\tset old_tree [gets $fd_ot]\n+\t\t# Drain the pipe before closing it: on Windows, closing it\n+\t\t# while git cat-file still has output to write makes the\n+\t\t# child process exit with a failure status.\n+\t\tread $fd_ot\n \t\tclose $fd_ot\n \n \t\tif {[string equal -length 5 {tree } $old_tree]\n\nbase-commit: 5dcb97869546d600a114ef422a135e2e909c923c\n-- \ngitgitgadget\n"},{"id":"551894","messageId":"51211bf8-caa6-4aa4-82fd-c80d9b378ea7@kdbg.org","threadId":"66268","inReplyTo":"pull.2216.git.1788452262806.gitgitgadget@gmail.com","subject":"Re: [PATCH] git-gui: drain the cat-file pipe before closing it","fromName":"Johannes Sixt","fromEmail":"j6t@kdbg.org","sentAt":"2026-09-03T17:49:40Z","receivedAt":"2026-09-03T18:36:46Z","isPatch":true,"body":"Am 03.09.26 um 18:17 schrieb chib via GitGitGadget:\n> From: chib <chib@foxmail.com>\n> \n> commit_committree opens \"git cat-file commit <parent>\" to read the tree\n> line for the empty-commit check, reads only the first line, and then\n> closes the pipe while the rest of the commit object (often several\n> kilobytes of commit message) is still unread.\n> \n> On Linux this is harmless: the child process dies of SIGPIPE when it\n> keeps writing, and that is not reported as an error when the pipe is\n> closed. On Windows there is no SIGPIPE: the native git.exe gets a\n> broken-pipe error when writing and exits with a non-zero status. Tcl's\n> [close] then surfaces that as \"child process exited abnormally\", the\n> commit is aborted, and the index lock is released with nothing\n> committed. The failure only shows up once the parent commit's object is\n> larger than the pipe buffer: in testing with Git for Windows 2.52,\n> objects up to ~6.5 KiB always succeed while objects of ~9 KiB and up\n> fail 10 out of 10 times (the threshold is around the 8 KiB pipe\n> buffer). Amending a commit with a long message therefore triggers it\n> reliably while short commits slip through.\n\nNicely analyzed. While this all sounds sensible, I am unable to\nreproduce the failure on Windows. (But I use my own build, not Git for\nWindows.) I made a tiny change, then inserted a lot of text in the\ncommit message field (18k), and committed. Then I clicked \"Amend Last\nCommit\", changed the commit message slightly, and committed again. No\nerror. Do you have instructions how to reproduce the failure?\n\n> Reading the pipe to EOF\n> before closing fixes it 10 out of 10 times, and is harmless on POSIX\n> platforms where the same test succeeds either way.\n> \n> Read the rest of the pipe before closing it, mirroring what the amend\n> path already does when loading the parent commit's message.\n\nYou can't compare this case with the \"amend\" case, because \"amend\" needs\nthe commit message. The usual way to stop that 'close' complains is to\nwrap it in a 'catch'.\n\n> Signed-off-by: chib <chib@foxmail.com>\nPlease use your full name as author and to sign off, not a nick name.\n\n-- Hannes\n\n"}]}