git - git reset 后,未删除无法访问的提交

标签 git git-branch git-reset git-gc

我有一个有几个提交的小仓库:

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

还有:

$ git status  
On branch testbranch  
nothing to commit, working directory clean  

我无法理解以下行为。在这种状态下,我运行: $ git reset initial
我现在看到了:

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

如我所料:提交 a0fc4f8 将被删除,因为它无法访问。
发生了什么:
1) git show a0fc4f8 仍然显示提交
2) git status 显示由提交 a0fc4f8 添加的 file.txt 未跟踪,由提交 f705657 添加的文件 hello 也显示为未跟踪。
3) 运行 git gcgit gc --prune=all 不会删除 a0fc4f8,尽管它不再可访问并且没有与之关联的名称/标签。
为什么会发生这些?

更新:

$ git fsck  
Checking object directories: 100% (256/256), done.  
Checking objects: 100% (15/15), done.    

更新 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  

$ 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  

最佳答案

1) Doing git show a0fc4f8 still shows the commit

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

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

修剪无法访问的对象是不时自动执行的。它也由一些 git 命令执行(fetchpush 是其中的一些命令)。

2) Doing git status shows the file.txt that was added by commit a0fc4f8 as untracked and file hello that was added by commit f705657 also shows up as untracked.

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

  • 分支被移动到命令中指定的提交(在本例中为initial);
  • 索引被重置以匹配分支指向的新提交;
  • 工作树没有被修改。

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

3) Running git gc or git gc --prune=all does not delete a0fc4f8 although it is not reachable anymore and has no name/tag associated with it.

git gc 还会检查分支 reflogs 中的引用。如果您的 testbranch 分支有 reflog启用然后 reflog 中的最新条目指向提交 a0fc4f8(这是在您运行 git reset 之前 testbranch 分支所在的位置)。您可以通过运行 git reflog testbranch 检查是否为分支 testbranch 启用了 reflog。如果它打印了一些内容,您会在第二行的 testbranch@{1} 位置找到提交 a0fc4f8。符号name@{n}表示分支 name 的先前 nth 值(它指向的提交,n 移动到过去).

你可以找到更多关于方式git gcdocumentation 工作.

注释部分,它显示:

git gc tries very hard to be safe about the garbage it collects. In particular, it will keep not only objects referenced by your current set of branches and tags, but also objects referenced by the index, remote-tracking branches, refs saved by git filter-branch in refs/original/, or reflogs (which may reference commits in branches that were later amended or rewound).

If you are expecting some objects to be collected and they aren’t, check all of those locations and decide whether it makes sense in your case to remove those references.

关于git - git reset 后,未删除无法访问的提交,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41387054/

相关文章:

git - 我丢失了自述文件,因为我在本地执行了 'git push --force' 但我不知道如何取回它。自述文件是在远程创建的

git - “弧形嫁接”和“弧形补丁”之间有什么区别?

git - 停止 git push 推送到多个分支

git - 撤消 “git add <dir>” ?

Git:主重置后分支会发生什么

Git:仅 merge 在分支上所做的更改

git - 在 Jenkins 管道 checkout 中禁用更改日志

git - git pull后如何查看代码变化?

Gitlab git push 因 Vagrant 管理的 Virtualbox 而失败

git - 如何对一系列提交进行 git rebase -i?