BFG Repo Cleaner——新鲜克隆的替代品
BFG Repo Cleaner – Alternative to Fresh Clone
我本来打算在存储库上问这个问题,但 SO 似乎更适合问这个问题。
我能够使用 BFG Repo Cleaner(很棒的工具,谢谢!)将我们的 .git
文件夹大小减少超过 1GB,就我们的存储库而言,这是一个巨大的成功。我还没有将我的裸克隆推送到远程,因为我担心在了解推送然后不重新克隆的后果之前提出这些更改。
我了解最佳实践规定,当历史以这种方式改变时,最好的解决方案是执行新的克隆。然而,我与一个超过 50 人的团队一起工作,在一个超过 2GB 和 23k 提交的存储库中,在我们的结构下跨团队协调可能非常困难。结果,我有一些问题:
- 如果我推送这些更改后的引用,而人们拉到他们现有的副本而不是创建一个新的副本,会有什么后果?
- 如果可行,他们是否需要做任何其他事情来减轻这些后果,作为他们拉力的一部分,或者除了他们的拉力之外?
- 如果您认为被删除的 blob 来自至少 1 年至多 3 年的历史记录,此建议是否会完全改变?
- 最后,鉴于新的克隆不会包含任何未同步到上游的工作,您是否有关于将未跟踪分支从一个克隆转移到另一个克隆的最佳方法的建议?如果已经存在执行此操作的 Git 命令,我很想听听您的见解。
再次感谢您创建了这样一个方便的工具,希望我能完成它,使其对我团队的项目有用。在此期间,我将继续在我的叉子上进行实验。
前言
在我们开始之前,让我澄清在活跃的团队开发人员的背景下清理Git历史记录的推荐过程(无论使用什么技术用于清洁 - 无论是 BFG Repo-Cleaner 还是 git filter-branch
):
- 在存储库的本地一次性副本上练习几次清理,这样您就有信心可以做到并获得所需的结果,并且您知道需要多长时间。
- 与您的团队沟通。这是必不可少的,不可避免的(因为 Git 是专门为抱怨而设计的,如果历史被重写,这会成为阻碍)并且对于任何团队来说都是 良好实践 :-) 你需要告诉他们:
- 为什么要进行清理(例如较小的回购!)
- 计划 清理时 - 提前给他们适当的警告。
- 将他们的工作全部推到主仓库之前清理开始-不需要合并到主分支,但所有工作都需要在一个分支或另一个分支上进行推送。
- 建议他们在清理完成后需要删除旧的存储库副本,re-clone 新清理的存储库
- 当所有工作都推送到主仓库后,对主仓库执行 mirror clone。备份此克隆,以便在出现问题时随时返回。
- 运行 清理(使用 BFG Repo-Cleaner 或更慢的工具,如
git filter-branch
),然后使用 git gc
trim死objects.
- 一旦你对清理工作感到满意,将清理后的历史推送回主仓库(因为它是一个
mirror
克隆,所有旧的 branches/tags 将被覆盖到新的清理历史)
- 告诉您的团队是时候删除他们旧的存储库副本,re-clone 清理存储库了。
所以,对于你的问题:
如果:具有 old 存储库的用户从 cleaned 存储库中提取?
What would the consequences be if I were to push these changed refs
and people were to pull to their existing copy rather than create a
fresh clone?
不好。根据经验,我可以说会有一团糟,人们会 困惑 和 沮丧 .
具体来说,在那个人的机器上发生的事情是 git pull
命令将旧的脏历史和新的清理历史合并在一起,有两个长期不同的历史(最初与第一个不同 'dirty' 提交你的历史,在你的情况下是 3 年前)与一个全新且非常混乱的合并提交结合在一起。用户很少清楚这已经发生 - 大多数 Git 日志可视化器不会以可能使其明显的方式呈现 - 如果你幸运的话,用户可能会说 "I've got two copies of every commit now, WTF?!" - 但前提是他们真的很细心。
如果该用户稍后进行了一些新的提交,并将其推回主存储库,他们会将脏历史推回已清理的主存储库,否定您的工作,使您的历史再次变脏,并创建一个非常令人困惑的 Git 历史记录,您的所有其他用户下次从主要 Git 存储库中拉出时都会接触到这些历史记录。
通过规划,有没有办法让用户保留他们的旧存储库但更新它以拥有清理过的历史记录?
Would they need to do anything else to mitigate these consequences as
part of, or in addition to their pull, if this is feasible?
从技术上讲,是的。实际上,过程很复杂,error-prone,如果只有一个用户弄错了,你就和以前一样完蛋了。
在这一点上,我们必须找出你为什么要躲避这个程序。是不是因为:
- 您试图让用户不必了解和处理更改 Git 历史记录? 听起来这可能是您的目标,基于您的说 "cross-team coordination can be incredibly difficult under our structure" - 但不幸的是 这不是一个可以实现的目标 ,因为 Git 不会让你在没有用户的情况下更改历史记录注意。用户将不得不做某事,他们将需要与您协调。
- 您想减少对您真正庞大的存储库进行全新克隆的下载时间,希望 Git 只会下载已更改的 blob,而不是所有 没有 改变? 对于需要数小时下载的巨大 multi-gigabyte 回购来说,这是一个稍微更合理的目标(如果你使用 BFG 来制作回购小得多,动力也少)- 不幸的是,由于 Git 协议的详细信息,您 将无法 实现这些好处。 Git 协议旨在确定远程服务器上的哪些提交不在您的本地存储库中,并发送一个定制的包文件,其中仅包含您更新本地存储库所需的内容。这很好,但请注意比较的单位是 commits。当你重写历史时,提交的 文件树 几乎没有变化——但是提交 ID all 改变了,因为 t提交 ID 是它的 父母历史 的散列,也是它的文件树内容。 Git 协议只比较提交 ID,它们都是不同的 - 所以 所有 提交将被发送, 连同它们的 file-tree objects。该协议没有深入到意识到它不需要发送其中的大部分 file-tree object - 因此您无法从本地已经拥有它们的副本中获益回购
坏事发生在历史多久之前重要吗?
Does this recommendation change at all if you consider that the blobs
that were deleted are from history that is at least a year old and at
most three years old?
如果最近提交了错误的内容,并且还没有其他用户将其删除(因此,在过去的几小时或几分钟内),您可能会先于其他人快速清理主仓库上的历史记录拉它。一旦其他人拉出脏数据,就需要对其进行净化,最简单的方法是删除并 re-clone.
如果坏事是几年前犯下的,那么每个人都有,他们所有都需要净化。
清理时 没有 推送到主存储库的流浪 commits/branches 怎么办?
Finally, given that a new clone would not include any work not synced
upstream, do you have a recommendation on the best way to carry over
untracked branches from one clone to another?
处理此问题的推荐方法是确保它不会发生。与您的团队沟通,告诉他们将要进行存储库清理,他们要做的就是确保他们在开始清理之前将任何分支上的所有工作推送到主存储库.
如果有人不这样做,他们可以尝试 将他们关心的分支变基到已清理的历史记录中。对于每个 feature
分支,类似于:
$ git rebase --onto clean-origin/feature unclean-origin/feature feature
...(粗略地翻译为“获取我的功能分支上的所有提交,我没有在清理之前推送到主仓库,并在该分支的主回购清理版本之上重播它们)。
如果用户弄错了,或者忘记只为一个分支做这件事,您将回到糟糕的混合 dirty/clean 历史场景。
结论
您了解您的团队,您确定他们都能完美地执行深奥的 Git 变基操作吗?如果他们这样做有什么好处?毕竟说完了,告诉他们删除旧的 repo 和 re-clone 不是更容易吗?
我本来打算在存储库上问这个问题,但 SO 似乎更适合问这个问题。
我能够使用 BFG Repo Cleaner(很棒的工具,谢谢!)将我们的 .git
文件夹大小减少超过 1GB,就我们的存储库而言,这是一个巨大的成功。我还没有将我的裸克隆推送到远程,因为我担心在了解推送然后不重新克隆的后果之前提出这些更改。
我了解最佳实践规定,当历史以这种方式改变时,最好的解决方案是执行新的克隆。然而,我与一个超过 50 人的团队一起工作,在一个超过 2GB 和 23k 提交的存储库中,在我们的结构下跨团队协调可能非常困难。结果,我有一些问题:
- 如果我推送这些更改后的引用,而人们拉到他们现有的副本而不是创建一个新的副本,会有什么后果?
- 如果可行,他们是否需要做任何其他事情来减轻这些后果,作为他们拉力的一部分,或者除了他们的拉力之外?
- 如果您认为被删除的 blob 来自至少 1 年至多 3 年的历史记录,此建议是否会完全改变?
- 最后,鉴于新的克隆不会包含任何未同步到上游的工作,您是否有关于将未跟踪分支从一个克隆转移到另一个克隆的最佳方法的建议?如果已经存在执行此操作的 Git 命令,我很想听听您的见解。
再次感谢您创建了这样一个方便的工具,希望我能完成它,使其对我团队的项目有用。在此期间,我将继续在我的叉子上进行实验。
前言
在我们开始之前,让我澄清在活跃的团队开发人员的背景下清理Git历史记录的推荐过程(无论使用什么技术用于清洁 - 无论是 BFG Repo-Cleaner 还是 git filter-branch
):
- 在存储库的本地一次性副本上练习几次清理,这样您就有信心可以做到并获得所需的结果,并且您知道需要多长时间。
- 与您的团队沟通。这是必不可少的,不可避免的(因为 Git 是专门为抱怨而设计的,如果历史被重写,这会成为阻碍)并且对于任何团队来说都是 良好实践 :-) 你需要告诉他们:
- 为什么要进行清理(例如较小的回购!)
- 计划 清理时 - 提前给他们适当的警告。
- 将他们的工作全部推到主仓库之前清理开始-不需要合并到主分支,但所有工作都需要在一个分支或另一个分支上进行推送。
- 建议他们在清理完成后需要删除旧的存储库副本,re-clone 新清理的存储库
- 当所有工作都推送到主仓库后,对主仓库执行 mirror clone。备份此克隆,以便在出现问题时随时返回。
- 运行 清理(使用 BFG Repo-Cleaner 或更慢的工具,如
git filter-branch
),然后使用git gc
trim死objects. - 一旦你对清理工作感到满意,将清理后的历史推送回主仓库(因为它是一个
mirror
克隆,所有旧的 branches/tags 将被覆盖到新的清理历史) - 告诉您的团队是时候删除他们旧的存储库副本,re-clone 清理存储库了。
所以,对于你的问题:
如果:具有 old 存储库的用户从 cleaned 存储库中提取?
What would the consequences be if I were to push these changed refs and people were to pull to their existing copy rather than create a fresh clone?
不好。根据经验,我可以说会有一团糟,人们会 困惑 和 沮丧 .
具体来说,在那个人的机器上发生的事情是 git pull
命令将旧的脏历史和新的清理历史合并在一起,有两个长期不同的历史(最初与第一个不同 'dirty' 提交你的历史,在你的情况下是 3 年前)与一个全新且非常混乱的合并提交结合在一起。用户很少清楚这已经发生 - 大多数 Git 日志可视化器不会以可能使其明显的方式呈现 - 如果你幸运的话,用户可能会说 "I've got two copies of every commit now, WTF?!" - 但前提是他们真的很细心。
如果该用户稍后进行了一些新的提交,并将其推回主存储库,他们会将脏历史推回已清理的主存储库,否定您的工作,使您的历史再次变脏,并创建一个非常令人困惑的 Git 历史记录,您的所有其他用户下次从主要 Git 存储库中拉出时都会接触到这些历史记录。
通过规划,有没有办法让用户保留他们的旧存储库但更新它以拥有清理过的历史记录?
Would they need to do anything else to mitigate these consequences as part of, or in addition to their pull, if this is feasible?
从技术上讲,是的。实际上,过程很复杂,error-prone,如果只有一个用户弄错了,你就和以前一样完蛋了。
在这一点上,我们必须找出你为什么要躲避这个程序。是不是因为:
- 您试图让用户不必了解和处理更改 Git 历史记录? 听起来这可能是您的目标,基于您的说 "cross-team coordination can be incredibly difficult under our structure" - 但不幸的是 这不是一个可以实现的目标 ,因为 Git 不会让你在没有用户的情况下更改历史记录注意。用户将不得不做某事,他们将需要与您协调。
- 您想减少对您真正庞大的存储库进行全新克隆的下载时间,希望 Git 只会下载已更改的 blob,而不是所有 没有 改变? 对于需要数小时下载的巨大 multi-gigabyte 回购来说,这是一个稍微更合理的目标(如果你使用 BFG 来制作回购小得多,动力也少)- 不幸的是,由于 Git 协议的详细信息,您 将无法 实现这些好处。 Git 协议旨在确定远程服务器上的哪些提交不在您的本地存储库中,并发送一个定制的包文件,其中仅包含您更新本地存储库所需的内容。这很好,但请注意比较的单位是 commits。当你重写历史时,提交的 文件树 几乎没有变化——但是提交 ID all 改变了,因为 t提交 ID 是它的 父母历史 的散列,也是它的文件树内容。 Git 协议只比较提交 ID,它们都是不同的 - 所以 所有 提交将被发送, 连同它们的 file-tree objects。该协议没有深入到意识到它不需要发送其中的大部分 file-tree object - 因此您无法从本地已经拥有它们的副本中获益回购
坏事发生在历史多久之前重要吗?
Does this recommendation change at all if you consider that the blobs that were deleted are from history that is at least a year old and at most three years old?
如果最近提交了错误的内容,并且还没有其他用户将其删除(因此,在过去的几小时或几分钟内),您可能会先于其他人快速清理主仓库上的历史记录拉它。一旦其他人拉出脏数据,就需要对其进行净化,最简单的方法是删除并 re-clone.
如果坏事是几年前犯下的,那么每个人都有,他们所有都需要净化。
清理时 没有 推送到主存储库的流浪 commits/branches 怎么办?
Finally, given that a new clone would not include any work not synced upstream, do you have a recommendation on the best way to carry over untracked branches from one clone to another?
处理此问题的推荐方法是确保它不会发生。与您的团队沟通,告诉他们将要进行存储库清理,他们要做的就是确保他们在开始清理之前将任何分支上的所有工作推送到主存储库.
如果有人不这样做,他们可以尝试 将他们关心的分支变基到已清理的历史记录中。对于每个 feature
分支,类似于:
$ git rebase --onto clean-origin/feature unclean-origin/feature feature
...(粗略地翻译为“获取我的功能分支上的所有提交,我没有在清理之前推送到主仓库,并在该分支的主回购清理版本之上重播它们)。
如果用户弄错了,或者忘记只为一个分支做这件事,您将回到糟糕的混合 dirty/clean 历史场景。
结论
您了解您的团队,您确定他们都能完美地执行深奥的 Git 变基操作吗?如果他们这样做有什么好处?毕竟说完了,告诉他们删除旧的 repo 和 re-clone 不是更容易吗?