搭建自己的 Git 服务器

640?wx_fmt=jpeg


根据 RhodeCode[1] 在 2016 年做过的一项分析报告 Version Control Systems Popularity in 2016[2],在如今的 VCS(版本控制系统)领域,Git 几乎已经一统江山,在选择自己的 VCS 时,有 87% 的人会选择使用 Git,排在第二名的 SVN 只占 6%,无论是从 Google Trends,还是在 Stack Overflow 上的提问,都可以看到 Git 的爆发式增长。另外,根据 Eclipse 的社区调查 (Eclipse Community Survey),在 2010 年前后,SVN 的使用率都远超其他几款 VCS,从 2010 年开始,SVN 的使用率开始快速下滑,相应的,Git 的使用率快速上升,并在 2014 年超过了 SVN。 
640?wx_fmt=jpeg
现在,Git 已经成为了程序员的必备技能,越来越多的企业开始采用 Git。在开源的世界里,GitHub 是程序员聚集的狂欢之地,但这并不适合企业的私有项目,虽然 GitHub 也支持创建私有项目,但是搭建一个自己的 Git 服务器在很多时候可能是更好的选择,这篇博客将介绍并学习几种搭建 Git 服务器的方法。
Git 支持四种不同的传输协议:本地协议(Local)、HTTP(S) 协议、SSH(Secure Shell)协议以及 Git 协议,这四种协议在不同的场合有不同的用途,并且各有利弊,可以根据实际情况来选择。
一、本地协议

640?wx_fmt=png


本地协议是 Git 最基本的协议,当我们想在本地做一些 Git 实验时,这将非常有用。我们首先建立两个目录:/git/repo 和 ~/working,前者作为远程版本库,后者作为本地工作目录。
 
  
  1. aneasystone@little-stone:~$ sudo mkdir -p /git/repo

  2. aneasystone@little-stone:~$ sudo git init --bare /git/repo/test.git

  3. 已初始化空的 Git 仓库于 /git/repo/test.git/


我们在 /git/repo 目录通过 git init --bare 命令创建一个裸仓库(bare repository,即一个不包含当前工作目录的仓库),只要这一步,我们就可以开始使用了。接着我们在工作目录 clone 这个版本库:
 
  
  1. aneasystone@little-stone:~$ cd ~/working/

  2. aneasystone@little-stone:~/working$ git clone /git/repo/test.git

  3. 正克隆到 'test'...

  4. warning: 您似乎克隆了一个空仓库。

  5. 完成。


然后我们可以使用 pull、push 就像操作其他的版本库一样。
 
  
  1. aneasystone@little-stone:~/working$ cd test/

  2. aneasystone@little-stone:~/working/test$ touch 1

  3. aneasystone@little-stone:~/working/test$ touch 2

  4. aneasystone@little-stone:~/working/test$ git add .

  5. aneasystone@little-stone:~/working/test$ git commit -m 'first commit'

  6. [master (根提交) 4983f84] first commit

  7. 2 files changed, 0 insertions(+), 0 deletions(-)

  8. create mode 100644 1

  9. create mode 100644 2

  10. aneasystone@little-stone:~/working/test$ sudo git push

  11. [sudo] aneasystone 的密码:

  12. 对象计数中: 3, 完成.

  13. Delta compression using up to 8 threads.

  14. 压缩对象中: 100% (2/2), 完成.

  15. 写入对象中: 100% (3/3), 205 bytes | 205.00 KiB/s, 完成.

  16. Total 3 (delta 0), reused 0 (delta 0)

  17. To /git/repo/test.git

  18. * [new branch]      master -> master


本地协议不仅在做 Git 实验时很有用,如果你的团队有一个共享文件系统,可以在这个共享文件系统上创建一个远程版本库,团队成员把这个共享文件系统挂在本地,就可以直接使用本地协议进行协作开发,完全不需要搭建一台专门的 Git 服务器。
二、SSH 协议

640?wx_fmt=png


