git重置后,无法删除无法访问的提交

Jim*_*Jim 4 git git-gc git-reset git-branch

我有一个小的回购,有几个提交:

* a0fc4f8 (HEAD -> testbranch) added file.txt  
* e6e6a8b (master) hello world now  
* f308f53 Made it echo  
* f705657 Added hello  
* 08a2de3 (tag: initial) initial  
Run Code Online (Sandbox Code Playgroud)

也:

$ git status  
On branch testbranch  
nothing to commit, working directory clean  
Run Code Online (Sandbox Code Playgroud)

我无法理解以下行为.在这种状态下我跑: $ git reset initial
我现在看到:

* e6e6a8b (master) hello world now  
* f308f53 Made it echo  
* f705657 Added hello  
* 08a2de3 (HEAD -> testbranch, tag: initial) initial  
Run Code Online (Sandbox Code Playgroud)

我期待的是:提交a0fc4f8将被删除,因为它无法访问.
发生了什么:
1)做git show a0fc4f8仍然显示提交
2)做git status显示file.txt通过提交a0fc4f8添加的未跟踪和由提交f705657添加的文件hello也显示为未跟踪.
3)运行git gcgit gc --prune=all不删除a0fc4f8虽然它不再可用,并且没有与之关联的名称/标签.
为什么会发生这种情况?

更新:

$ git fsck  
Checking object directories: 100% (256/256), done.  
Checking objects: 100% (15/15), done.    
Run Code Online (Sandbox Code Playgroud)

更新2:

$ git log --all --decorate --graph --oneline  
* e6e6a8b (master) hello world now  
* f308f53 Made it echo  
* f705657 Added hello  
* 08a2de3 (HEAD -> testbranch, tag: initial) initial  

$ git gc --force  
Counting objects: 15, done.  
Delta compression using up to 4 threads.  
Compressing objects: 100% (8/8), done.  
Writing objects: 100% (15/15), done.   
Total 15 (delta 1), reused 15 (delta 1)   

$ git log --all --decorate --graph --oneline  
* e6e6a8b (master) hello world now  
* f308f53 Made it echo  
* f705657 Added hello  
* 08a2de3 (HEAD -> testbranch, tag: initial) initial  
Run Code Online (Sandbox Code Playgroud)

$ git show a0fc4f8仍显示提交

更新3:

$ git reflog testbranch  
08a2de3 testbranch@{0}: reset: moving to initial  
a0fc4f8 testbranch@{1}: commit: added file.txt  
e6e6a8b testbranch@{2}: branch: Created from HEAD  
Run Code Online (Sandbox Code Playgroud)

axi*_*iac 6

1)做git show a0fc4f8仍然显示提交

这是设计的.由于以下几个原因,不会立即删除无法访问的对象:

  • 也许你错误地运行了最后一个命令(或者提供了错误的参数),你意识到错误并希望回到之前的状态;
  • 与完成操作所需的工作量相比,删除无法访问的对象(节省一些磁盘空间)的收益太小.

修剪不可到达的对象是不时自动执行的.它也由一些git命令执行(fetch并且push是其中一些命令).

2)执行git status显示file.txt通过提交添加的a0fc4f8未跟踪和hello由提交添加的文件f705657也显示为未跟踪.

git reset没有指定模式就跑了.默认模式是--mixed,这意味着:

  • 分支被移动到命令中指定的提交(initial在这种情况下);
  • 重置索引以匹配分支指向的新提交;
  • 工作树未被修改.

这解释了为什么文件在目录(第三个项目符号)中以及它们未被跟踪的原因(第二个项目符号;索引与initial提交匹配,但这些文件在创建时甚至不存在).

3)运行git gcgit gc --prune=all不删除a0fc4f8虽然它不再可用,并且没有与之关联的名称/标签.

git gc还检查分支reflogs以获取引用.如果您的testbranch分支已reflog启用,则reflog中的最新条目指向提交a0fc4f8(这是testbranch分支在您运行之前的位置git reset).您可以testbranch通过运行检查是否为分支启用了reflog git reflog testbranch.如果它打印出某些内容,您将a0fc4f8在第二行找到提交位置testbranch@{1}.符号name@{n}是指在现有n分支的值name(提交它被指向,n移动过去).

您可以git gc文档中找到有关工作方式的更多信息.

Notes部分中,它显示:

git gc非常努力地保护它收集的垃圾.特别是,它不仅会保留当前分支和标记集引用的对象,还会保留索引引用的对象,远程跟踪分支,由git filter-branchin 保存的ref refs/original/或reflogs(可能引用稍后修改的分支中的提交)或倒退).

如果您希望收集某些对象而不是它们,请检查所有这些位置,并确定在您的情况下删除这些引用是否有意义.