部署命令无法正常工作的post-receive hook

时间:2015-09-17 09:28:44

标签: git bash version-control hook

我在遥控器上有一个git,并添加了一个post-receive钩子。收件后挂钩应该执行以下操作。

如果提交消息中存在[composer],请执行作曲家更新
如果提交消息中存在[deploy],请检查已推送的分支(例如feature/testmaster等。)
如果提交消息中存在[migrate],请执行php artisan migrate

不幸的是,这不起作用。调用钩子,但操作错误"。

这是脚本

#!/bin/sh
MESSAGE=$(git log -1 HEAD --pretty=format:%s)

if [[ "$MESSAGE" == *\[composer\]* ]]; then
    composer --working-dir=/var/www/feedev/ update
fi

if [[ "$MESSAGE" == *\[deploy\]* ]]; then
    while read oldrev newrev ref
do
    branch=`echo $ref | cut -d/ -f3`
    git --work-tree=/var/www/feeddev/ --git-dir=/home/feeddev/staging.git checkout -f $branch
done
else
    git --work-tree=/var/www/feedev/ --git-dir=/home/feeddev/staging.git checkout -f
fi

if [[ "$MESSAGE" == *\[migrate\]* ]]; then
    php /var/www/feedev/artisan migrate
fi

这不起作用,因为出于测试目的,我添加了这些行

touch /home/ezidev/ezidev.git/$MESSAGE.lock

在读取消息变量之后,如果第二种情况为false,则添加此

touch /home/ezidev/ezidev.git/nodeploy.lock

所以现在我提交,并提交了[deploy]提交消息,但是,没有检出新分支,还生成了两个新文件

touch /home/ezidev/ezidev.git/$MESSAGE.lock生成/home/ezidev/ezidev.git/static.lock

touch /home/ezidev/ezidev.git/nodeploy.lock生成/home/ezidev/ezidev.git/nodeploy.lock

为什么$ MESSAGE = static.lock?我没有把它写入我的提交消息中。可能是什么问题,我该如何解决这个问题?

1 个答案:

答案 0 :(得分:1)

请记住,在git收集新对象并更新了一些引用(例如refs/heads/masterrefs/heads/bra/nch和/或refs/tags/v1.3)之后,会运行post-receive挂钩。 ("引用"是分支,标签,特殊存储引用等的通用名称。通常更新的两个"接收"操作是分支和标记,标记更新通常只是创建新标记。但是,其他更新也是可能的,具体取决于您在预接收和更新挂钩中允许的内容。此外,如果您使用git' s"注意"您将看到以refs/notes/开头的名称。)

考虑到这一点,让我们看一下脚本中的第一个命令:

MESSAGE=$(git log -1 HEAD --pretty=format:%s)

这使用HEADHEAD引用了哪些提交?

这不仅仅是一个修辞问题。 HEAD引用通常是对分支的间接引用:它根据当前签出指定存储库所在的分支" on"。正在运行git checkout $branch会更改HEAD的内容。即使在裸存储库中也是如此:HEAD指的是某个分支,最初是master但是可以更改,并且在您的情况下可能会更改,因为脚本中有一些git checkout命令。 / p>

在我的脚本运行时,我无法知道HEAD中的内容(通常,如果脚本运行,它可能已更改HEAD,因此可能很难甚至不可能找到)。但这将决定检查哪个提交git logHEAD可能包含一个分支名称,分支名称将指示一个特定的提交,这将是git log的(单个)提交使用

现在让我们再次回到post-receive hook实际获得的内容。它在接收到一些对象(甚至数千个提交)并更新一些引用(甚至可能是几十个引用)之后运行。然后,您在一个分支上查看一个提交,这可能是也可能不是许多已更新的分支之一,并使用它来决定如何处理所有许多分支上的许多提交的更新。

这似乎不太可能是正确的。

我无法为你写下你的钩子,但让我们再看一下你已经拥有的部分内容,其中包含一些正确的代码(以及一些iffy-at-best代码)太):

