# 协议
Git 可以使用四种主要的协议来传输资料:本地协议(Local),HTTP 协议,SSH(Secure Shell)协议及 Git 协议。在此,我们将会讨论那些协议及哪些情形应该使用(或避免使用)他们。
## 本地协议
最基本的就是 *本地协议(Local protocol)* ,其中的远程版本库就是硬盘内的另一个目录。这常见于团队每一个成员都对一个共享的文件系统(例如一个挂载的 NFS)拥有访问权,或者比较少见的多人共用同一台电脑的情况。后者并不理想,因为你的所有代码版本库如果长存于同一台电脑,更可能发生灾难性的损失。
如果你使用共享文件系统,就可以从本地版本库克隆(clone)、推送(push)以及拉取(pull)。像这样去克隆一个版本库或者增加一个远程到现有的项目中,使用版本库路径作为 URL。例如,克隆一个本地版本库,可以执行如下的命令:
~~~
$ 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)的干净版本库副本– 通常是在从其他版本控制系统导入后或一些类似情况(参见 [Chapter 10](#) for maintenance tasks)需要这么做。在此我们将使用普通路径,因为这样通常更快。
要增加一个本地版本库到现有的 Git 项目,可以执行如下的命令:
~~~
$ git remote add local_proj /opt/git/project.git
~~~
然后,就可以像在网络上一样从远端版本库推送和拉取更新了。
### 优点
基于文件系统的版本库的优点是简单,并且直接使用了现有的文件权限和网络访问权限。如果你的团队已经有共享文件系统,建立版本库会十分容易。只需要像设置其他共享目录一样,把一个裸版本库的副本放到大家都可以访问的路径,并设置好读/写的权限,就可以了,我们会在 [“在服务器上搭建 Git”](#) 讨论如何导出一个裸版本库。
这也是快速从别人的工作目录中拉取更新的方法。如果你和别人一起合作一个项目,他想让你从版本库中拉取更新时,运行类似 `git pull /home/john/project` 的命令比推送到服务再取回简单多了。
### 缺点
这种方法的缺点是,通常共享文件系统比较难配置,并且比起基本的网络连接访问,这不方便从多个位置访问。如果你想从家里推送内容,必须先挂载一个远程磁盘,相比网络连接的访问方式,配置不方便,速度也慢。
值得一提的是,如果你使用的是类似于共享挂载的文件系统时,这个方法不一定是最快的。访问本地版本库的速度与你访问数据的速度是一样的。在同一个服务器上,如果允许 Git 访问本地硬盘,一般的通过 NFS 访问版本库要比通过 SSH 访问慢。
最终,这个协议并不保护仓库避免意外的损坏。每一个用户都有“远程”目录的完整 shell 权限,没有方法可以阻止他们修改或删除 Git 内部文件和损坏仓库。
## 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 访问版本库的方法:
~~~
$ 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 的数据是以基本的静态文件形式提供的(详情见 [Chapter 10](#))。
通常的,会在可以提供读/写的智能 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 密码。
## 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 守护进程很常见,多数管理员都有使用经验,并且多数操作系统都包含了它及相关的管理工具。其次,通过 SSH 访问是安全的 —— 所有传输数据都要经过授权和加密。最后,与 HTTP/S 协议、Git 协议及本地协议一样,SSH 协议很高效,在传输前也会尽量压缩数据。
### 缺点
SSH 协议的缺点在于你不能通过他实现匿名访问。即便只要读取数据,使用者也要有通过 SSH 访问你的主机的权限,这使得 SSH 协议不利于开源的项目。如果你只在公司网络使用,SSH 协议可能是你唯一要用到的协议。如果你要同时提供匿名只读访问和 SSH 协议,那么你除了为自己推送架设 SSH 服务以外,还得架设一个可以让其他人访问的服务。
## 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 端口,但是企业防火墙一般不会开放这个非标准端口。而大型的企业防火墙通常会封锁这个端口。
- 前言
- Scott Chacon 序
- Ben Straub 序
- 献辞
- 贡献者
- 引言
- 1. 起步
- 1.1 关于版本控制
- 1.2 Git 简史
- 1.3 Git 基础
- 1.4 命令行
- 1.5 安装 Git
- 1.6 初次运行 Git 前的配置
- 1.7 获取帮助
- 1.8 总结
- 2. Git 基础
- 2.1 获取 Git 仓库
- 2.2 记录每次更新到仓库
- 2.3 查看提交历史
- 2.4 撤消操作
- 2.5 远程仓库的使用
- 2.6 打标签
- 2.7 Git 别名
- 2.8 总结
- 3. Git 分支
- 3.1 分支简介
- 3.2 分支的新建与合并
- 3.3 分支管理
- 3.4 分支开发工作流
- 3.5 远程分支
- 3.6 变基
- 3.7 总结
- 4. 服务器上的 Git
- 4.1 协议
- 4.2 在服务器上搭建 Git
- 4.3 生成 SSH 公钥
- 4.4 配置服务器
- 4.5 Git 守护进程
- 4.6 Smart HTTP
- 4.7 GitWeb
- 4.8 GitLab
- 4.9 第三方托管的选择
- 4.10 总结
- 5. 分布式 Git
- 5.1 分布式工作流程
- 5.2 向一个项目贡献
- 5.3 维护项目
- 5.4 总结
- 6. GitHub
- 6.1 账户的创建和配置
- 6.2 对项目做出贡献
- 6.3 维护项目
- 6.4 管理组织
- 6.5 脚本 GitHub
- 6.6 总结
- 7. Git 工具
- 7.1 选择修订版本
- 7.2 交互式暂存
- 7.3 储藏与清理
- 7.4 签署工作
- 7.5 搜索
- 7.6 重写历史
- 7.7 重置揭密
- 7.8 高级合并
- 7.9 Rerere
- 7.10 使用 Git 调试
- 7.11 子模块
- 7.12 打包
- 7.13 替换
- 7.14 凭证存储
- 7.15 总结
- 8. 自定义 Git
- 8.1 配置 Git
- 8.2 Git 属性
- 8.3 Git 钩子
- 8.4 使用强制策略的一个例子
- 8.5 总结
- 9. Git 与其他系统
- 9.1 作为客户端的 Git
- 9.2 迁移到 Git
- 9.3 总结
- 10. Git 内部原理
- 10.1 底层命令和高层命令
- 10.2 Git 对象
- 10.3 Git 引用
- 10.4 包文件
- 10.5 引用规格
- 10.6 传输协议
- 10.7 维护与数据恢复
- 10.8 环境变量
- 10.9 总结
- A. 其它环境中的 Git
- A1.1 图形界面
- A1.2 Visual Studio 中的 Git
- A1.3 Eclipse 中的 Git
- A1.4 Bash 中的 Git
- A1.5 Zsh 中的 Git
- A1.6 Powershell 中的 Git
- A1.7 总结
- B. 将 Git 嵌入你的应用
- A2.1 命令行 Git 方式
- A2.2 Libgit2
- A2.3 JGit
- C. Git 命令
- A3.1 设置与配置
- A3.2 获取与创建项目
- A3.3 快照基础
- A3.4 分支与合并
- A3.5 项目分享与更新
- A3.6 检查与比较
- A3.7 调试
- A3.8 补丁
- A3.9 邮件
- A3.10 外部系统
- A3.11 管理
- A3.12 底层命令