我在 WSL2 下的 Debian 中工作,但由于我的项目文件位于 Windows 文件系统中,因此我一直通过 WSL 互操作使用 Git for Windows,其 shell 函数如下:
git() {
case "$PWD" in
/mnt/*)
/mnt/c/Program\ Files/Git/bin/git.exe "$@"
;;
*)
/usr/bin/git "$@"
;;
esac
}
一般来说,这种方法效果很好,而且可以快速完成工作(比 git 从 VM 内部访问 repo 中的每个文件要快得多)。
但是,我注意到,很多时候,它最终会留下杂散的 git 进程。在我的 git 命令运行完毕后,仍然有大量进程git.exe
停留在那里,有时仍然持有打开的文件句柄,但实际上什么也没做。
它有时会导致后续 git 命令的执行速度明显变慢、工作树中的文件被阻塞,并且可能最终导致 repo 损坏。
我已经确定,这种情况大多发生在我将 git 命令的长输出通过管道传输到WSLless
或head
在 WSL 中时,例如
git log | less
git log | head -n 64
并非所有管道都像这样运行 — — 例如,管道到cat
、nano -
或确实可以tail
正确终止 git.exe。
是什么原因导致的?有没有办法解决?
git version 2.33.0.windows.2
答案1
这可能是由于 Windows 和 Unix 上的信号处理不同。
在 Unix 上,当管道右侧的进程(例如less
)退出时,左侧的进程会收到 SIGPIPE 信号,或者,如果左侧进程阻塞了它,则在尝试再次写入管道时会收到 EPIPE 错误。通常,该信号会终止进程并阻止其产生更多输出。
但是,Windows 没有此功能或 SIGPIPE,因此进程不会终止,直到它完成写入数据或出现错误。您会注意到,不会导致进程挂起的命令会读取所有输入,而会导致进程挂起的命令则不会。
如果您要在 WSL 下使用程序,则应避免以这种方式使用 Git for Windows,因为它无法接收 SIGPIPE 并退出。