本地协议虽然简单,但是一般来说并不适用,因为你无法控制用户对共享文件系统的操作,用户拥有 push 权限也就意味着用户对远程目录拥有完整的 Shell 权限,他们有可能会无意甚至有意的修改或删除 Git 内部文件,损坏 Git 仓库。
更安全的做法是使用专门的 Git 服务器,如果你有一台可以使用 SSH 连接的服务器,搭建 Git 服务将会非常简单。首先我们要确保服务器上运行着 SSH 服务(sshd),大多数 Linux 服务器版本都默认包含了该服务,如果没有,可以先安装 openssh-server。然后在服务器上创建 Git 远程版本库:
 
  
  1. root@myserver:~# mkdir -p /git/repo

  2. root@myserver:~# git init --bare /git/repo/test.git

  3. 已初始化空的 Git 仓库于 /git/repo/test.git/


然后在本地 clone 这个版本库:
 
  
  1. aneasystone@little-stone:~/working$ git clone ssh://root@myserver/git/repo/test.git

  2. 正克隆到 'test'...

  3. root@myserver's password:

  4. warning: 您似乎克隆了一个空仓库。


可以看到和使用本地协议几乎一样,不同的地方在于,在 clone 的时候需要在 URL 前面加上 ssh://root@myserver,你也可以使用 scp 式的写法:
 
  
  1. $ git clone root@myserver:/git/repo/test.git


另外一点不同的地方是,每次 pull、push 的时候都需要输入远程服务器的 root 密码。很显然,让每个 Git 用户都使用 root 来访问服务器是一种很不安全的做法,有几种方法可以解决这个问题:
  • 最显而易见的方法是为每个 Git 用户创建一个独立的账号,并分别为他们分配对仓库的读写权限,这种方法行的通,但是对账号的管理非常麻烦,在团队人员不是很多的时候可以尝试,但是并不推荐;

  • 另一种方法是配置 SSH 服务器使用某个已有的认证系统来管理用户,比如 LDAP,这在很多企业中是很常见的,这样可以省去用 adduser 手工管理服务器账号的麻烦;

  • 还有一种方法是只创建一个账号,比如叫做 Git,他对仓库具有读写权限,大家都使用这个账号来访问仓库。这种方法的好处是用户管理起来比较简单,而且可以使用后面介绍的 authorized_keys 文件对用户的公钥进行管理。


下面我们尝试下第三种方法。首先在服务器上创建一个名叫 Git 的账号:
 
  
  1. root@myserver:~# adduser git

  2. Adding user `git' ...

  3. Adding new group `git' (1000) ...

  4. Adding new user `git' (1000) with group `git' ...

  5. Creating home directory `/home/git' ...

  6. Copying files from `/etc/skel' ...

  7. Enter new UNIX password:

  8. Retype new UNIX password:

  9. passwd: password updated successfully

  10. Changing the user information for git

  11. Enter the new value, or press ENTER for the default

  12.    Full Name []: git

  13.    Room Number []:  

  14.    Work Phone []:

  15.    Home Phone []:

  16.    Other []:

  17. Is the information correct? [Y/n] Y


再设置一下 Git 仓库的权限(默认情况下,Git 仓库的权限为 rwxr-xr-x,只有创建者 root 有写的权限,也就意味着使用 Git 账号只能 clone pull,不能 push):
 
  
  1. # chmod a+w -R /git/repo/test.git


我们这里非常粗暴的使用 chmod a+w 将 Git 仓库设置为对所有人可写,这里可以想一想,如果我们希望设置某些用户对仓库具有只读的权限,该怎么做呢?
然后就可以在本地愉快的进行 Git 操作了:
 
  
  1. $ git clone git@myserver:/git/repo/test.git


