码迷,mamicode.com
首页 > 其他好文 > 详细

git详解

时间:2015-01-16 19:11:22      阅读:225      评论:0      收藏:0      [点我收藏+]

标签:git   分支   内部原理   详解   

Git详解

零、引入

之前在局域网搭建了Git环境,觉得Git的工作方式非常有效,在这里也做一个总结。

希望这篇文件也能帮助到开始学习Git的朋友,此文只介绍Git的相关知识,对于git的使用经验留在以后介绍。

 

一、使用方法

常用命令行

这里暂时不考虑分支的命令,将在下一节中具体介绍。下面的命令按照一般的操作流程的顺序一一介绍。 

命令

用法

作用

clone

git clone url repname

克隆一个git仓库

init

git init

初始化一个git仓库

status

git status

查看当前工作目录下的状态,一般会显示文件的变化情况

add

git add filename

将当前工作目录下的文件添加到stage(稍后会解释)

commit

git commit  - m “msg”

将当前stage中的内容存在一个新的commit中

push

git push origin master

将本地ref更新到远程服务端

pull

git pull

将远程仓库的变化合并到本地

 上面的这些命令,接下来通过情景的方式来介绍。

开发人员Jim进入项目开发团队,首先从Git远程库clone项目下来。Jim打开Bash或者其他git界面工具,Jim开始输入下面的命令行并执行。

技术分享

(这个例子中使用HTTP协议,局域网中安装了gitstack)

通过这个clone命令将远程端的prjx项目拷贝到了本地。这个时候出现了Prjx这个文件夹,在Prjx中会有有一个.git的文件夹(.git将在后面介绍Git内部原理的时候再进行介绍)。

好了,Jim已经有了当前远程端最新的项目。Jim开始开发,添加了一个非常不错的功能,由此引入了xxx.cpp文件。这个时候Jim打算将这个功能并入远程端,Jim使用git status查看了一下当前工作目录下的状态。

技术分享

然后使用git add xxx.cpp,将xxx.cpp文件加入了stage中。

Jim随后又使用git commit –m “new feature2.1”,将当前stage中的内容放入一个新的commit中。

Jim检测无误之后,决定将这一切提交到服务器上去。于是Jim便使用了git push origin master。这样一套流程就走完了。

第二天,Jim开始进行工作前,首先使用git pull将服务端最新的项目更新下来。

……

技术分享

此图便是使用git本地文件的变化图(此图来自“pro git”)。

我们在工作目录下行添加一个文件A,这个新加的文件处于一个untracked状态。如果此时我们使用git add 命令,文件A将直接进入stage。

但我们再去修改文件A后,文件A的这个变化,并未进入stage,在stage中的只是修改前的文件A。我们要将最新的文件A加入stage,还是使用git add。

使用git commit之后,stage中的内容被提交到新的commit中。


二、分支详解

分支基础

Git的分支概念是其中一个最为有用的功能。首先简单介绍与分支相关的几个命令。

命令

用法

作用

branch

git branch

查看当前所有的分支

branch

git branch branchname

创建一个新的分支

checkout

git checkout branchname

切换到指定分支

merge

git merge xxx

将分支xxx合并到当前分支

rebase

git merge br_a br_b

衍合操作

技术分享

此图是经过四次commit的master分支图。每一次commit,git会将master指针移动到最新的commit结点,比如当前的master处在C3。

技术分享

gitbranch br_1

当我们创建一个新的分支br_1时,git只是生成一个类似于master的新指针,并指向当前master指向的commit结点。由此可以发现其实对于git来说创建一个分支的开销非常小。

git内部会维护一个HEAD指针,这个指针存放的便是当前的分支指针,可以这里理解HEAD是当前分支指针的别名。

git checkout br_1,HEAD=br_1

git checkout master ,HEAD = master

 

合并merge

接下来是我们这一节的重点内容。

(1)首先我们切换到br_1之后,持续开发后又提交了两次。

gitcheckout br_1

gitcommit –m “C4”

gitcommit –m “C5”

技术分享

经过这些操作,分支流图就会变成上图所示情况,br_1指向C5,master仍旧停留在C3。

(2)经过测试,我们发现C4和C5是稳定有效的功能提交。我们打算将这两个提交合并到master中去。所以我们先切换到master。

gitcheckout master

gitmerge br_1

技术分享

我们可以发现,这个时候的合并只是简单的将master指针移动到br_1处。

接下来看一下比较复杂的合并。

(3)我们创建新分支br_2,在br_2分支流上提交C6,在br_1分支流上提交C7。

gitbranch br_2

gitcheckout br_2

gitcommit –m ”C6”

gitcheckout br_1

gitcommit –m “C7”

技术分享

执行完这些操作后,结果变成上图所示。

(4)我们开始将br_1合并到master

