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