【问题标题】:git remove old commitsgit 删除旧的提交
【发布时间】:2018-10-18 10:32:06
【问题描述】:

我犯了一个愚蠢的错误,不小心将 node_modules 文件夹提交到我的本地 git,然后将其推送到 github。这是一个巨大的文件夹,任何下载我的 repo 的人也会在旧提交中下载这个文件夹。我一直在尝试使用rebase --ontorebase -i 删除提交,但没有运气。这就是我的git log 的样子。

$ git log --oneline
44549c5f (HEAD -> alex/matUI, origin/alex/matUI) fighting with gitignore
a5a5a79c changed ui to material   ##<---- remove me!
dbec4ab3 converting to material ui      ##<---- remove me!
cd4352f6 (origin/master, origin/HEAD, master) Merge pull request #1 from notsmart/addFullstack
a058bf1e moved files to new repo
80c82607 Added README.md

您将如何删除这些提交?

【问题讨论】:

标签: git github commit rebase


【解决方案1】:

你必须做两件事:

  1. 在本地删除这些提交
  2. 用力推动它们覆盖原点上的分支

编辑:实际备份那些将首先删除的文件,因为此方法会将它们从您的文件系统中删除。

第一:

git rebase -i HEAD~4

现在您有一个打开的编辑器,其中的行与您编写的内容相似。删除包含您不想要的提交的行。保存并退出编辑器。

检查git log是否正确。

然后:

git push -f

说明:

首先您启动了一个交互式历史编辑会话。您在编辑器下面有可能的选项,注释掉了。您可以做很多事情,例如通过删除行来删除提交、将它们压缩在一起、仅通过重新排序行来重新排序等。

然后您删除了提交行并保存了。发生的事情是 git 试图创建新的提交链来应用您想要的更改。实际上创建了新的提交(部分提交链接到前一个提交),因此对于已更改的提交有新的哈希(因为从技术上讲它们是新的)。您将看到 origin/alex/matUI 不再在您的 HEAD 上(在 git log 中)。

你终于用力推了。这用您当前的 alex/matUI 覆盖了 origin/alex/matUI。这实际上会覆盖您的 HEAD 指向的任何分支并与 origin 上的分支绑定(您的 alex/matUI 与 origin/alex/matUI 绑定,这不是魔术,它是您手动创建或创建的显式绑定拉/克隆时)。通常push 是保守的,只允许在你的分支提示之后添加。 -f 强制通过。使用原力卢克:)

【讨论】:

  • 您可能还想运行git gc(垃圾收集),它应该从您的 git 存储库中删除无法访问的对象,因此 .git 文件夹将不再包含这些提交。我不能 100% 确定它会删除您刚刚删除的那些提交。我想是这样。无论如何 github 应该自己在服务器上运行这样的垃圾收集,所以不用担心它在他们的服务器上。
  • 不,gc 通常不会删除您刚刚从历史记录中删除的提交,因为它们仍然可以通过 reflog 访问。至于服务器,您能否参考确认gc 在 github 中如何使用的文档,或者您认为它“应该”如何工作?因为我已经很久没有专门查看该服务了,但我不记得它有那么好。
  • 感谢您的澄清!我不确定(这就是我没有将其添加到答案中的原因),但在我看来,这是一个非常合理的做法,可以以很少的计算成本节省空间(可能仅在 x 操作之后)。例如,GitLab 会在夜间进行清理,至少是自托管实例。一旦子模块修订在夜间消失,因为它是一个未附加的提交(已修改)。
【解决方案2】:

您可以应用的任何解决方案都将改写历史。这意味着它会对拥有你的 repo 副本的任何其他人产生不利影响,如果他们在尝试恢复时做错了事情,它可能会撤消你的修复。

因此,在公开可用的 repo 中出现这种情况是一个非常不幸的情况,但如果您碰巧知道没有多少人(或者可能没有人)克隆它,那么在实践中可能并不算太糟糕。重点是,以一种让所有回购用户都知道的方式传达你正在做的事情。

(通常我会说您需要任何拥有该回购副本的人的同意/协调;在这里,如果您将其视为您让其他人克隆的回购,我想您可以说只是衡量协调很好;但是除非您限制对源的推送,否则无论我们说什么“正确”,都存在某人进行“错误修复”并重新引入错误提交的可能性。)

无论如何,请注意以上内容,但实际上无济于事。你必须改写历史,问题是如何改写。

您可以删除自添加 node_modules 文件夹以来所做的所有提交,但当然您将丢失这些提交中的所有 other 更改。摆脱 node_modules 不丢失其他历史记录(并且没有 3rd 方工具)的最简单方法是 git filter-branch

当然,您要确保在本地拥有所有参考。由于您的 repo 可能是您已复制到 github 的真正原始版本,因此应该没问题。但如果需要,您可以获取或什至对原点进行 --mirror 克隆以开始工作。那么

git filter-branch --index-filter 'git rm --cached --ignore-unmatch -r node_modules' -- --all

如果您的提交在node_modules 之外没有任何改变,并且想要丢弃这些提交,您可以在-- 分隔符之前添加--prune-empty 选项。

(在具有大量历史记录(许多提交)的 repo 上,这可能会很慢;在这种情况下,您可以考虑使用第三方工具,例如 BFG Repo Cleaner,它是用于删除大型/不需要的更专业的工具历史文件(与 filter-branch 相对,后者是一种更通用的工具)。

运行此程序并检查历史记录是否正常后,您将需要对本地存储库进行一些清理。可以说最简单的事情就是用它来创建一个新的克隆。

cd ..
git clone file://localhost/path/to/old/repo newrepo

如果您想清理原始本地存储库,则需要删除 filter-branch 创建的一组“备份引用”(在 refs/original 下),并可能清除引用日志,然后使用gc 实际扔掉不需要的对象。

至于 github 上的 repo,再次删除它并重新创建它可能是最简单的事情 - 特别是如果您有许多重写的分支。或者,您可以强制推送 (git push -f) 每个重写的分支,并查阅 github 文档以获取有关服务器端 gc 的信息

【讨论】:

    猜你喜欢
    • 2023-02-08
    • 1970-01-01
    • 2013-10-16
    • 2022-07-03
    • 2021-12-22
    • 2011-01-14
    • 1970-01-01
    • 2018-07-19
    • 2011-12-19
    相关资源
    最近更新 更多