Git-子模块-子树合并-多仓逻辑聚合


在 Gitee 中,要在一个代码仓库(主仓库)中嵌入多个其他仓库(子仓库),核心是利用 Git 原生的子模块(Submodule)子树合并(Subtree Merge) 功能——这两种方法均兼容 Gitee(本质是 Git 仓库托管),且能实现“主仓库关联子仓库、保持同步更新”的需求,具体选择哪种取决于你的使用场景(是否需要子仓库独立维护、是否希望子仓库代码融入主仓库历史等)。

一、核心方法对比(先选对方案)

特性 子模块(Submodule) 子树合并(Subtree Merge)
本质 主仓库存储子仓库的“引用”(Commit ID + 地址) 子仓库代码完全合并到主仓库,形成统一历史
子仓库独立性 强(子仓库仍是独立 Git 仓库) 弱(子仓库代码融入主仓库,无独立引用)
主仓库体积 小(仅存引用,子仓库代码需单独拉取) 大(包含子仓库所有代码)
同步子仓库更新 需手动更新子模块引用 可直接拉取子仓库分支合并到主仓库
提交影响 主仓库仅提交“子模块引用变更”,不影响子仓库 主仓库提交可能包含子仓库代码修改(需手动推子仓库)
适用场景 子仓库独立维护、多项目复用(如公共组件库) 希望子仓库代码融入主仓库、简化部署(如单仓库部署)

推荐优先用「子模块」:大多数场景下(如主项目依赖多个独立维护的工具库、组件库),子模块更灵活,不会污染主仓库历史,且子仓库更新不影响主仓库稳定性。

二、方法一:子模块(Submodule)—— 推荐方案

核心逻辑

主仓库中创建一个“子目录”,该目录关联到目标子仓库,主仓库仅存储子仓库的 当前 Commit ID仓库地址,子仓库代码需单独拉取/更新,且子仓库的提交完全独立。

操作步骤(全程命令行,Gitee 网页端仅需创建仓库)

