当前位置: 首页 > news >正文

一个 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=falsefor file in $changedFiles
doif [[ $file == frontend/* ]]thenisFrontendChanged=trueelif [[ $file == backend/* ]]thenisBackendChanged=truefi
done# 改动的目录需要执行校验命令
# $1 $2 代表传给函数的第一个、第二个参数
execTask() {echo "root $1 commit-msg"cd $1FORCE_COLOR=1 node scripts/verifyCommitMsg.mjs $2
}if $isFrontendChanged
thenexecTask "frontend" $1 & # 使用 & 让任务在后台执行task1=$! # 保存任务 id
fiif $isBackendChanged
thenexecTask "backend" $1 &task2=$!
fiif [[ -n $task1 ]]; thenwait $task1
fiif [[ -n $task2 ]]; thenwait $task2
fiecho "All tasks finished."

上面脚本的逻辑是这样的:

  1. 每次 git 提交代码时,判断一下当前所有改动的文件是属于哪个项目
  2. 文件发生改动的项目需要执行校验任务
  3. 每个校验任务都使用子进程去执行
  4. 等待所有校验任务执行结束后,输出 All tasks finished.

pre-push 脚本编写

pre-commitcommit-msg 不同,在 pre-push 钩子中需要通过其他方式来拿到发生改动的文件,大家直接看代码:

#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"# 判断目录是否改动
isFrontendChanged=false
isComponentTemplateChanged=false
isComponentAttrPanelChanged=false# 获取远程仓库的名字和 URL
remote="$1"
url="$2"# 定义一个空的 git 哈希值
z40=0000000000000000000000000000000000000000# 这个循环从 stdin 读取数据,这些数据是 git 在调用 pre-push 钩子时传递的。
# 每一行数据包括 4 个字段:本地引用名,本地最新的提交哈希值,远程引用名,远程最新的提交哈希值。
while read local_ref local_sha remote_ref remote_sha
do# 这段代码检查是否正在删除一个引用(例如,删除一个分支)。如果是,那么本地的 sha 值将被设置为一个空哈希值。if [ "$local_sha" = $z40 ] then# Handle delete:else# 这段代码确定要检查哪些提交。如果远程的 sha 值是一个空哈希值,那么我们正在创建一个新的引用,所以我们需要检查所有的提交。# 否则,我们正在更新一个已经存在的引用,所以我们只需要检查新的提交。if [ "$remote_sha" = $z40 ] then# New branch, examine all commitsrange="$local_sha"else# Update to existing branch, examine new commitsrange="$remote_sha..$local_sha"fi# 这个循环对每一个包含在 range 变量中的提交执行 git rev-list 命令,这个命令会返回一系列的提交哈希值。# 然后,对每个提交,我们使用 git diff-tree 命令来找到在那个提交中修改的文件。这些文件的名字被存储在 files 变量中。for commit in $(git rev-list "$range"); do# 拿到所有改动的文件名files=$(git diff-tree --no-commit-id --name-only -r $commit)for file in $filesdoif [[ $file == frontend/* ]]thenisFrontendChanged=trueelif [[ $file == component-attr-panel/* ]]thenisComponentAttrPanelChanged=trueelif [[ $file == component-template/* ]]thenisComponentTemplateChanged=truefidonedonefi
done# 改动的目录需要执行校验命令
execTask() {echo "root $1 pre-push"cd $1npm run type-check
}if $isFrontendChanged
thenexecTask "frontend" & # 使用 & 让任务在后台执行task1=$! # 保存任务 id
fiif $isComponentTemplateChanged
thenexecTask "component-template" &task2=$!
fiif $isComponentAttrPanelChanged
thenexecTask "component-attr-panel" &task3=$!
fiif [[ -n $task1 ]]; thenwait $task1
fiif [[ -n $task2 ]]; thenwait $task2
fiif [[ -n $task3 ]]; thenwait $task3
fiecho "All tasks finished."

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

相关文章:

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

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

钉钉对接打通金蝶云星空获取流程实例列表详情(宜搭)接口与其他应收单接口

钉钉对接打通金蝶云星空获取流程实例列表详情(宜搭)接口与其他应收单接口 对接系统钉钉 钉钉(DingTalk)是阿里巴巴集团专为中国企业打造的免费沟通和协同的多端平台,提供PC版,Web版和手机版,有考…...

用python做一个小项目,python做简单小项目

大家好,本文将围绕用python做一个小项目展开说明,python做简单小项目是一个很多人都想弄明白的事情,想搞清楚python入门小项目需要先了解以下几个事情。 来源丨网络 经常听到有朋友说,学习编程是一件非常枯燥无味的事情。其实&…...

输入筛选框搜索

文章目录 输入筛选框实现效果图需求前端工具版本添加依赖main.js导入依赖 代码 后端代码对应 sql对应 mapper.xml 文件的动态 sql 输入筛选框实现 效果图 需求 通过筛选框,选择公司,传入后端,后端根据公司名称去文章的内容中进行模糊查询 …...

公司植物日常护养方法备忘录

植物为我们净化空气,美化环境,我们要按照科学的经验照顾好它们。公司植物日常通用护养方法如下: 首先剪掉已经枯黄的部分。 需要晒太阳的植物按时搬到外面晒太阳,每次晒1到2个小时。 所有植物统一在每个月的20号左右施肥一次&am…...

小红书JAVA后端一面汇总总结

小红书 2 年社招 Java 后端一面的面经,面试的风格是从一个知识一层一层深入问到底层。 从 Java IO,问到 socket 底层。从 Java 内存,问到操作系统内存。所以学习知识的时候,不要只 看八股文,还是需要从点到面一层层去掌握, 才能比较好应对这类的面试场景。 问题记录 自我…...

【图论】强连通分量进阶

一.作用 强连通分量可以判断环和进行缩点。还有一系列作用.... 这篇文章介绍缩点 二.题目 https://www.luogu.com.cn/problem/P2341 三.思路 我们分析可以知道当一个点没有出度时,则为最受欢迎的牛。但如果有多个出度,则没有最受欢迎的牛。 这是只有…...

perl GetOptions

在Perl中,你可以使用标准模块Getopt::Long来解析命令行选项(Command Line Options)。Getopt::Long模块允许你定义命令行选项以及它们的值,并且还可以处理各种类型的选项,如标志选项(flag options&#xff0…...

QGIS下载谷歌地图或者其他地图

QGIS安装Welcome to the QGIS project! 打开QGIS 添加图源 Google_Maps: https://mt1.google.com/vt/lyrsr&x{x}&y{y}&z{z} Google_Terrain: https://mt1.google.com/vt/lyrst&x{x}&y{y}&z{z} Google_Roads:https://mt1.google.com/vt/lyrsh&x{x…...

Python-re模块-正则表达式模块常用方法

re模块介绍: Python的re模块提供了正则表达式的功能,可以用来进行高级的字符串匹配和处理。re模块的主要功能包括: 编译正则表达式 - 使用re.compile()可以编译正则表达式字符串,生成正则表达式对象。 匹配字符串 - 使用正则表达式对象的match()、search()、finda…...

修改el-select或者el-input样式失效

下午改el-input和el-select这两个的样式真的烦,,,还不如写原生标签了。。 样式使用的是sass 我已经在样式器中挨着挨着去找了,把层级的类都写下来了 .select-wraper{//下拉框.el-select{.el-input .el-input__wrapper{backgrou…...

【Apifox】Apifox设置参数说明:

文章目录 一、效果:二、Query参数:三、返回响应: 一、效果: 二、Query参数: 三、返回响应:...

离线数仓中,为什么用两个flume,一个kafka

实时数仓中,为什么没有零点漂移问题? 因为flink直接取的事件时间用kafka是为了速度快,并且数据不丢,那为什么既用了kafkachannel,也用了kafka,而不只用kafkachannel呢? 因为需要削峰填谷离线数仓…...

p7付费课程笔记6:CMS GC

目录 前言 工作步骤 缺点 问题 前言 上一章节我们讲了串/并行GC,这一章节说下CMS GC。看前思考一个问题,并行GC与CMS GC的区别在哪里。 什么是CMS收集器 CMS(Concurrent Mark-Sweep)是以牺牲吞吐量为代价来获得最短回收停顿时间的垃圾回收器。对于…...

Linux性能分析--cpuinfo的内核实现

目录 一、引言 二、Linux性能分析工具介绍 ------>2.1、proc ------------>2.1.1、内核中的proc文件系统 ------------>2.2.2、proc的实现 ------>2.2、cpuinfo ------------>2.2.1、cpuinfo的内核实现 ------------>2.2.2、寄存器获取cpuinfo数据 …...

鲁大师7月新机性能/流畅/久用榜:骁龙8 Gen2领先版亮相,性能跑分再破新高

摘要:iQOO 11S突破上限,红魔8S Pro再创新高 继五月六月,搭载天玑9200的机型相继迎来上市之后,高通也终于按耐不住。 本月所有上市的新机均搭载高通骁龙系列芯片,其中骁龙8 Gen2领先版迎来首次亮相,除了主打…...

【QT学习】01:helloqt

helloqt OVERVIEW helloqt一、helloqt1.使用向导创建2.手动创建3.pro文件4.Qt应用程序框架 二、按钮创建main.cppmywidget.cpp 三、对象模型1.对象树引入2.存在的问题 一、helloqt 创建一个qt项目,可以使用creator的向导创建,也可自己手动创建&#xff…...

学习gRPC (三)

测试gRPC例子 编写proto文件实现服务端代码实现客户端代码 通过gRPC 已经编译并且安装好之后,就可以在源码目录下找到example 文件夹下来试用gRPC 提供的例子。 在这里我使用VS2022来打开仓库目录下example/cpp/helloworld目录 编写proto文件 下面是我改写的exa…...

【html】学习记录

1.在建立一个页面的时候不是打开软件就开始写代码,要先规划好页面的布局框架,不然思想会很混乱,如做个人简历,要分区分块,把每个区域的内容搞清楚。 2.html的很多标签看上去作用都是一样的,但是实际有很大不…...

2023年人工智能技术与智慧城市发展白皮书

人工智能与智慧城市是当前热门的话题和概念,通过将人工智能技术应用在城市管理和服务中,利用自动化、智能化和数据化的方式提高城市运行效率和人民生活质量,最终实现城市发展的智慧化,提升城市居民的幸福感。 AI技术在城市中的应…...

《Python入门到精通》条件控制 if 语句

「作者主页」:士别三日wyx 「作者简介」:CSDN top100、阿里云博客专家、华为云享专家、网络安全领域优质创作者 「推荐专栏」:小白零基础《Python入门到精通》 if 语句 1、四种语法格式1.1、if1.2、if else1.3、if elif else1.4、if 嵌套 2、…...

如何编写一个易于维护的考试系统源码

编写一个易于维护的考试系统源码对于开发人员来说非常重要。一个易于维护的系统可以使代码更易于理解、修改和扩展,从而提高开发效率和系统稳定性。 第一步:良好的项目结构 良好的项目结构是一个易于维护的源码的基础。可以按照模块、功能或层次等方式…...

day 2 |977.有序数组的平方、209.长度最小的子数组、59.螺旋矩阵II

目录: 解题及思路学习 977.有序数组的平方 https://leetcode.cn/problems/squares-of-a-sorted-array/submissions/ 给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。 示例 1&a…...

【力扣每日一题】2023.8.2 翻转卡片游戏

目录 题目: 示例: 分析: 代码: 题目: 示例: 分析: 这道题不是什么翻转卡片游戏,这就是纯纯的文字游戏,要是能看懂题目那就是非常简单,接下来我就给大家分…...

IDEA设置中文 中文插件

IDEA设置中文 中文插件 首先进入idea File --> Setting --> Plugin 输入Chinese 搜索插件 选择下图插件进行install 安装完成后,重启idea即可...

Python——调用webdriver.Chrome() 报错

今天运行脚本&#xff0c;报错内容如下&#xff1a; collecting ... login_case.py:None (login_case.py) login_case.py:11: in <module> dr webdriver.Chrome() D:\Program Files (x86)\Python\Python39\Lib\site-packages\selenium\webdriver\chrome\webdriver.p…...

人工智能发展的五个主要技术方向是什么?

人工智能主要分支介绍 通讯、感知与行动是现代人工智能的三个关键能力&#xff0c;在这里我们将根据这些能力/应用对这三个技术领域进行介绍&#xff1a; 计算机视觉(CV) 自然语言处理(NLP) 在 NLP 领域中&#xff0c;将覆盖文本挖掘/分类、机器翻译和语音识别。 机器人 1、…...

机器学习知识经验分享之六:决策树

python语言用于深度学习较为广泛&#xff0c;R语言用于机器学习领域中的数据预测和数据处理算法较多&#xff0c;后续将更多分享机器学习数据预测相关知识的分享&#xff0c;有需要的朋友可持续关注&#xff0c;有疑问可以关注后私信留言。 目录 一、R语言介绍 二、R语言安装…...

回归预测 | MATLAB实现SO-CNN-GRU蛇群算法优化卷积门控循环单元多输入单输出回归预测

回归预测 | MATLAB实现SO-CNN-GRU蛇群算法优化卷积门控循环单元多输入单输出回归预测 目录 回归预测 | MATLAB实现SO-CNN-GRU蛇群算法优化卷积门控循环单元多输入单输出回归预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 MATLAB实现SO-CNN-GRU蛇群算法优化卷积门控循…...

309. 买卖股票的最佳时机含冷冻期

给定一个整数数组prices&#xff0c;其中第 prices[i] 表示第 i 天的股票价格 。​ 设计一个算法计算出最大利润。在满足以下约束条件下&#xff0c;你可以尽可能地完成更多的交易&#xff08;多次买卖一支股票&#xff09;: 卖出股票后&#xff0c;你无法在第二天买入股票 …...