如果我理解您的问题正确(在阅读评论后),您的存储库当前看起来像这样:
![Initial State](https://istack.dev59.com/ZD7IG.webp)
第一个仓库中的提交记录(a-d)已被修改,以创建备用提交记录(a'-d'),这些记录被推送到第二个仓库,然后添加了其他提交记录(e-g)。
重新编辑您的历史记录
由于两个仓库中的身份信息没有一对一的关系,因此尝试使用filter-branch修改a'-d'以恢复原始历史记录,虽然在理论上是可能的,但需要一种方法来积极识别“原始提交记录”而不需要唯一标识提交记录的信息(其哈希值)。
提交记录基本上由几个信息组成:
1. 树的哈希值
2. 提交记录的父提交记录的哈希值
3. 作者的身份信息
4. 作者的时间戳
5. 提交者的身份信息
6. 提交记录的时间戳
7. 提交记录的消息
8. 所有信息的大小
所有这些内容都被哈希以创建您提交的唯一标识符。在更改2、3、5和8之后,我们留下了树,它不一定是唯一的;时间戳,也不一定是唯一的;以及提交消息,也不一定是唯一的。
很可能您只需比较树和一个时间戳就能得到一个相当匹配的结果,因此让我们为这种情况编写一些伪代码。
pseudoidentifier=$TREE + $AUTHOR_TIMESTAMP
cd /path/to/firstrepo
oldhash=`git log --format="{hash}~{tree}{authortimestamp}" | grep pseudoidenfier | sed "s/~.+$//"`
newidentity=`git show -q --format="{formatted identity}" $oldhash`
CORRECT_NAME=`sed 's/pattern//' $newidentity`
CORRECT_EMAIL=`sed 's/pattern//' $newidentity`
cd /path/to/secondrepo
export GIT_COMMITTER_NAME="$CORRECT_NAME"
export GIT_COMMITTER_EMAIL="$CORRECT_EMAIL"
很遗憾,这样写会很慢,测试也会非常困难和耗时。可能需要多次重新运行整个代码。既然你的最终目标是重新合并代码,有几种其他选项可能会导致更少的麻烦并且更快。特别是如果您确实需要保留具有身份更新的第二个存储库。
替代方法
即使没有共同的历史记录,您仍然可以使用相对手动的方式将两者同步。在这种情况下,我建议使用以下三种方法之一。
一些预备工作
在开始之前,我们可以使用git show命令检查d和d'处的代码是否相同。
$ git show -q --format="%T" d
a017285da45ec06fc744815f33a2e22627f4a799
$ git show -q --format="%T" d'
a017285da45ec06fc744815f33a2e22627f4a799
这个命令将输出提交所指向的树对象,如果两个树匹配,则处理相同的代码。完全可能在没有匹配代码库的情况下执行以下过程,但在这种情况下,您可能需要解决冲突。这一步只是告诉您它们如何轻松地合并在一起。
樱桃挑选方法
如果您最初用于修改提交的存储库完好无损,则可以从两个分支中获取到一个单一的存储库,并尝试使用cherry-pick复制提交。
git checkout <branch at d>
git cherry-pick d'...g
(请注意,语法是3个点)这将将从d之后(但不包括d)到g之间的每个提交中的更改应用于d。创建新的提交e' - g'。
![History after cherry-pick](https://istack.dev59.com/R8fCq.webp)
补丁方法
如果您没有简单的方法将两个分支的更改合并到单个存储库中,您可以为第二个存储库上的提交创建一系列补丁,并将其应用于第一个存储库。
在第二个存储库中
git checkout <branch of g>
git format-patch --output-directory <dir> d'...g
(再次强调,语法是三个点)这将输出从d到g之间每个提交后(不包括d),产生一系列补丁文件。然后将这些文件复制到第一个仓库可以访问的位置,以应用这些补丁。
在第一个仓库中
git checkout <branch of d>
git am /path/to/patches/*
你最终会和使用“挑樱桃法”得到的结果一样。
![History after patch](https://istack.dev59.com/R8fCq.webp)
创建一个嫁接点
如果有很多冲突并且您不需要保留已更改的身份信息,则还可以使用git replace
执行嫁接。
git replace --graft e d
这将创建一个以 d 作为父提交的 e 的副本,并添加一个引用,指示每当访问 e 时使用 e' 提交。实际上,使 d 成为两者的公共祖先,并允许您执行传统合并(h)。
![enter image description here](https://istack.dev59.com/uSSXg.webp)
然后呢?
将两个没有共同历史的仓库保持同步将会经常导致像这样的问题,并且随着两个仓库慢慢分歧(例如,当您解决冲突时),问题会越来越严重。随着时间的推移,这两种方法都需要越来越多的资源来维护这两个仓库。
我建议一旦两个仓库被同步,选择一个并从那时起专门使用它。如果您需要两个远程仓库,请将该仓库推送到两个仓库中。然后,您可以轻松使用任何经过验证的工作流程来维护这两个仓库。
如果这不是一个选项,我建议仔细检查您的两个仓库头部树是否经常完全相同。