如何配置Git以保留所有推送至服务器的提交、树、Blob和标签,同时仍允许通过git repack优化存储?
这个需求我太懂了!管理上千个仓库,部分还有百万级提交,既要保住所有推上来的东西不丢,又得让git repack正常优化存储,还怕搞一堆refs把ls-remote搞炸——完全是生产环境里的真实痛点,我之前在维护类似规模的Git集群时踩过不少坑,给你分享几个靠谱的方案:
方案一:用隐藏的永久引用锁死所有对象(最可靠)
Git的GC机制只会删除没有任何引用指向的对象——不管是分支、标签,还是你自己建的自定义引用,只要有个ref指着它,GC就动不了它。那我们的思路就是:每次推送后,把所有新提交(包括标签)都塞进一个隐藏的引用空间,既不会被ls-remote显示,又能给每个对象上"保险"。
具体操作步骤
添加服务器端推送钩子
在服务器端仓库的post-receive钩子(Gitea里可以在仓库「设置-钩子」中添加服务器端钩子)里写脚本,每次推送后自动给新增的提交创建隐藏引用:#!/bin/bash # 处理本次推送的所有ref更新 while read oldrev newrev refname; do # 跳过删除ref的操作 if [ "$newrev" = "0000000000000000000000000000000000000000" ]; then continue fi # 提取本次推送新增的所有提交哈希 git rev-list $oldrev..$newrev | while read commit_hash; do # 创建隐藏引用:refs/keep/commits/[哈希] git update-ref refs/keep/commits/$commit_hash $commit_hash done # 如果推送的是标签,同步到隐藏空间 if [[ $refname == refs/tags/* ]]; then tag_name=$(basename $refname) git update-ref refs/keep/tags/$tag_name $newrev fi done exit 0(不用给Blob和树单独加引用,因为提交会引用树,树会引用Blob,只要保住提交,底下的对象自然不会丢)
配置Git隐藏这些引用
在仓库的.git/config里添加以下配置,让git ls-remote不显示这些隐藏引用:[transfer] hideRefs = refs/keep/这样别人用
git ls-remote时,完全看不到这些refs/keep/下的引用,不会污染输出,完美解决你担心的ls-remote膨胀问题。保留基础GC配置
继续保留gc.pruneExpire = never,现在加上隐藏引用的双重保险,哪怕Gitea跑GC,也绝对删不掉任何有引用的对象。
方案优势
- 100%可靠:所有推送的提交都有专属引用,GC碰不了
- 无副作用:隐藏引用不会影响
ls-remote、git branch等日常命令 - 低开销:每次推送只处理新增提交,对于百万提交的仓库,首次初始化后日常开销可以忽略
方案二:拆分GC逻辑,只做打包不做清理(更简单)
如果你觉得写钩子脚本太折腾,还有个更轻量化的配置方案——直接把Git的GC拆成两半:允许它做repack优化存储,但彻底阻止它删除任何对象。
具体操作步骤
修改仓库Git配置
编辑仓库的.git/config,改成以下内容:[gc] pruneExpire = forever # 哪怕无引用对象也永远不删 auto = 0 # 禁用Git自动GC [repack] useDelta = true # 保留delta压缩(repack优化核心) packedGitLimit = 512m # 可根据你的存储容量调整 packedGitWindowSize = 100m接管GC触发逻辑
去Gitea的app.ini配置文件里,找到[git]部分的GCInterval,把它改成0或者直接注释掉,禁止Gitea自动跑git gc。然后自己写个定时任务(比如用Cron),定期给所有仓库跑:git repack -a -d -f这个命令只会把所有松散对象重新打包成更高效的压缩包,删除旧的无用打包文件,但绝对不会删除任何对象——包括无引用的。
方案优势
- 配置简单:不用写钩子脚本,改几个配置就行
- 完全可控:自己掌握GC节奏,避免Gitea误操作
- 不影响存储优化:
repack的所有压缩、打包优化都能正常运行
针对Gitea的额外注意事项
- 一定要检查Gitea的
app.ini配置,确保它不会强制触发git gc——比如[git]下的GCInterval要设为0,或者直接关闭自动GC功能 - 对于上千个仓库的批量配置,可以用脚本遍历所有仓库路径,批量修改
.git/config和添加钩子脚本,比如用find命令配合xargs批量操作
最后总结
- 追求绝对可靠选方案一:隐藏引用+钩子的组合,哪怕Gitea乱搞GC也不怕,是生产环境的首选
- 图省事选方案二:拆分GC逻辑,用定时任务跑
repack,适合不想折腾脚本的场景 - 不管用哪个方案,
git repack都能正常运行——它只是做存储打包优化,和对象保留完全不冲突,放心用就行!




