了解如何从 Git 历史记录中移除大型二进制文件,以管理克隆存储库的大小

Azure DevOps Services | Azure DevOps Server 2022 - Azure DevOps Server 2019

近年来,Git 作为一种分布式源代码存储库广受欢迎,利用它,用户可以在断开连接的状态下使用完整的存储库。 Git 的好处显而易见,但如果你需要在主存储库上“还原”,会发生什么情况? 这样做不是那么直观并且需要提升的权限,正如你可能期望的那样,会影响存储库的每个用户。

那么,如何安全地回退中心存储库呢?

问题场景

假设你将一个大型文件(例如视频)提交到 git 服务器。 在传统的源代码系统中,将所有内容存储在一个位置,然后拉取所需内容,这是很方便的。 然而,使用 git,会将整个存储库克隆到每个用户的本地计算机上。 对于大型文件,项目中的每个用户也需要下载该大型文件。 随着后续的每个大型文件提交到服务器,问题只会增加,直到存储库太大而无法满足用户的需求。 更糟糕的是,即使将违规者从本地存储库中移除并重新提交,该文件也仍然存在于存储库的历史记录中,这意味着它仍将作为历史记录的一部分下载到每个人的本地计算机上。

显示包含的更改中的大型视频的“团队资源管理器更改”对话框

将大型文件添加到本地存储库

包含大型视频文件的副本的服务器存储库和本地存储库

从本地存储库提交后,服务器也将包含大型文件

冻结存储库

重要

以下步骤将从分支历史记录中移除视频,但当你从 Azure Repos 克隆存储库时,该文件仍保留在存储库历史记录中。 从分支历史记录中删除文件会阻止文件更新,这将在存储库中创建另一个版本的大型文件。 详细了解在 Git 中管理大型文件,并参阅此博客文章,以了解使用 Azure Repos Git 存储库时有关此行为的详细说明和解决方法。

要解决此问题,必须从源头着手,在本例中为服务器存储库。 要求团队停止推送到存储库,但如果在此过程中发生其他推送,你也必须考虑到这些推送,以免丢失任何数据。

变基和强制推送

如果团队中其他人都没有对存储库进行过任何更改(通常是通过推送),你可以采取简单的方法,即使本地存储库外观基本上与你所需的一致(也就是说,不包含大型文件),然后强制对服务器进行更改。

注意:在开始这项工作之前,可能需要克隆或修复本地存储库。 这可能会导致工作丢失或更改,因此请谨慎操作。

默认情况下,你可能只能更改其本地项目文件和存储库并将所做的更改推送到服务器,因此你无法在服务器级别进行其他更改(例如删除或变基)。 因此,你需要从管理员那里获取项目强制推送(首选)或管理员权限,或者找到拥有这些权限并愿意提供帮助的人。 有关 git 权限的详细信息,请转到此处

命令提示符 - git push --force 权限。

接下来,你需要对存储库进行变基。

  1. 但首先,请使用 git log 查找最近提交的 SHA 哈希值 - 稍后你将需要此信息。 这是因为我们需要知道最近的良好提交。 通过打开 git 命令提示符并键入以下命令来获取该信息:

git log

此外,也可以通过在 Visual Studio 团队资源管理器中查看分支历史记录来获取 SHA 哈希。

主分支“查看历史记录”

  1. 现在,请打开 Git 命令提示符。

同步对话框 - 打开命令提示符操作

  1. 查找感兴趣的 SHA 哈希。

命令提示符 - 选择视频提交

  1. 你将需要以“25b4”开头的 SHA

请记住,git 使用指针来确定头部分支或当前分支在存储库中的位置。 因此,你感兴趣的存储库状态将处于过去的某个时间点。 要“回到过去”并使之前所需的状态成为新的当前状态,你需要使用 git rebase 命令:

git rebase -i <SHA hash of desired new current branch>

变基以移除视频文件

-i 切换提供了一点额外的安全性,因为它将在编辑器中显示历史记录(如果你使用过基于 Unix 的系统,你可能还记得我在 Windows 中的命令行上实现 git,从而打开了经典 vi 编辑器。)

  1. 对于我们的示例,你将输入:

git rebase -i 25b4

  1. 编辑器出现后,移除所有“pick”行,但要保留作为新头部分支的分支除外。 如果一切顺利,在 vi 中,键入“:w<enter>”以进行保存,或键入“!q<enter>”以退出而不保存。

命令提示符 - git rebase -i 25b4 pick 命令

你将更改不再需要的行

