前言
通常情况下,一个 git 仓库就是一个项目,只需要配置一套 git hooks 脚本就可以执行各种校验任务。对于 monorepo 项目也是如此,monorepo 项目下的多个 packages 之间,它们是有关联的,可以互相引用,所以当成一个项目也没问题。
但是也有一种情况,一个 git 仓库下的多个项目之间是彼此独立的,比如 git 仓库下存在前端项目、后端项目、文档项目等等。这时候就需要为每个项目配置不同的 git hooks 脚本了git安装配置,因为不同的项目有可能校验规则不一样。
本文主要探讨一下如何为不同的项目配置 git hooks 脚本。
PS:配置 git hooks 脚本使用huksy[1]。
方案一:每个项目下都配置一套 git hooks 脚本
假设仓库拥前后端两个项目:
frontend
backend
那么我们需要在每个项目下安装husky,同时要在package.json中配置一下prepare脚本(这里以前端项目为示例):
# package.json
{
"scripts" {
"prepare": "cd .. && husky install frontend/.husky"
}
}
然后按照husky文档创建pre-commit和commit-msg钩子文件:
. "$(dirname -- "$0")/_/husky.sh"
# pre-commit
cd frontend
npx lint-staged
. "$(dirname -- "$0")/_/husky.sh"
# commit-msg
cd frontend
FORCE_COLOR=1 node scripts/verifyCommitMsg.mjs $1
上面展示的是前端项目的 git hooks 创建过程,后端项目按照同样的过程创建即可。目前仓库的目录结构如下:
frontend
.husky
- pre-commit
- commit-msg
backend
.husky
- pre-commit
- commit-msg
运行一段时间后,发现这个方案有问题,那就是每次触发的 git hooks 脚本都是前端项目的,后端项目提交代码根本不触发 git hooks。排查问题后发现是 git 仓库的配置引起的git安装配置,打开.git/config文件:
[core]
hooksPath = frontend/.husky
上面hooksPath路径对应的就是 git hooks 的目录位置,目前 git 只支持指定一个目录作为 git hooks 的位置。所以第一个方案不靠谱,达不到我们想要的效果。
方案二:只在根目录下配置一套 git hooks 脚本
第二个方案是将 git hooks 放在项目根目录下,统一在根目录里执行各个子项目的校验脚本。这个方案有以下几个步骤:
修改 husky 安装位置
在每个项目下安装 husky 时,要把 git hooks 钩子目录设置在根目录:
# package.json
{
"scripts" {
"prepare": "cd .. && husky install .husky" # 放到根目录
}
}
同时.git/config文件也要修改一下:
[core]
hooksPath = .husky # 改为根目录
在 git hooks 中进行各个子项目的校验操作
这里以commit-msg作为示例编写一个脚本:
. "$(dirname -- "$0")/_/husky.sh"
# 拿到所有改动的文件名
changedFiles=$(git diff --cached --name-only --diff-filter=ACM)
# 判断目录是否改动
isBackendChanged=false
isFrontendChanged=false
for file in $changedFiles
do
if [[ $file == frontend/* ]]
then
isFrontendChanged=true
elif [[ $file == backend/* ]]
then
isBackendChanged=true
fi
done
# 改动的目录需要执行校验命令
# $1 $2 代表传给函数的第一个、第二个参数
execTask() {
echo "root $1 commit-msg"
cd $1
FORCE_COLOR=1 node scripts/verifyCommitMsg.mjs $2
}
if $isFrontendChanged
then
execTask "frontend" $1 & # 使用 & 让任务在后台执行
task1=$! # 保存任务 id
fi
if $isBackendChanged
then
execTask "backend" $1 &
task2=$!
fi
if [[ -n $task1 ]]; then
wait $task1
fi
if [[ -n $task2 ]]; then
wait $task2
fi
echo "All tasks finished."
上面脚本的逻辑是这样的:
1.每次 git 提交代码时,判断一下当前所有改动的文件是属于哪个项目2.文件发生改动的项目需要执行校验任务3.每个校验任务都使用子进程去执行4.等待所有校验任务执行结束后,输出All tasks finished.
测试一段时间后,发现第二个方案没发生什么问题,完全满足需求。
References
[1]huksy:
限时特惠:本站每日持续更新海量各大内部网赚创业教程,会员可以下载全站资源点击查看详情
站长微信: