git reset 学习

231 阅读10分钟

git reset命令

git reset 命令用于回退版本,可以指定退回某一次提交的版本。 git reset 命令语法格式如下:

git reset [--soft | --mixed | --hard] [HEAD]

对于git reset命令,git reset不仅能向后回退,也能够向前回退。我们煮个栗子:

bcb7721 (HEAD -> master) HEAD@{0}: commit: v9
e33516b HEAD@{1}: reset: moving to e33516b
2e09bc2 HEAD@{2}: commit: v8
9b2cfc4 HEAD@{3}: reset: moving to 9b2cfc4
e33516b HEAD@{4}: reset: moving to e33516b
e33516b HEAD@{5}: commit: v7
9b2cfc4 HEAD@{6}: reset: moving to 9b2cfc4
12d1d8c HEAD@{7}: commit: v6
9b2cfc4 HEAD@{8}: commit: v5
4372c5f HEAD@{9}: commit: feat: v4
a132213 HEAD@{10}: reset: moving to a13221361e8a7a84cb7ba4f7a3b114f8fdf3e1d3
bc662a6 HEAD@{11}: commit: test3
a132213 HEAD@{12}: reset: moving to a13221361e8a7a84cb7ba4f7a3b114f8fdf3e1d3
a132213 HEAD@{13}: reset: moving to a132213
6588fec HEAD@{14}: reset: moving to 6588fec
a132213 HEAD@{15}: reset: moving to a132213
6588fec HEAD@{16}: reset: moving to 6588fec
a132213 HEAD@{17}: commit: feat:添加app.txt文件
6588fec HEAD@{18}: commit (initial): feat: 这是原始版本

当前HEAD指向的是v9,当然可以通过git reset回退到v8然后再回退到v9当中。

前期知识铺垫 之 暂存区

所谓的暂存区,它存放的是当前这个项目中所有的文件的快照,只不过这些文件都是最新的版本的快照。它是一个树对象,呈现一个树形关系

100644 df3cc94c7147f3452b65d2e8d0db3e651cf7ab80 0       app.txt
100644 9a8b27268ca562c0e3f6ea87ac3a012f66bc501e 0       src/index.txt
100644 8124b75804539996072e60fbe4a57a48125d954f 0       test1.txt

我们在项目中新加一个app2.txt文件,然后放到暂存区,此时暂存区内容为:

100644 07f9e6e97a682c23f9c5d45afacfc9bc8b64c517 0       app.txt
100644 546b40eca05f826348b2e29b8d34036c7552224a 0       app2.txt
100644 9a8b27268ca562c0e3f6ea87ac3a012f66bc501e 0       src/index.txt
100644 8124b75804539996072e60fbe4a57a48125d954f 0       test1.txt

如果我们更改app.txt中的内容,那么此时暂存区中的内容如下:

100644 4ab52847b73171189919588850dddd73cf83259b 0       app.txt
100644 546b40eca05f826348b2e29b8d34036c7552224a 0       app2.txt
100644 9a8b27268ca562c0e3f6ea87ac3a012f66bc501e 0       src/index.txt
100644 8124b75804539996072e60fbe4a57a48125d954f 0       test1.txt

我们发现app.txt在暂存区中的哈希值变化了。因为暂存区只存储当前项目中最新版本的文件的快照,所以才会出现这种情况。 当使用commit进行提交的时候,此时提交对象就是这个树形结构的一个包装。提交之后暂存区不会被清除。还是存储的是当前项目中所有文件最新的快照。 我们在vsCode当中看到的那个git图标并不是暂存区,它只是一个对比显示的区域。也就是说当前你的暂存区中和工作区中有哪些不一样,通过diff暂存区文件和工作区文件给你显示出来。 vscode中那个图标有两个显示,分别是:更改暂存更改。所谓的更改就是git会将工作区文件内容和暂存区文件内容进行diff,然后将不同展示出来。 如果我们修改了工作区文件的内容,然后通过git add ./将这个文件的快照放入暂存区,那么此时就会出现暂存更改。暂存更改指的是当前暂存区的所有文件快照和上一次提交后暂存区中所有文件快照进行对比,看看哪些是不同的。 这里注意一下,其实暂存区是有提交节点的。什么意思呢?我们煮个栗子。 假如我们在工作区对一些文件做了一些改动,此时git add到暂存区中,然后通过git commit -m "v7"提交了。此时暂存区中的所有文件快照会被记录下来。然后我们又改了一些文件,然后通过add放到了暂存区中,然后通过git commit -m "v8", 此时会记录v8版本当前的暂存区文件快照。现在我们的暂存区内容是v8版本的,当进行版本回退,回退到v7的时候,此时暂存区中的文件快照也会回到v7提交后的那个版本(前提是当前的回退会把暂存区一起回退了,有的参数不会回退暂存区,例如--soft)。

--hard

通过使用--hard可以用来回退工作区,暂存区,版本库。什么意思呢?我们煮个栗子: 假如我们当前处于v8版本,然后我们在该版本的index.txt中追加一个666字符串,然后提交:

