58

我有一个 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

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

4

2 回答 2

104

您可以使用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选项不会自动提交,它允许您编辑和添加自己的提交消息

请注意,与git reset所有git revert还原的提交不同,提交历史记录中仍将存在

于 2013-12-02T09:57:24.483 回答
13

这里有两种情况:

  1. 当您已经将 git 树推送到某个地方并且您不想更改历史记录时。在这种情况下,您将需要一个新的提交来表达您在恢复之前的提交时所做的更改。您应该使用@mamapitufo 的答案。

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

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

git rebase -i 23def8231

或者,如果您从分支开始origin/dev_branch并完成了包括要在您的分支上删除的位的工作dev_branch,您可以这样做

git rebase -i origin/dev_branch

现在,您将被发送到一个编辑器窗口,您可以在其中看到您正在变基的所有提交的列表。这可能是vim- 如果您通常不在终端中进行编辑,则可以将其设置为默认值。如果是这种情况,您可能需要一份 vim 快速入门指南和开放的心态。

现在,最简单的做法是删除提交。为此,您可以删除该行,或在#该行的开头添加表示注释的 a。(文件中已经有一些注释,给你解释。忽略这些或删除它们没有效果。)

完成后,保存文件并退出编辑器。变基是这样发生的:git 回到你命名的提交。它遍历您保存的列表并重播该列表中的每个提交。然后它使该过程的结果成为您最初所在分支的新版本。

要记住的重要事项:

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

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

于 2015-10-10T23:14:03.553 回答