git暂缓区工作区原理和修改删除等命令
Posted zst062102
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了git暂缓区工作区原理和修改删除等命令相关的知识,希望对你有一定的参考价值。
前言:
在前面几篇,特别是第(3)篇已经详细的说了几个很重要也很常见的命令了。这一节接着说。同样也是参考了这本书:
http://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000
工作区和暂存区的关系及区别
前面我们多次提到命令git status命令,他的一些状态变化,其实都与现在我们将要说的工作区和暂存区有关,再说这个之前呢,我们先来理清楚几个名词概念,会更好理解工作区和暂存区。
工作区
工作区(working Directory),就是我们项目的目录,也就是我们例子中的learngit 目录,这就是我们所说的工作区,比较简单。如下图所示:
这个目录就是一个工作区,我们需要版本的控制的文件都放到这个文件夹下面。
版本库
版本库(Repository) ,工作区有一个隐藏目录“.git”,如上图所示,这个目录不算工作区,而是Git的版本库。我们打开这个.git文件夹,里面有很多文件:
其中最重要的就是称为stage(或者叫index)的暂存区,还有Git为我们自动创建的第一个分支master,以及指向master的一个指针叫HEAD。
暂缓区
我们先来看一张图,用来区分工作区和暂缓区以及分支的概念:
上图中,工作区就是我们的本地目录,也就是learngit目录,stage就是暂缓区,master分支就是主分支。
我们先把这三个关系说一下,然后我们再具体的例子来说明:
前面讲了我们把文件往Git版本库里添加的时候,是分两步执行的:
第一步是用“git add”把文件添加进去,实际上就是把文件修改添加到暂存区;
第二步是用“git commit”提交更改,实际上就是把暂存区的所有内容提交到当前分支。
因为我们创建Git版本库时,Git自动为我们创建了唯一一个master分支,所以,现在,commit就是往master分支上提交更改。
你可以简单理解为,需要提交的文件修改通通放到暂存区,然后,一次性提交暂存区的所有修改。
第一步是用“git add”把文件添加进去,实际上就是把文件修改添加到暂存区;
第二步是用“git commit”提交更改,实际上就是把暂存区的所有内容提交到当前分支。
因为我们创建Git版本库时,Git自动为我们创建了唯一一个master分支,所以,现在,commit就是往master分支上提交更改。
你可以简单理解为,需要提交的文件修改通通放到暂存区,然后,一次性提交暂存区的所有修改。
写个例子
好,现在我们来写个例子来说明下工作区,暂存区以及分支之间的关系。我们主要是用git status这个命令,来查看。
我们先来修改一个README.md文件,加一行内容:Git has a mutable index called stage.
-
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.
然后,在工作区,也就是learngit 目录下,新增一个LICENSE文本文件(内容随便写)。我们拷贝一段apache的:
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中。
tonyyang@021ZJ1315 /d/learngit (master) $ git add README.md tonyyang@021ZJ1315 /d/learngit (master) $ git add LICENSEok,之前说过没有任何输出代表成功了。现在就是将工作区(working Directory)的代码提交到了暂存区(stage),所以这一步的操作,我们画图就是这样:
ok,添加到暂存区之后,我们再来git status这个命令查看下,状态是啥样。
tonyyang@021ZJ1315 /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 LICENSEok,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管理的是修改,当你用“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.mdok,提示我们撤销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 HEAD@{1}: commit: xiaowang is sb a2f0cbc HEAD@{2}: commit: git tracks changes b4a73ed HEAD@{3}: commit: modify README.md and add a new LICENSE file c790395 HEAD@{4}: reset: moving to c790395 0e87e34 HEAD@{5}: reset: moving to HEAD^ c790395 HEAD@{6}: reset: moving to c790395 0e87e34 HEAD@{7}: reset: moving to HEAD^ c790395 HEAD@{8}: commit: add GPL 0e87e34 HEAD@{9}: commit: it is a good tool 4b86146 HEAD@{10}: commit: modify a line c96a8e5 HEAD@{11}: commit (initial): write a new readme.md file $ git reset --hard a2f0cbc HEAD is now at a2f0cbc git tracks changesok。恢复了。
要是你用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暂缓区工作区原理和修改删除等命令的主要内容,如果未能解决你的问题,请参考以下文章