到这里似乎一切都很正常,但是几次实操之后你就会发现,每次 Git 操作都要输入一次密码,这也太麻烦了,能不能“免密提交代码”呢?首先我们要知道,只要能通过 SSH 登陆到服务器,我们就能操作 Git,所以如果 SSH 能支持免密登陆,我们就可以“免密提交代码”。还好,SSH 支持公钥认证,这种认证方式无需密码登陆。在 Linux 操作系统中,每个用户都可以拥有自己的一个或多个密钥对(公钥和私钥成对出现),这些密钥一般情况会保存在 ~/.ssh 目录下,在开始之前,我们先确认下自己是否已经生成过公钥了,可以看下这个目录下是否有 iddsa.pub 或 idrsa.pub 这样的文件,如果没有,我们通过 ssh-keygen 来生成:
 
  
  1. aneasystone@little-stone:~/.ssh$ ssh-keygen

  2. Generating public/private rsa key pair.

  3. Enter file in which to save the key (/home/aneasystone/.ssh/id_rsa):

  4. Enter passphrase (empty for no passphrase):

  5. Enter same passphrase again:

  6. Your identification has been saved in /home/aneasystone/.ssh/id_rsa.

  7. Your public key has been saved in /home/aneasystone/.ssh/id_rsa.pub.

  8. The key fingerprint is:

  9. SHA256:4Ulpufuhs/AgDMb0VXnqMUTw6bD/HrAOI2z9c1cod9I aneasystone@little-stone

  10. The key's randomart image is:

  11. +---[RSA 2048]----+

  12. |      .oo.       |

  13. |       oo+.      |

  14. |  .   o.Oo       |

  15. | o . . B++       |

  16. |  + . ..So   o   |

  17. | . + . ..+. + E  |

  18. |    * * + oo +   |

  19. |   . o Oo+.o.    |

  20. |        **+.     |

  21. +----[SHA256]-----+


这样我们在 ~/.ssh 目录生成了两个文件,idrsa 是你的私钥,idrsa.pub 是你的公钥。关于私钥和公钥的原理以及 RSA 加密算法等内容可以参考我之前写过的一篇介绍 HTTPS 和证书[3]的文章。
我们假设你的 Git 服务器是由专门的服务器管理员负责维护和管理,当你生成你的公钥之后,就可以给服务器管理员发送一封申请 Git 服务的邮件,并附上你的公钥。服务器管理员在收到你的申请之后,如果同意了,就可以进行下面的操作:
首先将公钥文件拷贝到服务器上:
 
  
  1. # scp id_rsa.pub root@myserver:/home/git


将公钥文件的内容追加到 Git 账户的 authorizedkeys 文件中(要注意的是,如果是第一次操作,/home/git 目录下是没有 .ssh 目录的,需要手工创建 .ssh 目录和 authorizedkeys 文件):
 
  
  1. root@myserver:/home/git# cat id_rsa.pub >> /home/git/.ssh/authorized_keys


后续如果有其他的用户申请 Git 服务,都可以按照这个步骤操作。一旦完成这个操作,服务器管理员将会回复你的邮件,通知你 Git 服务已经开通,这个时候你再进行 Git 操作就可以不用输入密码了。关于 SSH 的使用,更详细的步骤可以参考 GitHub 上的这篇指南:Connecting to GitHub with SSH[4]。
作为服务器管理员,关于 SSH 还有一点需要考虑,那就是 SSH 的安全问题。在上面介绍本地协议时,我们说这种方式无法控制用户对 Git 仓库的操作,无法防止用户有意或无意的损坏 Git 仓库,使用 SSH 协议一样存在这样的问题,用户能通过 SSH 拉取和提交代码,也就意味着用户可以通过 SSH 连接到服务器,对 Git 仓库进行任何操作,这是一件很让人担心的事情。
因此,我们还需要对 Git 账号做一些限制。默认情况下,我们新建账号的登陆 shell 是 /bin/bash,这个配置在 /etc/passwd 文件中:
 
  
  1. git:x:1000:1000:git,,,:/home/git:/bin/bash


可以使用 chsh 命令修改用户的登陆 shell,让他不能通过 SSH 访问服务器,怎么修改呢?我们可以看一下 /etc/shells 文件,这里定义了所有可以使用的登陆 shell,你可以将 /bin/bash 改成这里的任何一个:
 
  
  1. root@myserver:~# cat /etc/shells

  2. # /etc/shells: valid login shells

  3. /bin/sh

  4. /bin/dash

  5. /bin/bash

  6. /bin/rbash


很显然,这些 shell 并不是我们想要的,有没有一个 shell 只允许用户进行 Git 操作,而不允许其他操作呢?还好,Git 的软件包提供了一个名叫 git-shell 的登陆 shell,我们可以把他加进去,一般情况下位于 /usr/bin/git-shell。我们使用 chsh 修改 Git 的登陆 shell:
 
  
  1. root@myserver:~# chsh git

  2. Changing the login shell for git

  3. Enter the new value, or press ENTER for the default

  4.    Login Shell [/bin/bash]: /usr/bin/git-shell


