一、详细学习Gitgit
https://github.com/geeeeeeeeek/git-recipes/wikigithub
二、git reset、git checkout、git revert 学习缓存
git reset
、git checkout
和 git revert
是你的 Git 工具箱中最有用的一些命令。它们都用来撤销代码仓库中的某些更改,而前两个命令不只能够做用于提交,还能够做用于特定文件。工具
由于它们很是类似,因此咱们常常会搞混,不知道什么场景下该用哪一个命令。在这篇文章中,咱们会比较 git reset
、git checkout
和 git revert
最多见的用法。但愿你在看完后能游刃有余地使用这些命令来管理你的仓库。学习
[此处有图]spa
Git 仓库有三个主要组成——工做目录,缓存区和提交历史。这张图有助于理解每一个命令到底产生了哪些影响。当你阅读的时候,牢记这张图。code
你传给 git reset
和 git checkout
的参数决定了它们的做用域。若是你没有包含文件路径,这些操做对全部提交生效。咱们这一节要探讨的就是提交层面的操做。注意,git revert
没有文件层面的操做。ip
在提交层面上,reset 将一个分支的末端指向另外一个提交。这能够用来移除当前分支的一些提交。好比,下面这两条命令让 hotfix 分支向后回退了两个提交。ci
git checkout hotfix git reset HEAD~2
hotfix 分支末端的两个提交如今变成了悬挂提交。也就是说,下次 Git 执行垃圾回收的时候,这两个提交会被删除。换句话说,若是你想扔掉这两个提交,你能够这么作。reset 操做以下图所示:
[此处有图]
若是你的更改尚未共享给别人,git reset
是撤销这些更改的简单方法。当你开发一个功能的时候发现「糟糕,我作了什么?我应该从新来过!」时,reset 就像是 go-to 命令同样。
除了在当前分支上操做,你还能够经过传入这些标记来修改你的缓存区或工做目录:
把这些标记想成定义 git reset
操做的做用域就容易理解多了。
[此处有图]
这些标记每每和 HEAD 做为参数一块儿使用。好比,git reset --mixed HEAD
将你当前的改动从缓存区中移除,可是这些改动还留在工做目录中。另外一方面,若是你想彻底舍弃你没有提交的改动,你可使用 git reset --hard HEAD
。这是 git reset
最经常使用的两种用法。
当你传入 HEAD 之外的其余提交的时候要格外当心,由于 reset 操做会重写当前分支的历史。正如 rebase 黄金法则所说的,在公共分支上这样作可能会引发严重的后果。
你应该已经很是熟悉提交层面的 git checkout
。当传入分支名时,能够切换到那个分支。
git checkout hotfix
上面这个命令作的不过是将HEAD移到一个新的分支,而后更新工做目录。由于这可能会覆盖本地的修改,Git 强制你提交或者缓存工做目录中的全部更改,否则在 checkout 的时候这些更改都会丢失。和 git reset
不同的是,git checkout
没有移动这些分支。
[此处有图]
除了分支以外,你还能够传入提交的引用来 checkout 到任意的提交。这和 checkout 到另外一个分支是彻底同样的:把 HEAD 移动到特定的提交。好比,下面这个命令会 checkout 到当前提交的祖父提交。
git checkout HEAD~2
这对于快速查看项目旧版原本说很是有用。但若是你当前的 HEAD 没有任何分支引用,那么这会形成 HEAD 分离。这是很是危险的,若是你接着添加新的提交,而后切换到别的分支以后就没办法回到以前添加的这些提交。所以,在为分离的 HEAD 添加新的提交的时候你应该建立一个新的分支。
Revert 撤销一个提交的同时会建立一个新的提交。这是一个安全的方法,由于它不会重写提交历史。好比,下面的命令会找出倒数第二个提交,而后建立一个新的提交来撤销这些更改,而后把这个提交加入项目中。
git checkout hotfix git revert HEAD~2
以下图所示:
[此处有图]
相比 git reset
,它不会改变如今的提交历史。所以,git revert
能够用在公共分支上,git reset
应该用在私有分支上。
你也能够把 git revert
看成撤销已经提交的更改,而 git reset HEAD
用来撤销没有提交的更改。
就像 git checkout
同样,git revert
也有可能会重写文件。因此,Git 会在你执行 revert 以前要求你提交或者缓存你工做目录中的更改。
git reset
和 git checkout
命令也接受文件路径做为参数。这时它的行为就大为不一样了。它不会做用于整份提交,参数将它限制于特定文件。
当检测到文件路径时,git reset
将缓存区同步到你指定的那个提交。好比,下面这个命令会将倒数第二个提交中的 foo.py
加入到缓存区中,供下一个提交使用。
git reset HEAD~2 foo.py
和提交层面的 git reset
同样,一般咱们使用HEAD而不是某个特定的提交。运行 git reset HEAD foo.py
会将当前的 foo.py
从缓存区中移除出去,而不会影响工做目录中对 foo.py
的更改。
[此处有图]
--soft
、--mixed
和 --hard
对文件层面的 git reset
毫无做用,由于缓存区中的文件必定会变化,而工做目录中的文件必定不变。
Checkout 一个文件和带文件路径 git reset
很是像,除了它更改的是工做目录而不是缓存区。不像提交层面的 checkout 命令,它不会移动 HEAD引用,也就是你不会切换到别的分支上去。
[此处有图]
好比,下面这个命令将工做目录中的 foo.py
同步到了倒数第二个提交中的 foo.py
。
git checkout HEAD~2 foo.py
和提交层面相同的是,它能够用来检查项目的旧版本,但做用域被限制到了特定文件。
若是你缓存而且提交了 checkout 的文件,它具有将某个文件回撤到以前版本的效果。注意它撤销了这个文件后面全部的更改,而 git revert
命令只撤销某个特定提交的更改。
和 git reset
同样,这个命令一般和 HEAD 一块儿使用。好比 git checkout HEAD foo.py
等同于舍弃 foo.py
没有缓存的更改。这个行为和 git reset HEAD --hard
很像,但只影响特定文件。
你如今已经掌握了 Git 仓库中撤销更改的全部工具。git reset
、git checkout
和 git revert
命令比较容易混淆,但当你想起它们对工做目录、缓存区和提交历史的不一样影响,就会容易判断如今应该用哪一个命令。
下面这个表格总结了这些命令最经常使用的使用场景。记得常常对照这个表格,由于你使用 Git 时必定会常常用到。
命令 | 做用域 | 经常使用情景 |
---|---|---|
git reset | 提交层面 | 在私有分支上舍弃一些没有提交的更改 |
git reset | 文件层面 | 将文件从缓存区中移除 |
git checkout | 提交层面 | 切换分支或查看旧版本 |
git checkout | 文件层面 | 舍弃工做目录中的更改 |
git revert | 提交层面 | 在公共分支上回滚更改 |
git revert | 文件层面 | (然而并无) |