如何将子目录的Git仓库合并到主项目并保留提交记录?
场景还原
我在本地开发一个项目时,先在dataset子文件夹下创建了Git仓库,用于管理数据集相关的代码和版本控制。随着项目扩大,我需要将整个项目(包含dataset子目录)上传到GitHub,但希望保留dataset文件夹的独立提交历史。
问题核心:
如何将一个已存在独立Git仓库的子目录(dataset),合并到主项目的Git仓库中,同时保留其完整的提交记录?
解决方案:使用Git Subtree合并仓库
Git Subtree 允许将一个仓库作为子目录嵌入到另一个仓库,并保留完整历史记录。与Submodule不同,Subtree会将代码完全合并到主仓库,更适合需要频繁修改子目录内容的场景。
操作步骤:
1. 初始化主项目仓库
# 进入项目根目录
cd C:\Users\hollow\YKF2a
# 初始化Git仓库并创建main分支
git init -b main
# 添加文件并提交初始版本
git add .
git commit -m "Initial commit for main project"2. 使用Subtree添加子仓库
# 语法:git subtree add --prefix=<子目录名> <子仓库路径> <分支名>
git subtree add --prefix=dataset C:\Users\hollow\毕业论文\dataset main• --prefix=dataset:指定子目录名称为dataset
• 子仓库路径:本地或远程仓库地址(此处为本地绝对路径)
• 分支名:要合并的子仓库分支(此处为main)
3. 验证结果
git log --oneline --graph
# 输出示例
* cdbed89 (HEAD -> main) Add 'dataset' via subtree
|\
| * 3a2b1c0 (subproject/main) [dataset] Update data processing
| * 8f7e6d5 [dataset] Initial dataset commit
* 9a8b7c6 Initial commit for main project此时dataset目录已合并到主项目,且提交历史完整保留。
关键点解析
- 为什么不用Submodule?
Submodule仅保存子仓库的引用,需要用户手动更新。而Subtree将代码直接合并到主仓库,更适合需要共同开发的场景。 - 路径处理注意事项
• 若子仓库位于远程(如GitHub),需替换为远程URL:
git subtree add --prefix=dataset https://github.com/user/dataset.git main
• 路径含空格或特殊字符时建议使用双引号包裹。 - 后续更新子仓库
• 拉取子仓库更新:
git subtree pull --prefix=dataset [URL] main
• 推送修改到子仓库:
git subtree push --prefix=dataset [URL] main - 关于 --squash 参数
若希望合并子仓库的历史提交为单次提交(避免主仓库历史被污染),可在命令中添加 --squash。
适用场景:子仓库提交历史复杂,且主仓库只需保留关键版本记录时。
完整操作日志参考
PS C:\Users\hollow\YKF2a> git init -b main
Initialized empty Git repository in C:/Users/94918/Desktop/YKF2a/.git/
PS C:\Users\hollow\YKF2a> git add .
PS C:\Users\hollow\YKF2a> git commit -m "Initial commit for main project"
[main (root-commit) cdbed89] Initial commit for main project
1 file changed, 47 insertions(+)
create mode 100644 "\347\273\274\350\277\260\346\241\206\346\236\266.md"
PS C:\Users\hollow\YKF2a> git subtree add --prefix=dataset C:\Users\hollow\毕业论文\dataset main
git fetch C:\Users\hollow\metaProject\dataset main
...
Added dir 'dataset'最终项目结构
YKF2a(主仓库)
├── 文献综述.md
└── dataset(子仓库合并后的目录)
├── data.csv
└── process.py优点总结:
• 保留子目录完整开发历史
• 主仓库可独立管理整体项目