【Git】Git指令学习与其原理探究(一)

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/Always__/article/details/51693203
这篇文章记录我学习Git的过程中遇到的问题及对于某些问题的看法,如有错误,还望不吝赐教!
ps:这篇文章介绍本地库,下篇将介绍与远程库的交互。

Git是什么 & 为什么要有Git?

    既然您能看到这篇文章,相信你对Git也有了一点点的了解,或者您本来就是大神,来观望下博主而已。
    言归正传,那么到底什么是Git呢!

    Git是目前世界上最先进的分布式版本控制系统(没有之一)。

    Git有什么特点?简单来说就是:高端大气上档次!

    那么什么是版本控制系统呢?:所谓的版本控制系统呢,简单来说就是你写的一个小项目,经过多次修改,你发现这和你原本的意愿越走越远,此时就想退回原来未修改前版本代码,但是你发现这可不是一件简单的事,然后你想有没有一种工具能让我在写的各个版本的源代码之间随意切换,满足我的要求,那岂不是太爽了。这个需求linus帮你完成了,没错还是这个人。两周时间自己用C写了一个分布式版本控制系统,这就是Git!一个月之内,Linux系统的源码已经由Git管理了!牛是怎么定义的呢?大家可以体会一下。

    Git迅速成为最流行的分布式版本控制系统,尤其是2008年,GitHub网站上线了,它为开源项目免费提供Git存储,无数开源项目开始迁移至GitHub,包括jQuery,PHP,Ruby等等。


SVN与Git的最主要的区别?


      SVN也是一种版本控制系统,不过它是集中式版本控制系统,版本库是集中放在中央服务器的,而干活的时候,用的都是自己的电脑,所以首先要从中央服务器哪里得到最新的版本,然后干活,干完后,需要把自己做完的活推送到中央服务器。集中式版本控制系统是必须联网才能工作,如果在局域网还可以,带宽够大,速度够快,如果在互联网下,如果网速慢的话,就纳闷了。

      Git是分布式版本控制系统,那么它就没有中央服务器的,每个人的电脑就是一个完整的版本库,这样,工作的时候就不需要联网了,因为版本都是在自己的电脑上。既然每个人的电脑都有一个完整的版本库,那多个人如何协作呢?比如说自己在电脑上改了文件A,其他人也在电脑上改了文件A,这时,你们两之间只需把各自的修改推送给对方,就可以互相看到对方的修改了。


Git是如何工作的?

首先看张图吧



图中是我们经常使用的几个命令,接下来我将根据图中的命令详细介绍各个部分。远程仓库,本地仓库,工作区和暂存区的功能以及他们如何协调工作的。


Git本地仓库:

    git的本地仓库主要有两部分:



工作区(WorkSpace)就是存放你实际文件的地方,主要保存些你的代码,文件夹等,你在这个目录下操作自己的文件,这些文件都是最后你要上传到远程仓库的。

      版本库(.git): 这个文件夹是你自己创建的目录,具体操作请自行百度。版本库又名仓库,英文名repository,你可以简单的理解一个目录,这个目录里面的所有文件都可以被Git管理起来,每个文件的修改,删除,Git都能跟踪,以便任何时刻都可以追踪历史,或者在将来某个时刻还可以将文件”还原”,满足你的需求。当我们通过git init命令将一个目录编程git可以管理的仓库时,这个目录下就会生成一个隐藏的.git文件夹,这就是git的根本,git就是通过这个文件夹来完成我们的指令操作。.git目录下还存在好多目录,下面我们将介绍下上图中的几个比较重要的目录,有的是文件。


1.objects目录存放的是实际的文件,当git add命令执行的时候,文件已经被存到了objects目录下。

.git/objects目录下的对象都有一个40位的id,前两位作为目录名,后38位作为文件名,您可以自行查看下,这些对象主要是commit对象和tree对象(目录树)。


2.index是一个索引文件。存放的是暂存区的整个目录树的信息,并且为目录树中的每个文件都保存了时间戳和长度。

当git add 将某个文件添加到暂存区的时候,index文件中添加了这个文件的基本信息。

当我们修改了工作区的某个文件(比如用touch config.js修改时间戳信息),这会导致该文件的时间戳发生变化,而index里面存放的仍然是旧的信息。

此时当我们执行git status命令来检查版本库的状况:

a. git status就会用config.js的时间戳和长度和index文件里面保存的config.js的时间戳和长度进行比较。

b. 如果相同,则认为没有改变。

c. 如果发现不同。git status会继续用config.js的文件现在的内容和旧版本的config.js(保存在.git/objects中)的内容进行比较。

d. 如果内容没有改变,就简单的将最新的config.js的时间戳信息更新到index文件中

