Git
章节 ▾ 第二版

4.1 Git 服务器 - 协议

到目前为止,您应该能够完成大部分日常使用 Git 的任务。但是,为了在 Git 中进行协作,您需要一个远程 Git 仓库。虽然您可以将更改推送到个人仓库并从个人仓库中拉取更改,但这样做并不鼓励,因为如果您不小心,很容易混淆他们的工作内容。此外,您希望您的合作者即使在您的计算机离线时也能访问仓库 - 拥有一个更可靠的公共仓库通常很有用。因此,与他人协作的首选方法是设置一个中间仓库,您双方都可以访问,并且可以向其中推送更改并从中拉取更改。

运行 Git 服务器相当简单。首先,您需要选择服务器要支持的协议。本章的第一部分将介绍可用的协议以及每种协议的优缺点。接下来的部分将解释使用这些协议的一些典型设置,以及如何让服务器使用这些协议运行起来。最后,我们将介绍一些托管选项,如果您不介意在其他人的服务器上托管您的代码,并且不想设置和维护自己的服务器。

如果您没有兴趣运行自己的服务器,您可以跳到本章的最后一部分,查看一些设置托管帐户的选项,然后继续下一章,我们将讨论在分布式源代码控制环境中工作时的各种进进出出。

远程仓库通常是一个 _裸仓库_ - 一个没有工作目录的 Git 仓库。由于仓库仅用作协作点,因此没有理由在磁盘上检出一个快照;它只是 Git 数据。简单来说,裸仓库就是项目 `。git` 目录的内容,其他什么都没有。

协议

Git 可以使用四种不同的协议来传输数据:本地、HTTP、安全外壳 (SSH) 和 Git。这里我们将讨论它们是什么以及在哪些基本情况下您想要(或不想要)使用它们。

本地协议

最基本的是 _本地协议_,其中远程仓库位于同一主机上的另一个目录中。这通常用于您的团队中的每个人都可以访问共享文件系统,例如 NFS 挂载,或者不太可能的情况下,每个人都登录到同一台计算机。后者并不理想,因为您所有的代码仓库实例都将驻留在同一台计算机上,这使得灾难性损失的可能性大大增加。

如果您有共享的挂载文件系统,那么您可以克隆、推送到本地文件系统仓库并从中拉取更改。要克隆这样的仓库,或者将它作为远程仓库添加到现有项目中,请使用仓库的路径作为 URL。例如,要克隆本地仓库,您可以运行以下命令

$ git clone /srv/git/project.git

或者您也可以这样做

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

如果您在 URL 的开头显式指定 `file://`,Git 的操作略有不同。如果您只指定路径,Git 会尝试使用硬链接或直接复制它需要的文件。如果您指定 `file://`,Git 会启动它通常用于通过网络传输数据的进程,这通常效率要低得多。指定 `file://` 前缀的主要原因是如果您想要仓库的干净副本,而没有无关的引用或对象(通常是在从其他 VCS 导入之后或类似情况,请参阅 Git 内部机制 获取维护任务)。我们将在此处使用正常路径,因为这样做几乎总是更快。

要将本地仓库添加到现有的 Git 项目中,您可以运行类似以下命令:

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

然后,您可以使用新的远程名称 local_proj 推送到该远程仓库并从该远程仓库拉取,就像您在网络上进行操作一样。

优点

基于文件的仓库的优点是简单,并且使用现有的文件权限和网络访问。如果您已经有整个团队都可以访问的共享文件系统,那么设置仓库非常容易。您只需将裸仓库副本放置在每个人都可以访问的共享位置,并像设置任何其他共享目录一样设置读写权限。我们将在 在服务器上安装 Git 中讨论如何导出裸仓库副本以用于此目的。

这也是快速获取他人工作仓库的一种不错选择。如果您和同事正在同一个项目上工作,而他们希望您查看某些内容,运行类似 git pull /home/john/project 的命令通常比他们推送到远程服务器,然后您再从远程服务器获取要容易得多。

缺点

这种方法的缺点是,从多个位置设置和访问共享访问通常比基本的网络访问更难。如果您想从家中的笔记本电脑推送,则必须挂载远程磁盘,这可能比基于网络的访问更困难和更慢。

