从 git 恢复特定提交
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/20324638/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Reverting specific commits from git
提问by Sankar
I have a git tree with a lot of commits and a lot of files. Now, I want to revert specific commits that touch a file only. To explain:
我有一个包含大量提交和大量文件的 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
Now I want to revert just the two commits b49eb8and 1d8b06without reverting the changes to a. IOW revert only the commits in a file (without reverting other intermediate commits (which may be thousands in number) in different files) How is this possible ?
现在我只想恢复b49eb8和1d8b06的两个提交,而不将更改恢复到 a。IOW 仅还原文件中的提交(不还原不同文件中的其他中间提交(可能有数千个))这怎么可能?
回答by mamapitufo
You can use git revert
with the --no-commit
option. In your example:
您可以使用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"
If you don't provide a commit message then a prepared message will be available when the commit message editor is started.
如果您不提供提交消息,则在启动提交消息编辑器时将提供准备好的消息。
If you omit the --no-commit
option then the changes in the commits you specify will be reverted. This is achieved by applying the reverse of the changes in the specified commits and committing that. This results in a new commit, both the original and the reverted commit will be in the history of your repository.
如果您省略该--no-commit
选项,则您指定的提交中的更改将被还原。这是通过在指定的提交中应用更改的反向并提交来实现的。这会导致一个新的提交,原始提交和恢复的提交都将在您的存储库的历史记录中。
回答by jwg
There are two cases here:
这里有两种情况:
When you have already pushed your git tree to somewhere and you don't want to change the history. In this case you will need a new commit expressing the changes you made in reverting the previous commits. You should use @mamapitufo's answer.
If you have never pushed the branch that the changes are on, and you can change the history. In this case you can completely remove the unwanted commits. This will neaten the history and means that you don't push a wrong turning to your co-workers or the public.
当您已经将 git 树推送到某个地方并且您不想更改历史记录时。在这种情况下,您将需要一个新的提交来表达您在还原先前提交时所做的更改。您应该使用@mamapitufo 的答案。
如果您从未推送更改所在的分支,则可以更改历史记录。在这种情况下,您可以完全删除不需要的提交。这将整理历史,并意味着您不会将错误转向您的同事或公众。
In the second case you should do git rebase -i
. Find a commit which comes before any of the history you want to change. This might be the hash of the commit, or the name of the branch or tag. For example, you could do
在第二种情况下,您应该这样做git rebase -i
。查找在您要更改的任何历史记录之前的提交。这可能是提交的哈希值,或者分支或标签的名称。例如,你可以做
git rebase -i 23def8231
or if you started from the branch origin/dev_branch
and did the work which includes the bits to remove on your branch called dev_branch
, you could do
或者,如果您从分支开始origin/dev_branch
并完成了包括要在名为 的分支上删除的位的工作dev_branch
,您可以这样做
git rebase -i origin/dev_branch
Now, you will be sent into an editor window where you can see a list of all the commits which you are rebasing. This might be vim
- if you don't usually edit in the terminal it could be set as the default. You will probably need a quick start guide to vim and an open mind if that's the case.
现在,您将被发送到一个编辑器窗口,在那里您可以看到您正在重新定位的所有提交的列表。这可能是vim
- 如果您通常不在终端中进行编辑,则可以将其设置为默认值。如果是这种情况,您可能需要一个 vim 快速入门指南和一个开放的心态。
Now, the easiest thing to do is to remove commits. You do this by deleting the line, or adding a #
which indicates a comment to the start of the line. (There are already some comments in the file, to explain things to you. Ignoring these or deleting them has no effect.)
现在,最简单的方法是删除提交。您可以通过删除该行或#
在该行的开头添加指示注释来完成此操作。(文件中已经有一些注释,向您解释。忽略这些或删除它们没有任何效果。)
When you are finished, save the file and exit the editor. The rebase happens like this: git goes back to the commit you named. It goes through the list you saved and replays each commit in that list. Then it makes the result of that process the new version of the branch you were originally on.
完成后,保存文件并退出编辑器。rebase 是这样发生的:git 返回到你命名的提交。它遍历您保存的列表并重播该列表中的每个提交。然后它使该过程的结果成为您最初所在分支的新版本。
Important things to remember:
要记住的重要事项:
- If you get lost or delete too many lines, you can cancel the rebase by deleting every commit line in the file, and saving. The rebase process will end with nothing changed at all.
- It's possible to create conflicts. For example if you remove a commit which edits a file, and leave in a later commit which edits the same place. The later commit will now not apply correctly and you will have to edit by hand or in a merge tool to get the version you want.
- 如果丢失或删除了太多行,可以通过删除文件中的每个提交行并保存来取消 rebase。变基过程将在没有任何更改的情况下结束。
- 有可能产生冲突。例如,如果您删除编辑文件的提交,并保留在稍后编辑同一位置的提交。以后的提交现在将无法正确应用,您必须手动或在合并工具中进行编辑才能获得所需的版本。
You can also do lots of other manipulation in git rebase -i
. For example changing the order of commits, squashing several together into one, adding extra changes between commits, or changing the messages. It is very useful. The classic use case is cleaning up your local branch before you push it back to somewhere where other people will look at your changes.
您还可以在git rebase -i
. 例如,更改提交的顺序、将多个合并为一个、在提交之间添加额外的更改或更改消息。这是非常有用的。经典用例是在将本地分支推回其他人会查看您的更改的某个地方之前清理它。