理想状态下,我们期望在完成一次主干分支的代码合并后,能够由机器自动的完成所有的上线流程:测试、打包、发布、回归;
进一步的,团队、个人,存在规范约束、质量要求,最好有一个非人工的关卡来进行代码质量的检查,降低人工 review 的成本。
Git hooks 就是一个理想的工具,下面一起来看下如何实现我们期望的效果
什么是 Git Hooks
Git Hooks(钩子)是 Git 在特定的动作发生时,触发的自定义脚本事件 / 任务,若 hook 执行失败,将终止后续操作。根据 hook 执行的位置,可以分为两种类型:
客户端钩子:控制客户端 Git 的提交工作流
pre-commit
: 执行git commit
时触发,可用于检查代码风格;prepare-commit-msg
:commit message
唤起前,默认 commit message 创建后触发;commit-msg
:完成并确认 commit message 后触发;post-commit
:完成git commit
后触发- ...
服务端钩子:在代码推送到服务器之前和之后的策略执行
pre-receive
:服务端收到一个push
操作时触发,可以检查提交内容;update
:与pre-receive
相似,区别是,push 更新多个分支时,pre-receive 执行一次,update
每一个分支都会执行一次;post-receive
:完成push
操作后触发- ...
如何使用 Git Hooks
在本地 Git 代码仓库中,存在一个隐藏目录:.git
,用于保存所有的版本记录、钩子方法等,这里我们关注其中的子目录:hooks
➜ hooks git:(master) ls
applypatch-msg.sample pre-applypatch.sample pre-rebase.sample
commit-msg.sample pre-commit.sample pre-receive.sample
fsmonitor-watchman.sample pre-merge-commit.sample prepare-commit-msg.sample
post-update.sample pre-push.sample update.sample
初始化 Git 的项目里,都会提供多种 Git hooks 的 shell 脚本模版,另外也可以在脚本首行声明、使用 py、node 等脚本语言编写 ,移除 文件 .sample
后缀后,即会生效;
下面举三个例子说明 Git hooks 的应用场景:
早间年的 DIY pre-commit
在使用原始 sass
本地编译的时候,非常容易出现语法错误导致 sass
编译失败、提交代码存在未解决冲突的情况,为了避免代码直接提交上线,导致线上 case,产生了提交前检查代码的想法:devTool
提供了 pre-commit
脚本的一键安装 sh,支持提交前检查
- Merge conflicts, forbidden commit;
- scss compile error, forbidden commit;
- use elementUi, forbidden commit;
vue-cli
初始化的 pre-commit
这里的 yorkie 是尤大 fork 了 husky,进行了部分改写。husky
是用 node 实现的一个快速安装 Git hooks 的工具,可以在package.json
中指定相关钩子执行的npm scripts。
➜ hooks git:(account) cat pre-commit
#!/bin/sh
#yorkie 2.0.0
command_exists () {
command -v "$1" >/dev/null 2>&1
}
has_hook_script () {
[ -f package.json ] && cat package.json | grep -q "\"$1\"[[:space:]]*:"
}
# OS X and Linux only
load_nvm () {
# If nvm is not loaded, load it
command_exists nvm || {
export NVM_DIR="$1"
[ -s "$1/nvm.sh" ] && . "$1/nvm.sh"
}
}
# OS X and Linux only
run_nvm () {
# If nvm has been loaded correctly, use project .nvmrc
command_exists nvm && [ -f .nvmrc ] && nvm use
}
cd "."
# Check if pre-commit is defined, skip if not
has_hook_script pre-commit || exit 0
# Add common path where Node can be found
# Brew standard installation path /usr/local/bin
# Node standard installation path /usr/local
export PATH="$PATH:/usr/local/bin:/usr/local"
# Try to load nvm using path of standard installation
load_nvm /Users/lideguang/.nvm
run_nvm
# Export Git hook params
export GIT_PARAMS="$*"
# Run hook
node "./node_modules/yorkie/src/runner.js" pre-commit || {
echo
echo "pre-commit hook failed (add --no-verify to bypass)"
exit 1
}
服务端自动发布 (未测试)
我们在进行静态博客更新时,往往需要 push 内容更新、登录服务器、pull 更新、重启服务 等一系列操作,才能完成一篇文章的更新,那能不能省掉这些重复操作呢?服务端钩子可以来简化操作:
进入服务器 repo .git/hooks
目录,创建一个文件,名为:post-update
,写入执行脚本,并设置执行权限 chmod +x post-update
!/bin/sh
unset GIT_DIR
NowPath=`pwd`
DeployPath="../../www"
cd $DeployPath
git add . -A && git stash
git pull origin master
echo "your root password" | sudo -S nginx -s reload
cd $NowPath
echo "deploy done"
exit 0
以上是 三个例子来说明如何使用 Git hooks 进行自动化的检查和自动部署,事件和回调可以使用多种脚本语言来进行编写,具有很强的扩展性,将代码检查、消息通知、构建等需要重复性无脑操作的事情,变成自动化的模式。减少人的因素产生的不确定性、提高效率。
你觉着有哪些场景适合做成 钩子函数 呢 ?
参考: