git:为什么我可以结帐到我删除的提交? [英] git: why can I checkout to the commit I deleted?

查看:37
本文介绍了git:为什么我可以结帐到我删除的提交?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a branch with three commits:

mybranch: a -> b -> c

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

I pushed it to the remote repo. Then I decided that I don't want to keep the commits b and c, so deleted them as described here:

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

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

Afterwards, I checked git log and confirmed that only the commit a was visible. However:

  • 我仍然可以检查提交 bc.这是为什么?
  • 当我使用 SourceTree 查找我的 git 存储库时,我仍然可以在我的分支中看到这些提交(尽管当前提交 a 被正确表示为我当前正在进行的提交).我使用 git bash 来检查我的提交是否正确,并且我的 HEAD 未处于分离状态.
  • I still can checkout to the commits b and c. Why is that?
  • when I used SourceTree to look up my git repo, I still could see these commits in my branch (although the current commit a was denoted correctly as the commit I was currently on). I used git bash to check that I was on the correct commit and that my HEAD was not in the detached state.

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

What is wrong with the procedure I used? Why did it keep the commits b and c? How can I remove them completely?

推荐答案

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

Actually deleting a commit is fairly difficult in git, by design. Many commands that people think delete commits (like rebase, or reset), actually just make those commits "unreachable" - causing the default output of various commands and tools to exclude them.

删除提交的理由保证成本的情况相对较少.有时提交包含敏感信息(不过,在这种情况下,无论您是否努力将其从 repo 中清除,最好考虑信息泄露几乎总是最好的).也许一个提交包含过大的二进制文件,这些文件在任何其他提交中都不存在,从而使存储库膨胀.如果归结为想要隐藏"一个错误"以使 repo 看起来很完美,我不会浪费时间.

It's relatively rare that the reason to delete a commit warrants the cost. Sometimes a commit contains sensitive information (though, in that case, it's almost always best to consider the information compromised, whether or not you take efforts to scrub it from the repo). Maybe a commit contains excessively large binary files that are not present in any other commit, bloating the repo. If it just boils down to wanting to "hide" a "mistake" so the repo looks perfect, I wouldn't waste time on it.

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

But if you do want to remove the commit, here's what you need to know:

首先,您必须删除提交的所有知识.您的 reset 命令使它从您 ddi reset 所在的分支无法访问"(通过父指针).如果有其他分支可以到达提交,则需要将它们resetrebased 远离提交(或删除).如果删除的提交上有标签,则需要移动或删除它们.在某些特殊情况下,其他 refs 可以指向提交,但我假设它们不适用.(这将是诸如替换或来自 filter-branch 的备份 refs 之类的事情......基本上,如果您可以在 .git/packed-refs 中找到任一提交的 SHA文件或 refs 下的任何文件,则需要采取一些措施来补救.)

First, you have to remove all knowledge of the commit. Your reset commands have made it "unreachable" (by parent pointers) from the branch on which you ddi the resets. If there are other branches that can reach the commits, they need to be reset or rebased away from the commit (or deleted). If there are tags on the removed commits, they need to be moved or deleted. There are special cases when other refs could point to the commits, but I'll assume they don't apply. (It would be things like replacements, or backup refs from filter-branch... Basically if you can find the SHA for either commit in the .git/packed-refs file or in any file under refs, then some action is needed to remedy that.)

一旦删除了所有引用,提交就会悬空";但它仍然可以通过 reflog 访问.您可以尝试使 reflogs 过期

Once all refs are removed, the commit is "dangling"; but it still may be reachable via the reflog. You can try to expiire the reflogs

git reflog expire --expire=all --all

我从来没有那么幸运(这可能只是意味着我永远不会记得正确的论点);我总是做类似的事情

I've never had much luck with that (which probably just means I never remember the right arguments); I always end up doing something like

rm -r .git/logs

无论如何,缺点是您会丢失所有 reflog 信息.您可以更有选择性地决定哪些 reflog 过期.(您可能需要 HEAD 以及提交(或曾经)可访问的任何分支.)您甚至可以使用 delete 而不是 expire 来追捕个别的 reflog 条目.同样,这完全取决于您想为此付出多少努力.

The downside in any event is that you lose all of your reflog information. You can be more selective about which reflogs you expire. (You probably need HEAD and any branch from which the commits are (or were) reachable.) You could even use delete instead of expire to hunt down individual reflog entries. Again it all depends how much effort you're wanting to put into this.

所以一旦没有可以到达提交的引用和引用日志,gc 可用于从本地存储库中物理删除提交.

So once there are no refs and no reflogs that can reach the commit, gc can be used to physically delete the commit from the local repo.

git gc --aggressive --prune=now

但现在仍然存在一个问题:如果提交被推送,远程仍然拥有它们;现在推送不会从遥控器中删除它们.(推送更新远程引用,并根据需要添加对象以填充历史;但它不会从远程删除对象.)

But now there's still an issue: If the commits were ever pushed, the remote still has them; and pushing now won't delete them from the remote. (Pushing updates remote refs and, as needed, adds objects to fill in history; but it doesn't delete objects from the remote.)

如果远程只是文件共享(或您控制的 Web 服务器,或其他)上的存储库:您可以登录服务器并像清理本地一样清理它.(如果你已经推送了 refs,那么那部分已经完成了;但是你可能需要清理 reflogs 并且你将不得不运行 gc.)

If the remote is just a repo on a file share (or web server you control, or whatever): you can log into the server and clean it up the same way you cleaned up your local. (If you've pushed refs, then that part's already done; but you may have to clean up reflogs and you will have to run gc.)

如果远程是托管的(github、gitlab、TFS、bitbucket...),那么这取决于主机提供对 gc 的访问权限.在 TFS(至少我用过的版本)中,你是一棵树;充其量您可以删除并重新创建回购.其他主机服务器可能提供触发gc的能力,甚至可能在某些事件后自动运行gc;您必须查阅托管服务/软件的文档.

If the remote is hosted (github, gitlab, TFS, bitbucket...) then it depends on what access to gc is provided by the host. In TFS (at least versions I've used) you're up a tree; at best you could delete and recreate the repo. Other host servers may provide the ability to trigger gc, or may even run gc automatically after certain events; you'd have to consult the docs for the hosting service/software.

这篇关于git:为什么我可以结帐到我删除的提交?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