git 删除旧提交

git remove old commits

我犯了一个愚蠢的错误,不小心将 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

你会如何删除这些提交?

你必须做两件事:

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

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

第一个:

git rebase -i HEAD~4

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

检查 git log 是否正确。

然后:

git push -f

解释:

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

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

你终于用力一推。这会用您当前的 alex/matUI 覆盖 origin/alex/matUI。这实际上会覆盖您的 HEAD 指向的任何分支并与原点上的分支绑定(您的 alex/matUI 与 origin/alex/matUI 绑定,这不是魔法,它是您手动创建或拥有的明确绑定它在 pulling/cloning 时创建)。通常 push 是保守的,只允许在你的分支提示之后添加。 -f 强制通过。使用原力 Luke :)

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

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

(通常我会说你需要 agreement/coordination 任何拥有回购协议副本的人;在这里,如果你将它视为你的回购协议,你正在让其他人克隆,我想你可以说只是一种协调措施就可以了;但是除非你限制推送到原点,否则有人做 "wrong fix" 并重新引入错误提交的可能性存在,无论我们怎么说 "right"。)

总之,知道以上几点,实在没办法。你必须改写历史,问题是如何改写。

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

当然你想确保你有本地的所有参考。由于您的回购协议可能是真正的原始版本,您已将其复制到 github,因此应该没问题。但如果需要,您可以获取甚至做一个 --mirror 来源的克隆来开始。那么

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

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

(在历史悠久(多次提交)的回购中,这可能会很慢;在这种情况下,您可以考虑使用第三方工具,如 BFG Repo Cleaner,这是一个更专业的工具,用于删除 large/unwanted 个历史文件(与 filter-branch 相反,后者是一个更通用的工具)。)

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

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

如果您想清理原始本地存储库,则需要删除 filter-branch 创建的一组 "backup refs"(在 refs/original 下),并可能擦除清除 reflog,然后使用 gc 实际丢弃不需要的对象。

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

的信息