git概念和原理

来源:互联网 发布:uva 编程 编辑:程序博客网 时间:2024/04/30 15:06



工作区 Working Directory

电脑上能看到的目录即工作目录,比如:/e/git_repo/


版本库Repository

工作区有一个隐藏目录.git,这个不算工作区,而是git的版本库。
git的版本库里存了很多东西,其中最重要的就是称为stage(或者叫index)的暂存区,还有git为我们自动创建的第一个分支master,以及指向master的一个指针叫HEAD。构造参见上面的结构图。


暂存区 Storage

暂存区就是版本库中的一个区域,具体参见上面的结构图。


工作区、版本库、暂存区之间的关系

git工作的流程就是:
第1步,使用git add把文件从工作区添加到版本库中的暂存区,git add命令可以多次用;
第2步,使用git commit提交代码,就是把暂存区的所有内容提交到当前分支。
综上,需要提交的文件修改通通放到暂存区(可能有多次的git add),然后,一次性提交暂存区的所有修改到当前分支(git commit)。


分支

分支(branch)有什么用呢?假设你准备开发一个新功能,但是需要两周才能完成,第一周你写了50%的代码,如果立刻提交,由于代码还没写完,不完整的代码库会导致别人不能干活了。如果等代码全部写完再一次提交,又存在丢失每天进度的巨大风险。
现在有了分支,就不用怕了。你创建了一个属于你自己的分支,别人看不到,还继续在原来的分支上正常工作,而你在自己的分支上干活,想提交就提交,直到开发完毕后,再一次性合并到原来的分支上,这样,既安全,又不影响别人工作。


分支内部原理

1、如下图所示,版本的每一次提交(commit),git都将它们根据提交的时间点串联成一条线。刚开始是只有一条时间线,即master分支,HEAD指向的是当前分支的当前版本。

 

2、当创建了新分支,比如dev分支(通过命令git branch dev完成),git新建一个指针dev,dev=master,dev指向master指向的版本,然后切换到dev分支(通过命令git checkout dev完成),把HEAD指针指向dev,如下图。

3、在dev分支上编码开发时,都是在dev上进行指针移动,比如在dev分支上commit一次,dev指针往前移动一步,但是master指针没有变,如下:

4、当我们完成了dev分支上的工作,要进行分支合并,把dev分支的内容合并到master分支上(通过首先切换到master分支,git branch master,然后合并git merge dev命令完成)。其内部的原理,其实就是先把HEAD指针指向master,再把master指针指向现在的dev指针指向的内容。如下图。

5、当合并分支的时候出现冲突(confict),比如在dev分支上commit了一个文件file1,同时在master分支上也提交了该文件file1,修改的地方不同(比如都修改了同一个语句),那么合并的时候就有可能出现冲突,如下图所示。


这时候执行git merge dev命令,git会默认执行合并,但是要手动解决下冲突,然后在master上git add并且git commit,现在git分支的结构如下图。

可以使用如下命令查看分支合并情况。

[cpp] view plain copy
  1. git log --graph --pretty=oneline --abbrev-commit  

6、合并完成后,就可以删除掉dev分支(通过git branch -d dev命令完成)。


如此,就是分支开发的原理。其好处也是显而易见的。


分支策略

如何合适地使用分支?

在实际开发中,我们应该按照几个基本原则进行分支管理:
1、master分支应该是非常稳定的,也就是仅用来发布新版本,平时不要在master分支上编码开发。master分支应该与远程仓库保持同步
2、平常编码开发都在dev分支上,也就是说,dev分支是不稳定的,到某个时候,比如1.0版本发布时,再把dev分支合并到master上,在master分支发布1.0版本;dev分支也应该与远程保持同步;(git push/git pull也要解决冲突)
3、你和团队成员每个人都在本地的dev分支上干活,每个人都有自己的分支,时不时地往远程dev分支上push/pull就可以了。(push/pull的时候是要解决冲突的.

上面这个图是大致示意图,其实上面这个图是省略了git push/git pull操作的,比如bob在本地dev分支上,新建了一个feature1分支干完活,在本地的dev分支上合并了feature1分支,然后要把dev分支push到公共服务器上,这样michael才能pull下来bob完成的内容。更详细一点的图如下:


PS:git本没有公共服务器的概念,git的每个节点都是一个完整的git库,但是公共服务器是方便了git节点之间的代码互相push/pull(要不然每个git节点都需要互相连接,每增加一个git节点就要连接其他的git节点)。如下图所示:

        

        有公共服务器的结构                             无公共服务器的结构

有公共服务器的,增加tom节点时候,只需要tom和公共服务器相连接,tom就可以取得(pull)michael提交(push,此处不是commit,commit是本地提交,没有推送到公共服务器)的代码,也可以取得bob提交(push)的代码。

如果没有公共服务器,tom要想取得(pull)michael的代码,则必须在tom和michael之间建立一个网络连接; 要想取得(pull)bob的代码,必须在tom和bob之间建立一个网络连接。