用 Shell 脚本结合 Git 检测子目录里的文件是否有更改
注意:git diff --quiet HEAD master -- ./source
不知道为什么失效了,因此谷月姐采用了 Plan B 并修改了这篇文章。
S. 场景
谷月姐的博客(以下简称本博)是用 hexo-abbrlink 插件来生成每篇文章的文件名。这个插件会在执行 hexo g
渲染静态页面时,在每个 MarkDown 源文件的 front-matter 区域生成一个唯一不变的编号,并把这个编号作为对应的 HTML 网页文件的主文件名。
本博是用 GitHub Actions 自动部署的,这样就意味着,在 GitHub Actions 的虚拟机中执行 hexo g
以后,还要执行一次 git push
,将修改过的 MarkDown 源文件推送回 GitHub 仓库。
C. 冲突
在实践中,谷月姐发现两个问题:
-
如果没有任何文件发生更改,执行
git commit -m "something" -a
的返回值是1
,这会导致 GitHub Actions 判定这个 step 执行状态为 fail,进而终止执行[1]。 -
由于未知的原因,在 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 |
|
把以上代码写入到 GitHub Actions 自动部署脚本 deploy.yml
中即可。完整的脚本见这里。
N. 注意事项
- 在工作区里,无论是新建文件、删除文件,还是修改已有文件的内容,Git 命令
git status --porcelain ./source
都能检测到。 - Git 命令
git status --porcelain ./source
默认是递归的,可以检测source
子目录中所有的文件,及其每一级子目录中的文件。
T. Two More Things …
-
在推送到 GitHub 之前,先在本地运行一遍
hexo s
,也会在每个 MarkDown 源文件的 front-matter 区域生成一个唯一不变的编号,并把这个编号作为对应的 HTML 网页文件的主文件名。这样就省去了在 GitHub Actions 虚拟机中将修改过的 MarkDown 源文件推送回 GitHub 仓库的麻烦。 -
新版 Hexo (应该是从 6.0 开始),Hexo 本身也可以生成唯一的编号,用它充当每篇文章对应的 HTML 网页文件的主文件名[4]。它是在执行
hexo g
渲染时自动生成,不会修改 MarkDown 源文件。这样彻底省去了在 GitHub Actions 虚拟机中将修改过的 MarkDown 源文件推送回 GitHub 仓库的麻烦。但是我无法放弃 hexo-abbrlink 改用这个方案,因为这个方案会更改本博所有博文的 URL,影响搜索引擎的索引,也影响读者通过搜索引擎访问本博。
R. 参考文献
图片版权
头图:Banner Image by milkusmaximus from Pixabay