用 Shell 脚本结合 Git 检测子目录里的文件是否有更改

注意:git diff --quiet HEAD master -- ./source 不知道为什么失效了,因此谷月姐采用了 Plan B 并修改了这篇文章。

用 Shell 脚本结合 Git 检测子目录里的文件是否有更改

S. 场景

谷月姐的博客(以下简称本博)是用 hexo-abbrlink 插件来生成每篇文章的文件名。这个插件会在执行 hexo g 渲染静态页面时,在每个 MarkDown 源文件的 front-matter 区域生成一个唯一不变的编号,并把这个编号作为对应的 HTML 网页文件的主文件名。

本博是用 GitHub Actions 自动部署的,这样就意味着,在 GitHub Actions 的虚拟机中执行 hexo g 以后,还要执行一次 git push,将修改过的 MarkDown 源文件推送回 GitHub 仓库。

C. 冲突

在实践中,谷月姐发现两个问题:

  1. 如果没有任何文件发生更改,执行 git commit -m "something" -a 的返回值是 1,这会导致 GitHub Actions 判定这个 step 执行状态为 fail,进而终止执行[1]

  2. 由于未知的原因,在 GitHub Actions 的虚拟机中每次执行过 hexo g 命令后,node_modules 目录中总有一些与 markdown-it 和 katex 有关的文件被更改,这种情况在本地渲染从来没有发生过,而且,这样的更改是万万不能推送回 GitHub 仓库的
    有一些文件被更改

Q. 问题

谷月姐发现,hexo-abbrlink 插件只会修改 source/_posts 目录中的 MarkDown 源文件。

那么,有没有办法只检测这个子目录中文件的更改,并且只推送这个更改呢?

参考文献[1]给出的办法,仅能检测仓库中全部文件的更改,无法把检测范围局限在某个子目录。

经过摸索,谷月姐找到了只检测某个子目录中的文件更改的方法。

A. 答案

Git 命令 git diff --quiet HEAD master -- ./source 可以检测当前仓库的 master 分支中 source 子目录中已暂存的文件内容的更改[2]。如果文件内容没有改动,上述命令的返回值(exit code)是 0;如果文件内容有改动,返回值是 1

Git 命令 git status --porcelain ./source 可以检测当前工作区的 source 子目录中的更改,包括新增文件、删除文件、修改文件内容。如果无更改,上述命令的结果为空;如果有更改,上述命令会列出发生更改的文件名[3]

为什么是检测 source 子目录而不是 source/_posts 子目录呢?一是为了省事儿,二是为了防备日后有其他的插件修改 source 子目录中其他的文件。

如果检测到 source 子目录中的文件内容没有改动,就略过;如果检测有改动,就提交并推送回 GitHub 仓库。具体代码如下:

1
2
3
4
5
6
7
if [ -z "$(git status --porcelain ./source)" ]; then
echo "nothing to update."
else
git add ./source
git commit -m "triggle by commit ${GITHUB_SHA}"
git push
fi

把以上代码写入到 GitHub Actions 自动部署脚本 deploy.yml 中即可。完整的脚本见这里

N. 注意事项

1. Git 命令 `git diff --quiet HEAD master -- ./source` **只能**检测当前仓库的 `master` 分支中 `source` 子目录中**已暂存的文件内容的更改**(包括文件被删除)。如果新增文件但是没有暂存,它是检测不到的。 2. Git 命令 `git diff --quiet HEAD master -- ./source` 默认是**递归**的,可以检测 `source` 子目录中所有的文件,及其每一级子目录中的文件。
  1. 在工作区里,无论是新建文件、删除文件,还是修改已有文件的内容,Git 命令 git status --porcelain ./source 都能检测到。
  2. Git 命令 git status --porcelain ./source 默认是递归的,可以检测 source 子目录中所有的文件,及其每一级子目录中的文件。

T. Two More Things …

  1. 在推送到 GitHub 之前,先在本地运行一遍 hexo s,也会在每个 MarkDown 源文件的 front-matter 区域生成一个唯一不变的编号,并把这个编号作为对应的 HTML 网页文件的主文件名。这样就省去了在 GitHub Actions 虚拟机中将修改过的 MarkDown 源文件推送回 GitHub 仓库的麻烦。

  2. 新版 Hexo (应该是从 6.0 开始),Hexo 本身也可以生成唯一的编号,用它充当每篇文章对应的 HTML 网页文件的主文件名[4]。它是在执行 hexo g 渲染时自动生成,不会修改 MarkDown 源文件。这样彻底省去了在 GitHub Actions 虚拟机中将修改过的 MarkDown 源文件推送回 GitHub 仓库的麻烦。但是我无法放弃 hexo-abbrlink 改用这个方案,因为这个方案会更改本博所有博文的 URL,影响搜索引擎的索引,也影响读者通过搜索引擎访问本博

R. 参考文献

图片版权

头图:Banner Image by milkusmaximus from Pixabay


求扫码打赏
“我这么可爱,请给我钱 o(*^ω^*)o”

用 Shell 脚本结合 Git 检测子目录里的文件是否有更改
https://blog.kukmoon.com/4713c775c574/
作者
Kukmoon谷月
发布于
2022年4月21日
许可协议