服务器上的 Git

服务器上的 Git

  1. 协议

    Git 可以使用四种不同的协议来传输资料:本地协议(Local),HTTP 协议,SSH(Secure Shell)协议及 Git协议。

  • 本地协议(Local protocol)是最基本的,其中的远程版本库就是同一主机上的另一个目录。

    • 增加一个本地版本库到现有的 Git 项目,就可以通过新的远程仓库名 local_proj 像在网络上一样从远端版本库推送和拉取更新了。可以执行如下的命令:

      $ git remote add local_proj /srv/git/project.git

    • 克隆一个本地版本库,可以执行如下的命令:

      $ git clone /srv/git/project.git

    • 或者可以执行这个命令:

      $ git clone file:///srv/git/project.git

    • 如果在 URL 开头明确的指定 file://,那么 Git 的行为会略有不同。 如果仅是指定路径,Git 会尝试使用硬链接(hard link)或直接复制所需要的文件。 如果指定 file://,Git 会触发平时用于网路传输资料的进程,那样传输效率会更低。 指定 file:// 的主要目的是取得一个没有外部参考(extraneous references) 或对象(object)的干净版本库副本——通常是在从其他版本控制系统导入后或一些类似情况需要这么做。

    • 优点

      基于文件系统的版本库的优点是简单,并且直接使用了现有的文件权限和网络访问权限。只需要像设置其他共享目录一样,把一个裸版本库的副本放到大家都可以访问的路径,并设置好读/写的权限,就可以了。

    • 缺点

      缺点是通常共享文件系统比较难配置,并且比起基本的网络连接访问,这不方便从多个位置访问。如果你想从家里推送内容,必须先挂载一个远程磁盘,相比网络连接的访问方式,配置不方便,速度也慢。在同一个服务器上,如果允许 Git 访问本地硬盘,一般的通过 NFS 访问版本库要比通过 SSH 访问慢。每一个用户都有“远程”目录的完整shell权限,没有方法可以阻止他们修改或删除 Git 内部文件和损坏仓库。这个协议并不保护仓库避免意外的损坏。

  • HTTP 协议

    Git 通过 HTTP 通信有两种模式。 在 Git 1.6.6 版本之前只有一个方式可用,十分简单并且通常是只读模式的。Git 1.6.6 版本引入了一种新的、更智能的协议,让 Git 可以像通过 SSH 那样智能的协商和传输数据。 之后几年,这个新的 HTTP 协议因为其简单、智能变的十分流行。 新版本的 HTTP 协议一般被称为 智能 HTTP 协议,旧版本的一般被称为 哑 HTTP 协议。

    • 智能 HTTP 协议

      智能 HTTP 的运行方式和 SSH 及 Git 协议类似,只是运行在标准的 HTTP/S 端口上并且可以使用各种 HTTP 验证机制, 这意味着使用起来会比 SSH 协议简单的多,比如可以使用 HTTP 协议的用户名/密码授权,免去设置SSH 公钥。智能 HTTP 协议或许已经是最流行的使用 Git 的方式了,它即支持像 git:// 协议一样设置匿名服务, 也可以像SSH 协议一样提供传输时的授权和加密。 而且只用一个 URL 就可以都做到,省去了为不同的需求设置不同的URL。 如果你要推送到一个需要授权的服务器上(一般来讲都需要),服务器会提示你输入用户名和密码。 从服务器获取数据时也一样。

    • 哑(Dumb) HTTP 协议

      如果服务器没有提供智能 HTTP 协议的服务,Git 客户端会尝试使用更简单的“哑” HTTP 协议。 哑 HTTP 协议里 web 服务器仅把裸版本库当作普通文件来对待,提供文件服务。 哑 HTTP 协议的优美之处在于设置起来简单。 基本上,只需要把一个裸版本库放在 HTTP 根目录,设置一个叫做 post-update 的挂钩就可以了。 此时,只要能访问 web 服务器上你的版本库,就可以克隆你的版本库。 下面是设置从 HTTP 访问版本库的方法:

        $ 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 的获取和克隆操作正常工作。只需要把裸版本库放到正确的目录下就可以,Git 的数据是以基本的静态文件形式提供的。这条命令会在你通过 SSH 向版本库推送之后被执行;然后别人就可以通过类似下面的命令来克隆:

        $ git clone https://example.com/gitproject.git
      
    • 优点

      只需要一个 URL 以及服务器只在需要授权时提示输入授权信息,这两个简便性让终端用户使用Git 变得非常简单。也可以在 HTTPS 协议上提供只读版本库的服务,在传输数据的时候就可以加密数据;或者,让客户端使用指定的 SSL 证书。HTTPS 协议被广泛使用,一般的企业防火墙都会允许这些端口的数据通过。

    • 缺点

      在一些服务器上,架设 HTTPS 协议的服务端会比 SSH 协议的棘手一些。

      在 HTTP 上使用需授权的推送,管理凭证会比使用 SSH 密钥认证麻烦一些。

  • SSH 协议

    架设 Git 服务器时常用 SSH 协议作为传输协议。 因为大多数环境下服务器已经支持通过 SSH 访问 —— 即使没有也很容易架设。 SSH 协议也是一个验证授权的网络协议;并且,因为其普遍性,架设和使用都很容易。

    通过 SSH 协议克隆版本库,你可以指定一个 ssh:// 的 URL:

      $ git clone ssh://[user@]server/project.git
    

    或者使用一个简短的 scp 式的写法:

      $ git clone [user@]server:project.git
    

    在上面两种情况中,如果你不指定可选的用户名,那么 Git 会使用当前登录的用的名字。

    • 优势

      首先,SSH 架设相对简单 —— SSH 守护进程很常见,多数管理员都有使用经验,并且多数操作系统都包含了它及相关的管理工具。

      其次,通过 SSH 访问是安全的 —— 所有传输数据都要经过授权和加密。 最后,与 HTTPS 协议、Git 协议及本地协议一样,SSH 协议很高效,在传输前也会尽量压缩数据。

    • 缺点

      SSH 协议的缺点在于它不支持匿名访问 Git 仓库。 如果你使用 SSH,那么即便只是读取数据,使用者也 必须 通过 SSH 访问你的主机, 这使得 SSH 协议不利于开源的项目,毕竟人们可能只想把你的仓库克隆下来查看。 如果你只在公司网络使用,SSH 协议可能是你唯一要用到的协议。 如果你要同时提供匿名只读访问和 SSH 协议,那么你除了为自己推送架设 SSH 服务以外, 还得架设一个可以让其他人访问的服务。

  • Git 协议

    这是包含在 Git 里的一个特殊的守护进程;它监听在一个特定的端口(9418),类似于SSH服务,但是访问无需任何授权。

    要让版本库支持 Git 协议,需要先创建一个 git-daemon-export-ok 文件—— 它是 Git 协议守护进程为这个版本库提供服务的必要条件 —— 但是除此之外没有任何安全措施。要么谁都可以克隆这个版本库,要么谁也不能。这意味着,通常不能通过 Git 协议推送。由于没有授权机制,一旦你开放推送操作,意味着网络上知道这个项目 URL 的人都可以向项目推送数据。

    • 优点

      目前,Git 协议是 Git 使用的网络传输协议里最快的。如果你的项目有很大的访问量,或者你的项目很庞大并且不需要为写进行用户授权,架设 Git 守护进程来提供服务是不错的选择。 它使用与 SSH 相同的数据传输机制,但是省去了加密和授权的开销。

    • 缺点

      Git 协议缺点是缺乏授权机制。 把 Git 协议作为访问项目版本库的唯一手段是不可取的。 一般的做法里,会同时提供 SSH 或者 HTTPS 协议的访问服务,只让少数几个开发者有推送(写)权限,其他人通过 git:// 访问只有读权限。 Git 协议也许也是最难架设的。 它要求有自己的守护进程,这就要配置 xinetd、systemd 或者其他的程序,这些工作并不简单。 它还要求防火墙开放 9418 端口,但是企业防火墙一般不会开放这个非标准端口。而大型的企业防火墙通常会封锁这个端口。

