2

我有三个 git 存储库:

  1. 我的 git 服务器上的一个裸存储库
  2. 我笔记本电脑上的本地存储库(A)(我在这台机器上开发网页。)
  3. 托管服务器上的本地存储库(B)(我将其用作 http 服务器。)

我在裸存储库上设置了一个 post-receive(服务器端挂钩),以使存储库(B)从裸存储库中拉出,并让 git 服务器在我提交并从存储库(A)推送到裸存储库时发送通知电子邮件存储库。我在裸仓库做的post-receive文件如下:

#!/bin/sh
ssh -l MYUSER -i PRIVKEY www.HOSTINGSERVER.com "cd GITDIRECTORY;git pull"
. $(dirname $0)/post-receive-email

而且我还在裸存储库上设置了环境变量:

git config hooks.mailinglist "MyMailAddress"
git config hooks.announcelist "MyMailAddress"
git config hooks.emailprefix "FooBar"
echo FooBar > description

当我提交并推送到裸存储库时,我希望存储库(B)被拉出并且 git 服务器通过 post-receive-email 发送一封通知电子邮件,但是 post-receive 没有按我希望的那样工作。它有存储库(B)拉,但没有让 git 服务器发送任何电子邮件。我在 git 服务器上的日志中没有看到任何电子邮件错误。

当我注释掉 post-receive 的 ssh 部分时,我收到了一封电子邮件。当我注释掉 post-receive-email 部分时,repository(B) 正确提取。当 ssh 部分和 post-receive-email 部分都处于活动状态时,post-receive 只有 repository(B) pull 并且没有发送任何电子邮件。

当 ssh 部分和 post-receive-email 部分同时存在时,我不知道为什么 post-receive 不能按预期工作。

任何提示和评论表示赞赏。先感谢您。

4

1 回答 1

4

TL;DR ssh -n:。

背景事实:

  1. post-receive 挂钩在其标准输入上获取输入。阅读标准输入,您将在每个更新的参考中获得一行,其格式在githooks 文档中描述。

  2. 所有在标准输入上接收输入的 Git 钩子都是在管道上完成的。(我认为这是一个坏主意——他们应该将输入作为在临时文件上打开的文件描述符接收——但这是一场单独的战斗。即使不是这种情况,你仍然需要另一个技巧。)

  3. 读取管道上可用的输入会消耗该输入。读完,就没了。

    (顺便说一句,这就是read内置 shell 效率如此之低的原因:必须一次读取一个字节的输入,因此只read消耗要读取的内容。)

考虑到这一点,请考虑该命令,以及它的文档ssh摘录:

-n从/dev/null     重定向标准输入(实际上,阻止从标准输入读取)。

那么,如果你ssh 没有 -n运行会发生什么?当然,它会读取标准输入。但是......它会读多少好吧,严格来说,这取决于:ssh 运行多个进程和/或线程,如果有大量 stdin 输入并且在远程端运行的命令执行得非常快,则存在竞争,但一般来说, ssh 读取的是所有标准输入。

现在参考背景事实#3,并回答问题:当 ssh 完成时,stdin 上还剩下什么?

现在,想想你发送电子邮件的 post-receive 钩子是做什么的。它必须,必须,阅读它的标准输入,看看哪些引用被更新了。它将在其标准输入上获得什么数据?

如果您阻止ssh读取(并因此消耗)所有输入,则 post-receive 挂钩将能够读取(并消耗,但现在不再重要)所有输入,因此可以正常运行。

于 2017-12-23T20:02:15.997 回答