-
Notifications
You must be signed in to change notification settings - Fork 6
Description
Git作为一个系统,以它的一般操作来管理并操纵着这三棵树:
| 树 | 用途 |
|---|---|
| HEAD | 上一次提交的快照,下一次提交的父节点 |
| Index | 预期的下一次提交的快照 |
| Work Directory | 沙盒,当前工作目录 |
HEAD
通常指的是当前分支的引用指针,指向到上一次提交的引用,总是指向该分支上的最后一次提交。
常用底层命令
git cat-file -p HEAD git ls-tree -r HEAD
索引 Index
预期的下一次提交,其实就是本地工作目录编辑的文件添加到追踪,称之为暂存区
git ls-files -s
工作目录
另外两棵树是一种高效但不直观的方式将内容存储在.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
有时候提交后发现漏掉几个文件没有添加或者没有去掉注释,或者提交信息写错了,可以使用该命令,最终只会有一个提交.
git commit --amend
可以理解为:用新的提交替换旧的提交。但是要注意上一次提交需要没有push到远程分支
取消暂存的文件
当我们执行了git add .后,如果想取消暂存其中一个怎么处理呢?其实git status 已经提示了:git reset HEAD <file>来进行取消暂存
撤销对文件的修改
如果不想保留对文件的修改,git status也提示了如果处理:
git checkou <file>,但这样做其实很危险,因为会将修改的文件永久消失。