git暂缓区工作区原理和修改删除等命令

前言:
 
在前面几篇,特别是第(3)篇已经详细的说了几个很重要也很常见的命令了。这一节接着说。同样也是参考了这本书:
 
http://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000
 
工作区和暂存区的关系及区别
 
前面我们多次提到命令git status命令,他的一些状态变化,其实都与现在我们将要说的工作区和暂存区有关,再说这个之前呢,我们先来理清楚几个名词概念,会更好理解工作区和暂存区。
 
工作区
 
工作区(working Directory),就是我们项目的目录,也就是我们例子中的learngit 目录,这就是我们所说的工作区,比较简单。如下图所示:
 
git暂缓区工作区原理和修改删除等命令
 
这个目录就是一个工作区,我们需要版本的控制的文件都放到这个文件夹下面。
 
版本库
 
版本库(Repository) ,工作区有一个隐藏目录“.git”,如上图所示,这个目录不算工作区,而是Git的版本库。我们打开这个.git文件夹,里面有很多文件:
 
git暂缓区工作区原理和修改删除等命令
 
其中最重要的就是称为stage(或者叫index)的暂存区,还有Git为我们自动创建的第一个分支master,以及指向master的一个指针叫HEAD。
 
暂缓区
 
我们先来看一张图,用来区分工作区和暂缓区以及分支的概念:
 
git暂缓区工作区原理和修改删除等命令
 
上图中,工作区就是我们的本地目录,也就是learngit目录,stage就是暂缓区,master分支就是主分支。
 
我们先把这三个关系说一下,然后我们再具体的例子来说明:
 
前面讲了我们把文件往Git版本库里添加的时候,是分两步执行的:

第一步是用“git add”把文件添加进去,实际上就是把文件修改添加到暂存区

第二步是用“git commit”提交更改,实际上就是把暂存区的所有内容提交到当前分支

因为我们创建Git版本库时,Git自动为我们创建了唯一一个master分支,所以,现在,commit就是往master分支上提交更改。

你可以简单理解为,需要提交的文件修改通通放到暂存区,然后,一次性提交暂存区的所有修改。
 
写个例子
 
好,现在我们来写个例子来说明下工作区,暂存区以及分支之间的关系。我们主要是用git status这个命令,来查看。
 
我们先来修改一个README.md文件,加一行内容:Git has a mutable index called stage.
  1.  
    Git is a distributed version control system.
  2.  
    Git is free software. it is a good tool. distributed under the GPL.
  3.  
    Git has a mutable index called stage.
<span>然后,在工作区,也就是learngit 目录下,新增一个LICENSE文本文件(内容随便写)。我们拷贝一段apache的:</span>
Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/


   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
好。这个时候,我们使用一下git status这个命令,来查看下:
$ 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:   README.md


Untracked files:
  (use "git add <file>..." to include in what will be committed)


        LICENSE


no changes added to commit (use "git add" and/or "git commit -a")
我们注意观察这2段内容,它的表述是不一样的。README.md是说 Changes not staged for commit,意思有改动还没修改加到暂存区,刚好我们前面提到暂存区就是stage,所以not staged就是没有到暂存区。LICENSE是说Untracked files ,意思是还没添加追踪,因为我们是新加的,从没git add,所以没被git版本库管理起来。
 
好,那我们就分2次用git add命令将这2次加到暂存区,也就stage中。
/d/learngit (master)
$ git add README.md
 /d/learngit (master)
$ git add LICENSE

ok,之前说过没有任何输出代表成功了。现在就是将工作区(working Directory)的代码提交到了暂存区(stage),所以这一步的操作,我们画图就是这样:

 

 
ok,添加到暂存区之后,我们再来git status这个命令查看下,状态是啥样。

 /d/learngit (master)
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)


        new file:   LICENSE
        modified:   README.md

它提示我们2个文件,一个是new新的,一个modified修改过,都已经提交到暂缓区,但是都没提交commit到master分支。也就是说现在暂存区是有东西的。

 
那我们就提交到分支吧,还记得怎么提交分支嘛?对,用这个命令:git commit
 -m "some msg"

$ git commit -m "modify README.md and add a new LICENSE file"
[master b4a73ed] modify README.md and add a new LICENSE file
 2 files changed, 6 insertions(+)
 create mode 100644 LICENSE

ok,commit成功了。提示我们成功了。那么,现在的暂存区状态是什么样子呢?我们也来画图看看:

 

 
我们通过上诉图,很清楚的看到了。暂存区现在是空的了,工作区也已经是干净的了,代码已经提交到当前的master分支上去了。是不是这样呢。同样,我们用git status这个命令查看下

$ git status
On branch master
nothing to commit, working directory clean

它提示我们都已经提交了,工作区也是干净的。

 
 
git跟踪的是修改
 
上面很详细的说了暂存区的一些基本的东西,下面我们通过管理修改的例子,说学习一下为毛git这么快,比其他的版本工具来优秀,因为git跟踪并管理的是修改,并不是文件。
 
