Git:重置揭秘
本文详细讲述了Git中重置相关的git-reset、git-checkout、git-revert的命令。
前提知识
树名称 | 说明 |
---|---|
Working Directory | 工作区 |
Index 或 Stage | 暂存区,预期的下一次要被提交的快照 |
HEAD | HEAD 指向目前所在的本地分支,它是一个符号引用,所谓符号引用,表示它是一个指向其他引用的指针。并且它总是指向当前分支的最后一次提交。 |
git reset
示例数据准备:master分支分别进行3次修改、提交,形成如下提交拓扑图:
reset+commit
它的基本语义是:将HEAD指向的当前分支重置到指定的“提交”状态,其中根据指定的参数对暂存区和工作区进行相应的修改。
1步:移动HEAD
使用git reset --soft <commit>
命令将HEAD指向的当前分支移动到指定的“提交”位置。
示例:
1 | git reset --soft HEAD~ |
2步:移动HEAD+更新暂存区
使用git reset [--mixed] <commit>
命令将HEAD指向的当前分支移动到指定的“提交”位置,并同步重置暂存区。
示例:
1 | git reset HEAD~ |
3步:移动HEAD+更新暂存区+更新工作区
使用git reset --hard <commit>
命令将HEAD指向的当前分支移动到指定的“提交”位置,并同步重置暂存区和工作区。
示例:
1 | git reset --hard HEAD~ |
reset+path
它的基本语义是:将暂存区中的文件恢复到指定“提交”时的状态(注意,不会移动HEAD指针)。git reset <commit> [--] path
命令中不能有--soft
和--hard
参数。
示例:
1 | git reset HEAD~ file.txt |
如果使用git reset HEAD file.txt
,它的效果就有“取消暂存文件”的效果,相当于撤销git add
所做的事情。
git checkout
示例数据准备:master分支分别进行3次修改、提交;dev分支进行一次修改、提交,形成如下提交拓扑图:
checkout+branch
它的基本语义是:检出指定分支,使得HEAD指向被检出的分支,暂存区和工作区不是像reset
操作那样进行直接覆盖更新,而是在检出时会进行智能化地合并切换前后对应区域中的内容。
命令形式为:git checkout <branch>
示例:
1 | git checkout master |
我们注意到,上例途中,checkout
操作是将HEAD的指向进行变更,而reset
是对HEAD指向的分支进行移动。下图来自Git官方文档给出的一个非常形象的关于checkout和reset的对比:
checkout+path
它的基本语义是:将特定“分支”的最后“提交”中对应的文件更新到暂存区,再将暂存区相应文件直接覆盖到工作区中的文件(注意,是直接覆盖工作区,不会做智能地合并)。
命令形式为:git checkout [tree-ish] -- path
示例:
1 | git checkout HEAD~ -- file.txt |
特例:git checkout -- path
实际对应的git checkout HEAD -- path
。
git revert
revert
可以理解为撤销
的意思,该命令的基本语义是:对当前分支,撤销某次提交所对应的变更,并使用一次新的提交来合并因撤销提交所造成的影响。理解该命令需要注意几点:
- 在执行该命令时,要求工作区是
clean
状态; - 它不是真正撤销某次提交,而是撤销某次提交所对应的变更,直观上,在该命令执行完成后,被撤销的提交仍然在提交的拓扑图中;
示例数据准备:master分支分别进行3次新建文件、提交;dev分支进行一次修改、提交,形成如下提交拓扑图:
撤销后直接提交
使用git revert [--edit] <commit>
或git revert [-e] <commit>
命令将指定的提交影响进行撤销,并且--edit
或-e
选项允许在提交合并的结果之前来编辑提交信息(注意,如果在revert
某次提交期间,导致在Git处理合并有冲突时,需要我们手动解决完冲突,然后再进行手动commit操作)。
示例:
1 | git revert da814a2 |
当然,如果我们不想自己来编辑revert
命令衍生新提交的提交信息,可以使用--no-edit
选项,该选项会自动为新提交创建提交信息,格式为:Resert + 被撤销的信息。
撤销后不直接提交
使用git revert -n <commit>
或git revert --no-commit <commit>
命令只将撤销合并后的结果放到工作区和暂存区,不会提交到仓库中。
示例:
1 | git revert -n da814a2 |