要理解 git reset 需要先了解其在版本管理中用到的三个重要概念,通常被称为三棵“树”,“树” 的实际意思是 “文件的集合”,而不是指特定的数据结构。这三棵树即:

含义
HEAD 上一次提交的快照,下一次提交的父结点
Index 预期的下一次提交的快照
Working Directory 工作目录

HEAD 是当前分支引用的指针,它总是指向该分支上的最后一次提交。 这表示 HEAD 将是下一次提交的父结点。 通常,理解 HEAD 的最简方式,就是将它看做 你的上一次提交 的快照。

Index 即索引,通常也被称之为暂存区,是 预期的下一次提交。 当运行 git add 时添加的内容都存储在暂存区中。

工作目录即包含 git 实际管理的文件的目录,我们在该目录下增、删、改内容然后提交给 git 管理,所以称之为工作目录。

Git 的工作流程主要就是通过操纵这三棵树来以更加连续的状态记录项目的快照。

Git 三棵树

git reset 命令使用格式:

git reset [--soft | --mixed [-N] | --hard] [-q] [<commit>]

reset 命令以一种简单可预见的方式直接操纵三棵树,它做了三个基本操作:移动 HAED,重置索引,重置工作目录。实际上 reset 是以特定的顺序来重写三棵树,并在指定相应选项时停止:

  • 1、移动 HEAD 分支的指向 (若指定了 --soft,则到此停止)
  • 2、使索引看起来像 HEAD (若未指定 --hard,则到此停止)
  • 3、使工作目录看起来像索引

可见 reset 涉及到三个重要的参数 softmixedhard无论指定那个参数,reset 都会移动 HEAD 的位置。其中 mixed 参数是默认行为,也就是 git reset --mixedgit reset 等价。

可以这样简单的来理解着三个参数:

  • 1、 git reset --soft 只移动 HEAD 到指定的 commit,但保留原先暂存区和工作目录的内容,同时会将指定 commit 之后提交的内容设置到暂存区中
  • 2、 git reset --mixed 移动 HEAD 到指定的 commit,同时重置暂存区为指定 commit 的状态(将内容从 HEAD 复制到暂存区中),但保留原先的工作目录,同时将添加暂存区的修改撤销到工作目录中。该选项为默认选项,可以省略
  • 3、 git reset --hard 移动 HEAD,同时重置暂存区和工作目录到指定 commit。也即是将三个树都重置为指定的 commit。

这三个参数中,只有 soft 和 mixed 是安全的,hard 会令工作丢失,使用时应该小心。

reset 命令还可以作用域路径。若指定了一个路径,reset 将会跳过第 1 步(移动 HEAD),并且将作用范围限定为指定的文件或文件集合。不过索引和工作目录 可以部分更新,所以重置会继续进行第 2、3 步。例如运行 git reset file.txt(这其实是 git reset --mixed HEAD file.txt 的简写形式,因为既没有指定一个提交的 SHA-1 或分支,也没有指定 --soft 或 --hard),它会跳过移动 HEAD 的指向,但让索引看起来像 HEAD(到此处停止)。

git reset --mixed取消暂存文件 效果。实际上它与 git add 所做的操作相反,可以用该命令撤销 add 到暂存区的修改到工作区。

git reset --soft <commit> 可以用于压缩最近的提交,用该命令将 HEAD 移动到一个旧一点的提交上(即你想要保留的第一个提交),然后然后再 commit 就可以将多个最近的提交压缩为一个(当然,该功能也可以用 git rebase -i 实现)。