本章主要测试讲解
- 如何将两个 git 管理的项目合并成一个项目,并保留住各自项目中所有的历史提交记录。(后续可以自行拓展到三个、四个……的合并)
本篇内容,不建议跳过,如果有这个需求,还请仔细详细查看,谢谢。
测试过程
前置说明
git 管理的项目合并,还要保留之前的提交历史记录,则表明不能直接异动到原项目.git 文件夹仓库,需要通过其它方式把子项目的.git 文件夹合并到一起,才能保存住所有提交信息。
项目准备
- 先从 github 克隆了两个项目用于测试,一个是 dayjs,一个是 moment;
- 计划是把 dayjs 和 moment 合并为一个项目,名为 timetools;
- 该项目包含两个文件夹,一是 dtool,对应原本的 dayjs;
- 二是 mtool,对应原本的 moment。
效果,合并前
- dayjs => 独立的 dayjs 项目,有自己的.gitignore 和 .git/
- moment => 独立的 moment 项目,有自己的.gitignore 和 .git/
合并后:
- timetools/ => 即最开始的 dayjs,整合完后更名
- .gitignore => 合并两个 repos 的忽略文件
- .git/ => 最终仅余一个 repo
+ dtool/ => 对应 dayjs
+ mtool/ => 对应 moment
克隆的项目,内容如下:
使用git log --oneline | wc -l
获取提交数量。
粗略可见,dayjs 的提交为 1046 次,moment 提交为 3724 次。
注意分支名,dayjs 为 dev,moment 为 develop。
大概流程
- 1 进入 dayjs 文件夹,将 moment 作为远程仓库添加到 dayjs 来;
- 2 合并添加的库 moment 到原本的 dayjs 项目;
- 3 创建 mtool 文件夹,把 moment 的 develop 分支合并到 mtool 文件夹;
- 4 完成 moment 转移提交;
- 5 完成 dayjs 文件的迁移;
- 6 完成项目合并并查看历史记录。
测试步骤
进入 dayjs 文件夹,将 moment 作为远程仓库添加到 dayjs 来
使用命令:
git remote add -f moment D:/davidsu/Desktop/GitlabTest/full/moment
命令说明:git remote add
添加远程仓库路径
- -f 的作用是在添加后立刻 fetch。
D:/davidsu/Desktop/GitlabTest/full/
为需要被合并 moment 项目的绝对路径 。
如下图:
合并添加的库 moment 到原本的 dayjs 项目
使用命令(注意分支名):
git merge --strategy ours --no-commit --allow-unrelated-histories moment/develop
命令说明:git merge
为合并分支
- –strategy ours 解析合并,在合并时,如果遇到冲突,以我的为准。(本例是在 dayjs 中合并 moment,遇到冲突以 dayjs 的为准)。结果就是:
- moment 的历史记录被合并到 dayjs 的历史记录中。
- moment 的文件树被读取并和 dayjs 的文件树比对进行冲突解析。
- –no-commit 合并解析完成后中断,停留在最后的提交步骤之前。
- 只要你还没 commit,那么 merge 的结果就暂时保存在缓存区中,只有完成提交步骤合并才算彻底完成(文件树被正式改变)。
- –allow-unrelated-histories 允许合并无关的历史记录。
- 如果不添加此选项,可能会出现
fatal: refusing to merge unrelated histories
错误。
- 如果不添加此选项,可能会出现
如下图:
创建 mtool 文件夹,把 moment 的 develop 分支合并到 mtool 文件夹
使用命令:
mkdir mtool # 创建文件夹
git read-tree --prefix=mtool/ -u moment/develop
命令说明:git read-tree
给定的树信息读入索引
- –prefix 用于指定文件树读取后保存的路径,相对于当前路径并且一定要追加 /。
- -u 是说在读取后更新 index,使得 working tree 与 index 保持同步。
这个命令的意义在于,之前的git merge
命令可能会在解决冲突的时候,把 moment 的文件树弄得比较混乱,再使用read-tree
去修复一下。
如下图(再次提醒,=前后不要空格):
完成 moment 转移提交
上一步已经修复了文件数,执行完之后,仍然在 MERGING 状态,需要提交一次修改。
使用命令:
git commit --message '完成moment 的迁移,新目录为 mtool'
如下图(MERGING 过成已完成):
完成 dayjs 文件的迁移
以上,已把 momet 项目迁移到了 dayjs 下的 mtool 文件夹了。现在要迁移 dayjs 文件夹了。
在 dayjs 文件夹下,新建文件夹 dtool
mkdir dtool
再把所有原本属于 dayjs 的文件移动到新建的 dtool 去。
也就是除了 dtool/、mtool/、.git/、.gitignore 之外的所有。
剪切完之后,把这个原本的 dayjs 的文件夹重命名为 timetools。
完成项目合并并查看历史记录
到这一步,原本的 dayjs 项目,就变成了 timetools 项目,里面的 dtool 文件夹就是 dayjs 项目。
不过还差一点,之前只是把文件放进去了,还需要合并.gitignore 文件。
在新的 timetools 文件夹下,运行:
cat mtool/.gitignore >> .gitignore
把原本 moment 项目,现在的 mtool 文件夹下的.gitignore 的内容,合并到现在 timetools 文件夹下的.gitignore 中,完成忽略文件的合并。
如下图:
到这里,合并作业就基本完成了,最后在添加提交一次,做合并项目的记录
git add --all;
git commit --message '迁移整合完成!'
如下图:
合并前后的文件夹结构如下:
查看合并后的项目历史记录,如下图:
提交数:4772 = 1046 + 3724 + 2。
总结
以上,完成了两个项目合并到一个项目的示例接操作演示,后续有更多的项目想要合并,可以类似。
本示例使用步驟
- 进入 dayjs
- git remote add -f moment D:/davidsu/Desktop/GitlabTest/full/moment
- git merge –strategy ours –no-commit –allow-unrelated-histories moment/develop
- mkdir mtool
- git read-tree –prefix=mtool/ -u moment/develop
- git commit –message ‘完成 moment 的迁移,新目录为 mtool’
- mkdir dtool (还在 dayjs 下面)
- 拷贝 dayjs 的原始项目文件(除了 .git/ 和 .gitignore 以外)至 dtool/;
- 拷贝完之后,可以把原本文件夹名 dayjs 改为 timetools;
- 把此时 mtool 下的.gitignore 文件内容,整理合并到 timetools 下的.gitignore 文件中去。
- 合并完之后,再全部添加提交一次,做为整合操作的记录:
- git add –all; git commit –message ‘迁移整合完成!’
整理引用原作者步骤:
目标:将 frontend 项目与 backend 项目,合并到 project 项目下的 client 文件夹与 server 文件夹。
- $ [~]
cd frontend
- $ [frontend]
git remote add -f backend /fullpath/to/backend
- $ [frontend]
git merge --strategy ours --no-commit backend/master
- $ [frontend]
mkdir -p server
- $ [frontend]
git read-tree --prefix=server/ -u backend/master
- $ [frontend]
git commit --message '完成 backend 的迁移,新目录为 server'
- $ [frontend]
mkdir -p client
# 拷贝 frontend 的原始项目文件(除了 .git/ 和 .gitignore 以外) 至 client/
- $ [frontend]
cd ..; mv frontend/ project/; cd project
- $ [project]
cat server/.gitignore >> .gitignore
# 整理合并后的 .gitignore,修复其中的路径缺失并保存;修复各种项目依赖的缺失,本地测试。
- $ [project]
git add --all; git commit --message '迁移整合完成!'