Gitea 自动同步子仓库
Gitea 自动同步子仓库
博客代码仓库与文章仓库是两个独立的版本仓库,博客仓库通过子模块的方式来引用文章仓库。把博客的代码(Vuepress)和文章放一起,会更简单——不用折腾 @vuepress/plugin-git 问题,也不需要推送子仓库之后再去更新主仓库。
但是个人习惯上,还是倾向于将应用与数据分离开来。更新文章即关注博文的编辑与发布;而功能或 UI 上的改进即为博客版本的迭代。二者之间不具有强关联性——如果想换一个博客框架的话,只要保证新框架具有相似的功能集(Markdown 文件的静态编译功能)就好了,没有的话也可以自己开发;可能的话,网友替换掉子模块后,便能得到一个文章内容不同克隆体。
子仓库的自动同步配置
子仓库的自动同步功能是由 Webhook 结合 Gitea Actions 协作来完成的。子模块推送更新后,触发子仓库 Webhook ,主仓收到 Webhook 请求后执行更新子仓库的工作流——模块的更新、合并和提交等操作,完成主仓库的同步更新。
Gitea 默认具有 Webhook 支持,除了和自身集成,还支持飞书、钉钉和企业微信等应用。要想通过 Webhoook 启动工作流,需要 /repos/{owner}/{repo}/actions/workflows/{workflow_id}/dispatches 这个接口的支持。
添加自动更新子模块的工作流(Gitea Actions)
博客仓库(vuepress-starter)切换到 dev 分支,在项目录下的 .gitea 目录里添加 update-submodules.yml 文件, 内容如下:
默认主分支(
main)写保护,主分支不直接用来做提交和推送。最终的提交经由其他分支开发并测试好之后,再合并或者变基过去。
name: Sync Submodules
run-name: ${{ gitea.actor }}
on:
workflow_dispatch:
jobs:
update-submodules:
runs-on: nas
steps:
- name: Checkout main repo
uses: https://gitea.com/actions/checkout@v4
with:
ssh-key: ${{ secrets.DEPLOYKEY }}
ssh-known-hosts: ssh-keyscan gitea.mtfh.cc
- name: Update submodules
run: |
git submodule update --init --remote --merge
- name: Commit updated submodules
run: |
git config user.name "${{ USER_NAME }}"
git config user.email "${{ USER_EMAIL }}"
git add .
if ! git diff --cached --quiet; then
git commit -m "$(git -C src/posts log -1 --pretty=format:"%s")"
git push origin HEAD:dev
else
echo "No submodule updates"
fi工作流功能便是合并子模块的最新提交,提交信息使用的是子模块最新的提交信息。
重点关注工作流的触发方式,这里使用的是 workflow_dispatch 。该方式可以在仓库网页里的工作流标签中手动触发,也可以使用接口来触发,Webhook 采用的便是后者。

最后添加 update-submodules.yml 文件到 Git 仓库,提交并推送到 Gitea。
准备 Gitea 接口密钥和部署密钥
接口密钥用于 Webhook 发送工作流触发请求;部署密钥用于授权工作流对博客和文章仓库的拉取和推送操作。
创建接口密钥
依次选择:设置 => 应用 => 管理 Access Token 。然后,生成一个 Gitea API 访问令牌。

生成的密钥字段保存好,后面配置 Webhook 时会用到。

配置部署密钥
使用 ssh-keygen 创建密钥
# -f 后面是文件名称,如果没有该参数,将默认生成到 $HOME/.ssh
# 添加这个是为了更改默认生成的位置
# -C 为备注内容,会被添加到公钥末尾
ssh-keygen -t ed25519 -C "deploy@mtfh.cc" -f id_ed25519
为 Gitea Actions 添加密钥和为仓库添加部署密钥参考创建 Gitea Actions |Vuepress 自动化部署(基于 Gitea Actions)
配置「文章」仓库的 Webhook
前往仓库设置 => Web 钩子 => 添加 Web 钩子 => Gitea

填写接口地址,设置接口访问密钥等一系列参数设置

