我在遥控器上有一个git,并添加了一个post-receive钩子。收件后挂钩应该执行以下操作。
如果提交消息中存在[composer]
,请执行作曲家更新
如果提交消息中存在[deploy]
,请检查已推送的分支(例如feature/test
,master
等。)
如果提交消息中存在[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?我没有把它写入我的提交消息中。可能是什么问题,我该如何解决这个问题?
答案 0 :(得分:1)
请记住,在git收集新对象并更新了一些引用(例如refs/heads/master
,refs/heads/bra/nch
和/或refs/tags/v1.3
)之后,会运行post-receive挂钩。 ("引用"是分支,标签,特殊存储引用等的通用名称。通常更新的两个"接收"操作是分支和标记,标记更新通常只是创建新标记。但是,其他更新也是可能的,具体取决于您在预接收和更新挂钩中允许的内容。此外,如果您使用git' s"注意"您将看到以refs/notes/
开头的名称。)
考虑到这一点,让我们看一下脚本中的第一个命令:
MESSAGE=$(git log -1 HEAD --pretty=format:%s)
这使用HEAD
。 HEAD
引用了哪些提交?
这不仅仅是一个修辞问题。 HEAD
引用通常是对分支的间接引用:它根据当前签出指定存储库所在的分支" on"。正在运行git checkout $branch
会更改HEAD
的内容。即使在裸存储库中也是如此:HEAD
指的是某个分支,最初是master
但是可以更改,并且在您的情况下可能会更改,因为脚本中有一些git checkout
命令。 / p>
在我的脚本运行时,我无法知道HEAD
中的内容(通常,如果脚本运行,它可能已更改HEAD
,因此可能很难甚至不可能找到)。但这将决定检查哪个提交git log
:HEAD
可能包含一个分支名称,分支名称将指示一个特定的提交,这将是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/master
,refs/heads/bra/nch
和refs/tags/v1.3
。回声和切割序列只需要取每个的第三个词:master
,bra
和v1.3
。第一个是好的:它是全名refs/heads/master
的缩写形式,即分支master
。第二个不合适:它是分支bra/nch
的简短形式的一部分,但它只是部分,它不会工作好。第三种也可能不行:它是名称refs/tags/v1.3
的缩写形式,即标记v1.3
,但它是标记,而不是分支。似乎有些不同的东西适合于此。
接下来,脚本在阅读后会忽略$oldrev
和$newrev
。这适用于大多数(但不是全部)接收后操作:如果$ref
已经存在,$oldrev
是它用于指向的SHA-1,$newrev
是SHA- 1它现在指向更新后的指向。例如,如果您只是将一些新提交推送到分支feat/ure
,以便快速更新分支,$ref
为refs/heads/feat/ure
并使用{ {1}}将为每个新提交获取SHA-1。 (如果它是一个强制推送 - 例如,git rev-list $oldrev..$newrev
或git 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
)以检查其提交主题行和/或提交关键字的邮件正文。适当地采取行动,无论什么"适当的"是,基于每个提交中给出的(可能是多个)关键字在提交和/或分支上。