Learn Version Control with Git
A step-by-step course for the complete beginner
Learn Version Control with Git featured image

撤销操作

撤销是 Git 提供的一个非常优秀的功能,它可以允许你撤消刚刚所做的操作。这就意味着你不必害怕搞砸你正在工作的项目: Git 一直会让你的项目处于一个安全的状态。

修改最后一次提交

无论你如何精心地推敲你的提交,你总是有可能出错的。比如忘记了把一个改动过的文件添加到提交中,或者是输入了错误的提交注释等等。当你认为提交有问题时,你都可以使用 “git commit” 命令,并附带上 “--amend” 参数,这个操作可以非常轻松地来修改你的_最后一次_提交。
如果你仅仅是想修改上一次的提交注释,你并不需要操作暂存区,简单地再次输入 “git commit --amend” 并附带上正确的注释就可以了:

$ git commit --amend -m "This is the correct message"

如果你想要添加更多的改动到上一次提交中,你可以像平常一样把这些新的改动添加到暂存区。然后再次使用 “--amend” 参数进行提交:

$ git add some/changed/file.ext
$ git commit --amend -m "commit message"
黄金法则

No. 5: 不要修改已经被发布的提交

“amend” 操作是一个非常强大的小帮手,这点你会很快地领会到。但是在你使用它的同时,你一定要考虑到以下一些方面:

  • (a) 你只能使用它来修正你的上一次提交。更早的提交是不能使用 “amend” 来进行操作的。
  • (b) 你不要对一个已经在远程仓库上被发布,或者说已经被共享的提交进行 “amend” 操作!这是因为 “amend” 操作实际上在后台打包了一个全新的提交来替换旧的提交。如果在这个远程仓库里仅仅只有你一个人在工作,那么这种操作是没有问题的。但是在团队工作中,如果开发团队的其他人员已经得到了你所发布的改动,并且在此基础之上进行了他自己的改动,再次整合一个被修改过的(amended)提交就会出现很多麻烦。

撤销本地改动

当改动还没有被提交之前,它们仍然被称之为 “本地” 改动。这些在你的工作目录(working directory)的修改还仍然在本地,它们属于未被提交的改动(uncommitted changes)。
有时候你对代码进行了一些修改,但是发现这些改动带来的问题比之前还要多。在这种情况下,你可能想要放弃你刚刚的改动,让代码恢复到你改动之前的版本,也就是上次提交之后的状态。

恢复一个文件到上次提交之后的状态,你可以使用 “git checkout” 命令:

$ git checkout -- file/to/restore.ext

我们已经知道了 “checkout” 命令主要是用来切换分支用的。但是你同样可以给这个命令附带上 “--” 参数,并加上用一个空格来分隔的文件路径。这个操作将撤销在特定文件上所有的未提交的改动。

如果你想要放弃你在工作副本(working copy)中的所有本地改动,并让你的本地副本恢复到上次提交之后的版本,你可以使用 “git reset” 命令:

$ git reset --hard HEAD

上面这个操作会通知 Git 将你本地副本上的所有文件替换到和 “HEAD” 分支一致的版本(也就是上次提交之后的版本状态)上,并放弃所有的本地改动。

注释

放弃本地未被提交的改动是不能被撤销的。这是因为这些改动还没有保存在你的仓库中。因此,Git 也就没有任何机会来挽回这种操作带来的改动。

请在你撤销本地改动时始终牢记这一点。

撤销已提交的改动

有时你也许想撤销某一个之前的提交。例如当你发现你的改动存在错误,或是整个改动就是错误的,又或者你的客户决定不需要这个改动了等等。

使用 “git revert” 命令可以撤销某个之前的提交。但是这个命令并不是删除那个提交,相反的,它是恢复那个提交的改动,这只是看起来像是撤销而已。这个操作实际上会自动产生一个新的提交。在提交中包括了你想要撤销的那个提交的所有反向改动。例如在原始提交中,你在某一个位置添加一些字符,那么这个恢复提交(reverting commit)就会把这些字符删除掉。

如果想要撤销已提交的改动,你只需要简单地给出这个提交的 commit hash:

$ git revert 2b504be
[master 364d412] Revert "Change headlines for about and imprint"
 2 files changed, 2 insertions(+), 2 deletions (-)

$ git log
commit 364d412a25ddce997ce76230598aaa7b9759f434
Author: Tobias Günther <support@learn-git.com>
Date: Tue Aug 6 10:23:57 2013 +0200

    Revert "Change headlines for about and imprint"

    This reverts commit 2b504bee4083a20e0ef1e037eea0bd913a4d56b6.

另外一种撤销提交的方法是使用 “git reset” 命令。这个操作不会自动产生一个新的提交,或是删除你要撤销的提交,它会重置你当前的 HEAD 分支到一个特定旧的版本,也被称作 “回滚(rolling back)” 到旧的版本:

$ git reset --hard 2be18d9

在执行了这个操作之后,你当前签出的分支将被重置为版本 2be18d9。在这个版本之后的一个或者多个版本将被真正的放弃,它们也不会显示在分支的历史记录中。

如果在这个命令上使用 “--hard” 参数则一定要小心,Git 将会丢弃所有你当前可能拥有的本地改动。整个项目将会被恢复成一个之前的旧版本。
如果你使用 “--keep” 参数来替代 “--hard” 参数,那么在 “回滚” 到的版本之后的所有改动将会转换成本地改动,并保留在你的工作目录中。

注释

和 “revert” 命令一样, “reset” 命令也不会删除任何已存在的提交。这些操作仅仅是做得好像这个提交不存在似的,并从历史记录中删除它们。无论如何,提交会被保存在 Git 的数据库中至少30天。因此,如果你发现你曾经不小心删除了一个仍然有用的提交,任何一个精通 Git 的同事都能为你恢复它们。

这两个命令(revert and reset)只是工作于当前 HEAD 分支上。因此在你执行这些操作之前,你必须要切换到正确的分支上去。

About Us

As the makers of Tower, the best Git client for Mac and Windows, we help over 100,000 users in companies like Apple, Google, Amazon, Twitter, and Ebay get the most out of Git.

Just like with Tower, our mission with this platform is to help people become better professionals.

That's why we provide our guides, videos, and cheat sheets (about version control with Git and lots of other topics) for free.