git add ./
git commit -m "v9"

此时HEAD指向v9。此时的工作区的内容其实就是v9版本的内容,即index.txt文件中多了一个666字符串。此时的暂存区是最新的文件快照,为了方便我们将此时的暂存区内容标记为v9版本。当前HEAD指向v9的提交对象。当我们使用:

git reset --hard  [v8的哈希值]

此时git就会将版本回退到v8版本。当回退后,版本库中HEAD指向是v8commit对象(版本库回退)。此时的暂存区的内容也回到了v8版本提交后所对应的暂存区的内容(暂存区回退)。同时我们的工作区(即项目目录)也会发生变化,他会回到我们v8版本提交后对应的工作目录(工作区回退)。

通过上述的表述,我们发现--hard它的回退是包含三区的,因此我们使用该参数的时候应该小心。但也不必担心找不到v9版本的代码,只要再通过:

git reset --hard [v9的哈希值]

此时三区的代码又回到了v9的版本。

非跟踪状态的版本回退

这里啰嗦几句,上面使用--hard进行版本回退的栗子主要是对已经完成提交后的一个版本回退。假如当前HEAD指向v9,并且完成提交。然后我们修改某一个文件的内容,并不通过add放到暂存区,此时使用:

git reset --hard [v8的哈希值]

此时我们的工作区回退到v8版本,并且不会将我们的修改也带过去,v8时的工作区怎么样,回退后的工作区就怎么样,回退后的工作区不会包含一点我们回退前操作的内容。

跟踪状态的版本回退

和非跟踪状态的版本回退一样,因为--hard它回退也包含了暂存区,就算我们通过add将更改放到暂存区让暂存区更新了文件快照,但是因为--hard回退暂存区,因此回退到v8之后暂存区仍然是v8版本的暂存区,没有我们添加的文件的快照。毕竟是包含暂存区回退。

--mixed(默认值)

通过使用--mixed可以用来回退暂存区,版本库。什么意思呢?其实这个也很好理解。有了上面对--hard的解释,那么此时理解起--mixed就更加的简单了。

当我们使用命令:

git reset [v8的哈希值]

因为--mxied是一个默认值,因此可以省略不写。此时HEAD会指向v8commit对象(版本回退)。此时我们的暂存区会回退到v8版本时的暂存区(暂存区回退)。但是此时的工作区没有回退,仍然是v9版本的工作区

非跟踪状态的版本回退

假如当前HEAD指向v9,并且完成提交。然后我们修改某一个文件的内容,并不通过add放到暂存区,此时使用:

git reset --mixed [v8的哈希值]

此时commit对象和暂存区都回退了。但是因为不会回退工作区,因此此时的工作区仍然保持v9版本状态,并且保持你修改的状态。说白了就是git没有动你的工作区,该是什么样就是什么样。

跟踪状态的版本回退

假如当前HEAD指向v9,并且完成提交。然后我们修改某一个文件的内容,并通过add放到暂存区,此时使用:

git reset --mixed [v8的哈希值]

此时HEAD会指向v8commit对象(版本回退)。因为我们将最新的修改的文件的快照放到了暂存区,因此暂存区和v9的暂存区有区别,但是这仍然不影响暂存区的回退。执行完命令之后的暂存区是v8版本时(v8版本提交后对应的暂存区)的暂存区。而工作区git并没有动,因此仍然是v9版本并包含最新的更改。

--soft

通过使用--soft只能用来回退版本库。当我们使用命令:

git reset --soft [v8的哈希值]

此时HEAD的指针指向v8commit记录(版本回退)。但是此时的暂存区仍是最新的暂存区,即v9版本的暂存区。工作区也是最新版本的工作区,即v9版本的工作区。也就是说git没有动我们的工作区和暂存区。

这个操作有点类似于我们处于v8版本,然后重新做v9版本的修改和放到暂存区,并没有提交。

如果我们使用git status命令,我们会发现会提示有已跟踪但未提交的提示。其实它有点像动作回退,即回退到执行git commit -m "v9"这个指令之前。当然这只是动作像,并不是说这个参数就是为了这个的。

非跟踪状态的版本回退

当我们在工作区修改了内容,并没有把修改放到暂存区中,此时执行:

git reset --soft [v8的哈希值]

此时HEAD会指向v8commit对象(版本回退)。但是此时工作区和暂存区都是最新的。暂存区是v9的暂存区,而工作区是v9的工作区并包含最新的更改。也就是说git没有动我们的工作区和暂存区。

跟踪状态的版本回退

当我们修改了工作区的文件并把它放到暂存区中,此时执行:

git reset --soft [v8的哈希值]

此时HEAD会指向v8commit对象(版本回退)。但是此时工作区和暂存区都是最新的。暂存区是v9的暂存区并包含最新更改,而工作区是v9的工作区并包含最新的更改。也就是说git没有动我们的工作区和暂存区。