1. 准备工作

  • 已创建 主仓库(如 main-repo),并克隆到本地: bash git clone https://gitee.com/你的用户名/main-repo.git cd main-repo # 进入主仓库目录
  • 需嵌入的 子仓库 已存在(如 sub-repo1sub-repo2),获取其 Gitee 克隆地址(如 https://gitee.com/你的用户名/sub-repo1.git)。

2. 添加子模块

在主仓库中执行 git submodule add,指定子仓库地址和本地存储路径(路径建议用子仓库名,如 submodules/sub-repo1):

# 格式:git submodule add 子仓库地址 本地存储路径
git submodule add https://gitee.com/你的用户名/sub-repo1.git submodules/sub-repo1
git submodule add https://gitee.com/你的用户名/sub-repo2.git submodules/sub-repo2
  • 执行后,主仓库会生成两个关键文件:
  • .gitmodules:记录子模块的关联配置(仓库地址、本地路径),需提交到主仓库。
  • 子仓库路径(如 submodules/sub-repo1):作为“引用目录”,内部是子仓库的代码(但主仓库仅追踪其 Commit ID)。

3. 提交主仓库变更

添加子模块后,主仓库会有未提交的变更(.gitmodules 和子模块路径),需提交并推送到 Gitee:

git add .gitmodules submodules/sub-repo1 submodules/sub-repo2
git commit -m "添加子模块 sub-repo1 和 sub-repo2"
git push origin main  # 推送到主仓库的主分支(如 main/master)

4. 查看 Gitee 效果

刷新主仓库的 Gitee 网页端,会看到 submodules/sub-repo1 目录显示为 蓝色链接,点击可直接跳转到子仓库——这是子模块的标志性特征,表明该目录关联了独立仓库。

5. 克隆包含子模块的主仓库(他人协作时)

如果他人克隆你的主仓库,默认不会自动拉取子模块的代码,需额外执行以下命令:

# 方法1:克隆主仓库时同时拉取子模块(推荐)
git clone --recursive https://gitee.com/你的用户名/main-repo.git

# 方法2:已克隆主仓库,后续拉取子模块
cd main-repo
git submodule init  # 初始化子模块配置(读取 .gitmodules)
git submodule update  # 拉取子模块的代码(基于主仓库记录的 Commit ID)

6. 同步子仓库的更新(子仓库有新提交时)

如果子仓库(如 sub-repo1)有新的代码提交,需在主仓库中更新子模块的引用:

# 进入子模块目录,拉取最新代码
cd submodules/sub-repo1
git pull origin main  # 拉取子仓库的主分支最新代码
cd ../..  # 回到主仓库目录

# 主仓库会检测到子模块的 Commit ID 变更,提交该变更
git add submodules/sub-repo1
git commit -m "更新子模块 sub-repo1 到最新版本"
git push origin main

7. 删除子模块(如需移除)

# 1. 移除子模块引用
git submodule deinit -f submodules/sub-repo1
# 2. 删除子模块目录
rm -rf submodules/sub-repo1
# 3. 删除 .gitmodules 中的对应配置
git config -f .gitmodules --remove-section submodule.submodules/sub-repo1
# 4. 提交变更
git add .gitmodules
git commit -m "删除子模块 sub-repo1"
git push origin main

三、方法二:子树合并(Subtree Merge)—— 备选方案

核心逻辑

将子仓库的某个分支(如 main)完全合并到主仓库的一个目录下,子仓库代码会融入主仓库的提交历史,主仓库中看不到“子仓库引用”,仅显示普通目录和文件。适合需要将子仓库代码“打包”进主仓库、无需子仓库独立维护的场景。

操作步骤

1. 准备主仓库(同子模块步骤1)

克隆主仓库并进入目录:

git clone https://gitee.com/你的用户名/main-repo.git
cd main-repo

2. 添加子仓库为“远程仓库”

给主仓库添加子仓库的远程地址(命名为 sub-repo1,方便后续引用):

git remote add -f sub-repo1 https://gitee.com/你的用户名/sub-repo1.git
git remote add -f sub-repo2 https://gitee.com/你的用户名/sub-repo2.git
  • -f:添加远程时同时拉取子仓库的代码。

3. 合并子仓库到主仓库的指定目录

使用 git subtree add 将子仓库的分支合并到主仓库的目录(如 subtrees/sub-repo1):

# 格式:git subtree add --prefix=本地目录 远程仓库名 子仓库分支
git subtree add --prefix=subtrees/sub-repo1 sub-repo1 main --squash
git subtree add --prefix=subtrees/sub-repo2 sub-repo2 main --squash
  • --prefix=subtrees/sub-repo1:指定子仓库代码在主仓库中的存储目录。
  • --squash:将子仓库的所有提交压缩为一个提交,避免主仓库历史过于冗长(可选,不加则保留子仓库完整历史)。

4. 提交并推送到 Gitee

git commit -m "合并子仓库 sub-repo1 和 sub-repo2 到 subtrees 目录"
git push origin main

5. 同步子仓库的更新(子仓库有新提交时)

# 1. 拉取子仓库的最新代码
git fetch sub-repo1 main
# 2. 合并到主仓库的子树目录
git subtree pull --prefix=subtrees/sub-repo1 sub-repo1 main --squash
# 3. 提交并推送
git commit -m "同步子仓库 sub-repo1 最新更新"
git push origin main

6. 从主仓库推送修改到子仓库(如需修改子仓库代码)

如果在主仓库中修改了子树目录(如 subtrees/sub-repo1)的代码,可推送到原教子仓库:

git subtree push --prefix=subtrees/sub-repo1 sub-repo1 main

四、关键注意事项

  1. 子模块的“引用一致性”:主仓库存储的是子模块的固定 Commit ID,他人协作时需确保拉取子模块的对应版本(否则可能出现代码不一致)。
  2. 子树的冲突处理:子树合并后,主仓库和子仓库的代码在同一目录下,若有文件同名可能出现冲突,需手动解决。
  3. Gitee 网页端操作限制:子模块和子树的添加/更新均需通过本地 Git 命令行操作,Gitee 网页端仅支持查看(子模块显示为链接,子树显示为普通目录)。
  4. 仓库权限:主仓库的协作者需同时拥有子仓库的读取权限(子模块)或写入权限(子树推送修改),否则无法拉取/推送子仓库代码。

总结

  • 若子仓库需独立维护、多项目复用 → 选 子模块(Submodule)(Gitee 显示蓝色链接,灵活且不污染主仓库)。
  • 若需将子仓库代码融入主仓库、简化部署 → 选 子树合并(Subtree)(Gitee 显示普通目录,代码一体化)。

两种方法均完全兼容 Gitee,核心操作依赖 Git 原生功能,无需 Gitee 额外配置,按步骤执行即可实现“一个主仓库嵌入多个子仓库”的需求。