gitcheckout master

gitmerge br_1

技术分享

(5)接着再将br_2合并到master。

gitmerge br_2

技术分享

在C7处的master合并在C6处的br_2。结果就会变成上图所示。

 

衍合rebase

我们先来看实例,首先我们回到上一节的第四个步骤“(4)我们开始将br_1合并到master”

技术分享

当前我们的分支流图是上图所示。

现在我们合并br_2 和 master,使用衍合操作试试,效果会如何。

技术分享

这里git的做法是,br_2将当前的C6做一个补丁C6’直接打到master分支流上。最终结果就如上图所示。

衍合会放弃了当前的分支。所以在使用的时候要格外小心,比如分支br_2,已经提交到远程服务器,就不要使用衍合操作了。

 

三、内部原理

对于git的内部原理,我们可以打开.git文件夹。

技术分享

上面的文件和文件夹,我需要特别关注refs、objects和HEAD。

HEAD就是第二节中HEAD指针。

objects存放的便是git的文件快照。

refs存放的是git的分支指针。

 

文件快照

我们还是通过实例来介绍git的文件快照机制。

(1)我们在一个空的git本地仓库中,添加文件1.txt,在1.txt写入“HelloWorld”,保存后add到stage中。

gitadd 1.txt

打开.git/objects文件夹,发现出现了一个文件夹5e,而5e内部存放了一个文件1c309dae7f45e0f39b1bf3ac3cd9db12e7d689。

其实git对于一个文件的做法,便是将文件变化内容做特殊的hash(sha1)处理之后,截取头两个字母做文件夹名称,后38位做文件名称存放在objects文件夹中。上述的文件1.txt对应的文件快照名称是

5e1c309dae7f45e0f39b1bf3ac3cd9db12e7d689。

我们使用cat-file 命令查看一下这个文件快照里面的内容是什么。

gitcat-file –p 5e1c309dae7f45e0f39b1bf3ac3cd9db12e7d689

技术分享

输出内容便是Hello World,其实就是1.txt。

 

(2)修改1.txt,添加字符“Test Git”,再次add。按照上述方式,查看快照文件ff75b86b8ab9128431a56785d1f25ddf9965bf47。

技术分享

发现便是新的1.txt。

git对于文件便是如上操作存放起来的。

 

git文件树

(1)在commit之前我们先来看一下ref/head,发现里面什么都没有。

承接上面的操作,我们直接commit

gitcommit –m “C1”

再去看ref/head发现多了一个master文件。打开此文件后发现里面存放的是b87f30e98b7b31b48d281987b1fdf30b9b13ddbc。去object查找,发现它的存放方式和文件快照的存放是一样的。

(2)再使用cat-file

gitcat-file -p  b87f30e98b7b31b48d281987b1fdf30b9b13ddbc

技术分享

发现这个文件和之前的文件快照不太一样。里面存放的是一个tree。

(3)查看tree

技术分享

发现里面存放的是一个blob,而且是我们之前创建的1.txt,它对应的快照名称也是ff75b86b8ab9128431a56785d1f25ddf9965bf47。

为了更加形象展现git文件树,我们这边在做一些小操作。

 

(4)添加文件2.txt 并提交

git add 2.txt

git commit –m “C2”

我们来看一下当前的文件树。

master变成了a5791eb37be360b030e013fee532ffc276f32787。

技术分享

查看tree

技术分享

tree adc1c0e82bbc6ce4dc116d0c8dd52a7616432e7d下有两个blob节点,就是当前的两个文件。

现在我们用图来展示一下

技术分享

图3.1

我们看到,commit2处也就是master指针指向的地方是一个tree(adc1c0)该树有两个blob节点,分别是我们的1.txt和2.txt文件。这两个文件通过各自的40位的文件快照号就能具体找到这两个文件的内容。

 

git文件树和分支

我们再来回忆一下,分支的内容。

(1)在上面的基础上,我么再创建一个新分支br_1

git branch br_1

技术分享

图3.2

在创建分支对于git来说再简单不过,就是添加了一个新指针br_1,并指向当前节点commit2。我们在看一下ref/head文件夹,发现多了一个文件br_1。打开它和master对比一下。

技术分享

发现这两个文件内容是一模一样的。

(2)切换分支

git checkout br_1

技术分享 

图3.3

git将HEAD指向br_1,这样就完成了分支的切换。

我们打开HEAD文件,发现里面你内容由ref: refs/heads/master变成了ref: refs/heads/br_1。

 

四、总结

git的介绍先到这里。

此文如有纰漏,请多多包涵。

之后会带来一些关于git使用上的一些经验介绍。

 

 

git详解

标签:git   分支   内部原理   详解   

原文地址:http://blog.csdn.net/stan1989/article/details/42779597

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!