Skip to content
Souloss
Go back

如何使用 Git 钩子设置创建和修改日期

如何使用 Git 钩子在 astro-minimax 中自动设置创建和修改日期

教程/工程化 |
更新于:
| 4 分钟阅读 | 1,136 字

在这篇文章中,我将解释如何使用 pre-commit Git 钩子来自动填充 astro-minimax 博客主题 frontmatter 中的创建日期(pubDatetime)和修改日期(modDatetime)。

Table of contents

Open Table of contents

到处都有它们

Git 钩子非常适合自动化任务,比如添加检查分支名称到提交消息,或者阻止你提交明文密码。它们最大的缺点是客户端钩子是每台机器单独配置的。

你可以通过创建一个 hooks 目录并手动将它们复制到 .git/hooks 目录或设置符号链接来解决这个问题,但这都需要你记得去设置,而这不是我擅长做的事情。

由于这个项目使用 npm,我们可以利用一个名为 Husky 的包(astro-minimax 中已经安装)来自动为我们安装钩子。

更新!在 astro-minimax v4.3.0 中,pre-commit 钩子已被移除,改用 GitHub Actions。但是,你可以轻松地自己安装 Husky

钩子

由于我们希望在提交代码时运行此钩子来更新日期,然后将其作为我们更改的一部分,我们将使用 pre-commit 钩子。这个 astro-minimax 项目已经设置好了,但如果没有,你需要运行 npx husky add .husky/pre-commit 'echo "This is our new pre-commit hook"'

导航到 hooks/pre-commit 文件,我们将添加以下一个或两个代码片段。

编辑文件时更新修改日期


更新:

本节已更新为新版本的钩子,它更智能。现在它不会增加 modDatetime 直到文章发布。首次发布时,将 draft 状态设置为 first,然后看奇迹发生。


git diff --cached --name-status 从 git 获取已暂存待提交的文件。输出如下:

A       src/content/blog/setting-dates-via-git-hooks.md
shell

开头的字母表示已采取的操作,在上面的示例中文件已被添加。修改的文件有 M

我们将该输出通过管道传递给 grep 命令,查找每行中已修改的文件。该行需要以 M 开头(^(M)),后面可以有任意数量的字符(.*),并以 .md 文件扩展名结尾(.(md)$)。这将过滤掉不是已修改 markdown 文件的行 egrep -i "^(M).*\.(md)$"


改进 - 更明确

这可以添加为仅查找 blog 目录中的 markdown 文件,因为只有这些文件才有正确的 frontmatter。


正则表达式将捕获两个部分,字母和文件路径。我们将把此列表通过管道传递给 while 循环来遍历匹配的行,并将字母分配给 a,路径分配给 b。我们暂时忽略 a

要知道文件的草稿状态,我们需要它的 frontmatter。在以下代码中,我们使用 cat 获取文件内容,然后使用 awk 以 frontmatter 分隔符(---)分割文件并取第二个块(frontmatter,即 --- 之间的部分)。从这里我们再次使用 awk 查找 draft 键并打印其值。

  filecontent=$(cat "$file")
  frontmatter=$(echo "$filecontent" | awk -v RS='---' 'NR==2{print}')
  draft=$(echo "$frontmatter" | awk '/^draft: /{print $2}')
shell

现在我们有了 draft 的值,我们将做以下 3 件事之一:将 modDatetime 设置为现在(当 draft 为 false 时 if [ "$draft" = "false" ]; then),清除 modDatetime 并将 draft 设置为 false(当 draft 设置为 first 时 if [ "$draft" = "first" ]; then),或者什么也不做(在任何其他情况下)。

接下来带有 sed 命令的部分对我来说有点神奇,因为我不经常使用它,它是从另一篇关于类似操作的博客文章中复制的。本质上,它在文件的 frontmatter 标签(---)内查找 pubDatetime: 键,获取整行并用 pubDatetime: $(date -u "+%Y-%m-%dT%H:%M:%SZ")/" 替换它,即相同的键和格式正确的当前日期时间。

这个替换是在整个文件的上下文中进行的,所以我们将其放入临时文件(> tmp),然后将新文件移动到旧文件的位置,覆盖它。然后将其添加到 git 中,准备像我们自己做了更改一样提交。


注意

要使 sed 工作,frontmatter 需要已经有 modDatetime 键。要让应用以空日期构建,你还需要进行一些其他更改,请参阅下面


为新文件添加日期

为新文件添加日期与上述过程相同,但这次我们要查找已添加(A)的行,并且我们将替换 pubDatetime 值。

# New files, add/update the pubDatetime
git diff --cached --name-status | egrep -i "^(A).*\.(md)$" | while read a b; do
  cat $b | sed "/---.*/,/---.*/s/^pubDatetime:.*$/pubDatetime: $(date -u "+%Y-%m-%dT%H:%M:%SZ")/" > tmp
  mv tmp $b
  git add $b
done
shell

改进 - 只循环一次

我们可以使用 a 变量在循环内切换,要么更新 modDatetime 要么添加 pubDatetime,在一个循环中完成。


填充 frontmatter

如果你的 IDE 支持代码片段,则可以选择创建自定义代码片段来填充 frontmatter。astro-minimax v4 将默认为 VSCode 提供一个代码片段。

modDatetime 更改

要让 Astro 编译 markdown 并执行其操作,它需要知道 frontmatter 中期望什么。它通过 src/content/config.ts 中的配置来完成此操作。

要允许键存在但没有值,我们需要编辑第 10 行以添加 .nullable() 函数。

为了阻止 IDE 在博客引擎文件中抱怨,我还做了以下操作:

  1. src/layouts/Layout.astro 的第 15 行添加 | null,使其看起来像:

    export interface Props {
      title?: string;
      author?: string;
      description?: string;
      ogImage?: string;
      canonicalURL?: string;
      pubDatetime?: Date;
      modDatetime?: Date | null;
    }
    typescript
  2. src/components/ui/Datetime.astro 的第 5 行添加 | null,使其看起来像:

    interface DatetimesProps {
      pubDatetime: string | Date;
      modDatetime: string | Date | undefined | null;
    }
    typescript


上一篇
astro-minimax 1.0
下一篇
预定义配色方案

相关推荐

评论区

文明评论,共建和谐社区