模拟发送请求,应该发送失败——前面添加的工作流并不在 main 分支中。
功能测试与验证
默认的 Webhook 推送只能触发主分支的工作流,但测试只能使用 dev 分支或其他。这样一来在正式发布前,就无法进行基础的流程测试了。
一个比较笨的方法就是本地镜像一个 Gitea 服务,使用镜像的主分支测试。因为曾经做过 Gitea 备份,想要本地镜像一个很简单,甚至之前做测试时有一个现成的。
另一种方式是,单步验证——分别验证 Action 触发情况和 Webhook 的发送情况。
单步验证的方式,可以规避人为的粗心大意导致的问题。比如
update-submodules.yml便是在多次执行验证之后得到的结果。
推送文章更新, 验证 Webhook 触发情况
配置好 Webhook 后,除了测试推送外,随意修改点内容推送到 Gitea 就可以看到,Webhook 发送记录。
模拟 Webhook 请求,验证 Actions 执行情况
由于默认的 Webhook 只能触发主分支工作流,因此想要验证工作流正确与否,就需要手动构造并发送 Webhook 请求。
curl 命令发送请求示例:
curl -X POST
-H "Content-Type: application/json"
-H "Authorization: token <your api token>" \
https://<your domain>/api/v1/repos/<username>/<repo>/actions/workflows/<workflow id>/dispatches
-d '{"ref": "dev"}'除了使用 curl 命令外,还可以使用 Postman 、Apiforx 等图形化工具。Apifox 以项目的角度管理接口,除了设计接口,还可以通过多种方式导入接口。将 Gitea 的接口导入进来,测试和查找接口就比较方便了。



