撤消旧提交中特定文件的更改,不留下任何痕迹

时间:2013-07-08 16:09:45

标签: git version-control git-revert

我有一个分支,我在几个提交中对几个文件进行了一些更改。有一段时间,我开始对这些文件的子集做一些工作,并检查了一些更改。之后,我们决定删除这些文件作为另一个分支中正在完成的事情的一部分。因此,我想“解开”那些文件 - 它们与我在分支机构中的操作无关,而且我不希望因此而导致与其他已删除文件发生任何合并冲突。

有没有什么方法可以更新进行这些更改的提交,使这些文件保持不变,并且在我的分支历史之外

更具体地说:

在当前状态下考虑以下源树:

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 个答案:

答案 0 :(得分:1)

虽然在评论中 the now deleted answer by RyPeck RyPeck linked to a good way of doing this using 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模式,您可以对其进行任何更改。