git: 为什么我可以检出我删除的提交?

git: why can I checkout to the commit I deleted?

我有一个包含三个提交的分支:

mybranch: a -> b -> c

我把它推送到了远程仓库。然后我决定不想保留提交 bc,所以按照 here:

git reset --hard HEAD~1
git reset --hard HEAD~1
git push origin mybranch -f

之后,我检查了git log并确认只有提交a可见。然而:

我使用的程序有什么问题?为什么它保留提交 bc?我怎样才能完全删除它们?

git reset 不会删除提交,它会将您的分支重置为给定的提交(使用 HEAD~1,您的分支当前 HEAD 提交的直接前身)。后续提交不再是您分支的一部分。如果没有其他分支在其历史记录中有提交,则提交将成为 'dangling' 提交,任何分支都无法访问(编辑:实际上它首先变为 'unreachable',并且仅 'dangling'稍后当它甚至无法通过 reflog 访问时;请参阅下面链接答案的评论)。如果它长时间保持这种状态,gits 的垃圾收集最终会删除它。在此之前,提交仍可通过其 SHA id 访问。

事实上,如果您弄乱了分支历史记录,这将非常方便。使用 reflog 或其他方式,您可以获得丢失的提交的 SHA id 并恢复您的工作(如果它没有丢失太久)。

SourceTree 仍然显示从 ba 的连接,因为每个提交都知道其前身。 bc 然而不再是你分支的一部分,因为它的 HEAD 提交是 a.

你所做的没有任何问题,没有必要进一步尝试删除提交。如果您继续在存储库中工作,它们最终将被删除。有关通过垃圾收集删除的详细信息,请参阅 this answer

实际上在 git 中删除提交是相当困难的,这是设计使然。人们 认为 删除提交的许多命令(如变基或重置),实际上只是使这些提交 "unreachable" - 导致各种命令和工具的默认输出将它们排除在外。

以删除提交为由支付费用的情况相对较少。有时提交包含敏感信息(尽管在这种情况下,无论您是否努力将其从存储库中清除,几乎总是最好考虑已泄露的信息)。也许提交包含过大的二进制文件,这些文件在任何其他提交中都不存在,从而使存储库膨胀。如果它只是归结为想要 "hide" 一个 "mistake" 所以回购协议看起来很完美,我不会浪费时间。

但如果您确实想删除提交,则需要了解以下内容:

首先,您必须删除提交的所有知识。您的 reset 命令已从您 ddi reset 的分支中取得 "unreachable"(通过父指针)。如果有其他分支可以到达提交,则它们需要 resetrebased 远离提交(或删除)。如果删除的提交上有标签,则需要移动或删除它们。在某些特殊情况下,其他 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.