章节 ▾ 第二版

4.1 Git 服务器 - 协议

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

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

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

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

协议

Git 可以使用四种不同的协议来传输数据:本地、HTTP、安全 Shell (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 上的 Keychain 访问和 Windows 上的 Credential Manager,以使其相当轻松。 阅读凭据存储,了解如何在你的系统上设置安全的 HTTP 密码缓存。

SSH 协议

自托管时 Git 的常见传输协议是通过 SSH。 这是因为在大多数地方已经设置了对服务器的 SSH 访问 — 如果不是,也很容易做到。 SSH 也是经过身份验证的网络协议,并且由于它无处不在,因此通常很容易设置和使用。

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

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

或者你可以使用更短的类似 scp 的语法来表示 SSH 协议

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

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

优点

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

缺点

SSH 的缺点是它不支持对你的 Git 仓库进行匿名访问。 如果你使用 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,控制你的路由器等的攻击者可以修改你刚刚克隆的 repo,将恶意代码插入其中。 如果你随后编译/运行你刚刚克隆的代码,你将执行恶意代码。 对于相同的原因,应该避免运行 git clone http://example.com/project.git

  • 运行 git clone https://example.com/project.git 不会遇到相同的问题(除非攻击者可以为 example.com 提供 TLS 证书)。 仅当你接受错误的 SSH 密钥指纹时,运行 git clone git@example.com:project.git 才会遇到此问题。

它也没有身份验证,即任何人都可以克隆 repo(尽管这通常正是你想要的)。 它也可能是最难设置的协议。 它必须运行自己的守护程序,这需要 xinetdsystemd 配置或类似配置,这并不总是那么容易。 它还需要防火墙访问端口 9418,这不是公司防火墙始终允许的标准端口。 在大型公司防火墙后面,这个晦涩的端口通常被阻止。

scroll-to-top