Git-reset

git reset

image-20230921115030651

在Git的版本管理系统中,代码的版本库由一个个提交commit构成,有以下几种情况,我们想要让代码库退回到某一次提交的状态:

  1. 想要保留所有的更改并准备进行下一个提交,但要合并多个提交。比如已经做了三个连续的提交,但现在意识到这三个提交实际上可以合并为一个。现在想回到三个提交前,然后重新进行一个包含所有更改的提交。
  2. 发现提交的更改中有些文件出现了错误,想要撤销这部分错误代码的更改。
  3. 想要完全丢弃自某次提交以来的所有更改。比如发现自某次提交以来的更改完全是错误的,或者你从另一个分支合并了错误的内容,想要彻底回到上一个已知的稳定状态。

这几种情况下我们可以用git reset来回退到对应的提交,git reset有三种模式,分别是--hard, --soft, --mixed,如果不加任何参数默认就是mixed选项。

三种命令的区别

假如我们的当前的版本库是这样的,我们历史上一共有6次提交,在最新的提交节点上,我们的版本库里有4个文件。现在我们在最新提交的基础上,又增加了两个文件,一个是staged.txt,用git add staged.txt把它加到Git的索引中,放到暂存区里。此时在Vscode中这个文件显示为"A",表示文件已被添加到暂存区,等待在下一个提交中被提交。另一个是untracked.txt,我们没有把它添加到Git索引中,它只是出现在这个目录里,因此Git目前无权管理这个文件,在Vscode中这个文件显示为"U"。

image-20230921114701081

执行git reset 126f271...,也就是--mixed,项目目录变成了下面这样,我们的工作目录保持不变,所有的文件都是和执行reset命令之前一样的,只不过这些文件的在Git中显示的状态发生了改变。因为之前Git显示的是当前工作目录相当于93ab45a节点的改变,而现在Git显示的是当前工作目录相对于126f271节点的改变。此时当前Git的项目中只剩下了两个提交节点,在126f271之后的提交节点记录全部清空,但是我们对这些代码的变动是全部保留的。同时,还发现这些新增的文件的状态都是"U",在默认模式下,自指定提交以来的所有更改将不会被暂存,而是保留在工作目录中为未暂存的更改。我们可以把它们全部暂存,这就恢复到原来的情况了。也可以手动暂存一部分,撤销自从126f271提交以后对于某些文件的更改。但是虽然我们对代码库的变动并不会消失,但是中间这些提交记录就没有了,相当于做了一次提交压缩。

image-20230921114833898

如果执行git reset --soft 126f271...,项目目录变成了下面这样,所有的文件都是一样的,只不过这时候自从126f271提交以来新增的文件状态变成了"A",这些更改被Git自动保存到暂存区了,没有加入到Git索引中的untracked.txt还是untracked,Git无权管理他们。所以git reset --soft就相当于git reset + git add files

image-20230921114750001

如果执行git reset --hard 126f271...,Git版本库里自从126f271提交以来的所有代码变动全部丢弃,但是同样,未加入到Git索引中的文件还是不会受到影响。

image-20230921114906123


所以总结一下,三种提交模式下,回退提交节点之后的所有提交记录都会消失。但是git reset --mixedgit reset --soft并不会影响自从回退提交节点以来的代码变动,这两个模式的区别就是--soft模式会自动把这些变动加入到暂存区里,这两个模式类似于把多个提交压缩成一个提交,但是我们可以对某些文件做一些变动,比如放弃某个文件自从指定提交以来的更改,来创建一个总的新提交,所以这两个命令是相对安全的。git reset --hard会完全丢弃自某次提交以来的所有更改,这是一个有风险的操作,在使用这个命令之前应该确保所有重要的工作都已经被备份或提交,以防止数据丢失。