如何在裸git仓库中获得最后收到的分支?

时间:2014-12-10 18:22:35

标签: git

我在登台服务器上有一个简单的repo设置。我从那里开始,开发,然后推回到远程仓库,我有一个post-receive hook设置,用git --work-tree=/server/document/root --git-dir=/path/to/repo checkout -f检查到staging服务器DocumentRoot的repo。但是,总是检查主分支。理想情况下,我希望能够在最后收到的分支或最近更新的分支上进行钩子检查,因为在我对我的更改感到满意并且他们已经过检查之前我不想与master合并。登台服务器。这是可能的,如果是这样的话?

1 个答案:

答案 0 :(得分:3)

这里有一个问题,因为"最后收到的概念"或者"最后更新"没有很好的定义。

让我们假设这个回购通过push更新(可能是一个安全的假设)。现在假设两个不同的push - 大约在同一时间开始git push,一个在上午10:01开始,一个在上午10:02。人员A,从10:01开始,将更新推送到分支A1A2(两者都包含在一次推送中)。人员B,从10:02开始,将更新推送到分支B(仅更典型的单分支推送)。

然而,人员A处于一个缓慢的网络上,他上传时需要花费几分钟来实际完成并且他的提议更新分支A1A2才能完成,所以在接收方面,这发生在上午10:03。 B人在快速网络上,他的推送建议在10:02开始完成。

您的repo脚本检查提案并确定它们是允许的,因此分支B在10:02更新。因此,您可以部署分支B,这很容易。

然后,人A的推动最终完成,分支A1A2在10:03同时更新。你现在部署哪个分支?

此外,B人的推送命令是否比人A更晚发起是否重要?


一旦你找到了这个问题的答案,实际部署一个特定的分支很容易:只需让你的钩子检查出那个特定的分支,而不是让repo只使用HEAD分支(这是通常master:一个裸的回购仍然有一个HEAD,它通常从未被触及过。 (请注意,git将尝试通过索引优化结帐过程。根据许多其他事情,您可能需要调整或失败。请注意,检出特定的命名分支将更改HEAD,除非您使用避免更改HEAD的语法。)

好的,那怎么样?

当然,在钩子中,让我们通过钩子

当客户端执行推送时,服务器上运行三个挂钩:

  • 预接收
  • 更新
  • 后接收

其中每一个都有不同的用途,但实际上只有两个必要。首先,客户端上传所有内容(所有提交以及所需的任何树和blob对象)。然后:

  1. 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;等等。

    如果预接收挂钩拒绝推送,则通知客户端完全拒绝推送,此时整个停止。 (要拒绝,只需以非零状态退出;接受,退出时为零状态。)

  2. git调用update挂钩,每个要更新的ref-name调用一次,传递ref-name,旧的SHA-1和新的​​SHA-1。更新挂钩应决定是接受还是拒绝此特定更改。

    如果更新挂钩拒绝更改,则会通知客户端一个引用更新被拒绝,但推送继续尝试其余更改。

  3. 现在所有引用都已单独更新或拒绝,git运行post-receive挂钩。这个钩子获得与预接收钩子相同的输入(在stdin上)。

    由于所有更新都已完成,因此该钩子通常是部署新版本的好地方。

    请注意,post-receive挂钩无法停止任何更新,但是由于git中的一个小错误,如果它退出非零,则会通知客户端推送失败(至少对于某些版本的git),所以应该退出零以避免惊讶。

  4. 那么哪个钩子记录和哪个钩子部署?

    这部分由您决定。收件后挂钩通常是正确的位置,但你可以在任何你喜欢的地方做到这一点。

    如果您选择在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),因为您无法检查不再存在的分支

    有很多部署脚本在那里,质量各异。抓住一些,戳穿它们,记住上面的注意事项。