Git实践

Git Submodule 交付:固定提交不等于交付完成

2026-06-08 #多仓协作#Git Submodule#发布治理

Submodule 很适合由根仓固定多个独立仓库的精确版本,但它只记录一个提交指针,不保证该提交能被其他人获取。很多“本地一切正常、同事无法初始化”的问题,都来自忽略了远端可达性。

三个身份必须明确

每个子模块都需要唯一路径、权威远端和跟踪分支。跟踪分支只说明未来更新的来源,不代表每次都应该自动推进到最新提交。真正交付的是根仓索引中记录的精确 gitlink。

只更新受影响模块

开始前记录已初始化模块、当前提交、分支和工作区状态。只初始化任务需要的路径,不无差别更新全部模块;未知本地修改不得重置、覆盖或混入交付。

正确的交付顺序

先在子仓完成原生验证与提交,再正常推送或通过已授权的 PR 合入目标分支。随后 fresh fetch,并证明选定提交从权威远端目标分支可达。只有这一步通过,根仓才能更新 gitlink。PR 处于开放状态时,根指针保持不变。

在隔离环境验收

根仓变更完成后,用临时 clone 或干净 fixture 只初始化本次模块,检查远端映射、固定提交、目录边界和验证脚本。这样能发现本机对象缓存掩盖的“远端其实没有该提交”。

删除与替换更谨慎

删除子模块是破坏性操作,要同时处理配置、gitlink、Profile 和文档,并验证全新初始化不再依赖旧条目。未明确授权时,不清理用户本地的嵌套仓库数据。

可靠的 Submodule Harness 关注的是可复现性:任何人只凭根仓提交和相同权限,都应得到同一组子仓版本。

第二轮实践复核

可复用交付物: 子模块身份、固定提交可达性和隔离初始化记录。这些内容是从工程实践抽象出的通用方法,不包含内部仓库、真实工作项、业务数据、凭据、地址或实现源码。

最低验收: 临时 clone 能只凭根仓提交初始化到同一子仓版本。验收记录必须分开事实、推断、缺口和授权范围;只读检查不能自动扩展为提交、推送、评论或发布。

可执行的交付证明

更新前先保存机器可读清单:

1
2
3
4
5
6
path=services/order
url=ssh://git.example.invalid/order.git
configured_branch=release/2.4
old_gitlink=<sha-old>
candidate_gitlink=<sha-new>
working_tree=clean

.gitmodules 的 branch 只是 git submodule update --remote 的候选来源,根仓真正记录的是 mode 160000 的 gitlink。验收时直接检查 index 与子仓 HEAD,不能用目录内容“看起来是新的”代替。

1
2
3
4
git ls-files --stage services/order
git -C services/order rev-parse HEAD
git -C services/order fetch origin release/2.4
git -C services/order merge-base --is-ancestor <sha-new> origin/release/2.4

最后一条只能证明提交是目标分支祖先;若团队允许标签、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 到上一可达提交。
评论
分享

评论