我怎样才能在一个简单的git回购中获得最后收到的分支?

我怎样才能在一个简单的git回购中获得最后收到的分支?,git,Git,我在临时服务器上有一个裸机回购设置。我从那里拉,开发,然后推回到远程repo,我有一个post-receive钩子设置,可以使用git--work tree=/server/document/root--git dir=/path/to/repo checkout-f将repo签出到临时服务器DocumentRoot。但是,它总是检查主分支。理想情况下,我希望能够让钩子签出最后收到的分支,或者最近更新的分支,因为我不希望与master合并,直到我对我的更改感到满意,并且它们已经在staging服

我在临时服务器上有一个裸机回购设置。我从那里拉,开发,然后推回到远程repo,我有一个post-receive钩子设置,可以使用
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