再议git的checkout, revert, 和reset命令
这三个命令都是git用于回退,修正错误的命令。
三个基本概念
Working Directory(工作区) <--> Staged Snapshot(暂存区) <--> Commit History
git checkout
迁出历史版本文件。
用法
git checkout <branch> # 这个是切换branch,不讨论
git checkout <commit> # 这个命令很难用, 我不知道怎么用?
git checkout <commit> -- <file> #连续两个连号(--)表示后面是文件名,而不是分支名。
功能
git checkout -- <file>
丢弃当前工作区的文件,把Staged区文件拷贝到当前工作区。git checkout HEAD -- <file>
丢弃当前工作区和Staged区的文件,把HEAD文件拷贝到当前工作区和Staged区。-
git checkout <commit> -- <file>
把历史版本的文件拷贝到当前工作区和Staged区,接下来有两个选项可以继续- 只是看一下历史版本,然后丢弃历史版本
git checkout HEAD -- <file> # 这个命令的含义是把HEAD再拷贝到当前工作区和Staged区,冲掉之前的历史版本 - 需要提交这个历史版本
git add <file>
git commit <file>
- 只是看一下历史版本,然后丢弃历史版本
补充一点 git checkout <commit>的用法
通常把某个<commit>迁出后,在迁出的代码上拉一个新的分支,然后在新的分支里面继续做开发,最后提交新分支的代码。
$ git checkout <commit>
Note: checking out '<commit>'.
You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.
If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:
git checkout -b new_branch_name
HEAD is now at <commit>... <description>
$ git status
# HEAD detached at <commit>
nothing to commit, working directory clean
$ git branch
* (detached from <commit>)
<current_branch>
$ git checkout -b test_branch
Switched to a new branch 'test_branch'
$ git status
# On branch test_branch
nothing to commit, working directory clean
$ git branch
<current_branch>
* test_branch
git revert
revert的作用是翻转一个commit;作用对象是一个commit,把它所有的改动翻转。
revert不能翻转单个文件,只能对一个完整的commit翻转。这个commit可以是最新的commit,或者历史上的任何一个commit。
用法
git revert <commit>
git revert HEAD~1
功能
- 如果翻转过程顺利,没有合并冲突, 那么
这个翻转操作会自动发起一个新的commit提交; 在代码历史里面可以看到本次翻转的commit操作。 - 如果翻转过程存在冲突,不能自动完成(通常发生在需要翻转一个历史commit时),那么
git revert 命令会把冲突的文件保存在当前工作区,然后用户手工完成代码merge操作,然后git add 加到stage区,最后git commit 手动发起commit操作
git reset
reset的作用是回退到之前的某一个状态
reset既可以作用于commit,也可以作用于file
注意和revert的区别,revert作用于具体一个commit,而reset是commit所处的那个点的状态,所以那个点之后的信息全会被丢弃,包括历史,即那个点之后的所有操作历史都丢弃了。
也就是说以前的操作历史都被抹去了,是不是很开心,犯了错误找不到痕迹了?(想的美:-))
用法
git reset <commit> [<file>]
git reset HEAD~2 [<file>]
功能
- git reset <commit>
则回退到<commit>的状态,也就是<commit>完成后的状态,所有<commit>之后的提交都丢弃,<commit>之后的commit历史记录也丢弃。
然后会把所有<commit>之后的提交改动都存放在当前工作区,这样用户可以选择丢弃,也可以选择修改,再次提交; - git reset HEAD~2
则是丢弃最近的两个commit,回退到最近的第三次提交状态。
注意reset之后,<commit>之后的操作历史都丢弃了,因此这个命令不能用在公共的分支上,也不能用在已经push到服务器上的分支上;所以通常在私有的分支上做reset操作。
因为如果分支已经push到服务器了,在reset完之后status命令会告诉你,当前分支已经落后服务器上的分支了,需要你重新从服务器pull下代码来,这样相当于reset没有用白做了嘛;而你如果想push到服务器,git直接就给你失败,因为你已经落后了。
三个选项
--soft – staged和当前工作区都不更新. (很少用到这个选项)
--mixed(default) – staged更新,但当前工作区不更新
--hard – staged和当前工作区都更新
git diff
缺省情况下git diff比较的是当前工作区和Staged区的文件差异。