获取子模块最新提交信息的方法研究
观察前面的工作流文件,可以看到,我是通过以下命令获取子仓库的最新提交信息的:
git -C src/posts log -1 --pretty=format:"%s"最初的思路并不打算使用命令的方式来获取子仓库的提交信息,因为 Webhook 的推送数据中包含相关信息,请求体样本如下:
{
"ref": "refs/heads/dev",
"before": "c07cc3900253bb43a682cc4ed354c225ed472867",
"after": "2518d11a6ef532597e4490aec36f1c3570d0aa7d",
"compare_url": "https://gitea.mtfh.cc/mtfhx/blog-posts/compare/c07cc3900253bb43a682cc4ed354c225ed472867...2518d11a6ef532597e4490aec36f1c3570d0aa7d",
"commits": [
{
"id": "2518d11a6ef532597e4490aec36f1c3570d0aa7d",
"message": "Posts: 2025-09-21 11:11:48\n",
"url": "https://gitea.mtfh.cc/mtfhx/blog-posts/commit/2518d11a6ef532597e4490aec36f1c3570d0aa7d",
"author": {
"name": "Happilys",
"email": "happilys_mtfh@sina.com",
"username": "mtfhx"
},
"committer": {
"name": "Happilys",
"email": "happilys_mtfh@sina.com",
"username": "mtfhx"
},
"verification": null,
"timestamp": "2025-09-21T11:11:48+08:00",
"added": [],
"removed": [],
"modified": [
".obsidian/core-plugins.json",
".obsidian/workspace.json"
]
}
],
"total_commits": 1,
"head_commit": {
"id": "2518d11a6ef532597e4490aec36f1c3570d0aa7d",
"message": "Posts: 2025-09-21 11:11:48\n",
"url": "https://gitea.mtfh.cc/mtfhx/blog-posts/commit/2518d11a6ef532597e4490aec36f1c3570d0aa7d",
"author": {
"name": "Happilys",
"email": "happilys_mtfh@sina.com",
"username": "mtfhx"
},
"committer": {
"name": "Happilys",
"email": "happilys_mtfh@sina.com",
"username": "mtfhx"
},
"verification": null,
"timestamp": "2025-09-21T11:11:48+08:00",
"added": [],
"removed": [],
"modified": [
".obsidian/core-plugins.json",
".obsidian/workspace.json"
]
},
// 以下内容省略
}经过一番尝试后——使用 toJSON(github.event) 打印出 github.events 对象,发现没有提交信息相关内容,也就宣告这种方式在当前的 Gitea 版本(1.24.5)中不适用。
(问 AI)调研一番后,才决定使用命令来获取提交信息。
尝试后,给我一种与下面例子类似的感觉。
卖方已经将货物的重量和数量报给对方海关。货物运输抵达后,咨询我方海关货物重量和数量信息,被告知没有相关数据。取货后,只好自行为货物称重和计数。
版本上线
九月底实际上线时,出现了些小问题。更新了 Vuepress 版本之后,NodeJS 的最低版本需要 20 以上。当初作自动化部署时使用的版本是 18 ,部署方式使用的官方预编译的二进制安装的。
使用 Linux 预编译的二进制安装方式如下
wget https://nodejs.org/dist/v22.20.0/node-v22.20.0-linux-x64.tar.xz
tar -xvzf node-v22.20.0-linux-x64.tar.xz && cd node-v22.20.0-linux-x64
install -m 755 bin/* /usr/local/bin/
cp -r include/* /usr/local/include/
cp -r lib/* /usr/local/lib/
cp -r share/* /usr/local/share/后面有必要把文档编译过程扔到容器里完成。
因为博客仓库的主分支设置了分支保护,白名单设置里,只允许我自己向主分支推送。要么取消白名单保护,要么将部署密钥添加到用户级(尚未验证)。
懒得再去重新添加密钥,就取消了白名单保护——只要密钥拥有写权限,就可以推送提交。
自动同步子仓库的失败尝试
Gitea 1.22.2 版本不支持通过接口来触发工作流,但是可以通过评论工单的方式来变相触发工作流 。
基于评论工单的方式触发工作流,工作流文件需要放在 .github 目录下,触发方式为 issue_comments ,并且 .gitea 和 .github 只能存在一个。
为了自定义工单评论请求的请求体,就需要手动构造请求,让 Gitea Actions 执行 curl 命令来发送这份请求。另外,只要有文章更新,这一流程会被反复触发。工单系统会因为工作流的反复触发而导致数据污染,当然如果不介意的话倒也没问题。
实际考量,如果想获得子模块的自动同步的话,更新 Gitea 是最根本方式;如果项目急需上线的话,便只能如此了。但,后续还是应该升级 Gitea ,并改为 Webhook 的方式。
系统维护除了解决一个个具体问题外,还需要疏通各个通路和问题解决后的收尾工作。
否则在面对紧急问题时哪头都堵,不得已作出各种让步;随之而来的便是系统维护代价越来越高,以至于走向崩溃。
待续
该功能作为博客文章一键发布功能之一,然而本地写作流程还没有具体方案。做这些的主要目标便是搭建一个契合自己的内容输出平台,也是学习闭环中的关键流程。
目前的创作流程还比较粗糙,学习、实践和记录三者同时进行,结束后(成功抑或失败)再编写文章总结。与此同时还需要去对关键步骤进行还原,为文章提供素材。文章草稿完成后,再校验和发布。整个流程走下来还是比较漫长的,除了文章的编辑过程,还有发布流程的改进。
该功能上线之后,只需推送 「文章」仓库的提交便搞定了,不需要手动地合并子仓库的提交了。
而文章的创作流程有待进一步改进……
先在笔记中罗列大纲,编辑为草稿;移到「文章」仓库,补充素材(图片、流程图)、链接和参考文献等,创建提交并推送到 Gitea,然后去主仓库合并更新并推送提交。
参考
- Git子模块合并错误-ChatGPT
- API 使用指南 | Gitea Documentation
- Webhooks | Gitea Documentation
- Workflow syntax for GitHub Actions - GitHub Docs
- 变量参考 - GitHub 文档
- Actions - Manually trigger a workflow/action · Issue #23668 · go-gitea/gitea
- Actions support workflow dispatch event by pangliang · Pull Request #28163 · go-gitea/gitea
- 导入 OpenAPI/Swagger - Apifox 帮助文档
- 生成新的 SSH 密钥并将其添加到 ssh-agent - GitHub 文档
