首先必须说明的是, 这篇文章不是阐述GIT原理性和比较深入的文章。只是对于日常开发中比较常用的需求的总结和GIT 这些命令大体的原理解释。所以掌握这个只能说能够应付一定的开发需求。但是如果你是个追求极值和完美的人。应该 再去了解下GIT具体的模型和实现细节。需要说明的是, 技术性东西,得先入门再深入理论,这很重要,入门可以让你不断 的进行实践,加深理解,而不是纸上谈兵,看着理论无从下手。GIT的应用我们主要掌握GIT中团队开发协助的常用命令和 场景。在这之前,我们需要先介绍一些必备概念。
A、基本概念
一、Repository
repository, 使用过SVN的应该都知道,这是版本库。何为版本库,简单理解就是用来存储和检索数据的一个仓库,只不过我们 用它来存储代码,来实现团队开发中的代码共享,以此来实现协同工作。简单的所就是用来保证,一个软件项目中的代码同步。
在GIT中的版本库一般有两个, 一个是本地版本库,一个是服务器版本库(共享版本库)。这是因为GIT本身就是设计为非集中式(分布式) 版本控制器,其优点就是,当你没有网络的时候,你不用依赖于服务器版本库(共享版本库)。想一下,你使用SVN的时候, 可以不用联网吗?如果希望一个项目交由GIT来管理,那么应该再该项目所在的同级目录中有一个.GIT文件夹,该文件夹里存放的就是 本地版本库,这时候,当你没有网络的时候,可以在本地进行版本管理。再有网络连接时候, 再将本地版本库与共享版本库进行同步。
在GIT中,我们使用git init命令来创建初始化一个版本库。其会自动生产.GIT文件夹和对应的文件,这时候就能用GIT进行版本管理。 git init --bare 用在(共享版本库中),因为在共享版本库中, 我们不需要工程文件夹(即工作空间), 因为共享版本库,相当于一个存放 代码的服务器,不需要工作空间。
总而言之
- git init用在我们本地工作空间中需要进行管理的项目中。
- git init --bare用在创建共享版本库,用来于本地版本库进行同步,实现多人开发的版本库。
二、工作区
所谓的工作区, 就是你项目所在的文件夹里,都可以统称为工作区。
三、暂存区(stage、index)
该区域是用来保存要提交到本地版本库中的所有文件, 称为stage或index。当执行git commit指令时候,会一次性将该区域类的文件提交到 本地版本库。可以理解为相当于一个缓存区,用来缓存要交给本地版本库管理的文件。而要将文件加入暂存区域,需要 使用git add指令进行添加操作。也就是说要提交到本地版本库需要两步操作: git add + git commit。执行完这两条只是提交到了本地版本库, 只能自己来使用,要是在团队开发中,要需要执行git push提交到共享版本库.
四、HEAD指针
简而言之,这里的HEAD指针就是一个用来标识当前所在的版本。也就是我们是通过HEAD所指向的版本来确定 当前所在的版本,所以当我们进行版本切换的时候,进行的就是改变HEAD指针的指向。
B、基本操作
一、增
由GIT的模型我们知道,要交给本地仓库管理,我们必须先将其提交到stage中。再又stage提交到本地版本库中,我将这步操作归纳为增。以此来 于数据库中的增概念类比,方便学习。所以我们这里所谓的增加细分而来个分为向stage中增加,和向本地版本库中增加。需要明确的是本地版本库 的增, 是依赖于stage中的。具体的例子演示。
由于我们要模拟多人开发,所以先完成以下的准备工作。
准备工作
1.创建一个SWPTest文件夹,我们准备在该文件夹中创建A用户的工作空间,和共享代码库。
执行如下操作
- mkdir SWPTest
- cd SWPTest/
- mkdir AWorker sharedRep
2.创建共享版本库(模拟远程版本库)
- cd sharedRep
- git init --bare
3.用户A将服务器上版本库下载下来,准备工作。并加入.gitigonre忽略文件(用来过滤掉项目中不提交给 版本库进行管理的文件)。(记得在SWPTest根目录位置执行命令)
- cd AWorder
- git clone ../sharedRep/
- touch .gitignore // 在工作区创建了.gitignore文件
- open .gitignore
- git add .gitignore // 执行完这步, 将工作区的.gitignore文件提交到了暂存区(缓存区)
- git status -s // 查询的是工作区与暂存区的文件状态(文件状态的理解是重点)
- git commit -m "添加gitignore文件" // 执行完之后,一次性将暂存区的内容提交到本地版本库。此时暂存区清空。
然后向.gitignore文件中粘贴object-c的忽略信息。(Github上搜索gitignore)
总结:以上三小步,分别为服务器端的版本库的创建(1,2), 与客户端(3,)clone到本地(如果该工程没有gitignore文件, 最好自己加上, 并添加到本地版本库和服务端版本库(共享版本库))。
增总结(三种不同的添加)
- 1.向stage中增加(提交): git add <file> // <file>值的是要交给git管理的文件,上面第三步的最后一小步,就是stage添加
- 2.向本地版本库种增加(提交): git commit // 基于stage缓存
- 3.向共享版本库增加(提交): git push origin master // 将当前的暂存区的所有数据提交到共享版本库(远程版本库)
- 在执行完上面3个小步骤时候,你也可以立即将该文件同步到共享代码库,方便其它同事的使用。
- git push origin master // 提交到主分支
二、删
在进行删除模拟前,我们先做如下准备工作,创建a.m, b.m, c.m三个源文件。并准备将其交给本地版本库管理。 所以进行向stage添加操作。具体如下
- suweipeng:sharedRep sixleaves$ touch a.m b.m c.m
- suweipeng:sharedRep sixleaves$ git add *.m
- suweipeng:sharedRep sixleaves$ git status -s
- A a.m
- A b.m
- A c.m
- suweipeng:sharedRep sixleaves$
当查询当前暂存区的文件状态的时候,会发现,已经变成A(第一栏表示暂存区,第二栏表示工作区),表示已经添加到暂存区域, 状态为A(add)。接着我们开始研究删除。 通过模型,我们可以知道,git中又有三块存储文件的地方,分别是工作区、暂存区(stage)、分支。所以,我们应该 在学习之前就问自己一个问题,如果有删除操作,是针对哪块区域的。 我们通过具体操作来理解,如下(针对的缓存区和工作区一起删除)
- suweipeng:sharedRep sixleaves$ git rm a.m
- error: the following file has changes staged in the index:
- a.m
- (use --cached to keep the file, or -f to force removal)
- suweipeng:sharedRep sixleaves$ git rm -f a.m
- rm 'a.m'
- suweipeng:sharedRep sixleaves$ ls -al
- total 8
- drwxr-xr-x 6 sixleaves staff 204 7 21 16:43 .
- drwxr-xr-x 3 sixleaves staff 102 7 21 11:34 ..
- drwxr-xr-x 13 sixleaves staff 442 7 21 16:43 .git
- -rw-r--r--@ 1 sixleaves staff 836 7 21 15:59 .gitignore
- -rw-r--r-- 1 sixleaves staff 0 7 21 16:27 b.m
- -rw-r--r-- 1 sixleaves staff 0 7 21 16:27 c.m
- suweipeng:sharedRep sixleaves$
第一行的意思是将a.m这个文件从工作区,并在暂存区响应的文件中标记删除操作。但是提示出错, 根据提示,我们可以使用-f来强制执行。
在Git 2.0中已经支持一种更加容易理解的方式来进行文件的删除。
新方法:
现在我们直接使用系统自带的rm程序来删除,而不使用git rm。 步骤如下
- 使用rm删除工作区的文件。
- 使用git add <删除的文件名>将工作区的删除添加到暂存区。(删除工作区、暂存区中指定的文件)
- 使用git commit -m "删除文件b"。将文件从本地仓库中删除。(删除工作区、暂存区中件、本地版本库指定的文)
- 使用git push origin master. 则这时候,不仅可以将本地版本库中的文件删除,同时也将共享版本库中的文件删除。((删除工作区、暂存区中件、本地版本库、共享版本库指定的文件)。
也许你会想问,那么如果是已经提交到本地版本库中的文件呢?只是想将其从本地版本库中删除,是不能用这种新方法的,因为这种方法的前提你要删除工作区间的文件,并且让版本库中的也删除。那么如何应对这种需求,请看下面。
git rm剖析: 此时我们来验证git rm的作用区域,在验证的时候,我这边只剩下一个e.m文件,并且已经交给git管理。 此时再重新创建b.m与c.m并将其交给git管理。
具体分析: 首先怎么验证所git rm -f a.m删除的是这两个区域的呢?如果一个文件已经提交到版本库中,那么此时在使用该操作会不会影响版本库呢?答案是否定的,它只影响暂存区和工作区,也就是所只删除这两个区域的元素。验证思路很简单,我们创建一个文件z.m,然后将其提交给本地版本库进行管理,在提交的后,暂存区就清空了,所以此时只剩下版本库和工作区又这个文件,此时我们执行git rm,接着在同步到共享版本库,再另外一个员工的工作目录中clone下共享版本库,查看是否存在z.m。如果存在z.m,那么也就是所git rm是不会影响版本库的中已经存在的文件。
在AWorker的工作空间中,此时AWork的暂存区存在两个文件,将其提交到本地版本库中进行管理。并同步到共享版本库中。接着我们删除git rm删除其中b.m这个文件,由于此时暂存区没有存在该文件,工作区有所以git rm不会提示 错误。这时候假设git rm对本地版本库有影响,则我们再本地版本库同步到共享版本库,如果有影响,则此时的共享版本库就不会存在该文件。于是我们又在BWorker中进行git pull指令来验证。
AWorker
- suweipeng:sharedRep sixleaves$ git status -s
- A b.m
- A c.m
- suweipeng:sharedRep sixleaves$ git commit -m "添加b、c文件"
- [master b8e8cc9] 添加b、c文件
- 2 files changed, 0 insertions(+), 0 deletions(-)
- create mode 100644 b.m
- create mode 100644 c.m
- suweipeng:sharedRep sixleaves$ git push origin master
- Counting objects: 2, done.
- Delta compression using up to 4 threads.
- Compressing objects: 100% (2/2), done.
- Writing objects: 100% (2/2), 288 bytes | 0 bytes/s, done.
- Total 2 (delta 0), reused 0 (delta 0)
- To /Users/sixleaves/SWPTest/AWorker/../sharedRep/
- 97b6aa0..b8e8cc9 master -> master
- suweipeng:sharedRep sixleaves$ git rm b.m
- rm 'b.m'
- suweipeng:sharedRep sixleaves$ ls -l
- total 0
- -rw-r--r-- 1 sixleaves staff 0 7 21 17:27 c.m
- -rw-r--r-- 1 sixleaves staff 0 7 21 17:16 e.m
- suweipeng:sharedRep sixleaves$ git push origin master
- Everything up-to-date
- suweipeng:sharedRep sixleaves$
在BWorker中进行git pull指令,具体细节如下,可以看到BWorker工作区间在pull之后,存在b.m c.m e.m 所以我们可以得出结论git rm针对的只是工作区和暂存区域,当两个区域同时存在该文件的时候,进行删除 操作会出错,我们需要详细说明是不是要保存工作区的文件。
BWorker
- suweipeng:sharedRep sixleaves$ pwd
- /Users/sixleaves/SWPTest/BWorker/sharedRep
- suweipeng:sharedRep sixleaves$ git pull
- remote: Counting objects: 2, done.
- remote: Compressing objects: 100% (2/2), done.
- remote: Total 2 (delta 0), reused 0 (delta 0)
- Unpacking objects: 100% (2/2), done.
- From /Users/sixleaves/SWPTest/BWorker/../sharedRep
- 97b6aa0..b8e8cc9 master -> origin/master
- Updating 97b6aa0..b8e8cc9
- Fast-forward
- b.m | 0
- c.m | 0
- 2 files changed, 0 insertions(+), 0 deletions(-)
- create mode 100644 b.m
- create mode 100644 c.m
- suweipeng:sharedRep sixleaves$ ls -al
- total 8
- drwxr-xr-x 7 sixleaves staff 238 7 21 19:00 .
- drwxr-xr-x 3 sixleaves staff 102 7 21 17:18 ..
- drwxr-xr-x 15 sixleaves staff 510 7 21 19:00 .git
- -rw-r--r-- 1 sixleaves staff 836 7 21 17:18 .gitignore
- -rw-r--r-- 1 sixleaves staff 0 7 21 19:00 b.m
- -rw-r--r-- 1 sixleaves staff 0 7 21 19:00 c.m
- -rw-r--r-- 1 sixleaves staff 0 7 21 17:18 e.m
- suweipeng:sharedRep sixleaves$
最后分别针对这三个区域总结,如下
- 针对工作区域的删除: (如果文件是已经交给git管理)这种情况,也必须同步版本库,所以其实就是新方法的完整流程。如果是还没提交给git管理,此时直接是用rm删除即可。
- 针对暂存区域的删除(而不删除工作区): git rm <文件名> --cached
- 针对分支(版本库)的删除: 所谓的针对分支的删除其实是没必要的,因为每次提交的时候都会产生一个新版本。 如果出错,我们可以直接使用git reset 进行版本回退。所以如果你想做到针对版本库的删除效果,就只能使用版本回退。其它:
- 针对同时删除工作区域和暂存区域的: git rm -f <file>
三、改
需要明确的一点是,当你把文件交给git管理的时候,一旦你一修改一个文件(无论是换行还是空格都算),git就会追踪到此时文件发生了变化。也就是所此时你必须再每次改完后,add到暂存区,然后进行commit。总要的事要所三篇!!!每次修改完都必须add到暂存区,保持暂存区该份文件的最新状态,这样在commit之后,版本库中保存的才是我们修改的文件!!!。觉得改也就这个注意点,是比较简单的,所以具体的操作,可以常见官方文档。
所以我把改分为两种,一种是针对自己编程任务进行编码的"改"。一种是你需要从共享版本库种更新下来最新 代码的"改"。前者不在复述,后者简单说一下。
在git中,我们可以使用git pull来更新一个已经和共享版本库关联起来的本地版本库,和相应的工作区间。严谨点来说git pull = git fetch + merge。即一步是取数据,一步是合并数据,所以git pull可能会在合并时候产生数据冲突,后面会详细介绍产生冲突的解决方案。这边暂且掌握简单的更新操作即可。
四、查
所谓的查有两种,一种是查看版本记录。一种是查看暂缓区和工作区的中的文件差别,以此来判断时候要更新暂缓区的文件。
查看版本记录: 就是进行版本的查看(git log、git reflog)。前者是当前存在的可追溯的版本,后者是历史记录中存在的版本。一般如果我们要回退版本的话,使用git reflog会更方便,应该它可以查看到所有的版本的历史记录。
suweipeng:sharedRep sixleaves$ git log
commit 7f0486eda9bfcaaae56ec8382be580d446d854d3
Author: sixleaves <18649772243@163.com>
Date: Tue Jul 21 20:09:53 2015 +0800
添加了main.m
commit 97b6aa090388d0fc1b73eaeb615d86faf83807f7
Author: sixleaves <18649772243@163.com>
Date: Tue Jul 21 17:20:05 2015 +0800
删除文件b
commit ef1169ef156294cfd68ac10b568781ca9ab4a15c
Author: sixleaves <18649772243@163.com>
Date: Tue Jul 21 17:16:46 2015 +0800
添加了e文件
commit 4eb100209198d1f5c7bf914bdf9776795f7753f1
Author: sixleaves <18649772243@163.com>
Date: Tue Jul 21 17:15:00 2015 +0800
添加了b文件
suweipeng:sharedRep sixleaves$ git reflog
7f0486e HEAD@{0}: commit: 添加了main.m
97b6aa0 HEAD@{1}: reset: moving to 97b6aa0
b8e8cc9 HEAD@{2}: commit: 添加b、c文件
97b6aa0 HEAD@{3}: commit: 删除文件b
ef1169e HEAD@{4}: commit: 添加了e文件
4eb1002 HEAD@{5}: commit: 添加了b文件
a18151c HEAD@{6}: commit (initial): add gitignore file
suweipeng:sharedRep sixleaves$
查看工作区的文件状态:
git status 指令会去暂缓区中与工作区进行比较,如果是暂缓区不存在,而工作区存在的,则会显示两个?,表示还没提交给git进行管理。此时可以执行git add命令将其提交到暂缓区,此时暂缓区的文件状态,就变成了A,表示已经加入暂缓区,此时若在提交到本地版本库,则git就可以管理该文件了,所以此时再使用git status查询是没有结果的,因为此时暂缓区已经清空(在执行git commit后清空),而工作区中的文件已经交给git管理,并且没有发送变化。
suweipeng:sharedRep sixleaves$ git status -s ?? 1.m suweipeng:sharedRep sixleaves$ git add 1.m suweipeng:sharedRep sixleaves$ git status -s A 1.m suweipeng:sharedRep sixleaves$ vim 1.m suweipeng:sharedRep sixleaves$ git status -s A 1.m suweipeng:sharedRep sixleaves$ vim 1.m suweipeng:sharedRep sixleaves$ git status -s AM 1.m suweipeng:sharedRep sixleaves$ git add 1.m suweipeng:sharedRep sixleaves$ git status -s A 1.m suweipeng:sharedRep sixleaves$ git commit -m "添加1.m" [master f6378aa] 添加1.m 1 file changed, 1 insertion(+) create mode 100644 1.m suweipeng:sharedRep sixleaves$ git status -s suweipeng:sharedRep sixleaves$
如果修改了main.m文件,再进行查看此时,第二栏目就变成了红色的M,表示已经修改工作区的文件,而此时git中版本库里的文件和该文件不同,所以我们要将其同步,必须得先进行git add,此时文件状态由工作区的M变成了暂缓区的M,并且变成绿色,而工作区的M会消失。
此时可以使用git diff查看工作区和暂缓区中具体的变化。
suweipeng:sharedRep sixleaves$ touch 2.m suweipeng:sharedRep sixleaves$ git add 2.m suweipeng:sharedRep sixleaves$ vim 2.m suweipeng:sharedRep sixleaves$ git status -s AM 2.m suweipeng:sharedRep sixleaves$ git diff diff --git a/2.m b/2.m index e69de29..abe4786 100644 --- a/2.m +++ b/2.m @@ -0,0 +1 @@ +ddddd suweipeng:sharedRep sixleaves$
上图的意思是在变动后的文件种,新增加了一行ddddd
查总结
1.查询版本记录使用git log或者git reflog。
前者记录的是当前版本号的迭代顺序(可能会因为回退而覆盖)。
后者记录的是所有的历史版本记录。(后者包含前者)。
2.使用git status -s就可知道暂存区的数据是否是最新的,是否有文件没有添加进暂存取。
3.如果暂存区数据不是最新的,可以使用git diff必将查看变化的数据。
git diff中的格式说明
---: 表示变动前的文件(工作区文件)。
+++: 表示变动后的文件(暂存区文件)。
没有减号或加号的行表示没有变动的行。
-号的行表示第一个文件中删除的行,+号表示第二个文件中增加的行。
@@ -1,7 +1,7 @@这句话中的减号和加号分别表示第一个文件,和第二个文件。
文件状态总结:
补充: 暂存区的D和工作区的D的区别:
1.第一栏目的,也就是暂存区显示的是绿色的D,则表示该文件已经从工作空间
删除,删除标志提交到了暂存区,此时若再执行git commit就会将其从版本库种删除。
2.而红色的D,再第二栏目,表示工作空间上的文件已经被删除,但是删除操作还没有提交到暂存区。
只有提交到了暂存区才有机会,将其在git种删除。
颜色的红绿只是为了让你能迅速的分辨出暂存区和工作区的文件状态的修改状态。
这是第一篇GIT简要入门的文章,如果有疑惑的地方,可以给我留言,大家相互交流。后面的文章还会再介绍 git种的冲突解决等问题。