从git恢复特定提交

时间:2013-12-02 09:17:08

标签: git github git-rebase revert git-revert

我有一个包含很多提交和大量文件的git树。现在,我想恢复仅触及文件的特定提交。解释:

> git init
Initialized empty Git repository in /home/psankar/specific/.git/
> echo "File a" > a
> git add a ; git commit -m "File a"
[master (root-commit) 5267c21] File a
 1 file changed, 1 insertion(+)
 create mode 100644 a
> echo "File b" > b
> git add b; git commit -m "File b"
[master 7b560ae] File b
 1 file changed, 1 insertion(+)
 create mode 100644 b
> echo "File c" > c
> git add c; git commit -m "File c"
[master fd6c132] File c
 1 file changed, 1 insertion(+)
 create mode 100644 c
> echo "b and c modified" > b ; cp b c
> git commit -a -m "b and c modified"
[master 1d8b062] b and c modified
 2 files changed, 2 insertions(+), 2 deletions(-)
> echo "a modified" > a
> git commit -a -m "a modified"
[master 5b7e0cd] a modified
 1 file changed, 1 insertion(+), 1 deletion(-)
> echo "c modified" > c
> git commit -a -m "c modified"
[master b49eb8e] c modified
 1 file changed, 1 insertion(+), 1 deletion(-)
> git log --pretty=oneline c
> git log --pretty=oneline c | cat
b49eb8e03af331bddf90342af7d076f831282bc9 c modified
1d8b062748f23d5b75a77f120930af6610b8ff98 b and c modified
fd6c13282ae887598d39bcd894c050878c53ccf1 File c

现在我想恢复两个提交 b49eb8 1d8b06 而不将更改还原为a。 IOW只恢复文件中的提交(不会在不同的文件中恢复其他中间提交(可能数千个))这怎么可能?

2 个答案:

答案 0 :(得分:75)

您可以将git revert--no-commit选项一起使用。在您的示例中:

$ git revert --no-commit b49eb8e 1d8b062
# Files that were modified in those 2 commits will be changed in your working directory
# If any of those 2 commits had changed the file 'a' then you could discard the revert for it:
$ git checkout a
$ git commit -a -m "Revert commits b49eb8e and 1d8b062"

如果您未提供提交消息,则在启动提交消息编辑器时,可以使用准备好的消息。

如果省略--no-commit选项,则将恢复您指定的提交中的更改。这是通过应用指定提交中的更改的反向并提交它来实现的。这会导致新的提交,原始提交和还原提交都将在您的存储库的历史记录中。

答案 1 :(得分:11)

这里有两种情况:

  1. 当你已经把你的git树推到某个地方并且你不想改变历史时。在这种情况下,您将需要一个新的提交,表示您在还原先前提交时所做的更改。你应该使用@ mamapitufo的答案。

  2. 如果您从未推动更改所在的分支,则可以更改历史记录。在这种情况下,您可以完全删除不需要的提交。这将扼杀历史,意味着你不会错误地转向你的同事或公众。

  3. 在第二种情况下,您应该git rebase -i。找到您要更改的任何历史记录之前的提交。这可能是提交的哈希值,也可能是分支或标记的名称。例如,你可以做

    git rebase -i 23def8231
    

    或者如果你从分支origin/dev_branch开始并且做了包含要在你的分支上删除的名为dev_branch的位的工作,你可以做

    git rebase -i origin/dev_branch
    

    现在,您将被发送到编辑器窗口,在该窗口中您可以看到所有要重新设置的提交的列表。这可能是vim - 如果您通常不在终端中进行编辑,则可将其设置为默认值。如果是这样的话,你可能需要一个快速入门的vim和开放的思想。

    现在,最简单的方法是删除提交。您可以通过删除该行,或添加一个#来表示对该行的开头的注释。 (文件中已经有一些注释,向你解释。忽略这些或删除它们都没有效果。)

    完成后,保存文件并退出编辑器。 rebase发生如下:git返回到你命名的提交。它会浏览您保存的列表并重播该列表中的每个提交。然后它将该过程的结果作为您最初所在分支的新版本。

    要记住的重要事项:

    • 如果丢失或删除太多行,可以通过删除文件中的每个提交行并保存来取消rebase。 rebase过程将结束,一切都没有改变。
    • 可能会产生冲突。例如,如果删除编辑文件的提交,则保留稍后编辑相同位置的提交。现在,以后的提交将无法正确应用,您必须手动或在合并工具中进行编辑才能获得所需的版本。

    您还可以在git rebase -i中进行许多其他操作。例如,更改提交顺序,将几个压缩成一个,在提交之间添加额外的更改,或更改消息。这非常有用。经典的用例是在将其推回到其他人会查看您的更改的地方之前清理您的本地分支。