重要的是要注意,如果您使用的是某种共享挂载,这并不一定是最快的方法。本地仓库只有在您能够快速访问数据时才是快速的。在 NFS 上的仓库通常比在同一服务器上通过 SSH 的仓库慢,因为 Git 允许在每个系统上的本地磁盘上运行。

最后,此协议无法保护仓库免受意外损坏。每个用户都拥有对“远程”目录的完全 shell 访问权限,没有任何东西可以阻止他们更改或删除内部 Git 文件并损坏仓库。

HTTP 协议

Git 可以通过 HTTP 使用两种不同的模式进行通信。在 Git 1.6.6 之前,它只有一种方法可以做到这一点,这种方法非常简单,通常是只读的。在 1.6.6 版本中,引入了一种新的、更智能的协议,该协议允许 Git 智能地协商数据传输,类似于它通过 SSH 的方式。在过去几年中,这种新的 HTTP 协议变得非常流行,因为它对用户来说更简单,并且在通信方式上更加智能。较新的版本通常被称为智能 HTTP 协议,而较旧的方式被称为 HTTP。我们将首先介绍较新的智能 HTTP 协议。

智能 HTTP

智能 HTTP 的操作方式与 SSH 或 Git 协议非常相似,但它通过标准 HTTPS 端口运行,并且可以使用各种 HTTP 身份验证机制,这意味着它对用户来说通常比 SSH 更容易,因为您可以使用用户名/密码身份验证等方式,而无需设置 SSH 密钥。

它可能已成为目前使用 Git 的最流行方式,因为它可以设置为以匿名方式提供服务,就像 git:// 协议一样,也可以通过身份验证和加密进行推送,就像 SSH 协议一样。您现在可以使用一个 URL 来完成这两件事,而不是为这些事情设置不同的 URL。如果您尝试推送并且仓库需要身份验证(通常应该如此),服务器可能会提示输入用户名和密码。读取访问权限也是如此。

