git重置后,无法删除的提交未删除
我有一个小型仓库,其中有几个提交:
I have a small repo that has a couple of commits:
* 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
我现在看到了:
I can not understand the following behavior. On this state I run:
$ git reset initial
I see now:
* 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 gc
或 git gc --prune = all
不会删除a0fc4f8,尽管它不再可访问并且没有名称/标签与之关联.
为什么会这样?
What I was expecting: Commit a0fc4f8 would be deleted since it is unreachable.
What happened:
1) Doing git show a0fc4f8
still shows the commit
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.
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.
Why are these happening?
更新:
$ 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仍然显示提交
$ git show a0fc4f8 Still shows the commit
更新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)进行
git show a0fc4f8
仍显示提交
这是设计使然.由于以下几种原因,无法立即删除无法访问的对象:
This is by design. The unreachable objects are not removed immediately for several reasons:
- 也许您是错误地运行了最后一条命令(或为其提供了错误的参数),您意识到了该错误并想回到先前的状态;
- 与完成操作所需的工作量相比,删除无法访问的对象(节省一些磁盘空间)的收益太小了.
不时自动修剪不可达对象.它也由一些git命令执行( fetch
和 push
是其中的一些命令).
Pruning the unreachable object is performed automatically from time to time. It is also performed by some git commands (fetch
and push
are some of them).
2)执行
git status
会显示file.txt
,该文件是由提交a0fc4f8
作为未跟踪添加的,并且是文件hello 提交
f705657
添加的code>也显示为未跟踪.
2) Doing
git status
shows thefile.txt
that was added by commita0fc4f8
as untracked and filehello
that was added by commitf705657
also shows up as untracked.
您在未指定 git reset
>模式.默认模式是-mixed
,表示:
You ran git reset
without specifying a mode. The default mode is --mixed
and that means:
- 将分支移动到命令中指定的提交(在本例中为
initial
); - 重置索引以匹配分支所指向的新提交;
- 未修改工作树.
这说明了为什么文件在目录中(第三个项目符号)以及为什么未对其进行跟踪(第二个项目符号;索引与 initial
提交匹配,但这些文件甚至在存在时都不存在)已创建).
This explains why the files are in the directory (the third bullet) and why they are untracked (the second bullet; the index matches the initial
commit but these files didn't even exist when it was created).
3)运行
git gc
或git gc --prune = all
不会删除a0fc4f8
,尽管它不再可访问并且没有与之关联的名称/标签.
3) Running
git gc
orgit gc --prune=all
does not deletea0fc4f8
although it is not reachable anymore and has no name/tag associated with it.
git gc
还会检查分支reflog中是否有引用.如果您的 testbranch
分支具有 reflog
启用,然后引用日志中的最新条目指向提交 a0fc4f8
(这是运行 git reset
之前 testbranch
分支的位置).您可以通过运行 git reflog testbranch
来检查是否为分支 testbranch
启用了reflog.如果它打印出一些内容,您将在第二行的位置 testbranch @ {1}
处找到提交 a0fc4f8
.符号 name @ {n}
表示分支 name
的 n
th 值(指向的提交, n
过去移动).
git gc
also checks the branch reflogs for references. If your testbranch
branch has the reflog
enabled then the most recent entry in the reflog points to commit a0fc4f8
(this is where the testbranch
branch was before you ran git reset
). You can check if the reflog is enabled for branch testbranch
by running git reflog testbranch
. If it prints something you'll find the commit a0fc4f8
on the second line, at position testbranch@{1}
. The notation name@{n}
means the prior n
th value of branch name
(the commit it was pointing to, n
moves in the past).
您可以找到有关 git gc
方式的更多信息可在文档中使用.
You can find more about the way git gc
works in the documentation.
在 注释 部分中,内容为:
In the Notes section it reads:
git gc
尽力确保其收集的垃圾安全.特别是,它将不仅保留当前分支和标签集引用的对象,还保留索引,远程跟踪分支以及中的
或reflog(可以引用分支中的提交,这些分支后来被修改或倒回).git filter-branch
保存的引用所引用的对象refs/original/
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 bygit filter-branch
inrefs/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.