这样当用户 Git 通过 SSH 连接服务器时,就会直接被拒绝了。
三、Git 协议

640?wx_fmt=png


SSH 协议解决了用户直接操作 Git 仓库的权限问题,但是如果我们希望对除仓库维护者之外的所有人都开放 Git 仓库的只读权限,这在开源项目中和企业内部往往是很常见的,任何人都可以去查看仓库的代码,这时管理员需要给每一个用户配置 SSH 密钥是非常麻烦的。虽然也可以使用变通的方法来达到这个效果,但是很繁琐,下面是具体的步骤:
  • 使用 g+w 设置 Git 仓库的权限,让仓库创建者所在的用户组具有写权限,而不是所有人都有写权限(这一步通常也可以在 git init 的时候加上 --shared 参数);

  • 然后将 Git 账号加到仓库创建者的用户组;

  • 再创建一个 git_ro 账户,这个账户对仓库只有只读权限;

  • 最后为 gitro 账户创建一个密钥对,把 gitro 的私钥公开出来供所有人使用。


可以看到使用 SSH 协议最终都逃不过授权这一步,而且公开私钥的做法也不是很优雅。实际上,Git 提供了另一种方式来让这个操作更简单,那就是 Git 协议。使用 Git 协议必须要在服务器上运行 Git 守护进程,Git 命令自带了一个 daemon 参数:
 
  
  1. root@myserver:~# git daemon --reuseaddr --base-path=/git/repo/ /git/repo/


上面的各个参数可以 参考 git-daemon[5] 的文档。git-daemon 会监听 9418 端口,如果你的服务器有防火墙,需要将该端口添加到白名单,如果你使用的是阿里云服务器,需要像下面这样添加一个安全组规则: 
640?wx_fmt=jpeg
为了让所有的用户都可以访问我们的仓库,还需要在仓库目录下创建一个名为 git-daemon-export-ok 的文件:
 
  
  1. root@myserver:~# cd /git/repo/test.git/

  2. root@myserver:/git/repo/test.git/# touch git-daemon-export-ok


