本章主要测试讲解

  • 如何将两个 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

克隆的项目,内容如下:

1.png

使用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 项目的绝对路径

如下图:

2.png

合并添加的库 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错误。

如下图:

3.png

创建 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去修复一下。

如下图(再次提醒,=前后不要空格):

4.png

完成 moment 转移提交

上一步已经修复了文件数,执行完之后,仍然在 MERGING 状态,需要提交一次修改。

使用命令:

git commit --message '完成moment 的迁移,新目录为 mtool'

如下图(MERGING 过成已完成):

5.png

完成 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 中,完成忽略文件的合并。

如下图:

6.png

到这里,合并作业就基本完成了,最后在添加提交一次,做合并项目的记录

git add --all;
git commit --message '迁移整合完成!'

如下图:

7.png

合并前后的文件夹结构如下:

8.png

查看合并后的项目历史记录,如下图:

9.png

提交数: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 文件夹。

  1. $ [~] cd frontend
  2. $ [frontend] git remote add -f backend /fullpath/to/backend
  3. $ [frontend] git merge --strategy ours --no-commit backend/master
  4. $ [frontend] mkdir -p server
  5. $ [frontend] git read-tree --prefix=server/ -u backend/master
  6. $ [frontend] git commit --message '完成 backend 的迁移,新目录为 server'
  7. $ [frontend] mkdir -p client
  8. # 拷贝 frontend 的原始项目文件(除了 .git/ 和 .gitignore 以外) 至 client/
  9. $ [frontend] cd ..; mv frontend/ project/; cd project
  10. $ [project] cat server/.gitignore >> .gitignore
  11. # 整理合并后的 .gitignore,修复其中的路径缺失并保存;修复各种项目依赖的缺失,本地测试。
  12. $ [project] git add --all; git commit --message '迁移整合完成!'

参考文件:
https://segmentfault.com/a/1190000000678808