4

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

* 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) Doinggit show a0fc4f8仍然显示提交
2) Doing将提交 a0fc4f8 添加的git status显示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  
4

1 回答 1

6

1)Doinggit show a0fc4f8仍然显示提交

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

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

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

2) 执行将提交添加的文件git status显示为未跟踪,提交添加的文件也显示为未跟踪。file.txta0fc4f8hellof705657

您在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}的先前nname(它指向的提交,n移动到过去)。

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

注释部分,它写道:

git gc非常努力地确保它收集的垃圾的安全。特别是,它不仅会保留当前分支和标签集引用的对象,还会保留索引、远程跟踪分支、git filter-branchin保存的 refsrefs/original/或 reflogs 引用的对象(可能会引用后来修改的分支中的提交或重绕)。

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

于 2016-12-29T21:50:41.700 回答