git-reset的效果是重置当时分支的HEAD指针,将HEAD指针指向特定的状况。

运用概述

git reset [<tree-ish>] [--] <pathspec>
git reset [--pathspec-from-file=<file> [--pathspec-file-nul]] [<tree-ish>]
git reset (--patch | -p) [<tree-ish>] [--] [<pathspec>]
git reset [--soft | --mixed [-N] | --hard | --merge | --keep] [<commit>]

前三行reset指令的效果是将指定的<tree-ish>内容作为参考依据,然后把内容拷贝到方针的缓存区中。

<tree-ish>便是像树相同的东西,git中是有很多都能组成树的,比方commit树或者tag树。

最后一行reset指令的效果是将当时分支的HEAD指针指向<commit>,一起能够运用多种可选项来操控是否修正缓存区或作业区。

在以上一切的指令方式中,都是把<tree-ish>或<commit>默认作为HEAD指针。

git reset [<tree-ish>] [–] <pathspec>

该方法有如下规矩:

  1. 会将与<pathspec>相匹配的途径资源在缓存区中重置成<tree-ish>中的状况。不了解<pathspec>是什么?
  2. 被提交到缓存区中的改动会被复原到作业区中。

举个

假定项目中有一个coffee.txt文件,文件内容如下:

卡布奇诺纳瑞冰-19.9¥
规范美式-14.9¥
香草拿铁-19.9¥
生椰爱摩卡-19.9¥
...

咱们运用git的tag指令将当时的版别标记成v1.0.0(这儿运用tag标签作为)。

随后修正coffee.txt文件,修正内容如下:

卡布奇诺纳瑞冰-19.9--> 卡布奇诺纳瑞冰-14.9¥
规范美式-14.9--> 规范美式-9.9¥
香草拿铁-19.9--> 香草拿铁-14.9¥
生椰爱摩卡-19.9--> 生椰爱摩卡-14.9¥
...

改变了coffee.txt文件后,再运用git tag打上了v1.0.1标记。

假定此刻想将coffee.txt文件复原成v1.0.0版别中的文件,就能够运用git reset指令并指定为v1.0.0,操作如下:

git reset v1.0.0 coffee.txt

运用VSCode查看缓存区的文件变化:

Git命令中的reset是什么?
能够看到图中的右侧的代码改动对比,此刻缓存区中的coffee.txt文件现已成功被重置成v1.0.0版别中文件的状况(规矩1)。而且此刻v1.0.1现已提交到缓存区中的变化也被复原到了作业树中(规矩2)。
Git命令中的reset是什么?

能够看出git reset指令与git add指令效果相反,一个是将指定的资源添加到缓存区,另一个则是从缓存区中移除。而且这个指令与git restore [–source=<tree-ish>] –staged <pathspec>具有相同的效果,对restore感兴趣的能够看看这篇文章。

上面说过了,在运用reset指令后,此刻缓存区中文件内容是v1.0.0的,能够合作git restore指令将缓存区中的内容复原到作业区中然后进行修正:

git restore coffee.txt --staged

也能够根据需求挑选复原作业区的内容:

git restore coffee.txt --worktree

git reset[–pathspec-from-file=<file> [–pathspec-file-nul]] [<tree-ish>]

在上面的比如中每次进行reset和restore的都是想同的<pathspec>途径(coffee.txt)。由于该文件途径比较简略,所以每次操作都比较便利输入。但是在一些情况下,或许需求reset比较复杂的<pathspec>途径,比方项目目录层次较深,那么很或许需求输入一长串的<pathspec>途径,这样每次进行操作就会很麻烦,所以git供给了一个–pathspec-from-file选项,让咱们能够直接指定一个文件,这个文件就包含了或许需求重复运用的<pathspec>途径。这儿有更具体的用法。

该文件每一行都是一个<pathspec>,假定有多个<pathspec>运用换行符作为分隔。当然也能够运用–pathspec-file-nul让NUL作为每一个<pathspec>的分隔符。

git reset (–patch | -p) [<tree-ish>] [–] [<pathspec>]

交互式的挑选<tree-ish>与缓存区之间的差异而发生的hunks。这些被挑选的hunks将会撤销缓存区中的发生的修正。这儿有更具体的–patch选项用法。

git reset [<mode>] [<commit>]

该指令会把当时分支的HEAD指针指向某个<commit>,然后由<mode>决议是否一起更新缓存区或作业区的内容。<mode>默认值是–mixed,且必须是以下几种:

–soft

作业区和缓存区中的文件变化都将被保存,然后将HEAD指针指向<commit>。

还是以咖啡菜单为,假定第一次commit到仓库中的文件内容如下:

卡布奇诺纳瑞冰-19.9¥
规范美式-14.9¥
香草拿铁-19.9¥
生椰爱摩卡-19.9¥
...

然后做第二次commit操作,删去规范美式,增加生椰拿铁:

卡布奇诺纳瑞冰-19.9¥
-规范美式-14.9¥
+生椰拿铁-19.9¥
香草拿铁-19.9¥
生椰爱摩卡-19.9¥
...

在commit后,修正卡布奇诺纳瑞冰的价格,添加到缓存区。再修正香草拿铁的价格,保存在作业区:

