DEBUG.WIKI
ZgoCloud:多地区部署,按需选节点;日本、美国、香港、德国
搬瓦工;先看线路,再选 VPS;CN2 GIA · 对应线路套餐;查看线路 →
V.PS:让项目靠近用户,亚太、欧洲、北美 KVM VPS

Cargo 在 GitLab CI 报 os error 2,检查复用工作区的子模块

Cargo1.98.0打包在子模块状态检查中失败,干净克隆可通过。区分未初始化与残留元数据,按包的真实依赖选择clone或显式子模块检出。

GitLab CI 中执行 Cargo 1.98.0 的打包或发布流程,只报 No such file or directory (os error 2),而仓库里的 Cargo.toml 和源码都在。若跟踪日志停在 cargo::ops::cargo_package::vcs::status_submodules,先检查 Runner 复用的 Git 工作区与子模块状态,不要马上重写 manifest 路径。

这里有一个重要条件:同一项目在复用、重新初始化已有仓库的作业里失败,而采用全新克隆的作业可以通过。仅看到 Skipping Git submodules setup,还不足以把所有未初始化子模块的项目都判为会失败。

报错来自打包前的仓库状态检查

Cargo 1.98.0 在制作包时会检查 Git 状态并递归查看子模块。相应实现调用 submodule.open(),返回的错误可以直接向上传播。一个完全未初始化的子模块可能被识别为不存在而跳过;已有 Git 元数据却打不开,是另一种状态。

这也解释了为什么 --allow-dirty、--no-verify 没有绕过这里:允许未提交修改,不代表不再检查仓库;跳过打包后的编译验证,也不等于跳过制作包和 VCS 元数据处理。不要继续加参数去掩盖缺文件的位置。

保存失败作业的 Cargo 版本、工作区获取方式和第一条错误。在可控日志中临时打开 CARGO_LOG=trace 可以定位到这条调用链,但日志可能包含仓库路径或私有地址,应限制存放和访问范围。本文针对这个已定位的分支,普通的文件路径不存在仍需按实际报错处理。

为不需要子模块内容的作业选择干净克隆

如果发布包确实不依赖子模块文件,可以在专用作业中让 Runner 每次重新克隆,而不是继续复用这份状态异常的工作区。下面是合并到已有 GitLab 作业中的变量片段:

variables:
  GIT_STRATEGY: clone
  GIT_SUBMODULE_STRATEGY: none

clone 会由 Runner 清理已有工作副本并重新取得仓库。它适用于可重建的 CI 检出目录,不应拿来处理开发者尚未保存的工作;作业需要保留的构建结果应先走既有 artifacts 或缓存约定。全新克隆还会增加拉取成本。

这条调整不保证省略子模块后仍能打出正确包。先检查 Cargo 的 include/exclude、build.rs、符号链接以及包引用的 README、许可证文件,确认没有依赖那些目录。需要的文件缺失时,应把获取步骤补全。

需要子模块时,显式检出所需提交

项目确实依赖子模块,则按可信地址、访问权限和递归范围配置 GIT_SUBMODULE_STRATEGY: normal 或 recursive。前者只处理顶层,后者继续处理嵌套子模块;不要为方便获取未经检查的外部仓库,也不要自动追踪到远端最新提交。

在已有检出目录中核对状态与指定提交的含义,可参照子模块初始化与提交核对。不过,失败作业如果只有残留仓库元数据异常,单纯重复初始化不一定比一份干净、可复现的 CI 检出更可靠。不要先删除 .git/modules,那会破坏诊断材料,也可能影响仍有修改的子模块。

验证时先列出待打包文件,检查没有把私有配置或多余依赖带进包,再在不上传 registry 的打包步骤中验证相同仓库状态检查能否完成。原发布命令不能当成无限重试的探针;若已有上传尝试,先按 registry 的真实状态确认版本是否存在。工作区问题解决后,认证、依赖构建和发布权限仍须分别验收。