git 中如何定义修改呢:你新增了一行,这就是一个修改,删除了一行,也是一个修改,更改了某些字符,也是一个修改,删了一些又加了一些,也是一个修改,甚至创建一个新文件,也算一个修改。
 
SVN中是跟踪的是这个文件,只要这个文件发生变化,我们就认为是有diff的。但是GIT跟踪的是修改,一个修改只要没被add到缓存区,都不算diff。
 
我们直接看例子吧:
 
第一步,对README.md做一个修改,比如加一行内容:  Git tracks changes.


$ vi README.md
Git is a distributed version control system.
Git is free software. it is a good tool. distributed under the GPL.
Git has a mutable index called stage.
Git tracks changes.
第二步:我们用git add 命令将这次修改添加到暂存区。并用git status这个命令查看下状态
 
$ git add README.md
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)


        modified:   README.md

提示我们已经添加到了暂存区。
 
第三步:我们再继续修改下这个文件:
 

$ vi README.md
Git is a distributed version control system.
Git is free software. it is a good tool. distributed under the GPL.
Git has a mutable index called stage.
Git tracks changes of files.
第四步:我们不对第三步的修改添加到暂存区,我们这一步直接提交到master分支,用git commit -m "msg"
 
$ git commit -m "git tracks changes"
[master a2f0cbc] git tracks changes
 1 file changed, 1 insertion(+)

ok,提示我们已经commit成功,我们现在再用git status这个命令查看下状态

 

$ 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:   README.md


no changes added to commit (use "git add" and/or "git commit -a")
我们发现,第三步我们的修改 Git tracks changes of files. 还存放在工作区,没有被commit。为毛会这样呢?别激动,我们一开始不就说了嘛:git 跟踪管理的是你的每一次修改,并不是这个文件。

 
如果你还不清楚,我们理一下刚才这个例子的顺序:
 
第一次修改 -> git add -> 第二次修改(没有git add) -> git commit
你看,我们前面讲了,Git管理的是修改,当你用“git add”命令后,在工作区的第一次修改被放入暂存区,准备提交,但是,在工作区的第二次修改并没有放入暂存区,所以,“git commit”只负责把暂存区的修改提交了,也就是第一次的修改被提交了,第二次的修改不会被提交。
 
由于,第二次修改还在工作区,根据前面讲的,我们是可以用git diff这个命令来看差异的。
 

$ git diff
diff --git a/README.md b/README.md
index f4febdd..0262b58 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
 Git is a distributed version control system.
 Git is free software. it is a good tool. distributed under the GPL.
 Git has a mutable index called stage.
-Git tracks changes.
+Git tracks changes of files.

可见,第二次修改确实没有被提交。
 

那怎么提交第二次修改呢?你可以继续add再commit,也可以别着急提交第一次就commit修改,先add第二次修改,再commit,就相当于把两次修改合并后一块提交了:
第一次修改 -> add -> 第二次修改 -> add -> commit


如何撤销修改
 
通过上面的N个步骤学习,我们渐渐的掌握了git中的基本命令,也清楚了git的工作方式,git中的工作区暂存区的联系,那么,我们现在来看看如何撤销的修改。
 
这个场景很常见,一般我们使用版本管理也是觉得这个功能很赞。注意,这里的撤销与之前咱们讲到的版本管理还是有点区别的,版本回退是已经提交commit到master分支了。但是我们现在说的这个撤销有点类似于SVN 你的 reset 命令,还没有commit 到分支。
 
由于是还没提交到master 分支,所以就分为2种情况:1. 还在工作区,还没add到暂存区,2. 已经add到暂存区了。
 
我们来看下第一种情况:还在工作区。
 
还在工作区
 
比如我看小王不爽了,很郁闷就在README.md里骂了一句,xiaowang is sb.

Git is a distributed version control system.
Git is free software. it is a good tool. distributed under the GPL.
Git has a mutable index called stage.
Git tracks changes of files.
xiaowang is sb.

现在想想不应该骂他的,反悔了。那我如何撤销我刚才的修改呢?你说我一行行的手动去掉行不行?当然可以。但是这样做就真的是sb了。要是工作量太大,那不还把人搞死啊。
 
我们用可以先用git status这个命令查看下状态

$ 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:   README.md


no changes added to commit (use "git add" and/or "git commit -a")

正是说明了我刚才加的还在工作区,还没add到暂存区。它也提示我们 use "git checkout -- <file>..." to discard changes in working directory

 
正是这个命令:git checkout -- file来撤销一个文件的修改。注意一定要加
 -- 。不然就是创建分支了。后面我们会讲到。
 

$ git checkout -- readme.txt
 
我们试一下:

 

$ git checkout -- README.md
$ git status
On branch master
nothing to commit, working directory clean