在服务器上搭建 Git

  1. 在开始架设 Git 服务器前,需要把现有仓库导出为裸仓库——即一个不包含当前工作目录的仓库。

    通过克隆现有的仓库来创建一个新的裸仓库,需要在克隆命令后加上 --bare 选项。 按照惯例,裸仓库的目录名以 .git 结尾,就像这样:

     $ git clone --bare my_project my_project.git
    

    整体上效果大致相当于:

     $ cp -Rf my_project/.git my_project.git
    

    虽然在配置文件中有若干不同,但是对于你的目的来说,这两种方式都是一样的。 它只取出 Git 仓库自身,不要工作目录,然后特别为它单独创建一个目录。

  2. 把裸仓库放到服务器上

    假设一个域名为git.example.com 的服务器已经架设好,并可以通过 SSH 连接, 你想把所有的 Git 仓库放在 /srv/git 目录下。 假设服务器上存在 /srv/git/ 目录,你可以通过以下命令复制你的裸仓库来创建一个新仓库:

     $ scp -r my_project.git user@git.example.com:/srv/git
    

    其他可通过 SSH 读取此服务器上 /srv/git 目录的用户,可运行以下命令来克隆你的仓库。

     $ git clone user@git.example.com:/srv/git/my_project.git
    

    如果一个用户,通过使用 SSH 连接到一个服务器,并且其对 /srv/git/my_project.git 目录拥有可写权限,那么他将自动拥有推送权限。

    如果到该项目目录中运行 git init 命令,并加上 --shared 选项, 那么 Git 会自动修改该仓库目录的组权限为可写。 注意,运行此命令的工程中不会摧毁任何提交、引用等内容。

     $ ssh user@git.example.com
     $ cd /srv/git/my_project.git
     $ git init --bare --shared
    

    根据现有的 Git 仓库创建一个裸仓库,然后把它放上你和协作者都有 SSH 访问权的服务器就可以在同一项目上展开合作了。值得注意的是,这的确是架设一个几个人拥有连接权的 Git 服务的全部—— 只要在服务器上加入可以用 SSH 登录的帐号,然后把裸仓库放在大家都有读写权限的地方。

