24.1 pre-push(推送前钩子)
从 Git 1.8.2 版本开始可用。
版本 ≥ 1.8
推送前钩子可用于阻止推送操作。这在以下情况下很有用:阻止意外手动向特定分支推送,或在建立的检查失败时阻止推送(单元测试、语法检查)。
创建推送前钩子的方法很简单:在 .git/hooks/ 目录下创建一个名为 pre-push 的文件,并确保该文件具有可执行权限:chmod +x ./git/hooks/pre-push。
以下是一个由 Hannah Wolfe 提供的示例,用于阻止向 master 分支推送:
#!/bin/bash
protected_branch='master'
current_branch=$(git symbolic-ref HEAD | sed -e 's,.*/\(.*\),\1,')
if [ "$protected_branch" = "$current_branch" ]; then
read -p "You're about to push master, is that what you intended? [y|n] " -n 1 -r < /dev/tty
echo
if echo "$REPLY" | grep -E '^[Yy]$' > /dev/null; then
exit 0 # 推送将执行
fi
exit 1 # 推送将不执行
else
exit 0 # 推送将执行
fi
以下是一个由 Volkan Unsal 提供的示例,用于在推送前确保 RSpec 测试通过:
#!/usr/bin/env ruby
require 'pty'
html_path = "rspec_results.html"
begin
PTY.spawn("rspec spec --format h > rspec_results.html") do |stdin, stdout, pid|
begin
stdin.each { |line| print line }
rescue Errno::EIO
end
end
rescue PTY::ChildExited
puts "Child process exit!"
end
# 检查是否有错误
html = open(html_path).read
examples = html.match(/(\d+) examples/)[0].to_i rescue 0
errors = html.match(/(\d+) errors/)[0].to_i rescue 0
if errors == 0 then
errors = html.match(/(\d+) failure/)[0].to_i rescue 0
end
pending = html.match(/(\d+) pending/)[0].to_i rescue 0
if errors.zero?
puts "0 failed! #{examples} run, #{pending} pending"
# 测试成功时的 HTML 输出:
# puts "View spec results at #{File.expand_path(html_path)}"
sleep 1
exit 0
else
puts "\aCOMMIT FAILED!!"
puts "View your rspec results at #{File.expand_path(html_path)}"
puts
puts "#{errors} failed! #{examples} run, #{pending} pending"
# 测试失败时的 HTML 输出:
# `open #{html_path}`
exit 1
end
正如你所看到的,有多种可能性,但核心部分是如果一切顺利则退出 0,如果有问题则退出 1。任何时候退出 1,推送将被阻止,你的代码将保持在运行 git push 之前的状态。
使用客户端钩子时,请记住,用户可以通过在推送时使用 --no-verify 选项来跳过所有客户端钩子。如果你依赖钩子来强制执行流程,可能会遇到问题。
文档:https://git-scm.com/docs/githooks#_pre_push
官方示例:https://github.com/git/git/blob/87c86dd14abe8db7d00b0df5661ef8cf147a72a3/templates/hooks--pre-push.sample
24.2 提交前验证 Maven 构建(或其他构建系统)
.git/hooks/pre-commit
#!/bin/sh
if [ -s pom.xml ]; then
echo "Running mvn verify"
mvn clean verify
if [ $? -ne 0 ]; then
echo "Maven build failed"
exit 1
fi
fi
24.3 自动将某些推送转发到其他仓库
$ cat .git/hooks/post-receive
#!/bin/bash
IFS=' '
while read local_ref local_sha remote_ref remote_sha
do
echo "$remote_ref" | egrep '^refs/heads/[A-Z]+-[0-9]+$' >/dev/null && {
ref=`echo $remote_ref | sed -e 's/^refs/heads\///'`
echo Forwarding feature branch to other repository: $ref
git push -q --force other_repos $ref
}
done
在此示例中,egrep 正则表达式用于查找特定的分支格式(这里:JIRA-12345,用于命名 Jira 问题)。如果你希望转发所有分支,可以省略这部分内容。
24.4 commit-msg(提交消息钩子)
此钩子与 prepare-commit-msg 钩子类似,但它是在用户输入提交消息后而不是之前调用的。这通常用于警告开发人员如果他们的提交消息格式不正确。
此钩子仅接受一个参数:包含消息的文件的名称。如果你不喜欢用户输入的消息,可以像 prepare-commit-msg 那样直接修改该文件,或者通过退出非零状态来完全取消提交。
以下示例用于检查提交消息中是否包含以单词 ticket 开头并跟有数字的内容:
word="ticket [0-9]"
isPresent=$(grep -Eoh "$word" $1)
if [[ -z $isPresent ]]; then
echo "Commit message KO, $word is missing"; exit 1;
else
echo "Commit message OK"; exit 0;
fi
24.5 本地钩子
本地钩子仅影响它们所在的本地仓库。每个开发人员都可以更改自己的本地钩子,因此它们不能可靠地用于强制执行提交策略。它们旨在使开发人员更容易遵循某些准则并避免未来的潜在问题。
有六种类型的本地钩子:pre-commit、prepare-commit-msg、commit-msg、post-commit、post-checkout 和 pre-rebase。
前四个钩子与提交相关,允许你在提交生命周期的每个部分中进行一些控制。最后两个钩子用于在执行 git checkout 和 git rebase 命令时执行一些额外操作或安全检查。
所有“pre-”钩子都可以更改即将进行的操作,而“post-”钩子主要用于通知。
24.6 post-checkout(检出后钩子)
此钩子与 post-commit 钩子类似,但它在每次成功检出引用时调用。这可以是一个有用的工具,用于清除工作目录中的自动生成文件,否则这些文件可能会引起混淆。
此钩子接受三个参数:
- 前一个
HEAD的引用。 - 新的
HEAD的引用。 - 标志,指示是分支检出还是文件检出(分别为 1 和 0)。
其退出状态不会影响 git checkout 命令。
24.7 post-commit(提交后钩子)
此钩子在 commit-msg 钩子之后立即调用。它不能更改 git commit 操作的结果,因此主要用于通知目的。
此脚本不接受任何参数,其退出状态不会以任何方式影响提交。
24.8 post-receive(推送后钩子)
此钩子在推送操作成功后调用。通常用于通知目的。
此脚本不接受任何参数,但会通过标准输入接收与 pre-receive 相同的信息:
<old-value> <new-value> <ref-name>
24.9 pre-commit(提交前钩子)
此钩子在每次运行 git commit 时执行,用于验证即将提交的内容。你可以使用此钩子检查即将提交的快照。
此类型的钩子可用于运行自动化测试,以确保即将提交的更改不会破坏项目现有功能。此类型的钩子还可以检查空白字符或行尾错误。
不向 pre-commit 脚本传递任何参数,退出非零状态将取消整个提交。
24.10 prepare-commit-msg(准备提交消息钩子)
此钩子在 pre-commit 钩子之后调用,用于在文本编辑器中填充提交消息。这通常用于修改自动生成的提交消息,例如合并提交或拆分提交。
此钩子接受一到三个参数:
- 包含消息的临时文件的名称。
- 提交类型,可以是:
message(使用-m或-F选项),template(使用-t选项),merge(如果是合并提交),squash(如果是拆分其他提交)。
- 相关提交的 SHA1 哈希值。仅在使用
-c、-C或--amend选项时提供。
与 pre-commit 类似,退出非零状态将取消提交。
24.11 pre-rebase(变基前钩子)
此钩子在 git rebase 开始更改代码结构之前调用。通常用于确保变基操作是适当的。
此钩子接受两个参数:
- 系列分支是从哪个上游分支分叉的。
- 正在变基的分支(如果变基当前分支,则为空)。
你可以通过退出非零状态来取消变基操作。
24.12 pre-receive(推送前钩子)
此钩子每次有人使用 git push 将提交推送到仓库时执行。它始终位于推送的目标远程仓库中,而不是起始(本地)仓库。
钩子在任何引用更新之前运行。通常用于强制执行任何类型的开发策略。
此脚本不接受任何参数,但每个被推送的引用都会通过标准输入传递给脚本,每行一个,格式如下:
<old-value> <new-value> <ref-name>
24.13 update(更新钩子)
此钩子在 pre-receive 之后调用,与 pre-receive 的工作方式相同。它在实际更新之前被调用,但与 pre-receive 不同,它为每个被推送的引用单独调用,而不是一次性处理所有引用。
此钩子接受以下三个参数:
- 正在更新的引用的名称。
- 存储在引用中的旧对象名称。
- 存储在引用中的新对象名称。
此信息与传递给 pre-receive 的相同,但由于 update 是为每个引用单独调用的,你可以拒绝某些引用,同时允许其他引用。