V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
moment082
V2EX  ›  程序员

使用 git diff 命令实现根目录文档的更新的时候自动更新子文档 😯😯😯

  •  
  •   moment082 · 19 天前 · 374 次点击

    在开始之前,首先描述一下我们目前遇到的场景,目前我们正在开发一个 前端脚手架 开源项目,当前项目使用 Truborepo+PNPM 开发的一个 Monorepo 项目,在根目录中,我们有一个文档,然后 packages 目录下有些子包的文档应该是和根目录下的包是一样的。

    因为我们的包是发布到 NPM 上的,并且是 GitHub 上开源的,所以根目录上的 README.me 应该是在 GItHub 上一打开项目的时候就能查看的,而 packages 目录下的子包文档应该是当在 NPM 网站上打开的时候就能看到的。

    如下图所示 GitHub:

    20240411073036

    而在 NPM 上也是这样的:

    20240411073140

    那么接下来我们的任务是当我们根目录下的 README.md 发生变动的时候,我们 packages 目录下的固定子包应该也会发生改变。

    git diff

    在开始之前,我们先来学习一下 git diff 这个命令。

    git diff 是 Git 版本控制系统中一个非常有用的命令,用于显示文件之间的差异、差异补丁和进行代码审查。这个命令可以用来比较文件的变化,检查工作目录中未暂存的改动,以及比较已暂存的改动和最近的提交等。

    查看未暂存的更改:

    git diff
    

    这个命令将会显示自从上次 git add 之后,工作目录中有哪些更改尚未暂存。

    20240411075324

    查看已暂存的更改:

    git diff --cached
    # 或者使用另外一个写法
    git diff --staged
    

    20240411075655

    这个时候我们可以看得出,使用 git diff --cached 命令是我们还不能查找得出文件内容是否有发生变更的,这个前提是需要他把文件添加到暂存区,也就是执行 git add,如下所示:

    20240411075837

    除此之外,我们还可以查看到具体哪个文件发生了变化,使用的命令是 git diff --cached <具体文件路径>

    20240411080029

    生成补丁文件,这个在我们前面的文章内容中就已经有讲解过了:

    git diff > changes.patch
    

    这个时候我们已经知道了怎么查找文件的变更了,那么我们应该如何来实现这个 git diff 命令呢,以及在哪里实现呢?

    配合 husky 来实现文档自动更新

    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 提交更改到本地仓库。

    如下图所示,我们的文件发生了如下变化:

    20240411101718

    当我们执行完成 git commit 的时候,packages 目录下固定包的 README 文件被我们正确的修改了:

    20240411101916

    到这里,我们就完成了我们的文档自动同步的需求了。

    总结

    在这篇文章中我们只要使用 git diff 在 Git 提交流程中自动检测和处理特定文件的更改,确保所有相关的部分都保持最新,并自动完成这些更改的提交。这种自动化有助于保持项目的不同部分同步,特别是在大型项目中,当某个核心文件(如 README.md )更新时,需要同步更新到多个位置。

    最后分享两个我的两个开源项目,它们分别是:

    这两个项目都会一直维护的,如果你想参与或者交流学习,可以加我微信 yunmz777 如果你也喜欢,欢迎 star 🚗🚗🚗

    目前尚无回复
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   1051 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 23:53 · PVG 07:53 · LAX 16:53 · JFK 19:53
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.