Submodule 很适合由根仓固定多个独立仓库的精确版本,但它只记录一个提交指针,不保证该提交能被其他人获取。很多“本地一切正常、同事无法初始化”的问题,都来自忽略了远端可达性。
三个身份必须明确
每个子模块都需要唯一路径、权威远端和跟踪分支。跟踪分支只说明未来更新的来源,不代表每次都应该自动推进到最新提交。真正交付的是根仓索引中记录的精确 gitlink。
只更新受影响模块
开始前记录已初始化模块、当前提交、分支和工作区状态。只初始化任务需要的路径,不无差别更新全部模块;未知本地修改不得重置、覆盖或混入交付。
正确的交付顺序
先在子仓完成原生验证与提交,再正常推送或通过已授权的 PR 合入目标分支。随后 fresh fetch,并证明选定提交从权威远端目标分支可达。只有这一步通过,根仓才能更新 gitlink。PR 处于开放状态时,根指针保持不变。
在隔离环境验收
根仓变更完成后,用临时 clone 或干净 fixture 只初始化本次模块,检查远端映射、固定提交、目录边界和验证脚本。这样能发现本机对象缓存掩盖的“远端其实没有该提交”。
删除与替换更谨慎
删除子模块是破坏性操作,要同时处理配置、gitlink、Profile 和文档,并验证全新初始化不再依赖旧条目。未明确授权时,不清理用户本地的嵌套仓库数据。
可靠的 Submodule Harness 关注的是可复现性:任何人只凭根仓提交和相同权限,都应得到同一组子仓版本。
第二轮实践复核
可复用交付物: 子模块身份、固定提交可达性和隔离初始化记录。这些内容是从工程实践抽象出的通用方法,不包含内部仓库、真实工作项、业务数据、凭据、地址或实现源码。
最低验收: 临时 clone 能只凭根仓提交初始化到同一子仓版本。验收记录必须分开事实、推断、缺口和授权范围;只读检查不能自动扩展为提交、推送、评论或发布。
可执行的交付证明
更新前先保存机器可读清单:
1 | path=services/order |
.gitmodules 的 branch 只是 git submodule update --remote 的候选来源,根仓真正记录的是 mode 160000 的 gitlink。验收时直接检查 index 与子仓 HEAD,不能用目录内容“看起来是新的”代替。
1 | git ls-files --stage services/order |
最后一条只能证明提交是目标分支祖先;若团队允许标签、PR merge commit 或其他发布引用,应在 Profile 中明确对应可达规则。远端 URL、分支与 SHA 都来自已确认配置,不把占位符直接执行。
状态矩阵
| 子仓状态 | 根仓动作 |
|---|---|
| 有未知本地修改 | 停止,不 stash/reset |
| candidate 仅存在本机 | 停止,不更新 gitlink |
| PR 已开但未合入 | 等待,根指针不变 |
| 已从权威目标 ref 可达 | 允许进入组合验证 |
| 子仓验证失败 | 停止并保留原指针 |
干净环境验收与恢复
在临时目录克隆根仓的候选提交,执行 submodule sync 后只初始化本次路径,检查最终 SHA、远端映射和原生测试。再模拟本地对象缓存为空、浅克隆和无额外凭据,确保成功不是开发机偶然状态。
如果根提交已发布但 gitlink 不可达,最安全的恢复通常是提交一个新根仓修正,把指针指回上一可达 SHA;不要强推重写共享历史。删除子模块时先提交不再引用它的业务变化,再处理 .gitmodules、gitlink 与文档;用户工作区中的嵌套仓库数据不在自动清理授权内。
公开规范
规范复核日期:2026-08-22。
小规模演练
在子仓验证并发布一个测试提交,证明远端目标可达后更新 gitlink,再用临时 clone 单独初始化。
- 失败注入: 故意提供一个缺字段、过期版本或无权限目标,确认流程停在预定门禁。
- 观测指标: 不可达 gitlink 数、初始化失败数、无关指针移动数。
- 回滚方法: 任一步失败都不更新根仓;已更新但未发布时回退 gitlink 到上一可达提交。
评论