-卡布奇诺纳瑞冰-19.9¥
+卡布奇诺纳瑞冰-14.9¥ // 添加到缓存区中
生椰拿铁-19.9¥
-香草拿铁-19.9¥
+香草拿铁-14.9¥ // 保存在作业区
生椰爱摩卡-19.9¥
...

此刻我想保存作业区和缓存区做的改动,而且将HEAD指针指向第一次commit。这时能够运用–soft选项实现:

git reset HEAD^ --soft // 这儿运用HEAD^表明上一个commit,相同也能够运用hash id

运用git log查看当时HEAD指针确实现已指向第一个commit,第二个commit被扔掉了:

Git命令中的reset是什么?
一起一切的作业区和缓存区的改动都被保存了:
Git命令中的reset是什么?

当时只要两次的commit,是为了便利演示–soft选项的效果。但是在实践开发中,咱们或许会commit多次,尤其是在测验环境改几个BUG就要提交到发布平台,这样会导致很多无意义的commit。这时候就能够运用–soft选项,重置HEAD到指定的<commit>只保存一到两个重要的commit。

–mixed

重置缓存区,但是会保存作业区的内容,这是<mode>的默认值。

相信有了解了–soft效果后,了解–mixed不难,上面比如中假定是运用–mixed那么最终成果如下:

Git命令中的reset是什么?
该选项会重置缓存区,但是保存作业区的改动,并将当时指针指向<commit>。

–hard

重置缓存区和作业区中的一切的变化,而且将指针指向<commit>。

–hard愈加的简略粗犷,咱们将–soft比如改为–hard来查看成果:

Git命令中的reset是什么?
如图所示,作业区和缓存区的内容都被重置了。不止是如此,就连Untracked文件相同也会被删去。

–merge

该选项的效果,看字面意思就知道大概便是把当时分支和指定的<commit>进行兼并,规矩如下:

  1. 重置缓存区,任何现已添加到缓存区的改动都将被扔掉
  2. 假定<commit>和HEAD之间有文件存在不同(这个不同指的是文件被删去或者新增),那么将会把该文件重置成<commit>中的状况(新增或删去)。
  3. 假定<commit>和HEAD之间有文件存在不同(这个不同是指文件内容的不同),且此刻作业区也存在未提交的改动,那么本次的reset将会被停止。
  4. 假定一个文件在<commit>和HEAD中完全相同,但是它的作业区存与缓存区存在着不同(也便是改动未提交到缓存区),那么该文件在作业区的改动在重置之后就会被保存。

咱们举个比如来验证一下以上列出的规矩,假定此刻的咖啡店项目有如下的几个commit。

第一个commit和文件内容如下:

Git命令中的reset是什么?
第一个commit中只要一个coffee.txt菜单文件,此刻假定咖啡店引进了新品种开始卖果汁,那么就需求新增果汁菜单文件fruits.txt,所以就有了第二个commit:
Git命令中的reset是什么?
此刻咱们做一些改动来验证1,2,4这几点的规矩,改动后的文件如下:
Git命令中的reset是什么?
首要修正coffee.txt文件,新增一款生椰拿铁咖啡,保存在作业区中。然后增加咖啡豆菜单文件beans.txt,将其添加到缓存区中。

假定因需求变化,咖啡豆菜单文件在缓存区中需求清除,果汁菜单文件需求删去,只要咖啡菜单中新增的生椰拿铁的改动需求保存。那么就能够运用git reset –merge将HEAD和commit-1进行兼并,操作如下:

git reset --merge HEAD^

成果如下:

Git命令中的reset是什么?
执行指令reset指令发生了如下效果:

  • 将当时HEAD指针指向了commit-1
  • 将缓存区中的beans.txt文件扔掉(规矩1)
  • HEAD(commit-2)和commit-1中的fruits.txt文件存在不同(commit-2中新增fruits.txt),所以会将fruits.txt删去(规矩2)
  • coffee.txt文件新增生椰拿铁的改动被保存在作业区中(规矩4)

再来验证一下第3点规矩,假定咖啡店项目此刻第一个commit如下:

Git命令中的reset是什么?
接下去相同新增水果茶菜单,然后再修正coffee.txt文件,第二个commit如下:
Git命令中的reset是什么?
然后在HEAD中再修正coffee.txt文件,删去掉规范美式品种:
Git命令中的reset是什么?
此刻,假定咱们再运用git reset –merge HEAD^就无法再进行重置,该操作会被git停止(规矩3)。而且操控台会进行报错提示:
Git命令中的reset是什么?

–keep

该选参的效果和–merge类似,仅有的差异便是缓存区中被重置的会被保存在作业区中。

结构如下第一个commit:

Git命令中的reset是什么?
改造第二个commit:
Git命令中的reset是什么?
在HEAD中进行修正
Git命令中的reset是什么?
运用git reset –keep指令:
Git命令中的reset是什么?
从成果上来看,只要fruits.txt文件被删去了,beans.txt文件被重置回了作业区中。coffee.txt文件的改动也被保存了。

–[no-]recurse-submodules

运用该选项能够操控是否递归的重置submdoule。假定想要更具体了解,查看这篇文章。

总结

git-reset指令的效果便是重置缓存区和作业区,一起它也供给多个选项来做更具体的操控,使得该指令愈加灵敏多变。git-reset指令在咱们的作业中经常运用,因而熟练掌握该指令是非常重要的。