11

我想自动将 post-receive 钩子中的提交从我们 LAN 上的中央仓库推送到云中的另一个中央仓库。LAN 存储库是使用git clone --mirror git@cloud:/path/to/repo或等效命令创建的。

因为提交的文件相对于我们的上游带宽来说会很大,所以完全有可能发生这样的事情:

  1. Alice 发起对 LAN 存储库的推送。
  2. 当 post-receive 钩子运行时,Bill 从 LAN 存储库中提取。
    • LAN 存储库正在推送到云存储库。
    • 这也意味着 Bill 的本地仓库包含 Alice 推送的提交。通过测试确认。
  3. Bill 启动了对 LAN 存储库的推送。
    • Bill 的推送是 Alice 推送的快进,因此 LAN repo 将接受它。

当 LAN repo 的 post-receive 钩子执行时,将启动从 LAN repo 到云 repo 的第二次推送,并且两者将同时运行。

我不担心 git 对象。最坏的情况是两个推送都从 Alice 的推送中上传所有对象,但据我了解 git 的内部结构,这无关紧要。

我担心裁判。假设 Alice 使用慢得多的连接进行推送,因此 Bill 的推送首先完成。假设数据包丢失或其他原因导致钩子从 LAN 存储库推送到 Bill 的推送云之前完成,然后钩子从 LAN 存储库推送到 Alice 的推送云。如果 Alice 和 Bill 都在推送 master 分支并且 Bill 的推送首先完成,那么 master ref 在云存储库上会是什么?我希望它是 Bill 的 HEAD,因为那是后来的推送,但我担心它会是 Alice 的 HEAD。

进一步澄清:

我意识到如果 Bill 从他的机器推送到 LAN 存储库首先完成,Alice 从她的机器到 LAN 存储库的推送将失败。在这种情况下,LAN repo 的 post-receive 钩子将不会执行。此外,请假设没有人会强制推送,所以如果 post-receive 钩子在 LAN repo 上运行,所有 ref 更改都是快进的。

4

2 回答 2

4

如果 Bill 的推送首先完成,Alice 的推送将失败,因为在更新 ref 之前 git 确保 repo 的 ref 仍然与以前相同。在这种情况下,它不会。Alice 最终会看到错误消息并需要解决问题。在反之亦然的情况下,比尔也是如此。因此,在您的 post-receive 挂钩中,您必须确保 repo 的原始引用和新引用现在不同。如果没有,那么根本不要推送到新的 repo 以节省一些工作。

不过,我仍然在您的场景中看到了一个问题,这与推送到云端有关。将两个有效的引用推到云位置的钩子可能会遇到相同的问题。除了现在,如果第一次失败,您将不知道是否需要推送到脚本中的 repo,因为您不知道失败的 ref 是比推送的更旧还是更新……特别是如果它们不简单快进可能不时发生。如果您只是强制推送,那么无论发生什么,云都会有一个 OLD ref,直到另一个钩子稍后再推送其他东西。在 Alice 的情况下,他将合并来自上游或任何数量的其他解决方案的更改,但脚本可能不应该具有这样的决策能力。

在钩子中,您可能能够在当前存储库上执行一些脚本魔术来确定时间戳等,并且仅在有快进时才推送,但这似乎很混乱,而且很可能还是需要合并。我认为比使用 post-receive 钩子更好的解决方案是每五分钟(或者无论你想要多么频繁)使用一个 cron 或计划任务,它只需在远程镜像的 master 分支上运行一个 git pull 。如果您无权访问该存储库,则可以使用 cron 作业从 LAN 存储库强制推送。我认为这比钩子更安全,也更简单。这将确保备份云上的分支每隔几分钟总是在正确的位置,并且不会冒险推送旧的 ref 并且在用户再次推送之前永远不会获得最新的 ref,就像 hook 所做的那样。

于 2011-12-08T16:18:34.867 回答
3

Git 2.4+(2015 年第 2 季度)将引入atomic pushs,这将使服务器更容易管理推送顺序。参见Stefan Beller ( )
所做的工作:stefanbeller

这增加了对 atomic push 选项的测试。
前四个测试检查 atomic 选项是否在良好的条件下工作,最后三个补丁检查 atomic 选项是否阻止在只有一个 ref 无法更新的情况下推送任何更改。

如果可用,请在远程端使用原子事务。
要么更新所有 refs,要么在错误时不更新 refs。
如果服务器不支持原子推送,推送将失败。

这增加了对 send-pack 的支持,以便在服务器支持的情况下协商和使用原子推送。原子推送由新的命令行标志激活--atomic

这添加了原子协议选项,以允许receive-pack通知客户端它具有原子推送功能
此提交使先前提交中引入的功能在服务端生效。
文档中的更改反映了服务器的协议功能。

   atomic
   ------

如果服务器发送 ' atomic' 能力,它就能够接受原子推送。
如果推送客户端请求此功能,服务器将在一个原子事务中更新 refs。
要么所有参考都更新,要么没有。


使用 Git 2.29(2020 年第四季度) ,想要成为原子并想要发送推送证书的“ git pushman学会了在本地检查失败时不准备和签署推送证书(因此由于原子性,众所周知没有证书需要)。

参见韩信 ( ) 的commit a4f324a (19 Sep 2020 )(由Junio C Hamano 合并 -- --提交 b5847b9中,2020 年 9 月 25 日)chiyutianyi
gitster

send-pack: 在原子推送检查后运行 GPG

签字人:韩信

refs 更新命令可以通过两种不同的方式发送到服务器端:GPG 签名或未签名。
我们应该在同一个“最后,告诉另一端!”中运行这两个操作。代码块,但它们由“清除每个参考的状态”代码块分隔。
这将导致轻微的性能损失,因为失败的原子推送仍然会为浅广告和 GPG 签名的命令缓冲区执行不必要的准备,并且当没有要签名的内容时,用户可能不得不被(可能的)GPG 密码输入所困扰.

在 t5534 中添加一个新的测试用例,以确保 GPG 签名的原子推送失败时不会调用 GPG。

于 2015-02-15T04:39:24.293 回答