撤销旧提交中特定文件的更改,不留痕迹。

3
我有一个分支,在这个分支中我修改了几个文件,进行了几次提交。一段时间以前,我开始在这些文件的子集上进行一些工作,并检入了一些更改。之后,我们决定将这些文件删除作为另一个分支正在完成的事情的一部分。因此,我想要“取消触摸”这些文件 - 它们与我在我的分支中所做的工作无关,我不想因此造成任何合并冲突与其他地方已删除的文件。

是否有任何方法可以更新使这些文件保持不变的提交,并且不会出现在我的分支历史记录之中

更具体地说:

考虑当前状态下的以下源代码树:

src/A.java
src/B.java
src/C.java
src/D.java

在大约10个提交记录之前,有一个提交记录做了以下更改:

M   src/B.java
M   src/C.java
A   src/D.java

有没有办法从历史记录中删除对C.java的更改,这样当您查看其上面的提交时,它看起来像

M   src/B.java
A   src/D.java

如您所见,C.java 文件未被我的分支更改过。

我尝试了使用 git revert 命令,但是没有找到一种不需要创建新提交的方式来撤销更改。我知道可以通过在我的分支中删除文件来避免合并冲突,但这感觉像是一个“丑陋”的解决方案,本次虽然有效但下一次可能无效(如果另一个分支的更改不是删除而是修改呢?),所以如果有更加优雅的方法,我希望能学习到它。


1个回答

1

虽然 现已删除的 RyPeck 回答 RyPeck 在评论中提供了使用 git filter-branch 的好方法,但我采用了不同的方法解决了这个问题,所以我想分享一下我是如何解决的 - 即使没有其他目的,也为了将来的参考(我未来肯定还会经常在网上问这个问题...):

首先,我使用 git rebase -i master 进行交互式变基。这打开了我的文本编辑器(我恰好配置了 git 以打开 Notepad++),其中包含类似于此的文件:

pick First commit message
pick Second commit message
pick This is where I touched the files I didn't want to touch
pick Another commit
pick This goes on for a while
pick I think you get the point
pick I'll stop now

接着是一些关于如何编辑文件的评论。我的做法是将包含我想要修改的提交的那行改变为

...
edit This is where I touched the files I didn't want to touch
...

然后保存并关闭编辑器。此时,Git 将应用前三个提交,并停止并显示:

Stopped at <hash>... This is where I touched the files I didn't want to touch
You can amend the commit now, with

    git commit --amend

Once you are satisfied with your changes, run

    git rebase --continue

然后,我使用类似于以下内容的方法将文件重置为此提交之前的状态:

git reset HEAD^ src/C.java # undoes the changes to the file
git add src/C.java         # stages the undoing of the changes
git commit --amend         # amends the undoing to the last commit

之后,提交已经两次更改了文件 - 首先是我所做的更改,然后再次更改为原样 - git已将这两组更改压缩成一个,其中它们互相抵消并没有产生任何作用。现在我运行

git rebase --continue

完成任务。如果我现在查看 src/C.java 的历史记录,就不会有关于这一系列提交的任何记录。
这种技术非常灵活 - 使用提交的 edit 模式,您可以对其进行任何更改。

1
这对于大型项目历史来说将是一个巨大的痛苦。仅供讨论,这与git filter-branch最终执行的操作有多大不同? - RyPeck
@IamReck:我不知道 - 在我完成这个之前,我没有找到你的答案,所以我没有机会测试git filter-branch并查看会发生什么。如果我有时间,我可能会检查一个虚拟分支并运行一些测试。 - Tomas Aschan
2
@IamReck:另外,关于“大型项目历史记录”的问题:我绝对不建议在更大的范围内或在多个开发人员之间共享的任何项目上这样做。在我的情况下,我独自在一个特性分支上工作,并决定一些更改实际上应该在它们的分支中,因为它们是不同特性的一部分。因此,我的更改都在本地未发布的分支上 - 这样的分支历史记录(希望如此)永远不会非常庞大... - Tomas Aschan
我没有正确地使用git filter-branch。我在这里找到了正确的方法。https://dev59.com/W2kw5IYBdhLWcg3woMFD - RyPeck

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