使用Git备份含嵌套Git仓库的项目时克隆子模块文件夹为空
问题根因
克隆后嵌套仓库文件夹为空,本质是两个核心问题导致的:
- Git子模块的机制本身就不会在主仓库存储子模块的实际文件,主仓库只会记录每个子模块对应的远程地址、以及当前绑定的子模块commit哈希。普通
git clone默认不会拉取子模块内容,自然会显示空文件夹。 - 你的现有配置和脚本存在逻辑错误:
- 给备份仓库添加远程时使用了
--mirror=fetch参数,该参数用于仓库镜像全量同步场景,会强制本地引用和远程完全对齐,不适合作为存放子模块引用的普通备份仓库使用,会导致子模块引用记录推送异常。 - 原有
find命令没有加深度限制,会递归遍历所有层级的目录,包括子模块内部的.git目录,会出现嵌套重复添加子模块的问题;同时没有做重复添加判断,二次运行脚本就会抛出子模块已存在的错误。
- 给备份仓库添加远程时使用了
修复方案
按以下步骤操作即可正常实现备份效果:
- 第一步:重置备份仓库的远程配置,移除错误的mirror模式绑定
进入本地D:\Projekts目录,执行以下命令:git remote remove origin git remote add origin git@<备份服务器IP>:backup.git - 第二步:替换原有子模块添加脚本,修复递归遍历、重复添加的问题
cd "D:\Projekts" # 清理之前残留的错误子模块缓存 rm -rf .git/modules/* git rm --cached -r . 2>/dev/null # 限制遍历深度,只识别直接存放在项目目录下的独立Git仓库,不递归进入子仓库内部 find . -maxdepth 2 -type d -name ".git" | while read gitdir ; do submod_path=$(dirname "${gitdir}") cd "${submod_path}" origin_url=$(git config --get remote.origin.url) cd - 1>/dev/null # 跳过已经添加过的子模块,避免重复执行报错 if ! git config --file .gitmodules --get submodule."${submod_path}".url >/dev/null 2>&1; then echo "Adding submodule: ${submod_path}" git submodule add "${origin_url}" "${submod_path}" fi done echo "All submodules added" - 第三步:正常提交推送备份内容
git add .gitmodules . git commit -m "new backup" # 替换成你自己使用的分支名,比如master、main都可以 git push -u origin main echo "Backup push completed" - 第四步:克隆备份时拉取子模块内容
后续恢复备份时,不能直接用普通clone命令,需要加递归参数拉取所有子模块的实际文件:
如果已经执行过普通克隆、文件夹为空,进入克隆后的仓库目录执行以下命令即可拉取所有子模块内容:git clone --recurse-submodules git@<备份服务器IP>:backup.gitgit submodule update --init --recursive
补充说明:子模块方案只会在主备份仓库保存引用关系,所有子仓库的实际内容还是存放在你服务器上对应的独立Git仓库中,做备份前要确认每个独立子仓库的最新提交都已经推送到服务器。如果你希望把所有文件内容直接存到主备份仓库、不需要保留子仓库独立的提交历史,可以在遍历过程中先删除每个嵌套目录下的
.git文件夹,再统一执行git add .提交即可。
内容的提问来源于stack exchange,提问作者Hazel
相关产品推荐
相关产品推荐

