在`git pull`时自动触发`git prune`吗?

13

在我本地的公司代码库副本上(我经常创建很多短期分支并频繁使用git rebase,同时许多其他人也将短期分支推送到我正在拉取的origin),我经常与git进行以下对话。

(env)$ git pull
remote: Counting objects: 382, done.
remote: Compressing objects: 100% (247/247), done.
remote: Total 382 (delta 182), reused 62 (delta 62), pack-reused 73
Receiving objects: 100% (382/382), 228.63 KiB | 0 bytes/s, done.
Resolving deltas: 100% (232/232), completed with 15 local objects.
From github.com:anon/anony2
   aee962f..055a717  master     -> origin/master
   [...]
Auto packing the repository in background for optimum performance.
See "git help gc" for manual housekeeping.
error: The last gc run reported the following. Please correct the root cause
and remove .git/gc.log.
Automatic cleanup will not be performed until the file is removed.

warning: There are too many unreachable loose objects; run 'git prune' to remove them.

Updating aee962f..055a717
Fast-forward
Auto packing the repository in background for optimum performance.
See "git help gc" for manual housekeeping.
error: The last gc run reported the following. Please correct the root cause
and remove .git/gc.log.
Automatic cleanup will not be performed until the file is removed.

warning: There are too many unreachable loose objects; run 'git prune' to remove them.
 [...]
 9 files changed, 128 insertions(+), 95 deletions(-)
(env)$ git prune
Checking connectivity: 772524, done.
(env)$ rm .git/gc.log
(env)$

也就是说:我输入 git pull 命令后,Git 会返回一大堆信息,其中包含两个必须的命令,我需要手动执行这些命令才能继续我的工作。

如果 Git 能够自动帮我执行那些命令,而不是强制我复制和粘贴它们,那就太好了。我知道这不是 git pull 的默认行为,但这似乎应该是一个可以添加到我的 .gitconfig 文件中的选项。是否存在这样的选项?


1
如果我理解正确的话,自动执行的 git gc 没有做正确的事情的唯一原因是我的 git reflog 太大了,因为我经常进行激进的变基(而仍在 reflog 中的内容不会被 gc,但它们会被 prune)。如果“减少我的 reflog 的默认保留策略”既可行又足以解决我的问题,那么我将接受一个只描述如何执行此操作的答案。 - Quuxplusone
为什么不为此编写一个Shell脚本呢? - kabanus
@kabanus:如果有一个涉及编写shell脚本的答案,我可能会接受;但是当“git pull”失败时,它必须DTRT,并且它必须是“git pull”的即插即用替代品(即,我应该能够在命令行上调用它作为“git pull”,“git pull origin”等,而特别是作为“my-git-pull.sh”或其他任何东西,因为我的手指不知道那个短语);即使这样,它也不是最佳答案,因为它最终不会教我如何使用git。但是它可能会胜过“这在git 3.7.42中;只需升级!”之类的答案 ;) - Quuxplusone
git config --get extensions.preciousobjects 的输出是什么?(这是在 Git 2.7.0 中引入的功能,它可以防止 git gc 剪切对象。) - torek
@torek: git config --get extensions.preciousobjects 返回空值并返回退出码1。 git --version 输出 git版本2.9.3 - Quuxplusone
好的,那么这很可能是问题所在。 :-) - torek
1个回答

14

问题很可能是您生成的松散对象足够快,以至于实际上超过了默认的git gc保护时间2.weeks.ago

--prune=<date>
       修剪早于指定日期的松散对象(默认为两周前,可以通过配置变量gc.pruneExpire进行覆盖)。--prune=all会修剪所有松散对象,而不考虑它们的年龄(不要使用--prune=all,除非你非常清楚自己在做什么。除非存储库处于静止状态,否则你将会失去尚未被锚定引用的新创建的对象,并且最终会损坏你的存储库).--prune默认开启。

这里发生的是git gc在后台自动使用其默认机制修剪松散对象,即运行git prune --expire=2.weeks.ago(或您为gc.pruneExpire配置的任何内容)。但这会留下足够的松散对象,以至于git gc认为它修剪得不够好。
在手动git prune中无需过期时间(如manual git prune)或使用--prune=allgit gc中,可以删除所有松散对象。只有在没有其他Git命令正在运行时才安全。由于git gc --auto在后台运行,因此需要一个安全裕度,但两周对您的用途来说太长了。
如果您确信各种Git命令将在一周内甚至可能一天内完成, :-)则可以将gc.pruneExpire配置为1.week.ago1.day.ago以更积极地进行修剪。除非您正在生成大量松散对象,否则这通常就足够了。
$ git config gc.pruneExpire 3.days.ago

请注意,当以此方式设置时,您仅更改存储库的设置,并覆盖任何更全局的设置。或者:
$ git config --global gc.pruneExpire 1.week.ago

这将把你的个人(用户全局)默认设置为一周,而不是两周(但如果设置了特定于存储库的“三天”设置,则将被覆盖)。

我注意到在检查所有内容时,extensions.preciousObjects 没有文档说明。(与所有配置变量一样,可能会拼写任意的大小写混合。)它是在Git 2.7.0中添加的,可以防止 所有 对象的自动修剪,如果您设置了一个共享库,可能需要这样做。(它很棘手,可能不是任何普通用户都应该设置的东西。)


这个答案可以进一步改进,通过展示如何在.gitconfig文件中启用gc.pruneExpire来实现。我应该创建一个[gc]部分,并将pruneExpire = 1.week.ago添加到该部分中,但只是为了记录...? - Quuxplusone
很难确定它是否有效(因为如果它有效,根据定义我不会注意到 :)),但至少我暂时接受它。谢谢! - Quuxplusone

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接