撤销提交中文件的更改

222

我想撤销特定提交所做的文件更改。

我可以使用git revert命令吗?

还有其他简单的方法吗?


请将特定文件恢复到特定版本的方法:
  1. 使用以下命令查找要恢复的文件的SHA-1哈希值:git log --oneline <file_path>
  2. 找到要恢复的版本的SHA-1哈希值。
  3. 使用以下命令将文件恢复到指定版本:git checkout <commit_hash> <file_path>例如,如果要将文件“example.txt”恢复到SHA-1哈希值为abc123的提交中,则使用以下命令:git checkout abc123 example.txt
- koppor
奇怪...为什么这么多年后会有变化? - VonC
8个回答

353

我见过的最干净的做法在这里描述。

git show some_commit_sha1 -- some_file.c | git apply -R

与VonC的回答类似,但使用git showgit apply


10
做得不错。这个脚本解决方案对此来说有些过度了。为什么不能只使用“git revert sha-1 文件名”呢? - Mark Edington
21
这在我的Mac上可以运行,但在Windows(使用Cygwin)上却显示“致命错误:无法识别的输入”。 - Kedar Mhaswade
5
一个提示:当补丁失败时,我几乎总是需要在git apply命令中添加"-3"标志进行三方合并,因为我通常是在时间上回退一些更改。 - angularsen
3
对于大多数人来说可能很明显,但请确保som_file.c包含了文件的路径,如果有的话,否则你将会悄无声息地修补错误 :) - Warpling
5
不能用于二进制文件。不过,我复制了原始文件,然后执行了 git add/git commit --amend。 - manpatha
显示剩余10条评论

67

如果可以更改提交历史,这里有一个撤销先前提交中单个文件更改的工作流程:

例如,您想要撤销提交 aaa222 中 1 个文件 (badfile.txt) 中的更改:

aaa333 Good commit
aaa222 Problem commit containing badfile.txt
aaa111 Base commit

在基础提交上变基,修改问题提交,然后继续。

1) 开始交互式变基:

git rebase -i aaa111

2) 将需要修改的提交标记为编辑状态,通过将 pick 改为 e

e aaa222
pick aaa333

3) 恢复对错误文件的更改:

git show -- badfile.txt | git apply -R

4) 添加更改并修订提交:

git add badfile.txt
git commit --amend

5) 完成变基:

git rebase --continue

只是想指出,这假定您可以编辑git历史记录。上面的一些答案创建了一个新的提交,以撤消特定更改而不编辑历史记录,这并不总是可能/允许的。 - angularsen
太棒了。这正是我在寻找的。我已经有了这个想法,但在进行交互式变基时,当执行“edit”操作时,文件没有显示为已更改,让我感到困惑。但是,“git show -- badfile.txt | git apply -R”给了我需要的答案<3。 - mraxus
如果我理解得对,git apply -R会移除该文件的提交,并将其设置回原始更改状态? - Linda Lawton - DaImTo

24

简单得多:

git reset HEAD^ path/to/file/to/revert

然后

git commit --amend   

然后

git push -f

文件已经消失,但提交哈希值、信息等内容保持不变。


1
为了完整性,您需要执行git checkout -- path/to/file/to/revert步骤吗?此外,事实并非如此,哈希值之后也不同,对吧?最后一句话可能更好地表述为:“结果是最后一个提交被一个新的提交所替换,两者唯一的区别在于新提交不包含对还原文件的更改。” - Kevin
@Kevin 你可能是对的。我得再仔细检查一下最后一行,但回想起几年前的情况,如果提交哈希值没有改变,我会感到惊讶的。 - Forrest

22

git revert用于撤销提交中的所有文件内容。

对于单个文件,您可以script it

#!/bin/bash

function output_help {
    echo "usage: git-revert-single-file <sha1> <file>"
}

sha1=$1
file=$2

if [[ $sha1 ]]; then
git diff $sha1..$sha1^ -- $file | patch -p1
else
output_help
fi

(来自 git-shell-scripts 实用程序,由 smtlaissezfaire 提供)


注意:
如果您还没有提交当前的修改,另一种方法在这里描述
git checkout -- filename

git checkout 命令有一些选项可以针对文件进行操作,从HEAD中修改文件,覆盖您的更改。


在Caprica上丢弃评论中提到

你可以为git添加别名,这样你就可以使用git revert-file <hash> <file-loc>来还原特定的文件。
查看此gist

[alias]
  revert-file = !sh /home/some-user/git-file-revert.sh

只是为了增加这里的讨论,您可以向git添加别名,以便您可以执行git revert-file <hash> <file-loc>并还原特定文件。 我从这个答案中提取(尽管我不得不进行一些编辑才能正常工作)。 您可以在此处找到我的.gitconfig和编辑后的脚本的副本:https://gist.github.com/droppedoncaprica/5b67ec0021371a0ad438 - AlbertEngelB
@Dropped.on.Caprica 很好的观点。我已经将它包含在答案中以增加可见性。 - VonC

18

如果您想要将文件的更改恢复到上次提交的状态,这是我通常使用的方法。我认为这是最简单的解决方案。

请注意,该文件将被添加到暂存区。

git checkout <prev_commit_hash> -- <path_to_your_file>
希望它有所帮助 :)

2
如果您不想重写历史记录,这是正确的方法。我一直在使用它来清理那些在压缩合并之前不需要处理的文件。然后,变更就会被覆盖掉。 - Preston McCormick
1
这将还原自那次提交以来对文件所做的所有更改,而不仅仅是一个提交。 - vpzomtrrfrt
1
这将还原自那次提交以来对文件所做的所有更改,而不仅仅是一个提交。 - undefined
1
正确的词是“上一个提交哈希”,而不是当前提交。谢谢 @Gabeeka - undefined

13

我会简单地使用--no-commit选项来使用git-revert,然后在最终提交之前从索引中删除不想还原的文件。下面是一个例子,演示如何轻松恢复倒数第二个提交中 foo.c 的更改:

$ git revert --no-commit HEAD~1
$ git reset HEAD
$ git add foo.c
$ git commit -m "Reverting recent change to foo.c"
$ git reset --hard HEAD

首先,git-reset会“取消暂存”所有文件,这样我们就可以只添加回想要还原的那个文件。最后的git-reset --hard会丢弃我们不想保留的其余文件还原。


11
git reset HEAD^ path/to/file/to/revert/in/commit

上面的命令将从提交中取出文件,但在git status中会反映出来。

git checkout path/to/file/to/revert/in/commit

上述命令将撤消更改(结果是您获得与HEAD相同的文件)。

git commit

(传递--amend来修改提交。)

git push

通过这样做,已经提交的文件被删除并还原。

上述步骤应该在提交所在的分支中执行。


8
您可以按照以下步骤操作:
  1. git revert -n <*commit*>-n 撤消所有更改但不会提交它们)
  2. git add <*filename*>(要恢复和提交的文件名)
  3. git commit -m 'reverted message'(添加一个撤销的消息)
  4. 提交后放弃其他文件的更改,以便文件与您之前恢复的更改保持一致

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