如何通过非交互方式挤压除最近提交之外的所有提交来减小膨胀的Git回购的大小?

如何通过非交互方式挤压除最近提交之外的所有提交来减小膨胀的Git回购的大小?,git,rebase,git-rebase,git-rewrite-history,Git,Rebase,Git Rebase,Git Rewrite History,我的Git repo有数百GB的数据,比如说数据库备份,所以我尝试删除旧的、过时的备份,因为它们让一切变得更大、更慢。所以我自然需要一些快速的东西;越快越好 我如何挤压(或者干脆移除)除最近提交之外的所有提交,并且不必手动挤压一个文件中的每个提交?具体来说,我不想使用 git rebase -i --root 例如,我有以下提交: A .. B .. C ... ... H .. I .. J .. K .. L 我想要的是(将A和H之间的所有内容压缩成A): 甚至这样也行: H .. I

我的Git repo有数百GB的数据,比如说数据库备份,所以我尝试删除旧的、过时的备份,因为它们让一切变得更大、更慢。所以我自然需要一些快速的东西;越快越好

我如何挤压(或者干脆移除)除最近提交之外的所有提交,并且不必手动挤压一个文件中的每个提交?具体来说,我不想使用

git rebase -i --root
例如,我有以下提交:

A .. B .. C ... ... H .. I .. J .. K .. L
我想要的是(将
A
H
之间的所有内容压缩成
A
):

甚至这样也行:

H .. I .. J .. K .. L
有一个关于如何提交的答案,但我想保留一些最近的提交。我也不想。(特别是我需要保持前两次提交从顶部开始计数。)

(几年后编辑。这个问题的正确答案是使用合适的工具来完成这项工作。Git不是存储备份的好工具,不管它有多方便。)

原始海报:

如果我们对commit 10004进行快照,删除它之前的所有提交,并将commit 10004设置为根提交,我就可以了

一种方法是在这里,假设您当前的工作名为
branchname
。每当我做一个大的重新基准时,我喜欢使用一个临时标记来双重检查是否没有变化,并在出现问题时标记一个我可以重置的点(不确定这是否是标准程序,但它对我有效):

git标记温度
git签出10004
git签出--孤立的新根
git提交-m“设置新根目录10004”
git rebase——在新根10004 branchname上
git diff temp#验证它是否在没有更改的情况下工作
git标签-d温度
git分支-D新根
要摆脱旧的分支,您需要删除它上的所有标记和分支标记;然后

git prune
git gc
将从您的回购中清除它

请注意,您将暂时拥有所有内容的两个副本,直到您拥有
gc
'd,但这是不可避免的;即使你做了一次标准的挤压和重基处理,在重基处理完成之前,你仍然有两份所有内容的副本。

XY问题 请注意,最初的海报有一个问题,他试图找出如何压缩他以前的提交(Y问题),而他的真正问题实际上是试图减小Git存储库的大小(X问题):

拥有大量的提交并不一定会膨胀到Git回购的规模。Git在压缩基于文本的文件方面非常有效。您确定提交的数量是导致回购规模过大的实际问题吗?更可能的情况是,您有太多的二进制资产版本,与纯文本文件相比,Git对这些资产的压缩效果不好(或者根本不好)

尽管如此,为了完整起见,我还将为Y问题添加一个替代解决方案

挤压(成百上千)旧的提交 正如最初的海报已经指出的那样,当有许多提交(以数百或数千为单位)时,使用带有
--root
标志的交互式基础是不切实际的,特别是因为交互式基础不能在如此多的提交上有效运行

正如马特·麦克纳布(Matt McNabb)在他的回答中指出的那样,一种解决方案是使用一个孤立的分支作为一个新的(被压扁的)根,然后在其上重新基址。另一种解决方案是使用分支的两种不同重置来实现相同的效果:

#将分支的当前状态保存到其他几个分支中
重置前的git分支
git分支验证
#还要标记要开始挤压提交的位置
git分支oldBase
#暂时从当前分支中删除最近的提交,
#因为我们不想压扁那些:
git重置--硬oldBase
#对根提交使用软重置将保留所有更改
#在索引中分段,因此您只需修改对
#根提交:
git重置——软
修改最后一次提交
#重新设置到新修订的根上,
#从oldBase开始,上升到beforeReset
git重设基础--在重置之前将其重新设置到主oldBase上
#切换回主控并(快进)将其与beforeReset合并
切换到主分支
重置之前的git合并
#确认主设备仍然包含与所有重置之前相同的状态
git差异验证
#清理
git分支-重置oldBase验证之前的D
#作为清理的一部分,因为原始海报提到
#他有很多承诺,他想取消,以减少
#他的回购规模,垃圾回收旧的,悬而未决的承诺
git gc--prune=all

git gc的
--prune=all
选项将确保所有悬空提交都被垃圾收集,而不仅仅是那些超过2周的提交,这是git gc

的默认设置。最快的计数实现时间几乎肯定是在grafts和,尽管您可能能够通过手动顺序处理输出来获得更快的执行速度

构建重基是为了在不同内容上应用更改。您在这里所做的是保存内容,并故意丢失生成内容的更改历史,因此几乎所有rebase最乏味、最缓慢的工作都被浪费了

这里的有效载荷是,根据你的照片

echo `git rev-parse H; git rev-parse A` > .git/info/grafts  
git filter-branch -- --all
和的文档

过滤器分支非常小心,可以在任何点发生故障后恢复,这当然是最安全的。。。。但是,只有当简单地重做恢复时,如果情况不好,恢复不会更快更容易,这才是真正有帮助的。由于故障很少,重启成本通常很低,所以要做的是进行一次非“安全”但非常快速的操作,这几乎肯定会奏效。为此,这里最好的选择是在tmpfs上进行(我所知道的Windows上最接近的等价物是r
echo `git rev-parse H; git rev-parse A` > .git/info/grafts  
git filter-branch -- --all