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 都在远程":
- clone 父仓库时,gitlink 只记录一个 SHA(160000 模式条目),不做可达性校验;
- 只有执行
git submodule update --init时,才需要当前 gitlink 指向的那一个 commit 的对象可获取; - 因此普通 git 只关心"现在要 checkout 的那个 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>