我怎样才能在一个简单的git回购中获得最后收到的分支?
我在临时服务器上有一个裸机回购设置。我从那里拉,开发,然后推回到远程repo,我有一个post-receive钩子设置,可以使用我怎样才能在一个简单的git回购中获得最后收到的分支?,git,Git,我在临时服务器上有一个裸机回购设置。我从那里拉,开发,然后推回到远程repo,我有一个post-receive钩子设置,可以使用git--work tree=/server/document/root--git dir=/path/to/repo checkout-f将repo签出到临时服务器DocumentRoot。但是,它总是检查主分支。理想情况下,我希望能够让钩子签出最后收到的分支,或者最近更新的分支,因为我不希望与master合并,直到我对我的更改感到满意,并且它们已经在staging服
git--work tree=/server/document/root--git dir=/path/to/repo checkout-f
将repo签出到临时服务器DocumentRoot。但是,它总是检查主分支。理想情况下,我希望能够让钩子签出最后收到的分支,或者最近更新的分支,因为我不希望与master合并,直到我对我的更改感到满意,并且它们已经在staging服务器上被检查。这可能吗?如果可能,又是如何实现的?这里有一个问题,因为“上次接收”或“上次更新”的概念没有得到很好的定义
让我们假设此回购协议是通过推送更新的(可能是一个安全的假设)。现在假设两个不同的push
-er大约同时启动git push
,一个在上午10:01,另一个在上午10:02。人员A从10:01开始将更新推送到分支机构A1
和A2
(两个分支都包含在一次推送中)。人员B从10:02开始,将更新推送到分支B
(仅适用于更典型的单分支推送)
然而,A个人的网络速度很慢,他需要几分钟才能完成上传,他更新分支机构A1
和A2
的建议也需要几分钟才能完成,因此在接收端,这发生在上午10:03。人员B在快速网络上,他的推送计划在10:02开始并完成
您的回购脚本将检查这些建议并确定它们是允许的,因此分支机构B
将在10:02更新。因此,您将部署分支B
,这非常简单
然后,人员A的推送最终成功,分支A1
和A2
在10:03同时更新。您现在部署哪个分支
此外,人员B的推送命令比人员A的推送命令晚启动是否重要
一旦你找到了这个问题的答案,实际上部署一个特定的分支就足够容易了:让你的钩子检查这个特定的分支,而不是让回购只使用头分支(通常是master
:裸回购仍有头部
,通常从未触及)。(请注意,git将尝试通过索引优化签出过程。根据许多其他情况,您可能希望调整或取消此操作。另外请注意,签出特定命名分支将更改HEAD
,除非您使用避免更改HEAD
的语法)
好吧,那怎么办?
当然是在钩子里,但是让我们穿过钩子
当客户端执行推送时,服务器上运行三个钩子:
- 预收
- 更新
- 后接
其中每一个都有一些不同的目的,但实际上只需要两个。首先,客户端上载所有内容(所有提交以及所需的任何树和blob对象)。然后:
git调用pre-receive
hook,在stdin上为其提供一系列行。每行有两个SHA-1值(当前又名“old”,以及建议的替换或“new”)和一个ref名称。新旧SHA-1值中的任何一个(但不是全部)都可以为零,表示正在创建(以前不存在)或删除ref(如果允许推送,则不存在)。预接收挂钩应读取所有行,检查每个参考名称和每个提供的SHA-1,并决定整个推送是接受还是拒绝
注意,ref名称总是完全限定的:像dev/joe
这样的分支是refs/heads/dev/joe
;像v1.2
这样的标记是refs/tags/v1.2
;依此类推
如果预接收钩子拒绝推送,则会通知客户端推送已被完全拒绝,并且整个过程在此点停止。(要拒绝,只需以非零状态退出;要接受,以零状态退出。)
git调用update
hook,每个要更新的ref名称调用一次,并将ref名称、旧的SHA-1和新的SHA-1传递给它。更新hook应该决定接受还是拒绝这个特定的更改
如果更新钩子拒绝了更改,客户端将被告知一个引用更新被拒绝,但推送将继续尝试其余的更改
现在所有的引用都被单独更新或拒绝,git运行post-receive
钩子。这个钩子获得与pre-receive钩子相同的输入(在stdin上)
因为所有的更新都完成了,所以这个钩子通常是部署新版本的好地方
请注意,post-receive钩子无法停止任何更新,但由于git中存在一个小错误,如果它退出非零,则会通知客户端推送失败(至少在某些git版本中是如此),因此它应该退出零以避免惊讶
那么,哪个钩子记录和部署了哪个钩子?
这部分取决于你。后接收挂钩通常是正确的位置,但你可以在任何你喜欢的地方这样做
如果您选择在post receive钩子中进行部署,但在早期钩子中做出决策,则需要记录决策。记录决策的位置取决于您自己。如果您在选择部署内容的同一位置进行部署,则不必记录决策,因为相同的代码位同时执行这两项任务,因此它可以请记住
至于如何实现部署,一个非常简单的方法是删除目标工作树,然后使用使用特定提交的文件覆盖工作树的表单执行git签出
。假设分支refs/heads/B
更新为提交1234567
rm -rf /server/document/root &&
mkdir /server/document/root &&
git --work-tree=/server/document/root checkout -f B -- .
行
git --work-tree=/server/document/root checkout -f B
while read oldsha newsha ref; do
case "$ref" in
refs/heads/*)
branch=${ref#refs/heads/}
reftype=branch;;
*)
reftype=unknown;;
esac
done