跳至主要内容

Git Prune:什么是 Git 修剪以及如何使用 Git Prune

git prune 是一个 Git 命令,用于移除仓库中不再能从任何提交或分支到达的对象,帮助释放磁盘空间。
· 5分钟 阅读

使用 AI 探索

Git 对数据删除采取保护性策略,防止重要提交或数据被意外丢失。

然而,这也可能导致过时数据(例如对已删除分支的引用)仍然可见。随着时间推移,Git 仓库会累积无引用对象,它们会占用不必要的磁盘空间,并可能带来困扰。

Git 中的 git prune 命令是一种日常维护工具,主要用于清理仓库中无法到达的对象。

无法到达对象是指无法通过任何分支、标签、远程跟踪分支或其他引用访问到的对象。这些对象会在仓库中占用空间,长期下来会造成不必要的数据堆积。

虽然 git prune 是保持仓库精简的强大工具,但大多数用户可能无需直接使用它,因为 Git 会通过自动垃圾回收(git gc)来清理。了解其角色与功能,对高级 Git 用户或在需要(或偏好)手动维护仓库的特定场景中会有所帮助。

什么是 git prune?

git prune 命令用于移除本地仓库中不再需要的对象。这些对象可能是提交(commit)、树(目录快照)、二进制大对象(blob,文件)以及标签(tag),且它们不再能从仓库中的任何分支或标签访问到。

简单来说,git prune 有助于清理仓库中的不必要文件和数据,节省空间并减少杂乱。

对象如何变得不可到达?

对象可能通过多种方式变得不可到达——例如删除分支或重写提交。当分支被删除时,属于该分支且未被其他分支或标签包含的唯一提交将变为不可到达。

使用 git rebase 等命令进行提交重写会生成新的提交并丢弃旧的提交,从而也会使旧提交变为不可到达。

宽限期与 reflog

Git 维护了分支尖端和其他引用更新的日志,称为 reflog(引用日志)。可以使用 git reflog 命令查看。

即使一个对象不可到达,只要它仍在 reflog 中,git prune 也不会将其删除。

默认情况下,reflog 的过期时间为 90 天,提供了一个宽限期,在此期间不可到达对象会被暂时保留,不会立刻被修剪。

何时使用 git prune

通常,我们不需要直接使用 git prune。Git 具有垃圾回收机制,会在某些命令后自动运行,通过压缩部分对象来清理不必要文件并优化本地仓库效率。

尽管如此,我们也可能希望手动清理仓库,例如:

  • 在执行会产生不可到达对象的操作后(如删除分支)。 
  • 希望立即释放磁盘空间。
  • 希望随时保持仓库整洁干净。

使用 git gc 进行垃圾回收

通常建议依赖垃圾回收机制,而不是直接修剪。它不仅会执行 git prune,还会通过压缩对象来优化空间。

如上所述,垃圾回收会在某些命令后自动执行。我们也可以通过以下命令手动触发垃圾回收:

git gc

如何使用 git prune

由于 git prune 会删除数据,建议先使用 --dry-run 选项执行。

git prune --dry-run

该选项会列出将被修剪的对象,但不会实际删除。输出类似于:

0d7dff8258654c03a058987b3e63c86feca9200d commit
ea1380f52f0bfa0142e46767adfd56593681091a blob
fa91af78a1ab453c1d7632192b3ca8bf217ec711 commit

该输出表明有两个提交和一个 blob 不可到达,将被删除。在确认没有重要数据被列出后,我们可以继续执行清理:

git prune

在某些情况下,我们希望在执行会导致对象不可到达的操作(如删除分支)后立即清理仓库。我们可能运行 git prune --dry-run,但输出为空。原因是被删除的提交仍在 reflog 中被引用。

如果不想等待它们在 reflog 中过期,可以使用以下命令手动使其过期:

git reflog expire --expire-unreachable=now --all

我们来分解一下所用选项:

  • --expire-unreachable=now 选项将所有不可到达对象的过期时间设为现在,从而立即使其过期。
  • --all 选项会作用于仓库中的所有 reflog 条目。若不使用该选项,我们需要指定要操作的特定引用(如某个分支或标签)。

git prune:高级用法

来看一些进阶技巧,例如指定过期时间或修剪已打包的文件。

指定过期时间

我们可能只想清理较旧的不可到达对象,例如只修剪至少两周前的对象。

--expire <time> 选项允许指定截止时间。Git 会删除不可到达时间超过指定时长的对象。<time> 参数支持多种格式,如 "2 weeks ago"、"3 days"、"yesterday" 等,便于灵活设定过期周期。

示例命令:

git prune --expire=2.weeks.ago

修剪已打包的文件

Git 主要通过两种方式存储对象:作为单独文件(松散对象)和作为打包文件(pack)。打包是一种通过将多个对象存储于单个文件并去除冗余来节省空间、提升性能的机制。

有时,同一个对象可能同时以松散形式和打包形式存在。这种冗余虽无大碍(只是多占一点磁盘空间),但我们可能希望清理那些已被打包却仍以松散形式存在的对象以回收空间。

git prune-packed 命令会移除已包含在 pack 中的松散对象。与 git prune 不同,git prune-packed 不接受 --expire <time> 等选项。它仅用于清理已被打包的松散对象。

总结

随着我们使用仓库,一些对象会变得不可到达,从而造成不必要的磁盘占用。Git 通过垃圾回收系统来管理这一点,在对象一段时间未被使用后删除不可到达对象。

垃圾回收机制会在某些命令后由 Git 自动执行,但我们也可以使用 git gc 命令手动运行。该过程不仅会通过 git prune 移除不可到达对象,还会通过压缩部分对象来优化磁盘空间。

高级 Git 用户可能希望手动保持仓库整洁。git prune 命令可用于手动删除不可到达对象。在执行 git prune 前,应始终先运行 git prune --dry-run,以预览修剪过程中将被删除的对象。

François Aubry

作者

François Aubry

全栈工程师,CheapGPT 创始人。我一直热爱教学。从学生时代起,我就积极寻找机会为同学提供辅导与帮助。这份热情促使我攻读博士学位,并在此期间担任助教,以支持我的学术追求。那些年里,我在传统课堂环境中收获了极大的成就感,既建立联系也促进学习。随着在线学习平台的兴起,我也看到了数字教育的变革潜力。事实上,我曾参与我们大学一款此类平台的建设。我致力于将传统教学理念与创新的数字方法相融合。我的热情在于打造既有吸引力、信息量充足,又能让当代学习者轻松获取的课程。

主题