Git是一个分布式的版本管理工具,分布式肯定会涉及到远程通信,下面我们来了解一下Git的远程通信协议。分布式通信需要有应用协议,应用协议的实现包含编码,解码和远程传输的实现,Git支持四种应用协议,分别是Local,http,git,ssh。通过四种协议都可以手动搭建简单的git仓库私服。
Local协议(本地协议)
本地协议和分布式有什么关系呢?本地协议可以基于本地文件系统,或者共享(NFS)文件系统进行访问,来实现源码的一个共享,使用Local协议搭建Git私服是最轻松的,也是最简单的。我们可以在一个服务器中,专门建立一个文件夹进行共享,作为一个Git的私服,然后把我们的项目代码放进去,存储在文件夹中。开发人员就可以基于本地协议,直接访问文件夹,实现代码的推送和拉取,
优点:
简单,直接使用了现有的文件权限和网络访问权限,小团队小项目建立一个这样的版本管理系统是非常轻松的一件事。
缺点:
这种协议缺陷就是本身共享文件系统的局限,只能在局域网,而且速度也慢。
适应场景:
小团队,小项目临时搭建版本服务。
下面来演示一下使用Local协议搭建git私服。比如我们来使用目录 /tmp/git/local 作为git公共仓库,我们来在仓库中创建一个裸项目,名字为hello:
git init --bare hello.git
可以看到仓库没有类似.git 的文件夹目录,进入仓库后就是类似.git文件夹内容的目录,这样一个本地git私服就创建完了,非常简单。开发人员以及可以拉取和提交内容了。前提是能否访问得到这个目录。
我们不再将文件夹进行共享,直接在本机访问私服,直接创建目录,/tmp/git/user,然后克隆项目:
可以看到我们直接输入仓库的文件夹路径就能克隆下这个本地git仓库,我们来提交一个文件:
这时候再来一个开发人员,比如在 /tmp/git/user2 下面从新拉取代码加入开发:
我们可以看到,第二个同学在拉取代码的时候可以正常的把前面的人的代码拉取下来,这样两个人可以和谐的共同工作!通过上面可以看到,通过local协议创建git私服是非常的简单快速。这是在同一台电脑上演示,如果访问局域网的共享文件,按照正常的方法加上ip,访问共享文件夹即可。
上面除了可以使用文件夹路径的方式,还可以使用file协议,比如
git clone file:///D:/a/b/c.git
使用file协议的区别在于,在拉取代码的时候,file协议会对文件的元数据进行压缩,非file协议会把远程私服的objects文件夹全部拷贝下来,file协议拷贝的是git gc后的内容,来看下git gc前后的区别:
git gc来举个例子,例如我们新建了一个分支,并在分支上做了一些提交,但是切换回来后,并没有把新分支merge到主干上面,这时候发现新建的分支做了无用功,因此删除了,但是新分支做的提交的元数据依然存在,这时候可以通过 git gc 来删除无用的元数据。感兴趣可以试一下。
ssh协议
在Linux中,ssh协议是我们经常用到的。ssh属于Linux里面的一个通信协议,基于ssh在Linux中搭建私服,访问Git仓库是不需要做额外的配置的。只需要基于ssh的用户名密码即可。git 支持利用ssh 协议进行通信,这是绝大部分linux、uninx系统都支持的,所以利用该协议架设GIT版本服务是非常方便的。
优点:
首先SSH 架设相对简单、其次通过 SSH 访问是安全的,另外SSH 协议很高效,在传输前也会尽量压缩数据。
缺点:
权限体系不灵活,必须提供操作系统的帐户密码,哪怕是只需要读取版本。
适用场景:
团队、小项目、临时项目
下面来演示一下,我们在服务器192.168.65.135上面创建一个裸项目,
然后在另一台服务器192.168.65.137上面通过ssh协议,拉取代码:
git clone root@192.168.65.135:/tmp/git/hello.git
这种方式需要输入一次密码,注意,如果输入密码后显示下面的错误:
什么原因呢?原来代码服务器【192.168.65.135】上的git安装路径是/usr/git,不是默认路径,根据提示,在git服务器192.168.65.135上, 建立链接文件:
ln -s /usr/git/bin/git-upload-pack /usr/bin/git-upload-pack
再试就可以了。如果想再省事一点,不想输入密码,可以在代码服务器集中配置使用者的公钥,这样可以免密登录。首先在192.168.65.137开发服务器上生成公钥:
ssh-keygen -t rsa
公钥生成的位置在用户目录下的.ssh文件夹下面,我们来查看公钥内容:
cat ~/.ssh/id_rsa.pub
复制内容,到代码服务器的用户目录的.ssh文件夹下面的authorized_keys文件中,没有就新建:
这样就完成了免密码登录,我们再来从新克隆,就不用了要求输入密码了:
下面就可以在这个项目里提交和修改了!
http协议
Git http 协议实现是依懒WEB容器(apache、nginx)及cgi 组件进行通信交互,并利用WEB容器本身权限体系进行授权验证。在Git 1.6.6 前只支持http Dumb(哑)协议,该协议只能下载不能提交,通常会配合ssh 协议一起使用,ssh 分配提交帐号,http dumb提供只读帐号。1.6.6 之后git 提供了git-http-backend 的 CGI 用于实现接收远程推送等功能。
优点:
解决了local 与ssh权限验证单一的问题、可基于http url 提供匿名服务,从而可以放到公网上去。而local 与ssh 是很难做到这一点,比如实现一个类似github 这样的网站。
缺点:
架设复杂一些需要部署 WEB服务器,和https 证书之类的配置
适用场景:
大型团队、需要对权限精准控制、需要把服务部署到公网上去
哑协议最大的特点就是只读,不能够推送代码,只能够拉取。下面演示一下哑协议,首先还是使用上面创建的裸项目:
/tmp/git/hello.git
然后在仓库中加一个钩子,首先进入目录:
cd /tmp/git/hello.git/hooks
然后修改文件:
mv post-update.sample post-udpate
这个表示当有项目修改的时候,就会触发这个钩子,来看一下文件的内容:
文件显示执行了一个命令,这个命令是帮我们打包,然后生成web端能够访问的静态文件,其实就是生成了一些索引目录,如果是空项目,没有任何变化的时候,没有打过包,那么远程其实是无法通过http拉取代码的,我们现在来执行一下(进入hello.git文件夹执行即可):
git update-server-info
然后我们在仓库服务器上面安装一个Nginx(关于Nginx的学习,可以访问我的Nginx教程),访问效果如下:
下面来修改nginx的配置文件,首先配置使用root权限:
然后配置域名为:
git.demo.com
然后把root指定为git仓库的路径:
表示/tmp/git下面的所有git项目都可以访问,然后把index删掉:
这样一个简单的git服务配置就完成了,我们从新加载nginx,然后在本地从新配置一个host:
这时候我们来访问一下域名:
之所以访问不到,是因为它虽然是http协议,但是git本身并没有提供任何页面,我们可以通过http拉取代码,但是没有提供可供访问的页面,我们来直接拉取代码试试:
可以看到拉取代码是没问题的!不过哑协议只能拉取,无法提交。
哑协议只能拉取代码,但是http智能协议可以同时实现拉取和推送。 设置 Smart HTTP 一般只需要在服务器上启用一个 Git 自带的名为 git-http-backend 的 CGI 脚本。 该 CGI 脚本将会读取由 git fetch 或 git push 命令向 HTTP URL 发送的请求路径和头部信息,来判断该客户端是否支持 HTTP 通信(不低于 1.6.6 版本的客户端支持此特性)。 如果 CGI 发现该客户端支持智能(Smart)模式,它将会以智能模式与它进行通信,否则它将会回落到哑(Dumb)模式下(因此它可以对某些老的客户端实现向下兼容)。(智能协议使用不再演示)
git协议
git协议类似svn,本身会启动一个git进程。接下来我们将通过 “Git” 协议建立一个基于守护进程的仓库。 对于快速且无需授权的 Git 数据访问,这是一个理想之选。 请注意,因为其不包含授权服务,任何通过该协议管理的内容将在其网络上公开。如果运行在防火墙之外的服务器上,它应该只对那些公开的只读项目服务。 如果运行在防火墙之内的服务器上,它可用于支撑大量参与人员或自动系统(用于持续集成或编译的主机)只读访问的项目,这样可以省去逐一配置 SSH 公钥的麻烦。
Git 协议是非常容易设定的。 我们来以后台形式运行下面的命令,比如我们的git所有仓库的根目录为 /tmp/git:
nohup git daemon --reuseaddr --base-path=/tmp/git/ /tmp/git/ &
这样我们的git协议就配置好了,然后在仓库下面创建一个项目:
然后进入项目文件夹,新建一个文件git-daemon-export-ok:
在Git 工程下新建一个名为 git-daemon-export-ok 的文件放到 .git 目录下,表明该工程允许非授权访问。接下来我就可以从远程克隆项目了:
远程提交同样没问题:
这样通过git协议搭建私服就完成了!我们来看一下服务器上面的git守护进程:
当我们停掉这个进程的时候,git仓库也就无法访问了!