一个 git 仓库下拥有多个项目的 git hooks 配置

前言

通常情况下,一个 git 仓库就是一个项目,只需要配置一套 git hooks 脚本就可以执行各种校验任务。对于 monorepo 项目也是如此,monorepo 项目下的多个 packages 之间,它们是有关联的,可以互相引用,所以当成一个项目也没问题。

但是也有一种情况,一个 git 仓库下的多个项目之间是彼此独立的,比如 git 仓库下存在前端项目、后端项目、文档项目等等。这时候就需要为每个项目配置不同的 git hooks 脚本了,因为不同的项目有可能校验规则不一样。

本文主要探讨一下如何为不同的项目配置 git hooks 脚本。

PS:配置 git hooks 脚本使用 huksy

方案一:每个项目下都配置一套 git hooks 脚本

假设仓库拥前后端两个项目:

frontend
backend

那么我们需要在每个项目下安装 husky,同时要在 package.json 中配置一下 prepare 脚本(这里以前端项目为示例):

# package.json
{
	"scripts" {
		"prepare": "cd .. && husky install frontend/.husky"
	}
}

然后按照 husky 文档创建 pre-commitcommit-msg 钩子文件:

#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

# pre-commit
cd frontend
npx lint-staged
#!/usr/bin/env sh
. "$(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/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 作为示例编写一个脚本:

#!/usr/bin/env sh
. "$(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.

测试一段时间后,发现第二个方案没发生什么问题,完全满足需求。

全部评论

相关推荐

点赞 评论 收藏
分享
06-13 17:33
门头沟学院 Java
顺序不记了,大致顺序是这样的,有的相同知识点写分开了1.基本数据类型2.基本数据类型和包装类型的区别3.==和equals区别4.ArrayList与LinkedList区别5.hashmap底层原理,put操作时会发生什么6.说出几种树型数据结构7.B树和B+树区别8.jvm加载类机制9.线程池核心参数10.创建线程池的几种方式11.callable与runnable区别12.线程池怎么回收线程13.redis三剑客14.布隆过滤器原理,不要背八股,说说真正使用时遇到了问题没有(我说没有,不知道该怎么回答了)15.堆的内存结构16.自己在写项目时有没有遇见过oom,如何处理,不要背八股,根据真实经验,我说不会17.redis死锁怎么办,watchdog机制如何发现是否锁过期18.如何避免redis红锁19.一个表性别与年龄如何加索引20.自己的项目的QPS怎么测的,有没有真正遇到大数量表21.说一说泛型22.springboot自动装配原理23.springmvc与springboot区别24.aop使用过嘛?动态代理与静态代理区别25.spring循环依赖怎么解决26.你说用过es,es如何分片,怎么存的数据,1000万条数据怎么写入库中27.你说用limit,那么在数据量大之后,如何优化28.rabbitmq如何批次发送,批量读取,答了延迟队列和线程池,都不对29.计网知不知道smtp协议,不知道写了对不对,完全听懵了30.springcloud知道嘛?只是了解反问1.做什么的?短信服务,信息量能到千万级2.对我的建议,基础不错,但是不要只背八股,多去实际开发中理解。面试官人不错,虽然没露脸,但是中间会引导我回答问题,不会的也只是说对我要求没那么高。面完问我在济宁生活有没有困难,最快什么时候到,让人事给我聊薪资了。下午人事打电话,问我27届的会不会跑路,还在想办法如何使我不跑路,不想扣我薪资等。之后我再联系吧,还挺想去的😭,我真不跑路哥😢附一张河科大幽默大专图,科大就是大专罢了
查看30道真题和解析
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务