如何在 Git 里撤销任何操作

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何在 Git 里撤销任何操作相关的知识,希望对你有一定的参考价值。

任何一个版本控制系统中,最有用的特性之一莫过于 逗撤销(undo)地操作。在Git中,逗撤销地有很多种含义。

当你完成了一次新的提交(commit),Git会及时存储当前时刻仓库(repository)的快照(snapshot);你能够使用Git将项目回退到任何之前的版本。

下文中,我将列举几个常见的、需要逗撤销地的场景,并且展示如何使用Git来完成这些操作。

一、撤销一个公共修改 Undo a "public" change

场景:你刚刚用git push将本地修改推送到了GitHub,这时你意识到在提交中有一个错误。你想撤销这次提交。

使用撤销命令:git revert

发生了什么:git revert将根据给定SHA的相反值,创建一个新的提交。如果旧提交是逗matter地,那么新的提交就是逗anti-matter地——旧提交中所有已移除的东西将会被添加进到新提交中,旧提交中增加的东西将在新提交中移除。

这是Git最安全、也是最简单的逗撤销地场景,因为这样不会修改历史记录——你现在可以git push下刚刚revert之后的提交来纠正错误了。

二、修改最近一次的提交信息 Fix the last commit message

场景:你只是在最后的提交信息中敲错了字,比如你敲了git commit -m "Fxies bug #42",而在执行git push之前你已经意识到你应该敲"Fixes bug #42"。

使用撤销命令:git commit –amend或git commit --amend -m "Fixes bug #42"

发生了什么:git commit –amend将使用一个包含了刚刚错误提交所有变更的新提交,来更新并替换这个错误提交。由于没有staged的提交,所以实际上这个提交只是重写了先前的提交信息。

三、撤销本地更改 Undo "local" changes

场景:当你的猫爬过键盘时,你正在编辑的文件恰好被保存了,你的编辑器也恰在此时崩溃了。此时你并没有提交过代码。你期望撤销这个文件中的所有修改——将这个文件回退到上次提交的状态。

使用撤销命令:git checkout --

发生了什么:git checkout将工作目录(working directory)里的文件修改成先前Git已知的状态。你可以提供一个期待回退分支的名字或者一个确切的SHA码,Git也会默认检出HEAD——即:当前分支的上一次提交。

注意:用这种方法逗撤销地的修改都将真正的消失。它们永远不会被提交。因此Git不能恢复它们。此时,一定要明确自己在做什么!(或许可以用git diff来确定)

四、重置本地修改 Reset "local" changes

场景:你已经在本地做了一些提交(还没push),但所有的东西都糟糕透了,你想撤销最近的三次提交——就像它们从没发生过一样。

使用撤销命令:git reset或git reset --hard

发生了什么:git reset将你的仓库纪录一直回退到指定的最后一个SHA代表的提交,那些提交就像从未发生过一样。默认情况下,git
reset会保留工作目录(working
directory)。这些提交虽然消失了,但是内容还在磁盘上。这是最安全的做法,但通常情况是:你想使用一个命令来逗撤销地所有提交和本地修改——那
么请使用--hard参数吧。

五、撤销本地后重做 Redo after undo "local"

场景:你已经提交了一些内容,并使用git reset –hard撤销了这些更改(见上面),突然意识到:你想还原这些修改!

使用撤销命令:git reflog和git reset, 或者git checkout

发生了什么:git reflog是一个用来恢复项目历史记录的好办法。你可以通过git reflog恢复几乎任何已提交的内容。

你或许对git log命令比较熟悉,它能显示提交列表。git reflog与之类似,只不过git reflog显示的是HEAD变更次数的列表。

一些说明:

1. 只有HEAD会改变。当你切换分支时,用git commit提交变更时,或是用git
reset撤销提交时,HEAD都会改变。但当你用git checkout --时,
HEAD不会发生改变。(就像上文提到的情形,那些更改根本就没有提交,因此reflog就不能帮助我们进行恢复了)

