git push
命令内容呢?例如,当我运行git push origin master
时,将会执行pre-push钩子。我想在这个钩子中获取origin
和master
,该怎么做呢? 我应该如何获取参数列表呢?您的钩子脚本(假设是sh/bash)应该包含以下形式的循环:
while read localname localhash remotename remotehash; do
... code here using $localname etc ...
done
所有Git钩子的说明都在githooks页面中。 pre-push
钩子的说明如下:
This hook is called by git push and can be used to prevent a push from taking place. The hook is called with two parameters which provide the name and location of the destination remote, if a named remote is not being used both values will be the same.
Information about what is to be pushed is provided on the hook’s standard input with lines of the form:
<local ref> SP <local sha1> SP <remote ref> SP <remote sha1> LF
For instance, if the command
git push origin master:foreign
were run the hook would receive a line like the following:refs/heads/master 67890 refs/heads/foreign 12345
although the full, 40-character SHA-1s would be supplied. ...
第一个段落的意思是,在一个shell脚本中,$1
和$2
分别代表远程仓库的名称(例如origin
)以及其URL,或者如果用户运行了$ git remote add <name> <url>
命令,$1
和$2
则表示URL重复两次。
git push https://some.host.name/some/path ...
第二段是重要的内容。 git push
命令可以推送一个以上的分支。例如,我可以运行:
git push origin feature-A feature-B
需要同时推送feature-A
和feature-B
。必须逐行阅读所有输入行,以发现要推送的内容。仓库中的当前分支并不重要:读取HEAD
将得到错误的答案,除非用户恰好正在推送当前分支。另一方面,大多数用户大多只推送当前分支。这会让你产生你的钩子是100%可靠的错觉,实际上它只有92.37%的可靠性。1
正如文档所述,钩子获取每个引用的完整名称。如果你在推送一个分支,那么该完整名称以refs/heads/
开头,但你也可以推送一个标记,在这种情况下,完整名称以refs/tags/
开头。为编写可靠的钩子,你必须检查完整名称,而不仅仅是删除前两个组件。2
1像38.61%的统计数据一样,这个是临时捏造的。:-)
2有很多糟糕的示例钩子(不是所有都是预提交钩子),它们使用了:
branch=$(echo $ref | cut -d/ -f3)
如果你正在推送标签v2.3
,这个钩子会认为你正在推送一个名为v2.3
的分支。如果你正在推送名为bugfix/1234
的分支,它会认为你正在推送一个名为bugfix
的分支!使用cut
技术是错误的,但后者的快速解决方法是使用-f3-
,至少可以生成bugfix/1234
。最好验证引用的前几个组件,例如:
case $ref in
refs/heads/*) ... it's a branch ...;;
refs/tags/*) ... it's a tag ...;;
*) ... it's something else entirely, such as refs/notes/* ...;;
esac
一旦你知道前缀,你可以使用${ref#refs/heads/}
或${ref#refs/tags/}
来去掉已知的前缀并获取完整但未限定的分支或标签名称。然而,在许多情况下,你可以直接使用完整的引用名称。
这些参数被传递到钩子中
在钩子中,您可以通过以下方式获取分支名称:
branch=$(git symbolic-ref HEAD | sed -e 's,.*/\(.*\),\1,')
# get the name of the tracking branches
git branch -a -vv
# or:
git status -b --porcelain
# to get the name of the current branch:
git symbolic-ref -q HEAD
pre-push
钩子?git push --no-verify
git status -b --short
而不是git status -b --porcelain
。如果启用了color.status
配置(默认),它以更易读的方式提供相同的信息。porcelain
选项默认禁用颜色。 - clickMe--porcelain
用于脚本,其中颜色会妨碍脚本解释输出。--short
用于人类消费,其中颜色很有用,除非你是色盲 :-) - toreksed
命令返回错误结果。最好使用git rev-parse --abbrev-ref HEAD
直接获取当前分支名称(不带“refs/heads”前缀),避免进行此类操作。 - Mark Amery