首页 > 其他分享 >一个 git 仓库下拥有多个项目的 git hooks 配置方案

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

时间:2023-08-17 14:59:45浏览次数:51  
标签:git 项目 仓库 hooks commit husky fi

前言

通常情况下,一个 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.

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 commits
            range="$local_sha"
        else
            # Update to existing branch, examine new commits
            range="$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 $files
            do
                if [[ $file == frontend/* ]]
                then
                    isFrontendChanged=true
                elif [[ $file == component-attr-panel/* ]]
                then
                    isComponentAttrPanelChanged=true
                elif [[ $file == component-template/* ]]
                then
                    isComponentTemplateChanged=true
                fi
            done
        done
    fi
done

# 改动的目录需要执行校验命令
execTask() {
    echo "root $1 pre-push"
    cd $1
    npm run type-check
}

if $isFrontendChanged
then
    execTask "frontend" & # 使用 & 让任务在后台执行
    task1=$! # 保存任务 id
fi

if $isComponentTemplateChanged
then
    execTask "component-template" &
    task2=$!
fi

if $isComponentAttrPanelChanged
then
    execTask "component-attr-panel" &
    task3=$!
fi

if [[ -n $task1 ]]; then
    wait $task1
fi

if [[ -n $task2 ]]; then
    wait $task2
fi

if [[ -n $task3 ]]; then
    wait $task3
fi

echo "All tasks finished."

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

PS:在写脚本的时候要注意各个任务是否能并发执行,比如 lint-staged 这个任务就不能并发执行,所以在编写 pre-commit 脚本执行代码校验的时候,得改为串行。

标签:git,项目,仓库,hooks,commit,husky,fi
From: https://www.cnblogs.com/woai3c/p/17637534.html

相关文章

  • Git的拓展
    为了维护版本信息,修改对应版本的具体内容,需要进入指定的版本下一、广义下的git的使用1、首先,确保目录干净,以下情况则说明目录干净 2、查看提交历史:gitlog(发现,共提交过三次) 3、恢复历史提交   恢复至最后一次提交的上一次提交(也即倒数第二次提交)   gitrese......
  • 智能仓储管理系统(自动化仓库管理解决方案)
        企业实际的仓储管理中,往往会出现那样这样的错误,归根结底,主要是由于没使用合适的仓库管理工具。相反,人工使用合适的仓库管理工具,不仅可以在日常仓库管理方法中根据采集到的产品信息数据,大大地提高管理效率,降低库存实际管控成本,还可降低人工管理库存的操作失误,智能化仓储......
  • 智能仓储管理系统(自动化仓库管理解决方案)
        企业实际的仓储管理中,往往会出现那样这样的错误,归根结底,主要是由于没使用合适的仓库管理工具。相反,人工使用合适的仓库管理工具,不仅可以在日常仓库管理方法中根据采集到的产品信息数据,大大地提高管理效率,降低库存实际管控成本,还可降低人工管理库存的操作失误,智能化仓储......
  • GIT简记
    GIT简记gitinitgitremoteaddoriginhttp://xxx.com/xxx.gitgitpulloriginmastergitstatusgitadd.gitcommit-m'修改日志'gitpushoriginmaster 2023年08月17日更新:#要提交到多个git仓库,可以先添加:gitremoteaddorigin_aliyunhttp.......#提交......
  • Git删除tag
    1.idea在工具栏找到Terminal——》输入git ,确保支持git命令 2.查看所有tag 3. 删除git上指定tag单个删除: gittag-d<tagname>批量删除: gittag-d<tagname1><tagname2><tagname3> 4.push到远程 ......
  • 基于springcolud微服务的超市仓库管理系统
    随着信息技术和网络技术的飞速发展,人类已进入全新信息化时代,传统管理技术已无法高效,便捷地管理信息。为了迎合时代需求,优化管理效率,各种各样的管理系统应运而生,各行各业相继进入信息管理时代,超市仓库管理系统就是信息时代变革中的产物之一。任何系统都要遵循系统设计的基本流程,本系......
  • ubuntu虚拟机git环境配置
    1 ssh-keygen-trsa-C‘git注册的邮箱’  //记得改成自己的注册git的邮箱 2 把公钥黏贴到http://git.software.team/profile/keys页面中的大框中3本地配置全局用户名和用户Email gitconfig--globaluser.email"[email protected]"gitconfig--globaluser.n......
  • Git安装和TortoiseGit安装图文详解
    0、环境windows1064位 1、Git下载和安装Git官网:Git-DownloadingPackage(git-scm.com)                  右键可以看到这两个选项即安装成功。   2、TortoiseGit下载和安装官网地址:Download–Tortoi......
  • github网站访问不通。。。代码推不上去。。。github网站访问好慢。。。怎么解决啊。。
    一直受github网站访问很慢的困扰。之前有用极光进行加速来着,但是网站不稳定,有时候用不了。所以我今天试了另外一种方案,真的很给力啊。。。首先下载一个steam++,下载地址:https://steampp.net/下载安装好后,可以操作如下,对github进行加速: 然后尝试去拉代码,结果又报了下面的错......
  • 【题解】[ARC158C] All Pair Digit Sums
    传送门题目分析我们可以先从简单一点的情况开始分析,如果现在\(a_{[i]},a_{[j]}\)都不会进位,那么最后的\(f(a_{[i]}+a_{[j]})=f(a_{[i]})+f(a_{[j]})\)。证明如下:有两个数\(x=\overline{x_nx_{n-1}....x_1}\)和\(y=\overline{y_my_{m-1}...y_1}\)。令\(n\lem\),由于不会......