内容纲要

🗂 | 查看 Git 专题可浏览更多内容


撤销「工作区」或「暂存区」

从暂存区中移除文件

使用 git rm --cached <文件名> 命令可将文件从暂存区与版本库中移除:

$ git rm --cached <文件名>

如果有一个文件想在工作区中保留,但从暂存区和版本库中移除,就可以使用该命令,这样该文件状态就会变成「未跟踪」。

将工作区中的修改恢复到最后一次的提交

如果想要将工作区中的修改恢复到版本库中的最后一次提交可以使用 git restore 或 git checkout 命令。

# 恢复当前目录中的所有文件
$ git restore .
# git restore <文件名>
$ git restore README.md

# 或 git checkout -- <文件名>,同样的也可以使用 .
$ git checkout -- README.md

取消暂存区中添加的修改

如果想要取消暂存,将添加到暂存区的修改回撤到工作区,那么可以:

$ git restore --staged .
# 或 git restore --staged <文件名> 来指定特定文件

# 或
$ git reset HEAD

如果添加暂存后工作区中的文件也进行了修改,那么从暂存区中回撤的修改会与添加暂存后工作区的修改共存。

所以如果不想要此时工作区的修改,可将工作区中的修改回撤到最后一次提交,然后再将暂存区的修改回撤工作区。

将工作区与暂存区都恢复到 HEAD

如果想要将工作区与暂存区都恢复到指定提交:

# 将工作区与暂存区所有文件恢复
$ git restore --source=HEAD --staged --worktree .

# 指定特定文件恢复
$ git restore --source=HEAD --staged --worktree <文件名>

其中的 HEAD 可以改成 Commit ID 以指定版本。

撤销「版本库」

修改最后一次提交

有的时候提交完了才发现少提交了某个文件,或是提交信息写错了,这时候再进行一次类似的提交就会让提交信息变得很难看。

这时候可以使用 --amend 选项,就相当于用一个新的提交来替换掉之前的最后一次。

⚠️ 注意,使用这个技巧的时候需要小心,因为修正会改变提交的 SHA-1 校验和。 它类似于一个小的「变基」,所以如果已经推送了最后一次提交就不要修正它。

使用方法很简单,你可以将需要补充提交的文件添加到暂存区,然后:

$ git commit --amend

这时候会进入到另一个界面,主要是修改提交信息,如果你从未使用过,简单来说是这样:

  1. 按 I 键进入「编辑模式」,以修改提交信息;
  2. 修改完后按 Ctrl + C 键然后输入::wq 保存并退出即可。

如果你的改动并不大,故而并不想修改提交信息,那么可以在添加需要补充的文件至暂存区后使用命令:

$ git commit --amend --no-edit

这样就会使用上一次的提交信息提交这一次的修改。

回滚上一次提交

如果在提交后发现这一次的提交并不好,前一版更好用,就可以使用 git revert 命令:

⚠️ 使用 git revert 命令需要保证你的工作区是干净的

$ git revert HEAD

同 git commit --amend 命令一样会需要填写提交信息,写明为什么需要这次回滚。

不保留历史回退到指定版本

举个例子:

$ git log --pretty=oneline
9a201ca2be395f656318d47a3c1f9573041d4e14 (HEAD -> master) 添加正文内容
a02c2108c97e8ea09f623404360940c528415ffb 添加文章标题
de4d93a0f98c0657188222bbc0053f6fdc63b4a7 添加说明文件
8cc6573cd56084378cd48dad4951cbdcd0e61b74 项目成立

假设这个说明文件的改动很不满意,想回到刚开始只是添加了一个空白的说明文件的那一版,而之后的两个版本都不要了,就可以使用 git reset 命令。

另外请注意,与使用 git commit --amend 命令时提到的一样:最好不要在你与他人共同协作的「公共分支」上使用 git reset。

因为当把提交推送到公共分支后,其他人很可能就已经拉取并使用,而此时如果你强制推送 reset 后的提交到远程仓库后,其他人拉取这个公共分支时他们的历史会消失一部分。

总而言之其实就是要注意一点:你的操作不能影响到他人。

git reset 有三个选项:

  • --mixed;
  • --soft;
  • --hard;

它们可以做到不同的效果:

回退版本库至指定历史版本

使用 --soft 回退版本时不会操作工作区和暂存区的内容:

# git reset --soft <commit-id>
$ git reset --soft de4d93a

另外除了 Commit ID 还可以有别的表达方式:

  • HEAD:最后一次提交;
  • HEAD^:上一次提交;
  • HEAD~n:上 n 次提交,如 git reset --soft HEAD~2 回到前一次提交;

回退暂存区与版本库至指定历史版本

--mixed 就是默认不带任何选项时的 git reset 命令的效果:

# git reset <commit-id>
$ git reset de4d93a # 等同 git reset --mixed de4d93a

这样工作区中的修改不变,但是暂存区和历史版本会回到指定的版本。

回退工作区、暂存区及版本库至指定历史版本

如果工作区和暂存区的东西都不想要了,只想与版本库一样回退到指定版本,就可以使用 --hard 选项,这也是最直接、最危险以及最常用的选项。

# git reset --hard <commit-id>
$ git reset --hard de4d93a

回退至未来版本

如果回到过去的版本后后悔了,这时使用 git log 已经看不到被删除的版本了怎么办?

可以使用 git reflog:

$ git reflog
ec1420c (HEAD -> master) [email protected]{0}: reset: moving to ec1420c
c0b3823 [email protected]{1}: commit: 修改正文内容
40f6729 [email protected]{2}: commit: 添加正文内容
ec1420c (HEAD -> master) [email protected]{3}: commit: 添加标题
6cdb131 [email protected]{4}: commit (initial): 添加说明文件

然后选择要回退到 ID

$ git reset --hard 40f6729

小结

  • 使用 git rm --cached <文件名> 命令可将文件从暂存区与版本库中移除,但在工作区中保留;
  • 使用 git restore <文件名> 命令可将工作区中修改的文件恢复到最后一次提交,在老版本 Git 中通常会使用另一个命令:git checkout -- <文件名>;
  • 使用 git restore --staged <文件名> 命令可将添加到暂存区的修改回撤到工作区中,在老版本 Git 中通常会使用另一个命令:git reset HEAD;
  • 使用 git restore --source=HEAD --staged --worktree <文件名> 命令可将工作区与暂存区都恢复到指定版本;
  • 使用 git commit --amend 会以一个新的提交替换掉当前最新的提交;
  • 使用 git revert HEAD 命令会回滚指定提交至前一次提交,并以一个新的提交提交至版本库;
  • 使用 git reset 命令可不保留历史重置到指定版本;
  • 当使用远程仓库与他人共同协作时,使用 git commit --amend、git reset等会对历史提交有所修改的命令时需要谨慎操作,因为这些操作可能会影响到其他人,应该确保不会影响到他人或与他人达成共识再进行操作。

延伸