reset
命令主要用来根据你传递给动作的参数来执行撤销操作。
上图展示的是一个有三次提交记录的仓库,当我们执行 reset
指令后,该仓库的变化如下:
-
第一步:移动 HEAD 指针指向的的分支,也就是改变将当前分支指向的 commit(与
checkout
做的不一样)。此时 HEAD 处于 v2 版本,但是暂存区和工作区依然是处于 v3 版本。 - 第二步:用 HEAD 指向的当前快照的内容来更新暂存区(索引),即将版本 v2 的内容覆盖暂存区,此时只有工作区是版本 v3 的内容。
- 第三步:使工作区看起来像暂存区(索引)。
1. 取消暂存的文件
当你修改了两个文件并且想要将它们分别提交,但是却意外地将它们两个都暂存了:
$ 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
这时就可以使用 reset
指令取消暂存其中的一个:
$ git reset HEAD CONTRIBUTING.md
Unstaged changes after reset:
M CONTRIBUTING.md
上述的指令是通过指定文件路径来重置的,这个操作会跳过第一步移动 HEAD 分支的指向,直接进行第二步将暂存区(索引)看起来像 HEAD。这个操作其实跟 git add
是相反的。
注意:上述的 git reset HEAD CONTRIBUTING.md
指令其实是 git reset --mixed HEAD CONTRIBUTING.md
的简写形式。
2. 重置
本文开头讲述的例子即是 reset
的重置功能,具体语法其实是这样的:
git reset [--soft | --mixed [-N] | --hard ] [<commit>]
通过传递不同的选项来决定应该重置到哪一步:
- 若指定了
--soft
则在第一步移动 HEAD 分支的指向就停止。 - 若指定了
--mixed
(默认值)则走到第二步使暂存区(索引)看起来像 HEAD 停止。 - 若指定了
--hard
则走到第三步使工作目录看起来像暂存区停止。
注意:慎用 --hard
标记,一旦你的工作区的修改内容还没有提交就使用了 git reset --hard
,那么你的心血是无法恢复的。
3. 压缩提交
继续使用上述的仓库,假如你想将后面的两次提交合并成一次提交,也可以通过 reset
指令来完成。
首先执行 git reset --soft HEAD~2
,则 HEAD 分支指向了版本 v1,即版本 v2 和版本 v3 的提交也没有了:
别忘记了此时的暂存区(索引)和工作区依然是版本 v3 的内容,所以最后只需要执行 git commit
指令就完成了多次提交的合并了。
4. reset 与 checkout 的区别
二者的区别在于 reset
会移动 HEAD 分支的指向,而 checkout
只会移动 HEAD 自身来指向另一个分支。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。