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

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

问题描述

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

  mybranch:a  - > b  - > c 

我将它推送到远程回购站。然后我决定我不想保留提交 b c ,所以按照

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

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


  • 我仍然可以签出提交 b c 。为什么会这样?

  • 当我使用SourceTree查找我的git repo时,我仍然可以在分支中看到这些提交(尽管当前提交 a 正如我目前的提交一样)。我使用git bash来检查我是否正确提交,并且我的HEAD不处于分离状态。 与我使用的程序?为什么它保留提交 b c ?如何将它们完全删除?

    解决方案

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



    删除提交的原因相当罕见,可以保证成本。有时一个提交包含敏感信息(尽管在这种情况下,考虑信息受到损害几乎总是最好的,无论你是否努力从回购中清除它)。也许一个提交包含过大的二进制文件,不存在于任何其他提交中,使存储库膨胀。如果它只是想要隐藏一个错误,所以回购看起来很完美,我不会浪费时间在上面。



    但如果你想要要删除提交,这里是你需要知道的:

    首先,你必须删除提交的所有知识。你的 reset 命令已经使你从 reset s的分支无法访问(通过父指针) 。如果还有其他可以到达提交的分支,它们需要在提交之后(或者 c> reset 或 rebased >)删除)。如果移除的提交中有标签,则需要移动或删除它们。有些特殊情况下,其他裁判可以指出提交,但我会假设他们不适用。 (这将是替代品或从 filter-branch ...的备份参考文件...基本上如果您可以在中找到用于提交的SHA。 git / packed-refs 文件,或者在 refs 下的任何文件中,那么需要采取一些措施来解决该问题。)



    一旦所有ref被移除,提交就是dangling;但它仍然可以通过reflog访问。您可以尝试过期reflogs

      git reflog expire --expire = all --all 

    我从来没有多少运气(这可能意味着我永远不会记住正确的参数);我总是最终做一些类似于

      rm -r .git / logs 

    任何情况下的不利之处都是你失去了所有的reflog信息。您可以更具选择性地列出您过期的reflog。 (你可能需要 HEAD 以及任何可以提交的分支)。甚至可以使用 delete 而不是过期来搜寻单个reflog条目。再次,这一切都取决于你想要付出多少努力。



    所以一旦没有可以达到提交的refs和reflog, gc 可以用来从本地仓库物理删除提交。

      git gc  - -aggressive --prune = now 

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



    如果远程只是一个文件共享(或您控制的Web服务器,或其他)的回购:您可以登录到服务器并以清理本地文件的方式进行清理。 (如果你推送了参考资料,那么这个部分已经完成了;但是你可能需要清理reflogs,你将不得不运行 gc 。)



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


    I have a branch with three commits:

    mybranch: a -> b -> c
    

    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
    

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

    • 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.

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

    解决方案

    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.

    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:

    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.)

    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
    

    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.

    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.)

    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.)

    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天全站免登陆