git 常见问题记录

八月 11, 2026 [杂项] #Git

工作中遇到的 git 常见问题,按主题持续补充。

子模块历史中引用的 commit 必须在远程可达

现象

Jenkins 构建时在 SCM checkout 阶段失败,还没有进入编译:

Fetching submodule cmake
 * [new branch]      xxx-db-tar -> origin/xxx-db-tar
fatal: git upload-pack: not our ref 869a283bf32a3ec38e4c4224e0babdad3c97e019
fatal: remote error: upload-pack: not our ref 869a283bf32a3ec38e4c4224e0babdad3c97e019
Errors during submodule fetch:
	cmake
ERROR: Error fetching remote repo 'origin'

背景

父仓库(这里用 xxx-tool-database 代替真名)的 refactor 分支历史中,较早的提交 ba5e751 引用过 cmake 子模块的提交 869a283。之后子模块被回退、新开了 xxx-db-tar 分支并推送,但 869a283 这个旧提交只存在于本地,从未推送到远程 xxx-cmake 仓库。

Jenkins 递归拉取子模块时,需要为父仓库 gitlink 引用的提交做 fetch,远程仓库里没有这个对象,于是报 not our ref。

原理:普通 git 与 Jenkins 的要求差异

普通 git 本身并不要求"父仓库所有历史引用的子模块 commit 都在远程":

但远程服务端(GitLab/GitHub)对 git fetch <明确 SHA> 有限制:默认只允许 fetch 在某个分支/标签上可达的对象(uploadpack.allowAnySHA1InWant 关闭)。所以子模块 commit 必须推到了远程某个 ref 上才能被 fetch。

Jenkins 的 SCM checkout 会对子模块做 fetch,把父仓库 gitlink 引用的 commit 取下来。当父仓库历史中引用过某个从未推送的子模块 commit 时,就会触发上述 not our ref 错误。

结论

父仓库历史中引用过的所有子模块 commit,都必须在子模块远程仓库的某个 ref 上可达,否则 Jenkins 递归拉取子模块会失败。推父仓库分支到上游前,先确认历史中引用过的子模块提交都已在远程推送。

排查方法

列出父仓库历史中引用的子模块提交:

git log --format='%h %s' -- <submodule-path>

逐个确认这些提交是否在子模块远程分支上可达:

git -C <submodule> merge-base --is-ancestor <sha> origin/master
git -C <submodule> merge-base --is-ancestor <sha> origin/<branch>

缺失时补推一个临时分支即可:

git -C <submodule> push origin <sha>:temp-<short-sha>