【发布时间】:2015-05-03 11:54:54
【问题描述】:
我正在使用 Ruby。我试图弄清楚为什么捆绑器的rake release 挂在git push 步骤上,还有discussed inconclusively here。
我已经把它缩小到这行代码挂起:
`git push 2>&1`
我可以通过在 IRB 中运行同一行代码来重现该问题。
神秘的是,底层的git push 确实执行了,但由于某种原因,Ruby 从未收到返回状态。它只是无限期地等待子进程。
检查进程列表显示子进程具有Z+(僵尸?)状态:
UID PID PPID C STIME TTY TIME CMD USER PGID SESS JOBC STAT TT
501 23397 3757 0 1:44PM ttys001 0:00.54 irb mbrictson 23397 0 1 S+ s001
501 26035 23397 0 2:06PM ttys001 0:00.00 (sh) mbrictson 23397 0 1 Z+ s001
显然,git push 运行只是在我的 shell 中找到。只是当它通过 Ruby 使用反引号调用时才会挂起。
另外,这很好用:
system("git push 2>&1") # => true
这(即没有输出重定向)也可以正常工作!
`git push` # => "Everything up-to-date"
部分问题显然是我的~/.ssh/config 中的ControlMaster auto。当执行git push 时,这会导致在后台产生一个新的控制连接进程。也许%x(git push 2>&1) 正在等待这个后台进程退出?如果我在 SSH 配置中禁用 ControlMaster,这实际上可以解决问题。
不过,这让我很困扰。我宁愿不必为了让 Ruby 的反引号操作符高兴而禁用 ControlMaster。
谁能解释一下:
- 为什么
%x()挂起,而system()没有? - 为什么删除
2>&1会有所不同?
这是在带有 Ruby 2.2.0 的 Mac OS X Yosemite 上。
【问题讨论】:
-
%x版本捕获输出,system版本不捕获。我不确定这是否会影响git,它可能会因某种原因提出阻碍流程的问题。如果您想知道发生了什么,最好使用popen3以获得最大控制权。 -
命令运行时git有没有事有关系吗?
-
@EtanReisner 它似乎与 git 正在做的事情没有任何关系。当有要推送的提交并且所有内容都是最新的时,我会看到问题。
-
ssh 进程的 fd 在挂起时是什么样子的?在等待输出时,额外的过程可能会混淆反引号(正如 tadman 指出的那样,
system不会等待)。 -
@tadman 我不认为 git 在问问题;就像我说的,删除
ControlMaster似乎是决定因素。出于好奇,我希望找出根本原因。如果是常见问题,也许bundler会接受一个PR来切换到popen3。