章节 ▾ 第二版

2.4 Git 基础 - 撤消操作

撤消操作

在任何阶段,你可能需要撤消某些操作。在这里,我们将回顾一些用于撤消你所做更改的基本工具。要小心,因为你并非总是能够撤消这些撤消操作。这是 Git 中少数几个如果你操作不当可能会丢失部分工作的领域之一。

常见的撤消操作之一发生在你提交过早,可能忘记添加某些文件,或者搞砸了提交消息。如果你想重做该提交,进行你忘记的额外更改,将它们暂存,然后再次使用 --amend 选项提交

$ git commit --amend

此命令将你的暂存区用于提交。如果你自上次提交以来没有做任何更改(例如,你在上次提交后立即运行此命令),那么你的快照将完全相同,你所更改的只是你的提交消息。

同样的提交消息编辑器会启动,但它已经包含了你上次提交的消息。你可以像往常一样编辑消息,但它会覆盖你之前的提交。

例如,如果你提交后意识到忘记暂存一个文件中的更改,而你希望将这些更改添加到此次提交中,你可以这样做

$ git commit -m 'Initial commit'
$ git add forgotten_file
$ git commit --amend

你最终会得到一个单独的提交——第二个提交替换了第一个提交的结果。

注意

重要的是要理解,当你修改上次提交时,你并不是在修复它,而是完全用一个新的、改进的提交来“替换”它,这个新提交将旧提交推开并取而代之。实际上,就好像之前的提交从未发生过,它不会显示在你的仓库历史中。

修改提交的明显价值在于对上次提交进行微小改进,而不会用“哎呀,忘记添加文件”或“糟了,修复上次提交中的一个错字”之类的提交消息弄乱你的仓库历史。

注意

只修改那些仍是本地的、尚未被推送的提交。修改之前已推送的提交并强制推送分支会给你的协作者带来问题。有关当你这样做时会发生什么以及如果你处于接收端如何恢复的更多信息,请阅读变基的危险

取消暂存已暂存的文件

接下来的两节将演示如何处理你的暂存区和工作目录的更改。好消息是,你用来确定这两个区域状态的命令也会提醒你如何撤消对它们的更改。例如,假设你更改了两个文件并希望将它们作为两个单独的更改提交,但你意外地输入了 git add * 并将它们都暂存了。你如何取消暂存其中一个呢?git status 命令会提醒你

$ git add *
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    renamed:    README.md -> README
    modified:   CONTRIBUTING.md

在“要提交的更改”文本下方,它提示使用 git reset HEAD <file>…​ 来取消暂存。那么,我们按照这个建议来取消暂存 CONTRIBUTING.md 文件

$ git reset HEAD CONTRIBUTING.md
Unstaged changes after reset:
M	CONTRIBUTING.md
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    renamed:    README.md -> README

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   CONTRIBUTING.md

CONTRIBUTING.md 文件已修改但再次取消暂存。

注意

git reset 确实是一个危险的命令,特别是如果你提供了 --hard 标志。然而,在上述情况下,你工作目录中的文件没有被触及,所以它是相对安全的。

目前,关于 git reset 命令你只需要知道这个神奇的用法。我们将在揭秘 Reset中更详细地探讨 reset 的作用以及如何掌握它来做一些非常有趣的事情。

取消修改已修改的文件

如果你意识到不想保留对 CONTRIBUTING.md 文件的更改怎么办?如何轻松地取消修改它——将其恢复到你上次提交时(或最初克隆时,或无论你如何将其放入工作目录时)的样子?幸运的是,git status 也会告诉你如何做到这一点。在上次的输出示例中,未暂存区域看起来是这样的

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   CONTRIBUTING.md

它非常明确地告诉你如何放弃你所做的更改。让我们按照它说的做

$ git checkout -- CONTRIBUTING.md
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    renamed:    README.md -> README

你可以看到更改已被还原。

重要提示

重要的是要理解 git checkout -- <file> 是一个危险的命令。你对该文件所做的任何本地更改都将消失——Git 只是用上次暂存或提交的版本替换了该文件。除非你完全确定不想要那些未保存的本地更改,否则绝不要使用此命令。

如果你想保留对该文件所做的更改但现在仍需要将其移开,我们将在Git 分支中介绍储藏和分支;这些通常是更好的方法。

请记住,Git 中任何“已提交”的内容几乎总是可以恢复的。即使是已删除分支上的提交或被 --amend 提交覆盖的提交也可以恢复(请参阅数据恢复了解数据恢复)。但是,任何你丢失的、从未提交的内容,很可能再也找不回来了。

使用 git restore 撤消操作

Git 2.23.0 版本引入了一个新命令:git restore。它基本上是我们刚才介绍的 git reset 的一个替代品。从 Git 2.23.0 版本开始,Git 将在许多撤消操作中使用 git restore 而不是 git reset

让我们重新回顾我们的步骤,并使用 git restore 而不是 git reset 来撤消操作。

使用 git restore 取消暂存已暂存的文件

接下来的两节将演示如何使用 git restore 处理你的暂存区和工作目录的更改。好消息是,你用来确定这两个区域状态的命令也会提醒你如何撤消对它们的更改。例如,假设你更改了两个文件并希望将它们作为两个单独的更改提交,但你意外地输入了 git add * 并将它们都暂存了。你如何取消暂存其中一个呢?git status 命令会提醒你

$ git add *
$ git status
On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
	modified:   CONTRIBUTING.md
	renamed:    README.md -> README

在“要提交的更改”文本下方,它提示使用 git restore --staged <file>…​ 来取消暂存。那么,我们按照这个建议来取消暂存 CONTRIBUTING.md 文件

$ git restore --staged CONTRIBUTING.md
$ git status
On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
	renamed:    README.md -> README

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
	modified:   CONTRIBUTING.md

CONTRIBUTING.md 文件已修改但再次取消暂存。

使用 git restore 取消修改已修改的文件

如果你意识到不想保留对 CONTRIBUTING.md 文件的更改怎么办?如何轻松地取消修改它——将其恢复到你上次提交时(或最初克隆时,或无论你如何将其放入工作目录时)的样子?幸运的是,git status 也会告诉你如何做到这一点。在上次的输出示例中,未暂存区域看起来是这样的

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
	modified:   CONTRIBUTING.md

它非常明确地告诉你如何放弃你所做的更改。让我们按照它说的做

$ git restore CONTRIBUTING.md
$ git status
On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
	renamed:    README.md -> README
重要提示

重要的是要理解 git restore <file> 是一个危险的命令。你对该文件所做的任何本地更改都将消失——Git 只是用上次暂存或提交的版本替换了该文件。除非你完全确定不想要那些未保存的本地更改,否则绝不要使用此命令。

scroll-to-top