git reset

Published: 13 May 2014 Category: git

参考文档:http://git-scm.com/blog/2011/07/11/reset.html

git reset在git所有操作中扮演着举足轻重的作用,这一点毋庸置疑,下面就结合实例做简单的介绍。

git reset 不跟文件路径的情况

这种情况下无非就三种:

  1. git reset --soft 某个commit
  2. git reset [--mixed] 某个commit(默认)
  3. git reset --hard 某个commit

简单来说,这三种情况分别表示:

  1. 把HEAD退回到某个commit上,不影响 ### 暂存区 ###和### 工作区 ###
  2. 把HEAD退回到某个commit上,### 影响暂存区 ###但是### 不影响工作区 ###
  3. 把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同时会### 影响工作区 ###