生成 SSH 公钥

首先,你需要确认自己是否已经拥有密钥。 默认情况下,用户的 SSH 密钥存储在其 ~/.ssh 目录下。 进入该目录并列出其中内容,确认自己是否已拥有密钥:
    $ cd ~/.ssh
    $ ls
寻找一对以 id_dsa 或 id_rsa 命名的文件,其中一个带有 .pub 扩展名。 .pub 文件是你的公钥,另一个则是与之对应的私钥。 如果找不到这样的文件(或者根本没有 .ssh 目录),你可以通过运行 ssh-keygen 程序来创建它们。 在 Linux/macOS 系统中,ssh-keygen 随 SSH 软件包提供;在 Windows 上,该程序包含于 MSysGit 软件包中。
    $ ssh-keygen -o
首先 ssh-keygen 会确认密钥的存储位置(默认是 .ssh/id_rsa),然后它会要求你输入两次密钥口令。 如果你不想在使用密钥时输入口令,将其留空即可。 然而,如果你使用了密码,那么请确保添加了 -o 选项,它会以比默认格式更能抗暴力破解的格式保存私钥。 你也可以用 ssh-agent 工具来避免每次都要输入密码。
    $ cat ~/.ssh/id_rsa.pub

配置服务器

使用 authorized_keys 方法来对用户进行认证。
  1. 首先,创建一个操作系统用户 git,并为其建立一个 .ssh 目录。

     $ sudo adduser git
     $ su git
     $ cd
     $ mkdir .ssh && chmod 700 .ssh
     $ touch .ssh/authorized_keys && chmod 600 .ssh/authorized_keys
    

    以下操作可通过 ssh-copy-id 命令自动完成,这样就不必手动复制并安装公钥了。
    ssh-copy-id 用来将本地公钥复制到远程主机。如果不传入 -i 参数,ssh-copy-id 使用默认 ~/.ssh/identity.pub 作为默认公钥。如果多次运行 ssh-copy-id ,该命令不会检查重复,会在远程主机中多次写入 authorized_keys.

    ssh-copy-id仅仅支持SSH运行在22端口的情况,服务器的SSH端口改成10022端口时运行ssh-copy-id就会报错了。
    # vi ~/.ssh/config
    加上内容:
    Host server
    Hostname ip
    Port 10022
    也可以单独只加入Port一行配置,那样就是一个全局配置,保存后再运行ssh-copy-id命令就不会报错了。
    不修改config文件,按如下方式也可以:
    ssh-copy-id -i ~/.ssh/id_rsa.pub “-p 10022 user@server”

  2. 添加SSH公钥。
    为系统用户 git 的 authorized_keys 文件添加一些开发者 SSH 公钥。 假设我们已经获得了
    若干受信任的公钥,并将它们保存在临时文件中。

     $ cat /tmp/id_rsa.john.pub
    

    将这些公钥加入系统用户 git 的 .ssh 目录下 authorized_keys 文件的末尾:

     $ cat /tmp/id_rsa.john.pub >> ~/.ssh/authorized_keys
     $ cat /tmp/id_rsa.josie.pub >> ~/.ssh/authorized_keys
     $ cat /tmp/id_rsa.jessica.pub >> ~/.ssh/authorized_keys
    

    为开发者新建一个空仓库。可以借助带 --bare 选项的 git init 命令来做到这一点,该命令在初始化仓库时不会创建工作目录:

     $ cd /srv/git
     $ mkdir project.git
     $ cd project.git
     $ git init --bare
    
  3. 推送项目到仓库

    假定 myproject 是已有项目且其中已包含文件:

     # on John's computer
     $ cd myproject
     $ git init
     $ git add .
     $ git commit -m 'initial commit'
     $ git remote add origin git@gitserver:/srv/git/project.git
     $ git push origin master
    

    此时,其他开发者可以克隆此仓库,并推回各自的改动:

     $ git clone git@gitserver:/srv/git/project.git
     $ cd project
     $ vim README
     $ git commit -am 'fix for the README file'
     $ git push origin master
    
  4. 限制用户 git 的活动在与 Git 相关的范围内。

    目前所有(获得授权的)开发者用户都能以系统用户 git 的身份登录服务器从而获得一个普通shell。 如果你想对此加以限制,则需要修改 /etc/passwd 文件中(git 用户所对应)的 shell 值。

    借助一个名为 git-shell 的受限 shell 工具,该工具随 Git 软件包一同提供。如果将 git-shell 设置为用户 git 的登录 shell(login shell), 那么该用户便不能获得此服务器的普通 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 -e /etc/shells # and add the path to git-shell from last command
    

    使用 chsh -s 命令修改任一系统用户的 shell:

     $ sudo chsh git -s $(which git-shell)
    

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

     $ ssh git@gitserver
    

    此时,用户仍可通过 SSH 端口转发来访问任何可达的 git 服务器。 如果你想要避免它,可编辑authorized_keys 文件并在所有想要限制的公钥之前添加以下选项:

     no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty
    

    结果查看:

     $ cat ~/.ssh/authorized_keys
    

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值