在开始之前,首先描述一下我们目前遇到的场景,目前我们正在开发一个 前端脚手架 开源项目,当前项目使用 Truborepo+PNPM 开发的一个 Monorepo 项目,在根目录中,我们有一个文档,然后 packages 目录下有些子包的文档应该是和根目录下的包是一样的。
因为我们的包是发布到 NPM 上的,并且是 GitHub 上开源的,所以根目录上的 README.me 应该是在 GItHub 上一打开项目的时候就能查看的,而 packages 目录下的子包文档应该是当在 NPM 网站上打开的时候就能看到的。
如下图所示 GitHub:
而在 NPM 上也是这样的:
那么接下来我们的任务是当我们根目录下的 README.md 发生变动的时候,我们 packages 目录下的固定子包应该也会发生改变。
在开始之前,我们先来学习一下 git diff 这个命令。
git diff 是 Git 版本控制系统中一个非常有用的命令,用于显示文件之间的差异、差异补丁和进行代码审查。这个命令可以用来比较文件的变化,检查工作目录中未暂存的改动,以及比较已暂存的改动和最近的提交等。
查看未暂存的更改:
git diff
这个命令将会显示自从上次 git add 之后,工作目录中有哪些更改尚未暂存。
查看已暂存的更改:
git diff --cached
# 或者使用另外一个写法
git diff --staged
这个时候我们可以看得出,使用 git diff --cached
命令是我们还不能查找得出文件内容是否有发生变更的,这个前提是需要他把文件添加到暂存区,也就是执行 git add
,如下所示:
除此之外,我们还可以查看到具体哪个文件发生了变化,使用的命令是 git diff --cached <具体文件路径>
:
生成补丁文件,这个在我们前面的文章内容中就已经有讲解过了:
git diff > changes.patch
这个时候我们已经知道了怎么查找文件的变更了,那么我们应该如何来实现这个 git diff 命令呢,以及在哪里实现呢?
Husky 是一个流行的工具,用于在 Git 钩子中自动化 JavaScript 和其他语言的项目的代码质量检查、测试以及在提交前自动修正问题。它使得配置和使用 Git 钩子变得简单便捷,如 pre-commit 或 pre-push 钩子,从而可以在代码提交到版本控制系统之前执行代码检查和格式化任务,确保代码库的整洁和一致性。
要想实现我们的需求,首先我们可以在 pre-commit 钩子中通过 git diff 来查找出文件的变更或者然后根据这个文件变更的内容编写一个脚本自动复制到某个具体的文件。
首先我们在 husky 的 pre-commit 中添加如下代码:
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
echo 'running pre-commit checks ...'
npx lint-staged -q
+ npx ts-node --transpile-only ./scripts/check-readme-change.ts
echo -e 'pre-commit success!\n'
需要提前执行 pnpm add ts-node -Dw
然后我们要在根目录下的 scripts 目录下添加 check-readme-change.ts 文件并编写如下代码:
const { execSync } = require("child_process");
const fs = require("fs");
const path = require("path");
const fileToCheck = "README.md"; // 需要检查的文件
const destinationFiles = ["packages/core/README.md"];
try {
// 执行 git diff 命令以检查是否有文件更改
const result = execSync(`git diff --cached --name-only`).toString();
// 检查目标文件是否在更改列表中
if (result.split("\n").includes(fileToCheck)) {
// 如果文件有更改,读取文件内容
const data = fs.readFileSync(fileToCheck, "utf8");
// 将内容复制到所有目标文件
destinationFiles.forEach((filePath) => {
const targetPath = path.join(process.cwd(), filePath);
fs.writeFileSync(targetPath, data);
console.log(`Copied updated ${fileToCheck} to ${targetPath}`);
});
// 提交文件更改
execSync("git add .");
execSync("git commit --no-verify --allow-empty-message");
}
} catch (error) {
console.error("Error executing git diff:", error);
process.exit(1); // 有错误发生时退出脚本
}
在上面的代码中就是查找出 README.md 文件有没有发生改变,如果没有发生改变的直接跳过,如果改变了则将文件复制到固定目录下并使用 git add .
将所有修改过的文件添加到 Git 暂存区。用 git commit --no-verify --allow-empty-message
提交更改到本地仓库。
如下图所示,我们的文件发生了如下变化:
当我们执行完成 git commit 的时候,packages 目录下固定包的 README 文件被我们正确的修改了:
到这里,我们就完成了我们的文档自动同步的需求了。
在这篇文章中我们只要使用 git diff 在 Git 提交流程中自动检测和处理特定文件的更改,确保所有相关的部分都保持最新,并自动完成这些更改的提交。这种自动化有助于保持项目的不同部分同步,特别是在大型项目中,当某个核心文件(如 README.md )更新时,需要同步更新到多个位置。
最后分享两个我的两个开源项目,它们分别是:
这两个项目都会一直维护的,如果你想参与或者交流学习,可以加我微信 yunmz777 如果你也喜欢,欢迎 star 🚗🚗🚗