如何缩减/削减 Git 仓库的大小

7
我们有一个Git仓库,有7名开发人员参与,有超过2.5年的历史记录和约10,000个提交。我们使用Assembla来上传和下载。当我们添加新的开发人员时,他们从克隆仓库到自己的开发计算机上需要花费近一小时。
我不确定这是否是正确的术语,但我们的目标是通过“剪切/修剪”掉前1.5年的提交,并仅保留最近一年的历史记录来“缩小”仓库。我们想要保留整个仓库的“备份”副本,可以作为单独的仓库或分支。我们希望将来能够重复这样的操作并在需要时将最初的分离合并到新的分离中,但我不确定这是否可能。如果有一种方法可以将所有历史记录存储在单独的分支中,并只保留master分支上最近一年的历史记录,那就太好了,但请告诉我可能的优缺点。
我不知道我们拥有哪些可能性/选项,这就是我在这里的原因。我看到了关于patches的一些内容,但我不确定那是否真正是我需要的或者是否有更好/更容易的方法。你们处理这种问题的方式是什么,包括优缺点?请记住,我仍然需要每个开发人员继续上传和下载,最好保持在master分支上。
谢谢!

你的代码库有多大(磁盘大小)?Git 应该能够处理这么多的提交。你也可以查看服务器上是否存在过载或网络问题(作为比较,Linux 内核大约有 800MB 大小,有 400K 次提交,并且从 git.kernel.org 克隆需要大约半小时)。 - Rudi
Rudi,这个仓库大约有30GB大小,超过了10K次提交(.git/objects/文件夹大小为12GB),但与Linux内核相比微不足道。然而,除了可能存在的网络问题之外,我不仅仅是想修复问题并继续前进,我还想学习关于此的不同方法。谢谢! - RoLYroLLs
可能是Git删除历史提交记录的重复问题。 - sschuberth
2个回答

7

您可以在Git SCM历史博客文章"Replace Kicker"或Git书籍的"Replace"章节中找到最好的逐步说明。

简短地说,如下:

  • 创建一个新分支,该分支位于您想要切换的地方,例如git branch history哈希
  • 将历史记录推送到新存储库。
  • 使用git commit-tree创建一个新的基础。
  • 将后-history提交重新应用到新基础上。
  • 将新截断的master分支推送到服务器。
  • 然后,人们可以使用git replace将历史记录重新连接在一起。

原始文章通过图片更好地解释了这个过程。

当处理涉及合并的复杂历史记录时,这种方法可能效果不佳,具体取决于git rebase --onto如何与--preserve-merges一起使用。在继续之前,您应该进行充分的测试。


谢谢!我实际上很喜欢这个过程。我只是在测试这种方法。你知道是否有一种方法可以保持这种方法的一半吗?例如:master分支有截断版本,而history分支保留到我拆分它们之前的整个历史记录?我希望不必推送到单独的存储库。 - RoLYroLLs
补充一下我的评论,我刚刚读到git pull {remote}会拉取所有分支,但不会为远程仓库上的任何/所有分支创建本地分支。如果我设法将历史记录保留在一个分支中,并将所有新提交保存在另一个分支中,那么新开发人员最终会从每个分支拉取所有数据吗(我猜这就是你回答中“推送”到新存储库的原因),还是只会拉取分支名称而不是数据? - RoLYroLLs
我在另一个仓库上进行了一些测试,并得到了关于git pull获取多少数据的答案。实际上,它确实获取所有分支及其跟踪的更改,即使您没有本地分支跟踪特定分支的更改。因此,我将无法将历史记录保留在单独的分支上。我将不得不遵循您发布的“Replace Kicker”帖子!谢谢! - RoLYroLLs

0
免责声明:您应该先使用测试存储库进行此操作,因为此处列出的命令可能会破坏您的数据
您可以通过快速导出机制编辑(即让脚本编辑)历史记录。第一步是运行git fast-export --signed-tags=strip --no-data --full-tree --export-marks=export.marks branch1 branch2 [...] branchN > commits.fi。现在您拥有所有分支的快速导入流。在此流中,您可以通过删除从提交refs/...到尾随换行符的行来删除提交。您还需要从您的新“第一个”提交中删除from :<mark>行(如果您的新历史记录以合并开始,则还要删除merge :<mark>行)。
为了帮助这个过程,您应该查看修订图,并选择没有合并穿越其历史记录的修订版本。在下面的图表中,A、D和F是很好的起点。B或C存在问题,因为后继的D也依赖于G和A。
A ---- B ---- C ---- D --- E ---- F
  \                /  \     \   /
   \--- G ------- H    \--I--J-/

使用 export.marks 文件,您可以将提交 ID 转换为流中的标记号。

您需要给您的分支命名,因为 git fast-import 不会接受新历史记录,因为新分支不包含现有分支的提交。

创建新历史记录后,您需要使用 git fastimport < manipulated-history.fi 将其导入到现有存储库中。

现在是检查导入是否正确的时候了。为此,您需要将存储库克隆到临时存储库中,并在该临时存储库中为每个新创建的提交创建一个嫁接,以使其具有与之前相同的父修订版本。然后运行 git filter-branch newBranch1 newBranch2 [...] newBranchN。如果每个新分支现在停留在与相应分支相同的提交上,则导入正确。

如果到目前为止一切正常,您可以创建一个新存储库,并从第一个工作克隆中拉取 newBranch 分支,使其成为新的工作存储库。还要注意,您不应该在任何地方留下带有嫁接的存储库,因为嫁接可能会造成损害。


@Rubi 谢谢你。不确定这个解决方案会因你提到的图表问题而起作用得如何。 - RoLYroLLs

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接