如何从实际数据库中永久删除最近的git提交

时间:2016-05-27 12:49:53

标签: git version-control revert space-efficiency

实施例

所以,让我说我有一个10个提交的本地git仓库,有SHA消化0-9所以我的git日志看起来像这样

9 (HEAD -> master)
8
7
6
5
4
3
2
1
0 <- initial commit

我决定提交5-9是垃圾,我想永久从repositoy 和他们引入的磁盘空间中删除它们的所有记录。在一般情况下,我希望我的回购状态与提交4时的状态相同,并且让它像5-9甚至从未发生过。

我知道git reset --hard 4会使我的repo 显示被重新提交到提交4,但据我所知,这只会将提交master点更改为9到4但实际上并没有删除任何东西。所有数据仍然存在,如果您知道提交9的SHA,则可以恢复。

我也知道git filter-branch,但只删除历史记录中的文件,而不是提交。

我尝试过:

git reset --hard 4
git gc --prune=now

但执行此操作后,我的.git目录的磁盘空间使用量相同或更大,我仍然可以使用git checkout 9恢复历史记录。为什么git gc --prune=now不修剪提交5-9?我是否需要使reflog过期?

更一般地说:

如果我有一个包含许多分支,标签,提交,合并和发展历史的复杂仓库,我怎样才能永久地自动删除所有提交,以及它们引入的更改以及它们消耗的磁盘空间,在一定时间后发生。有效地将整个仓库倒回到那个时间并永久销毁在该日期之后发生的所有活动。

2 个答案:

答案 0 :(得分:0)

git reset不会删除内容。它只需更改您的HEAD即可指向您要求的新SHA-1。

如何删除内容?

  

我也知道git filter-branch,但只删除了历史记录中的文件,而不是提交。

让我纠正你。

一旦你执行git过滤器分支,它就会更新内容并创建一个新的提交。

那么旧的提交在哪里?

旧的提交它仍在您的存储库中。它成为一个悬垂的对象,这意味着有一些内容无法从任何分支到达。

首先阅读这个答案,了解什么是HEAD

现在您必须使用BFGgit filter-branch而不是执行git gc

enter image description here

  

...我认为提交5-9是垃圾,我想从存储库和它们引入的磁盘空间中永久删除它们的所有记录

你有几个选择来实现它。这是一个简单的:

# Get back to the desired commit
git checkout <commit> # in your case 4

# now delete the old branch with the 5-9 commits
git branch -D <branch name>

# now create a new branch from commit #4
git checkout -b <branch>

# now you have to clean the leftovers.
# first lets see them (not required just for us to prove that we delete them)
git fsck --full 

# now you will get a list of all the "removed" commit.
# lets clean the repo right now.
git gc --aggressive --prune=now
  

为什么git gc --prune =现在不修剪提交5-9?

它不会删除提交,因为重置只会更改HEAD而不是存储库的内容。

答案 1 :(得分:0)

让我们分一部分......

  

我知道git reset --hard 4会让我的repo似乎被重新提交为4,但据我所知,这只是将提交master点从9改为4但实际上并没有删除任何东西所有数据仍然存在,如果您知道提交9的SHA,则可以恢复。

这是对的。此外,有两个reflog可以保留指向提交5,6,7,8和9的指针:HEAD一个,它会记住HEAD何时指向这些提交(如果HEAD曾经指出过它们,还有一个master,它记得master指向那些提交时(如果master指向它们 - 我们肯定它指向{{} 1}}因为它在9之前的位置,但是我们不知道它是否单独指向以前的每一个,或者你是否可能以某种方式将它们全部带入不知何故,例如,来自另一个分支)。

可能有也可能没有指向这些提交的其他分支和/或reflog。

  

我也知道reset,但只删除历史记录中的文件,而不是提交。

这是不正确的,尽管Wolfgang Pauli对其他事情说了些什么,&#34;这是不对的。这甚至都不对!&#34;特别是,这种措辞意味着git filter-branch删除了东西。它没有:添加新的提交

Git基本上是围绕添加新内容的想法而构建的,并且永远不会删除任何内容。其中包括git filter-branchgit commit --amendgit rebase:他们添加了新的提交。真正删除过期内容的唯一Git命令是与gc相关的命令(git filter-branchgit prunegit reflog expiregit repack等等,当然还有{{1本身)。

  

我已经尝试过:

git prune-packed
     

但执行此操作后,我的git gc目录的磁盘空间使用量相同或更大,我仍然可以使用git reset --hard 4 git gc --prune=now 恢复历史记录。为什么.git不修剪提交5-9?我是否需要使我的reflog过期?

要让旧物体消失,你必须:

  • 追捕并销毁所有引用,包括reflog中的引用
  • 修剪松散的物体,无论其年龄如何(上面的git checkout 9部分)
  • 重新打包这些对象的任何打包版本。

git gc --prune=now处理最后两个步骤,但不处理第一个步骤。使用--prune=now清除所有reflog(这是过度杀伤:git gc --prune=now可能就是你所需要的)。如果你有其他的迷路引用(其他分支,标签,松散的git reflog --expire=now --expire-unreachable=now或两个,甚至可能是--expire-unreachablestash),你必须手动清理它们。另请注意,ORIG_HEAD会在CHERRY_PICK_HEAD中保留原始引用集,并保留所有原始(预过滤后复制)对象。