You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将Git子模块作为独立仓库完整克隆?

问题背景

子模块可以作为独立仓库添加到主仓库中,此时每个子模块都拥有自己的.git目录:

[submodule-test] $ mkdir super-repo
[submodule-test] $ cd super-repo/
[super-repo] $ mkdir sub-repo
[super-repo] $ cd sub-repo/
[sub-repo] $ git init
Initialized empty Git repository in /home/foobar/tmp/submodule-test/super-repo/sub-repo/.git/
[sub-repo] $ touch foo.txt
[sub-repo] $ git add foo.txt
[sub-repo] $ git commit -m "* initial commit"
[main (root-commit) 60c3e14] * initial commit
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 foo.txt
[sub-repo] $ cd ..
[super-repo] $ git init
Initialized empty Git repository in /home/foobar/tmp/submodule-test/super-repo/.git/
[super-repo] $ git submodule add ./sub-repo sub-repo
Adding existing repo at 'sub-repo' to the index
[super-repo] $ git commit -m "* initial commit"
[main (root-commit) 826f205] * initial commit
 2 files changed, 4 insertions(+)
 create mode 100644 .gitmodules
 create mode 160000 sub-repo
[super-repo] $ file sub-repo/.git
sub-repo/.git: directory

但克隆主仓库后,子模块的.git会变成指向主仓库的文本文件,不再是独立目录。以下克隆命令的参数是为了:

  • 允许文件系统内克隆
  • 模拟真实场景:存在大量嵌套远程子模块,无法逐个处理,需要自动化操作,且子模块默认分支各不相同
[super-repo] $ cd ..
[submodule-test] $ mkdir clone-of-super
[submodule-test] $ cd clone-of-super/
[clone-of-super] $ git -c protocol.file.allow=always clone --recurse-submodules --remote-submodules ../super-repo
Cloning into 'super-repo'...
done.
Submodule 'sub-repo' (/home/foobar/tmp/submodule-test/clone-of-super/../super-repo/sub-repo) registered for path 'sub-repo'
Cloning into '/home/foobar/tmp/submodule-test/clone-of-super/super-repo/sub-repo'...
done.
Submodule path 'sub-repo': checked out '60c3e1457a183d14a6af4ba9472e99d99e12de94'
[clone-of-super] $ cd super-repo/
[super-repo] $ file sub-repo/.git
sub-repo/.git: ASCII text
[super-repo] $ cat sub-repo/.git
gitdir: ../.git/modules/sub-repo

核心问题:如何克隆仓库,使得子模块作为拥有独立.git目录的独立仓库被克隆?


解决方案

Git默认把子模块的仓库数据存放在主仓库的.git/modules目录下,用gitdir文件指向该路径,目的是节省空间和统一管理。如果要让子模块恢复独立的.git目录,可以通过以下方法实现:

方法1:克隆后手动迁移单个子模块的.git目录

针对单个子模块,执行以下步骤:

  1. 进入子模块目录:
cd sub-repo
  1. 查看当前关联的git仓库路径:
cat .git
  1. 将主仓库.git/modules下的子模块仓库目录,移动到当前子模块目录下并重命名为.git:
mv ../.git/modules/sub-repo .git
  1. 重置子模块确保版本关联正常:
git reset --hard

方法2:脚本批量处理嵌套子模块

如果有大量嵌套子模块,编写shell脚本自动化处理:
创建fix-submodules.sh脚本:

#!/bin/bash
# 递归遍历所有子模块,迁移.git目录
git submodule foreach --recursive '
  # 提取当前子模块关联的仓库路径
  GIT_REPO_PATH=$(cat .git | sed "s/gitdir: //")
  # 移动仓库目录到子模块本地
  mv "$GIT_REPO_PATH" .git
  # 重置子模块以修复关联
  git reset --hard
'

赋予执行权限并运行:

chmod +x fix-submodules.sh
./fix-submodules.sh

方法3:修改Git配置指定子模块.git位置

可以针对特定仓库配置子模块的.git目录路径:

# 为当前仓库的sub-repo子模块设置独立.git目录
git config submodule.sub-repo.gitdir sub-repo/.git

该方式需要提前知晓子模块名称,适合少量已知子模块的场景,大量嵌套子模块推荐使用脚本批量处理。


内容的提问来源于stack exchange,提问作者jhu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 11:25:09