加入子树的提交历史

问题描述

有一个git存储库,其中的一部分是从另一个存储库复制粘贴的,并在某个时刻一次提交了所有提交。

此后进行了许多更改。

我想跨多个分支向该子树添加过去的提交历史记录。有没有办法解决这个麻烦?

解决方法

假设您已经(或可以创建)带有您要添加的历史记录的git repo,那么就可以完成。首先是要确定是否要重写历史记录。

我认为,如果您可以重写历史记录,那么这是更好的选择。问题在于,使用回购协议的每个人都需要一定程度的合作。 (要进行一次全面的更改,理想情况下,您应该安排一个日期,使每个人都将所有工作推到原始位置-不必合并或进行任何操作,而必须全部放在一个原始存储库中-然后丢弃其克隆,这样他们就可以在重写后重新克隆。)

但是,如果进行重写不切实际,则还有另一种选择:您可以使用git replace在逐个repo的基础上拼接历史记录。有关警告的列表,请参见git replace文档,但是最明显的问题是,您必须在要查看合并历史记录的每个克隆上进行设置。

无论如何,一旦您确定了走哪条路并进行了必要的准备(即,如果要进行硬转换,请所有人推动),您将需要导入其他方法。历史记录回购。您最有可能希望创建原始镜像副本并进行相应的工作。

git clone --mirror <origin-url>

将添加的代码的历史存储库添加为远程存储并从中获取

git remote add history <history-repo-url>
git fetch history

现在history中的某个位置应该是一个提交,当代码被添加到您的仓库中时,将从中复制文件。这是历史记录的简化图:

A -- B -- C -- D -- E <--(master)

a -- b -- c -- d <--(history/master)

,也许c处的代码已作为提交B的一部分复制到您的存储库中。真实的历史可能更复杂,但是在几乎任何情况下,我都认为这没关系。您需要做的是检出将文件添加到您的仓库中的提交(在示例中为B)。在该示例中,它只是master的第三个祖先(在第一对父链接之后);实际上,您可能必须查找其提交ID。

git checkuot master~3

现在,如果仅 B所做的就是将c中的文件添加到您的仓库中,那么您可能希望完全替换它。因此,您可以签出其父项

git checkout HEAD^

如果B进行了其他更改,那么您将希望保留它们。究竟要怎么做可能取决于这些更改是否需要添加的代码。 (如果不是,您可能希望在合并历史记录之前先进行其他更改;如果是,那么您可能想在之后重新添加它们。)与其分支为三个相似但不同的过程,不如现在假设文件是在自己的提交中添加的。因此,现在您已将该提交的父母签出。

接下来,您将合并其他历史记录。在我们的示例中,该历史记录是history/master的父级;同样,您可能需要使用其他表达式来标识提交,或者可能只需要查找其提交ID。

更大的问题是,您希望代码位于存储库的子目录中。但这大概是另一个仓库的根源。有几种解决方法。这是其中之一。

git merge --s ours --no-commit --allow-unrelated history/master^
git read-tree --prefix=<path-to-subdirectory> history/master^
git commit

(您的工作树现在可能会丢失您合并到其中的文件,因此您会看到未暂存的删除;可以使用git restore刷新工作树。)

现在您有类似这样的内容:

          A -- B -- C -- D -- E <--(master)
           \
            M <-(HEAD)
           /
a -- b -- c -- d <--(history/master)

M应该与TREE具有相同的内容(B)(您可以使用git diff进行验证),但是具有添加的历史记录。因此,剩下的就是重新设置C的父级。这个重新设定父级的步骤是进行全面重写的地方。因此,在这里您要标记新的合并,如果不打算进行重写,则将其留给单个集群使用git replace

您可以使用git filter-branch进行重新父级化;但是git filter-branch又是一个旧工具,其文档建议您改用git filter-repo。我对新工具不熟悉,可能不应该花时间宣传使用旧工具的食谱,因此在这一步中,我将带您参考文档。 (通常,如果您使用Google git <any-git-command>,只要知道要使用的命令,就不难找到任何命令的官方文档。)

最后,您可以删除history遥控器,然后有一个适合用作origin(或从中创建新原点)的新存储库。

请注意,此过程的确在您的存储库中留下了两个不同的历史记录。从“当前”提交中,您将能够“查看”任何文件的完整历史记录,但是如果您checkout进入一个历史记录,则另一个将从索引和工作树中消失,直到您移回到较新的共享目录为止。历史。

拥有一个真正统一的历史会非常困难,但从技术上来讲并非不可能。您可以使用filter-repo来重写“其他”历史记录,使其看起来始终位于其子目录中,但是随后您必须弄清楚如何合并历史记录的时间表,而我只能看到手动方式做到这一点。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...