0

我想从 git 存储库中删除大量单元测试文件,并将它们从提交历史记录中擦除,以节省空间。我知道这样做的两种主要方法是使用 git filter-branch 或使用 BFG repo 清洁器(由Roberto编写。)

1) 假设主 repo 已经被清理并且团队成员没有删除他们旧的脏版本 repo。如果他们执行 git pull --rebase,然后推送到主仓库,历史还会变脏吗?

2) 如上所述,假设主 repo 已被清理,并且团队成员尚未删除他们旧的脏版本 repo。假设团队成员推送到主仓库。我怎么能知道团队成员使用了他们肮脏版本的 repo 进行了推送?(我是否必须只比较该提交的父级的提交哈希?我的理解是,无论是通过 BFG 还是 git filter-branch 清理主仓库都会更改仓库中所有提交的所有哈希)

4

2 回答 2

0

这两个问题的答案都是肯定的:将旧(清理前)存储库与新(清理后)存储库混合会导致两个存储库合并。然而,对于问题 2,git push没有做git fetch第一个的顺子(或任何类型的拉,它运行 fetch 作为它的第一步),无论是谁做git push都会看到失败,接收存储库抱怨推送不是快进。他们将不得不使用+or--force标志来覆盖这个失败。

git pull可能会或可能不会因抱怨不相关的历史而失败,这取决于哪些复制的提交(参见下面的描述)最终会重新使用原始提交。这也取决于特定的 Git 版本,因为较旧的 Git 会尝试git merge不相关的历史记录而不需要该--allow-unrelated-histories选项。

(我是否必须只比较该提交的父级的提交哈希?我的理解是,无论是通过 BFG 还是 git filter-branch 清理主仓库都会更改仓库中所有提交的所有哈希)

这是正确的,但在某些重要细节上是错误的。

过滤(通过任何方式)实际上是复制提交的过程。我们获取所有原始提交,以及它们的父哈希 ID 和树以及存储的 blob,并复制每个提交到一个新的提交。新提交将应用过滤器:我们删除任何我们想要删除的 blob,或对树和/或提交元数据(用户名、时间戳、消息等)进行我们希望的任何其他更改. 第一个结果是另一棵树,如果我们没有对树进行任何更改,则重用一些现有的树哈希 ID,或者如果新树与每个现有树不同,则重用新树 ID。我们使用更新的父哈希将这个旧的或新的树 ID 放入我们的旧的或新的提交元数据中。如果任何先前提交发生任何更改,则更新的父哈希是新的,否则相同。然后我们进行新的提交:如果它与原始提交 100% 相同,我们将返回原始哈希 ID,否则我们将获得一个新的哈希 ID。

这意味着只要新副本与原件 100% 逐位相同,您实际上只是在重复使用原件。但是一旦某个提交发生了变化,哪怕是一点点,新副本就是一个不同的提交,并且它的所有子节点现在都有一个不同的父哈希,并且它们本身也是不同的提交。

最终效果是,在使用 过滤存储库后git filter-branch,您通常拥有一个加倍的存储库,减去 Git 能够重用现有提交的任何数量。原来的分支头现在只能通过refs/original/命名空间找到。如果您使用 a --tag-name-filter cat,则所有标签都会更新以使用新提交,因此删除所有refs/original/引用会消除原始提交。

BFG 通过重写原始引用而不保留备份来避免所有这些refs/original/(当然比 更快、更方便git filter-branch)。尽管如此,它仍然有效地将所有原始提交复制到新提交。实际上,您复制的存储库是一个几乎全新的存储库,永远不应与旧存储库混合。

当然,如果有人想要从基于旧版本的自己的存储库中带来一些提交,那么该人将不得不以某种方式混合新旧存储库。 进行这种混合的人要小心,并确保不会重新引入所有旧的提交。

对于许多用户来说,在大多数情况下,将过滤后的存储库视为一个全新的项目就足够了,重新克隆它并丢弃他们以前的存储库。只有那些承诺移植的人需要了解以上所有内容。

于 2018-04-16T21:50:41.110 回答
0

1)别担心,他们的拉动会失败。因为历史不同,他们需要修复远程存储库和本地存储库之间的差异。正如您所提到的,删除本地存储库并进行新的克隆是执行此操作的一种方法,但它可能会丢失有价值的数据 - 例如,在其他分支或 .gitignored 文件中。

更好的方法是在强制更新后 Git 拉取

2)同样,别担心 - git 不会让他们推送具有不同历史记录的副本。他们将需要使用--force来执行此操作,因此他们会非常清楚自己正在覆盖其他人的工作。

如果他们要使用--forcegit 不会阻止他们(就像它并没有阻止你一开始就使用--force来改变历史一样)。但是,您可以将服务器配置为拒绝某些人的强制推送。如果您使用网络服务;GitHub、GitLab、BitBucket 等都有拒绝强制推送的选项 - 转到存储库的设置进行配置。

于 2018-04-16T21:40:23.290 回答