Ubuntu 搭建简单的git server

简介

Git 可使用四种主要的协议来传输资料:html

  1. 本地协议(Local):
      最基本的就是 本地协议(Local protocol), 其中的远程版本库就是硬盘内的另外一个目录。 这常见于团队每个成员都对一个共享的文件系统(例如一个挂载的 NFS)拥有访问权,或者比较少见的多人共用同一台电脑的状况。 后者并不理想,由于你的全部代码版本库若是长存于同一台电脑,更可能发生灾难性的损失。
      若是你使用共享文件系统,就能够从本地版本库克隆(clone)、推送(push)以及拉取(pull)。 像这样去克隆一个版本库或者增长一个远程到现有的项目中,使用版本库路径做为 URL。 例如,克隆一个本地版本库,能够执行以下的命令:
    shell git clone /opt/git/project.git 或 git clone file:///opt/git/project.git
       若是在 URL 开头明确的指定 file://,那么 Git 的行为会略有不一样。 若是仅是指定路径,Git 会尝试使用硬连接(hard link)或直接复制所须要的文件。
       若是指定 file://,Git 会触发平时用于网路传输资料的进程,那一般是传输效率较低的方法。 指定 file:// 的主要目的是取得一个没有外部参考(extraneous references)或对象(object)的干净版本库副本– 一般是在从其余版本控制系统导入后或一些相似状况(参见 Git 内部原理 for maintenance tasks)须要这么作。 在此咱们将使用普通路径,由于这样一般更快。
       要增长一个本地版本库到现有的 Git 项目,能够执行以下的命令:
    shell git remote add local_proj /opt/git/project.git
       而后,就能够像在网络上同样从远端版本库推送和拉取更新了。
       优势: 基于文件系统的版本库的优势是简单,而且直接使用了现有的文件权限和网络访问权限。 若是你的团队已经有共享文件系统,创建版本库会十分容易。 只须要像设置其余共享目录同样,把一个裸版本库的副本放到你们均可以访问的路径,并设置好读/写的权限,就能够了, 咱们会在 在服务器上搭建 Git 讨论如何导出一个裸版本库。
       这也是快速从别人的工做目录中拉取更新的方法。 若是你和别人一块儿合做一个项目,他想让你从版本库中拉取更新时,运行相似 git pull /home/john/project 的命令比推送到服务再取回简单多了。
       缺点: 这种方法的缺点是,一般共享文件系统比较难配置,而且比起基本的网络链接访问,这不方便从多个位置访问。 若是你想从家里推送内容,必须先挂载一个远程磁盘,相比网络链接的访问方式,配置不方便,速度也慢。
       值得一提的是,若是你使用的是相似于共享挂载的文件系统时,这个方法不必定是最快的。 访问本地版本库的速度与你访问数据的速度是同样的。 在同一个服务器上,若是容许 Git 访问本地硬盘,通常的经过 NFS 访问版本库要比经过 SSH 访问慢。
       最终,这个协议并不保护仓库避免意外的损坏。 每个用户都有“远程”目录的完整 shell 权限,没有方法能够阻止他们修改或删除 Git 内部文件和损坏仓库。linux

  2. HTTP 协议:
       Git 经过 HTTP 通讯有两种模式。 在 Git 1.6.6 版本以前只有一个方式可用,十分简单而且一般是只读模式的。 Git 1.6.6 版本引入了一种新的、更智能的协议,让 Git 能够像经过 SSH 那样智能的协商和传输数据。 以后几年,这个新的 HTTP 协议由于其简单、智能变的十分流行。 新版本的 HTTP 协议通常被称为“智能” HTTP 协议,旧版本的通常被称为“哑” HTTP 协议。 咱们先了解一下新的“智能” HTTP 协议。
       智能(Smart) HTTP 协议: “智能” HTTP 协议的运行方式和 SSH 及 Git 协议相似,只是运行在标准的 HTTP/S 端口上而且可使用各类 HTTP 验证机制,这意味着使用起来会比 SSH 协议简单的多,好比可使用 HTTP 协议的用户名/密码的基础受权,免去设置 SSH 公钥。
       智能 HTTP 协议或许已是最流行的使用 Git 的方式了,它即支持像 git:// 协议同样设置匿名服务,也能够像 SSH 协议同样提供传输时的受权和加密。 并且只用一个 URL 就能够都作到,省去了为不一样的需求设置不一样的 URL。 若是你要推送到一个须要受权的服务器上(通常来说都须要),服务器会提示你输入用户名和密码。 从服务器获取数据时也同样。
       事实上,相似 GitHub 的服务,你在网页上看到的 URL (好比,https://github.com/schacon/simplegit[]),和你在克隆、推送(若是你有权限)时使用的是同样的。
       哑(Dumb) HTTP 协议: 若是服务器没有提供智能 HTTP 协议的服务,Git 客户端会尝试使用更简单的“哑” HTTP 协议。 哑 HTTP 协议里 web 服务器仅把裸版本库看成普通文件来对待,提供文件服务。 哑 HTTP 协议的优美之处在于设置起来简单。 基本上,只须要把一个裸版本库放在 HTTP 根目录,设置一个叫作 post-update 的挂钩就能够了(见 Git 钩子)。 此时,只要能访问 web 服务器上你的版本库,就能够克隆你的版本库。 下面是设置从 HTTP 访问版本库的方法:
    shell cd /var/www/htdocs/ git clone --bare /path/to/git_project gitproject.git cd gitproject.git mv hooks/post-update.sample hooks/post-update chmod a+x hooks/post-update
       这样就能够了。 Git 自带的 post-update 挂钩会默认执行合适的命令(git update-server-info),来确保经过 HTTP 的获取和克隆操做正常工做。 这条命令会在你经过 SSH 向版本库推送以后被执行;而后别人就能够经过相似下面的命令来克隆:
    shell git clone https://example.com/gitproject.git
       这里咱们用了 Apache 里设置了经常使用的路径 /var/www/htdocs,不过你可使用任何静态 web 服务器 —— 只须要把裸版本库放到正确的目录下就能够。 Git 的数据是以基本的静态文件形式提供的(详情见 Git 内部原理)。
       一般的,会在能够提供读/写的智能 HTTP 服务和简单的只读的哑 HTTP 服务之间选一个。 极少会将两者混合提供服务。
       优势: 咱们将只关注智能 HTTP 协议的优势。不一样的访问方式只须要一个 URL 以及服务器只在须要受权时提示输入受权信息,这两个简便性让终端用户使用 Git 变得很是简单。 相比 SSH 协议,可使用用户名/密码受权是一个很大的优点,这样用户就没必要须在使用 Git 以前先在本地生成 SSH 密钥对再把公钥上传到服务器。 对非资深的使用者,或者系统上缺乏 SSH 相关程序的使用者,HTTP 协议的可用性是主要的优点。 与 SSH 协议相似,HTTP 协议也很是快和高效。
       你也能够在 HTTPS 协议上提供只读版本库的服务,如此你在传输数据的时候就能够加密数据;或者,你甚至可让客户端使用指定的 SSL 证书。
       另外一个好处是 HTTP/S 协议被普遍使用,通常的企业防火墙都会容许这些端口的数据经过。
       缺点: 在一些服务器上,架设 HTTP/S 协议的服务端会比 SSH 协议的棘手一些。 除了这一点,用其余协议提供 Git 服务与 “智能” HTTP 协议相比就几乎没有优点了。
       若是你在 HTTP 上使用需受权的推送,管理凭证会比使用 SSH 密钥认证麻烦一些。 然而,你能够选择使用凭证存储工具,好比 OSX 的 Keychain 或者 Windows 的凭证管理器。 参考 凭证存储 如何安全地保存 HTTP 密码。git

  3. SSH(Secure Shell)协议
       架设 Git 服务器时经常使用 SSH 协议做为传输协议。 由于大多数环境下已经支持经过 SSH 访问 —— 即时没有也比较很容易架设。 SSH 协议也是一个验证受权的网络协议;而且,由于其广泛性,架设和使用都很容易。
       经过 SSH 协议克隆版本库,你能够指定一个 ssh:// 的 URL:
    shell git clone ssh://user@server/project.git
       或者使用一个简短的 scp 式的写法:
    shell git clone user@server:project.git
       你也能够不指定用户,Git 会使用当前登陆的用户名。
       优点: 用 SSH 协议的优点有不少。 首先,SSH 架设相对简单 —— SSH 守护进程很常见,多数管理员都有使用经验,而且多数操做系统都包含了它及相关的管理工具。 其次,经过 SSH 访问是安全的 —— 全部传输数据都要通过受权和加密。 最后,与 HTTP/S 协议、Git 协议及本地协议同样,SSH 协议很高效,在传输前也会尽可能压缩数据。github

      缺点: SSH 协议的缺点在于你不能经过他实现匿名访问。 即使只要读取数据,使用者也要有经过 SSH 访问你的主机的权限,这使得 SSH 协议不利于开源的项目。 若是你只在公司网络使用,SSH 协议多是你惟一要用到的协议。 若是你要同时提供匿名只读访问和 SSH 协议,那么你除了为本身推送架设 SSH 服务之外,还得架设一个可让其余人访问的服务。web

  4. Git 协议
       接下来是 Git 协议。 这是包含在 Git 里的一个特殊的守护进程;它监听在一个特定的端口(9418),相似于 SSH 服务,可是访问无需任何受权。 要让版本库支持 Git 协议,须要先建立一个 git-daemon-export-ok 文件 —— 它是 Git 协议守护进程为这个版本库提供服务的必要条件 —— 可是除此以外没有任何安全措施。 要么谁均可以克隆这个版本库,要么谁也不能。 这意味着,一般不能经过 Git 协议推送。 因为没有受权机制,一旦你开放推送操做,意味着网络上知道这个项目 URL 的人均可以向项目推送数据。 不用说,极少会有人这么作。
       优势: 目前,Git 协议是 Git 使用的网络传输协议里最快的。 若是你的项目有很大的访问量,或者你的项目很庞大而且不须要为写进行用户受权,架设 Git 守护进程来提供服务是不错的选择。 它使用与 SSH 相同的数据传输机制,可是省去了加密和受权的开销。
       缺点: Git 协议缺点是缺少受权机制。 把 Git 协议做为访问项目版本库的惟一手段是不可取的。 通常的作法里,会同时提供 SSH 或者 HTTPS 协议的访问服务,只让少数几个开发者有推送(写)权限,其余人经过 git:// 访问只有读权限。 Git 协议也许也是最难架设的。 它要求有本身的守护进程,这就要配置 xinetd 或者其余的程序,这些工做并不简单。 它还要求防火墙开放 9418 端口,可是企业防火墙通常不会开放这个非标准端口。 而大型的企业防火墙一般会封锁这个端口。
       这里使用的是ssh协议,采用的是的gitcore搭建的,若是想搭建一个高端一点的(相似github,有web界面的)能够点击参考,里面由关于gitweb和gitlab的介绍。

    shell

环境

服务端: ubuntu 14.04 、 gitcore 1.9.1
客户端: ubuntu 16.04 、 git 2.7.4ubuntu

搭建过程

服务端

  1. 先建立一个帐户用于操做git仓库
    shell sudo adduser git #用户名随意叫,普通用户便可
  2. 安装git core
    shell sudo apt-get update && sudo apt-get upgrade && sudo apt-get install git-core
  3. 建立测试git仓库
    shell su git #切换到git用户,这样接下来的建立的仓库保证都是具备读写权限的 cd ~ && mkdir -p ~/github/test.git cd ~/github/test.git && git init --shared --bare #--bare 建立一个空仓库 --shared 用于配置仓库的访问权限 ,咱们这里采用默认配置,同属于git group的人能够访问。
    此时会显示:vim

    Initialized empty Git repository in /home/git/github/test.git

客户端

  1. 生成用于ssh登陆的证书:安全

    ssh-keygen -t rsa #产生证书过程当中会有两步提示,第一步让你选择文件保存位置,这一步直接回车;第二步让你输入私钥保护密码,建议设置密码为了安全。

    这时在home目录下会产生一个.ssh的隐藏文件夹,里面会产生一个 id_rsa 和 id_rsa.pub的公私钥对.bash

  2. 上传证书到服务器

    cat ~/.ssh/id_rsa.pub | ssh git@server "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys" #server是你服务器的域名或者ip地址
  3. 登陆服务器(optional)
    shell  ssh git@server #若是在建立私钥的时候输入了保护密码,此时会向你索取保护密码

  4. 测试上传代码
    若是本地没有已经存在的代码:
    shell git clone git@server:~/git/github/test.git cd test touch README.md git add README.md git commit -a #提交代码的时候会要求你写入日志,若是是采用的nano编辑器,写入结束后按ctrl + x 保存退出 git push -u origin master
    若是你本地已经有写好的代码了则执行如下步骤:
    shell cd existing_dir git init git remote add origin git@server:~/git/github/test.git git add . git commit -a git push -u origin master
    注意: 当仓库为空时push操做没法成功,会报出error: src refspec master does not match any 错误。

添加用户

第一种

  1. 建立一个新的公私密钥对,而后将公钥添加到/home/git/.ssh/authorized_keys文件的末尾
    shell cat ~/.ssh/new.pub | ssh git@server "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys" #server是你服务器的域名或者ip地址

  2. 而后将公私密钥对分发给新用户,放在新用户本地的~/.ssh 文件夹下面便可。

  注: 已验证

第二种

  1. 在服务端建立一个git group的用户,而后为其生成公私密钥分发给新用户用于ssh通讯

   注:待验证

git shell 安全 (Optional)

   上面建立的git是一个普通用户,可是仍然能够登陆到服务器中,且对git仓库具有操做权限,存在潜在风险,为此咱们要限制它的能力。这能够借助一个名为 git-shell 的受限 shell 工具,你能够方便地将用户 git 的活动限制在与 Git 相关的范围内。该工具随 Git 软件包一同提供。

   若是将 git-shell 设置为用户 git 的登陆 shell(login shell),那么用户 git 便不能得到此服务器的普通 shell 访问权限。 若要使用 git-shell,须要用它替换掉 bash 或 csh,使其成为系统用户的登陆 shell。 为进行上述操做,首先你必须确保 git-shell 已存在于 /etc/shells 文件中:

cat /etc/shells   # see if `git-shell` is already in there.  If not...
    which git-shell   # make sure git-shell is installed on your system.
    sudo vim /etc/shells  # and add the path to git-shell from last command

   如今你可使用 chsh 命令修改任一系统用户的 shell:

sudo chsh git  # and enter the path to git-shell, usually: /usr/bin/git-shell

   这样,用户 git 就只能利用 SSH 链接对 Git 仓库进行推送和拉取操做,而不能登陆机器并取得普通 shell。 若是试图登陆,你会发现尝试被拒绝,像这样:

ssh git@gitserver
    fatal: Interactive git shell is not enabled.
    hint: ~/git-shell-commands should exist and have read and execute access.
    Connection to gitserver closed.

   如今,网络相关的 Git 命令依然可以正常工做,可是开发者用户已经没法获得一个普通 shell 了。 正如输出信息所提示的,你也能够在 git 用户的家目录下创建一个目录,来对 git-shell 命令进行必定程度的自定义。 好比,你能够限制掉某些本应被服务器接受的 Git 命令,或者对刚才的 SSH 拒绝登陆信息进行自定义,这样,当有开发者用户以相似方式尝试登陆时,便会看到你的信息。 要了解更多有关自定义 shell 的信息,请运行 git help shell。

Git守护进程(Optional)

   接下来咱们将经过 “Git” 协议创建一个基于守护进程的仓库。 对于快速且无需受权的 Git 数据访问,这是一个理想之选。 请注意,由于其不包含受权服务,任何经过该协议管理的内容将在其网络上公开。

   若是运行在防火墙以外的服务器上,它应该只对那些公开的只读项目服务。 若是运行在防火墙以内的服务器上,它可用于支撑大量参与人员或自动系统(用于持续集成或编译的主机)只读访问的项目,这样能够省去逐一配置 SSH 公钥的麻烦。

   不管什么时候,该 Git 协议都是相对容易设定的。 一般,你只须要以守护进程的形式运行该命令:

git daemon --reuseaddr --base-path=/opt/git/ /opt/git/

   --reuseaddr 容许服务器在无需等待旧链接超时的状况下重启,--base-path 选项容许用户在未彻底指定路径的条件下克隆项目,结尾的路径将告诉 Git 守护进程从何处寻找仓库来导出。 若是有防火墙正在运行,你须要开放端口 9418 的通讯权限。

   你能够经过许多方式将该进程以守护进程的方式运行,这主要取决于你所使用的操做系统。 在一台 Ubuntu 机器上,你可使用一份 Upstart 脚本。 所以,找到以下文件:

/etc/event.d/local-git-daemon

   并添加下列脚本内容:

start on startup
    stop on shutdown
    exec /usr/bin/git daemon \
        --user=git --group=git \
        --reuseaddr \
        --base-path=/opt/git/ \
        /opt/git/
    respawn

   出于安全考虑,强烈建议使用一个对仓库拥有只读权限的用户身份来运行该守护进程 - 你能够建立一个新用户 git-ro 而且以该用户身份来运行守护进程。 为简便起见,咱们将像 git-shell 同样,一样使用 git 用户来运行它。

   当你重启机器时,你的 Git 守护进程将会自动启动,而且若是进程被意外结束它会自动从新运行。 为了在不重启的状况下直接运行,你能够运行如下命令:

initctl start local-git-daemon

   在其余系统中,你可使用 sysvinit 系统中的 xinetd 脚本,或者另外的方式来实现 - 只要你可以将其命令守护进程化并实现监控。

   接下来,你须要告诉 Git 哪些仓库容许基于服务器的无受权访问。 你能够在每一个仓库下建立一个名为 git-daemon-export-ok 的文件来实现。

cd /path/to/project.git
    touch git-daemon-export-ok

   该文件将容许 Git 提供无需受权的项目访问服务。

参考网址:

相关文章
相关标签/搜索