本技能介绍在 Kotlin Multiplatform 仓库中把 git submodule 当作一组 Gradle 模块使用的方法。子模块本身只是一棵模块目录树,没有 settings 文件,也没有根构建脚本;只有父构建的 settings 文件才能把这些目录变成 Gradle 项目。技能给出 .gitmodules 与 settings.gradle.kts 的示例:通过 include 声明项目,并用 projectDir 把扁平的 Gradle 路径指向子模块内的实际目录,使磁盘路径位于另一个仓库的两层目录之下。
主要能力在于梳理这种映射方式带来的额外陷阱。其一,普通克隆会得到空目录,projectDir 指向没有构建脚本的目录,构建直到第一个依赖该映射项目的模块时才失败,并报告某个项目“不存在”,报错指向新贡献者从未听过的模块。可用 git submodule status 检查,行首为 - 表示未初始化;修复方式分为对尚未发生的克隆执行 git clone --recurse-submodules,以及对已有仓库执行 git submodule update --init --recursive。技能建议把递归克隆命令放进 README 第一个代码块。
其二,CI 检出默认不拉取子模块,需要显式配置 submodules: 'recursive'。技能给出一条可用于审计的判断规则:任何需要配置构建的任务都需要子模块,只搬运产物的任务则不需要;并提供一个遍历 .github/workflows/*.yml 统计 checkout 次数与递归检出次数的 shell 循环,同时提醒不要看到数字差距就下结论,要读懂差距对应的是哪个任务。
其三,父仓库记录的是子模块的提交指针。移动共享代码涉及两次提交:先在子模块推送,再在父仓库提交指针,顺序不能颠倒。可用 git diff 查看“Subproject commit”变动来确认指针移动。若本地正常而 runner 构建旧代码,通常是第二次提交未暂存。检出跟随的是记录中的提交而非分支,除非 .gitmodules 中配置 branch 并执行 git submodule update --remote。
其四,不要给子模块单独的 settings 文件,因为 settings 文件标识构建边界,会让同一批目录被父构建映射和该文件重复认领;可用 ls 检查子模块根下不存在 settings.gradle* 与 build.gradle*。此外,映射应以 rootDir 为锚点,避免相对向上查找,防止误绑到同名兄弟检出。
使用方式部分给出验证流程:故意执行不带标志的 git clone 到临时目录,确认 git submodule status 每行都以 - 开头;再从该状态执行 git submodule update --init --recursive,并用 find 统计子模块内 build.gradle.kts 数量、用 grep 统计 settings.gradle.kts 中的 projectDir 数量,两者应一致。
适用场景为在 Kotlin Multiplatform 项目中复用共享模块、需要在多应用间消费同一棵模块树并保持扁平 Gradle 路径的团队,尤其适合排查子模块相关构建失败与 CI 与本地不一致的问题。限制方面,资料未提供该技能所依赖的具体插件、版本要求、安装命令或使用入口,暂未提供。