拆分 Git 存储库并仅保留剩余文件的历史记录
Split Git Repository and only keep history of remaining files
我有一个 git 存储库,其中包含 11 个不同且独立的项目(不要问我为什么 **** 它们都在一个存储库中)。由于一些项目包含许多资产,gitlab 表示回购协议的大小约为 14.3 GB,这会导致大量的结帐时间(在我们的 CI/CD 系统上最多 20 分钟)。
因为我们一次只构建一个项目,所以我想将所有项目分离到不同的存储库中。因为项目A不需要项目B的文件相关的提交,所以我想清理整个历史。
我已经尝试过不同的方法:
- 正在删除文件。文件已消失,但仍可通过历史记录访问。
- 使用简单
git filter-branch --prune-empty
,但我想保留文件结构。
- 使用
git filter-branch --index-filter --prune-empty
和 git rm --cached --ignore-unmatch
,但我仍然可以恢复旧文件。
- 删除文件并使用 Git BFG 和
--delete-folders
。很好的结果,但我只能提供一个 glob/regex 和一些项目,其中包含带有其他项目名称的文件夹(命名错误...),这些文件夹也被删除了...
最好是像 BFG 一样工作的 tool/command,但它允许我提供删除路径或保留更好的路径。
文件结构示例:
./
+- Project A/
+- Project B/
+- UI Projects/
| +- Foo/
| +- Bar/
+- Project E/
| +- Foo/
| +- Bar/
+- Build
+- build_a/
+- build_b/
+- build_foo/
+- build_bar/
+- build_e/
我的要求是:
- 保留文件结构
- 保留多个路径(例如
./Project A/
和 ./Build/build_a/
用于 Repo A)
- 不再属于新存储库的文件的历史记录被清除
有什么建议吗?
好吧...您在这里遗漏了一个更大的问题,但我会回过头来。按照要求解决您的问题:
在您尝试过的选项中,filter-branch
是应该有效的选项。 (请注意,git 有一个新工具,filter-repo
,他们推荐超过 filter-branch
;但我没有花时间切换,听起来你几乎- 工作 filter-branch
程序,所以我将使用 filter-branch
...)
来解决问题
因此,您说在使用 filter-branch
和 index-filter
后仍然可以恢复已删除的文件。这有几个可能的原因,但一般来说,关键是 git 试图避免丢失数据,除非它真的确定您不再需要它。所以:
filter-branch
每当重写 repo 的引用时都会创建一组 "backup refs"。那些"backup refs"还能传到老历史
- 您的分支机构的 reflogs 提供了一种返回到这些分支机构先前指向的位置的方法;那些历史reflog条目仍然可以达到旧历史
消除所有这些问题的最简单方法是从您进行清理的存储库中重新克隆。如果真的想原地清理,需要(1)删除original
命名空间下的refs; (2) 过期或删除 reflogs - 我总是无法让 git 过期它们,但如果所有其他方法都失败了 rm -r .git/logs
; (3) 运行 GC。对于这种类型的操作,我使用 gc --force --aggressive --prune=now
.
现在...更大的问题是,如果 11 个项目的历史总和为 14.3GB,那么每个项目的历史(平均)超过 1GB - 这仍然很荒谬。你有一个更深层次的问题。在我看来,拆分回购是一个好主意(我不喜欢 "monorepo" 趋势);但你也应该尝试减少 repo 的整体大小。
您很可能在源代码管理下拥有大型二进制文件。很少有人这样做是可取的。如果你确实需要这样做,你应该使用像 git lfs
这样的工具来保持核心 repo 小且易于管理。但是,如果您只是存储构建工件、依赖项或类似的东西,您最好查看工件存储库(artifactory、nexus 等)。这可能需要改进构建工具来管理依赖版本
以下树过滤器满足您的要求:
find . ./Build -maxdepth 1 -path . -o -path ./Build -o -path "./Project A" -o -path ./Build/build_a -o -exec rm -rf {} +
将Project A
和build_a
替换为实际的项目名称。您可以按照 ./Build
文件夹的示例添加其他路径。
传递给filter-branch的--tree-filter
选项:
git filter-branch --tree-filter '...' --tag-name-filter cat --prune-empty -- --all
我有一个 git 存储库,其中包含 11 个不同且独立的项目(不要问我为什么 **** 它们都在一个存储库中)。由于一些项目包含许多资产,gitlab 表示回购协议的大小约为 14.3 GB,这会导致大量的结帐时间(在我们的 CI/CD 系统上最多 20 分钟)。
因为我们一次只构建一个项目,所以我想将所有项目分离到不同的存储库中。因为项目A不需要项目B的文件相关的提交,所以我想清理整个历史。
我已经尝试过不同的方法:
- 正在删除文件。文件已消失,但仍可通过历史记录访问。
- 使用简单
git filter-branch --prune-empty
,但我想保留文件结构。 - 使用
git filter-branch --index-filter --prune-empty
和git rm --cached --ignore-unmatch
,但我仍然可以恢复旧文件。 - 删除文件并使用 Git BFG 和
--delete-folders
。很好的结果,但我只能提供一个 glob/regex 和一些项目,其中包含带有其他项目名称的文件夹(命名错误...),这些文件夹也被删除了...
最好是像 BFG 一样工作的 tool/command,但它允许我提供删除路径或保留更好的路径。
文件结构示例:
./
+- Project A/
+- Project B/
+- UI Projects/
| +- Foo/
| +- Bar/
+- Project E/
| +- Foo/
| +- Bar/
+- Build
+- build_a/
+- build_b/
+- build_foo/
+- build_bar/
+- build_e/
我的要求是:
- 保留文件结构
- 保留多个路径(例如
./Project A/
和./Build/build_a/
用于 Repo A) - 不再属于新存储库的文件的历史记录被清除
有什么建议吗?
好吧...您在这里遗漏了一个更大的问题,但我会回过头来。按照要求解决您的问题:
在您尝试过的选项中,filter-branch
是应该有效的选项。 (请注意,git 有一个新工具,filter-repo
,他们推荐超过 filter-branch
;但我没有花时间切换,听起来你几乎- 工作 filter-branch
程序,所以我将使用 filter-branch
...)
因此,您说在使用 filter-branch
和 index-filter
后仍然可以恢复已删除的文件。这有几个可能的原因,但一般来说,关键是 git 试图避免丢失数据,除非它真的确定您不再需要它。所以:
filter-branch
每当重写 repo 的引用时都会创建一组 "backup refs"。那些"backup refs"还能传到老历史- 您的分支机构的 reflogs 提供了一种返回到这些分支机构先前指向的位置的方法;那些历史reflog条目仍然可以达到旧历史
消除所有这些问题的最简单方法是从您进行清理的存储库中重新克隆。如果真的想原地清理,需要(1)删除original
命名空间下的refs; (2) 过期或删除 reflogs - 我总是无法让 git 过期它们,但如果所有其他方法都失败了 rm -r .git/logs
; (3) 运行 GC。对于这种类型的操作,我使用 gc --force --aggressive --prune=now
.
现在...更大的问题是,如果 11 个项目的历史总和为 14.3GB,那么每个项目的历史(平均)超过 1GB - 这仍然很荒谬。你有一个更深层次的问题。在我看来,拆分回购是一个好主意(我不喜欢 "monorepo" 趋势);但你也应该尝试减少 repo 的整体大小。
您很可能在源代码管理下拥有大型二进制文件。很少有人这样做是可取的。如果你确实需要这样做,你应该使用像 git lfs
这样的工具来保持核心 repo 小且易于管理。但是,如果您只是存储构建工件、依赖项或类似的东西,您最好查看工件存储库(artifactory、nexus 等)。这可能需要改进构建工具来管理依赖版本
以下树过滤器满足您的要求:
find . ./Build -maxdepth 1 -path . -o -path ./Build -o -path "./Project A" -o -path ./Build/build_a -o -exec rm -rf {} +
将Project A
和build_a
替换为实际的项目名称。您可以按照 ./Build
文件夹的示例添加其他路径。
传递给filter-branch的--tree-filter
选项:
git filter-branch --tree-filter '...' --tag-name-filter cat --prune-empty -- --all