仓库维护
git 从不告诉你一个仓库花了多少代价。不管它的对象数据库处于什么状态,它都照常干活,所以麻烦的第一个信号通常是一次慢如爬行的克隆,或者一台没有磁盘空间了的笔记本——而那时距离「一条命令就能搞定」的时刻,早就过去很久了。
这个面板就是那份缺失的读数:空间去哪儿了,其中多少能回收,以及每个任务在你运行它之前会做什么。
⌘K → 仓库维护。

读懂这些数字
所有数据都来自 git count-objects -v 和一次真实的可达性遍历——没有任何一项是估算的。
| 行 | 是什么 | 为什么会涨 |
|---|---|---|
| 已打包 | packfile 内部的对象,经过压缩和增量化 | 这是健康的状态 |
| 松散 | 每个对象一个文件,几乎没压缩 | 每次提交、每次获取都在写这些 |
| 不可达 | 已经没有任何东西指向它们的对象 | 被丢弃的提交、被修补过的消息、被放弃的变基 |
松散旁边那个计数——「n 个对象,其中 m 个已经打包过」——才是值得盯着看的那个。那 m 个东西存了两遍:一遍松散地存着,一遍在包里。它们是纯粹的重复,而 git gc 就是把它们塌缩掉的那把刀。
不可达还不等于垃圾。 正是这些对象,让 git reflog 能把你重置掉的提交请回来。git 是有意把它们留两周的。
那些任务
| 按钮 | 运行的是 | 代价 |
|---|---|---|
| 优化 | git gc |
几秒到一分钟。几乎永远是正确答案 |
| 从零重新打包 | git gc --aggressive |
大仓库上要几分钟。重算每一个增量 |
| 重建 commit graph | git commit-graph write --reachable |
很快。让日志和图的遍历明显更快 |
| 检查完整性 | git fsck --dangling |
大仓库上很慢,但什么都不改 |
| 立刻丢弃不可达对象 | git gc --prune=now |
毁掉 reflog 这张安全网 |
优化才是你该伸手去按的那个。它把松散对象打包,丢掉那些不可达已超过两周的东西,并让近期的历史仍然可恢复。
从零重新打包被吹过头了。它把现有的每一个增量都扔掉,从零开始重算,要花好几分钟,而通常也就比普通的 gc 多省下百分之几。导入一份巨大的历史之后做一次值得;例行公事地做,不值得。
立刻丢弃不可达对象会先问你,而且确认框里会写明有多少个对象、多少空间。做完之后,你一小时前重置掉的那个提交就再也找不回来了——reflog 条目也许还列在那儿,但它背后的对象已经没了。
检查完整性
git fsck 会核实:被其他对象引用的每一个对象都确实存在,而且内部自洽。
- 悬垂对象是正常的。 它们就是那些不可达对象,按名字列出来。一次变基之后有几百个悬垂对象的仓库是健康的。
- 缺失的对象才是损坏——一次被截断的写入、一块坏盘、一次中断的传输。一旦出现,千万不要重新打包:对一个已损坏的数据库做重新打包,可能把一个还救得回来的问题变成永久性的。从你的远程克隆一份好的副本,再用一个 bundle 把你没推送的分支搬过去。
后台维护
这个复选框会把仓库注册给 git maintenance,由它按你操作系统运行的计划(launchd、systemd 或任务计划程序)来打包和预取。
这里没有任何东西是 Gitcito 专属的:同一份计划也为你的终端服务,而且 git maintenance unregister 在任何地方都能撤销它。取消勾选做的正是这件事,同时会把计划本身留在原处,继续服务其他已注册的仓库。
值得知道的限制
- 不可达计数需要一次完整的可达性遍历,所以在一个特别大的仓库上打开这个面板会顿一下。那是诚实的数字,不是估算。
- 大小是磁盘实际交出去的量,不是内容的长度。一个 400 字节的松散对象照样占掉一个 4 KB 的块,这就是为什么一千个这样的对象要花掉好几兆——也是为什么把它们打包起来值得做。
- 工作树或子模块有自己的
.git,所以这里显示的大小只属于这一个仓库。 - 维护不能让历史变小。 如果一个 400 MB 的 blob 在某个提交里,它就是可达的,gc 会永远留着它——那属于把一个文件从历史中移除,是另一件事,而且破坏性大得多。
- Gitcito 从不背着你跑 gc。 git 自己的
gc --auto仍然可能会跑,一如既往;如果某次失败了,它会在.git/gc.log里留一条记录,而这个面板会把它显示出来。
另请参阅:把一个文件从历史中移除 · Bundle 与归档 · 恢复