while read oldrev newrev ref
do
    branch=`echo $ref | cut -d/ -f3`
    git --work-tree=/var/www/feeddev/ --git-dir=/home/feeddev/staging.git checkout -f $branch
done

接收后挂钩被告知哪些引用已更新,以及以何种方式更新为标准输入上的一组行。这个while循环读取这些行。这意味着while部分是正确的。

然而,循环中的第一个命令至少在某种程度上被打破了。从stdin读取一行后,$ref将类似refs/heads/masterrefs/heads/bra/nchrefs/tags/v1.3。回声和切割序列只需要取每个的第三个词:masterbrav1.3。第一个是好的:它是全名refs/heads/master的缩写形式,即分支master。第二个不合适:它是分支bra/nch的简短形式的一部分,但它只是部分,它不会工作好。第三种也可能不行:它是名称refs/tags/v1.3的缩写形式,即标记v1.3,但它是标记,而不是分支。似乎有些不同的东西适合于此。

接下来,脚本在阅读后会忽略$oldrev$newrev。这适用于大多数(但不是全部)接收后操作:如果$ref已经存在,$oldrev是它用于指向的SHA-1,$newrev是SHA- 1它现在指向更新后的指向。例如,如果您只是将一些新提交推送到分支feat/ure,以便快速更新分支,$refrefs/heads/feat/ure并使用{ {1}}将为每个新提交获取SHA-1。 (如果它是一个强制推送 - 例如,git rev-list $oldrev..$newrevgit push -f在客户端上 - 某些提交可能会被带走",您可以使用{{找到它们1}}。)

但还有两个案例需要考虑:首先,git push +sha1:refs/heads/feat/ure刚刚创建。这是标签的正常情况,因为标签通常永远不会被更改,只能创建。在这种情况下,git rev-list $newrev..$oldrev将为全零(四十$ref个字符)。在一般情况下,无法找到此引用的提交(如果有的话)(尽管可以使用一些技巧,例如,添加 pre -receive hook禁止无法弄清楚的更新,以便您只留下可处理的特殊情况)。最后一种情况是$oldrev正在被删除,例如,某人从服务器上的裸存储库中运行0以删除$ref。在这种情况下,git push origin :bra/nch将告诉您SHA-1 refs/heads/bra/nch是什么,$oldrev将是特殊的40 refs/heads/bra/nch s" null SHA-1" 。由于它刚被删除,你无法查看该分支。

最后,有一个$newrev指定一个特定的工作树和git目录(后者覆盖在post-receive hook中设置的0)。这些可能是正确的路径,但git checkout -f可能不是分支名称:在我们的示例中,它是$GIT_DIR,然后是$branch,然后是master in通过bra循环,在三次旅行中的每一次转弯。

简而言之(我知道,"太晚了" :-))这个特殊的post-receive钩子是非常严重的缺陷。您需要弄清楚您真正想要处理的案例,并编写一个以运行v1.3循环开始的新案例:

while

在循环内部,检查所有三个变量。针对40 - while s null-SHA1检查while read oldrev newrev ref; do ... done $oldrev,以确定该操作是创建,删除还是更新。然后检查$newrev的第一个组件,找到ref的名称空间;如果它是一个分支,从0开始,您可以剥离$ref部分以获取分支名称;如果它是别的东西,你可以只是refs/heads/循环忽略变化。

如果您要使用refs/heads/去除continue,请务必使用cut,而不仅仅是refs/heads/。 (我更喜欢使用shell的内置功能来剥离字符串,-f3-我自己,但-f3确实有效。)

然后,如果它是分支更新(不是创建,不是删除,只是更新),您可以使用${ref#refs/heads/}来查找添加到该分支的提交。在每个上使用echo ${ref} | cut -d/ -f3-(或者为了效率,git rev-list $oldrev..$newrev - git log将为您运行git log $oldrev..$newrev)以检查其提交主题行和/或提交关键字的邮件正文。适当地采取行动,无论什么"适当的"是,基于每个提交中给出的(可能是多个)关键字在提交和/或分支上。