git reset
命令用于将文件还原到历史版本。
前面有提到过,一个Git工程可以大致分为三部分:
现在我们用一个实例看看git reset命令如何对它们产生影响。
建立文件:
git add:
git commit:
edit:
git add:
git commit:
省略一些重复步骤后我们得到:
git reset
有三种模式:–soft、–mixed、–hard
假如我们进行git reset --soft HEAD~
这里HEAD~表示HEAD前一次的那个commit。也可以使用hash码(9e5e6a4等)来指示要返回的位置。
可以看到仅仅HEAD移动到了HEAD~(还包括HEAD指向的master),而Index(Staging area)、WD(Working Direcotry)没有变化。
而如果用–mixed:
–mixed是git reset
的默认选项,它在–soft的基础上,还会将index的内容也恢复到HEAD~
如果用–hard:
–hard在–mixed基础上还将工作目录下的内容也恢复到HEAD~。
当reset作用于具体的文件时会稍有不同。
它将不会把HEAD以及HEAD指向的分支移动回去。并且恢复范围仅限于指定的文件。
比如当我们用git add添加一个文件(file.txt v2)到index后:
可以使用
git reset --mixed HEAD file.txt
来完成反向的操作:
因为–mixed和HEAD都是默认参数,所以可以简单地使用
git reset file.txt
如果我们需要将某些文件回退到指定的版本,那么可以用
git reset eb43 -- file.txt
这里的”–”表示后面的是文件列表,它不一定是必须的。
但是这样只能更改index中的文件,而工作目录中的文件没有变化。如果想要让工作目录中的文件也恢复到指定的版本,需要使用–hard:
git reset --hard eb43 file.txt
Squash
前一章我们讲了用rebase来 rewriting history。用reset也能实现squash的部分需求,而且更简洁。
我们先使用git reset --soft HEAD~2
,让HEAD指针和master回到两个版本前的commit:
这时候的9e5e、38eb两个commits就相当于被抛弃了。
但是因为–soft不会改变index,所以index还是reset前的样子(即最新的版本),因此我们进行commit后:
就相当于把9e5e、38eb这两个commits合并成了一个新的commit(68ae)。
它的局限性是只能用于squash最近提交的commits,而不能像上一章里那样选择历史中任意的commits。
比较 reset 与 checkout
1. 不含文件时
git reset --hard <branch>
git checkout <branch>
以上两者很相似
checkout会确保woring-directory safe,确保不丢失文件的改动。
checkout不会移动HEAD指向的branch,只移动HEAD。
2. 含文件时
git reset --hard <commit> file
git checkout <commit> file
以上两者基本一样,都不会移动HEAD。
本系列暂时到此为止了。
感谢阅读。
End.