撤消 git 中的更改(不重写历史记录)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/642264/
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
Undo change in git (not rewriting history)
提问by dbr
I made a change in a script and committed it. Then I made a few other changes, and pushed them to a remote repository and such.
我对脚本进行了更改并提交了它。然后我做了一些其他更改,并将它们推送到远程存储库等。
Then I realised that first change I mentioned was stupid, and want to undo it.. Can I "unapply" that commit, without manually copy/pasting the diff?
然后我意识到我提到的第一个更改是愚蠢的,并且想要撤消它..我可以“取消应用”该提交,而无需手动复制/粘贴差异吗?
As an example: I have two files, a.py
and b.py
:
例如:我有两个文件,a.py
并且b.py
:
Commit 1:
I delete a function in a.py
Commit 2:
I change a few lines in b.py
Commit 3:
I change the docstring in a.py
Can I undo that function deletion, and make it appear as "commit 4" (rather than deleting commit 1)
我可以撤消该函数删除,并使其显示为“提交 4”(而不是删除提交 1)
回答by Jesse Rusak
Yes, you can use git revertfor this. See the git manual section on thisfor more information.
是的,您可以为此使用git revert。有关更多信息,请参阅git 手册部分。
The gist is that you can say:
要点是你可以说:
git revert 4f4k2a
Where 4f4k2a is the id of the commit you'd like to undo, and it will try to undo it.
其中 4f4k2a 是您要撤消的提交的 ID,它将尝试撤消它。
回答by VonC
Just a comment:
只是评论:
git revert aCommit
does revert the allcommit (as in "all the filespart of the commit" ):
it computes a reverse patch, applies it on HEAD and commit.
确实还原所有提交(如“提交的所有文件部分”):
它计算一个反向补丁,将其应用于 HEAD 并提交。
So two problems here (the first one is easily solved):
所以这里有两个问题(第一个很容易解决):
- it does always commit, so you may want to add
-no-commit
option: "git revert --no-commit aCommit
": this is useful when reverting more than one commits' effect to your index in a row. - it does not apply for a specific file (what if you a.py was part of a commit with 1000 other changes that you may not want to revert) ?
For that, if you want to extract specific files as they were in another commit, you should seegit-checkout
, specifically thegit checkout <commit> <filename>
syntax (that is not exactly what you need in this case though)
- 它确实总是提交,因此您可能需要添加
-no-commit
选项:“git revert --no-commit aCommit
”:这在将多个提交的效果连续恢复到您的索引时很有用。 - 它不适用于特定文件(如果您的 a.py 是具有 1000 个您可能不想还原的其他更改的提交的一部分,该怎么办)?
为此,如果您想像在另一个提交中一样提取特定文件,您应该看到git-checkout
,特别是git checkout <commit> <filename>
语法(尽管在这种情况下这并不是您所需要的)
Easy Git(Elijah Newren) tried to bring a more "complete revert" to the Git Mailing list; but without much success:
Easy Git(Elijah Newren) 试图为Git 邮件列表带来更“完整的还原” ;但没有取得多大成功:
People occasionally want to "revert changes".
Now, this may be:
- the changes between 32 and 29 revisions ago,
- it might be all changes since the last commit,
- it could be the changes since 3 commits ago, or
- it could be just one specific commit.
- The user may want to subset such reversions to just specific files,
人们偶尔想要“还原更改”。
现在,这可能是:
- 32 和 29 修订前的变化,
- 它可能是自上次提交以来的所有更改,
- 这可能是自 3 次提交以来的变化,或者
- 它可能只是一个特定的提交。
- 该用户可能希望子集,回复突变只是特定的文件,
(eg revert
is documented here, but I am not sure it is part of the current distribution of eg though)
(eg revert
被记录在这里,但我不知道它是例如电流分布的一部分,虽然)
but it all boils down to "reverting changes" in the end.
但这一切最终都归结为“还原更改”。
eg revert --since HEAD~3 # Undo all changes since HEAD~3
eg revert --in HEAD~8 # much like git revert HEAD~8, but nocommit by default
eg revert --since HEAD foo.py # Undo changes to foo.py since last commit
eg revert foo.py # Same as above
eg revert --in trial~7 bar.c baz. # Undo changes made in trial~7 to bar.[ch]
Are these kinds of "reverting data" really so different that there should need to be different commands, or that some of these operations shouldn't be supported by the simple revert command?
Sure, most users most of the time will probably use the "eg revert FILE1 FILE2...
" form, but I didn't see the harm in supporting the extra capabilities.Also...is there anything fundamental that would keep core git from adopting such behavior?
Elijah
Note: commits by default don't make sense for the generalized
revert
command, and "git revert REVISION
" would error out with instructions (telling the user to add the --in flag).
这些类型的“恢复数据”真的如此不同以至于需要不同的命令,或者简单的 revert 命令不应该支持其中的一些操作?
当然,大多数用户大部分时间可能会使用“eg revert FILE1 FILE2...
”形式,但我没有看到支持额外功能的危害。另外……有什么基本的东西可以阻止核心 git 采取这种行为吗?
以利亚
注意:默认情况下,提交对于通用
revert
命令没有意义,并且“git revert REVISION
”会错误提示(告诉用户添加 --in 标志)。
Lets say you have, out of 50 committed, 20 files you realize that old commit X introduced changes that should not have taken place.
A little plumbing is in order.
What you need is a way to list all the specific files you need to revert
(as in "to cancel changes made in commit X while keeping all subsequent changes"),
and then, for each of them:
假设您在 50 个提交的文件中,有 20 个文件您意识到旧的提交 X 引入了不应该发生的更改。
一个小管道是有序的。
您需要的是一种列出您需要还原的所有特定文件的方法
(如“取消提交 X 中所做的更改,同时保留所有后续更改”),
然后,对于每个文件:
git-merge-file -p a.py X X^
The issue here is to recover the lost function without obliterating all subsequent changes in a.py you might want to keep.
That technique is sometime called "negative merging".
这里的问题是恢复丢失的功能,而不会删除您可能想要保留的 a.py 中的所有后续更改。
该技术有时称为“负合并”。
Since git merge-file <current-file> <base-file> <other-file>
means:
incorporates all changes that lead from the <base-file>
to <other-file>
into <current-file>
, you can restorethe deleted function by saying you want to incorporate all changes.)
由于方法:整合了从导致所有更改,以进入,你可以恢复,说你想将所有的变化删除功能)。git merge-file <current-file> <base-file> <other-file>
<base-file>
<other-file>
<current-file>
- from: X (where the function has been deleted)
- to: X^ (the previous commit before X, where the function was still there)
- 来自:X(该函数已被删除)
- to: X^ (X 之前的前一次提交,函数还在那里)
Note: the '-p
'argument which allows you to review first the changes without doing anything on the current file. When you are sure, remove that option.
注意:' -p
'参数允许您首先查看更改而不对当前文件执行任何操作。当您确定时,删除该选项。
Note: the git merge-file
is not that simple: you can not reference previous versions of the file just like that.
(you would have over and over the frustrating message: error: Could not stat X
)
You have to:
注:该git merge-file
是没有那么简单:你不能引用该文件就这样的早期版本。
(你会一遍又一遍的令人沮丧的消息: error: Could not stat X
)
你必须:
git cat-file blob a.py > tmp/ori # current file before any modification
git cat-file blob HEAD~2:a.py > tmp/X # file with the function deleted
git cat-file blob HEAD~3:a.py > tmp/F # file with the function which was still there
git merge-file a.py tmp/X tmp/F # basically a RCS-style merge
# note the inversed commit order: X as based, then F
# that is why is is a "negative merge"
diff -u a.py tmp/ori # eyeball the merge result
git add a.py
git commit -m "function restored" # and any other changes made from X are preserved!
If this is to be done for a large number of files within a previous commit... some scripting is in order ;)
如果要对先前提交中的大量文件执行此操作...需要编写一些脚本;)
回答by Paul
To revert the changes to only one file within a commit, as VonCpointed out, I would checkout
the branch (master or trunk or whatever) and then checkout
the version of the file I wanted to revert and treat it as a new commit:
正如VonC指出的那样,要将更改恢复到提交中的一个文件,我将checkout
分支(主或主干或其他),然后checkout
是我想要恢复的文件版本并将其视为新提交:
$ git checkout trunk
$ git checkout 4f4k2a^ a.py
$ git add a.py
$ git diff #verify I'm only changing what I want; edit as needed
$ git commit -m 'recover function deleted from a.py in 4f4k2a'
There's probably a plumbing command that would do this directly, but I wouldn't use it if I knew it. It's not that I don't trust Git, but I don't trust myself -- I wouldn't trust that I knew without looking what was changed in that file in that commit and since then. And once I look, it's easier to just build a new commit by editing the diff
. Perhaps that's just personal workstyle.
可能有一个管道命令可以直接执行此操作,但如果我知道它,我就不会使用它。并不是我不信任 Git,而是我不信任自己——我不相信我不知道在那个提交中以及从那时起该文件中发生了什么变化。一旦我查看,通过编辑diff
. 也许这只是个人的工作方式。
回答by Mohan Nayaka
Have a look at this git revert question. There seems to be a issue reverting older commits if not in a consecutive sequence including the most recent commit.
看看这个 git revert question。如果不是在包括最近提交的连续序列中,则还原较旧的提交似乎存在问题。