至此,所有人都可以通过 Git 协议来克隆或拉取项目源码了(注意上面指定了 base-path 参数为 /git/repo/,所以 URL 可以直接写 git://myserver/test.git):
 
  
  1. aneasystone@little-stone:~/working$ git clone git://myserver/test.git


一般情况下,服务器管理员还会做一些其他的配置,譬如在服务器重启时让 Git 守护进程自动启动,这有很多种方式可以实现,可以参考《Pro Git[6]》 Git 守护进程这一节的内容。
四、HTTP(S) 协议

640?wx_fmt=png


我们一般通过 Git 协议进行无授权访问,通过 SSH 协议进行授权访问,如果你的项目是内部项目,只针对部分授权用户,那使用 SSH 协议就足够了,但是如果既需要授权访问也需要无授权访问,可能需要 SSH 协议和 Git 协议搭配使用,这在维护上成本很高。这时就到了我们的压轴戏 —— HTTP 协议出场的时候了,它同时支持上面两种访问方式。
通过 HTTP 协议访问 Git 服务是目前使用最广泛的方式,它支持两种模式:旧版本的 Dumb HTTP 和 新版本的 Smart HTTP,Dumb HTTP 一般很少使用,下面除非特殊说明,所说的 HTTP 协议都是 Smart HTTP。使用 HTTP 协议的好处是可以使用各种 HTTP 认证机制,比如用户名/密码,这比配置 SSH 密钥要简单的多,对普通用户来说也更能接受。如果担心数据传输安全,也可以配置 HTTPS 协议,这和普通的 Web 服务是一样的。
下面我们就来尝试搭建一个基于 HTTP 协议的 Git 服务器。《Pro Git》上提供了一个基于 Apache 的配置示例,如果你是使用 Apache 作为 Web 服务器,可以参考之,我们这里使用 Nginx 来作为 Web 服务器,其原理本质上是一样的,都是通过 Web 服务器接受 HTTP 请求,并将请求转发到 Git 自带的一个名为 git-http-backend 的 CGI 脚本。
首先我们安装所需的软件:
 
  
  1. # apt-get install -y git-core nginx fcgiwrap apache2-utils


其中,Nginx 作为 Web 服务器,本身是不能执行外部 CGI 脚本的,需要通过 FcgiWrap来中转,就像使用 php-fpm 来执行 PHP 脚本一样。apache2-utils 是 Apache 提供的一个 Web 服务器的工具集,包含了一些有用的小工具,譬如下面我们会用到的 htpasswd 可以生成 Basic 认证文件。
启动 Nginx 和 FcgiWrap,并访问 http://myserver 测试 Web 服务器是否能正常访问:
 
  
  1. # service nginx start

  2. # service fcgiwrap start


然后我们打开并编辑 Nginx 的配置文件(/etc/nginx/sites-available/default):
 
  
  1. location / {

  2.        include fastcgi_params;

  3.        fastcgi_param SCRIPT_FILENAME /usr/lib/git-core/git-http-backend;

  4.        fastcgi_param GIT_HTTP_EXPORT_ALL "";

  5.        fastcgi_param GIT_PROJECT_ROOT /git/repo;

  6.        fastcgi_param PATH_INFO $uri;

  7.        fastcgi_param REMOTE_USER $remote_user;

  8.        fastcgi_pass unix:/var/run/fcgiwrap.socket;

  9. }


这里通过 fastcgi_param 设置了一堆的 FastCGI 参数,如下:
  • SCRIPT_FILENAME:指定 CGI 脚本 git-http-backend 的位置,表示每次 HTTP 请求会被转发到该 CGI 脚本;

  • GITHTTPEXPORTALL:git-http-backend 默认只能访问目录下有 git-daemon-export-ok 文件的 Git 仓库,和上面介绍的 Git 协议是一样的,如果指定了 GITHTTPEXPORTALL,表示允许访问所有仓库;

  • GITPROJECTROOT:Git 仓库的根目录;

  • REMOTE_USER:如果有认证,将认证的用户信息传到 CGI 脚本;


改完之后我们重启 Nginx,并通过 HTTP 协议 clone 仓库:
 
  
  1. aneasystone@little-stone:~/working$ git clone http://myserver/test.git


4.1 开启身份认证
到这里一切 OK,但是当我们 push 代码的时候,却会报下面的 403 错误:
 
  
  1. aneasystone@little-stone:~/working/test$ git push origin master

  2. fatal: unable to access 'http://myserver/test.git/': The requested URL returned error: 403


为了解决这个错误,我们可以在 git-http-backend 的官网文档上找到这样的一段描述:
By default, only the upload-pack service is enabled, which serves git fetch-pack and git ls-remote clients, which are invoked from git fetch, git pull, and git clone. If the client is authenticated, the receive-pack service is enabled, which serves git send-pack clients, which is invoked from git push.
第一次读这段话可能会有些不知所云,这是因为我们对这里提到的 upload-pack、fetch-pack、receive-pack、send-pack 这几个概念还没有什么认识。但是我们大抵可以猜出来,默认情况下,只有认证的用户才可以 push 代码,如果某个 Git 仓库希望所有用户都有权限 push 代码,可以为相应的仓库设置 http.receivepack:
 
  
  1. root@myserver:/# cd /git/repo/test.git/

  2. root@myserver:/git/repo/test.git# git config http.receivepack true


当然最好的做法还是对 push 操作开启认证,官网文档上有一个 lighttpd 的配置我们可以借鉴:
 
  
  1. $HTTP["querystring"] =~ "service=git-receive-pack" {

  2.    include "git-auth.conf"

  3. }

  4. $HTTP["url"] =~ "^/git/.*/git-receive-pack$" {

  5.    include "git-auth.conf"

  6. }


这个配置看上去非常简单,但是想要理解为什么这样配置,就必须去了解下 Git 的内部原理。正如上面 git-http-backend 文档上的那段描述,当 Git 客户端执行 git fetch,git pull,and git clone 时,会调用 upload-pack 服务,当执行 git push 时,会调用 receive-pack 服务,为了更清楚的说明这一点,我们来看看 Nginx 的访问日志。
执行 git clone:
 
  
  1. [27/Nov/2018:22:18:00] "GET /test.git/info/refs?service=git-upload-pack HTTP/1.1" 200 363 "-" "git/1.9.1"

  2. [27/Nov/2018:22:18:00] "POST /test.git/git-upload-pack HTTP/1.1" 200 306 "-" "git/1.9.1"


执行 git pull:
 
  
  1. [27/Nov/2018:22:20:25] "GET /test.git/info/refs?service=git-upload-pack HTTP/1.1" 200 363 "-" "git/1.9.1"

  2. [27/Nov/2018:22:20:25] "POST /test.git/git-upload-pack HTTP/1.1" 200 551 "-" "git/1.9.1"


执行 git push:
 
  
  1. [27/Nov/2018:22:19:33] "GET /test.git/info/refs?service=git-receive-pack HTTP/1.1" 401 204 "-" "git/1.9.1"

  2. admin [27/Nov/2018:22:19:33] "GET /test.git/info/refs?service=git-receive-pack HTTP/1.1" 200 193 "-" "git/1.9.1"

  3. admin [27/Nov/2018:22:19:33] "POST /test.git/git-receive-pack HTTP/1.1" 200 63 "-" "git/1.9.1"


可以看到执行 clone 和 pull 请求的接口是一样的,先请求 /info/refs?service=git-upload-pack,然后再请求 /git-upload-pack;而 push 是先请求 /info/refs?service=git-receive-pack,然后再请求 /git-receive-pack,所以在上面的 lighttpd 的配置中我们看到了两条记录,如果要对 push 做访问控制,那么对这两个请求都要限制。关于 Git 传输的原理可以参考 《Pro Git》的 Git 内部原理 - 传输协议这一节。
我们依葫芦画瓢,Nginx 配置文件如下:
 
  
  1. location @auth {

  2.        auth_basic "Git Server";

  3.        auth_basic_user_file /etc/nginx/passwd;


  4.        include fastcgi_params;

  5.        fastcgi_param SCRIPT_FILENAME /usr/lib/git-core/git-http-backend;

  6.        fastcgi_param GIT_HTTP_EXPORT_ALL "";

  7.        fastcgi_param GIT_PROJECT_ROOT /git/repo;

  8.        fastcgi_param PATH_INFO $uri;

  9.        fastcgi_param REMOTE_USER $remote_user;

  10.        fastcgi_pass unix:/var/run/fcgiwrap.socket;

  11. }


  12. location / {

  13.        error_page 418 = @auth;

  14.        if ( $query_string = "service=git-receive-pack" ) {  return 418; }

  15.        if ( $uri ~ "git-receive-pack$" ) { return 418; }


  16.        include fastcgi_params;

  17.        fastcgi_param SCRIPT_FILENAME /usr/lib/git-core/git-http-backend;

  18.        fastcgi_param GIT_HTTP_EXPORT_ALL "";

  19.        fastcgi_param GIT_PROJECT_ROOT /git/repo;

  20.        fastcgi_param PATH_INFO $uri;

  21.        fastcgi_param REMOTE_USER $remote_user;

  22.        fastcgi_pass unix:/var/run/fcgiwrap.socket;

  23. }


其中相同的配置我们也可以用 include 指令放在一个共用的配置文件里,这样我们就实现了在 push 的时候需要填写用户名和密码了。我们通过 Nginx 的 authbasicuser_file 指令来做身份认证,用户名和密码保存在 /etc/nginx/passwd 文件中,这个文件可以使用上面提到的 apache2-utils 包里的 htpasswd 来生成:
 
  
  1. root@myserver:/# htpasswd -cb /etc/nginx/passwd admin 123456


另外,在 push 的时候,有时候可能会遇到 unpack failed: unable to create temporary object directory 这样的提示错误:
 
  
  1. aneasystone@little-stone:~/working/test$ git push origin master

  2. Counting objects: 3, done.

  3. Writing objects: 100% (3/3), 193 bytes | 0 bytes/s, done.

  4. Total 3 (delta 0), reused 0 (delta 0)

  5. error: unpack failed: unable to create temporary object directory

  6. To http://myserver/test.git

  7. ! [remote rejected] master -> master (unpacker error)

  8. error: failed to push some refs to 'http://myserver/test.git'


这一般情况下都是由于 Git 仓库目录的权限问题导致的,在这里 Git 仓库的根目录 /git/repo 是 root 创建的,而运行 nginx 和 fcgiwrap 的用户都是 www-data,我们可以把 Git 仓库目录设置成对所有人可读可写,也可以像下面这样将它的拥有者设置成 www-data 用户:
 
  
  1. root@myserver:/# chown -R www-data:www-data /git/repo


4.2 凭证管理
上面我们站在管理员的角度解决了用户身份认证的问题,但是站在用户的角度,每次提交代码都要输入用户名和密码是一件很痛苦的事情。在上面介绍 SSH 协议时,我们可以使用 SSH 协议自带的公钥认证机制来省去输入密码的麻烦,那么在 HTTP 协议中是否存在类似的方法呢?答案是肯定的,那就是 Git 的凭证存储工具:credential.helper。
譬如像下面这样,将用户名和密码信息保存在缓存中:
 
  
  1. $ git config --global credential.helper cache


这种方式默认只保留 15 分钟,如果要改变保留的时间,可以通过 --timeout 参数设置,或者像下面这样,将密码保存在文件中:
 
  
  1. $ git config --global credential.helper store


这种方式虽然可以保证密码不过期,但是要记住的是,这种方式密码是以明文的方式保存在你的 home 目录下的。可以借鉴操作系统自带的凭证管理工具来解决这个问题, 比如 OSX Keychain 或者 Git Credential Manager for Windows。更多的内容可以参考《Pro Git》凭证存储这一节。
除此之外,还有一种更简单粗暴的方式:
 
  
  1. aneasystone@little-stone:~/working$ git clone http://admin:123456@myserver/test.git


五、综合对比

640?wx_fmt=png


这一节对 Git 的四大协议做一个综合对比。
本地协议
  • 优点:架设简单,不依赖外部服务,直接使用现有文件和网络权限,常用于共享文件系统

  • 缺点:共享文件系统的配置和使用不方便,且无法保护仓库被意外损坏,传输性能较低


SSH 协议
  • 优点:架设简单,所有数据经过授权加密,数据传输很安全,传输性能很高

  • 缺点:不支持匿名访问,配置 SSH 的密钥对小白用户有一定的门槛


Git 协议
  • 优点:对开放的项目很适用,无需授权,传输性能最高

  • 缺点:缺乏授权机制,架设较麻烦,企业一般不会默认开放 9418 端口需要另行添加


HTTP/S 协议
  • 优点:同时支持授权访问和无授权访问,传输性能较高,配合 HTTPS 也可以实现数据安全

  • 缺点:架设 HTTP 服务较麻烦,认证凭证不好管理


六、更高级的工具

640?wx_fmt=png


上面介绍的是搭建 Git 服务器最基本的方法,如果你只是希望能找一个版本控制系统来替代现有的 SVN,这也许就足够了。但如果你希望你的版本控制系统能拥有一个更友好的 UI 界面,能更好的管理你的用户和权限,能支持更现代的 Pull Request 功能以及能和 CI/CD 系统更紧密的联系起来,你就需要一个更高级的工具,你可以试试 GitWeb、Gitolite、GitLab、Gogs、Gitea,当然,如果你愿意,你也可以把代码放在那些流行的代码托管平台上,比如 GitHub 等等。
相关链接:

  1. https://rhodecode.com/

  2. https://rhodecode.com/insights/version-control-systems-2016

  3. http://www.aneasystone.com/archives/2016/04/java-and-https.html

  4. https://help.github.com/articles/connecting-to-github-with-ssh/

  5. https://git-scm.com/docs/git-daemon

  6. https://git-scm.com/book/zh/v2


原文链接:https://www.aneasystone.com/archives/2018/12/build-your-own-git-server.html


Kubernetes实战培训

640?


Kubernetes实战培训将于2019年3月8日在深圳开课,3天时间带你系统掌握Kubernetes,学习效果不好可以继续学习 本次培训包括:云原生介绍、微服务;Docker基础、Docker工作原理、镜像、网络、存储、数据卷、安全;Kubernetes架构、核心组件、常用对象、网络、存储、认证、服务发现、调度和服务质量保证、日志、监控、告警、Helm、实践案例等。
640?wx_fmt=png

猜你喜欢

转载自blog.csdn.net/M2l0ZgSsVc7r69eFdTj/article/details/86942851