删除旧的git提交记录

3

我犯了一个愚蠢的错误,不小心将node_modules文件夹提交到了本地git并推送到了github。这是一个很大的文件夹,任何下载我的存储库的人都会在旧的提交中下载此文件夹。我一直在尝试使用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

你如何移除这些提交?

请阅读以下内容:https://dev59.com/cZLea4cB1Zd3GeqP8vCg。 - undefined
可能是从git历史中删除并完全移除提交的重复问题。 - undefined
2个回答

3
你需要做两件事情:
1. 本地删除这些提交。 2. 使用强制推送覆盖 origin 上的分支。
编辑:实际上,首先要备份那些将被删除的文件,因为这种方法会从你的文件系统中删除它们。
首先:
git rebase -i HEAD~4
现在你有一个打开的编辑器,其中包含类似于你编写的行。删除你不想要的提交行。保存并退出编辑器。
如果正确,请检查 git log。
然后:
git push -f
解释:
首先你启动了一个交互式历史编辑会话。您在编辑器中有可能的选项,已注释掉。您可以执行许多操作,例如通过删除行来删除提交、将它们压缩在一起、通过重新排序行来重新排序等等。
然后你删除了提交行并保存。发生的是 git 尝试创建新的提交链以应用你所需的更改。实际上,新的提交已经创建了(提交的一部分是链接到前一个提交),因此已更改的提交具有新的哈希值(因为从技术上讲,它们是新的)。你会发现 origin/alex/matUI 不再在你的 HEAD(在 git log 中)。
最后你使用强制推送。这样就将 origin/alex/matUI 覆盖为当前的 alex/matUI。这实际上覆盖了你的 HEAD 指向的任何分支,并与 origin 上的分支绑定(你的 alex/matUI 与 origin/alex/matUI 绑定,这不是魔术,它是一个明确的绑定,你可以手动创建或在拉取/克隆时自动创建)。通常,push 是保守的,在你的分支提示后只允许添加。-f 强制执行此操作。使用力量吧,卢克 :)

您可能还想运行 git gc(垃圾回收),它应该会从您的 git 存储库中删除不可访问的对象,因此 .git 文件夹将不再包含这些提交。我不能百分之百确定它是否会删除您刚刚删除的提交。我认为是这样的。无论如何,github 应该在服务器上自行运行此类垃圾回收,因此无需担心它在他们的服务器上。 - undefined
1
不,gc通常不会删除您刚从历史记录中删除的提交,因为它们仍然可以通过reflog访问到。至于服务器方面,您能否提供确认在GitHub上如何使用gc的文档,或者这只是您假设它“应该”工作的方式?因为我很久没有专门查看过该服务上的情况了,但我记得它并不像那样好用。 - undefined
谢谢澄清!我不确定(这就是为什么我没有在答案中添加它),但在我看来,这似乎是一个非常合理的做法,可以在几乎没有计算成本的情况下节省空间(可能只在进行了x次操作之后)。例如,GitLab每晚都会进行清理,至少自托管实例会这样做。有一次,一个子模块的修订版本在夜间消失了,因为它是一个未连接的提交(已经被修改)。 - undefined

1
您可以应用的任何解决方案都将重写历史记录。这意味着它会对拥有您的代码库副本的其他人产生不利影响,如果他们在尝试恢复时做错了事情,可能会撤销您的修复。
因此,在公开可用的代码库中出现这种情况是一个非常不幸的情况,但如果您知道没有多少人(或者可能没有人)克隆了它,实际上可能不会太糟糕。重点是以一种所有代码库用户都能了解的方式进行沟通。
(通常我会说您需要获得拥有代码库副本的任何人的同意/协调;在这里,如果您将其视为您让其他人克隆的代码库,我想您可以说只需要一定的协调措施就可以了;但是除非您限制推送到原始位置,否则某人重新引入错误提交并重新引入问题的可能性存在,无论我们怎么说都是“正确”的。)
无论如何,请注意上述内容,但它确实无法避免。您必须重写历史记录,问题是如何处理。
你可以删除自添加 node_modules 文件夹以来所做的所有提交,但这样做会丢失那些提交中的其他更改。最简单的方法是使用 git filter-branch 来去除 node_modules 而不会丢失其他历史记录(也无需第三方工具)。
当然,您需要确保在本地拥有所有引用。因为您的存储库可能是真正的原始存储库,您已经将其复制到了 GitHub 上,所以应该没问题。但如果需要,您可以获取或甚至使用 --mirror 克隆原始存储库来开始操作。
git filter-branch --index-filter 'git rm --cached --ignore-unmatch -r node_modules' -- --all

如果您有更改仅限于node_modules的提交,并希望放弃这些提交,您可以在--分隔符之前添加--prune-empty选项。
(对于具有大量历史记录(许多提交)的存储库,这可能会很慢;在这种情况下,您可以考虑使用第三方工具BFG Repo Cleaner,它是一种更专业的用于从历史记录中删除大型/不需要文件的工具(而不是filter-branch,后者是一种更通用的工具)。)
运行此操作后,请检查您的历史记录是否正确,然后您将需要清理本地存储库。最简单的方法可能是使用它来创建一个新克隆。
cd ..
git clone file://localhost/path/to/old/repo newrepo

如果您希望清理原始的本地仓库,您需要删除由filter-branch创建的一组“备份引用”(在refs/original下),可能还要清除引用日志,然后使用gc实际丢弃不需要的对象。
至于github上的仓库,如果您有许多重写的分支,删除并重新创建可能是最简单的方法。或者,您可以强制推送(git push -f)每个重写的分支,并查看github文档以获取有关服务器端gc的信息。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接