文件已经拆分时合并GIT对象历史记录

时间:2017-09-19 15:17:43

标签: git

我们有一个大型GIT项目,其中存储了所有数据。 前段时间我们决定将它们分开。现在我们有10个项目而不是1个。 遗憾的是,我们错过了使用相应历史记录迁移对象这意味着新项目中的对象的历史从头开始,旧的历史仍然在前者"大"项目

我只是尝试使用git bundle备份和恢复历史记录和剩余文件,效果非常好。 然而,这是整个历史存储。 是否有可能为我项目中的各个对象/项目备份/恢复/合并历史记录?

1 个答案:

答案 0 :(得分:0)

你想做的事情是可能的;但它可能有点牵扯。在下文中,我将历史回购称为Repo0,您将迁移到10个新存储库(Repo1,Repo2,...)。

创建新历史

在git中,提交或多或少是原子的;所以你不能真正说“创建一个包,但只包括这些路径”或类似的。相反,您必须为每个部分项目创建“新历史记录”。您可以使用filter-branch

执行此操作

当然,如果只有一个分支需要担心,这是最简单的,但我们假设Repo0可能有一组与任何给定项目相关的分支。假设masterdev包含Repo1的相关历史记录。

所以在Repo0中,您首先要创建新的分支

git branch Repo1/master master
git branch Repo1/dev dev

现在,您可以过滤新分支,将“大历史记录”转换为仅与Repo1相关的历史记录。如果Repo1对应Repo0中的子目录,则很容易。所以在最好的情况下Repo0看起来像

Project1-Files/
  some.file
  test/
    test.file
Project2-files/
  another.file
  ...

Repo1最终会以

结束
some.file
test/
  test.file

如果事情那么简单,那么你只需使用subdirectory-filter

git filter-branch subdirectory-filter Project1-Files --prune-empty -- Repo1/master Repo1/dev

如果需要更多重新排列,则可能需要使用tree-filter

git filter-branch tree-filter my-filter.sh --prune-empty -- Repo1/master Repo1/dev

其中my-filter.sh是一个脚本,可将工作树从Repo0转换为Repo1的正确结构。与subdirectory-filter方法相比,这是 更多的资源密集型。

妥协是使用index-filter,如果你真的想变得复杂,你可能能够比tree-filter更快地完成你想做的事情。语法与tree-filter的语法相同,但过滤器脚本必须直接在索引而不是工作树上运行。因此,“简单”的妥协是删除所有不相关的文件,但将相关文件保留在目录结构中。因此,你的历史可能会有一些虚假的“文件移动”,其中历史被拼接在一起。

无论如何,一旦成功运行,Repo1/masterRepo1/dev将包含适合Repo1的新历史记录。 (masterdev仍然是“大项目”的历史,你将回到那里作为建立彼此回购新历史的起点。)

接下来,将新记录转移到Repo1。您可以使用捆绑包(包含Repo1/masterRepo1/dev)执行此操作,也可以直接在Repo0中添加Repo1作为远程,并fetch方式。

最后,您会将已经在Repo1中的“近期历史”移植到您迁移的“旧历史”中。有两种一般的方法。

一种方法是物理地重写历史记录,这将再次使用filter-branch。这有一些变化,但基本上看看filter-branch --parent-filter的工作原理。这将创建最无缝的历史记录,但它会更改Repo1中每个提交的标识;所以我的建议是做一个“硬切换”,每个人都推动他们的Repo1更改并抛弃他们的克隆,你在Repo1来源执行转换,然后每个人都重新克隆。 / p>

如果您无法协调硬切换,或者由于某些其他原因您无法承担丢失旧提交ID的问题,那么您可以考虑使用git replace来记录历史中断。请参阅git replace文档,因为有一些怪癖和限制。

当然,你可以在每个新回购中留下第二套参考的“旧历史”