git reset
参考文档:http://git-scm.com/blog/2011/07/11/reset.html
git reset在git所有操作中扮演着举足轻重的作用,这一点毋庸置疑,下面就结合实例做简单的介绍。
git reset 不跟文件路径的情况
这种情况下无非就三种:
- git reset --soft 某个commit
- git reset [--mixed] 某个commit(默认)
- git reset --hard 某个commit
简单来说,这三种情况分别表示:
- 把HEAD退回到某个commit上,不影响 ### 暂存区 ###和### 工作区 ###
- 把HEAD退回到某个commit上,### 影响暂存区 ###但是### 不影响工作区 ###
- 把HEAD退回到某个commit上,### 影响暂存区 ###也### 影响工作区 ###
上述所谓的影响,这里做一点解释,即commit中的代码会覆盖所影响区的代码。
举个实例解释一下:
1.新建一个目录git-test,初始化一下仓库,做一次简单的提交:
mkdir git-test
cd git-test/
git init
echo 0 > test
git add .
git commit -am "init"
2.为了说明reset的作用,我们再做一次简单地提交:
echo 1 >> test
git commit -am "1"
3.我们来看一下历史提交记录:
linux-geek:/home/tmp/git-test # git log
commit c6c3801f47fdfd2fd7a9a552ab3335bd4f50f527
Author: zhuqinggooogle <zhuqinggooogle@gmail.com>
Date: Tue May 13 10:44:27 2014 +0800
1
commit 04d39a898b98407e10583678ef96af85725ce4af
Author: zhuqinggooogle <zhuqinggooogle@gmail.com>
Date: Tue May 13 10:43:47 2014 +0800
init
4.演示git reset --soft:
linux-geek:/home/tmp/git-test # git reset --soft HEAD~1
linux-geek:/home/tmp/git-test # git status
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# modified: test
#
linux-geek:/home/tmp/git-test # cat test
0
1
可见,暂存区的内容和工作区是一样的,但是暂存区和commit 04d39a898b98407e10583678ef96af85725ce4af的内容不一样,注意此时HEAD已经退回到了原来HEAD~1的位置,所以的确不影响 ### 暂存区 ###和### 工作区 ###。我们再来看一下历史提交记录:
linux-geek:/home/tmp/git-test # git log
commit 04d39a898b98407e10583678ef96af85725ce4af
Author: zhuqinggooogle <zhuqinggooogle@gmail.com>
Date: Tue May 13 10:43:47 2014 +0800
init
可见,历史提交就剩下第一次提交了。
5.演示git reset --mixed:
假设我们回到第3步,关于怎么在这种情况下直接退回到第3步,这儿先卖个关子,以后再说。
linux-geek:/home/tmp/git-test # git log
commit c6c3801f47fdfd2fd7a9a552ab3335bd4f50f527
Author: zhuqinggooogle <zhuqinggooogle@gmail.com>
Date: Tue May 13 10:44:27 2014 +0800
1
commit 04d39a898b98407e10583678ef96af85725ce4af
Author: zhuqinggooogle <zhuqinggooogle@gmail.com>
Date: Tue May 13 10:43:47 2014 +0800
init
linux-geek:/home/tmp/git-test # git reset --mixed HEAD~1
Unstaged changes after reset:
M test
linux-geek:/home/tmp/git-test # git status
# On branch master
# Changes not staged for commit:
# (use "git add <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
#
# modified: test
#
no changes added to commit (use "git add" and/or "git commit -a")
linux-geek:/home/tmp/git-test # cat test
0
1
可见,这的确### 影响暂存区 ###但是### 不影响工作区 ###。我们再来看一下历史提交记录:
linux-geek:/home/tmp/git-test # git log
commit 04d39a898b98407e10583678ef96af85725ce4af
Author: zhuqinggooogle <zhuqinggooogle@gmail.com>
Date: Tue May 13 10:43:47 2014 +0800
init
同样,历史提交就剩下第一次提交了。
6.演示git reset --hard:
假设我们回到第3步,
linux-geek:/home/tmp/git-test # git log
commit c6c3801f47fdfd2fd7a9a552ab3335bd4f50f527
Author: zhuqinggooogle <zhuqinggooogle@gmail.com>
Date: Tue May 13 10:44:27 2014 +0800
1
commit 04d39a898b98407e10583678ef96af85725ce4af
Author: zhuqinggooogle <zhuqinggooogle@gmail.com>
Date: Tue May 13 10:43:47 2014 +0800
init
linux-geek:/home/tmp/git-test # git reset --hard HEAD~1
HEAD is now at 04d39a8 init
linux-geek:/home/tmp/git-test # git status
# On branch master
nothing to commit (working directory clean)
linux-geek:/home/tmp/git-test # cat test
0
的确是### 影响暂存区 ###也### 影响工作区 ###
git reset 跟文件路径的情况
上述讨论了git reset 后面不跟文件路径的情况,下面讨论跟文件路径的情况。所谓跟文件路径,即这种格式:
git reset [--mixed] 某个commit -- 文件路径
没有其他两种格式,注意。
7.演示git reset -- 文件路径
同样,假设我们回到第3步:
linux-geek:/home/tmp/git-test # git log
commit c6c3801f47fdfd2fd7a9a552ab3335bd4f50f527
Author: zhuqinggooogle <zhuqinggooogle@gmail.com>
Date: Tue May 13 10:44:27 2014 +0800
1
commit 04d39a898b98407e10583678ef96af85725ce4af
Author: zhuqinggooogle <zhuqinggooogle@gmail.com>
Date: Tue May 13 10:43:47 2014 +0800
init
linux-geek:/home/tmp/git-test # git reset HEAD~1 -- ./test
Unstaged changes after reset:
M test
linux-geek:/home/tmp/git-test # git status
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# modified: test
#
# Changes not staged for commit:
# (use "git add <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
#
# modified: test
#
linux-geek:/home/tmp/git-test # git log
commit c6c3801f47fdfd2fd7a9a552ab3335bd4f50f527
Author: zhuqinggooogle <zhuqinggooogle@gmail.com>
Date: Tue May 13 10:44:27 2014 +0800
1
commit 04d39a898b98407e10583678ef96af85725ce4af
Author: zhuqinggooogle <zhuqinggooogle@gmail.com>
Date: Tue May 13 10:43:47 2014 +0800
init
linux-geek:/home/tmp/git-test #
我们再用git diff看一下或许会更清楚:
linux-geek:/home/tmp/git-test # git diff --cached
diff --git a/test b/test
index 0d66ea1..573541a 100644
--- a/test
+++ b/test
@@ -1,2 +1 @@
0
-1
linux-geek:/home/tmp/git-test # git diff
diff --git a/test b/test
index 573541a..0d66ea1 100644
--- a/test
+++ b/test
@@ -1 +1,2 @@
0
+1
可见,这时候直接把HEAD~1的代码覆盖了暂存区的代码,但是### 不影响工作区 ###,历史提交也是完整的。也许你会发现这有点像checkout,唯一一点不同就是checkout同时会### 影响工作区 ###