不会,git gc 默认只清理无任何引用(分支、标签、reflog)指向的不可达对象,未推送的提交只要被本地分支或reflog引用就安全;但若使用--prune=now会绕过reflog保护导致误删。

git gc 会删掉你还没推送的提交吗
不会,但前提是你没用 --aggressive 或手动指定 --prune=now。默认的 git gc 只清理“不可达对象”——也就是那些没有任何引用(branch、tag、reflog)指向的 commit、blob、tree。你本地分支上最新的提交、reflog 里最近 30 天的操作记录、甚至刚 merge 完但还没 push 的新 commit,全都被视为“可达”,不会被删。
常见错误现象:执行 git gc 后发现某个刚合完但没推的 feature 分支不见了。其实不是被删了,而是你误删了该分支(比如用了 git branch -D),或者 merge 时用了 --squash 导致原分支 head 没被保留,reflog 又过期了,这才让对象变成“不可达”。
-
git gc默认保留 reflog 中未过期的条目(默认 30 天),所以只要没手工清空 reflog,merge 后的提交基本安全 - 如果执行了
git gc --prune=now,reflog 保护就失效了,未被任何引用指向的对象会立刻被回收 -
git fsck --unreachable可以列出当前所有不可达对象,帮你预判 gc 影响范围
git prune 和远程分支删除有什么关系
git prune 不处理远程分支,它只清理本地对象数据库里“不可达”的 Git 对象。远程分支信息存在 .git/refs/remotes/ 下,属于引用(ref),不是对象(object)。真正同步远程分支状态的是 git fetch --prune 或 git remote update --prune。
容易踩的坑:有人以为 git prune 能删掉本地残留的远程跟踪分支(比如 origin/old-feature),结果发现没用。这是因为这些 ref 还活着,只是对应远程已删,它们本身仍是“可达引用”,git prune 不碰它们。
- 删本地残留远程跟踪分支,应该用
git remote prune origin -
git fetch --prune等价于先 fetch 再自动 prune,是日常推荐做法 -
git prune前建议先git fetch --all,避免把刚 fetch 到但尚未被本地 ref 引用的新对象误删
merge 后立即 gc + prune 有没有必要
没必要,而且可能干扰协作流程。merge 操作本身不产生垃圾对象;只有当你反复 reset、rebase、amend 或强制 push 后又丢弃旧引用时,才会积累不可达对象。一次干净 merge 后,git gc 几乎不释放空间。
性能影响很小,但时机很关键:如果你在 merge 后立刻 git gc --prune=now,而同事刚好在推新提交,你本地 fetch 还没完成,就可能把对方刚推上来、你还没 fetch 到的对象提前删掉——下次 fetch 会重新下载,但体验变差。
- Git 自动在某些操作(如
git repack、git fetch)后触发轻量级 gc,无需手动干预 - 真正需要手动
git gc的场景:仓库体积异常膨胀(比如误提交大文件后又 rm + commit)、或长期离线开发后想压缩 packfiles - CI/CD 流水线中可加
git gc --auto,它会按需触发,比盲目强制更安全
为什么 git gc --aggressive 实际效果常不如预期
--aggressive 并不是“更彻底地删”,而是换了一种 pack 压缩策略:它会尝试把所有松散对象重打包成更少、更大的 packfile,并做更耗时的 delta 压缩。但对象数量没变,只是存储方式变了;而且它会清空 reflog(除非显式加 --keep-largest-pack),反而增加丢失历史的风险。
真实效果往往相反:首次运行可能略减体积,但后续再跑,因 pack 已优化,收益趋近于零;同时 CPU 和 I/O 占用飙升,尤其在大仓库里卡住几秒到几分钟。
- 普通项目完全不需要
--aggressive,git gc默认行为已足够 - 若真要压缩 pack 大小,优先用
git repack -adF(-a 合并所有 pack,-d 删除旧 pack,-F 启用深度 delta) -
git gc --aggressive后 reflog 清空,git reflog将无法回溯近期操作,这点极易被忽略











