如何将多个 Git 回购合并为一个并交错历史记录

How to merge several Git repos into one and interleave histories

我的情况是我有两个 Git 个存储库,我需要将它们合并到一个存储库中(实际上还有更多的存储库,但我可以从两个开始)。

两个存储库是:

存储库 B 中的代码依赖于存储库 A 中的代码(但 反之亦然),并且两个存储库的历史按时间顺序相互跟随 - 大致(即回购 B 中的特定提交通常需要来自回购 的提交A 具有非常相似的提交时间)。

两个存储库中存在冲突的分支和标签名称(不能保证它们属于一起),但只需要保留来自 A 的引用。

新存储库 C 的要求是:

  1. 来自 A 的所有引用(分支和标签)都需要保留。
  2. 只有 B 的主分支提交需要保留(即 git log --first-parent master 报告的提交)。
  3. 每个源存储库中的文件应放入新存储库的子文件夹中(即来自 A 的文件应放入 A/,文件格式为 B 应进入 B/).
  4. 在存储库 C(例如发布标签)兼容文件中签出特定提交(包括在合并之前完成的提交)从两个源存储库应该在目录 A/B/ 中找到(至少在一两次提交中)。

到目前为止,我尝试了几种方法,包括this and git-stitch-repo,但都没有成功(它们没有满足上述要求)。

在这一点上,我已经设法:

目录 A
mv * .git忽略A/2> /dev/null
git commit -a -m 'DROPME' > /dev/null
git filter-branch --tag-name-filter cat --index-filter 'git ls-files -s | sed "s-\t\"*-&A/-" | GIT_INDEX_FILE=$GIT_INDEX_FILE.new git update-index --index-info && mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE" ||:' -- --all
git 重置 --hard origin/master
git for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git update-ref -d

我现在期望的是 git filter-branch 的一些巧妙用法应该使我能够将从 B 中选择的提交插入到 [=37 的主分支中=]A。但是怎么办?

首先,将repo A 中的所有内容移动到子目录A/。没什么特别的,只是 git mv。这将保留 A.

中的所有分支和标签以及提交 ID

然后使用git subtree使B的master分支成为目录B/中A的子树。

git subtree add -P B/ <remote for B> master

大功告成。


如果您希望 A 上的旧版本标签也能反映当时 B 中的内容……哎呀。您可以通过在每个发布标签之前将 B 合并到 A 中来做到这一点,而不会把您的历史搞得一团糟。

你有这个。

          * - * - *           * - * - * branch
    v1   /         \    v2   /
* - * - * - * - * - * - * - * - * - * master
                                   /
  * -- * ---- * - * - * --------- *

提交的底线是 B。B 的提交是按顺序排列的,因此它们与 A 的提交及时对齐。

而你想要这样的东西。

          * - * - *           * - * - * branch
    v1   /         \    v2   /
* * * - * - * - * - * * * - * - * - * master
  |                   |            /
  * -- * ---- * - * - * --------- *

这在每个发布标签之前将 B 合并到 A 中。这样可以避免人为编造A和B一起开发的历史。

我不知道如何以自动化方式执行此操作。问题是 rebase 不保留标签,只合并。因此,将合并提交添加到 v1 将丢失 v2 标记,我不确定如何识别变基提交的原始提交是什么。

祝你好运。

事实证明,解决方案比我希望的要复杂得多。它涉及操纵和组合两个(或更多)git fast-export 流的输出,并使用 git fast-import.

将它们导入到新的存储库中

简而言之,通过遍历两个输入流,并根据来自主要分支的按日期排序的日志在它们之间来回切换,生成一个新的 fast-import 流。

我已经在名为 join-git-repos.py 的 Python 脚本中实现了解决方案,我将其放入 GitHub 存储库 here