我们有一个大型GIT项目,其中存储了所有数据。 前段时间我们决定将它们分开。现在我们有10个项目而不是1个。 遗憾的是,我们错过了使用相应历史记录迁移对象这意味着新项目中的对象的历史从头开始,旧的历史仍然在前者"大"项目
我只是尝试使用git bundle
备份和恢复历史记录和剩余文件,效果非常好。
然而,这是整个历史存储。
是否有可能为我项目中的各个对象/项目备份/恢复/合并历史记录?
答案 0 :(得分:0)
你想做的事情是可能的;但它可能有点牵扯。在下文中,我将历史回购称为Repo0,您将迁移到10个新存储库(Repo1,Repo2,...)。
创建新历史
在git中,提交或多或少是原子的;所以你不能真正说“创建一个包,但只包括这些路径”或类似的。相反,您必须为每个部分项目创建“新历史记录”。您可以使用filter-branch
。
当然,如果只有一个分支需要担心,这是最简单的,但我们假设Repo0可能有一组与任何给定项目相关的分支。假设master
和dev
包含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/master
和Repo1/dev
将包含适合Repo1
的新历史记录。 (master
和dev
仍然是“大项目”的历史,你将回到那里作为建立彼此回购新历史的起点。)
接下来,将新记录转移到Repo1
。您可以使用捆绑包(包含Repo1/master
和Repo1/dev
)执行此操作,也可以直接在Repo0
中添加Repo1
作为远程,并fetch
方式。
最后,您会将已经在Repo1
中的“近期历史”移植到您迁移的“旧历史”中。有两种一般的方法。
一种方法是物理地重写历史记录,这将再次使用filter-branch
。这有一些变化,但基本上看看filter-branch
--parent-filter
的工作原理。这将创建最无缝的历史记录,但它会更改Repo1
中每个提交的标识;所以我的建议是做一个“硬切换”,每个人都推动他们的Repo1
更改并抛弃他们的克隆,你在Repo1
来源执行转换,然后每个人都重新克隆。 / p>
如果您无法协调硬切换,或者由于某些其他原因您无法承担丢失旧提交ID的问题,那么您可以考虑使用git replace
来记录历史中断。请参阅git replace
文档,因为有一些怪癖和限制。
当然,你可以在每个新回购中留下第二套参考的“旧历史”