- 当执行
git reset HEAD
命令时,暂存区的目录树会被重写,会被HEAD所指的目录树替换,但是工作区不受影响。 - 当执行
git rm --cached <file>
命令时,会直接从暂存区删除文件,工作区则不做出改变。 - 当执行
git checkout .
或git checkout -- <file>
命令时,会用暂存区全部的文件或指定的文件替换工作区的文件。这个操作很危险,会清除工作区中未添加到暂存区的改动。 - 当执行
git checkout HEAD .
或git checkout HEAD <file>
命令时,会用HEAD指向的分支中的全部或部分文件替换暂存区和工作区的文件。这个命令不但会清除工作区中未提交的改动,也会清除暂存区中未提交的改动。
用reflog挽救错误的重置
-
git reflog show master | head -5
查看master分支指向的变迁 -
git reset --hard master@{2}
重置master为两次改变之前的值
git reset
- 命令:
git reset
仅用HEAD指向的目录树重置暂存区,工作区不会受到影响,相当于将之前用git add命令更新到暂存区的内用撤出暂存区。引用也未改变,因为引用重置到HEAD相当于没有重置。 - 命定:
git reset HEAD
同上。 - 命令:
git reset -- filename
仅将文件filename的改动撤出暂存区,暂存区中的其他文件不改变。相当于对命令git add filename
的反向操作。 - 命令:
git reset HEAD filename
同上。 - 命令:
git reset --soft HEAD^
工作区和暂存区都不改变,但是引用向前回退一次。当对最新提交说明或提交的更改不满意时,撤销最新的提交以便重新提交。 - 命令:
git reset HEAD^
工作区不改变,但是暂存区会回退到上一次的提交之前,引用也会回退一次。 - 命令:
git reset --mixed HEAD^
同上。 - 命令:
git reset --hard HEAD^
彻底撤销最近的提交,引用回退到前一次,而且工作区和暂存区都会回退到上一次提交的状态。自上一次以来的提交全部丢失。
git checkout
-
git checkout branch
检出branch分支。更新HEAD以指向branch分支,以及用branch指向的树更新暂存区和工作区。 -
git checkout
汇总工作区、暂存区与HEAD的差异。 -
git checkout HEAD
同上。 -
git checkout -- filename
用暂存区中的filename文件来覆盖工作区懂得filename文件。相当于取消自上次执行git add filename以来(如果执行过)的本地修改。这个命令对于本地的修改会悄无声息地覆盖,毫不留情。 -
git checkout branch -- filename
维持HEAD的指向不变,用branch所指向的提交中的filename替换暂存区和工作区中相应的文件。注意会将暂存区和工作区中的filename直接覆盖。 -
git checkout -- .
或git checkout .
这个命令会取消本地所有的修改(相对于暂存区),相当于用暂存区的所有文件替换本地文件,不给用户任何确认的机会!
案例
假设你有一段很长的历史比如A-1-2-3-4-5-6-7-8-B,这个时候你忽然发现在1的地方,有一处错了,但你又不想git reset
,再一个一个重写提交信息,这个时候你就可以用git rebase --onto
了。其实很简单,假设我们在1这个节点有个错误,首先,我在1切一个分支temp,切过去之后做更改,更改之后我用git commit --amend
,即重写本次提交历史。提交之后,我1的提交信息没有改变,但文件已经被我改变了,好,接下来要做的就是把原来1之后到B的历史,加到新的1之上。因为我们通过log可以看到,此时的1和新1完全走的是两条分支状态,所以自然而然的我们会想到去这么做。这个时候就可以用我们的git rebase --onto
了,首先在切片末尾,即B上建立一个活动分支result,然后调用命令git rebase --onto 新1 1 result
,注意里面开闭区间的问题,因为我此时已经有1的历史,所以我应该从1的下一个开始,但又因为是坐开又闭,所以我这里就直接写1就没问题。这样就完成了回退历史做修改,并且可以不用重新写提交信息的操作。