git: 为什么我可以检出我删除的提交?
git: why can I checkout to the commit I deleted?
我有一个包含三个提交的分支:
mybranch: a -> b -> c
我把它推送到了远程仓库。然后我决定不想保留提交 b 和 c,所以按照 here:
git reset --hard HEAD~1
git reset --hard HEAD~1
git push origin mybranch -f
之后,我检查了git log
并确认只有提交a可见。然而:
- 我仍然可以签出提交 b 和 c。这是为什么?
- 当我使用 SourceTree 查找我的 git 存储库时,我仍然可以在我的分支中看到这些提交(尽管当前提交 a 被正确地表示为提交我目前正在)。我使用 git bash 检查我是否进行了正确的提交并且我的 HEAD 没有处于分离状态。
我使用的程序有什么问题?为什么它保留提交 b 和 c?我怎样才能完全删除它们?
git reset
不会删除提交,它会将您的分支重置为给定的提交(使用 HEAD~1,您的分支当前 HEAD 提交的直接前身)。后续提交不再是您分支的一部分。如果没有其他分支在其历史记录中有提交,则提交将成为 'dangling' 提交,任何分支都无法访问(编辑:实际上它首先变为 'unreachable',并且仅 'dangling'稍后当它甚至无法通过 reflog 访问时;请参阅下面链接答案的评论)。如果它长时间保持这种状态,gits 的垃圾收集最终会删除它。在此之前,提交仍可通过其 SHA id 访问。
事实上,如果您弄乱了分支历史记录,这将非常方便。使用 reflog
或其他方式,您可以获得丢失的提交的 SHA id 并恢复您的工作(如果它没有丢失太久)。
SourceTree 仍然显示从 b
到 a
的连接,因为每个提交都知道其前身。 b
和 c
然而不再是你分支的一部分,因为它的 HEAD 提交是 a
.
你所做的没有任何问题,没有必要进一步尝试删除提交。如果您继续在存储库中工作,它们最终将被删除。有关通过垃圾收集删除的详细信息,请参阅 this answer。
实际上在 git 中删除提交是相当困难的,这是设计使然。人们 认为 删除提交的许多命令(如变基或重置),实际上只是使这些提交 "unreachable" - 导致各种命令和工具的默认输出将它们排除在外。
以删除提交为由支付费用的情况相对较少。有时提交包含敏感信息(尽管在这种情况下,无论您是否努力将其从存储库中清除,几乎总是最好考虑已泄露的信息)。也许提交包含过大的二进制文件,这些文件在任何其他提交中都不存在,从而使存储库膨胀。如果它只是归结为想要 "hide" 一个 "mistake" 所以回购协议看起来很完美,我不会浪费时间。
但如果您确实想删除提交,则需要了解以下内容:
首先,您必须删除提交的所有知识。您的 reset
命令已从您 ddi reset
的分支中取得 "unreachable"(通过父指针)。如果有其他分支可以到达提交,则它们需要 reset
或 rebased
远离提交(或删除)。如果删除的提交上有标签,则需要移动或删除它们。在某些特殊情况下,其他 refs 可能指向提交,但我假设它们不适用。 (这可能是来自 filter-branch
的替换或备份引用之类的东西...基本上,如果您可以在 .git/packed-refs
文件或 refs
下的任何文件中找到提交的 SHA,那么需要采取一些措施来补救。)
删除所有引用后,提交为"dangling";但它仍然可以通过 reflog 访问。您可以尝试过期 reflogs
git reflog expire --expire=all --all
我从来没有运气好(这可能只是意味着我永远不记得正确的论点);我总是最终会做类似
的事情
rm -r .git/logs
无论如何,缺点是您会丢失 所有 reflog 信息。您可以更有选择地选择过期的 reflog。 (您可能需要 HEAD
以及可以(或曾经)访问提交的任何分支。)您甚至可以使用 delete
而不是 expire
来查找单个 reflog 条目。同样,这完全取决于您要为此付出多少努力。
所以一旦没有 refs 和 reflogs 可以到达提交,gc
可以用来从本地 repo 中物理删除提交。
git gc --aggressive --prune=now
但是现在还有一个问题:如果曾经推送过提交,远程仍然有它们;并且现在推送不会从遥控器中删除它们。 (推送更新远程引用,并根据需要 添加 对象以填充历史记录;但它不会从远程删除对象。)
如果远程只是文件共享(或您控制的 Web 服务器,或其他)上的存储库:您可以登录服务器并像清理本地一样清理它。 (如果您已推送 refs,那么该部分已经完成;但您可能必须清理 reflogs,并且您将不得不 运行 gc
。)
如果远程托管(github、gitlab、TFS、bitbucket...),则取决于主机提供对 gc
的访问权限。在 TFS 中(至少我用过的版本)你在树上;充其量您可以删除并重新创建回购协议。其他主机服务器可能会提供触发 gc
的能力,甚至可能会在某些事件后自动 运行 gc
;您必须查阅托管文档 service/software.
我有一个包含三个提交的分支:
mybranch: a -> b -> c
我把它推送到了远程仓库。然后我决定不想保留提交 b 和 c,所以按照 here:
git reset --hard HEAD~1
git reset --hard HEAD~1
git push origin mybranch -f
之后,我检查了git log
并确认只有提交a可见。然而:
- 我仍然可以签出提交 b 和 c。这是为什么?
- 当我使用 SourceTree 查找我的 git 存储库时,我仍然可以在我的分支中看到这些提交(尽管当前提交 a 被正确地表示为提交我目前正在)。我使用 git bash 检查我是否进行了正确的提交并且我的 HEAD 没有处于分离状态。
我使用的程序有什么问题?为什么它保留提交 b 和 c?我怎样才能完全删除它们?
git reset
不会删除提交,它会将您的分支重置为给定的提交(使用 HEAD~1,您的分支当前 HEAD 提交的直接前身)。后续提交不再是您分支的一部分。如果没有其他分支在其历史记录中有提交,则提交将成为 'dangling' 提交,任何分支都无法访问(编辑:实际上它首先变为 'unreachable',并且仅 'dangling'稍后当它甚至无法通过 reflog 访问时;请参阅下面链接答案的评论)。如果它长时间保持这种状态,gits 的垃圾收集最终会删除它。在此之前,提交仍可通过其 SHA id 访问。
事实上,如果您弄乱了分支历史记录,这将非常方便。使用 reflog
或其他方式,您可以获得丢失的提交的 SHA id 并恢复您的工作(如果它没有丢失太久)。
SourceTree 仍然显示从 b
到 a
的连接,因为每个提交都知道其前身。 b
和 c
然而不再是你分支的一部分,因为它的 HEAD 提交是 a
.
你所做的没有任何问题,没有必要进一步尝试删除提交。如果您继续在存储库中工作,它们最终将被删除。有关通过垃圾收集删除的详细信息,请参阅 this answer。
实际上在 git 中删除提交是相当困难的,这是设计使然。人们 认为 删除提交的许多命令(如变基或重置),实际上只是使这些提交 "unreachable" - 导致各种命令和工具的默认输出将它们排除在外。
以删除提交为由支付费用的情况相对较少。有时提交包含敏感信息(尽管在这种情况下,无论您是否努力将其从存储库中清除,几乎总是最好考虑已泄露的信息)。也许提交包含过大的二进制文件,这些文件在任何其他提交中都不存在,从而使存储库膨胀。如果它只是归结为想要 "hide" 一个 "mistake" 所以回购协议看起来很完美,我不会浪费时间。
但如果您确实想删除提交,则需要了解以下内容:
首先,您必须删除提交的所有知识。您的 reset
命令已从您 ddi reset
的分支中取得 "unreachable"(通过父指针)。如果有其他分支可以到达提交,则它们需要 reset
或 rebased
远离提交(或删除)。如果删除的提交上有标签,则需要移动或删除它们。在某些特殊情况下,其他 refs 可能指向提交,但我假设它们不适用。 (这可能是来自 filter-branch
的替换或备份引用之类的东西...基本上,如果您可以在 .git/packed-refs
文件或 refs
下的任何文件中找到提交的 SHA,那么需要采取一些措施来补救。)
删除所有引用后,提交为"dangling";但它仍然可以通过 reflog 访问。您可以尝试过期 reflogs
git reflog expire --expire=all --all
我从来没有运气好(这可能只是意味着我永远不记得正确的论点);我总是最终会做类似
的事情rm -r .git/logs
无论如何,缺点是您会丢失 所有 reflog 信息。您可以更有选择地选择过期的 reflog。 (您可能需要 HEAD
以及可以(或曾经)访问提交的任何分支。)您甚至可以使用 delete
而不是 expire
来查找单个 reflog 条目。同样,这完全取决于您要为此付出多少努力。
所以一旦没有 refs 和 reflogs 可以到达提交,gc
可以用来从本地 repo 中物理删除提交。
git gc --aggressive --prune=now
但是现在还有一个问题:如果曾经推送过提交,远程仍然有它们;并且现在推送不会从遥控器中删除它们。 (推送更新远程引用,并根据需要 添加 对象以填充历史记录;但它不会从远程删除对象。)
如果远程只是文件共享(或您控制的 Web 服务器,或其他)上的存储库:您可以登录服务器并像清理本地一样清理它。 (如果您已推送 refs,那么该部分已经完成;但您可能必须清理 reflogs,并且您将不得不 运行 gc
。)
如果远程托管(github、gitlab、TFS、bitbucket...),则取决于主机提供对 gc
的访问权限。在 TFS 中(至少我用过的版本)你在树上;充其量您可以删除并重新创建回购协议。其他主机服务器可能会提供触发 gc
的能力,甚至可能会在某些事件后自动 运行 gc
;您必须查阅托管文档 service/software.