事实上,对于像 GitHub 这样的服务,您用于在线查看仓库的 URL(例如,https://github.com/schacon/simplegit)与您用于克隆和(如果您有权限)推送的 URL 相同。

哑 HTTP

如果服务器没有响应 Git HTTP 智能服务,Git 客户端将尝试回退到更简单的 HTTP 协议。哑协议期望裸 Git 仓库像普通文件一样从 Web 服务器提供服务。哑 HTTP 的优点是设置简单。基本上,您所要做的就是将裸 Git 仓库放在您的 HTTP 文档根目录下,并设置一个特定的 post-update 钩子,您就完成了(参见 Git 钩子)。在那之后,任何可以访问您放置仓库的 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 获取和克隆正常工作。当您向该仓库(可能通过 SSH)推送时,就会运行该命令;然后,其他人可以通过以下方式克隆

$ git clone https://example.com/gitproject.git

在这种特定情况下,我们使用的是 Apache 设置中常见的 /var/www/htdocs 路径,但您可以使用任何静态 Web 服务器——只需将裸仓库放在其路径下即可。Git 数据作为基本的静态文件提供服务(有关其提供服务的具体方式,请参见 Git 内部结构 章)。

通常,您会选择运行读写智能 HTTP 服务器,或者只是以哑方式让文件作为只读访问。很少会运行两种服务的混合体。

优点

我们将集中介绍 HTTP 协议智能版本的优点。

对于所有类型的访问使用一个 URL,并且只有在需要身份验证时才提示服务器输入凭据的简单性,这使得最终用户使用起来非常方便。能够使用用户名和密码进行身份验证也是 SSH 的一大优势,因为用户无需在本地生成 SSH 密钥并将其公钥上传到服务器才能与之交互。对于不太精通的用户,或者在 SSH 不太常见的系统上,这对易用性来说是一个重大优势。它也是一个非常快速高效的协议,类似于 SSH 协议。

您还可以通过 HTTPS 以只读方式提供仓库,这意味着您可以加密内容传输;或者您还可以让客户端使用特定的已签名 SSL 证书。

另一个好处是,HTTP 和 HTTPS 是非常常见的协议,因此公司防火墙通常被设置为允许流量通过其端口。

缺点

与在某些服务器上设置 SSH 相比,通过 HTTPS 使用 Git 可能有点棘手。除此之外,其他协议在提供 Git 内容方面与智能 HTTP 相比几乎没有优势。

如果您使用 HTTP 进行身份验证推送,提供凭据有时比使用 SSH 上的密钥要复杂。但是,您可以使用几个凭据缓存工具,包括 macOS 上的钥匙串访问和 Windows 上的凭据管理器,使此操作变得非常轻松。阅读 凭据存储 了解如何在系统上设置安全的 HTTP 密码缓存。

SSH 协议

当您自托管 Git 时,一种常见的传输协议是通过 SSH。这是因为 SSH 访问服务器在大多数地方都已经设置好了——如果没有,也很容易设置。SSH 也是一种经过身份验证的网络协议,而且因为它无处不在,所以通常易于设置和使用。

要通过 SSH 克隆 Git 仓库,您可以指定 ssh:// URL,如下所示

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

或者,您可以使用 SSH 协议的更短的 scp 类似语法

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

在以上两种情况下,如果您没有指定可选的用户名,Git 会假定您当前登录的用户。

优点

使用 SSH 的优点很多。首先,SSH 相对容易设置——SSH 守护程序很常见,许多网络管理员都熟悉它们,许多操作系统发行版都配置了它们,或者具有管理它们的工具。其次,通过 SSH 的访问是安全的——所有数据传输都是加密和经过身份验证的。最后,与 HTTPS、Git 和本地协议一样,SSH 很高效,在传输数据之前将数据压缩得尽可能小。

缺点

SSH 的负面影响是它不支持对 Git 仓库的匿名访问。如果您使用 SSH,人们必须拥有对您机器的 SSH 访问权限,即使是以只读方式,这使得 SSH 不适合开源项目,因为人们可能只想克隆您的仓库以检查它。如果您只在公司网络内使用它,SSH 可能是您唯一需要处理的协议。如果您想允许对您的项目进行匿名只读访问,并且还想使用 SSH,您将不得不为您设置 SSH 以便推送,但要设置其他东西以便其他人从中获取。

Git 协议

最后,我们有 Git 协议。这是一个与 Git 一起打包的特殊守护程序;它监听一个专用端口 (9418),提供类似于 SSH 协议的服务,但完全没有身份验证或加密。为了使仓库可以通过 Git 协议提供服务,您必须创建一个 git-daemon-export-ok 文件——如果没有该文件,守护程序将不会提供仓库服务——但除此之外,没有任何安全性。要么 Git 仓库对每个人都可以克隆,要么不能。这意味着通常不会通过此协议进行推送。您可以启用推送访问,但鉴于缺乏身份验证,互联网上的任何人都可以找到您的项目的 URL 并向该项目推送。不用说,这是很少见的。

优点

Git 协议通常是最快的网络传输协议。如果您要为公共项目提供大量流量,或者要提供一个不需要用户身份验证即可读取访问权限的非常大的项目,那么您可能需要设置一个 Git 守护程序来提供您的项目服务。它使用与 SSH 协议相同的数据传输机制,但没有加密和身份验证的开销。

缺点

由于缺少 TLS 或其他加密,通过 git:// 克隆可能会导致任意代码执行漏洞,因此应避免这样做,除非您知道自己在做什么。

  • 如果您运行 git clone git://example.com/project.git,那么控制您的路由器等攻击者可以修改您刚刚克隆的仓库,并在其中插入恶意代码。如果您随后编译/运行您刚刚克隆的代码,您将执行恶意代码。运行 git clone http://example.com/project.git 应该出于同样的原因而避免。

  • 运行 git clone https://example.com/project.git 不会遇到同样的问题(除非攻击者可以提供 example.com 的 TLS 证书)。运行 git clone [email protected]:project.git 只有在你接受错误的 SSH 密钥指纹时才会遇到此问题。

它也没有身份验证,也就是说任何人都可以克隆仓库(尽管这通常是你想要的结果)。它也是最难设置的协议。它必须运行自己的守护进程,这需要 xinetdsystemd 等配置,并不总是那么容易。它还需要防火墙访问端口 9418,这不是企业防火墙总是允许的标准端口。在大型企业防火墙后面,这个不起眼的端口通常会被阻止。

scroll-to-top