Git作为一个系统,以它的一般操作来管理并操纵着这三棵树:
| 树 |
用途 |
| HEAD |
上一次提交的快照,下一次提交的父节点 |
| Index |
预期的下一次提交的快照 |
| Work Directory |
沙盒,当前工作目录 |
HEAD
通常指的是当前分支的引用指针,指向到上一次提交的引用,总是指向该分支上的最后一次提交。
常用底层命令
git cat-file -p HEAD
git ls-tree -r HEAD
索引 Index
预期的下一次提交,其实就是本地工作目录编辑的文件添加到追踪,称之为暂存区
工作目录
另外两棵树是一种高效但不直观的方式将内容存储在.git文件中。工作目录其实就是解包为实际文件以方便编辑,可以当做是沙盒。
Reset 命令
--soft (移动HEAD)
git reset --soft HEAD~
将HEAD指向到上一次commit命令之前,也就是add命令之后的状态,本质上只是撤销了上一次 git commit 命令,执行reset回HEAD~时,其实就是把该分支移动回原来的位置,而不会改变索引和工作目录。
--mixed (更新索引)
git reset [--mixed] HEAD~命令
属于默认行为,即执行git reset HEAD~等同于执行了--mixed,执行后会撤销上一次的提交,还会取消暂存所有的东西,于是,我们回滚了所有的git add 和 git commit命令之前
--hard (更新工作目录)
本质上是将HEAD复制到Index上,这一步很危险,会丢失之前的修改,并且还带有取消暂存文件的实际效果,比如指向舍弃本地的修改,可以直接git reset --hard HEAD,意味着将本地的HEAD指向到索引和工作区,甚至还可以通过具体的提交来拉取该文件的对应的版本git reset HASH -- xxxfile
Tips
-
git reset --hard方式可以将之前多个提交合并成一个,即使用git reset --soft HEAD~x
-
执行了git reset 后如果想放弃该操作,可以使用git reflog查看操作历史,找到之前的HEAD后,执行git reset --hard到那个HEAD,甚至可以更快一步,直接执行`git reset --hard HEAD~``
Checkout与Reset区别
不细看执行git checkout [branch]与git reset --hard [branch]非常类似,都是会更新三棵树,使其看起来像[branch],不过还是有很大的差别。
- 不同于
reset --hard,checkout对工作目录是安全的,通过检查确保不会将已经更改的文件弄丢。并会尝试在工作目录中进行简单合并,这样所有还未修改过的文件都会被更新。而reset --hard则会不做检查就全面替换所有东西,丢失所有修改的未提交的文件。
- 对
HEAD的更新处理方式不同,reset会移动HEAD分支的指向,而checkout只会移动HEAD自身来指向另一个分支
当checkout另一种使用方式就是指定一个文件路径,就像reset一样不会移动HEAD.类似于git reset [branch] file那样用该次提交中的那个文件来更新索引,但它会覆盖工作目录中对应的文件,就像是git reset --hard [branch] file。
另外git reset与git add、git checkout都接受--patch选项,允许你根据选择一块一块地恢复文件内容
影响表:
|
HEAD |
Index |
workdir |
wd safe |
| Commit Level |
|
|
|
|
| reset --soft [commit] |
REF |
NO |
NO |
YES |
| reset [commit] |
REF |
YES |
NO |
YES |
| reset --hard [commit] |
REF |
YES |
YES |
NO |
| checkout |
HEAD |
YES |
YES |
YES |
|
|
|
|
|
| File Level |
|
|
|
|
| reset [commit] |
NO |
YES |
NO |
YES |
| checkout [commit] |
NO |
YES |
YES |
NO |
撤销操作
--amend
有时候提交后发现漏掉几个文件没有添加或者没有去掉注释,或者提交信息写错了,可以使用该命令,最终只会有一个提交.
可以理解为:用新的提交替换旧的提交。但是要注意上一次提交需要没有push到远程分支
取消暂存的文件
当我们执行了git add .后,如果想取消暂存其中一个怎么处理呢?其实git status 已经提示了:git reset HEAD <file>来进行取消暂存
撤销对文件的修改
如果不想保留对文件的修改,git status也提示了如果处理:
git checkou <file>,但这样做其实很危险,因为会将修改的文件永久消失。
Git作为一个系统,以它的一般操作来管理并操纵着这三棵树:
HEAD
通常指的是当前分支的引用指针,指向到上一次提交的引用,总是指向该分支上的最后一次提交。
常用底层命令
索引 Index
预期的下一次提交,其实就是本地工作目录编辑的文件添加到追踪,称之为暂存区
工作目录
另外两棵树是一种高效但不直观的方式将内容存储在
.git文件中。工作目录其实就是解包为实际文件以方便编辑,可以当做是沙盒。Reset 命令
--soft (移动HEAD)
git reset --soft HEAD~将
HEAD指向到上一次commit命令之前,也就是add命令之后的状态,本质上只是撤销了上一次git commit命令,执行reset回HEAD~时,其实就是把该分支移动回原来的位置,而不会改变索引和工作目录。--mixed (更新索引)
git reset [--mixed] HEAD~命令属于默认行为,即执行
git reset HEAD~等同于执行了--mixed,执行后会撤销上一次的提交,还会取消暂存所有的东西,于是,我们回滚了所有的git add和git commit命令之前--hard (更新工作目录)
本质上是将
HEAD复制到Index上,这一步很危险,会丢失之前的修改,并且还带有取消暂存文件的实际效果,比如指向舍弃本地的修改,可以直接git reset --hard HEAD,意味着将本地的HEAD指向到索引和工作区,甚至还可以通过具体的提交来拉取该文件的对应的版本git reset HASH -- xxxfileTips
git reset --hard方式可以将之前多个提交合并成一个,即使用git reset --soft HEAD~x执行了
git reset后如果想放弃该操作,可以使用git reflog查看操作历史,找到之前的HEAD后,执行git reset --hard到那个HEAD,甚至可以更快一步,直接执行`git reset --hard HEAD~``Checkout与Reset区别
不细看执行
git checkout [branch]与git reset --hard [branch]非常类似,都是会更新三棵树,使其看起来像[branch],不过还是有很大的差别。reset --hard,checkout对工作目录是安全的,通过检查确保不会将已经更改的文件弄丢。并会尝试在工作目录中进行简单合并,这样所有还未修改过的文件都会被更新。而reset --hard则会不做检查就全面替换所有东西,丢失所有修改的未提交的文件。HEAD的更新处理方式不同,reset会移动HEAD分支的指向,而checkout只会移动HEAD自身来指向另一个分支当
checkout另一种使用方式就是指定一个文件路径,就像reset一样不会移动HEAD.类似于git reset [branch] file那样用该次提交中的那个文件来更新索引,但它会覆盖工作目录中对应的文件,就像是git reset --hard [branch] file。另外
git reset与git add、git checkout都接受--patch选项,允许你根据选择一块一块地恢复文件内容影响表:
撤销操作
--amend
有时候提交后发现漏掉几个文件没有添加或者没有去掉注释,或者提交信息写错了,可以使用该命令,最终只会有一个提交.
可以理解为:用新的提交替换旧的提交。但是要注意上一次提交需要没有
push到远程分支取消暂存的文件
当我们执行了
git add .后,如果想取消暂存其中一个怎么处理呢?其实git status已经提示了:git reset HEAD <file>来进行取消暂存撤销对文件的修改
如果不想保留对文件的修改,
git status也提示了如果处理:git checkou <file>,但这样做其实很危险,因为会将修改的文件永久消失。