工作原理
对每一条「目录 → 镜像」的映射,同步做的都是同一件事:main 是一条线性历史,所以第一次初始化之后,后面每次推送都能快进更新镜像的 main。同步只在改动合并进主仓 main 后才触发,而且只碰本次改动涉及的 prefix(连同它上面每一级的祖先目录)。
脚本:scripts/sync_to_mirrors.sh
那张映射表(12 条)就写在脚本里,脚本和工作流都以它为准。
| 模式 | 作用 |
|---|---|
--all | 同步全部镜像(第一次初始化时用) |
--changed BEFORE..AFTER | 只同步这个提交区间内有改动的 prefix |
<prefix> [<prefix>…] | 只同步指定的目录 |
--force | 强制推送(第一次初始化、或历史分叉后必须加) |
--dry-run | 只打印要执行的命令,不真的推 |
- CI 里:设了
MIRROR_SYNC_TOKEN,就走https+Authorization头推送。 - 本地:不设令牌,就走 SSH(
git@github.com:AgentEndeavour/<repo>.git),用你自己的密钥推。
git subtree(git 自带)。
CI 工作流:.github/workflows/mirror-sync.yml
- push 到 main:拿
github.event.before..github.sha算出改动区间,只同步被影响的镜像;如果是仓库的第一次 push(区间是全零),就自动退回成--all。 - 手动触发(
workflow_dispatch):用来做初始化,可以勾上all和force。 - checkout 用了
fetch-depth: 0(subtree split 需要完整历史);MIRROR_SYNC_TOKEN从 secret 注入。
配置 MIRROR_SYNC_TOKEN(维护者,一次性)
工作流需要一个对 12 个镜像仓库有 contents:write 权限的凭证,放在仓库 secret MIRROR_SYNC_TOKEN 里。两种做法二选一:
- 细粒度 PAT:对
AgentEndeavour下这 12 个镜像仓库授予 Contents: Read and write。 - GitHub App:装到这些仓库上、授予
contents:write,再用它签发 token。
MIRROR_SYNC_TOKEN 的 secret。
第一次初始化镜像(一次性)
扁平化那个 PR 合并进main 之后,做一次初始化:把各镜像和 monorepo 对齐,建立起 subtree 的同步关系。
如果镜像
main 开了分支保护,得允许这个令牌 / App 往里推(或者临时把保护放宽)。初始化之前,先把镜像仓库上还没处理的 PR 收拾干净(合并或关掉)——从这一步起,镜像就是只读的下游了。在本地手动同步
有需要的话,本地也能跑(用你自己的 SSH 密钥):排障
推送被拒(non-fast-forward)
推送被拒(non-fast-forward)
镜像
main 和 monorepo 这边的 subtree 历史对不上了(多半是还没初始化,或者有人直接改了镜像)。对这个 prefix 加 --force 重跑一遍就行;旧提交还能靠 pre-monorepo-* 标签找回来。CI 报错:缺少 MIRROR_SYNC_TOKEN
CI 报错:缺少 MIRROR_SYNC_TOKEN
secret 还没配,或者令牌没有
contents:write。照上面那节建好、授好权即可。镜像 main 有分支保护
镜像 main 有分支保护
放行这个令牌 / App 往
main 推,或者临时放宽保护,再做初始化。git subtree: command not found
git subtree: command not found
跑的环境里没有
git subtree(contrib 组件)。CI(ubuntu)上 git 自带;本地装个完整版的 git 就有了。相关
开发与贡献流程(含仓库模型)
monorepo 结构、目录 → 镜像映射,以及分支 → PR → 合并到 main → 自动同步的完整循环。
代码规范与提交检查
pre-commit + Ruff / dart 的安装与日常使用。