2. git reflog不会永远存在。Git将会定期清理那些逗不可达(unreachable)地的对象。不要期望能够在reflog里找到数月前的提交记录。

3. reflog只是你个人的。你不能用你的reflog来恢复其他开发者未push的提交。

因此,怎样合理使用reflog来找回之前逗未完成地的提交呢看这要看你究竟要做什么:

1. 如果你想恢复项目历史到某次提交,那请使用git reset --hard

2. 如果你想在工作目录(working direcotry)中恢复某次提交中的一个或多个文件,并且不改变提交历史,那请使用git checkout--

3. 如果你想确切的回滚到某次提交,那么请使用git cherry-pick。

六、与分支有关的那些事 Once more, with branching

场景:你提交了一些变更,然后你意识到你正在master分支上,但你期望的是在feature分支上执行这些提交。

使用撤销命令:git branch feature, git reset --hard origin/master, 和 git checkout feature

发生了什么:你可能用的是git checkout -b来建立新的分支,这是创建和检出分支的便捷方法——但实际你并不想立刻切换分支。git
branch feature会建立一个叫feature的分支,这个分支指向你最近的提交,但是你还停留在master分支上。

git reset --hard将master回退至origin/master,并忽略所有新提交。别担心,那些提交都还保留在feature上。

最后,git checkout将分支切换到feature,这个分支原封不动的保留了你最近的所有工作。

七、事半功倍处理分支 Branch in time saves nine

场景:你基于master新建了一个feature分支,但是master分支远远落后与origin/master。现在master分支与
origin/master同步了,你期望此刻能在feature下立刻commit代码,并且不是在远远落后master的情况下。

使用撤销命令:git checkout feature和git rebase master

发生了什么:你也许已经敲了命令:git reset(但是没用--hard,有意在磁盘上保存这些提交内容),然后敲了git checkout -b,之后重新提交更改,但是那样的话,你将失去本地的提交记录。不过,一个更好的方法:

使用git rebase master可以做到一些事情:

1.首先,它定位你当前检出分支和master之间的共同祖先节点(common ancestor)。

2.然后,它将当前检出的分支重置到祖先节点(ancestor),并将后来所有的提交都暂存起来。

3.最后,它将当前检出分支推进至master末尾,同时在master最后一次提交之后,再次提交那些在暂存区的变更。
参考技术A 撤销一个“已公开”的改变
场景:你已经执行了 git push , 把你的修改发送到了 GitHub,现在你意识到这些 commit 的其中一个是有问题的,你需要撤销那一个 commit.
方法: git revert <SHA>
原理: git revert 会产生一个新的 commit,它和指定 SHA 对应的 commit 是相反的(或者说是反转的)。如果原先的 commit 是“物质”,新的 commit 就是“反物质” — 任何从原先的 commit 里删除的内容会在新的 commit 里被加回去,任何在原先的 commit 里加入的内容会在新的 commit 里被删除。
这是 Git 最安全、最基本的撤销场景,因为它并不会 改变 历史 — 所以你现在可以 git push 新的“反转” commit 来抵消你错误提交的 commit。

如何在git里撤销任何操作

git revert [commit] 可以撤销一个提交 git reset 可以撤销stage git reset --soft [commit] 可以撤销[commit]之后的提交但并不同步修改本地代码 git reset --hard [commit] 可以撤销[commit]之后的提交并同步撤销所有本地代码修改 参考技术A 一、撤销一个公共修改 Undo a "public" change

场景:你刚刚用git push将本地修改推送到了GitHub,这时你意识到在提交中有一个错误。你想撤销这次提交。

使用撤销命令:git revert本回答被提问者采纳

以上是关于如何在 Git 里撤销任何操作的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Git 里撤销(几乎)任何操作

如何在Git中撤销一切

转如何在Git中撤销一切

如何撤销Git操作?

如何撤销Git的一次分支合并操作

谈谈 git 撤销操作