从git存储库中删除最早的提交

从git存储库中删除最早的提交,git,Git,可能重复: git对于客户端网站的夜间快照非常有用。了解php+mysqldump+用户文件上传的所有内容都在git存储库中,可以让您安心 由于一些站点的规模很大,我想知道是否有人知道一种中等容易的方法来删除所有超过30天的提交 存储库当前状态下的文件将保存为原始添加文件加上一系列更改,因此您无法删除添加文件的提交 有一个操作,您可以从日志中选择多个连续提交并合并为一个提交,但它不是Git中本机提供的,从我从出现的窗口中可以推断,实现为创建一个新的分支,应用原始分支的更改,只提交一次,并根据结

可能重复:

git对于客户端网站的夜间快照非常有用。了解php+mysqldump+用户文件上传的所有内容都在git存储库中,可以让您安心

由于一些站点的规模很大,我想知道是否有人知道一种中等容易的方法来删除所有超过30天的提交

存储库当前状态下的文件将保存为原始添加文件加上一系列更改,因此您无法删除添加文件的提交

有一个操作,您可以从日志中选择多个连续提交并合并为一个提交,但它不是Git中本机提供的,从我从出现的窗口中可以推断,实现为创建一个新的分支,应用原始分支的更改,只提交一次,并根据结果重定基址。当选择多个提交时,这当然不是一个快速操作,我想在大型存储库中它会更慢,而且在使用它之前我总是有一个备份

总而言之,我怀疑有一种简单的方法可以做到这一点。

事实上,你确实可以做到这一点。这有点棘手。这里有一个例子

$ cd /tmp
$ mkdir rmcommits
$ cd rmcommits
$ git init
Initialized empty Git repository in /tmp/rmcommits/.git/
$ cp /tmp/example/xy.c .
$ git add xy.c
$ git commit -m 'initial commit'
[master (root-commit) 8d5b88c] initial commit
 1 files changed, 273 insertions(+), 0 deletions(-)
 create mode 100644 xy.c
$ echo 'more stuff' > morestuff.txt
$ git add morestuff.txt; git commit -m 'add some stuff'
[master f971ae5] add some stuff
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 morestuff.txt
$ echo 'and still more' >> morestuff.txt 
$ git add morestuff.txt; git commit -m 'add more stuff'
[master bea9192] add more stuff
 1 files changed, 1 insertions(+), 0 deletions(-)
现在我选择一个地方,我希望历史在那里结束,分支大师,又名首领:

$ git rev-parse HEAD^
f971ae5b4225aca364223a44be8be84268385ff3
这是我最后的承诺

$ git filter-branch --parent-filter 'test $GIT_COMMIT == f971ae5b4225aca364223a44be8be84268385ff3 && echo "" || cat' HEAD
Rewrite bea9192a53a5aeb7532aa1e174f7f642363396de (3/3)
Ref 'refs/heads/master' was rewritten
$ git log --pretty=oneline
65a246b8320382a64550d2c4b650c942d7bfba70 add more stuff
7892ab45aa33cd5ebdc3090ce2622081059fdd79 add some stuff
说明:git筛选器分支基本上运行在分支中的所有提交上,在本例中为master,因为HEAD当前为ref:refs/heads/master,并且使用-parent筛选器,可以重写每个提交的父级。当我们找到目标提交(在此之前我们希望历史停止)时,我们不回显任何内容您不需要空字符串,这是我的老习惯,从没有参数的回显不做任何操作开始,否则我们使用cat复制现有的-p参数,如过滤器分支手册所示。这使得新的提交(基于我们测试的提交)没有父级,也就是说,它现在是一个初始提交-分支的根。这在git回购中是不寻常的,因为我们现在有两个根提交,一个在新的主服务器上,另一个在旧的保存的主服务器上,如下所述

请注意,较旧的提交树仍然完整地位于repo中,位于git filter branch使用的保存名称下:

在重写的提交和任何未引用的树、blob等真正消失之前,您必须删除该引用并清除reflog并执行git gc:

$ git update-ref -d refs/original/refs/heads/master
$ git reflog expire --expire=now --all
$ git gc --prune=now
$ git fsck --unreachable
$

最后一行表明它们真的消失了。

我不认为Git真的应该被用作备份解决方案,因此这样做并不是真正的目的。您可能只需使用rebase删除它们,但我不确定如何以编程方式执行。关于git不是用于备份解决方案,我想我们都同意这一点然而,从纯粹务实的角度来看,我自己和谷歌称,许多其他人发现它非常适合作为备份solution@JohnDouthat好地方!现在还不清楚它们是否是重复的,因为问题不同,但结果是一样的。挤压法确实会起作用。可能会很慢。我还没有对过滤器分支进行计时,这也可能非常慢。。。。在这两种情况下,您仍然可以通过reflog等进行原始提交,因此,如果要恢复磁盘空间,您仍然需要按原样取出垃圾。1:事实上,不是这样。这些文件包经过压缩,因此可以获得与Delta相同的节省空间效果,但每个文件都是完整存储的。git提交对象指向git树对象,树对象按SHA1 ID列出BLOB文件和更多树;从SHA1 ID中,您可以通过这些包的魔力全面提取文件。2.在原生git中,这是git rebase-interactive中的挤压。是的,在下面是通过建造一个新的分支来完成的。我被纠正了。我需要深入阅读我在阅读git内部结构时略读的章节。git的压缩技术是不寻常的,至少可以这么说:不过非常有效。包进行增量压缩,但对象本身只是zlib压缩,而且v2包中的校验和比v1包中的校验和更好。压缩算法以不同的方式重复使用,以获得拉和推操作的增量压缩,但这些操作在接收端被撤消。
$ git update-ref -d refs/original/refs/heads/master
$ git reflog expire --expire=now --all
$ git gc --prune=now
$ git fsck --unreachable
$