【git 命令】git reset
git的基本提交流程
git的基本流程,如图所示:
- Working Tree:本地的工作区。
- Index/Stage 暂存区域,和git stash命令暂存的地方不一样,使用git add xx,就可以将xx添加近Stage里面。
- Repository 本地仓库区,即使用git commit提交后的结果。
简单叙述流程:
1. 刚开始 working tree 、 index 与 repository(HEAD)里面的內容都是一致的。
2.当git管理的文件夹里面的内容出现改变后,此時 working tree 的內容就会跟 index 及 repository(HEAD)的不一致,而Git知道是哪些文件(Tracked File)被改动过,直接将文件状态设置为 modified (Unstaged files)。
3.当执行 git add 后,会将这些改变的文件內容加入 index 中 (Staged files),所以此时working tree跟index的內容是一致的,但他们与repository(HEAD)內容不一致。
4.执行 git commit 后,將Git索引中所有改变的文件內容提交至 Repository 中,建立出新的 commit 节点(HEAD)后, working tree 、 index 與与repository(HEAD)区域的内容 又会保持一致。
git reset --hard
作用:重置stage区和工作目录。
reset --hard 会在重置 HEAD 和branch的同时,重置stage区和工作区里面的内容。当你在 reset 后面加了 --hard 参数时,你的stage区和工作区的内容会被完全重置为和HEAD的新位置相同的内容。换句话说,就是你的没有commit的修改会被全部擦掉。
例如:你在上次 commit 之后又对文件做了一些改动:对test01.txt进行修改,执行了git add命令, 对test02.txt只进行修改,没做其他操作。执行命令 git reset --hard HEAD^ ,结果工作区、暂存区、版本仓库和上一次commit提交之后的状态完全一致。
现在我需要版本回退,想把当前的版本回退到上一个版本,可以使用如下两种命令:
① 回退上一个版本:git reset --hard HEAD^
② 如果回退到前50个版本的话,使用方法①就显得不太明智了,我们可以使用简便命令:git reset --hard HEAD~50
HEAD 说明:
-
HEAD 表示当前版本
-
HEAD^ 上一个版本
-
HEAD^^ 上上一个版本
-
HEAD^^^ 上上上一个版本
-
以此类推...
可以使用 ~数字表示
-
HEAD~0 表示当前版本
-
HEAD~1 上一个版本
-
HEAD~2 上上一个版本
-
HEAD~3 上上上一个版本
-
以此类推...
$ git reset --hard HEAD^ #回退到上个版本
$ git reset --hard HEAD~3 #回退到前3次提交之前,以此类推,回退到n次提交之前
$ git reset --hard commit_id #退到/进到 指定commit的sha码
# 强推到远程:
$ git push origin HEAD --force
总结:(1) 要放弃目前本地的所有改变時,即去掉所有add到暂存区的文件和工作区的文件,可以执行 git reset -hard HEAD 来强制恢复git管理的文件夹的內容及状态;(2) 真的想抛弃目标节点后的所有commit(可能觉得目标节点到原节点之间的commit提交都是错了,之前所有的commit有问题)。
reset --soft
作用:保留工作区,并把重置 HEAD 所带来的新的差异放进暂存区。如果工作区有修改,执行reset --soft操作后,工作区的修改依然会保留。
reset --soft 会在重置 HEAD 和 branch 时,保留工作区和暂存区中的内容,并把重置 HEAD 所带来的新的差异放进暂存区。
什么是「重置 HEAD 所带来的新的差异」?就是这里:
由于 HEAD 从 4 移动到了 3,而且在 reset 的过程中工作目录和暂存区的内容没有被清理掉,所以 4 中的改动在 reset 后就也成了工作目录新增的「工作目录和 HEAD 的差异」。这就是上面一段中所说的「重置 HEAD 所带来的差异」。
此模式下会保留 working tree工作目录的內容,不会改变到目前所有的git管理的文件夹的內容;也会
保留 index暂存区的內容,让 index 暂存区与 working tree 工作目录的內容是一致的。就只有 repository 中的內容的更变需要与 reset 目标节点一致,因此原始节点与reset节点之间的差异变更集合会存在与index暂存区中(Staged files),所以我们可以直接执行 git commit 將 index暂存区中的內容提交至 repository 中。
使用场景: 假如我们想合并「当前节点」与「reset目标节点」之间不具太大意义的 commit 记录(可能是阶段性地频繁提交,就是开发一个功能的时候,改或者增加一个文件的时候就commit,这样做导致一个完整的功能可能会好多个commit点,这时假如你需要把这些commit整合成一个commit的时候)时,可以考虑使用reset --soft来让 commit 演进线图较为清晰。总而言之,可以使用--soft合并commit节点。
总结:原节点和reset节点之间的【差异变更集】会放入index暂存区中(Staged files),所以假如我们之前工作目录没有改过任何文件,也没add到暂存区,那么使用reset --soft后,我们可以直接执行 git commit 將 index暂存区中的內容提交至 repository 。
注意:--hard 会清空工作目录和暂存区的改动; --soft则会保留工作目录的内容,并把因为保留工作目录内容所带来的新的文件差异放进暂存区。
reset 不加参数(mixed)
作用:保留区内容,并清空暂存区。
reset 如果不加参数,那么默认使用 --mixed 参数。它的行为是:保留工作区,并且清空暂存区。也就是说,工作区的修改、暂存区的内容以及由 reset 所导致的新的文件差异,都会被放进工作区。简而言之,就是「把所有差异都混合(mixed)放在工作区中」。
总结: 1. 使用完reset --mixed后,可以直接执行 git add 将這些改变果的文件內容加入 index 暂存区中,再执行 git commit 将 Index暂存区 中的內容提交至Repository中,这样一样可以达到合并commit节点的效果(与上面--soft合并commit节点差不多,只是多了git add添加到暂存区的操作);
2. 移除所有Index暂存区中准备要提交的文件(Staged files),我们可以执行 git reset HEAD 来 Unstage 所有已列入 Index暂存区 的待提交的文件。(有时候发现add错文件到暂存区,就可以使用命令)。