Git filter-branch命令给我生成了两组提交记录

5

我需要从我的提交历史中删除一个文件。我遵循了Github的删除敏感数据指南

$ git filter-branch --force --index-filter \
'git rm --cached --ignore-unmatch <myfile>' \
--prune-empty --tag-name-filter cat -- --all

...但我一定是做错了什么,因为现在我有很多重复的提交。一组提交仍然有我的文件;另一组没有。除此之外,它们完全相同。我该如何删除所有仍包含我的文件的提交?


你为什么说你有“重复”的提交?如果您能向我们展示您是如何得出这个结论的(即展示一些命令及其输出),那将会很有帮助。 - user456814
如果我查看 git log,现在我的提交次数是之前的两倍。每个原始提交都有一个相应的新提交,具有相同的提交消息、时间等。git diff 显示两者之间唯一的区别是我尝试删除的文件的存在。 - Katrina
我不明白你的日志中怎么可能有两倍的提交次数。我刚刚在自己的测试仓库上尝试了与GitHub说明相同的git filter-branch命令,它完全正常工作。你最初重写了多少个提交?在执行filter-branch之前,你是否备份了仓库?你是否运行了git log --oneline --graph master命令? - user456814
非常抱歉信息不足,我不知道自己做了什么。我相信Helmut已经准确地描述了根本原因 - 当我运行git log --oneline --graph master时,看起来就是这样 - 但我仍然不确定如何修复它。我最初有大约100个提交,可惜我没有备份。 - Katrina
只要您尚未运行“git gc”,我认为您的旧提交仍然可以恢复,如果这是您需要重新开始的事情(我将为此添加一个答案)。不过在未来,我强烈建议您在使用“git filter-branch”处理时,在像这样出现问题并需要返回原始状态的情况下,先备份克隆您的存储库。 - user456814
2个回答

7

假设您应用了filter-branch,然后从远程拉取。当您运行git filter-branch时,确实会复制您的历史记录。您将创建一组新的提交,它们与旧提交完全相同,除了应用的更改(在您的情况下是删除文件)。所有(或大多数)提交ID都将更改。但是您的更改仅在本地发生。远程仍然具有原始提交。现在您可能已经尝试推送提交,但它说了一些关于“分离头部”或者你的历史记录“分叉”的东西。然后通常要做的事情是拉取。通过这样做,您将获取原始提交并将其合并到重写的历史记录中。而不是拉取,您应该进行强制推送以破坏性地覆盖远程的历史记录,Git拒绝这样做是有很好的理由的。


我认为你假设得太多了,原帖作者提供的信息实在太少,我们无法确定她实际上做了什么。 - user456814
谢谢,@Helmut - 这听起来可能就是发生的事情。我以为通过拉取并合并我的远程分支,我会将远程旧的提交与我的重写提交合并。还有什么快速重写的方法吗?或者我需要手动删除我的提交,然后强制推送以修复远程分支? - Katrina
@Katrina,GitHub的说明指出,在确认filter-branch已经删除了你的文件后,立即进行force push,而不是立即pull。合并旧的远程提交是没有意义的,因为它们仍然包含你首先想要删除的文件。你真正想做的是用新的提交覆盖旧的远程提交,这正是GitHub的说明告诉你要做的。 - user456814

7
根据问题、现有答案和评论的信息,似乎原帖发布者在执行git filter-branch后犯了一些错误,并没有备份克隆仓库。如果原帖发布者想要将仓库恢复到filter-branch之前的状态,以下是返回仓库的说明。
原始参考资料 git filter-branch会自动保存旧提交的引用,以防需要恢复它们。你可以在仓库的.git/refs/original/refs/目录下找到它们。
ls -l .git/refs/original/refs/heads/
total 1
-rw-r--r--    1 Keoki    Administ       41 May 23 01:13 master

ls -l .git/refs/original/refs/tags/
total 1
-rw-r--r--    1 Keoki    Administ       41 May 23 01:13 v1.0

每个引用都包含您旧提交的提交sha ID:
cat .git/refs/original/refs/heads/master
276fc24dc4b12edf75aea40f4fd50e25a5840005

cat .git/refs/original/refs/tags/v1.0
475593a612141506f59a141e38b8c6a3a2917f85

使用硬重置进行恢复

要获取在执行filter-branch之前的原始master分支,只需使用上述引用进行硬重置,或使用其中包含的提交sha ID:

git checkout master

# Use reference
git reset --hard refs/original/refs/heads/master

# Or use sha ID
git reset --hard 276fc24dc4b12edf75aea40f4fd50e25a5840005

谢谢 - 这真的很有帮助,让我能够撤销我所犯的错误。我感激您的耐心,我知道从我这里获取正确的信息就像拔牙一样困难。 - Katrina
@Katrina,别担心,这没什么大不了的。现在你已经成功恢复了原始提交记录,你明白如何使用filter-branch和force push了吗?另外,在你再次使用filter-branch之前,我建议你使用git clone --bare <local-repo> "backup"快速备份克隆一下,这是在进行类似filter-branch这样的破坏性操作时通常要做的好习惯。 - user456814

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