git 重置后,未删除无法访问的提交
After a git reset, unreachable commit not removed
我有一个有几个提交的小回购:
* 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 gc
或 git gc --prune=all
不会删除 a0fc4f8 尽管它不再可达并且没有与之相关联的 name/tag。
为什么会发生这些?
更新:
$ git fsck
Checking object directories: 100% (256/256), done.
Checking objects: 100% (15/15), done.
更新二:
$ 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
这是设计使然。由于以下几个原因,无法立即删除无法访问的对象:
- 也许你 运行 错误地执行了最后一个命令(或向其提供了错误的参数),你意识到错误并想返回到之前的状态;
- 与完成操作所需的工作量相比,删除无法访问的对象(节省一些磁盘空间 space)的收益太小了。
修剪无法访问的对象是不时自动执行的。它也由一些 git 命令执行(fetch
和 push
是其中的一些)。
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
,这意味着:
- b运行ch 被移动到命令中指定的提交(在本例中为
initial
);
- 索引被重置以匹配 b运行ch 指向的新提交;
- 未修改工作树。
这解释了为什么文件在目录中(第三个项目符号)以及为什么它们未被跟踪(第二个项目符号;索引与 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
还会检查 b运行ch reflogs 中的引用。如果你的 testbranch
b运行ch 有 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}
意味着 b运行ch n
th 之前的值 name
(它指向的提交,n
移动到过去)。
你可以找到更多关于git gc
works in the documentation的方法。
在 Notes 部分显示:
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.
我有一个有几个提交的小回购:
* 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 gc
或 git gc --prune=all
不会删除 a0fc4f8 尽管它不再可达并且没有与之相关联的 name/tag。
为什么会发生这些?
更新:
$ git fsck
Checking object directories: 100% (256/256), done.
Checking objects: 100% (15/15), done.
更新二:
$ 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
这是设计使然。由于以下几个原因,无法立即删除无法访问的对象:
- 也许你 运行 错误地执行了最后一个命令(或向其提供了错误的参数),你意识到错误并想返回到之前的状态;
- 与完成操作所需的工作量相比,删除无法访问的对象(节省一些磁盘空间 space)的收益太小了。
修剪无法访问的对象是不时自动执行的。它也由一些 git 命令执行(fetch
和 push
是其中的一些)。
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
,这意味着:
- b运行ch 被移动到命令中指定的提交(在本例中为
initial
); - 索引被重置以匹配 b运行ch 指向的新提交;
- 未修改工作树。
这解释了为什么文件在目录中(第三个项目符号)以及为什么它们未被跟踪(第二个项目符号;索引与 initial
提交匹配,但这些文件在它被创建时甚至不存在已创建)。
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
还会检查 b运行ch reflogs 中的引用。如果你的 testbranch
b运行ch 有 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}
意味着 b运行ch n
th 之前的值 name
(它指向的提交,n
移动到过去)。
你可以找到更多关于git gc
works in the documentation的方法。
在 Notes 部分显示:
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.