e. 如果内容改变,则提示内容发生改变。但是并不更新index文件中的config.js的时间戳信息。

由于优先比较时间戳和长度,避免了当时间戳相同时的文件内容的比较,因此性能比较高。


因此,git add命令会做两件事情:

a.添加文件到暂存区(.git/objects)

b.添加文件索引到(.git/index)


3.当git commit被成功执行后,会产生一系列对象表示该commit的结果,都存储在.git/objects目录下。主要分成三部分:

a.tree对象表示当前commit时候的暂存区的目录树,tree对象的内容来自于.git/index文件。

b.blob对象

tree对象目录树中的文件总是以blob的对象被保存。如果tree中有三个文件,那么就有对应的三个blob对象,它们都能通过tree对象保存的这些blob对象的摘要信息(id,文件名,类型等)找到

c.commit对象

该对象记录了属于哪个tree对象,上一次commit的对象id,自己的id,作者等等。


因此,当git commit操作执行的时候,会:

a. 用.git/index文件保存的目录树创建tree对象,

b. 因此tree对象里面自然就指向了已经被git add添加到.git/objects中的blob文件。

c. .git/refs/heads/master文件保存了这次commit的id


4.HEAD文件保存了当前的branch,也就是说HEAD指向了master分支,如果存在多个分支,HEAD也可指向别的分支。


5. .git/refs 目录称为引用目录

引用就是一个文件,里面包含了一个commit id。.git/refs保存了所有的引用。

.git/refs/heads目录下保存的是分支引用,比如./git/refs/heads/master文件就是master分支的引用。

.git/refs/tags目录保存了tag引用。    


下面介绍一下上面所说的三个属于git的对象,它们的组成如图所示


如上是三个git的对象,那么他们是如何组织的呢,如下图:


下面我们将更具一次具体的操作来分析一下,常用指令的工作原理。

还是先上图:



当我们通过git add命令将文件添加到暂且区的时候,git add会做两件事

    1,添加文件到暂存区(.git/objects),保存实际文件的内容(修改后)

    2,index保存文件索引。

然后git commit将暂存区的文件提交时会存在上面说过的情况,

    a. 用.git/index文件保存的目录树创建tree对象,

    b. 因此tree对象里面自然就指向了已经被git add添加到.git/objects中的blob文件。然后就可以直接提交。

    c. .git/refs/heads/master文件保存了这次commit的id。

这就是add,commit命令的工作原理。上述c选项保存的id就是提供以后返回某个版本的根据。


下面我们学习常用的命令:

    git add 用于提交文件从working directory到index area

    git commit用于提交文件从stage area到history(版本库)

    git commit -a用于提交文件直接从working directory到history

    git reset用于撤销文件与git commit过程相反

    git checkout用于撤销文件与git add过程相反

    git status:可以列出当前目录所有还没有被git管理的文件和被git管理且被修改但还未提交(git commit)的文件。

    git diff命令:



git diff用于区别某一文件在working directory与stage area的区别

    git diff --cached用于区别某一文件在stage area与history的区别

    git diff HEAD用于区别某一文件在working directory与history的区别

     git log命令显示从最近到最远的显示日志。
     git reset  –hard HEAD^返回上个版本。
     git reflog 获得版本号。
     git reset  –hard 版本号 :会退到此版本之后的版本。
     git checkout  — file 可以丢弃工作区的修改。
     git commit -m "代码提交信息"

    命令 git checkout –readme.txt 意思就是,把readme.txt文件在工作区做的修改全部撤销,这里有2种情况,如下:

    1. readme.txt自动修改后,还没有放到暂存区,使用 撤销修改就回到和版本库一模一样的状态。
    2. 另外一种是readme.txt已经放入暂存区了,接着又作了修改,撤销修改就回到添加暂存区后的状态。

    对于第二种情况,我想我们继续做demo来看下,假如现在我对readme.txt添加一行 内容为6666666666666,我git add 增加到暂存区    后,接着添加内容7777777,我想通过撤销命令让其回到暂存区后的状态。如下所示:



 到此,本地库的探究就结束了,博主也是根据网上资料分析得出的这些点,难免有错误,还望指出,另外对于有的问题,涉入到git的原理,如若深剖,则也不是一两句就能说清的,有兴趣的读者可以参考下分享的资料,自行研究。


参考资料:

Git 内部原理 - Git 对象:https://git-scm.com/book/zh/v1/Git-%E5%86%85%E9%83%A8%E5%8E%9F%E7%90%86-Git-%E5%AF%B9%E8%B1%A1

git零基础深入浅出:http://blog.csdn.net/irean_lau/article/details/51661572#comments

手把手教你使用git:http://blog.jobbole.com/78960/


展开阅读全文

没有更多推荐了,返回首页