$ vi README.md
Git is a distributed version control system.
Git is free software. it is a good tool. distributed under the GPL.
Git has a mutable index called stage.
Git tracks changes.

OK,恢复到修改之前了。
 
已经add加到暂存区
 
第二种情况,就是手贱了,已经加到暂存去了。咋搞呢。也好搞
 
还是刚才这个例子,已经add 到暂存区了:
 

$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)


        modified:   README.md

提示我们已经加到暂存区了,准备提交。
 
我们如果到了这一步,我们也不用慌,我们肯定有办法的,你看,方法不是已经告诉你了嘛,上面仔细看:use git reset HEAD <file>.. to unstage
 
命令git reset HEAD file命令,可以把暂存区的修改撤销掉(unstage),重新放回工作区。这个命令同样可用来回退版本,之前第三篇已经讲过了:git
 reset --hard commit_id(id前7位)或者 git reset --hard HEAD^来回退版本。当我们用HEAD时,表示最新的版本。
 
好,我们来试一下:
 

$ git reset HEAD README.md
Unstaged changes after reset:
M       README.md

ok,提示我们撤销unstage成功。我们再看下status
 

$ 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:   README.md


no changes added to commit (use "git add" and/or "git commit -a")

非常完美,已经撤销到工作区了。那你如果也想工作区里的也撤销咋搞。那就是前面的第一种情况了,一步步的来:
 

$ git checkout -- README.md
$ git status
On branch master
nothing to commit, working directory clean

$ vi README.md
Git is a distributed version control system.
Git is free software. it is a good tool. distributed under the GPL.
Git has a mutable index called stage.
Git tracks changes.
如果,你更手贱,已经commit到master分支了。擦得。这样就更悲剧了。但是方法也有的,就是前面讲的回退了。我还是说一下吧,免得你记不住:
 
$ git reflog
29e9c55 {1}: commit: xiaowang is sb
a2f0cbc {2}: commit: git tracks changes
b4a73ed {3}: commit: modify README.md and add a new LICENSE file
c790395 {4}: reset: moving to c790395
0e87e34 {5}: reset: moving to HEAD^
c790395 {6}: reset: moving to c790395
0e87e34 {7}: reset: moving to HEAD^
c790395 {8}: commit: add GPL
0e87e34 {9}: commit: it is a good tool
4b86146 {10}: commit: modify a line
c96a8e5 {11}: commit (initial): write a new readme.md file

$ git reset --hard a2f0cbc
HEAD is now at a2f0cbc git tracks changes

ok。恢复了。
 
要是你用push 命令推送了远程服务器,抱歉,各种记录已经推送到远程了。小王要知道了,估计就马上打屎你了。阿门!
 
 
删除文件
 
删除文件同样是很常见的场景,我们可以将一个文件在版本库你删除,同样如果是不小心删除了,也可以恢复。
 
比如,我们新建一个文件test.txt文件,来用于演示我们删除要求。
 


$ vi test.txt
this file is will delete
然后我们将其添加到版本库:
 
$ git add test.txt
$ git commit -m "test.txt"
[master 4b8661a] test.txt
 1 file changed, 1 insertion(+)
 create mode 100644 test.txt

然后,我们手动将其删除:
 

$ rm test.txt
$ git status
On branch master
Changes not staged for commit:
  (use "git add/rm <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)


        deleted:    test.txt


no changes added to commit (use "git add" and/or "git commit -a")

我们已经捕捉到text.txt被删除了。如果我们是确认删除,我们可以用git rm file这个命令删掉,并且git commit -m "msg"提交确认。如果你没有用git rm 命令,直接commit会提示,而且会提交不成功。

 

$ git rm test.txt
rm ‘test.txt‘
$ git commit -m "delete test"
[master f6a084e] delete test
 1 file changed, 1 deletion(-)
 delete mode 100644 test.txt

好。ok就删除掉了。
 
如果你后悔了不想删除,一种是还没commit,用上面知道的修改撤销就可以搞定。

$ git checkout -- test.txt
一种是已经commit到分支了的,就只能借助于版本回退了:
$ git reset --hard HEAD^
好了。搞定。
 
本节总结
 
这一节,主要是对git的暂存区和工作区,进行了剖析,很详细,总结下:
 
1. 暂存区是Git非常重要的概念,弄明白了暂存区,就弄明白了Git的很多操作到底干了什么。
2. git 管理的是修改,不是文件,所以commit只会提交已经add的暂缓区的修改
3. 修改:当你改乱了工作区某个文件的内容,想直接丢弃工作区的修改时,用命令git checkout -- file

4 .修改:当你不但改乱了工作区某个文件的内容,还添加到了暂存区时,想丢弃修改,分两步,第一步用命令git reset HEAD file,在用git checkout -- file

5. 修改:已经提交了不合适的修改到版本库时,想要撤销本次提交,要用 git reset -- hard commit_id 来版本回退

6. git rm用于你确认删除一个文件

 

git

相关推荐