命令提示符 - git rebase -i 25b4 drop 命令

  1. 如图所示,将“pick”更改为“drop”,然后在 vi 中键入“:w”进行保存,并键入“:q!”以开始变基

现在再次键入 git log - 日志中应该没有违规分支。 如果存在违规分支,则你已准备好执行最后一步,这需要项目管理员权限。

git log

变基后的本地和服务器存储库

请注意,现已从本地存储库中删除对大型视频的提交

  1. 类型:git push --force

命令提示符 - git push --force

命令提示符 - git push --force 结果

此命令将强制存储库覆盖服务器上的存储库。

请谨慎使用,因为很容易丢失服务器上的数据!

显示要保留的内容(不包含视频文件)的强制推送

请注意,必须向服务器进行身份验证才能使其正常工作

如果使用的是 Azure Repos,可能需要设置一个不使用特殊字符(例如电子邮件地址中的“@”)的备用凭据。 为此,请按照此处的说明进行操作。

现在,分支将从服务器上永久删除,项目团队成员的后续克隆和同步将不会下载你试图移除的大型文件。 用户将需要从服务器中拉取,以确保他们与新的服务器存储库状态同步。

如果用户有更新的提交

如果其他用户已经提交给服务器存储库,则你还需要考虑其他注意事项。 你想要移除包含大型文件的分支,但又不希望丢失团队所做的更改。 若要解决此问题,当你在变基过程中打开编辑器时,请仔细查看提交。 确保在“pick”行中列出了要保留的提交;删除想要移除的提交,例如添加大型文件的位置。

请注意,在变基之后,团队中的其他用户也需要变基,以便每个人都拥有一致的服务器存储库副本。 这对每个人来说都是一种痛苦,通常应该避免。 因此,如果确实需要移除此处所述的推送,请务必与团队协调。 有关变基的完整详细信息,请查看此处的官方变基文档。

关键是要确保你知道所需的提交和不需要的提交。 在 IDE(例如 Visual Studio)中研究 git 日志或历史记录,并详细记录要保留和丢弃的 SHA 哈希。

在大型文件已经存在一段时间并且有后续分支和合并的情况下,可以使用 git filter-branch 切换移除该文件。 如果想尝试一下,请按照此处的说明进行操作。

最佳做法注意事项

它可节省大量工作,以确保大型文件一开始就不在主存储库中。 考虑到这一点,下面是团队要牢记的一些常识性最佳做法:

应做事项

  • 请经常提交更改。 你以后始终可以用 squash 或 rebase 来修复它们。
  • 请使用分支来隔离你的更改。 分支成本低廉且专用,合并也很简单。 还可以通过将分支推送到服务器来备份分支上的更改。
  • 发布主题分支时,请务必使用命名约定。 将分支命名为“users/<alias>/<branchname>”。 这将有助于对分支进行分组,并使其他人能够轻松标识“所有者”。
  • 请记住务必推送更改。 Commit != Checkin(Commit + Push) == Checkin
  • 请考虑对大型二进制文件使用 .gitignore,这样一开始就不会将这些文件添加到存储库中。有关详细信息,请单击此处
  • 请考虑使用 NuGet 或 TFS 版本控制来存储大型二进制文件。

禁止事项

  • 不要在推送后进行变基。 在 git 中对推送的提交进行变基可能不是件好事,因为它会强制存储库中的其他所有人对其本地更改进行变基。如果他们需要这样做,他们不会很高兴。 即使是推送的,在你自己的个人分支上对推送的提交进行变基也并不是什么大不了的事情,除非其他人正在拉取这些提交。
  • 不要将二进制文件提交到存储库。 Git 不会像 TFVC 那样压缩二进制文件,因为所有存储库都具有所有历史记录,因此提交二进制文件意味着永久膨胀。

摘要

有时会将不需要的元素(例如大型文件)添加到存储库中,因此需要将其移除,以使存储库保持干净且轻量级。 为此,可以使用 git rebase 命令按顺序获取本地存储库,然后使用 git push --force 命令通过本地存储库覆盖服务器存储库。

作者:Edward Fry 和 Jesse Houwing | 联系作者和 ALM | DevOps Rangers 此处

(c) 2015 Microsoft Corporation。 保留所有权利。ÿ本文档“按原样”提供。本文档中表达的信息和观点(包括 URL 和其他 Internet 网站引用)如有更改,恕不另行通知。 您自行承担其使用风险。

本文档未向您提供任何 Microsoft 产品中任何知识产权的任何合法权利。 您可为了内部参考目的复制和使用本文档。